github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/common/ledger/util/leveldbhelper/leveldb_provider.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package leveldbhelper 8 9 import ( 10 "bytes" 11 "fmt" 12 "sync" 13 14 "github.com/hechain20/hechain/common/ledger/dataformat" 15 "github.com/pkg/errors" 16 "github.com/syndtr/goleveldb/leveldb" 17 "github.com/syndtr/goleveldb/leveldb/iterator" 18 ) 19 20 const ( 21 // internalDBName is used to keep track of data related to internals such as data format 22 // _ is used as name because this is not allowed as a channelname 23 internalDBName = "_" 24 // maxBatchSize limits the memory usage (1MB) for a batch. It is measured by the total number of bytes 25 // of all the keys in a batch. 26 maxBatchSize = 1000000 27 ) 28 29 var ( 30 dbNameKeySep = []byte{0x00} 31 lastKeyIndicator = byte(0x01) 32 formatVersionKey = []byte{'f'} // a single key in db whose value indicates the version of the data format 33 ) 34 35 // closeFunc closes the db handle 36 type closeFunc func() 37 38 // Conf configuration for `Provider` 39 // 40 // `ExpectedFormat` is the expected value of the format key in the internal database. 41 // At the time of opening the db, A check is performed that 42 // either the db is empty (i.e., opening for the first time) or the value 43 // of the formatVersionKey is equal to `ExpectedFormat`. Otherwise, an error is returned. 44 // A nil value for ExpectedFormat indicates that the format is never set and hence there is no such record. 45 type Conf struct { 46 DBPath string 47 ExpectedFormat string 48 } 49 50 // Provider enables to use a single leveldb as multiple logical leveldbs 51 type Provider struct { 52 db *DB 53 54 mux sync.Mutex 55 dbHandles map[string]*DBHandle 56 } 57 58 // NewProvider constructs a Provider 59 func NewProvider(conf *Conf) (*Provider, error) { 60 db, err := openDBAndCheckFormat(conf) 61 if err != nil { 62 return nil, err 63 } 64 return &Provider{ 65 db: db, 66 dbHandles: make(map[string]*DBHandle), 67 }, nil 68 } 69 70 func openDBAndCheckFormat(conf *Conf) (d *DB, e error) { 71 db := CreateDB(conf) 72 db.Open() 73 74 defer func() { 75 if e != nil { 76 db.Close() 77 } 78 }() 79 80 internalDB := &DBHandle{ 81 db: db, 82 dbName: internalDBName, 83 } 84 85 dbEmpty, err := db.IsEmpty() 86 if err != nil { 87 return nil, err 88 } 89 90 if dbEmpty && conf.ExpectedFormat != "" { 91 logger.Infof("DB is empty Setting db format as %s", conf.ExpectedFormat) 92 if err := internalDB.Put(formatVersionKey, []byte(conf.ExpectedFormat), true); err != nil { 93 return nil, err 94 } 95 return db, nil 96 } 97 98 formatVersion, err := internalDB.Get(formatVersionKey) 99 if err != nil { 100 return nil, err 101 } 102 logger.Debugf("Checking for db format at path [%s]", conf.DBPath) 103 104 if !bytes.Equal(formatVersion, []byte(conf.ExpectedFormat)) { 105 logger.Errorf("The db at path [%s] contains data in unexpected format. expected data format = [%s] (%#v), data format = [%s] (%#v).", 106 conf.DBPath, conf.ExpectedFormat, []byte(conf.ExpectedFormat), formatVersion, formatVersion) 107 return nil, &dataformat.ErrFormatMismatch{ 108 ExpectedFormat: conf.ExpectedFormat, 109 Format: string(formatVersion), 110 DBInfo: fmt.Sprintf("leveldb at [%s]", conf.DBPath), 111 } 112 } 113 logger.Debug("format is latest, nothing to do") 114 return db, nil 115 } 116 117 // GetDataFormat returns the format of the data 118 func (p *Provider) GetDataFormat() (string, error) { 119 f, err := p.GetDBHandle(internalDBName).Get(formatVersionKey) 120 return string(f), err 121 } 122 123 // GetDBHandle returns a handle to a named db 124 func (p *Provider) GetDBHandle(dbName string) *DBHandle { 125 p.mux.Lock() 126 defer p.mux.Unlock() 127 dbHandle := p.dbHandles[dbName] 128 if dbHandle == nil { 129 closeFunc := func() { 130 p.mux.Lock() 131 defer p.mux.Unlock() 132 delete(p.dbHandles, dbName) 133 } 134 dbHandle = &DBHandle{dbName, p.db, closeFunc} 135 p.dbHandles[dbName] = dbHandle 136 } 137 return dbHandle 138 } 139 140 // Close closes the underlying leveldb 141 func (p *Provider) Close() { 142 p.db.Close() 143 } 144 145 // Drop drops all the data for the given dbName 146 func (p *Provider) Drop(dbName string) error { 147 dbHandle := p.GetDBHandle(dbName) 148 defer dbHandle.Close() 149 return dbHandle.deleteAll() 150 } 151 152 // DBHandle is an handle to a named db 153 type DBHandle struct { 154 dbName string 155 db *DB 156 closeFunc closeFunc 157 } 158 159 // Get returns the value for the given key 160 func (h *DBHandle) Get(key []byte) ([]byte, error) { 161 return h.db.Get(constructLevelKey(h.dbName, key)) 162 } 163 164 // Put saves the key/value 165 func (h *DBHandle) Put(key []byte, value []byte, sync bool) error { 166 return h.db.Put(constructLevelKey(h.dbName, key), value, sync) 167 } 168 169 // Delete deletes the given key 170 func (h *DBHandle) Delete(key []byte, sync bool) error { 171 return h.db.Delete(constructLevelKey(h.dbName, key), sync) 172 } 173 174 // DeleteAll deletes all the keys that belong to the channel (dbName). 175 func (h *DBHandle) deleteAll() error { 176 iter, err := h.GetIterator(nil, nil) 177 if err != nil { 178 return err 179 } 180 defer iter.Release() 181 182 // use leveldb iterator directly to be more efficient 183 dbIter := iter.Iterator 184 185 // This is common code shared by all the leveldb instances. Because each leveldb has its own key size pattern, 186 // each batch is limited by memory usage instead of number of keys. Once the batch memory usage reaches maxBatchSize, 187 // the batch will be committed. 188 numKeys := 0 189 batchSize := 0 190 batch := &leveldb.Batch{} 191 for dbIter.Next() { 192 if err := dbIter.Error(); err != nil { 193 return errors.Wrap(err, "internal leveldb error while retrieving data from db iterator") 194 } 195 key := dbIter.Key() 196 numKeys++ 197 batchSize = batchSize + len(key) 198 batch.Delete(key) 199 if batchSize >= maxBatchSize { 200 if err := h.db.WriteBatch(batch, true); err != nil { 201 return err 202 } 203 logger.Infof("Have removed %d entries for channel %s in leveldb %s", numKeys, h.dbName, h.db.conf.DBPath) 204 batchSize = 0 205 batch.Reset() 206 } 207 } 208 if batch.Len() > 0 { 209 return h.db.WriteBatch(batch, true) 210 } 211 return nil 212 } 213 214 // IsEmpty returns true if no data exists for the DBHandle 215 func (h *DBHandle) IsEmpty() (bool, error) { 216 itr, err := h.GetIterator(nil, nil) 217 if err != nil { 218 return false, err 219 } 220 defer itr.Release() 221 222 if err := itr.Error(); err != nil { 223 return false, errors.WithMessagef(itr.Error(), "internal leveldb error while obtaining next entry from iterator") 224 } 225 226 return !itr.Next(), nil 227 } 228 229 // NewUpdateBatch returns a new UpdateBatch that can be used to update the db 230 func (h *DBHandle) NewUpdateBatch() *UpdateBatch { 231 return &UpdateBatch{ 232 dbName: h.dbName, 233 Batch: &leveldb.Batch{}, 234 } 235 } 236 237 // WriteBatch writes a batch in an atomic way 238 func (h *DBHandle) WriteBatch(batch *UpdateBatch, sync bool) error { 239 if batch == nil || batch.Len() == 0 { 240 return nil 241 } 242 if err := h.db.WriteBatch(batch.Batch, sync); err != nil { 243 return err 244 } 245 return nil 246 } 247 248 // GetIterator gets an handle to iterator. The iterator should be released after the use. 249 // The resultset contains all the keys that are present in the db between the startKey (inclusive) and the endKey (exclusive). 250 // A nil startKey represents the first available key and a nil endKey represent a logical key after the last available key 251 func (h *DBHandle) GetIterator(startKey []byte, endKey []byte) (*Iterator, error) { 252 sKey := constructLevelKey(h.dbName, startKey) 253 eKey := constructLevelKey(h.dbName, endKey) 254 if endKey == nil { 255 // replace the last byte 'dbNameKeySep' by 'lastKeyIndicator' 256 eKey[len(eKey)-1] = lastKeyIndicator 257 } 258 logger.Debugf("Getting iterator for range [%#v] - [%#v]", sKey, eKey) 259 itr := h.db.GetIterator(sKey, eKey) 260 if err := itr.Error(); err != nil { 261 itr.Release() 262 return nil, errors.Wrapf(err, "internal leveldb error while obtaining db iterator") 263 } 264 return &Iterator{h.dbName, itr}, nil 265 } 266 267 // Close closes the DBHandle after its db data have been deleted 268 func (h *DBHandle) Close() { 269 if h.closeFunc != nil { 270 h.closeFunc() 271 } 272 } 273 274 // UpdateBatch encloses the details of multiple `updates` 275 type UpdateBatch struct { 276 *leveldb.Batch 277 dbName string 278 } 279 280 // Put adds a KV 281 func (b *UpdateBatch) Put(key []byte, value []byte) { 282 if value == nil { 283 panic("Nil value not allowed") 284 } 285 b.Batch.Put(constructLevelKey(b.dbName, key), value) 286 } 287 288 // Delete deletes a Key and associated value 289 func (b *UpdateBatch) Delete(key []byte) { 290 b.Batch.Delete(constructLevelKey(b.dbName, key)) 291 } 292 293 // Iterator extends actual leveldb iterator 294 type Iterator struct { 295 dbName string 296 iterator.Iterator 297 } 298 299 // Key wraps actual leveldb iterator method 300 func (itr *Iterator) Key() []byte { 301 return retrieveAppKey(itr.Iterator.Key()) 302 } 303 304 // Seek moves the iterator to the first key/value pair 305 // whose key is greater than or equal to the given key. 306 // It returns whether such pair exist. 307 func (itr *Iterator) Seek(key []byte) bool { 308 levelKey := constructLevelKey(itr.dbName, key) 309 return itr.Iterator.Seek(levelKey) 310 } 311 312 func constructLevelKey(dbName string, key []byte) []byte { 313 return append(append([]byte(dbName), dbNameKeySep...), key...) 314 } 315 316 func retrieveAppKey(levelKey []byte) []byte { 317 return bytes.SplitN(levelKey, dbNameKeySep, 2)[1] 318 }