Skip to content

Commit f689d2b

Browse files
authored
add the ability to leverage zero-copy on blockstores. (#75)
1 parent f88d4ac commit f689d2b

File tree

1 file changed

+27
-5
lines changed

1 file changed

+27
-5
lines changed

store.go

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,38 +26,60 @@ type IpldBlockstore interface {
2626
Put(block.Block) error
2727
}
2828

29+
// IpldBlockstoreViewer is a trait that enables zero-copy access to blocks in
30+
// a blockstore.
31+
type IpldBlockstoreViewer interface {
32+
// View provides zero-copy access to blocks in a blockstore. The callback
33+
// function will be invoked with the value for the key. The user MUST not
34+
// modify the byte array, as it could be memory-mapped.
35+
View(cid.Cid, func([]byte) error) error
36+
}
37+
2938
// BasicIpldStore wraps and IpldBlockstore and implements the IpldStore interface.
3039
type BasicIpldStore struct {
3140
Blocks IpldBlockstore
32-
Atlas *atlas.Atlas
41+
Viewer IpldBlockstoreViewer
42+
43+
Atlas *atlas.Atlas
3344
}
3445

3546
var _ IpldStore = &BasicIpldStore{}
3647

3748
// NewCborStore returns an IpldStore implementation backed by the provided IpldBlockstore.
3849
func NewCborStore(bs IpldBlockstore) *BasicIpldStore {
39-
return &BasicIpldStore{Blocks: bs}
50+
viewer, _ := bs.(IpldBlockstoreViewer)
51+
return &BasicIpldStore{Blocks: bs, Viewer: viewer}
4052
}
4153

4254
// Get reads and unmarshals the content at `c` into `out`.
4355
func (s *BasicIpldStore) Get(ctx context.Context, c cid.Cid, out interface{}) error {
56+
if s.Viewer != nil {
57+
// zero-copy path.
58+
return s.Viewer.View(c, func(b []byte) error {
59+
return s.decode(b, out)
60+
})
61+
}
62+
4463
blk, err := s.Blocks.Get(c)
4564
if err != nil {
4665
return err
4766
}
67+
return s.decode(blk.RawData(), out)
68+
}
4869

70+
func (s *BasicIpldStore) decode(b []byte, out interface{}) error {
4971
cu, ok := out.(cbg.CBORUnmarshaler)
5072
if ok {
51-
if err := cu.UnmarshalCBOR(bytes.NewReader(blk.RawData())); err != nil {
73+
if err := cu.UnmarshalCBOR(bytes.NewReader(b)); err != nil {
5274
return NewSerializationError(err)
5375
}
5476
return nil
5577
}
5678

5779
if s.Atlas == nil {
58-
return DecodeInto(blk.RawData(), out)
80+
return DecodeInto(b, out)
5981
} else {
60-
return recbor.UnmarshalAtlased(recbor.DecodeOptions{}, blk.RawData(), out, *s.Atlas)
82+
return recbor.UnmarshalAtlased(recbor.DecodeOptions{}, b, out, *s.Atlas)
6183
}
6284
}
6385

0 commit comments

Comments
 (0)