go/leveldb/db.go

155 lines
3.1 KiB
Go

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
}
func Open(configJson json.RawMessage) (*DB, error) {
cfg := new(Config)
err := json.Unmarshal(configJson, cfg)
if err != nil {
return nil, err
}
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)
db.db, err = levigo.Open(cfg.Path, db.opts)
return db, err
}
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)
}
blockSize := cfg.BlockSize * 1024
if blockSize > 0 {
opts.SetBlockSize(blockSize)
}
writeBufferSize := cfg.WriteBufferSize * 1024 * 1024
if writeBufferSize > 0 {
opts.SetWriteBufferSize(writeBufferSize)
}
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)
}