diff --git a/blockstore/badger/blockstore.go b/blockstore/badger/blockstore.go index 50a092d12..1ef622f39 100644 --- a/blockstore/badger/blockstore.go +++ b/blockstore/badger/blockstore.go @@ -222,15 +222,14 @@ func (b *Blockstore) unlockMove(state int) { b.moveMx.Unlock() } -// moveTo moves the blockstore to path, and creates a symlink from the current path -// to the new path; the old blockstore is deleted. -// If path is empty, then a new path adjacent to the current path is created -// automatically. -// The blockstore must accept new writes during the move and ensure that these +// movingGC moves the blockstore to a new path, adjacent to the current path, and creates +// a symlink from the current path to the new path; the old blockstore is deleted. +// +// The blockstore MUST accept new writes during the move and ensure that these // are persisted to the new blockstore; if a failure occurs aboring the move, // then they must be peristed to the old blockstore. // In short, the blockstore must not lose data from new writes during the move. -func (b *Blockstore) moveTo(path string) error { +func (b *Blockstore) movingGC() error { // this inlines moveLock/moveUnlock for the initial state check to prevent a second move // while one is in progress without clobbering state b.moveMx.Lock() @@ -248,9 +247,7 @@ func (b *Blockstore) moveTo(path string) error { b.moveCond.Broadcast() b.moveMx.Unlock() - if path == "" { - path = fmt.Sprintf("%s.%d", b.opts.Dir, time.Now().Unix()) - } + path := fmt.Sprintf("%s.%d", b.opts.Dir, time.Now().Unix()) defer func() { b.lockMove() @@ -469,39 +466,6 @@ func (b *Blockstore) deleteDB(path string) { } } -// CollectGarbage compacts and runs garbage collection on the value log; -// implements the BlockstoreGC trait -func (b *Blockstore) CollectGarbage(options map[interface{}]interface{}) error { - if err := b.access(); err != nil { - return err - } - defer b.viewers.Done() - - var movingGC bool - movingGCOpt, ok := options[blockstore.BlockstoreMovingGC] - if ok { - movingGC, ok = movingGCOpt.(bool) - if !ok { - return fmt.Errorf("incorrect type for moving gc option; expected bool but got %T", movingGCOpt) - } - } - - if !movingGC { - return b.onlineGC() - } - - var movingGCPath string - movingGCPathOpt, ok := options[blockstore.BlockstoreMovingGCPath] - if ok { - movingGCPath, ok = movingGCPathOpt.(string) - if !ok { - return fmt.Errorf("incorrect type for moving gc path option; expected string but got %T", movingGCPathOpt) - } - } - - return b.moveTo(movingGCPath) -} - func (b *Blockstore) onlineGC() error { b.lockDB() defer b.unlockDB() @@ -529,6 +493,29 @@ func (b *Blockstore) onlineGC() error { return err } +// CollectGarbage compacts and runs garbage collection on the value log; +// implements the BlockstoreGC trait +func (b *Blockstore) CollectGarbage(opts ...blockstore.BlockstoreGCOption) error { + if err := b.access(); err != nil { + return err + } + defer b.viewers.Done() + + var options blockstore.BlockstoreGCOptions + for _, opt := range opts { + err := opt(&options) + if err != nil { + return err + } + } + + if options.FullGC { + return b.movingGC() + } + + return b.onlineGC() +} + // Size returns the aggregate size of the blockstore func (b *Blockstore) Size() (int64, error) { if err := b.access(); err != nil { diff --git a/blockstore/badger/blockstore_test.go b/blockstore/badger/blockstore_test.go index f40ccbaf8..d1312eccc 100644 --- a/blockstore/badger/blockstore_test.go +++ b/blockstore/badger/blockstore_test.go @@ -154,9 +154,7 @@ func testMove(t *testing.T, optsF func(string) Options) { return nil }) g.Go(func() error { - return db.CollectGarbage(map[interface{}]interface{}{ - blockstore.BlockstoreMovingGC: true, - }) + return db.CollectGarbage(blockstore.WithFullGC(true)) }) err = g.Wait() diff --git a/blockstore/blockstore.go b/blockstore/blockstore.go index a9482b323..8ede31eb9 100644 --- a/blockstore/blockstore.go +++ b/blockstore/blockstore.go @@ -37,20 +37,23 @@ type BlockstoreIterator interface { // BlockstoreGC is a trait for blockstores that support online garbage collection type BlockstoreGC interface { - CollectGarbage(options map[interface{}]interface{}) error + CollectGarbage(options ...BlockstoreGCOption) error } -// garbage collection options -type blockstoreMovingGCKey struct{} -type blockstoreMovingGCPath struct{} +// BlockstoreGCOption is a functional interface for controlling blockstore GC options +type BlockstoreGCOption = func(*BlockstoreGCOptions) error -// BlockstoreMovingGC is a garbage collection option that instructs the blockstore -// to use moving GC if supported. -var BlockstoreMovingGC = blockstoreMovingGCKey{} +// BlockstoreGCOptions is a struct with GC options +type BlockstoreGCOptions struct { + FullGC bool +} -// BlockstoreMovingGCPath is a garbage collection option that specifies an optional -// target path for moving GC. -var BlockstoreMovingGCPath = blockstoreMovingGCPath{} +func WithFullGC(fullgc bool) BlockstoreGCOption { + return func(opts *BlockstoreGCOptions) error { + opts.FullGC = fullgc + return nil + } +} // BlockstoreSize is a trait for on-disk blockstores that can report their size type BlockstoreSize interface {