add the viewable trait to our gazillion blockstores.
This commit is contained in:
parent
3577300aee
commit
54bf7c99d7
@ -70,6 +70,7 @@ func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Ad
|
||||
}
|
||||
|
||||
var _ cbor.IpldBlockstore = (*gasChargingBlocks)(nil)
|
||||
var _ blockstore.Viewer = (*gasChargingBlocks)(nil)
|
||||
|
||||
type gasChargingBlocks struct {
|
||||
chargeGas func(GasCharge)
|
||||
@ -77,6 +78,24 @@ type gasChargingBlocks struct {
|
||||
under cbor.IpldBlockstore
|
||||
}
|
||||
|
||||
func (bs *gasChargingBlocks) View(c cid.Cid, cb func([]byte) error) error {
|
||||
if v, ok := bs.under.(blockstore.Viewer); ok {
|
||||
bs.chargeGas(bs.pricelist.OnIpldGet())
|
||||
return v.View(c, func(b []byte) error {
|
||||
// we have successfully retrieved the value; charge for it, even if the user-provided function fails.
|
||||
bs.chargeGas(newGasCharge("OnIpldViewEnd", 0, 0).WithExtra(len(b)))
|
||||
bs.chargeGas(gasOnActorExec)
|
||||
return cb(b)
|
||||
})
|
||||
}
|
||||
// the underlying blockstore doesn't implement the viewer interface, fall back to normal Get behaviour.
|
||||
blk, err := bs.Get(c)
|
||||
if err != nil && blk != nil {
|
||||
return cb(blk.RawData())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (bs *gasChargingBlocks) Get(c cid.Cid) (block.Block, error) {
|
||||
bs.chargeGas(bs.pricelist.OnIpldGet())
|
||||
blk, err := bs.under.Get(c)
|
||||
|
29
lib/blockstore/blockstore_bench_test.go
Normal file
29
lib/blockstore/blockstore_bench_test.go
Normal file
@ -0,0 +1,29 @@
|
||||
package blockstore
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkCast(b *testing.B) {
|
||||
temp := Blockstore(NewTemporary())
|
||||
for i := 0; i < b.N; i++ {
|
||||
if v, ok := temp.(Viewer); ok {
|
||||
_ = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkOnce(b *testing.B) {
|
||||
var viewer Viewer
|
||||
var once sync.Once
|
||||
temp := Blockstore(NewTemporary())
|
||||
for i := 0; i < b.N; i++ {
|
||||
once.Do(func() {
|
||||
if v, ok := temp.(Viewer); ok {
|
||||
viewer = v
|
||||
}
|
||||
})
|
||||
_ = viewer
|
||||
}
|
||||
}
|
@ -8,16 +8,27 @@ import (
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
)
|
||||
|
||||
// MemStore is a terminal blockstore that keeps blocks in memory.
|
||||
type MemStore map[cid.Cid]blocks.Block
|
||||
|
||||
func (m MemStore) DeleteBlock(k cid.Cid) error {
|
||||
delete(m, k)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m MemStore) Has(k cid.Cid) (bool, error) {
|
||||
_, ok := m[k]
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func (m MemStore) View(k cid.Cid, callback func([]byte) error) error {
|
||||
b, ok := m[k]
|
||||
if !ok {
|
||||
return blockstore.ErrNotFound
|
||||
}
|
||||
return callback(b.RawData())
|
||||
}
|
||||
|
||||
func (m MemStore) Get(k cid.Cid) (blocks.Block, error) {
|
||||
b, ok := m[k]
|
||||
if !ok {
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
// SyncStore is a terminal blockstore that is a synchronized version
|
||||
// of MemStore.
|
||||
type SyncStore struct {
|
||||
mu sync.RWMutex
|
||||
bs MemStore // specifically use a memStore to save indirection overhead.
|
||||
@ -18,11 +20,20 @@ func (m *SyncStore) DeleteBlock(k cid.Cid) error {
|
||||
defer m.mu.Unlock()
|
||||
return m.bs.DeleteBlock(k)
|
||||
}
|
||||
|
||||
func (m *SyncStore) Has(k cid.Cid) (bool, error) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
return m.bs.Has(k)
|
||||
}
|
||||
|
||||
func (m *SyncStore) View(k cid.Cid, callback func([]byte) error) error {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
return m.bs.View(k, callback)
|
||||
}
|
||||
|
||||
func (m *SyncStore) Get(k cid.Cid) (blocks.Block, error) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
@ -16,6 +16,9 @@ var log = logging.Logger("bufbs")
|
||||
type BufferedBS struct {
|
||||
read bstore.Blockstore
|
||||
write bstore.Blockstore
|
||||
|
||||
readviewer bstore.Viewer
|
||||
writeviewer bstore.Viewer
|
||||
}
|
||||
|
||||
func NewBufferedBstore(base bstore.Blockstore) *BufferedBS {
|
||||
@ -27,10 +30,20 @@ func NewBufferedBstore(base bstore.Blockstore) *BufferedBS {
|
||||
buf = bstore.NewTemporary()
|
||||
}
|
||||
|
||||
return &BufferedBS{
|
||||
bs := &BufferedBS{
|
||||
read: base,
|
||||
write: buf,
|
||||
}
|
||||
if v, ok := base.(bstore.Viewer); ok {
|
||||
bs.readviewer = v
|
||||
}
|
||||
if v, ok := buf.(bstore.Viewer); ok {
|
||||
bs.writeviewer = v
|
||||
}
|
||||
if (bs.writeviewer == nil) != (bs.readviewer == nil) {
|
||||
log.Warnf("one of the stores is not viewable; running less efficiently")
|
||||
}
|
||||
return bs
|
||||
}
|
||||
|
||||
func NewTieredBstore(r bstore.Blockstore, w bstore.Blockstore) *BufferedBS {
|
||||
@ -40,7 +53,8 @@ func NewTieredBstore(r bstore.Blockstore, w bstore.Blockstore) *BufferedBS {
|
||||
}
|
||||
}
|
||||
|
||||
var _ (bstore.Blockstore) = &BufferedBS{}
|
||||
var _ bstore.Blockstore = (*BufferedBS)(nil)
|
||||
var _ bstore.Viewer = (*BufferedBS)(nil)
|
||||
|
||||
func (bs *BufferedBS) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
|
||||
a, err := bs.read.AllKeysChan(ctx)
|
||||
@ -93,6 +107,25 @@ func (bs *BufferedBS) DeleteBlock(c cid.Cid) error {
|
||||
return bs.write.DeleteBlock(c)
|
||||
}
|
||||
|
||||
func (bs *BufferedBS) View(c cid.Cid, callback func([]byte) error) error {
|
||||
if bs.writeviewer == nil || bs.readviewer == nil {
|
||||
// none of the stores supports Viewer, just fall back to pure Get behaviour.
|
||||
blk, err := bs.Get(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return callback(blk.RawData())
|
||||
}
|
||||
|
||||
// both stores are viewable.
|
||||
if err := bs.writeviewer.View(c, callback); err == bstore.ErrNotFound {
|
||||
// not found in write blockstore; fall through.
|
||||
} else {
|
||||
return err // propagate errors, or nil, i.e. found.
|
||||
}
|
||||
return bs.readviewer.View(c, callback)
|
||||
}
|
||||
|
||||
func (bs *BufferedBS) Get(c cid.Cid) (block.Block, error) {
|
||||
if out, err := bs.write.Get(c); err != nil {
|
||||
if err != bstore.ErrNotFound {
|
||||
|
Loading…
Reference in New Issue
Block a user