2019-08-26 10:04:57 +00:00
|
|
|
package sectorblocks
|
2019-08-26 08:02:26 +00:00
|
|
|
|
|
|
|
import (
|
2019-08-26 10:04:57 +00:00
|
|
|
"context"
|
|
|
|
"github.com/filecoin-project/go-lotus/api"
|
2019-08-26 09:08:39 +00:00
|
|
|
"github.com/filecoin-project/go-lotus/node/modules/dtypes"
|
|
|
|
"github.com/ipfs/go-datastore/namespace"
|
2019-08-26 10:04:57 +00:00
|
|
|
"github.com/ipfs/go-datastore/query"
|
2019-08-26 08:02:26 +00:00
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/ipfs/go-cid"
|
|
|
|
"github.com/ipfs/go-datastore"
|
|
|
|
dshelp "github.com/ipfs/go-ipfs-ds-help"
|
|
|
|
files "github.com/ipfs/go-ipfs-files"
|
|
|
|
cbor "github.com/ipfs/go-ipld-cbor"
|
|
|
|
|
|
|
|
"github.com/filecoin-project/go-lotus/storage/sector"
|
|
|
|
)
|
|
|
|
|
|
|
|
type SealSerialization uint8
|
|
|
|
|
|
|
|
const (
|
|
|
|
SerializationUnixfs0 SealSerialization = 'u'
|
|
|
|
)
|
|
|
|
|
2019-08-26 09:08:39 +00:00
|
|
|
var dsPrefix = datastore.NewKey("/sealedblocks")
|
|
|
|
|
2019-08-26 10:04:57 +00:00
|
|
|
type SectorBlocks struct {
|
2019-08-26 08:02:26 +00:00
|
|
|
*sector.Store
|
|
|
|
|
2019-08-26 09:08:39 +00:00
|
|
|
keys datastore.Batching
|
2019-08-26 08:02:26 +00:00
|
|
|
keyLk sync.Mutex
|
|
|
|
}
|
|
|
|
|
2019-08-26 10:04:57 +00:00
|
|
|
func NewSectorBlocks(sectst *sector.Store, ds dtypes.MetadataDS) *SectorBlocks {
|
|
|
|
return &SectorBlocks{
|
2019-08-26 09:08:39 +00:00
|
|
|
Store: sectst,
|
|
|
|
keys: namespace.Wrap(ds, dsPrefix),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-26 08:02:26 +00:00
|
|
|
type UnixfsReader interface {
|
|
|
|
files.File
|
|
|
|
|
|
|
|
// ReadBlock reads data from a single unixfs block. Data is nil
|
|
|
|
// for intermediate nodes
|
2019-08-26 10:04:57 +00:00
|
|
|
ReadBlock(context.Context) (data []byte, offset uint64, cid cid.Cid, err error)
|
2019-08-26 08:02:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type refStorer struct {
|
|
|
|
blockReader UnixfsReader
|
2019-08-26 09:08:39 +00:00
|
|
|
writeRef func(cid cid.Cid, offset uint64, size uint32) error
|
2019-08-26 08:02:26 +00:00
|
|
|
|
2019-08-26 09:08:39 +00:00
|
|
|
pieceRef string
|
2019-08-26 08:02:26 +00:00
|
|
|
remaining []byte
|
|
|
|
}
|
|
|
|
|
2019-08-26 10:04:57 +00:00
|
|
|
func (st *SectorBlocks) writeRef(cid cid.Cid, offset uint64, size uint32) error {
|
2019-08-26 08:02:26 +00:00
|
|
|
st.keyLk.Lock() // TODO: make this multithreaded
|
|
|
|
defer st.keyLk.Unlock()
|
|
|
|
|
|
|
|
v, err := st.keys.Get(dshelp.CidToDsKey(cid))
|
|
|
|
if err == datastore.ErrNotFound {
|
|
|
|
err = nil
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-08-26 10:04:57 +00:00
|
|
|
var refs []api.SealedRef
|
2019-08-26 08:02:26 +00:00
|
|
|
if len(v) > 0 {
|
|
|
|
if err := cbor.DecodeInto(v, &refs); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-26 10:04:57 +00:00
|
|
|
refs = append(refs, api.SealedRef{
|
|
|
|
Piece: string(SerializationUnixfs0) + cid.String(),
|
|
|
|
Offset: offset,
|
|
|
|
Size: size,
|
2019-08-26 08:02:26 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
newRef, err := cbor.DumpObject(&refs)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return st.keys.Put(dshelp.CidToDsKey(cid), newRef) // TODO: batch somehow
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *refStorer) Read(p []byte) (n int, err error) {
|
|
|
|
offset := 0
|
|
|
|
if len(r.remaining) > 0 {
|
|
|
|
offset += len(r.remaining)
|
|
|
|
read := copy(p, r.remaining)
|
|
|
|
if read == len(r.remaining) {
|
|
|
|
r.remaining = nil
|
|
|
|
} else {
|
|
|
|
r.remaining = r.remaining[read:]
|
|
|
|
}
|
|
|
|
return read, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
2019-08-26 10:04:57 +00:00
|
|
|
data, offset, cid, err := r.blockReader.ReadBlock(context.TODO())
|
2019-08-26 08:02:26 +00:00
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := r.writeRef(cid, offset, uint32(len(data))); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2019-08-26 10:04:57 +00:00
|
|
|
read := copy(p, data)
|
|
|
|
if read < len(data) {
|
|
|
|
r.remaining = data[read:]
|
|
|
|
}
|
|
|
|
// TODO: read multiple
|
|
|
|
return read, nil
|
2019-08-26 08:02:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-26 10:04:57 +00:00
|
|
|
func (st *SectorBlocks) AddUnixfsPiece(ref cid.Cid, r UnixfsReader, keepAtLeast uint64) (sectorID uint64, err error) {
|
2019-08-26 08:02:26 +00:00
|
|
|
size, err := r.Size()
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
2019-08-26 09:08:39 +00:00
|
|
|
refst := &refStorer{blockReader: r, pieceRef: string(SerializationUnixfs0) + ref.String(), writeRef: st.writeRef}
|
2019-08-26 08:02:26 +00:00
|
|
|
|
|
|
|
return st.Store.AddPiece(refst.pieceRef, uint64(size), refst)
|
|
|
|
}
|
2019-08-26 10:04:57 +00:00
|
|
|
|
|
|
|
func (st *SectorBlocks) List() (map[cid.Cid][]api.SealedRef, error) {
|
|
|
|
res, err := st.keys.Query(query.Query{})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ents, err := res.Rest()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
out := map[cid.Cid][]api.SealedRef{}
|
|
|
|
for _, ent := range ents {
|
|
|
|
refCid, err := dshelp.DsKeyToCid(datastore.RawKey(ent.Key))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var refs []api.SealedRef
|
|
|
|
if err := cbor.DecodeInto(ent.Value, &refs); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
out[refCid] = refs
|
|
|
|
}
|
|
|
|
|
|
|
|
return out, nil
|
|
|
|
}
|