2014-08-20 15:26:31 +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.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2014-08-20 16:21:44 +02:00
|
|
|
"os"
|
|
|
|
|
2014-08-20 15:26:31 +02:00
|
|
|
"bitbucket.org/s_l_teichmann/mtredisalize/common"
|
|
|
|
|
|
|
|
leveldb "github.com/jmhodges/levigo"
|
|
|
|
)
|
|
|
|
|
2014-08-20 16:21:44 +02:00
|
|
|
type (
|
|
|
|
LevelDBBlockProducer struct {
|
|
|
|
db *leveldb.DB
|
|
|
|
opts *leveldb.Options
|
|
|
|
ro *leveldb.ReadOptions
|
|
|
|
iterator *leveldb.Iterator
|
|
|
|
splitter common.KeySplitter
|
|
|
|
decoder common.KeyDecoder
|
|
|
|
}
|
|
|
|
|
|
|
|
LevelDBBlockConsumer struct {
|
|
|
|
db *leveldb.DB
|
|
|
|
opts *leveldb.Options
|
|
|
|
wo *leveldb.WriteOptions
|
|
|
|
joiner common.KeyJoiner
|
|
|
|
encoder common.KeyEncoder
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2014-08-21 14:46:34 +02:00
|
|
|
func NewLevelDBBlockProducer(path string,
|
2014-08-20 16:21:44 +02:00
|
|
|
splitter common.KeySplitter,
|
|
|
|
decoder common.KeyDecoder) (ldbp *LevelDBBlockProducer, err error) {
|
|
|
|
|
|
|
|
// check if we can stat it -> exists.
|
|
|
|
if _, err = os.Stat(path); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
opts := leveldb.NewOptions()
|
|
|
|
opts.SetCreateIfMissing(false)
|
|
|
|
|
|
|
|
var db *leveldb.DB
|
|
|
|
if db, err = leveldb.Open(path, opts); err != nil {
|
|
|
|
opts.Close()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ro := leveldb.NewReadOptions()
|
|
|
|
ro.SetFillCache(false)
|
|
|
|
|
|
|
|
iterator := db.NewIterator(ro)
|
|
|
|
iterator.SeekToFirst()
|
|
|
|
|
|
|
|
ldbp = &LevelDBBlockProducer{
|
|
|
|
db: db,
|
|
|
|
opts: opts,
|
|
|
|
ro: ro,
|
|
|
|
iterator: iterator,
|
|
|
|
splitter: splitter,
|
|
|
|
decoder: decoder}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ldbp *LevelDBBlockProducer) Close() error {
|
|
|
|
if ldbp.iterator != nil {
|
|
|
|
ldbp.iterator.Close()
|
|
|
|
}
|
|
|
|
ldbp.ro.Close()
|
|
|
|
ldbp.db.Close()
|
|
|
|
ldbp.opts.Close()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ldbp *LevelDBBlockProducer) Next(block *Block) (err error) {
|
|
|
|
if ldbp.iterator == nil {
|
2014-08-21 14:46:34 +02:00
|
|
|
err = ErrNoMoreBlocks
|
2014-08-20 16:21:44 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if !ldbp.iterator.Valid() {
|
|
|
|
if err = ldbp.iterator.GetError(); err == nil {
|
2014-08-21 14:46:34 +02:00
|
|
|
err = ErrNoMoreBlocks
|
2014-08-20 16:21:44 +02:00
|
|
|
}
|
|
|
|
ldbp.iterator.Close()
|
|
|
|
ldbp.iterator = nil
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var key int64
|
|
|
|
if key, err = ldbp.decoder(ldbp.iterator.Key()); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
block.Coord = ldbp.splitter(key)
|
|
|
|
block.Data = ldbp.iterator.Value()
|
|
|
|
return
|
2014-08-20 15:26:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewLevelDBBlockConsumer(
|
|
|
|
path string,
|
|
|
|
joiner common.KeyJoiner,
|
|
|
|
encoder common.KeyEncoder) (ldbc *LevelDBBlockConsumer, err error) {
|
|
|
|
|
|
|
|
opts := leveldb.NewOptions()
|
|
|
|
opts.SetCreateIfMissing(true)
|
|
|
|
|
|
|
|
var db *leveldb.DB
|
|
|
|
if db, err = leveldb.Open(path, opts); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ldbc = &LevelDBBlockConsumer{
|
|
|
|
db: db,
|
2014-08-20 16:21:44 +02:00
|
|
|
opts: opts,
|
2014-08-20 15:26:31 +02:00
|
|
|
wo: leveldb.NewWriteOptions(),
|
|
|
|
joiner: joiner,
|
|
|
|
encoder: encoder}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ldbc *LevelDBBlockConsumer) Close() error {
|
|
|
|
ldbc.wo.Close()
|
|
|
|
ldbc.db.Close()
|
2014-08-20 16:21:44 +02:00
|
|
|
ldbc.opts.Close()
|
2014-08-20 15:26:31 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-08-20 15:34:20 +02:00
|
|
|
func (ldbc *LevelDBBlockConsumer) Consume(block *Block) (err error) {
|
2014-08-20 15:26:31 +02:00
|
|
|
var encodedKey []byte
|
|
|
|
if encodedKey, err = ldbc.encoder(ldbc.joiner(block.Coord)); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
err = ldbc.db.Put(ldbc.wo, encodedKey, block.Data)
|
|
|
|
return
|
|
|
|
}
|