2019-08-27 18:45:21 +00:00
|
|
|
package sectorblocks
|
|
|
|
|
|
|
|
import (
|
2019-11-06 12:22:08 +00:00
|
|
|
"bytes"
|
2019-08-27 18:45:21 +00:00
|
|
|
"context"
|
2020-01-24 20:19:52 +00:00
|
|
|
"encoding/binary"
|
2019-08-27 23:40:14 +00:00
|
|
|
"errors"
|
2019-11-06 17:38:42 +00:00
|
|
|
"io"
|
2019-08-27 18:45:21 +00:00
|
|
|
"sync"
|
|
|
|
|
2023-05-25 14:31:53 +00:00
|
|
|
dshelp "github.com/ipfs/boxo/datastore/dshelp"
|
2019-08-27 18:45:21 +00:00
|
|
|
"github.com/ipfs/go-datastore"
|
2019-11-06 12:22:08 +00:00
|
|
|
"github.com/ipfs/go-datastore/namespace"
|
|
|
|
"github.com/ipfs/go-datastore/query"
|
|
|
|
"golang.org/x/xerrors"
|
2019-08-27 18:45:21 +00:00
|
|
|
|
2020-01-24 20:19:52 +00:00
|
|
|
cborutil "github.com/filecoin-project/go-cbor-util"
|
2020-09-07 03:49:10 +00:00
|
|
|
"github.com/filecoin-project/go-state-types/abi"
|
2020-01-07 14:00:10 +00:00
|
|
|
"github.com/filecoin-project/lotus/api"
|
2019-11-06 12:22:08 +00:00
|
|
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
2022-06-17 11:31:05 +00:00
|
|
|
"github.com/filecoin-project/lotus/storage/sealer/storiface"
|
2019-08-27 18:45:21 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type SealSerialization uint8
|
|
|
|
|
|
|
|
const (
|
|
|
|
SerializationUnixfs0 SealSerialization = 'u'
|
|
|
|
)
|
|
|
|
|
|
|
|
var dsPrefix = datastore.NewKey("/sealedblocks")
|
|
|
|
|
2019-08-27 23:40:14 +00:00
|
|
|
var ErrNotFound = errors.New("not found")
|
|
|
|
|
2020-02-08 02:18:32 +00:00
|
|
|
func DealIDToDsKey(dealID abi.DealID) datastore.Key {
|
2020-01-24 20:19:52 +00:00
|
|
|
buf := make([]byte, binary.MaxVarintLen64)
|
2020-02-08 02:18:32 +00:00
|
|
|
size := binary.PutUvarint(buf, uint64(dealID))
|
2020-01-28 22:15:12 +00:00
|
|
|
return dshelp.NewKeyFromBinary(buf[:size])
|
2020-01-24 20:19:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func DsKeyToDealID(key datastore.Key) (uint64, error) {
|
|
|
|
buf, err := dshelp.BinaryFromDsKey(key)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
dealID, _ := binary.Uvarint(buf)
|
|
|
|
return dealID, nil
|
|
|
|
}
|
|
|
|
|
2021-07-06 15:33:47 +00:00
|
|
|
type SectorBuilder interface {
|
2022-06-17 11:31:05 +00:00
|
|
|
SectorAddPieceToAny(ctx context.Context, size abi.UnpaddedPieceSize, r storiface.Data, d api.PieceDealInfo) (api.SectorOffset, error)
|
2021-05-19 11:05:07 +00:00
|
|
|
SectorsStatus(ctx context.Context, sid abi.SectorNumber, showOnChainInfo bool) (api.SectorInfo, error)
|
|
|
|
}
|
|
|
|
|
2019-08-27 18:45:21 +00:00
|
|
|
type SectorBlocks struct {
|
2021-05-19 11:05:07 +00:00
|
|
|
SectorBuilder
|
2019-08-27 18:45:21 +00:00
|
|
|
|
2019-12-01 17:58:31 +00:00
|
|
|
keys datastore.Batching
|
|
|
|
keyLk sync.Mutex
|
2019-08-27 18:45:21 +00:00
|
|
|
}
|
|
|
|
|
2021-05-19 11:05:07 +00:00
|
|
|
func NewSectorBlocks(sb SectorBuilder, ds dtypes.MetadataDS) *SectorBlocks {
|
2019-08-27 18:45:21 +00:00
|
|
|
sbc := &SectorBlocks{
|
2021-05-19 11:05:07 +00:00
|
|
|
SectorBuilder: sb,
|
|
|
|
keys: namespace.Wrap(ds, dsPrefix),
|
2019-08-27 18:45:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return sbc
|
|
|
|
}
|
|
|
|
|
2021-12-11 21:03:00 +00:00
|
|
|
func (st *SectorBlocks) writeRef(ctx context.Context, dealID abi.DealID, sectorID abi.SectorNumber, offset abi.PaddedPieceSize, size abi.UnpaddedPieceSize) error {
|
2019-08-27 18:45:21 +00:00
|
|
|
st.keyLk.Lock() // TODO: make this multithreaded
|
|
|
|
defer st.keyLk.Unlock()
|
|
|
|
|
2021-12-11 21:03:00 +00:00
|
|
|
v, err := st.keys.Get(ctx, DealIDToDsKey(dealID))
|
2019-08-27 18:45:21 +00:00
|
|
|
if err == datastore.ErrNotFound {
|
|
|
|
err = nil
|
|
|
|
}
|
|
|
|
if err != nil {
|
2019-11-06 12:04:33 +00:00
|
|
|
return xerrors.Errorf("getting existing refs: %w", err)
|
2019-08-27 18:45:21 +00:00
|
|
|
}
|
|
|
|
|
2019-11-06 12:22:08 +00:00
|
|
|
var refs api.SealedRefs
|
2019-08-27 18:45:21 +00:00
|
|
|
if len(v) > 0 {
|
2019-11-07 14:11:39 +00:00
|
|
|
if err := cborutil.ReadCborRPC(bytes.NewReader(v), &refs); err != nil {
|
2019-11-06 12:04:33 +00:00
|
|
|
return xerrors.Errorf("decoding existing refs: %w", err)
|
2019-08-27 18:45:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-06 12:22:08 +00:00
|
|
|
refs.Refs = append(refs.Refs, api.SealedRef{
|
2019-12-01 17:58:31 +00:00
|
|
|
SectorID: sectorID,
|
|
|
|
Offset: offset,
|
|
|
|
Size: size,
|
2019-08-27 18:45:21 +00:00
|
|
|
})
|
|
|
|
|
2019-11-07 14:11:39 +00:00
|
|
|
newRef, err := cborutil.Dump(&refs)
|
2019-08-27 18:45:21 +00:00
|
|
|
if err != nil {
|
2019-11-06 12:04:33 +00:00
|
|
|
return xerrors.Errorf("serializing refs: %w", err)
|
2019-08-27 18:45:21 +00:00
|
|
|
}
|
2021-12-11 21:03:00 +00:00
|
|
|
return st.keys.Put(ctx, DealIDToDsKey(dealID), newRef) // TODO: batch somehow
|
2019-08-27 18:45:21 +00:00
|
|
|
}
|
|
|
|
|
2021-05-19 11:05:07 +00:00
|
|
|
func (st *SectorBlocks) AddPiece(ctx context.Context, size abi.UnpaddedPieceSize, r io.Reader, d api.PieceDealInfo) (abi.SectorNumber, abi.PaddedPieceSize, error) {
|
|
|
|
so, err := st.SectorBuilder.SectorAddPieceToAny(ctx, size, r, d)
|
2019-12-01 17:58:31 +00:00
|
|
|
if err != nil {
|
2020-07-30 12:31:31 +00:00
|
|
|
return 0, 0, err
|
2019-12-01 17:58:31 +00:00
|
|
|
}
|
|
|
|
|
2020-08-27 15:50:37 +00:00
|
|
|
// TODO: DealID has very low finality here
|
2021-12-11 21:03:00 +00:00
|
|
|
err = st.writeRef(ctx, d.DealID, so.Sector, so.Offset, size)
|
2020-01-28 22:15:12 +00:00
|
|
|
if err != nil {
|
2020-07-30 12:31:31 +00:00
|
|
|
return 0, 0, xerrors.Errorf("writeRef: %w", err)
|
2020-01-28 22:15:12 +00:00
|
|
|
}
|
2019-12-01 17:58:31 +00:00
|
|
|
|
2021-05-19 11:05:07 +00:00
|
|
|
return so.Sector, so.Offset, nil
|
2019-08-27 18:45:21 +00:00
|
|
|
}
|
|
|
|
|
2021-12-11 21:03:00 +00:00
|
|
|
func (st *SectorBlocks) List(ctx context.Context) (map[uint64][]api.SealedRef, error) {
|
|
|
|
res, err := st.keys.Query(ctx, query.Query{})
|
2019-08-27 18:45:21 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ents, err := res.Rest()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-01-24 20:19:52 +00:00
|
|
|
out := map[uint64][]api.SealedRef{}
|
2019-08-27 18:45:21 +00:00
|
|
|
for _, ent := range ents {
|
2020-01-24 20:19:52 +00:00
|
|
|
dealID, err := DsKeyToDealID(datastore.RawKey(ent.Key))
|
2019-08-27 18:45:21 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-11-06 12:22:08 +00:00
|
|
|
var refs api.SealedRefs
|
2019-11-07 14:11:39 +00:00
|
|
|
if err := cborutil.ReadCborRPC(bytes.NewReader(ent.Value), &refs); err != nil {
|
2019-08-27 18:45:21 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-01-24 20:19:52 +00:00
|
|
|
out[dealID] = refs.Refs
|
2019-08-27 18:45:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return out, nil
|
|
|
|
}
|
|
|
|
|
2021-12-11 21:03:00 +00:00
|
|
|
func (st *SectorBlocks) GetRefs(ctx context.Context, dealID abi.DealID) ([]api.SealedRef, error) { // TODO: track local sectors
|
|
|
|
ent, err := st.keys.Get(ctx, DealIDToDsKey(dealID))
|
2019-08-27 23:40:14 +00:00
|
|
|
if err == datastore.ErrNotFound {
|
|
|
|
err = ErrNotFound
|
|
|
|
}
|
2019-08-27 18:45:21 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-11-06 12:22:08 +00:00
|
|
|
var refs api.SealedRefs
|
2019-11-07 14:11:39 +00:00
|
|
|
if err := cborutil.ReadCborRPC(bytes.NewReader(ent), &refs); err != nil {
|
2019-08-27 18:45:21 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-11-06 12:22:08 +00:00
|
|
|
return refs.Refs, nil
|
2019-08-27 18:45:21 +00:00
|
|
|
}
|
|
|
|
|
2021-12-11 21:03:00 +00:00
|
|
|
func (st *SectorBlocks) GetSize(ctx context.Context, dealID abi.DealID) (uint64, error) {
|
|
|
|
refs, err := st.GetRefs(ctx, dealID)
|
2019-08-27 23:40:14 +00:00
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2020-01-24 20:19:52 +00:00
|
|
|
return uint64(refs[0].Size), nil
|
2019-08-27 23:40:14 +00:00
|
|
|
}
|
|
|
|
|
2021-12-11 21:03:00 +00:00
|
|
|
func (st *SectorBlocks) Has(ctx context.Context, dealID abi.DealID) (bool, error) {
|
2019-08-27 18:45:21 +00:00
|
|
|
// TODO: ensure sector is still there
|
2021-12-11 21:03:00 +00:00
|
|
|
return st.keys.Has(ctx, DealIDToDsKey(dealID))
|
2019-08-27 18:45:21 +00:00
|
|
|
}
|