You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

252 lines
4.7 KiB

// +build gcc
package db
import (
"bytes"
"fmt"
"path/filepath"
"github.com/jmhodges/levigo"
)
func init() {
dbCreator := func(name string, dir string) (DB, error) {
return NewCLevelDB(name, dir)
}
registerDBCreator(LevelDBBackendStr, dbCreator, true)
registerDBCreator(CLevelDBBackendStr, dbCreator, false)
}
var _ DB = (*CLevelDB)(nil)
type CLevelDB struct {
db *levigo.DB
ro *levigo.ReadOptions
wo *levigo.WriteOptions
woSync *levigo.WriteOptions
}
func NewCLevelDB(name string, dir string) (*CLevelDB, error) {
dbPath := filepath.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 {
panicNilKey(key)
res, err := db.db.Get(db.ro, key)
if err != nil {
panic(err)
}
return res
}
func (db *CLevelDB) Has(key []byte) bool {
panicNilKey(key)
panic("not implemented yet")
}
func (db *CLevelDB) Set(key []byte, value []byte) {
panicNilKey(key)
err := db.db.Put(db.wo, key, value)
if err != nil {
panic(err)
}
}
func (db *CLevelDB) SetSync(key []byte, value []byte) {
panicNilKey(key)
err := db.db.Put(db.woSync, key, value)
if err != nil {
panic(err)
}
}
func (db *CLevelDB) Delete(key []byte) {
panicNilKey(key)
err := db.db.Delete(db.wo, key)
if err != nil {
panic(err)
}
}
func (db *CLevelDB) DeleteSync(key []byte) {
panicNilKey(key)
err := db.db.Delete(db.woSync, key)
if err != nil {
panic(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() {
itr := db.Iterator(BeginningKey(), EndingKey())
defer itr.Close()
for ; itr.Valid(); itr.Next() {
key := itr.Key()
value := itr.Value()
fmt.Printf("[%X]:\t[%X]\n", key, value)
}
}
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
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 {
panic(err)
}
}
//----------------------------------------
// Iterator
func (db *CLevelDB) Iterator(start, end []byte) Iterator {
itr := db.db.NewIterator(db.ro)
return newCLevelDBIterator(itr, start, end)
}
func (db *CLevelDB) ReverseIterator(start, end []byte) Iterator {
// XXX
return nil
}
var _ Iterator = (*cLevelDBIterator)(nil)
type cLevelDBIterator struct {
itr *levigo.Iterator
start, end []byte
invalid bool
}
func newCLevelDBIterator(itr *levigo.Iterator, start, end []byte) *cLevelDBIterator {
if len(start) > 0 {
itr.Seek(start)
} else {
itr.SeekToFirst()
}
return &cLevelDBIterator{
itr: itr,
start: start,
end: end,
}
}
func (c *cLevelDBIterator) Domain() ([]byte, []byte) {
return c.start, c.end
}
func (c *cLevelDBIterator) Valid() bool {
c.assertNoError()
if c.invalid {
return false
}
c.invalid = !c.itr.Valid()
return !c.invalid
}
func (c *cLevelDBIterator) Key() []byte {
if !c.Valid() {
panic("cLevelDBIterator Key() called when invalid")
}
return c.itr.Key()
}
func (c *cLevelDBIterator) Value() []byte {
if !c.Valid() {
panic("cLevelDBIterator Value() called when invalid")
}
return c.itr.Value()
}
func (c *cLevelDBIterator) Next() {
if !c.Valid() {
panic("cLevelDBIterator Next() called when invalid")
}
c.itr.Next()
c.checkEndKey() // if we've exceeded the range, we're now invalid
}
// levigo has no upper bound when iterating, so need to check ourselves
func (c *cLevelDBIterator) checkEndKey() {
if !c.itr.Valid() {
c.invalid = true
return
}
key := c.itr.Key()
if c.end != nil && bytes.Compare(key, c.end) > 0 {
c.invalid = true
}
}
func (c *cLevelDBIterator) Close() {
c.itr.Close()
}
func (c *cLevelDBIterator) assertNoError() {
if err := c.itr.GetError(); err != nil {
panic(err)
}
}