@ -0,0 +1,134 @@ | |||
// +build gcc | |||
package db | |||
import ( | |||
"fmt" | |||
"path" | |||
"github.com/jmhodges/levigo" | |||
. "github.com/tendermint/go-common" | |||
) | |||
func init() { | |||
dbCreator := func(name string, dir string) (DB, error) { | |||
return NewCLevelDB(name, dir) | |||
} | |||
registerDBCreator(LevelDBBackendStr, dbCreator, true) | |||
registerDBCreator(CLevelDBBackendStr, dbCreator, false) | |||
} | |||
type CLevelDB struct { | |||
db *levigo.DB | |||
ro *levigo.ReadOptions | |||
wo *levigo.WriteOptions | |||
woSync *levigo.WriteOptions | |||
} | |||
func NewCLevelDB(name string, dir string) (*CLevelDB, error) { | |||
dbPath := path.Join(dir, name+".db") | |||
opts := levigo.NewOptions() | |||
opts.SetCache(levigo.NewLRUCache(1 << 30)) | |||
opts.SetCreateIfMissing(true) | |||
db, err := levigo.Open(dbPath, opts) | |||
if err != nil { | |||
return nil, err | |||
} | |||
ro := levigo.NewReadOptions() | |||
wo := levigo.NewWriteOptions() | |||
woSync := levigo.NewWriteOptions() | |||
woSync.SetSync(true) | |||
database := &CLevelDB{ | |||
db: db, | |||
ro: ro, | |||
wo: wo, | |||
woSync: woSync, | |||
} | |||
return database, nil | |||
} | |||
func (db *CLevelDB) Get(key []byte) []byte { | |||
res, err := db.db.Get(db.ro, key) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
return res | |||
} | |||
func (db *CLevelDB) Set(key []byte, value []byte) { | |||
err := db.db.Put(db.wo, key, value) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
} | |||
func (db *CLevelDB) SetSync(key []byte, value []byte) { | |||
err := db.db.Put(db.woSync, key, value) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
} | |||
func (db *CLevelDB) Delete(key []byte) { | |||
err := db.db.Delete(db.wo, key) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
} | |||
func (db *CLevelDB) DeleteSync(key []byte) { | |||
err := db.db.Delete(db.woSync, key) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
} | |||
func (db *CLevelDB) DB() *levigo.DB { | |||
return db.db | |||
} | |||
func (db *CLevelDB) Close() { | |||
db.db.Close() | |||
db.ro.Close() | |||
db.wo.Close() | |||
db.woSync.Close() | |||
} | |||
func (db *CLevelDB) Print() { | |||
iter := db.db.NewIterator(db.ro) | |||
defer iter.Close() | |||
for iter.Seek(nil); iter.Valid(); iter.Next() { | |||
key := iter.Key() | |||
value := iter.Value() | |||
fmt.Printf("[%X]:\t[%X]\n", key, value) | |||
} | |||
} | |||
func (db *CLevelDB) NewBatch() Batch { | |||
batch := levigo.NewWriteBatch() | |||
return &cLevelDBBatch{db, batch} | |||
} | |||
//-------------------------------------------------------------------------------- | |||
type cLevelDBBatch struct { | |||
db *CLevelDB | |||
batch *levigo.WriteBatch | |||
} | |||
func (mBatch *cLevelDBBatch) Set(key, value []byte) { | |||
mBatch.batch.Put(key, value) | |||
} | |||
func (mBatch *cLevelDBBatch) Delete(key []byte) { | |||
mBatch.batch.Delete(key) | |||
} | |||
func (mBatch *cLevelDBBatch) Write() { | |||
err := mBatch.db.db.Write(mBatch.db.wo, mBatch.batch) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
} |
@ -0,0 +1,86 @@ | |||
// +build gcc | |||
package db | |||
import ( | |||
"bytes" | |||
"fmt" | |||
"testing" | |||
. "github.com/tendermint/go-common" | |||
) | |||
func BenchmarkRandomReadsWrites2(b *testing.B) { | |||
b.StopTimer() | |||
numItems := int64(1000000) | |||
internal := map[int64]int64{} | |||
for i := 0; i < int(numItems); i++ { | |||
internal[int64(i)] = int64(0) | |||
} | |||
db, err := NewGoLevelDB(Fmt("test_%x", RandStr(12)), "") | |||
if err != nil { | |||
b.Fatal(err.Error()) | |||
return | |||
} | |||
fmt.Println("ok, starting") | |||
b.StartTimer() | |||
for i := 0; i < b.N; i++ { | |||
// Write something | |||
{ | |||
idx := (int64(RandInt()) % numItems) | |||
internal[idx] += 1 | |||
val := internal[idx] | |||
idxBytes := int642Bytes(int64(idx)) | |||
valBytes := int642Bytes(int64(val)) | |||
//fmt.Printf("Set %X -> %X\n", idxBytes, valBytes) | |||
db.Set( | |||
idxBytes, | |||
valBytes, | |||
) | |||
} | |||
// Read something | |||
{ | |||
idx := (int64(RandInt()) % numItems) | |||
val := internal[idx] | |||
idxBytes := int642Bytes(int64(idx)) | |||
valBytes := db.Get(idxBytes) | |||
//fmt.Printf("Get %X -> %X\n", idxBytes, valBytes) | |||
if val == 0 { | |||
if !bytes.Equal(valBytes, nil) { | |||
b.Errorf("Expected %X for %v, got %X", | |||
nil, idx, valBytes) | |||
break | |||
} | |||
} else { | |||
if len(valBytes) != 8 { | |||
b.Errorf("Expected length 8 for %v, got %X", | |||
idx, valBytes) | |||
break | |||
} | |||
valGot := bytes2Int64(valBytes) | |||
if val != valGot { | |||
b.Errorf("Expected %v for %v, got %v", | |||
val, idx, valGot) | |||
break | |||
} | |||
} | |||
} | |||
} | |||
db.Close() | |||
} | |||
/* | |||
func int642Bytes(i int64) []byte { | |||
buf := make([]byte, 8) | |||
binary.BigEndian.PutUint64(buf, uint64(i)) | |||
return buf | |||
} | |||
func bytes2Int64(buf []byte) int64 { | |||
return int64(binary.BigEndian.Uint64(buf)) | |||
} | |||
*/ |
@ -0,0 +1,118 @@ | |||
package db | |||
import ( | |||
"fmt" | |||
"path" | |||
"github.com/syndtr/goleveldb/leveldb" | |||
"github.com/syndtr/goleveldb/leveldb/errors" | |||
"github.com/syndtr/goleveldb/leveldb/opt" | |||
. "github.com/tendermint/go-common" | |||
) | |||
func init() { | |||
dbCreator := func(name string, dir string) (DB, error) { | |||
return NewGoLevelDB(name, dir) | |||
} | |||
registerDBCreator(LevelDBBackendStr, dbCreator, false) | |||
registerDBCreator(GoLevelDBBackendStr, dbCreator, false) | |||
} | |||
type GoLevelDB struct { | |||
db *leveldb.DB | |||
} | |||
func NewGoLevelDB(name string, dir string) (*GoLevelDB, error) { | |||
dbPath := path.Join(dir, name+".db") | |||
db, err := leveldb.OpenFile(dbPath, nil) | |||
if err != nil { | |||
return nil, err | |||
} | |||
database := &GoLevelDB{db: db} | |||
return database, nil | |||
} | |||
func (db *GoLevelDB) Get(key []byte) []byte { | |||
res, err := db.db.Get(key, nil) | |||
if err != nil { | |||
if err == errors.ErrNotFound { | |||
return nil | |||
} else { | |||
PanicCrisis(err) | |||
} | |||
} | |||
return res | |||
} | |||
func (db *GoLevelDB) Set(key []byte, value []byte) { | |||
err := db.db.Put(key, value, nil) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
} | |||
func (db *GoLevelDB) SetSync(key []byte, value []byte) { | |||
err := db.db.Put(key, value, &opt.WriteOptions{Sync: true}) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
} | |||
func (db *GoLevelDB) Delete(key []byte) { | |||
err := db.db.Delete(key, nil) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
} | |||
func (db *GoLevelDB) DeleteSync(key []byte) { | |||
err := db.db.Delete(key, &opt.WriteOptions{Sync: true}) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
} | |||
func (db *GoLevelDB) DB() *leveldb.DB { | |||
return db.db | |||
} | |||
func (db *GoLevelDB) Close() { | |||
db.db.Close() | |||
} | |||
func (db *GoLevelDB) Print() { | |||
iter := db.db.NewIterator(nil, nil) | |||
for iter.Next() { | |||
key := iter.Key() | |||
value := iter.Value() | |||
fmt.Printf("[%X]:\t[%X]\n", key, value) | |||
} | |||
} | |||
func (db *GoLevelDB) NewBatch() Batch { | |||
batch := new(leveldb.Batch) | |||
return &goLevelDBBatch{db, batch} | |||
} | |||
//-------------------------------------------------------------------------------- | |||
type goLevelDBBatch struct { | |||
db *GoLevelDB | |||
batch *leveldb.Batch | |||
} | |||
func (mBatch *goLevelDBBatch) Set(key, value []byte) { | |||
mBatch.batch.Put(key, value) | |||
} | |||
func (mBatch *goLevelDBBatch) Delete(key []byte) { | |||
mBatch.batch.Delete(key) | |||
} | |||
func (mBatch *goLevelDBBatch) Write() { | |||
err := mBatch.db.db.Write(mBatch.batch, nil) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
} |
@ -1,83 +0,0 @@ | |||
package db | |||
import ( | |||
"fmt" | |||
"path" | |||
"github.com/syndtr/goleveldb/leveldb" | |||
"github.com/syndtr/goleveldb/leveldb/errors" | |||
"github.com/syndtr/goleveldb/leveldb/opt" | |||
. "github.com/tendermint/go-common" | |||
) | |||
type LevelDB struct { | |||
db *leveldb.DB | |||
} | |||
func NewLevelDB(name string) (*LevelDB, error) { | |||
dbPath := path.Join(name) | |||
db, err := leveldb.OpenFile(dbPath, nil) | |||
if err != nil { | |||
return nil, err | |||
} | |||
database := &LevelDB{db: db} | |||
return database, nil | |||
} | |||
func (db *LevelDB) Get(key []byte) []byte { | |||
res, err := db.db.Get(key, nil) | |||
if err != nil { | |||
if err == errors.ErrNotFound { | |||
return nil | |||
} else { | |||
PanicCrisis(err) | |||
} | |||
} | |||
return res | |||
} | |||
func (db *LevelDB) Set(key []byte, value []byte) { | |||
err := db.db.Put(key, value, nil) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
} | |||
func (db *LevelDB) SetSync(key []byte, value []byte) { | |||
err := db.db.Put(key, value, &opt.WriteOptions{Sync: true}) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
} | |||
func (db *LevelDB) Delete(key []byte) { | |||
err := db.db.Delete(key, nil) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
} | |||
func (db *LevelDB) DeleteSync(key []byte) { | |||
err := db.db.Delete(key, &opt.WriteOptions{Sync: true}) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
} | |||
func (db *LevelDB) DB() *leveldb.DB { | |||
return db.db | |||
} | |||
func (db *LevelDB) Close() { | |||
db.db.Close() | |||
} | |||
func (db *LevelDB) Print() { | |||
iter := db.db.NewIterator(nil, nil) | |||
for iter.Next() { | |||
key := iter.Key() | |||
value := iter.Value() | |||
fmt.Printf("[%X]:\t[%X]\n", key, value) | |||
} | |||
} |