use functional options in the BlockstoreGC interface

This commit is contained in:
vyzo 2021-07-27 09:50:44 +03:00
parent 938330e6c3
commit 96c1123c33
3 changed files with 43 additions and 55 deletions

View File

@ -222,15 +222,14 @@ func (b *Blockstore) unlockMove(state int) {
b.moveMx.Unlock() b.moveMx.Unlock()
} }
// moveTo moves the blockstore to path, and creates a symlink from the current path // movingGC moves the blockstore to a new path, adjacent to the current path, and creates
// to the new path; the old blockstore is deleted. // 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
// 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, // are persisted to the new blockstore; if a failure occurs aboring the move,
// then they must be peristed to the old blockstore. // then they must be peristed to the old blockstore.
// In short, the blockstore must not lose data from new writes during the move. // 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 // this inlines moveLock/moveUnlock for the initial state check to prevent a second move
// while one is in progress without clobbering state // while one is in progress without clobbering state
b.moveMx.Lock() b.moveMx.Lock()
@ -248,9 +247,7 @@ func (b *Blockstore) moveTo(path string) error {
b.moveCond.Broadcast() b.moveCond.Broadcast()
b.moveMx.Unlock() 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() { defer func() {
b.lockMove() 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 { func (b *Blockstore) onlineGC() error {
b.lockDB() b.lockDB()
defer b.unlockDB() defer b.unlockDB()
@ -529,6 +493,29 @@ func (b *Blockstore) onlineGC() error {
return err 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 // Size returns the aggregate size of the blockstore
func (b *Blockstore) Size() (int64, error) { func (b *Blockstore) Size() (int64, error) {
if err := b.access(); err != nil { if err := b.access(); err != nil {

View File

@ -154,9 +154,7 @@ func testMove(t *testing.T, optsF func(string) Options) {
return nil return nil
}) })
g.Go(func() error { g.Go(func() error {
return db.CollectGarbage(map[interface{}]interface{}{ return db.CollectGarbage(blockstore.WithFullGC(true))
blockstore.BlockstoreMovingGC: true,
})
}) })
err = g.Wait() err = g.Wait()

View File

@ -37,20 +37,23 @@ type BlockstoreIterator interface {
// BlockstoreGC is a trait for blockstores that support online garbage collection // BlockstoreGC is a trait for blockstores that support online garbage collection
type BlockstoreGC interface { type BlockstoreGC interface {
CollectGarbage(options map[interface{}]interface{}) error CollectGarbage(options ...BlockstoreGCOption) error
} }
// garbage collection options // BlockstoreGCOption is a functional interface for controlling blockstore GC options
type blockstoreMovingGCKey struct{} type BlockstoreGCOption = func(*BlockstoreGCOptions) error
type blockstoreMovingGCPath struct{}
// BlockstoreMovingGC is a garbage collection option that instructs the blockstore // BlockstoreGCOptions is a struct with GC options
// to use moving GC if supported. type BlockstoreGCOptions struct {
var BlockstoreMovingGC = blockstoreMovingGCKey{} FullGC bool
}
// BlockstoreMovingGCPath is a garbage collection option that specifies an optional func WithFullGC(fullgc bool) BlockstoreGCOption {
// target path for moving GC. return func(opts *BlockstoreGCOptions) error {
var BlockstoreMovingGCPath = blockstoreMovingGCPath{} opts.FullGC = fullgc
return nil
}
}
// BlockstoreSize is a trait for on-disk blockstores that can report their size // BlockstoreSize is a trait for on-disk blockstores that can report their size
type BlockstoreSize interface { type BlockstoreSize interface {