Compare commits
3 Commits
c2d7ae8d3e
...
aed641de42
Author | SHA1 | Date | |
---|---|---|---|
aed641de42 | |||
509f844f49 | |||
0d6298995f |
@ -4,6 +4,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@ -51,6 +53,43 @@ func OpenDB(path string) *DB {
|
||||
}
|
||||
}
|
||||
|
||||
// Discover will discover and initialize all existing bitcask stores at the path opened by [OpenDB].
|
||||
func (db *DB) Discover() ([]string, error) {
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
stores := make([]string, 0)
|
||||
errs := make([]error, 0)
|
||||
if db.store == nil {
|
||||
db.store = make(map[string]Store)
|
||||
}
|
||||
entries, err := fs.ReadDir(os.DirFS(db.path), ".")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
name := entry.Name()
|
||||
if _, ok := db.store[name]; ok {
|
||||
continue
|
||||
}
|
||||
c, e := bitcask.Open(filepath.Join(db.path, name), defaultBitcaskOptions...)
|
||||
if e != nil {
|
||||
errs = append(errs, e)
|
||||
continue
|
||||
}
|
||||
db.store[name] = Store{Bitcask: c}
|
||||
stores = append(stores, name)
|
||||
}
|
||||
|
||||
for _, e := range errs {
|
||||
err = fmt.Errorf("%w: %w", err, e)
|
||||
}
|
||||
|
||||
return stores, err
|
||||
}
|
||||
|
||||
// Path returns the base path where we store our bitcask "stores".
|
||||
func (db *DB) Path() string {
|
||||
return db.path
|
||||
@ -138,11 +177,11 @@ func (db *DB) WithNew(storeName string, opts ...any) database.Filer {
|
||||
db.mu.RUnlock()
|
||||
err := db.Init(storeName)
|
||||
db.mu.RLock()
|
||||
if err == nil {
|
||||
return db.store[storeName]
|
||||
if err != nil {
|
||||
fmt.Println("error creating bitcask store: ", err)
|
||||
|
||||
}
|
||||
fmt.Println("error creating bitcask store: ", err)
|
||||
return Store{Bitcask: nil}
|
||||
return db.store[storeName]
|
||||
}
|
||||
|
||||
// Close is a simple shim for bitcask's Close function.
|
||||
|
@ -14,24 +14,26 @@ import (
|
||||
"git.tcp.direct/tcp.direct/database"
|
||||
)
|
||||
|
||||
func newTestDB(t *testing.T) database.Keeper {
|
||||
func newTestDB(t *testing.T) (string, database.Keeper) {
|
||||
t.Helper()
|
||||
tpath := t.TempDir()
|
||||
tdb := OpenDB(tpath)
|
||||
if tdb == nil {
|
||||
t.Fatalf("failed to open testdb at %s, got nil", tpath)
|
||||
}
|
||||
return tdb
|
||||
return tpath, tdb
|
||||
}
|
||||
|
||||
func seedRandKV(db database.Keeper, store string) error {
|
||||
return db.With(store).Put([]byte(c.RandStr(55)), []byte(c.RandStr(55)))
|
||||
}
|
||||
|
||||
func seedRandStores(db database.Keeper, t *testing.T) {
|
||||
func seedRandStores(db database.Keeper, t *testing.T) []string {
|
||||
t.Helper()
|
||||
names := make([]string, 0)
|
||||
for n := 0; n != 5; n++ {
|
||||
randstore := c.RandStr(5)
|
||||
names = append(names, randstore)
|
||||
err := db.Init(randstore)
|
||||
if err != nil {
|
||||
t.Errorf("failed to initialize store for test SyncAndCloseAll: %e", err)
|
||||
@ -42,10 +44,11 @@ func seedRandStores(db database.Keeper, t *testing.T) {
|
||||
}
|
||||
}
|
||||
t.Logf("seeded random stores with random values for test %s", t.Name())
|
||||
return names
|
||||
}
|
||||
|
||||
func TestDB_Init(t *testing.T) { //nolint:funlen,gocognit,cyclop
|
||||
var db = newTestDB(t)
|
||||
var _, db = newTestDB(t)
|
||||
type args struct{ storeName string }
|
||||
type test struct {
|
||||
name string
|
||||
@ -170,18 +173,36 @@ func TestDB_Init(t *testing.T) { //nolint:funlen,gocognit,cyclop
|
||||
db = nil
|
||||
})
|
||||
t.Run("SyncAndCloseAll", func(t *testing.T) {
|
||||
db = newTestDB(t)
|
||||
seedRandStores(db, t)
|
||||
var path string
|
||||
path, db = newTestDB(t)
|
||||
names := seedRandStores(db, t)
|
||||
err := db.SyncAndCloseAll()
|
||||
if err != nil {
|
||||
t.Errorf("[FAIL] failed to SyncAndCloseAll: %e", err)
|
||||
}
|
||||
db = OpenDB(path)
|
||||
found, err := db.(*DB).Discover()
|
||||
if err != nil {
|
||||
t.Errorf("[FAIL] failed to discover stores: %e", err)
|
||||
}
|
||||
for _, n := range names {
|
||||
matched := false
|
||||
for _, f := range found {
|
||||
if f == n {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
t.Errorf("[FAIL] failed to find store %s", n)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Sync(t *testing.T) {
|
||||
// TODO: make sure sync is ACTUALLY sycing instead of only checking for nil err...
|
||||
var db = newTestDB(t)
|
||||
var _, db = newTestDB(t)
|
||||
seedRandStores(db, t)
|
||||
t.Run("Sync", func(t *testing.T) {
|
||||
for d := range db.(*DB).store {
|
||||
@ -196,7 +217,7 @@ func Test_Sync(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Close(t *testing.T) {
|
||||
var db = newTestDB(t)
|
||||
var _, db = newTestDB(t)
|
||||
defer func() {
|
||||
db = nil
|
||||
}()
|
||||
@ -231,7 +252,7 @@ func Test_Close(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_withAll(t *testing.T) {
|
||||
var db = newTestDB(t)
|
||||
var _, db = newTestDB(t)
|
||||
asdf1 := c.RandStr(10)
|
||||
asdf2 := c.RandStr(10)
|
||||
|
||||
@ -247,7 +268,7 @@ func Test_withAll(t *testing.T) {
|
||||
}
|
||||
})
|
||||
t.Run("withAllNilMap", func(t *testing.T) {
|
||||
nilDb := newTestDB(t)
|
||||
_, nilDb := newTestDB(t)
|
||||
nilDb.(*DB).store = nil
|
||||
err := nilDb.(*DB).withAll(dclose)
|
||||
if err == nil {
|
||||
@ -473,7 +494,7 @@ func Test_WithOptions(t *testing.T) { //nolint:funlen,gocognit,cyclop
|
||||
}
|
||||
})
|
||||
t.Run("InitWithBogusOption", func(t *testing.T) {
|
||||
db := newTestDB(t)
|
||||
_, db := newTestDB(t)
|
||||
err := db.Init("bogus", "yeet")
|
||||
if err == nil {
|
||||
t.Errorf("[FAIL] Init should have failed with bogus option")
|
||||
|
7
go.mod
7
go.mod
@ -4,9 +4,10 @@ go 1.18
|
||||
|
||||
require (
|
||||
git.tcp.direct/Mirrors/bitcask-mirror v0.0.0-20220228092422-1ec4297c7e34
|
||||
git.tcp.direct/kayos/common v0.8.6
|
||||
git.tcp.direct/kayos/common v0.9.3
|
||||
github.com/akrylysov/pogreb v0.10.1
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/hashicorp/go-multierror v1.0.0
|
||||
)
|
||||
|
||||
require (
|
||||
@ -17,6 +18,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.8.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
nullprogram.com/x/rng v1.1.0 // indirect
|
||||
)
|
||||
|
16
go.sum
16
go.sum
@ -39,15 +39,15 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
git.tcp.direct/Mirrors/bitcask-mirror v0.0.0-20220228092422-1ec4297c7e34 h1:tvoLGGLsQ0IYKKQPweMF5qRm3qO4gcTpuzi9jAr3Wkk=
|
||||
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=
|
||||
git.tcp.direct/kayos/common v0.9.3 h1:MnQM4MH97zin+cloTsJRA3YEzagTGm/iR5sajpT+GoQ=
|
||||
git.tcp.direct/kayos/common v0.9.3/go.mod h1:tTqUGj50mpwoQD0Zsdsv6cpDzN9VfjnQMgpDC8aRfms=
|
||||
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=
|
||||
github.com/abcum/lcp v0.0.0-20201209214815-7a3f3840be81 h1:uHogIJ9bXH75ZYrXnVShHIyywFiUZ7OOabwd9Sfd8rw=
|
||||
github.com/abcum/lcp v0.0.0-20201209214815-7a3f3840be81/go.mod h1:6ZvnjTZX1LNo1oLpfaJK8h+MXqHxcBFBIwkgsv+xlv0=
|
||||
github.com/akrylysov/pogreb v0.10.1 h1:FqlR8VR7uCbJdfUob916tPM+idpKgeESDXOA1K0DK4w=
|
||||
github.com/akrylysov/pogreb v0.10.1/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
@ -182,9 +182,8 @@ github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
@ -488,9 +487,8 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.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=
|
||||
|
@ -13,6 +13,8 @@ type Keeper interface {
|
||||
// WithNew should initialize a new Filer at the given path.
|
||||
WithNew(name string, options ...any) Filer
|
||||
|
||||
Discover() ([]string, error)
|
||||
|
||||
AllStores() map[string]Filer
|
||||
// TODO: Backups
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user