github.com/lazyledger/lazyledger-core@v0.35.0-dev.0.20210613111200-4c651f053571/libs/db/badgerdb/db.go (about)

     1  package badgerdb
     2  
     3  import (
     4  	"bytes"
     5  	"os"
     6  	"path/filepath"
     7  
     8  	"github.com/dgraph-io/badger/v3"
     9  	"github.com/dgraph-io/badger/v3/options"
    10  
    11  	"github.com/lazyledger/lazyledger-core/libs/db"
    12  )
    13  
    14  // NewDB creates a Badger key-value store backed to the
    15  // directory dir supplied. If dir does not exist, it will be created.
    16  func NewDB(dbName, dir string) (*BadgerDB, error) {
    17  	// Since Badger doesn't support database names, we join both to obtain
    18  	// the final directory to use for the database.
    19  	path := filepath.Join(dir, dbName)
    20  
    21  	if err := os.MkdirAll(path, 0755); err != nil {
    22  		return nil, err
    23  	}
    24  	opts := badger.DefaultOptions(path)
    25  	opts.SyncWrites = false // note that we have Sync methods
    26  	// TODO(ismail): investigate if we don't want a logger here at least for errors though:
    27  	opts.Logger = nil // badger is too chatty by default
    28  	return NewDBWithOptions(opts)
    29  }
    30  
    31  // NewDBWithOptions creates a BadgerDB key value store
    32  // gives the flexibility of initializing a database with the
    33  // respective options.
    34  func NewDBWithOptions(opts badger.Options) (*BadgerDB, error) {
    35  	db, err := badger.Open(opts)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	return &BadgerDB{db: db}, nil
    40  }
    41  
    42  // NewInMemoryDB creates a light weight in-memory BadgerDB.
    43  // Mainly useful for unit-tests.
    44  func NewInMemoryDB() (*BadgerDB, error) {
    45  	opts := badger.DefaultOptions("")
    46  	opts.InMemory = true
    47  	opts.NumCompactors = 2          // minimize number of go-routines
    48  	opts.Compression = options.None // this is supposed to be short-lived
    49  	opts.ZSTDCompressionLevel = 0   // this is supposed to be short-lived
    50  	opts.Logger = nil               // there is not much that can go wrong in-memory
    51  	db, err := badger.Open(opts)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  	return &BadgerDB{db: db}, nil
    56  }
    57  
    58  type BadgerDB struct {
    59  	db *badger.DB
    60  }
    61  
    62  var _ db.DB = (*BadgerDB)(nil)
    63  
    64  func (b *BadgerDB) Get(key []byte) ([]byte, error) {
    65  	if len(key) == 0 {
    66  		return nil, db.ErrKeyEmpty
    67  	}
    68  	var val []byte
    69  	err := b.db.View(func(txn *badger.Txn) error {
    70  		item, err := txn.Get(key)
    71  		if err == badger.ErrKeyNotFound {
    72  			return nil
    73  		} else if err != nil {
    74  			return err
    75  		}
    76  		val, err = item.ValueCopy(nil)
    77  		if err == nil && val == nil {
    78  			val = []byte{}
    79  		}
    80  		return err
    81  	})
    82  	return val, err
    83  }
    84  
    85  func (b *BadgerDB) Has(key []byte) (bool, error) {
    86  	if len(key) == 0 {
    87  		return false, db.ErrKeyEmpty
    88  	}
    89  	var found bool
    90  	err := b.db.View(func(txn *badger.Txn) error {
    91  		_, err := txn.Get(key)
    92  		if err != nil && err != badger.ErrKeyNotFound {
    93  			return err
    94  		}
    95  		found = (err != badger.ErrKeyNotFound)
    96  		return nil
    97  	})
    98  	return found, err
    99  }
   100  
   101  func (b *BadgerDB) Set(key, value []byte) error {
   102  	if len(key) == 0 {
   103  		return db.ErrKeyEmpty
   104  	}
   105  	if value == nil {
   106  		return db.ErrValueNil
   107  	}
   108  	return b.db.Update(func(txn *badger.Txn) error {
   109  		return txn.Set(key, value)
   110  	})
   111  }
   112  
   113  func withSync(db *badger.DB, err error) error {
   114  	if err != nil {
   115  		return err
   116  	}
   117  	return db.Sync()
   118  }
   119  
   120  func (b *BadgerDB) SetSync(key, value []byte) error {
   121  	return withSync(b.db, b.Set(key, value))
   122  }
   123  
   124  func (b *BadgerDB) Delete(key []byte) error {
   125  	if len(key) == 0 {
   126  		return db.ErrKeyEmpty
   127  	}
   128  	return b.db.Update(func(txn *badger.Txn) error {
   129  		return txn.Delete(key)
   130  	})
   131  }
   132  
   133  func (b *BadgerDB) DeleteSync(key []byte) error {
   134  	return withSync(b.db, b.Delete(key))
   135  }
   136  
   137  func (b *BadgerDB) Close() error {
   138  	return b.db.Close()
   139  }
   140  
   141  func (b *BadgerDB) Print() error {
   142  	return nil
   143  }
   144  
   145  func (b *BadgerDB) iteratorOpts(start, end []byte, opts badger.IteratorOptions) (*badgerDBIterator, error) {
   146  	if (start != nil && len(start) == 0) || (end != nil && len(end) == 0) {
   147  		return nil, db.ErrKeyEmpty
   148  	}
   149  	txn := b.db.NewTransaction(false)
   150  	iter := txn.NewIterator(opts)
   151  	iter.Rewind()
   152  	iter.Seek(start)
   153  	if opts.Reverse && iter.Valid() && bytes.Equal(iter.Item().Key(), start) {
   154  		// If we're going in reverse, our starting point was "end",
   155  		// which is exclusive.
   156  		iter.Next()
   157  	}
   158  	return &badgerDBIterator{
   159  		reverse: opts.Reverse,
   160  		start:   start,
   161  		end:     end,
   162  
   163  		txn:  txn,
   164  		iter: iter,
   165  	}, nil
   166  }
   167  
   168  func (b *BadgerDB) Iterator(start, end []byte) (db.Iterator, error) {
   169  	opts := badger.DefaultIteratorOptions
   170  	return b.iteratorOpts(start, end, opts)
   171  }
   172  
   173  func (b *BadgerDB) ReverseIterator(start, end []byte) (db.Iterator, error) {
   174  	opts := badger.DefaultIteratorOptions
   175  	opts.Reverse = true
   176  	return b.iteratorOpts(end, start, opts)
   177  }
   178  
   179  // todo: see about exposing badgerdb stats
   180  func (b *BadgerDB) Stats() map[string]string {
   181  	return nil
   182  }
   183  
   184  func (b *BadgerDB) NewBatch() db.Batch {
   185  	wb := &badgerDBBatch{
   186  		db: b.db,
   187  		wb: b.db.NewWriteBatch(),
   188  	}
   189  	return wb
   190  }
   191  
   192  var _ db.Batch = (*badgerDBBatch)(nil)
   193  
   194  type badgerDBBatch struct {
   195  	db *badger.DB
   196  	wb *badger.WriteBatch
   197  }
   198  
   199  func (b *badgerDBBatch) Set(key, value []byte) error {
   200  	if len(key) == 0 {
   201  		return db.ErrKeyEmpty
   202  	}
   203  	if value == nil {
   204  		return db.ErrValueNil
   205  	}
   206  	return b.wb.Set(key, value)
   207  }
   208  
   209  func (b *badgerDBBatch) Delete(key []byte) error {
   210  	if len(key) == 0 {
   211  		return db.ErrKeyEmpty
   212  	}
   213  	return b.wb.Delete(key)
   214  }
   215  
   216  func (b *badgerDBBatch) Write() error {
   217  	return b.wb.Flush()
   218  }
   219  
   220  func (b *badgerDBBatch) WriteSync() error {
   221  	return withSync(b.db, b.Write())
   222  }
   223  
   224  func (b *badgerDBBatch) Close() error {
   225  	b.wb.Cancel()
   226  
   227  	return nil
   228  }
   229  
   230  type badgerDBIterator struct {
   231  	reverse    bool
   232  	start, end []byte
   233  
   234  	txn  *badger.Txn
   235  	iter *badger.Iterator
   236  
   237  	lastErr error
   238  }
   239  
   240  func (i *badgerDBIterator) Close() error {
   241  	i.iter.Close()
   242  	i.txn.Discard()
   243  	return nil
   244  }
   245  
   246  func (i *badgerDBIterator) Domain() (start, end []byte) { return i.start, i.end }
   247  func (i *badgerDBIterator) Error() error                { return i.lastErr }
   248  
   249  func (i *badgerDBIterator) Next() {
   250  	if !i.Valid() {
   251  		panic("iterator is invalid")
   252  	}
   253  	i.iter.Next()
   254  }
   255  
   256  func (i *badgerDBIterator) Valid() bool {
   257  	if !i.iter.Valid() {
   258  		return false
   259  	}
   260  	if len(i.end) > 0 {
   261  		key := i.iter.Item().Key()
   262  		if c := bytes.Compare(key, i.end); (!i.reverse && c >= 0) || (i.reverse && c < 0) {
   263  			// We're at the end key, or past the end.
   264  			return false
   265  		}
   266  	}
   267  	return true
   268  }
   269  
   270  func (i *badgerDBIterator) Key() []byte {
   271  	if !i.Valid() {
   272  		panic("iterator is invalid")
   273  	}
   274  	// Note that we don't use KeyCopy, so this is only valid until the next
   275  	// call to Next.
   276  	return i.iter.Item().KeyCopy(nil)
   277  }
   278  
   279  func (i *badgerDBIterator) Value() []byte {
   280  	if !i.Valid() {
   281  		panic("iterator is invalid")
   282  	}
   283  	val, err := i.iter.Item().ValueCopy(nil)
   284  	if err != nil {
   285  		i.lastErr = err
   286  	}
   287  	return val
   288  }