tendermint/db/c_level_db.go

288 lines
5.4 KiB
Go
Raw Normal View History

// +build gcc
2016-11-29 16:06:36 -08:00
package db
import (
2017-12-13 19:28:37 -08:00
"bytes"
2016-11-29 16:06:36 -08:00
"fmt"
2017-12-13 17:11:11 -08:00
"path/filepath"
2016-11-29 16:06:36 -08:00
"github.com/jmhodges/levigo"
)
func init() {
dbCreator := func(name string, dir string) (DB, error) {
return NewCLevelDB(name, dir)
}
2018-01-24 15:55:31 -08:00
registerDBCreator(LevelDBBackend, dbCreator, true)
registerDBCreator(CLevelDBBackend, dbCreator, false)
}
2017-12-12 17:58:35 -08:00
var _ DB = (*CLevelDB)(nil)
type CLevelDB struct {
2016-11-29 16:06:36 -08:00
db *levigo.DB
ro *levigo.ReadOptions
wo *levigo.WriteOptions
woSync *levigo.WriteOptions
}
func NewCLevelDB(name string, dir string) (*CLevelDB, error) {
2017-12-13 17:11:11 -08:00
dbPath := filepath.Join(dir, name+".db")
2016-11-29 16:06:36 -08:00
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{
2016-11-29 16:06:36 -08:00
db: db,
ro: ro,
wo: wo,
woSync: woSync,
}
return database, nil
}
// Implements DB.
func (db *CLevelDB) Get(key []byte) []byte {
key = nonNilBytes(key)
2016-11-29 16:06:36 -08:00
res, err := db.db.Get(db.ro, key)
if err != nil {
panic(err)
2016-11-29 16:06:36 -08:00
}
return res
}
// Implements DB.
2017-12-12 14:00:03 -08:00
func (db *CLevelDB) Has(key []byte) bool {
return db.Get(key) != nil
2017-12-12 14:00:03 -08:00
}
// Implements DB.
func (db *CLevelDB) Set(key []byte, value []byte) {
key = nonNilBytes(key)
value = nonNilBytes(value)
2016-11-29 16:06:36 -08:00
err := db.db.Put(db.wo, key, value)
if err != nil {
panic(err)
2016-11-29 16:06:36 -08:00
}
}
// Implements DB.
func (db *CLevelDB) SetSync(key []byte, value []byte) {
key = nonNilBytes(key)
value = nonNilBytes(value)
2016-11-29 16:06:36 -08:00
err := db.db.Put(db.woSync, key, value)
if err != nil {
panic(err)
2016-11-29 16:06:36 -08:00
}
}
// Implements DB.
func (db *CLevelDB) Delete(key []byte) {
key = nonNilBytes(key)
2016-11-29 16:06:36 -08:00
err := db.db.Delete(db.wo, key)
if err != nil {
panic(err)
2016-11-29 16:06:36 -08:00
}
}
// Implements DB.
func (db *CLevelDB) DeleteSync(key []byte) {
key = nonNilBytes(key)
2016-11-29 16:06:36 -08:00
err := db.db.Delete(db.woSync, key)
if err != nil {
panic(err)
2016-11-29 16:06:36 -08:00
}
}
func (db *CLevelDB) DB() *levigo.DB {
2016-11-29 16:06:36 -08:00
return db.db
}
// Implements DB.
func (db *CLevelDB) Close() {
2016-11-29 16:06:36 -08:00
db.db.Close()
db.ro.Close()
db.wo.Close()
db.woSync.Close()
}
// Implements DB.
func (db *CLevelDB) Print() {
itr := db.Iterator(nil, nil)
defer itr.Close()
2017-12-12 14:00:03 -08:00
for ; itr.Valid(); itr.Next() {
key := itr.Key()
value := itr.Value()
2016-11-29 16:06:36 -08:00
fmt.Printf("[%X]:\t[%X]\n", key, value)
}
}
// Implements DB.
func (db *CLevelDB) Stats() map[string]string {
// TODO: Find the available properties for the C LevelDB implementation
keys := []string{}
stats := make(map[string]string)
for _, key := range keys {
str := db.db.PropertyValue(key)
stats[key] = str
}
return stats
}
//----------------------------------------
// Batch
// Implements DB.
func (db *CLevelDB) NewBatch() Batch {
2016-11-29 16:06:36 -08:00
batch := levigo.NewWriteBatch()
return &cLevelDBBatch{db, batch}
2016-11-29 16:06:36 -08:00
}
type cLevelDBBatch struct {
db *CLevelDB
2016-11-29 16:06:36 -08:00
batch *levigo.WriteBatch
}
// Implements Batch.
func (mBatch *cLevelDBBatch) Set(key, value []byte) {
2016-11-29 16:06:36 -08:00
mBatch.batch.Put(key, value)
}
// Implements Batch.
func (mBatch *cLevelDBBatch) Delete(key []byte) {
2016-11-29 16:06:36 -08:00
mBatch.batch.Delete(key)
}
// Implements Batch.
func (mBatch *cLevelDBBatch) Write() {
2016-11-29 16:06:36 -08:00
err := mBatch.db.db.Write(mBatch.db.wo, mBatch.batch)
if err != nil {
panic(err)
2016-11-29 16:06:36 -08:00
}
}
// Implements Batch.
func (mBatch *cLevelDBBatch) WriteSync() {
err := mBatch.db.db.Write(mBatch.db.woSync, mBatch.batch)
if err != nil {
panic(err)
}
}
//----------------------------------------
// Iterator
// NOTE This is almost identical to db/go_level_db.Iterator
// Before creating a third version, refactor.
2017-12-12 14:00:03 -08:00
func (db *CLevelDB) Iterator(start, end []byte) Iterator {
2017-12-12 17:58:35 -08:00
itr := db.db.NewIterator(db.ro)
return newCLevelDBIterator(itr, start, end, false)
2017-12-12 14:00:03 -08:00
}
func (db *CLevelDB) ReverseIterator(start, end []byte) Iterator {
panic("not implemented yet") // XXX
}
2017-12-12 17:58:35 -08:00
var _ Iterator = (*cLevelDBIterator)(nil)
type cLevelDBIterator struct {
source *levigo.Iterator
2017-12-12 17:58:35 -08:00
start, end []byte
isReverse bool
isInvalid bool
}
func newCLevelDBIterator(source *levigo.Iterator, start, end []byte, isReverse bool) *cLevelDBIterator {
if isReverse {
panic("not implemented yet") // XXX
}
if start != nil {
source.Seek(start)
2017-12-15 12:58:23 -08:00
} else {
source.SeekToFirst()
2017-12-15 12:58:23 -08:00
}
return &cLevelDBIterator{
source: source,
start: start,
end: end,
isReverse: isReverse,
isInvalid: false,
2017-12-15 12:58:23 -08:00
}
}
func (itr cLevelDBIterator) Domain() ([]byte, []byte) {
return itr.start, itr.end
}
func (itr cLevelDBIterator) Valid() bool {
// Once invalid, forever invalid.
if itr.isInvalid {
2017-12-13 19:28:37 -08:00
return false
}
// Panic on DB error. No way to recover.
itr.assertNoError()
// If source is invalid, invalid.
if !itr.source.Valid() {
itr.isInvalid = true
return false
}
// If key is end or past it, invalid.
var end = itr.end
var key = itr.source.Key()
if end != nil && bytes.Compare(end, key) <= 0 {
itr.isInvalid = true
return false
}
// It's valid.
return true
}
func (itr cLevelDBIterator) Key() []byte {
itr.assertNoError()
itr.assertIsValid()
return itr.source.Key()
2017-12-13 19:28:37 -08:00
}
func (itr cLevelDBIterator) Value() []byte {
itr.assertNoError()
itr.assertIsValid()
return itr.source.Value()
}
2017-12-15 12:58:23 -08:00
func (itr cLevelDBIterator) Next() {
itr.assertNoError()
itr.assertIsValid()
itr.source.Next()
}
func (itr cLevelDBIterator) Close() {
itr.source.Close()
}
func (itr cLevelDBIterator) assertNoError() {
if err := itr.source.GetError(); err != nil {
2017-12-12 19:19:26 -08:00
panic(err)
}
}
func (itr cLevelDBIterator) assertIsValid() {
if !itr.Valid() {
panic("cLevelDBIterator is invalid")
}
}