Refactor: prep for adding pogreb by implementing interfaces
This commit is contained in:
parent
ff39591cbe
commit
c2d7ae8d3e
@ -2,6 +2,8 @@ package bitcask
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@ -119,9 +121,16 @@ func (db *DB) With(storeName string) database.Store {
|
||||
}
|
||||
|
||||
// WithNew calls the given underlying bitcask instance, if it doesn't exist, it creates it.
|
||||
func (db *DB) WithNew(storeName string) database.Filer {
|
||||
func (db *DB) WithNew(storeName string, opts ...any) database.Filer {
|
||||
db.mu.RLock()
|
||||
defer db.mu.RUnlock()
|
||||
for _, opt := range opts {
|
||||
if _, ok := opt.(bitcask.Option); !ok {
|
||||
fmt.Println("invalid bitcask option type: ", opt)
|
||||
continue
|
||||
}
|
||||
defaultBitcaskOptions = append(defaultBitcaskOptions, opt.(bitcask.Option))
|
||||
}
|
||||
d, ok := db.store[storeName]
|
||||
if ok {
|
||||
return d
|
||||
@ -132,6 +141,7 @@ func (db *DB) WithNew(storeName string) database.Filer {
|
||||
if err == nil {
|
||||
return db.store[storeName]
|
||||
}
|
||||
fmt.Println("error creating bitcask store: ", err)
|
||||
return Store{Bitcask: nil}
|
||||
}
|
||||
|
||||
@ -184,7 +194,11 @@ func (db *DB) withAll(action withAllAction) error {
|
||||
}
|
||||
switch action {
|
||||
case dclose:
|
||||
err = namedErr(name, store.Close())
|
||||
closeErr := store.Close()
|
||||
if errors.Is(closeErr, fs.ErrClosed) {
|
||||
continue
|
||||
}
|
||||
err = namedErr(name, closeErr)
|
||||
case dsync:
|
||||
err = namedErr(name, store.Sync())
|
||||
default:
|
||||
|
@ -3,14 +3,18 @@ package bitcask
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
c "git.tcp.direct/kayos/common/entropy"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
|
||||
"git.tcp.direct/tcp.direct/database"
|
||||
)
|
||||
|
||||
func newTestDB(t *testing.T) *DB {
|
||||
func newTestDB(t *testing.T) database.Keeper {
|
||||
t.Helper()
|
||||
tpath := t.TempDir()
|
||||
tdb := OpenDB(tpath)
|
||||
@ -20,11 +24,12 @@ func newTestDB(t *testing.T) *DB {
|
||||
return tdb
|
||||
}
|
||||
|
||||
func seedRandKV(db *DB, store string) error {
|
||||
func seedRandKV(db database.Keeper, store string) error {
|
||||
return db.With(store).Put([]byte(c.RandStr(55)), []byte(c.RandStr(55)))
|
||||
}
|
||||
|
||||
func seedRandStores(db *DB, t *testing.T) {
|
||||
func seedRandStores(db database.Keeper, t *testing.T) {
|
||||
t.Helper()
|
||||
for n := 0; n != 5; n++ {
|
||||
randstore := c.RandStr(5)
|
||||
err := db.Init(randstore)
|
||||
@ -130,10 +135,10 @@ func TestDB_Init(t *testing.T) { //nolint:funlen,gocognit,cyclop
|
||||
}
|
||||
})
|
||||
t.Run("syncAllShouldFail", func(t *testing.T) {
|
||||
db.store["wtf"] = Store{}
|
||||
db.(*DB).store["wtf"] = Store{}
|
||||
t.Cleanup(func() {
|
||||
t.Logf("deleting bogus store map entry")
|
||||
delete(db.store, "wtf")
|
||||
delete(db.(*DB).store, "wtf")
|
||||
})
|
||||
err := db.SyncAll()
|
||||
if err == nil {
|
||||
@ -179,7 +184,7 @@ func Test_Sync(t *testing.T) {
|
||||
var db = newTestDB(t)
|
||||
seedRandStores(db, t)
|
||||
t.Run("Sync", func(t *testing.T) {
|
||||
for d := range db.store {
|
||||
for d := range db.(*DB).store {
|
||||
err := db.With(d).Sync()
|
||||
if err != nil {
|
||||
t.Errorf("[FAIL] failed to sync %s: %e", d, err)
|
||||
@ -198,23 +203,23 @@ func Test_Close(t *testing.T) {
|
||||
seedRandStores(db, t)
|
||||
var oldstores []string
|
||||
t.Run("Close", func(t *testing.T) {
|
||||
for d := range db.store {
|
||||
for d := range db.AllStores() {
|
||||
oldstores = append(oldstores, d)
|
||||
err := db.Close(d)
|
||||
if err != nil {
|
||||
t.Fatalf("[FAIL] failed to close %s: %e", d, err)
|
||||
} else {
|
||||
t.Logf("[+] Close() successful for %s", d)
|
||||
t.Fatalf("[FAIL] failed to close %s: %v", d, err)
|
||||
}
|
||||
t.Logf("[+] Close() successful for %s", d)
|
||||
}
|
||||
})
|
||||
t.Run("AssureClosed", func(t *testing.T) {
|
||||
for _, d := range oldstores {
|
||||
if st := db.With(d); st != nil {
|
||||
t.Fatalf("[FAIL] store %s should have been deleted", d)
|
||||
t.Run("AssureClosed", func(t *testing.T) {
|
||||
for _, d := range oldstores {
|
||||
if st := db.With(d); st != nil {
|
||||
spew.Dump(st)
|
||||
t.Errorf("[FAIL] store %s should have been deleted", d)
|
||||
}
|
||||
}
|
||||
}
|
||||
t.Logf("[SUCCESS] Confirmed that all stores have been closed")
|
||||
t.Logf("[SUCCESS] Confirmed that all stores have been closed")
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("CantCloseBogusStore", func(t *testing.T) {
|
||||
@ -227,27 +232,34 @@ func Test_Close(t *testing.T) {
|
||||
|
||||
func Test_withAll(t *testing.T) {
|
||||
var db = newTestDB(t)
|
||||
defer db.CloseAll()
|
||||
asdf1 := c.RandStr(10)
|
||||
asdf2 := c.RandStr(10)
|
||||
|
||||
defer func() {
|
||||
if err := db.CloseAll(); err != nil && !errors.Is(err, fs.ErrClosed) {
|
||||
t.Errorf("[FAIL] failed to close all stores: %v", err)
|
||||
}
|
||||
}()
|
||||
t.Run("withAllNoStores", func(t *testing.T) {
|
||||
err := db.withAll(121)
|
||||
err := db.(*DB).withAll(121)
|
||||
if !errors.Is(err, ErrNoStores) {
|
||||
t.Errorf("[FAIL] got err %e, wanted err %e", err, ErrNoStores)
|
||||
}
|
||||
})
|
||||
t.Run("withAllNilMap", func(t *testing.T) {
|
||||
nilDb := newTestDB(t)
|
||||
nilDb.store = nil
|
||||
err := nilDb.withAll(dclose)
|
||||
nilDb.(*DB).store = nil
|
||||
err := nilDb.(*DB).withAll(dclose)
|
||||
if err == nil {
|
||||
t.Errorf("[FAIL] got nil err from trying to work on nil map, wanted err")
|
||||
}
|
||||
})
|
||||
t.Run("withAllBogusAction", func(t *testing.T) {
|
||||
err := db.Init("asdf")
|
||||
err := db.Init(asdf1)
|
||||
if err != nil {
|
||||
t.Errorf("[FAIL] unexpected error: %e", err)
|
||||
}
|
||||
wAllErr := db.withAll(121)
|
||||
wAllErr := db.(*DB).withAll(121)
|
||||
if !errors.Is(wAllErr, ErrUnknownAction) {
|
||||
t.Errorf("[FAIL] wanted error %e, got error %e", ErrUnknownAction, err)
|
||||
}
|
||||
@ -266,20 +278,20 @@ func Test_withAll(t *testing.T) {
|
||||
}
|
||||
t.Logf("[+] found store named %s: %v", n, s)
|
||||
}
|
||||
if len(allStores) != len(db.store) {
|
||||
t.Errorf("[FAIL] found %d stores, expected %d", len(allStores), len(db.store))
|
||||
if len(allStores) != len(db.(*DB).store) {
|
||||
t.Errorf("[FAIL] found %d stores, expected %d", len(allStores), len(db.(*DB).store))
|
||||
}
|
||||
})
|
||||
t.Run("ListAllAndInteract", func(t *testing.T) {
|
||||
err := db.Init("asdf2")
|
||||
err := db.Init(asdf2)
|
||||
if err != nil {
|
||||
t.Errorf("[FAIL] unexpected error: %e", err)
|
||||
}
|
||||
err = db.With("asdf").Put([]byte("asdf"), []byte("asdf"))
|
||||
err = db.With(asdf1).Put([]byte("asdf"), []byte("asdf"))
|
||||
if err != nil {
|
||||
t.Errorf("[FAIL] unexpected error: %e", err)
|
||||
}
|
||||
err = db.With("asdf2").Put([]byte("asdf2"), []byte("asdf2"))
|
||||
err = db.With(asdf2).Put([]byte("asdf"), []byte("asdf"))
|
||||
if err != nil {
|
||||
t.Errorf("[FAIL] unexpected error: %e", err)
|
||||
}
|
||||
@ -294,19 +306,19 @@ func Test_withAll(t *testing.T) {
|
||||
if s == nil {
|
||||
t.Errorf("[FAIL] store is nil")
|
||||
}
|
||||
if len(db.store) != 2 {
|
||||
t.Errorf("[SANITY FAIL] found %d stores, expected %d", len(allStores), len(db.store))
|
||||
if len(db.(*DB).store) != 2 {
|
||||
t.Errorf("[SANITY FAIL] found %d stores, expected %d", len(allStores), len(db.(*DB).store))
|
||||
}
|
||||
t.Logf("[+] found store named %s: %v", n, s)
|
||||
if len(allStores) != len(db.store) {
|
||||
t.Errorf("[FAIL] found %d stores, expected %d", len(allStores), len(db.store))
|
||||
if len(allStores) != len(db.(*DB).store) {
|
||||
t.Errorf("[FAIL] found %d stores, expected %d", len(allStores), len(db.(*DB).store))
|
||||
}
|
||||
var res []byte
|
||||
res, err = db.With(n).Get([]byte(n))
|
||||
res, err = db.With(n).Get([]byte("asdf"))
|
||||
if err != nil {
|
||||
t.Errorf("[FAIL] unexpected error: %e", err)
|
||||
t.Errorf("[FAIL] unexpected error: %v", err)
|
||||
}
|
||||
if !bytes.Equal(res, []byte(n)) {
|
||||
if !bytes.Equal(res, []byte("asdf")) {
|
||||
t.Errorf("[FAIL] expected %s, got %s", n, res)
|
||||
} else {
|
||||
t.Logf("[+] found %s in store %s", res, n)
|
||||
@ -314,14 +326,12 @@ func Test_withAll(t *testing.T) {
|
||||
}
|
||||
})
|
||||
t.Run("WithAllIncludingBadStore", func(t *testing.T) {
|
||||
db.store["yeeterson"] = Store{}
|
||||
err := db.withAll(dclose)
|
||||
if err != nil {
|
||||
t.Logf(err.Error())
|
||||
}
|
||||
db.(*DB).store["yeeterson"] = Store{}
|
||||
err := db.(*DB).withAll(dclose)
|
||||
if err == nil {
|
||||
t.Errorf("[FAIL] got nil err, wanted any error")
|
||||
}
|
||||
delete(db.(*DB).store, "yeeterson")
|
||||
})
|
||||
}
|
||||
|
||||
|
4
go.mod
4
go.mod
@ -4,7 +4,7 @@ go 1.18
|
||||
|
||||
require (
|
||||
git.tcp.direct/Mirrors/bitcask-mirror v0.0.0-20220228092422-1ec4297c7e34
|
||||
git.tcp.direct/kayos/common v0.8.2
|
||||
git.tcp.direct/kayos/common v0.8.6
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
)
|
||||
@ -17,6 +17,6 @@ require (
|
||||
github.com/plar/go-adaptive-radix-tree v1.0.4 // indirect
|
||||
github.com/rs/zerolog v1.26.1 // indirect
|
||||
golang.org/x/exp v0.0.0-20200228211341-fcea875c7e85 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
nullprogram.com/x/rng v1.1.0 // indirect
|
||||
)
|
||||
|
3
go.sum
3
go.sum
@ -41,6 +41,8 @@ git.tcp.direct/Mirrors/bitcask-mirror v0.0.0-20220228092422-1ec4297c7e34 h1:tvoL
|
||||
git.tcp.direct/Mirrors/bitcask-mirror v0.0.0-20220228092422-1ec4297c7e34/go.mod h1:NX/Gqm/iy6Tg2CfcmmB/kW/qzKKrGR6o2koOKA5KWnc=
|
||||
git.tcp.direct/kayos/common v0.8.2 h1:Usev4zpFLRFGTjQ+5vhReYSS/3+XGOgYbVufIWqMMW8=
|
||||
git.tcp.direct/kayos/common v0.8.2/go.mod h1:1XroljMDSTRybzyFGPTxs0gVb45YtH7wcehelU4koW8=
|
||||
git.tcp.direct/kayos/common v0.8.6 h1:lt8nv+PrgAcbiOnbKUt7diza5hifR5fV3un6uIp/YVc=
|
||||
git.tcp.direct/kayos/common v0.8.6/go.mod h1:QGGn7d2l4xBG7Cs/g84JzItPpHWjtfiyy+PSMnf6TzE=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
@ -488,6 +490,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -10,9 +10,15 @@ type Keeper interface {
|
||||
// With provides access to the given dataStore by providing a pointer to the related Filer.
|
||||
With(name string) Store
|
||||
|
||||
// WithNew should initialize a new Filer at the given path.
|
||||
WithNew(name string, options ...any) Filer
|
||||
|
||||
AllStores() map[string]Filer
|
||||
// TODO: Backups
|
||||
|
||||
Close(name string) error
|
||||
|
||||
CloseAll() error
|
||||
SyncAll() error
|
||||
SyncAndCloseAll() error
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user