forked from mirror/ledisdb
refactor store, reduce code
This commit is contained in:
parent
22161f91ba
commit
09e49ca346
|
@ -1,12 +1,12 @@
|
|||
# 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.
|
||||
|
||||
## 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.
|
||||
+ Various backend database to use: LevelDB, goleveldb, LMDB, RocksDB, BoltDB, HyperLevelDB.
|
||||
+ Supports expiration and ttl.
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
// +build !windows
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"github.com/siddontang/ledisdb/store/boltdb"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register(boltdb.Store{})
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package boltdb
|
||||
|
||||
const DBName = "boltdb"
|
|
@ -14,7 +14,7 @@ type Store struct {
|
|||
}
|
||||
|
||||
func (s Store) String() string {
|
||||
return "boltdb"
|
||||
return DBName
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func init() {
|
||||
driver.Register(Store{})
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"github.com/siddontang/ledisdb/store/goleveldb"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register(goleveldb.Store{})
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package goleveldb
|
||||
|
||||
const DBName = "goleveldb"
|
|
@ -17,7 +17,7 @@ type Store struct {
|
|||
}
|
||||
|
||||
func (s Store) String() string {
|
||||
return "goleveldb"
|
||||
return DBName
|
||||
}
|
||||
|
||||
type DB struct {
|
||||
|
@ -136,3 +136,7 @@ func (db *DB) NewIterator() driver.IIterator {
|
|||
func (db *DB) Begin() (driver.Tx, error) {
|
||||
return nil, driver.ErrTxSupport
|
||||
}
|
||||
|
||||
func init() {
|
||||
driver.Register(Store{})
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
// +build hyperleveldb
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"github.com/siddontang/ledisdb/store/hyperleveldb"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register(hyperleveldb.Store{})
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package hyperleveldb
|
||||
|
||||
const DBName = "hyperleveldb"
|
|
@ -24,7 +24,7 @@ type Store struct {
|
|||
}
|
||||
|
||||
func (s Store) String() string {
|
||||
return "hyperleveldb"
|
||||
return Name
|
||||
}
|
||||
|
||||
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) {
|
||||
return nil, driver.ErrTxSupport
|
||||
}
|
||||
|
||||
func init() {
|
||||
driver.Register(Store{})
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
// +build leveldb
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"github.com/siddontang/ledisdb/store/leveldb"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register(leveldb.Store{})
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package leveldb
|
||||
|
||||
const DBName = "leveldb"
|
|
@ -24,7 +24,7 @@ type Store struct {
|
|||
}
|
||||
|
||||
func (s Store) String() string {
|
||||
return "leveldb"
|
||||
return DBName
|
||||
}
|
||||
|
||||
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) {
|
||||
return nil, driver.ErrTxSupport
|
||||
}
|
||||
|
||||
func init() {
|
||||
driver.Register(Store{})
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
10
store/mdb.go
10
store/mdb.go
|
@ -1,10 +0,0 @@
|
|||
// +build !windows
|
||||
package store
|
||||
|
||||
import (
|
||||
"github.com/siddontang/ledisdb/store/mdb"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register(mdb.Store{})
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package mdb
|
||||
|
||||
const DBName = "lmdb"
|
|
@ -1,3 +1,5 @@
|
|||
// +build !windows
|
||||
|
||||
package mdb
|
||||
|
||||
import (
|
||||
|
@ -11,7 +13,7 @@ type Store struct {
|
|||
}
|
||||
|
||||
func (s Store) String() string {
|
||||
return "lmdb"
|
||||
return DBName
|
||||
}
|
||||
|
||||
type MDB struct {
|
||||
|
@ -275,3 +277,7 @@ func (db MDB) NewWriteBatch() driver.IWriteBatch {
|
|||
func (db MDB) Begin() (driver.Tx, error) {
|
||||
return newTx(db)
|
||||
}
|
||||
|
||||
func init() {
|
||||
driver.Register(Store{})
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build !windows
|
||||
|
||||
package mdb
|
||||
|
||||
import (
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
// +build rocksdb
|
||||
|
||||
package store
|
||||
|
||||
import (
|
||||
"github.com/siddontang/ledisdb/store/rocksdb"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register(rocksdb.Store{})
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package rocksdb
|
||||
|
||||
const DBName = "rocksdb"
|
|
@ -25,7 +25,7 @@ type Store struct {
|
|||
}
|
||||
|
||||
func (s Store) String() string {
|
||||
return "rocksdb"
|
||||
return DBName
|
||||
}
|
||||
|
||||
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) {
|
||||
return nil, driver.ErrTxSupport
|
||||
}
|
||||
|
||||
func init() {
|
||||
driver.Register(Store{})
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -6,55 +6,21 @@ import (
|
|||
"github.com/siddontang/ledisdb/store/driver"
|
||||
"os"
|
||||
"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 {
|
||||
return path.Join(cfg.DataDir, fmt.Sprintf("%s_data", cfg.DBName))
|
||||
}
|
||||
|
||||
func Open(cfg *config.Config) (*DB, error) {
|
||||
s, err := getStore(cfg)
|
||||
s, err := driver.GetStore(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -76,7 +42,7 @@ func Open(cfg *config.Config) (*DB, error) {
|
|||
}
|
||||
|
||||
func Repair(cfg *config.Config) error {
|
||||
s, err := getStore(cfg)
|
||||
s, err := driver.GetStore(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -85,3 +51,12 @@ func Repair(cfg *config.Config) error {
|
|||
|
||||
return s.Repair(path, cfg)
|
||||
}
|
||||
|
||||
func init() {
|
||||
_ = boltdb.DBName
|
||||
_ = goleveldb.DBName
|
||||
_ = hyperleveldb.DBName
|
||||
_ = leveldb.DBName
|
||||
_ = mdb.DBName
|
||||
_ = rocksdb.DBName
|
||||
}
|
||||
|
|
|
@ -3,11 +3,34 @@ package store
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/config"
|
||||
"github.com/siddontang/ledisdb/store/driver"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
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) {
|
||||
|
@ -16,6 +39,13 @@ func testStore(db *DB, t *testing.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) {
|
||||
key := []byte("key")
|
||||
value := []byte("hello world")
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"github.com/siddontang/ledisdb/store/driver"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -9,6 +10,16 @@ func TestTx(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")
|
||||
key2 := []byte("2")
|
||||
key3 := []byte("3")
|
||||
|
|
Loading…
Reference in New Issue