refactor store, reduce code

This commit is contained in:
siddontang 2014-08-16 00:08:01 +08:00
parent 22161f91ba
commit 09e49ca346
30 changed files with 158 additions and 329 deletions

View File

@ -1,12 +1,12 @@
# LedisDB # LedisDB
Ledisdb is a high performance NoSQL like Redis written by go. It supports some advanced data structure like kv, list, hash, zset, bitmap,set, and may be alternative for Redis. Ledisdb is a high performance NoSQL like Redis written by go. It supports some data structure like kv, list, hash, zset, bitmap,set, and may be alternative for Redis.
LedisDB now supports multiple databases as backend to store data, you can test and choose the proper one for you. LedisDB now supports multiple databases as backend to store data, you can test and choose the proper one for you.
## Features ## Features
+ Rich advanced data structure: KV, List, Hash, ZSet, Bitmap, Set. + Rich data structure: KV, List, Hash, ZSet, Bitmap, Set.
+ Stores lots of data, over the memory limit. + Stores lots of data, over the memory limit.
+ Various backend database to use: LevelDB, goleveldb, LMDB, RocksDB, BoltDB, HyperLevelDB. + Various backend database to use: LevelDB, goleveldb, LMDB, RocksDB, BoltDB, HyperLevelDB.
+ Supports expiration and ttl. + Supports expiration and ttl.

View File

@ -1,11 +0,0 @@
// +build !windows
package store
import (
"github.com/siddontang/ledisdb/store/boltdb"
)
func init() {
Register(boltdb.Store{})
}

3
store/boltdb/const.go Normal file
View File

@ -0,0 +1,3 @@
package boltdb
const DBName = "boltdb"

View File

@ -14,7 +14,7 @@ type Store struct {
} }
func (s Store) String() string { func (s Store) String() string {
return "boltdb" return DBName
} }
func (s Store) Open(dbPath string, cfg *config.Config) (driver.IDB, error) { func (s Store) Open(dbPath string, cfg *config.Config) (driver.IDB, error) {
@ -150,3 +150,7 @@ func (db *DB) BatchPut(writes []driver.Write) error {
}) })
return err return err
} }
func init() {
driver.Register(Store{})
}

View File

@ -1,39 +0,0 @@
package store
import (
"github.com/siddontang/ledisdb/config"
"os"
"testing"
)
func newTestBoltDB() *DB {
cfg := new(config.Config)
cfg.DBName = "boltdb"
cfg.DataDir = "/tmp/testdb"
os.RemoveAll(getStorePath(cfg))
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()
}

45
store/driver/store.go Normal file
View File

@ -0,0 +1,45 @@
package driver
import (
"fmt"
"github.com/siddontang/ledisdb/config"
)
type Store interface {
String() string
Open(path string, cfg *config.Config) (IDB, error)
Repair(paht string, cfg *config.Config) error
}
var dbs = map[string]Store{}
func Register(s Store) {
name := s.String()
if _, ok := dbs[name]; ok {
panic(fmt.Errorf("store %s is registered", s))
}
dbs[name] = s
}
func ListStores() []string {
s := []string{}
for k, _ := range dbs {
s = append(s, k)
}
return s
}
func GetStore(cfg *config.Config) (Store, error) {
if len(cfg.DBName) == 0 {
cfg.DBName = config.DefaultDBName
}
s, ok := dbs[cfg.DBName]
if !ok {
return nil, fmt.Errorf("store %s is not registered", cfg.DBName)
}
return s, nil
}

View File

@ -1,9 +0,0 @@
package store
import (
"github.com/siddontang/ledisdb/store/goleveldb"
)
func init() {
Register(goleveldb.Store{})
}

3
store/goleveldb/const.go Normal file
View File

@ -0,0 +1,3 @@
package goleveldb
const DBName = "goleveldb"

View File

@ -17,7 +17,7 @@ type Store struct {
} }
func (s Store) String() string { func (s Store) String() string {
return "goleveldb" return DBName
} }
type DB struct { type DB struct {
@ -136,3 +136,7 @@ func (db *DB) NewIterator() driver.IIterator {
func (db *DB) Begin() (driver.Tx, error) { func (db *DB) Begin() (driver.Tx, error) {
return nil, driver.ErrTxSupport return nil, driver.ErrTxSupport
} }
func init() {
driver.Register(Store{})
}

View File

@ -1,32 +0,0 @@
package store
import (
"github.com/siddontang/ledisdb/config"
"os"
"testing"
)
func newTestGoLevelDB() *DB {
cfg := new(config.Config)
cfg.DBName = "goleveldb"
cfg.DataDir = "/tmp/testdb"
os.RemoveAll(getStorePath(cfg))
db, err := Open(cfg)
if err != nil {
println(err.Error())
panic(err)
}
return db
}
func TestGoLevelDB(t *testing.T) {
db := newTestGoLevelDB()
testStore(db, t)
db.Close()
}

View File

@ -1,11 +0,0 @@
// +build hyperleveldb
package store
import (
"github.com/siddontang/ledisdb/store/hyperleveldb"
)
func init() {
Register(hyperleveldb.Store{})
}

View File

@ -0,0 +1,3 @@
package hyperleveldb
const DBName = "hyperleveldb"

View File

@ -24,7 +24,7 @@ type Store struct {
} }
func (s Store) String() string { func (s Store) String() string {
return "hyperleveldb" return Name
} }
func (s Store) Open(path string, cfg *config.Config) (driver.IDB, error) { func (s Store) Open(path string, cfg *config.Config) (driver.IDB, error) {
@ -257,3 +257,7 @@ func (db *DB) delete(wo *WriteOptions, key []byte) error {
func (db *DB) Begin() (driver.Tx, error) { func (db *DB) Begin() (driver.Tx, error) {
return nil, driver.ErrTxSupport return nil, driver.ErrTxSupport
} }
func init() {
driver.Register(Store{})
}

View File

@ -1,33 +0,0 @@
// +build hyperleveldb
package store
import (
"github.com/siddontang/ledisdb/config"
"os"
"testing"
)
func newTestHyperLevelDB() *DB {
cfg := new(config.Config)
cfg.DBName = "hyperleveldb"
cfg.DataDir = "/tmp/testdb"
os.RemoveAll(getStorePath(cfg))
db, err := Open(cfg)
if err != nil {
println(err.Error())
panic(err)
}
return db
}
func TestHyperLevelDB(t *testing.T) {
db := newTestHyperLevelDB()
testStore(db, t)
db.Close()
}

View File

@ -1,11 +0,0 @@
// +build leveldb
package store
import (
"github.com/siddontang/ledisdb/store/leveldb"
)
func init() {
Register(leveldb.Store{})
}

3
store/leveldb/const.go Normal file
View File

@ -0,0 +1,3 @@
package leveldb
const DBName = "leveldb"

View File

@ -24,7 +24,7 @@ type Store struct {
} }
func (s Store) String() string { func (s Store) String() string {
return "leveldb" return DBName
} }
func (s Store) Open(path string, cfg *config.Config) (driver.IDB, error) { func (s Store) Open(path string, cfg *config.Config) (driver.IDB, error) {
@ -257,3 +257,7 @@ func (db *DB) delete(wo *WriteOptions, key []byte) error {
func (db *DB) Begin() (driver.Tx, error) { func (db *DB) Begin() (driver.Tx, error) {
return nil, driver.ErrTxSupport return nil, driver.ErrTxSupport
} }
func init() {
driver.Register(Store{})
}

View File

@ -1,34 +0,0 @@
// +build leveldb
package store
import (
"github.com/siddontang/ledisdb/config"
"os"
"testing"
)
func newTestLevelDB() *DB {
cfg := new(config.Config)
cfg.DBName = "leveldb"
cfg.DataDir = "/tmp/testdb"
os.RemoveAll(getStorePath(cfg))
db, err := Open(cfg)
if err != nil {
println(err.Error())
panic(err)
}
return db
}
func TestLevelDB(t *testing.T) {
db := newTestLevelDB()
testStore(db, t)
db.Close()
}

View File

@ -1,10 +0,0 @@
// +build !windows
package store
import (
"github.com/siddontang/ledisdb/store/mdb"
)
func init() {
Register(mdb.Store{})
}

3
store/mdb/const.go Normal file
View File

@ -0,0 +1,3 @@
package mdb
const DBName = "lmdb"

View File

@ -1,3 +1,5 @@
// +build !windows
package mdb package mdb
import ( import (
@ -11,7 +13,7 @@ type Store struct {
} }
func (s Store) String() string { func (s Store) String() string {
return "lmdb" return DBName
} }
type MDB struct { type MDB struct {
@ -275,3 +277,7 @@ func (db MDB) NewWriteBatch() driver.IWriteBatch {
func (db MDB) Begin() (driver.Tx, error) { func (db MDB) Begin() (driver.Tx, error) {
return newTx(db) return newTx(db)
} }
func init() {
driver.Register(Store{})
}

View File

@ -1,3 +1,5 @@
// +build !windows
package mdb package mdb
import ( import (

View File

@ -1,43 +0,0 @@
// +build !windows
package store
import (
"github.com/siddontang/ledisdb/config"
"os"
"testing"
)
func newTestLMDB() *DB {
cfg := new(config.Config)
cfg.DBName = "lmdb"
cfg.DataDir = "/tmp/testdb"
cfg.LMDB.MapSize = 10 * 1024 * 1024
os.RemoveAll(getStorePath(cfg))
db, err := Open(cfg)
if err != nil {
println(err.Error())
panic(err)
}
return db
}
func TestLMDB(t *testing.T) {
db := newTestLMDB()
testStore(db, t)
db.Close()
}
func TestLMDBTx(t *testing.T) {
db := newTestLMDB()
testTx(db, t)
db.Close()
}

View File

@ -1,11 +0,0 @@
// +build rocksdb
package store
import (
"github.com/siddontang/ledisdb/store/rocksdb"
)
func init() {
Register(rocksdb.Store{})
}

3
store/rocksdb/const.go Normal file
View File

@ -0,0 +1,3 @@
package rocksdb
const DBName = "rocksdb"

View File

@ -25,7 +25,7 @@ type Store struct {
} }
func (s Store) String() string { func (s Store) String() string {
return "rocksdb" return DBName
} }
func (s Store) Open(path string, cfg *config.Config) (driver.IDB, error) { func (s Store) Open(path string, cfg *config.Config) (driver.IDB, error) {
@ -274,3 +274,7 @@ func (db *DB) delete(wo *WriteOptions, key []byte) error {
func (db *DB) Begin() (driver.Tx, error) { func (db *DB) Begin() (driver.Tx, error) {
return nil, driver.ErrTxSupport return nil, driver.ErrTxSupport
} }
func init() {
driver.Register(Store{})
}

View File

@ -1,34 +0,0 @@
// +build rocksdb
package store
import (
"github.com/siddontang/ledisdb/config"
"os"
"testing"
)
func newTestRocksDB() *DB {
cfg := new(config.Config)
cfg.DBName = "rocksdb"
cfg.DataDir = "/tmp/testdb"
os.RemoveAll(getStorePath(cfg))
db, err := Open(cfg)
if err != nil {
println(err.Error())
panic(err)
}
return db
}
func TestRocksDB(t *testing.T) {
db := newTestRocksDB()
testStore(db, t)
db.Close()
}

View File

@ -6,55 +6,21 @@ import (
"github.com/siddontang/ledisdb/store/driver" "github.com/siddontang/ledisdb/store/driver"
"os" "os"
"path" "path"
"github.com/siddontang/ledisdb/store/boltdb"
"github.com/siddontang/ledisdb/store/goleveldb"
"github.com/siddontang/ledisdb/store/hyperleveldb"
"github.com/siddontang/ledisdb/store/leveldb"
"github.com/siddontang/ledisdb/store/mdb"
"github.com/siddontang/ledisdb/store/rocksdb"
) )
type Config config.Config
type Store interface {
String() string
Open(path string, cfg *config.Config) (driver.IDB, error)
Repair(paht string, cfg *config.Config) error
}
var dbs = map[string]Store{}
func Register(s Store) {
name := s.String()
if _, ok := dbs[name]; ok {
panic(fmt.Errorf("store %s is registered", s))
}
dbs[name] = s
}
func ListStores() []string {
s := []string{}
for k, _ := range dbs {
s = append(s, k)
}
return s
}
func getStore(cfg *config.Config) (Store, error) {
if len(cfg.DBName) == 0 {
cfg.DBName = config.DefaultDBName
}
s, ok := dbs[cfg.DBName]
if !ok {
return nil, fmt.Errorf("store %s is not registered", cfg.DBName)
}
return s, nil
}
func getStorePath(cfg *config.Config) string { func getStorePath(cfg *config.Config) string {
return path.Join(cfg.DataDir, fmt.Sprintf("%s_data", cfg.DBName)) return path.Join(cfg.DataDir, fmt.Sprintf("%s_data", cfg.DBName))
} }
func Open(cfg *config.Config) (*DB, error) { func Open(cfg *config.Config) (*DB, error) {
s, err := getStore(cfg) s, err := driver.GetStore(cfg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -76,7 +42,7 @@ func Open(cfg *config.Config) (*DB, error) {
} }
func Repair(cfg *config.Config) error { func Repair(cfg *config.Config) error {
s, err := getStore(cfg) s, err := driver.GetStore(cfg)
if err != nil { if err != nil {
return err return err
} }
@ -85,3 +51,12 @@ func Repair(cfg *config.Config) error {
return s.Repair(path, cfg) return s.Repair(path, cfg)
} }
func init() {
_ = boltdb.DBName
_ = goleveldb.DBName
_ = hyperleveldb.DBName
_ = leveldb.DBName
_ = mdb.DBName
_ = rocksdb.DBName
}

View File

@ -3,11 +3,34 @@ package store
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/siddontang/ledisdb/config"
"github.com/siddontang/ledisdb/store/driver"
"os"
"testing" "testing"
) )
func TestStore(t *testing.T) { func TestStore(t *testing.T) {
cfg := new(config.Config)
cfg.DataDir = "/tmp/testdb"
cfg.LMDB.MapSize = 10 * 1024 * 1024
ns := driver.ListStores()
for _, s := range ns {
cfg.DBName = s
os.RemoveAll(getStorePath(cfg))
db, err := Open(cfg)
if err != nil {
t.Fatal(err)
}
testStore(db, t)
testClear(db, t)
testTx(db, t)
db.Close()
}
} }
func testStore(db *DB, t *testing.T) { func testStore(db *DB, t *testing.T) {
@ -16,6 +39,13 @@ func testStore(db *DB, t *testing.T) {
testIterator(db, t) testIterator(db, t)
} }
func testClear(db *DB, t *testing.T) {
it := db.RangeIterator(nil, nil, RangeClose)
for ; it.Valid(); it.Next() {
db.Delete(it.RawKey())
}
}
func testSimple(db *DB, t *testing.T) { func testSimple(db *DB, t *testing.T) {
key := []byte("key") key := []byte("key")
value := []byte("hello world") value := []byte("hello world")

View File

@ -1,6 +1,7 @@
package store package store
import ( import (
"github.com/siddontang/ledisdb/store/driver"
"testing" "testing"
) )
@ -9,6 +10,16 @@ func TestTx(t *testing.T) {
} }
func testTx(db *DB, t *testing.T) { func testTx(db *DB, t *testing.T) {
if tx, err := db.Begin(); err != nil {
if err == driver.ErrTxSupport {
return
} else {
t.Fatal(err)
}
} else {
tx.Rollback()
}
key1 := []byte("1") key1 := []byte("1")
key2 := []byte("2") key2 := []byte("2")
key3 := []byte("3") key3 := []byte("3")