2019-08-27 18:45:21 +00:00
|
|
|
package sectorblocks
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
logging "github.com/ipfs/go-log"
|
|
|
|
|
|
|
|
"github.com/filecoin-project/go-lotus/api"
|
|
|
|
"github.com/filecoin-project/go-lotus/lib/sectorbuilder"
|
|
|
|
)
|
|
|
|
|
|
|
|
var log = logging.Logger("sectorblocks")
|
|
|
|
|
|
|
|
type unsealedBlocks struct {
|
|
|
|
lk sync.Mutex
|
|
|
|
sb *sectorbuilder.SectorBuilder
|
|
|
|
|
|
|
|
// TODO: Treat this as some sort of cache, one with rather aggressive GC
|
|
|
|
// TODO: This REALLY, REALLY needs to be on-disk
|
|
|
|
unsealed map[string][]byte
|
|
|
|
|
|
|
|
unsealing map[string]chan struct{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ub *unsealedBlocks) getRef(ctx context.Context, refs []api.SealedRef, approveUnseal func() error) ([]byte, error) {
|
|
|
|
var best api.SealedRef
|
|
|
|
|
|
|
|
ub.lk.Lock()
|
|
|
|
for _, ref := range refs {
|
|
|
|
b, ok := ub.unsealed[ref.Piece]
|
|
|
|
if ok {
|
|
|
|
ub.lk.Unlock()
|
2019-08-29 18:55:20 +00:00
|
|
|
return b[ref.Offset : ref.Offset+uint64(ref.Size)], nil
|
2019-08-27 18:45:21 +00:00
|
|
|
}
|
|
|
|
// TODO: pick unsealing based on how long it's running (or just select all relevant, usually it'll be just one)
|
|
|
|
_, ok = ub.unsealing[ref.Piece]
|
|
|
|
if ok {
|
|
|
|
best = ref
|
|
|
|
break
|
|
|
|
}
|
|
|
|
best = ref
|
|
|
|
}
|
|
|
|
ub.lk.Unlock()
|
|
|
|
|
|
|
|
b, err := ub.maybeUnseal(ctx, best.Piece, approveUnseal)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-08-29 18:55:20 +00:00
|
|
|
return b[best.Offset : best.Offset+uint64(best.Size)], nil
|
2019-08-27 18:45:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ub *unsealedBlocks) maybeUnseal(ctx context.Context, pieceKey string, approveUnseal func() error) ([]byte, error) {
|
|
|
|
ub.lk.Lock()
|
|
|
|
defer ub.lk.Unlock()
|
|
|
|
|
|
|
|
out, ok := ub.unsealed[pieceKey]
|
|
|
|
if ok {
|
|
|
|
return out, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
wait, ok := ub.unsealing[pieceKey]
|
|
|
|
if ok {
|
|
|
|
ub.lk.Unlock()
|
|
|
|
select {
|
|
|
|
case <-wait:
|
|
|
|
ub.lk.Lock()
|
|
|
|
// TODO: make sure this is not racy with gc when it's implemented
|
|
|
|
return ub.unsealed[pieceKey], nil
|
|
|
|
case <-ctx.Done():
|
|
|
|
ub.lk.Lock()
|
|
|
|
return nil, ctx.Err()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: doing this under a lock is suboptimal.. but simpler
|
|
|
|
err := approveUnseal()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ub.unsealing[pieceKey] = make(chan struct{})
|
|
|
|
ub.lk.Unlock()
|
|
|
|
|
|
|
|
log.Infof("Unsealing piece '%s'", pieceKey)
|
|
|
|
data, err := ub.sb.ReadPieceFromSealedSector(pieceKey)
|
2019-08-27 23:40:14 +00:00
|
|
|
ub.lk.Lock()
|
|
|
|
|
2019-08-27 18:45:21 +00:00
|
|
|
if err != nil {
|
2019-08-27 23:40:14 +00:00
|
|
|
// TODO: tell subs
|
|
|
|
log.Error(err)
|
2019-08-27 18:45:21 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ub.unsealed[pieceKey] = data
|
|
|
|
close(ub.unsealing[pieceKey])
|
|
|
|
return data, nil
|
|
|
|
}
|