add boltdb support

This commit is contained in:
siddontang 2014-08-02 15:16:16 +08:00
parent 812ca13c81
commit a2fdea39c6
9 changed files with 337 additions and 7 deletions

32
store/boltdb.go Normal file
View File

@ -0,0 +1,32 @@
// +build !windows
package store
import (
"github.com/siddontang/copier"
"github.com/siddontang/ledisdb/store/boltdb"
"github.com/siddontang/ledisdb/store/driver"
)
const BoltDBName = "boltdb"
type BoltDBStore struct {
}
func (s BoltDBStore) Open(cfg *Config) (driver.IDB, error) {
c := &boltdb.Config{}
copier.Copy(c, cfg)
return boltdb.Open(c)
}
func (s BoltDBStore) Repair(cfg *Config) error {
c := &boltdb.Config{}
copier.Copy(c, cfg)
return boltdb.Repair(c)
}
func init() {
Register(BoltDBName, BoltDBStore{})
}

146
store/boltdb/db.go Normal file
View File

@ -0,0 +1,146 @@
package boltdb
import (
"github.com/boltdb/bolt"
"github.com/siddontang/ledisdb/store/driver"
"os"
"path"
)
var bucketName = []byte("ledisdb")
type Config struct {
Path string `json:"path"`
NoSync bool `json:"nosync"`
}
type DB struct {
cfg *Config
db *bolt.DB
}
func Open(cfg *Config) (*DB, error) {
os.MkdirAll(cfg.Path, os.ModePerm)
name := path.Join(cfg.Path, "ledis_bolt.db")
db := new(DB)
var err error
db.db, err = bolt.Open(name, 0600, nil)
if err != nil {
return nil, err
}
db.db.NoSync = cfg.NoSync
var tx *bolt.Tx
tx, err = db.db.Begin(true)
if err != nil {
return nil, err
}
_, err = tx.CreateBucketIfNotExists(bucketName)
if err != nil {
tx.Rollback()
return nil, err
}
if err = tx.Commit(); err != nil {
return nil, err
}
return db, nil
}
func Repair(cfg *Config) error {
return nil
}
func (db *DB) Close() error {
return db.db.Close()
}
func (db *DB) Get(key []byte) ([]byte, error) {
var value []byte
t, err := db.db.Begin(false)
if err != nil {
return nil, err
}
b := t.Bucket(bucketName)
value = b.Get(key)
err = t.Rollback()
if err != nil {
return nil, err
}
if value == nil {
return nil, nil
} else {
return append([]byte{}, value...), nil
}
}
func (db *DB) Put(key []byte, value []byte) error {
err := db.db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketName)
return b.Put(key, value)
})
return err
}
func (db *DB) Delete(key []byte) error {
err := db.db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketName)
return b.Delete(key)
})
return err
}
func (db *DB) NewIterator() driver.IIterator {
tx, err := db.db.Begin(false)
if err != nil {
return &Iterator{}
}
b := tx.Bucket(bucketName)
return &Iterator{
tx: tx,
it: b.Cursor()}
}
func (db *DB) NewWriteBatch() driver.IWriteBatch {
return driver.NewWriteBatch(db)
}
func (db *DB) Begin() (driver.Tx, error) {
tx, err := db.db.Begin(true)
if err != nil {
return nil, err
}
return &Tx{
tx: tx,
b: tx.Bucket(bucketName),
}, nil
}
func (db *DB) BatchPut(writes []driver.Write) error {
err := db.db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket(bucketName)
var err error
for _, w := range writes {
if w.Value == nil {
err = b.Delete(w.Key)
} else {
err = b.Put(w.Key, w.Value)
}
if err != nil {
return err
}
}
return nil
})
return err
}

50
store/boltdb/iterator.go Normal file
View File

@ -0,0 +1,50 @@
package boltdb
import (
"github.com/boltdb/bolt"
)
type Iterator struct {
tx *bolt.Tx
it *bolt.Cursor
key []byte
value []byte
}
func (it *Iterator) Close() error {
if it.tx != nil {
return it.tx.Rollback()
} else {
return nil
}
}
func (it *Iterator) First() {
it.key, it.value = it.it.First()
}
func (it *Iterator) Last() {
it.key, it.value = it.it.Last()
}
func (it *Iterator) Seek(key []byte) {
it.key, it.value = it.it.Seek(key)
}
func (it *Iterator) Next() {
it.key, it.value = it.it.Next()
}
func (it *Iterator) Prev() {
it.key, it.value = it.it.Prev()
}
func (it *Iterator) Valid() bool {
return !(it.key == nil && it.value == nil)
}
func (it *Iterator) Key() []byte {
return it.key
}
func (it *Iterator) Value() []byte {
return it.value
}

57
store/boltdb/tx.go Normal file
View File

@ -0,0 +1,57 @@
package boltdb
import (
"github.com/boltdb/bolt"
"github.com/siddontang/ledisdb/store/driver"
)
type Tx struct {
tx *bolt.Tx
b *bolt.Bucket
}
func (t *Tx) Get(key []byte) ([]byte, error) {
return t.b.Get(key), nil
}
func (t *Tx) Put(key []byte, value []byte) error {
return t.b.Put(key, value)
}
func (t *Tx) Delete(key []byte) error {
return t.b.Delete(key)
}
func (t *Tx) NewIterator() driver.IIterator {
return &Iterator{
tx: nil,
it: t.b.Cursor(),
}
}
func (t *Tx) NewWriteBatch() driver.IWriteBatch {
return driver.NewWriteBatch(t)
}
func (t *Tx) BatchPut(writes []driver.Write) error {
var err error
for _, w := range writes {
if w.Value == nil {
err = t.b.Delete(w.Key)
} else {
err = t.b.Put(w.Key, w.Value)
}
if err != nil {
return err
}
}
return nil
}
func (t *Tx) Rollback() error {
return t.tx.Rollback()
}
func (t *Tx) Commit() error {
return t.tx.Commit()
}

38
store/boltdb_test.go Normal file
View File

@ -0,0 +1,38 @@
package store
import (
"os"
"testing"
)
func newTestBoltDB() *DB {
cfg := new(Config)
cfg.Name = BoltDBName
cfg.Path = "/tmp/testdb/boltdb"
os.RemoveAll(cfg.Path)
db, err := Open(cfg)
if err != nil {
println(err.Error())
panic(err)
}
return db
}
func TestBoltDB(t *testing.T) {
db := newTestBoltDB()
testStore(db, t)
db.Close()
}
func TestBoltDBTx(t *testing.T) {
db := newTestBoltDB()
testTx(db, t)
db.Close()
}

View File

@ -14,4 +14,7 @@ type Config struct {
//for lmdb //for lmdb
MapSize int `json:"map_size"` MapSize int `json:"map_size"`
//for boltdb
NoSync bool `json:"nosync"`
} }

View File

@ -1,6 +1,6 @@
package mdb package driver
type batchPut interface { type BatchPuter interface {
BatchPut([]Write) error BatchPut([]Write) error
} }
@ -10,7 +10,7 @@ type Write struct {
} }
type WriteBatch struct { type WriteBatch struct {
batch batchPut batch BatchPuter
wb []Write wb []Write
} }
@ -33,3 +33,7 @@ func (w *WriteBatch) Rollback() error {
w.wb = w.wb[0:0] w.wb = w.wb[0:0]
return nil return nil
} }
func NewWriteBatch(puter BatchPuter) IWriteBatch {
return &WriteBatch{puter, []Write{}}
}

View File

@ -85,7 +85,7 @@ func (db MDB) Put(key, value []byte) error {
return itr.Close() return itr.Close()
} }
func (db MDB) BatchPut(writes []Write) error { func (db MDB) BatchPut(writes []driver.Write) error {
itr := db.iterator(false) itr := db.iterator(false)
for _, w := range writes { for _, w := range writes {
@ -258,7 +258,7 @@ func (db MDB) NewIterator() driver.IIterator {
} }
func (db MDB) NewWriteBatch() driver.IWriteBatch { func (db MDB) NewWriteBatch() driver.IWriteBatch {
return &WriteBatch{&db, []Write{}} return driver.NewWriteBatch(db)
} }
func (db MDB) Begin() (driver.Tx, error) { func (db MDB) Begin() (driver.Tx, error) {

View File

@ -45,10 +45,10 @@ func (t *Tx) newIterator() *MDBIterator {
} }
func (t *Tx) NewWriteBatch() driver.IWriteBatch { func (t *Tx) NewWriteBatch() driver.IWriteBatch {
return &WriteBatch{t, []Write{}} return driver.NewWriteBatch(t)
} }
func (t *Tx) BatchPut(writes []Write) error { func (t *Tx) BatchPut(writes []driver.Write) error {
itr := t.newIterator() itr := t.newIterator()
for _, w := range writes { for _, w := range writes {