Compare commits

...

3 Commits

5 changed files with 88 additions and 27 deletions

View File

@ -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.

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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