ledisdb/store/leveldb/db.go

260 lines
4.5 KiB
Go
Raw Normal View History

2014-07-25 13:58:00 +04:00
// +build leveldb
2014-07-09 05:33:44 +04:00
// Package leveldb is a wrapper for c++ leveldb
2014-06-19 13:19:40 +04:00
package leveldb
/*
#cgo LDFLAGS: -lleveldb
#include <leveldb/c.h>
#include "leveldb_ext.h"
2014-06-19 13:19:40 +04:00
*/
import "C"
import (
"github.com/siddontang/ledisdb/config"
2014-07-25 13:58:00 +04:00
"github.com/siddontang/ledisdb/store/driver"
2014-06-19 13:19:40 +04:00
"os"
"runtime"
2014-06-19 13:19:40 +04:00
"unsafe"
)
const defaultFilterBits int = 10
type Store struct {
}
2014-06-19 13:19:40 +04:00
func (s Store) String() string {
return "leveldb"
2014-06-19 13:19:40 +04:00
}
func (s Store) Open(path string, cfg *config.Config) (driver.IDB, error) {
if err := os.MkdirAll(path, os.ModePerm); err != nil {
2014-06-19 13:19:40 +04:00
return nil, err
}
db := new(DB)
db.path = path
db.cfg = &cfg.LevelDB
2014-06-19 13:19:40 +04:00
if err := db.open(); err != nil {
return nil, err
}
return db, nil
}
func (s Store) Repair(path string, cfg *config.Config) error {
2014-07-25 13:58:00 +04:00
db := new(DB)
db.cfg = &cfg.LevelDB
db.path = path
2014-07-25 13:58:00 +04:00
err := db.open()
defer db.Close()
//open ok, do not need repair
if err == nil {
return nil
}
2014-06-19 13:19:40 +04:00
2014-06-26 07:04:54 +04:00
var errStr *C.char
ldbname := C.CString(path)
2014-06-26 07:04:54 +04:00
defer C.leveldb_free(unsafe.Pointer(ldbname))
2014-06-19 13:19:40 +04:00
2014-07-25 13:58:00 +04:00
C.leveldb_repair_db(db.opts.Opt, ldbname, &errStr)
2014-06-26 07:04:54 +04:00
if errStr != nil {
return saveError(errStr)
}
return nil
}
2014-06-19 13:19:40 +04:00
2014-07-25 13:58:00 +04:00
type DB struct {
path string
cfg *config.LevelDBConfig
2014-06-26 07:04:54 +04:00
2014-07-25 13:58:00 +04:00
db *C.leveldb_t
2014-06-26 07:04:54 +04:00
2014-07-25 13:58:00 +04:00
opts *Options
//for default read and write options
readOpts *ReadOptions
writeOpts *WriteOptions
iteratorOpts *ReadOptions
cache *Cache
filter *FilterPolicy
}
func (db *DB) open() error {
db.initOptions(db.cfg)
2014-06-19 13:19:40 +04:00
var errStr *C.char
ldbname := C.CString(db.path)
2014-06-19 13:19:40 +04:00
defer C.leveldb_free(unsafe.Pointer(ldbname))
2014-07-25 13:58:00 +04:00
db.db = C.leveldb_open(db.opts.Opt, ldbname, &errStr)
2014-06-19 13:19:40 +04:00
if errStr != nil {
2014-07-25 13:58:00 +04:00
db.db = nil
2014-06-19 13:19:40 +04:00
return saveError(errStr)
}
return nil
}
func (db *DB) initOptions(cfg *config.LevelDBConfig) {
2014-06-19 13:19:40 +04:00
opts := NewOptions()
opts.SetCreateIfMissing(true)
cfg.Adjust()
2014-06-19 13:19:40 +04:00
db.cache = NewLRUCache(cfg.CacheSize)
opts.SetCache(db.cache)
//we must use bloomfilter
db.filter = NewBloomFilter(defaultFilterBits)
opts.SetFilterPolicy(db.filter)
if !cfg.Compression {
opts.SetCompression(NoCompression)
2014-07-25 13:58:00 +04:00
} else {
opts.SetCompression(SnappyCompression)
2014-06-19 13:19:40 +04:00
}
opts.SetBlockSize(cfg.BlockSize)
opts.SetWriteBufferSize(cfg.WriteBufferSize)
opts.SetMaxOpenFiles(cfg.MaxOpenFiles)
2014-06-26 07:04:54 +04:00
db.opts = opts
db.readOpts = NewReadOptions()
db.writeOpts = NewWriteOptions()
db.iteratorOpts = NewReadOptions()
db.iteratorOpts.SetFillCache(false)
2014-06-19 13:19:40 +04:00
}
func (db *DB) Close() error {
2014-06-26 07:04:54 +04:00
if db.db != nil {
C.leveldb_close(db.db)
db.db = nil
}
2014-06-19 13:19:40 +04:00
db.opts.Close()
if db.cache != nil {
db.cache.Close()
}
if db.filter != nil {
db.filter.Close()
}
db.readOpts.Close()
db.writeOpts.Close()
db.iteratorOpts.Close()
return nil
}
func (db *DB) Put(key, value []byte) error {
return db.put(db.writeOpts, key, value)
}
func (db *DB) Get(key []byte) ([]byte, error) {
2014-07-25 13:58:00 +04:00
return db.get(db.readOpts, key)
2014-06-19 13:19:40 +04:00
}
func (db *DB) Delete(key []byte) error {
return db.delete(db.writeOpts, key)
}
2014-07-25 13:58:00 +04:00
func (db *DB) NewWriteBatch() driver.IWriteBatch {
2014-06-19 13:19:40 +04:00
wb := &WriteBatch{
db: db,
wbatch: C.leveldb_writebatch_create(),
}
runtime.SetFinalizer(wb, func(w *WriteBatch) {
w.Close()
})
2014-06-19 13:19:40 +04:00
return wb
}
2014-07-25 13:58:00 +04:00
func (db *DB) NewIterator() driver.IIterator {
2014-06-19 13:19:40 +04:00
it := new(Iterator)
it.it = C.leveldb_create_iterator(db.db, db.iteratorOpts.Opt)
return it
}
func (db *DB) put(wo *WriteOptions, key, value []byte) error {
var errStr *C.char
var k, v *C.char
if len(key) != 0 {
k = (*C.char)(unsafe.Pointer(&key[0]))
}
if len(value) != 0 {
v = (*C.char)(unsafe.Pointer(&value[0]))
}
lenk := len(key)
lenv := len(value)
C.leveldb_put(
db.db, wo.Opt, k, C.size_t(lenk), v, C.size_t(lenv), &errStr)
if errStr != nil {
return saveError(errStr)
}
return nil
}
2014-07-25 13:58:00 +04:00
func (db *DB) get(ro *ReadOptions, key []byte) ([]byte, error) {
2014-06-19 13:19:40 +04:00
var errStr *C.char
var vallen C.size_t
var k *C.char
if len(key) != 0 {
k = (*C.char)(unsafe.Pointer(&key[0]))
}
var value *C.char
c := C.leveldb_get_ext(
db.db, ro.Opt, k, C.size_t(len(key)), &value, &vallen, &errStr)
2014-06-19 13:19:40 +04:00
if errStr != nil {
return nil, saveError(errStr)
}
if value == nil {
return nil, nil
}
defer C.leveldb_get_free_ext(unsafe.Pointer(c))
2014-07-25 13:58:00 +04:00
return C.GoBytes(unsafe.Pointer(value), C.int(vallen)), nil
2014-06-19 13:19:40 +04:00
}
func (db *DB) delete(wo *WriteOptions, key []byte) error {
var errStr *C.char
var k *C.char
if len(key) != 0 {
k = (*C.char)(unsafe.Pointer(&key[0]))
}
C.leveldb_delete(
db.db, wo.Opt, k, C.size_t(len(key)), &errStr)
if errStr != nil {
return saveError(errStr)
}
return nil
}
2014-07-29 13:29:51 +04:00
func (db *DB) Begin() (driver.Tx, error) {
return nil, driver.ErrTxSupport
}