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 }