Initial commit: bolt, map, leveldb support and test

master
Bel LaPointe 2019-03-13 14:06:46 -06:00
commit 8a1cf7104c
7 changed files with 220 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.*.go
vendor
*.swp
*.swo

44
bolt.go Normal file
View File

@ -0,0 +1,44 @@
package storage
import "github.com/boltdb/bolt"
type Bolt struct {
db *bolt.DB
}
func NewBolt(path string) (*Bolt, error) {
db, err := bolt.Open(path, 0600, nil)
return &Bolt{
db: db,
}, err
}
func (b *Bolt) Get(key string) ([]byte, error) {
var result []byte
err := b.db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket([]byte(DefaultNamespace))
if bkt == nil {
return ErrNotFound
}
result = bkt.Get([]byte(key))
if result == nil {
return ErrNotFound
}
return nil
})
return result, err
}
func (b *Bolt) Set(key string, value []byte) error {
return b.db.Update(func(tx *bolt.Tx) error {
bkt, err := tx.CreateBucketIfNotExists([]byte(DefaultNamespace))
if err != nil {
return err
}
return bkt.Put([]byte(key), value)
})
}
func (b *Bolt) Close() error {
return b.db.Close()
}

9
db.go Normal file
View File

@ -0,0 +1,9 @@
package storage
type DB interface {
Get(string) ([]byte, error)
Set(string, []byte) error
Close() error
}
var DefaultNamespace = "namespace"

62
db_test.go Normal file
View File

@ -0,0 +1,62 @@
package storage
import (
"bytes"
"io/ioutil"
"os"
"path"
"testing"
)
type mock struct {
m map[string][]byte
}
func (mock *mock) Get(key string) ([]byte, error) {
v, ok := mock.m[key]
if ok {
return v, nil
}
return nil, ErrNotFound
}
func (mock *mock) Set(key string, value []byte) error {
mock.m[key] = value
return nil
}
func (mock *mock) Close() error {
return nil
}
func TestImplementations(t *testing.T) {
dir, err := ioutil.TempDir("", "storage_tests_")
if err != nil {
t.Fatalf("cannot create temp dir: %v", err)
return
}
defer os.RemoveAll(dir)
bolt, _ := NewBolt(path.Join(dir, "bolt"))
leveldb, _ := NewLevelDB(path.Join(dir, "leveldb"))
cases := []DB{
&mock{m: make(map[string][]byte)},
NewMap(),
bolt,
leveldb,
}
validKey := "key"
validValue := []byte("value")
for _, db := range cases {
if err := db.Set(validKey, validValue); err != nil {
t.Fatalf("cannot set %T: %v", db, err)
}
if v, err := db.Get(validKey); err != nil {
t.Fatalf("cannot get %T: %v", db, err)
} else if !bytes.Equal(v, validValue) {
t.Fatalf("wrong get %T: %q vs %q", db, v, validValue)
}
}
}

7
errors.go Normal file
View File

@ -0,0 +1,7 @@
package storage
import "errors"
var ErrNotFound = errors.New("not found")
var ErrNotImpl = errors.New("not implemented")

47
leveldb.go Normal file
View File

@ -0,0 +1,47 @@
package storage
import (
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/filter"
"github.com/syndtr/goleveldb/leveldb/opt"
)
type LevelDB struct {
db *leveldb.DB
}
func NewLevelDB(path string) (*LevelDB, error) {
db, err := leveldb.OpenFile(path, &opt.Options{
Filter: filter.NewBloomFilter(32),
})
return &LevelDB{
db: db,
}, err
}
func (ldb *LevelDB) Get(key string) ([]byte, error) {
snapshot, err := ldb.db.GetSnapshot()
if err != nil {
return nil, err
}
defer snapshot.Release()
v, err := snapshot.Get([]byte(key), nil)
if err == leveldb.ErrNotFound {
err = ErrNotFound
} else if err != nil {
return nil, err
}
return v, err
}
func (ldb *LevelDB) Set(key string, value []byte) error {
batch := &leveldb.Batch{}
batch.Put([]byte(key), value)
return ldb.db.Write(batch, nil)
}
func (ldb *LevelDB) Close() error {
return ldb.db.Close()
}

47
map.go Normal file
View File

@ -0,0 +1,47 @@
package storage
import (
"fmt"
)
type Map map[string][]byte
func NewMap() Map {
m := make(map[string][]byte)
n := Map(m)
return n
}
func (m Map) String() string {
s := ""
for k, v := range m {
if s != "" {
s += ",\n"
}
s += fmt.Sprintf("[%s]:[%s]", k, v)
}
return s
}
func (m Map) Close() error {
m = nil
return nil
}
func (m Map) Get(key string) ([]byte, error) {
if _, ok := m[key]; !ok {
return nil, ErrNotFound
}
return m[key], nil
}
func (m Map) Set(key string, value []byte) error {
if value == nil {
if _, ok := m[key]; ok {
delete(m, key)
}
return nil
}
m[key] = value
return nil
}