arnaucube
arnaucube/go-merkletree-iden3Public Self-hosted repository
go-merkletree-iden3/db/leveldb/leveldb.go
db/leveldb/leveldb.goRaw
  1package leveldb
  2
  3import (
  4	"github.com/iden3/go-merkletree/db"
  5	log "github.com/sirupsen/logrus"
  6	"github.com/syndtr/goleveldb/leveldb"
  7	"github.com/syndtr/goleveldb/leveldb/errors"
  8	"github.com/syndtr/goleveldb/leveldb/opt"
  9	"github.com/syndtr/goleveldb/leveldb/util"
 10)
 11
 12// Storage implements the db.Storage interface
 13type Storage struct {
 14	ldb    *leveldb.DB
 15	prefix []byte
 16}
 17
 18// StorageTx implements the db.Tx interface
 19type StorageTx struct {
 20	*Storage
 21	cache db.KvMap
 22}
 23
 24// NewLevelDbStorage returns a new Storage
 25func NewLevelDbStorage(path string, errorIfMissing bool) (*Storage, error) {
 26	o := &opt.Options{
 27		ErrorIfMissing: errorIfMissing,
 28	}
 29	ldb, err := leveldb.OpenFile(path, o)
 30	if err != nil {
 31		return nil, err
 32	}
 33	return &Storage{ldb, []byte{}}, nil
 34}
 35
 36// WithPrefix implements the method WithPrefix of the interface db.Storage
 37func (l *Storage) WithPrefix(prefix []byte) db.Storage {
 38	return &Storage{l.ldb, db.Concat(l.prefix, prefix)}
 39}
 40
 41// NewTx implements the method NewTx of the interface db.Storage
 42func (l *Storage) NewTx() (db.Tx, error) {
 43	return &StorageTx{l, make(db.KvMap)}, nil
 44}
 45
 46// Get retreives a value from a key in the db.Storage
 47func (l *Storage) Get(key []byte) ([]byte, error) {
 48	v, err := l.ldb.Get(db.Concat(l.prefix, key[:]), nil)
 49	if err == errors.ErrNotFound {
 50		return nil, db.ErrNotFound
 51	}
 52	return v, err
 53}
 54
 55// Iterate implements the method Iterate of the interface db.Storage
 56func (l *Storage) Iterate(f func([]byte, []byte) (bool, error)) error {
 57	// FIXME: Use the prefix!
 58	snapshot, err := l.ldb.GetSnapshot()
 59	if err != nil {
 60		return err
 61	}
 62	iter := snapshot.NewIterator(util.BytesPrefix(l.prefix), nil)
 63	defer iter.Release()
 64	for iter.Next() {
 65		localKey := iter.Key()[len(l.prefix):]
 66		if cont, err := f(localKey, iter.Value()); err != nil {
 67			return err
 68		} else if !cont {
 69			break
 70		}
 71	}
 72	iter.Release()
 73	return iter.Error()
 74}
 75
 76// Get retreives a value from a key in the interface db.Tx
 77func (tx *StorageTx) Get(key []byte) ([]byte, error) {
 78	var err error
 79
 80	fullkey := db.Concat(tx.prefix, key)
 81
 82	if value, ok := tx.cache.Get(fullkey); ok {
 83		return value, nil
 84	}
 85
 86	value, err := tx.ldb.Get(fullkey, nil)
 87	if err == errors.ErrNotFound {
 88		return nil, db.ErrNotFound
 89	}
 90
 91	return value, err
 92}
 93
 94// Put saves a key:value into the db.Storage
 95func (tx *StorageTx) Put(k, v []byte) error {
 96	tx.cache.Put(db.Concat(tx.prefix, k[:]), v)
 97	return nil
 98}
 99
100// Add implements the method Add of the interface db.Tx
101func (tx *StorageTx) Add(atx db.Tx) error {
102	ldbtx := atx.(*StorageTx)
103	for _, v := range ldbtx.cache {
104		tx.cache.Put(v.K, v.V)
105	}
106	return nil
107}
108
109// Commit implements the method Commit of the interface db.Tx
110func (tx *StorageTx) Commit() error {
111	var batch leveldb.Batch
112	for _, v := range tx.cache {
113		batch.Put(v.K, v.V)
114	}
115
116	tx.cache = nil
117	return tx.ldb.Write(&batch, nil)
118}
119
120// Close implements the method Close of the interface db.Tx
121func (tx *StorageTx) Close() {
122	tx.cache = nil
123}
124
125// Close implements the method Close of the interface db.Storage
126func (l *Storage) Close() {
127	if err := l.ldb.Close(); err != nil {
128		panic(err)
129	}
130	log.Info("Database closed")
131}
132
133// LevelDB is an extra method that returns the *leveldb.DB
134func (l *Storage) LevelDB() *leveldb.DB {
135	return l.ldb
136}
137
138// List implements the method List of the interface db.Storage
139func (l *Storage) List(limit int) ([]db.KV, error) {
140	ret := []db.KV{}
141	err := l.Iterate(func(key []byte, value []byte) (bool, error) {
142		ret = append(ret, db.KV{K: db.Clone(key), V: db.Clone(value)})
143		if len(ret) == limit {
144			return false, nil
145		}
146		return true, nil
147	})
148	return ret, err
149}