package blockstore import ( "github.com/ipfs/go-ipfs/blocks" key "github.com/ipfs/go-ipfs/blocks/key" ds "gx/ipfs/QmTxLSvdhwg68WJimdS6icLPhZi28aTp6b7uihC2Yb47Xk/go-datastore" lru "gx/ipfs/QmVYxfoJQiZijTgPNHCHgHELvQpbsJNTg6Crmc3dQkj3yy/golang-lru" context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type arccache struct { arc *lru.ARCCache blockstore Blockstore } func arcCached(bs Blockstore, lruSize int) (*arccache, error) { arc, err := lru.NewARC(lruSize) if err != nil { return nil, err } return &arccache{arc: arc, blockstore: bs}, nil } func (b *arccache) DeleteBlock(k key.Key) error { if has, ok := b.hasCached(k); ok && !has { return ErrNotFound } b.arc.Remove(k) // Invalidate cache before deleting. err := b.blockstore.DeleteBlock(k) switch err { case nil: b.arc.Add(k, false) case ds.ErrNotFound, ErrNotFound: b.arc.Add(k, false) default: return err } return nil } // if ok == false has is inconclusive // if ok == true then has respons to question: is it contained func (b *arccache) hasCached(k key.Key) (has bool, ok bool) { if k == "" { // Return cache invalid so call to blockstore // in case of invalid key is forwarded deeper return false, false } h, ok := b.arc.Get(k) if ok { return h.(bool), ok } else { return false, false } } func (b *arccache) Has(k key.Key) (bool, error) { if has, ok := b.hasCached(k); ok { return has, nil } res, err := b.blockstore.Has(k) if err == nil { b.arc.Add(k, res) } return res, err } func (b *arccache) Get(k key.Key) (blocks.Block, error) { if has, ok := b.hasCached(k); ok && !has { return nil, ErrNotFound } bl, err := b.blockstore.Get(k) if bl == nil && err == ErrNotFound { b.arc.Add(k, false) } else if bl != nil { b.arc.Add(k, true) } return bl, err } func (b *arccache) Put(bl blocks.Block) error { if has, ok := b.hasCached(bl.Key()); ok && has { return nil } err := b.blockstore.Put(bl) if err == nil { b.arc.Add(bl.Key(), true) } return err } func (b *arccache) PutMany(bs []blocks.Block) error { var good []blocks.Block for _, block := range bs { if has, ok := b.hasCached(block.Key()); !ok || (ok && !has) { good = append(good, block) } } err := b.blockstore.PutMany(bs) if err == nil { for _, block := range bs { b.arc.Add(block.Key(), true) } } return err } func (b *arccache) AllKeysChan(ctx context.Context) (<-chan key.Key, error) { return b.blockstore.AllKeysChan(ctx) } func (b *arccache) GCLock() Unlocker { return b.blockstore.(GCBlockstore).GCLock() } func (b *arccache) PinLock() Unlocker { return b.blockstore.(GCBlockstore).PinLock() } func (b *arccache) GCRequested() bool { return b.blockstore.(GCBlockstore).GCRequested() }