2014-04-18 10:50:29 +04:00
|
|
|
package leveldb
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"github.com/jmhodges/levigo"
|
|
|
|
)
|
|
|
|
|
|
|
|
const defaultFilterBits int = 10
|
|
|
|
|
|
|
|
type Config struct {
|
|
|
|
Path string `json:"path"`
|
|
|
|
|
|
|
|
Compression bool `json:"compression"`
|
|
|
|
|
|
|
|
BlockSize int `json:"block_size"`
|
|
|
|
WriteBufferSize int `json:"write_buffer_size"`
|
|
|
|
CacheSize int `json:"cache_size"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type DB struct {
|
|
|
|
cfg *Config
|
|
|
|
db *levigo.DB
|
|
|
|
|
|
|
|
opts *levigo.Options
|
|
|
|
|
|
|
|
//for default read and write options
|
|
|
|
readOpts *levigo.ReadOptions
|
|
|
|
writeOpts *levigo.WriteOptions
|
|
|
|
iteratorOpts *levigo.ReadOptions
|
|
|
|
|
|
|
|
cache *levigo.Cache
|
|
|
|
|
|
|
|
filter *levigo.FilterPolicy
|
|
|
|
}
|
|
|
|
|
2014-04-30 04:56:51 +04:00
|
|
|
func OpenWithConfig(cfg *Config) (*DB, error) {
|
2014-04-18 10:50:29 +04:00
|
|
|
db := new(DB)
|
|
|
|
db.cfg = cfg
|
|
|
|
|
|
|
|
db.opts = db.initOptions(cfg)
|
|
|
|
|
|
|
|
db.readOpts = levigo.NewReadOptions()
|
|
|
|
db.writeOpts = levigo.NewWriteOptions()
|
|
|
|
db.iteratorOpts = levigo.NewReadOptions()
|
|
|
|
db.iteratorOpts.SetFillCache(false)
|
|
|
|
|
2014-04-30 04:56:51 +04:00
|
|
|
var err error
|
2014-04-18 10:50:29 +04:00
|
|
|
db.db, err = levigo.Open(cfg.Path, db.opts)
|
|
|
|
return db, err
|
|
|
|
}
|
|
|
|
|
2014-04-30 04:56:51 +04:00
|
|
|
func Open(configJson json.RawMessage) (*DB, error) {
|
|
|
|
cfg := new(Config)
|
|
|
|
err := json.Unmarshal(configJson, cfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return OpenWithConfig(cfg)
|
|
|
|
}
|
|
|
|
|
2014-04-18 10:50:29 +04:00
|
|
|
func (db *DB) initOptions(cfg *Config) *levigo.Options {
|
|
|
|
opts := levigo.NewOptions()
|
|
|
|
|
|
|
|
opts.SetCreateIfMissing(true)
|
|
|
|
|
|
|
|
if cfg.CacheSize > 0 {
|
|
|
|
db.cache = levigo.NewLRUCache(cfg.CacheSize)
|
|
|
|
opts.SetCache(db.cache)
|
|
|
|
}
|
|
|
|
|
|
|
|
//we must use bloomfilter
|
|
|
|
db.filter = levigo.NewBloomFilter(defaultFilterBits)
|
|
|
|
opts.SetFilterPolicy(db.filter)
|
|
|
|
|
|
|
|
if !cfg.Compression {
|
|
|
|
opts.SetCompression(levigo.NoCompression)
|
|
|
|
}
|
|
|
|
|
2014-04-30 04:56:51 +04:00
|
|
|
if cfg.BlockSize > 0 {
|
|
|
|
opts.SetBlockSize(cfg.BlockSize)
|
2014-04-18 10:50:29 +04:00
|
|
|
}
|
|
|
|
|
2014-04-30 04:56:51 +04:00
|
|
|
if cfg.WriteBufferSize > 0 {
|
|
|
|
opts.SetWriteBufferSize(cfg.WriteBufferSize)
|
2014-04-18 10:50:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return opts
|
|
|
|
}
|
|
|
|
|
|
|
|
func (db *DB) Close() {
|
|
|
|
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()
|
|
|
|
|
|
|
|
db.db.Close()
|
|
|
|
db.db = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (db *DB) Destroy() {
|
|
|
|
db.Close()
|
|
|
|
opts := levigo.NewOptions()
|
|
|
|
defer opts.Close()
|
|
|
|
|
|
|
|
levigo.DestroyDatabase(db.cfg.Path, opts)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (db *DB) Put(key, value []byte) error {
|
|
|
|
return db.db.Put(db.writeOpts, key, value)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (db *DB) Get(key []byte) ([]byte, error) {
|
|
|
|
return db.db.Get(db.readOpts, key)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (db *DB) Delete(key []byte) error {
|
|
|
|
return db.db.Delete(db.writeOpts, key)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (db *DB) NewWriteBatch() *WriteBatch {
|
|
|
|
wb := new(WriteBatch)
|
|
|
|
wb.wb = levigo.NewWriteBatch()
|
|
|
|
wb.db = db
|
|
|
|
return wb
|
|
|
|
}
|
|
|
|
|
|
|
|
//like c++ iterator, [begin, end)
|
|
|
|
//begin should less than end
|
|
|
|
//if begin is nil, we will seek to first
|
|
|
|
//if end is nil, we will next until read last
|
|
|
|
//limit <= 0, no limit
|
|
|
|
func (db *DB) Iterator(begin []byte, end []byte, limit int) *Iterator {
|
|
|
|
return newIterator(db, db.iteratorOpts, begin, end, limit, forward)
|
|
|
|
}
|
|
|
|
|
|
|
|
//like c++ reverse_iterator, [rbegin, rend)
|
|
|
|
//rbegin should bigger than rend
|
|
|
|
//if rbegin is nil, we will seek to last
|
|
|
|
//if end is nil, we will next until read first
|
|
|
|
//limit <= 0, no limit
|
|
|
|
func (db *DB) ReverseIterator(rbegin []byte, rend []byte, limit int) *Iterator {
|
|
|
|
return newIterator(db, db.iteratorOpts, rbegin, rend, limit, backward)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (db *DB) NewSnapshot() *Snapshot {
|
|
|
|
return newSnapshot(db)
|
|
|
|
}
|