2014-08-03 15:59:56 +02:00
|
|
|
// Copyright 2014 by Sascha L. Teichmann
|
|
|
|
// Use of this source code is governed by the MIT license
|
|
|
|
// that can be found in the LICENSE file.
|
|
|
|
|
2014-08-03 11:25:25 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2014-08-06 01:11:41 +02:00
|
|
|
"log"
|
|
|
|
|
2014-08-03 11:25:25 +02:00
|
|
|
leveldb "github.com/jmhodges/levigo"
|
|
|
|
)
|
|
|
|
|
|
|
|
type LevelDBBackend struct {
|
|
|
|
cache *leveldb.Cache
|
|
|
|
db *leveldb.DB
|
2014-08-06 01:11:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type LevelDBSession struct {
|
|
|
|
backend *LevelDBBackend
|
|
|
|
tx *leveldb.WriteBatch
|
2014-08-03 11:25:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewLeveDBBackend(path string, cacheSize int) (ldb *LevelDBBackend, err error) {
|
|
|
|
cache := leveldb.NewLRUCache(cacheSize * 1024 * 1024)
|
|
|
|
opts := leveldb.NewOptions()
|
|
|
|
opts.SetCache(cache)
|
|
|
|
opts.SetCreateIfMissing(true)
|
|
|
|
var db *leveldb.DB
|
|
|
|
if db, err = leveldb.Open(path, opts); err != nil {
|
|
|
|
cache.Close()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ldb = &LevelDBBackend{
|
|
|
|
cache: cache,
|
|
|
|
db: db}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-08-06 01:11:41 +02:00
|
|
|
func (ldb *LevelDBBackend) NewSession() (Session, error) {
|
|
|
|
return &LevelDBSession{ldb, nil}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ldbs *LevelDBSession) Close() error {
|
|
|
|
if ldbs.tx != nil {
|
|
|
|
ldbs.tx.Close()
|
2014-08-04 15:29:26 +02:00
|
|
|
}
|
2014-08-06 01:11:41 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ldb *LevelDBBackend) Shutdown() error {
|
2014-08-03 11:25:25 +02:00
|
|
|
ldb.db.Close()
|
|
|
|
ldb.cache.Close()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-08-06 01:11:41 +02:00
|
|
|
func (ldbs *LevelDBSession) Fetch(hash, key []byte) (value []byte, err error) {
|
2014-08-03 11:25:25 +02:00
|
|
|
ro := leveldb.NewReadOptions()
|
2014-08-06 01:11:41 +02:00
|
|
|
value, err = ldbs.backend.db.Get(ro, key)
|
2014-08-04 22:23:16 +02:00
|
|
|
ro.Close()
|
|
|
|
return
|
2014-08-03 11:25:25 +02:00
|
|
|
}
|
|
|
|
|
2014-08-06 01:11:41 +02:00
|
|
|
func (ldbs *LevelDBSession) InTransaction() bool {
|
|
|
|
return ldbs.tx != nil
|
2014-08-03 11:25:25 +02:00
|
|
|
}
|
|
|
|
|
2014-08-06 01:11:41 +02:00
|
|
|
func (ldbs *LevelDBSession) keyExists(key []byte) (exists bool, err error) {
|
2014-08-03 11:25:25 +02:00
|
|
|
ro := leveldb.NewReadOptions()
|
|
|
|
defer ro.Close()
|
|
|
|
var data []byte
|
2014-08-06 01:11:41 +02:00
|
|
|
if data, err = ldbs.backend.db.Get(ro, key); err != nil {
|
2014-08-03 11:25:25 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
exists = data != nil
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-08-06 01:11:41 +02:00
|
|
|
func (ldbs *LevelDBSession) Store(hash, key, value []byte) (exists bool, err error) {
|
2014-08-03 11:25:25 +02:00
|
|
|
|
2014-08-04 17:10:19 +02:00
|
|
|
var pos int64
|
|
|
|
if pos, err = bytes2pos(key); err != nil {
|
|
|
|
return
|
|
|
|
}
|
2014-08-04 21:06:41 +02:00
|
|
|
// Re-code it to make LevelDB happy.
|
|
|
|
key = pos2bytes(pos)
|
2014-08-04 17:10:19 +02:00
|
|
|
|
2014-08-06 01:11:41 +02:00
|
|
|
if exists, err = ldbs.keyExists(key); err != nil {
|
2014-08-03 11:25:25 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-08-06 01:11:41 +02:00
|
|
|
if ldbs.tx != nil {
|
|
|
|
ldbs.tx.Put(key, value)
|
2014-08-03 11:25:25 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
wo := leveldb.NewWriteOptions()
|
2014-08-06 01:11:41 +02:00
|
|
|
err = ldbs.backend.db.Put(wo, key, value)
|
2014-08-04 15:28:01 +02:00
|
|
|
wo.Close()
|
2014-08-03 11:25:25 +02:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-08-06 01:11:41 +02:00
|
|
|
func (ldbs *LevelDBSession) BeginTransaction() error {
|
|
|
|
ldbs.tx = leveldb.NewWriteBatch()
|
2014-08-03 11:25:25 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-08-06 01:11:41 +02:00
|
|
|
func (ldbs *LevelDBSession) CommitTransaction() (err error) {
|
|
|
|
tx := ldbs.tx
|
|
|
|
if tx == nil {
|
|
|
|
log.Println("WARN: No transaction running.")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
ldbs.tx = nil
|
2014-08-03 11:25:25 +02:00
|
|
|
wo := leveldb.NewWriteOptions()
|
2014-08-06 01:11:41 +02:00
|
|
|
err = ldbs.backend.db.Write(wo, tx)
|
2014-08-04 15:29:26 +02:00
|
|
|
wo.Close()
|
|
|
|
return
|
2014-08-03 11:25:25 +02:00
|
|
|
}
|