2021-03-02 17:03:11 +00:00
|
|
|
package blockstore
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
2023-03-25 07:33:05 +00:00
|
|
|
blocks "github.com/ipfs/go-block-format"
|
2021-03-02 17:03:11 +00:00
|
|
|
"github.com/ipfs/go-cid"
|
2022-06-28 11:09:59 +00:00
|
|
|
ipld "github.com/ipfs/go-ipld-format"
|
2021-03-02 17:03:11 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type unionBlockstore []Blockstore
|
|
|
|
|
|
|
|
// Union returns an unioned blockstore.
|
|
|
|
//
|
2022-08-29 14:25:30 +00:00
|
|
|
// - Reads return from the first blockstore that has the value, querying in the
|
|
|
|
// supplied order.
|
|
|
|
// - Writes (puts and deletes) are broadcast to all stores.
|
2021-03-02 17:03:11 +00:00
|
|
|
func Union(stores ...Blockstore) Blockstore {
|
|
|
|
return unionBlockstore(stores)
|
|
|
|
}
|
|
|
|
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m unionBlockstore) Has(ctx context.Context, cid cid.Cid) (has bool, err error) {
|
2021-03-02 17:03:11 +00:00
|
|
|
for _, bs := range m {
|
2021-11-19 01:50:25 +00:00
|
|
|
if has, err = bs.Has(ctx, cid); has || err != nil {
|
2021-03-02 17:03:11 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return has, err
|
|
|
|
}
|
|
|
|
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m unionBlockstore) Get(ctx context.Context, cid cid.Cid) (blk blocks.Block, err error) {
|
2021-03-02 17:03:11 +00:00
|
|
|
for _, bs := range m {
|
2022-06-28 11:09:59 +00:00
|
|
|
if blk, err = bs.Get(ctx, cid); err == nil || !ipld.IsNotFound(err) {
|
2021-03-02 17:03:11 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return blk, err
|
|
|
|
}
|
|
|
|
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m unionBlockstore) View(ctx context.Context, cid cid.Cid, callback func([]byte) error) (err error) {
|
2021-03-02 17:03:11 +00:00
|
|
|
for _, bs := range m {
|
2022-06-28 11:09:59 +00:00
|
|
|
if err = bs.View(ctx, cid, callback); err == nil || !ipld.IsNotFound(err) {
|
2021-03-02 17:03:11 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m unionBlockstore) GetSize(ctx context.Context, cid cid.Cid) (size int, err error) {
|
2021-03-02 17:03:11 +00:00
|
|
|
for _, bs := range m {
|
2022-06-28 11:09:59 +00:00
|
|
|
if size, err = bs.GetSize(ctx, cid); err == nil || !ipld.IsNotFound(err) {
|
2021-03-02 17:03:11 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return size, err
|
|
|
|
}
|
|
|
|
|
2020-11-24 07:11:28 +00:00
|
|
|
func (m unionBlockstore) Flush(ctx context.Context) (err error) {
|
|
|
|
for _, bs := range m {
|
|
|
|
if err = bs.Flush(ctx); err != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m unionBlockstore) Put(ctx context.Context, block blocks.Block) (err error) {
|
2021-03-02 17:03:11 +00:00
|
|
|
for _, bs := range m {
|
2021-11-19 01:50:25 +00:00
|
|
|
if err = bs.Put(ctx, block); err != nil {
|
2021-03-02 17:03:11 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m unionBlockstore) PutMany(ctx context.Context, blks []blocks.Block) (err error) {
|
2021-03-02 17:03:11 +00:00
|
|
|
for _, bs := range m {
|
2021-11-19 01:50:25 +00:00
|
|
|
if err = bs.PutMany(ctx, blks); err != nil {
|
2021-03-02 17:03:11 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m unionBlockstore) DeleteBlock(ctx context.Context, cid cid.Cid) (err error) {
|
2021-03-02 17:03:11 +00:00
|
|
|
for _, bs := range m {
|
2021-11-19 01:50:25 +00:00
|
|
|
if err = bs.DeleteBlock(ctx, cid); err != nil {
|
2021-03-02 17:03:11 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-11-19 01:50:25 +00:00
|
|
|
func (m unionBlockstore) DeleteMany(ctx context.Context, cids []cid.Cid) (err error) {
|
2021-03-03 10:26:10 +00:00
|
|
|
for _, bs := range m {
|
2021-11-19 01:50:25 +00:00
|
|
|
if err = bs.DeleteMany(ctx, cids); err != nil {
|
2021-03-03 10:26:10 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-03-02 17:03:11 +00:00
|
|
|
func (m unionBlockstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
|
|
|
|
// this does not deduplicate; this interface needs to be revisited.
|
|
|
|
outCh := make(chan cid.Cid)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
defer close(outCh)
|
|
|
|
|
|
|
|
for _, bs := range m {
|
|
|
|
ch, err := bs.AllKeysChan(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for cid := range ch {
|
|
|
|
outCh <- cid
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
return outCh, nil
|
|
|
|
}
|
|
|
|
|
2021-12-11 21:03:00 +00:00
|
|
|
func (m unionBlockstore) HashOnRead(enabled bool) {
|
2021-03-02 21:22:24 +00:00
|
|
|
for _, bs := range m {
|
2021-12-11 21:03:00 +00:00
|
|
|
bs.HashOnRead(enabled)
|
2021-03-02 21:22:24 +00:00
|
|
|
}
|
2021-03-02 17:03:11 +00:00
|
|
|
}
|