2020-10-12 22:52:38 +00:00
|
|
|
package blockstore
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
|
|
|
blocks "github.com/ipfs/go-block-format"
|
|
|
|
"github.com/ipfs/go-cid"
|
2022-06-28 11:09:59 +00:00
|
|
|
ipld "github.com/ipfs/go-ipld-format"
|
2020-10-12 22:52:38 +00:00
|
|
|
)
|
|
|
|
|
2021-01-29 20:01:00 +00:00
|
|
|
// NewMemory returns a temporary memory-backed blockstore.
|
|
|
|
func NewMemory() MemBlockstore {
|
|
|
|
return make(MemBlockstore)
|
|
|
|
}
|
|
|
|
|
|
|
|
// MemBlockstore is a terminal blockstore that keeps blocks in memory.
|
2022-08-05 20:34:16 +00:00
|
|
|
// To match behavior of badger blockstore we index by multihash only.
|
|
|
|
type MemBlockstore map[string]blocks.Block
|
2020-10-12 22:52:38 +00:00
|
|
|
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m MemBlockstore) DeleteBlock(ctx context.Context, k cid.Cid) error {
|
2022-08-05 20:34:16 +00:00
|
|
|
delete(m, string(k.Hash()))
|
2020-10-12 22:52:38 +00:00
|
|
|
return nil
|
|
|
|
}
|
2020-11-10 12:40:32 +00:00
|
|
|
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m MemBlockstore) DeleteMany(ctx context.Context, ks []cid.Cid) error {
|
2021-03-02 14:45:45 +00:00
|
|
|
for _, k := range ks {
|
2022-08-05 20:34:16 +00:00
|
|
|
delete(m, string(k.Hash()))
|
2021-03-02 14:45:45 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m MemBlockstore) Has(ctx context.Context, k cid.Cid) (bool, error) {
|
2022-08-05 20:34:16 +00:00
|
|
|
_, ok := m[string(k.Hash())]
|
2020-10-12 22:52:38 +00:00
|
|
|
return ok, nil
|
|
|
|
}
|
2020-11-10 12:40:32 +00:00
|
|
|
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m MemBlockstore) View(ctx context.Context, k cid.Cid, callback func([]byte) error) error {
|
2022-08-05 20:34:16 +00:00
|
|
|
b, ok := m[string(k.Hash())]
|
2020-11-10 12:40:32 +00:00
|
|
|
if !ok {
|
2022-06-28 11:09:59 +00:00
|
|
|
return ipld.ErrNotFound{Cid: k}
|
2020-11-10 12:40:32 +00:00
|
|
|
}
|
|
|
|
return callback(b.RawData())
|
|
|
|
}
|
|
|
|
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m MemBlockstore) Get(ctx context.Context, k cid.Cid) (blocks.Block, error) {
|
2022-08-05 20:34:16 +00:00
|
|
|
b, ok := m[string(k.Hash())]
|
2020-10-12 22:52:38 +00:00
|
|
|
if !ok {
|
2022-06-28 11:09:59 +00:00
|
|
|
return nil, ipld.ErrNotFound{Cid: k}
|
2020-10-12 22:52:38 +00:00
|
|
|
}
|
|
|
|
return b, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetSize returns the CIDs mapped BlockSize
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m MemBlockstore) GetSize(ctx context.Context, k cid.Cid) (int, error) {
|
2022-08-05 20:34:16 +00:00
|
|
|
b, ok := m[string(k.Hash())]
|
2020-10-12 22:52:38 +00:00
|
|
|
if !ok {
|
2022-06-28 11:09:59 +00:00
|
|
|
return 0, ipld.ErrNotFound{Cid: k}
|
2020-10-12 22:52:38 +00:00
|
|
|
}
|
|
|
|
return len(b.RawData()), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Put puts a given block to the underlying datastore
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m MemBlockstore) Put(ctx context.Context, b blocks.Block) error {
|
2020-10-12 22:52:38 +00:00
|
|
|
// Convert to a basic block for safety, but try to reuse the existing
|
|
|
|
// block if it's already a basic block.
|
2022-08-05 20:34:16 +00:00
|
|
|
k := string(b.Cid().Hash())
|
2020-10-12 22:52:38 +00:00
|
|
|
if _, ok := b.(*blocks.BasicBlock); !ok {
|
|
|
|
// If we already have the block, abort.
|
|
|
|
if _, ok := m[k]; ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
// the error is only for debugging.
|
|
|
|
b, _ = blocks.NewBlockWithCid(b.RawData(), b.Cid())
|
|
|
|
}
|
2022-08-05 20:34:16 +00:00
|
|
|
m[k] = b
|
2020-10-12 22:52:38 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// PutMany puts a slice of blocks at the same time using batching
|
|
|
|
// capabilities of the underlying datastore whenever possible.
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m MemBlockstore) PutMany(ctx context.Context, bs []blocks.Block) error {
|
2020-10-12 22:52:38 +00:00
|
|
|
for _, b := range bs {
|
2021-11-19 01:50:25 +00:00
|
|
|
_ = m.Put(ctx, b) // can't fail
|
2020-10-12 22:52:38 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// AllKeysChan returns a channel from which
|
|
|
|
// the CIDs in the Blockstore can be read. It should respect
|
|
|
|
// the given context, closing the channel if it becomes Done.
|
2021-01-29 20:01:00 +00:00
|
|
|
func (m MemBlockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
|
2020-10-12 22:52:38 +00:00
|
|
|
ch := make(chan cid.Cid, len(m))
|
2022-08-05 20:34:16 +00:00
|
|
|
for _, b := range m {
|
|
|
|
ch <- b.Cid()
|
2020-10-12 22:52:38 +00:00
|
|
|
}
|
|
|
|
close(ch)
|
|
|
|
return ch, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// HashOnRead specifies if every read block should be
|
|
|
|
// rehashed to make sure it matches its CID.
|
2021-12-11 21:03:00 +00:00
|
|
|
func (m MemBlockstore) HashOnRead(enabled bool) {
|
2020-10-12 22:52:38 +00:00
|
|
|
// no-op
|
|
|
|
}
|