arnaucube
arnaucube/go-merkletree-iden3Public Self-hosted repository
go-merkletree-iden3/db/pebble/pebble.go
db/pebble/pebble.goRaw
  1package pebble
  2
  3import (
  4	"bytes"
  5	"encoding/json"
  6
  7	"github.com/cockroachdb/pebble"
  8	"github.com/iden3/go-merkletree/db"
  9	log "github.com/sirupsen/logrus"
 10)
 11
 12// PebbleStorage implements the db.Storage interface
 13type PebbleStorage struct {
 14	pdb    *pebble.DB
 15	prefix []byte
 16}
 17
 18// PebbleStorageTx implements the db.Tx interface
 19type PebbleStorageTx struct {
 20	*PebbleStorage
 21	batch *pebble.Batch
 22}
 23
 24// NewPebbleStorage returns a new PebbleStorage
 25func NewPebbleStorage(path string, errorIfMissing bool) (*PebbleStorage, error) {
 26	o := &pebble.Options{
 27		ErrorIfNotExists: errorIfMissing,
 28	}
 29	rdb, err := pebble.Open(path, o)
 30	if err != nil {
 31		return nil, err
 32	}
 33	return &PebbleStorage{rdb, []byte{}}, nil
 34}
 35
 36type storageInfo struct {
 37	KeyCount   int
 38	ClaimCount int
 39}
 40
 41// Info implements the method Info of the interface db.Storage
 42func (p *PebbleStorage) Info() string {
 43	keycount := 0
 44	claimcount := 0
 45	err := p.Iterate(func(key []byte, value []byte) (bool, error) {
 46		if value[0] == byte(1) {
 47			claimcount++
 48		}
 49
 50		keycount++
 51		return true, nil
 52	})
 53	if err != nil {
 54		return err.Error()
 55	}
 56	json, _ := json.MarshalIndent(
 57		storageInfo{
 58			KeyCount:   keycount,
 59			ClaimCount: claimcount,
 60		},
 61		"", "  ",
 62	)
 63	return string(json)
 64}
 65
 66// WithPrefix implements the method WithPrefix of the interface db.Storage
 67func (p *PebbleStorage) WithPrefix(prefix []byte) db.Storage {
 68	return &PebbleStorage{p.pdb, db.Concat(p.prefix, prefix)}
 69}
 70
 71// NewTx implements the method NewTx of the interface db.Storage
 72func (p *PebbleStorage) NewTx() (db.Tx, error) {
 73	return &PebbleStorageTx{p, p.pdb.NewIndexedBatch()}, nil
 74}
 75
 76// Get retreives a value from a key in the db.Storage
 77func (p *PebbleStorage) Get(key []byte) ([]byte, error) {
 78	v, closer, err := p.pdb.Get(db.Concat(p.prefix, key[:]))
 79	if err == pebble.ErrNotFound {
 80		return nil, db.ErrNotFound
 81	}
 82	closer.Close()
 83	return v, err
 84}
 85
 86// Iterate implements the method Iterate of the interface db.Storage
 87func (p *PebbleStorage) Iterate(f func([]byte, []byte) (bool, error)) error {
 88	// NewIter already provides a point-in-time view of the current DB
 89	// state, but if is used for long term (is not the case), should use an
 90	// iterator over an snapshot:
 91	// snapshot := p.pdb.NewSnapshot()
 92	// defer snapshot.Close()
 93	// iter := snapshot.NewIter(nil)
 94	iter := p.pdb.NewIter(nil)
 95	defer iter.Close()
 96
 97	iter.First() // move the iterator to the first key/value pair
 98	if len(iter.Key()) < len(p.prefix) || !bytes.Equal(iter.Key()[:len(p.prefix)], p.prefix) {
 99	} else {
100		localKey := iter.Key()[len(p.prefix):]
101		if _, err := f(localKey, iter.Value()); err != nil {
102			return err
103		}
104	}
105	for iter.Next() {
106		if len(iter.Key()) < len(p.prefix) || !bytes.Equal(iter.Key()[:len(p.prefix)], p.prefix) {
107			continue
108		}
109		localKey := iter.Key()[len(p.prefix):]
110		if cont, err := f(localKey, iter.Value()); err != nil {
111			return err
112		} else if !cont {
113			break
114		}
115	}
116	return iter.Error()
117}
118
119// Get retreives a value from a key in the interface db.Tx
120func (tx *PebbleStorageTx) Get(key []byte) ([]byte, error) {
121	var err error
122
123	fullkey := db.Concat(tx.prefix, key)
124
125	v, closer, err := tx.batch.Get(fullkey)
126	if err == pebble.ErrNotFound {
127		return nil, db.ErrNotFound
128	}
129	closer.Close()
130
131	return v, err
132}
133
134// Put saves a key:value into the db.Storage
135func (tx *PebbleStorageTx) Put(k, v []byte) error {
136	return tx.batch.Set(db.Concat(tx.prefix, k[:]), v, nil)
137}
138
139// Add implements the method Add of the interface db.Tx
140func (tx *PebbleStorageTx) Add(atx db.Tx) error {
141	patx := atx.(*PebbleStorageTx)
142	return tx.batch.Apply(patx.batch, nil)
143}
144
145// Commit implements the method Commit of the interface db.Tx
146func (tx *PebbleStorageTx) Commit() error {
147	return tx.batch.Commit(nil)
148}
149
150// Close implements the method Close of the interface db.Tx
151func (tx *PebbleStorageTx) Close() {
152	_ = tx.batch.Close()
153}
154
155// Close implements the method Close of the interface db.Storage
156func (p *PebbleStorage) Close() {
157	if err := p.pdb.Close(); err != nil {
158		panic(err)
159	}
160	log.Info("Database closed")
161}
162
163// Pebble is an extra method that returns the *pebble.DB
164func (p *PebbleStorage) Pebble() *pebble.DB {
165	return p.pdb
166}
167
168// List implements the method List of the interface db.Storage
169func (p *PebbleStorage) List(limit int) ([]db.KV, error) {
170	ret := []db.KV{}
171	err := p.Iterate(func(key []byte, value []byte) (bool, error) {
172		ret = append(ret, db.KV{K: db.Clone(key), V: db.Clone(value)})
173		if len(ret) == limit {
174			return false, nil
175		}
176		return true, nil
177	})
178	return ret, err
179}