diff --git a/README.md b/README.md index 30ff2c7..2541aa3 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/store/boltdb.go b/store/boltdb.go deleted file mode 100644 index 8ad5615..0000000 --- a/store/boltdb.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build !windows - -package store - -import ( - "github.com/siddontang/ledisdb/store/boltdb" -) - -func init() { - Register(boltdb.Store{}) -} diff --git a/store/boltdb/const.go b/store/boltdb/const.go new file mode 100644 index 0000000..1e7d0ae --- /dev/null +++ b/store/boltdb/const.go @@ -0,0 +1,3 @@ +package boltdb + +const DBName = "boltdb" diff --git a/store/boltdb/db.go b/store/boltdb/db.go index dc3cf65..6e126b6 100644 --- a/store/boltdb/db.go +++ b/store/boltdb/db.go @@ -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{}) +} diff --git a/store/boltdb_test.go b/store/boltdb_test.go deleted file mode 100644 index 2268768..0000000 --- a/store/boltdb_test.go +++ /dev/null @@ -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() -} diff --git a/store/driver/store.go b/store/driver/store.go new file mode 100644 index 0000000..91f4c66 --- /dev/null +++ b/store/driver/store.go @@ -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 +} diff --git a/store/goleveldb.go b/store/goleveldb.go deleted file mode 100644 index 2367048..0000000 --- a/store/goleveldb.go +++ /dev/null @@ -1,9 +0,0 @@ -package store - -import ( - "github.com/siddontang/ledisdb/store/goleveldb" -) - -func init() { - Register(goleveldb.Store{}) -} diff --git a/store/goleveldb/const.go b/store/goleveldb/const.go new file mode 100644 index 0000000..6486e3f --- /dev/null +++ b/store/goleveldb/const.go @@ -0,0 +1,3 @@ +package goleveldb + +const DBName = "goleveldb" diff --git a/store/goleveldb/db.go b/store/goleveldb/db.go index 802b1fb..33e408f 100644 --- a/store/goleveldb/db.go +++ b/store/goleveldb/db.go @@ -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{}) +} diff --git a/store/goleveldb_test.go b/store/goleveldb_test.go deleted file mode 100644 index 3e29aa6..0000000 --- a/store/goleveldb_test.go +++ /dev/null @@ -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() -} diff --git a/store/hyperleveldb.go b/store/hyperleveldb.go deleted file mode 100644 index 6ef70f1..0000000 --- a/store/hyperleveldb.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build hyperleveldb - -package store - -import ( - "github.com/siddontang/ledisdb/store/hyperleveldb" -) - -func init() { - Register(hyperleveldb.Store{}) -} diff --git a/store/hyperleveldb/const.go b/store/hyperleveldb/const.go new file mode 100644 index 0000000..cc69f3a --- /dev/null +++ b/store/hyperleveldb/const.go @@ -0,0 +1,3 @@ +package hyperleveldb + +const DBName = "hyperleveldb" diff --git a/store/hyperleveldb/db.go b/store/hyperleveldb/db.go index 946a2f6..a37d8d2 100644 --- a/store/hyperleveldb/db.go +++ b/store/hyperleveldb/db.go @@ -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{}) +} diff --git a/store/hyperleveldb_test.go b/store/hyperleveldb_test.go deleted file mode 100644 index 2d3a25b..0000000 --- a/store/hyperleveldb_test.go +++ /dev/null @@ -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() -} diff --git a/store/leveldb.go b/store/leveldb.go deleted file mode 100644 index eeda5e7..0000000 --- a/store/leveldb.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build leveldb - -package store - -import ( - "github.com/siddontang/ledisdb/store/leveldb" -) - -func init() { - Register(leveldb.Store{}) -} diff --git a/store/leveldb/const.go b/store/leveldb/const.go new file mode 100644 index 0000000..df5b3c7 --- /dev/null +++ b/store/leveldb/const.go @@ -0,0 +1,3 @@ +package leveldb + +const DBName = "leveldb" diff --git a/store/leveldb/db.go b/store/leveldb/db.go index 960d525..f42726f 100644 --- a/store/leveldb/db.go +++ b/store/leveldb/db.go @@ -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{}) +} diff --git a/store/leveldb_test.go b/store/leveldb_test.go deleted file mode 100644 index 8e63101..0000000 --- a/store/leveldb_test.go +++ /dev/null @@ -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() -} diff --git a/store/mdb.go b/store/mdb.go deleted file mode 100644 index 1e097f1..0000000 --- a/store/mdb.go +++ /dev/null @@ -1,10 +0,0 @@ -// +build !windows -package store - -import ( - "github.com/siddontang/ledisdb/store/mdb" -) - -func init() { - Register(mdb.Store{}) -} diff --git a/store/mdb/const.go b/store/mdb/const.go new file mode 100644 index 0000000..cdc70e0 --- /dev/null +++ b/store/mdb/const.go @@ -0,0 +1,3 @@ +package mdb + +const DBName = "lmdb" diff --git a/store/mdb/mdb.go b/store/mdb/mdb.go index ad767dc..177a3d1 100644 --- a/store/mdb/mdb.go +++ b/store/mdb/mdb.go @@ -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{}) +} diff --git a/store/mdb/tx.go b/store/mdb/tx.go index 0946727..a9ed5ef 100644 --- a/store/mdb/tx.go +++ b/store/mdb/tx.go @@ -1,3 +1,5 @@ +// +build !windows + package mdb import ( diff --git a/store/mdb_test.go b/store/mdb_test.go deleted file mode 100644 index 4cd7a6b..0000000 --- a/store/mdb_test.go +++ /dev/null @@ -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() -} diff --git a/store/rocksdb.go b/store/rocksdb.go deleted file mode 100644 index 53ce8af..0000000 --- a/store/rocksdb.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build rocksdb - -package store - -import ( - "github.com/siddontang/ledisdb/store/rocksdb" -) - -func init() { - Register(rocksdb.Store{}) -} diff --git a/store/rocksdb/const.go b/store/rocksdb/const.go new file mode 100644 index 0000000..f4155bb --- /dev/null +++ b/store/rocksdb/const.go @@ -0,0 +1,3 @@ +package rocksdb + +const DBName = "rocksdb" diff --git a/store/rocksdb/db.go b/store/rocksdb/db.go index be061bf..d8f26c4 100644 --- a/store/rocksdb/db.go +++ b/store/rocksdb/db.go @@ -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{}) +} diff --git a/store/rocksdb_test.go b/store/rocksdb_test.go deleted file mode 100644 index e8b75aa..0000000 --- a/store/rocksdb_test.go +++ /dev/null @@ -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() -} diff --git a/store/store.go b/store/store.go index eb64e83..50d2744 100644 --- a/store/store.go +++ b/store/store.go @@ -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 +} diff --git a/store/store_test.go b/store/store_test.go index a008d03..2c3517c 100644 --- a/store/store_test.go +++ b/store/store_test.go @@ -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") diff --git a/store/tx_test.go b/store/tx_test.go index cc1115b..2b86c64 100644 --- a/store/tx_test.go +++ b/store/tx_test.go @@ -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")