Initial commit: bolt, map, leveldb support and test
commit
8a1cf7104c
|
|
@ -0,0 +1,4 @@
|
||||||
|
.*.go
|
||||||
|
vendor
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package storage
|
||||||
|
|
||||||
|
type DB interface {
|
||||||
|
Get(string) ([]byte, error)
|
||||||
|
Set(string, []byte) error
|
||||||
|
Close() error
|
||||||
|
}
|
||||||
|
|
||||||
|
var DefaultNamespace = "namespace"
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var ErrNotFound = errors.New("not found")
|
||||||
|
|
||||||
|
var ErrNotImpl = errors.New("not implemented")
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue