github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/common/ledger/util/leveldbhelper/leveldb_provider.go (about) 1 /* 2 Copyright IBM Corp. 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/osdi23p228/fabric/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 // DBHandle is an handle to a named db 146 type DBHandle struct { 147 dbName string 148 db *DB 149 closeFunc closeFunc 150 } 151 152 // Get returns the value for the given key 153 func (h *DBHandle) Get(key []byte) ([]byte, error) { 154 return h.db.Get(constructLevelKey(h.dbName, key)) 155 } 156 157 // Put saves the key/value 158 func (h *DBHandle) Put(key []byte, value []byte, sync bool) error { 159 return h.db.Put(constructLevelKey(h.dbName, key), value, sync) 160 } 161 162 // Delete deletes the given key 163 func (h *DBHandle) Delete(key []byte, sync bool) error { 164 return h.db.Delete(constructLevelKey(h.dbName, key), sync) 165 } 166 167 // DeleteAll deletes all the keys that belong to the channel (dbName). 168 func (h *DBHandle) DeleteAll() error { 169 iter, err := h.GetIterator(nil, nil) 170 if err != nil { 171 return err 172 } 173 defer iter.Release() 174 175 // use leveldb iterator directly to be more efficient 176 dbIter := iter.Iterator 177 178 // This is common code shared by all the leveldb instances. Because each leveldb has its own key size pattern, 179 // each batch is limited by memory usage instead of number of keys. Once the batch memory usage reaches maxBatchSize, 180 // the batch will be committed. 181 numKeys := 0 182 batchSize := 0 183 batch := &leveldb.Batch{} 184 for dbIter.Next() { 185 if err := dbIter.Error(); err != nil { 186 return errors.Wrap(err, "internal leveldb error while retrieving data from db iterator") 187 } 188 key := dbIter.Key() 189 numKeys++ 190 batchSize = batchSize + len(key) 191 batch.Delete(key) 192 if batchSize >= maxBatchSize { 193 if err := h.db.WriteBatch(batch, true); err != nil { 194 return err 195 } 196 logger.Infof("Have removed %d entries for channel %s in leveldb %s", numKeys, h.dbName, h.db.conf.DBPath) 197 batchSize = 0 198 batch = &leveldb.Batch{} 199 } 200 } 201 if batch.Len() > 0 { 202 return h.db.WriteBatch(batch, true) 203 } 204 return nil 205 } 206 207 // NewUpdateBatch returns a new UpdateBatch that can be used to update the db 208 func (h *DBHandle) NewUpdateBatch() *UpdateBatch { 209 return &UpdateBatch{ 210 dbName: h.dbName, 211 Batch: &leveldb.Batch{}, 212 } 213 } 214 215 // WriteBatch writes a batch in an atomic way 216 func (h *DBHandle) WriteBatch(batch *UpdateBatch, sync bool) error { 217 if batch == nil || batch.Len() == 0 { 218 return nil 219 } 220 if err := h.db.WriteBatch(batch.Batch, sync); err != nil { 221 return err 222 } 223 return nil 224 } 225 226 // GetIterator gets an handle to iterator. The iterator should be released after the use. 227 // The resultset contains all the keys that are present in the db between the startKey (inclusive) and the endKey (exclusive). 228 // A nil startKey represents the first available key and a nil endKey represent a logical key after the last available key 229 func (h *DBHandle) GetIterator(startKey []byte, endKey []byte) (*Iterator, error) { 230 sKey := constructLevelKey(h.dbName, startKey) 231 eKey := constructLevelKey(h.dbName, endKey) 232 if endKey == nil { 233 // replace the last byte 'dbNameKeySep' by 'lastKeyIndicator' 234 eKey[len(eKey)-1] = lastKeyIndicator 235 } 236 logger.Debugf("Getting iterator for range [%#v] - [%#v]", sKey, eKey) 237 itr := h.db.GetIterator(sKey, eKey) 238 if err := itr.Error(); err != nil { 239 itr.Release() 240 return nil, errors.Wrapf(err, "internal leveldb error while obtaining db iterator") 241 } 242 return &Iterator{h.dbName, itr}, nil 243 } 244 245 // Close closes the DBHandle after its db data have been deleted 246 func (h *DBHandle) Close() { 247 if h.closeFunc != nil { 248 h.closeFunc() 249 } 250 } 251 252 // UpdateBatch encloses the details of multiple `updates` 253 type UpdateBatch struct { 254 *leveldb.Batch 255 dbName string 256 } 257 258 // Put adds a KV 259 func (b *UpdateBatch) Put(key []byte, value []byte) { 260 if value == nil { 261 panic("Nil value not allowed") 262 } 263 b.Batch.Put(constructLevelKey(b.dbName, key), value) 264 } 265 266 // Delete deletes a Key and associated value 267 func (b *UpdateBatch) Delete(key []byte) { 268 b.Batch.Delete(constructLevelKey(b.dbName, key)) 269 } 270 271 // Iterator extends actual leveldb iterator 272 type Iterator struct { 273 dbName string 274 iterator.Iterator 275 } 276 277 // Key wraps actual leveldb iterator method 278 func (itr *Iterator) Key() []byte { 279 return retrieveAppKey(itr.Iterator.Key()) 280 } 281 282 // Seek moves the iterator to the first key/value pair 283 // whose key is greater than or equal to the given key. 284 // It returns whether such pair exist. 285 func (itr *Iterator) Seek(key []byte) bool { 286 levelKey := constructLevelKey(itr.dbName, key) 287 return itr.Iterator.Seek(levelKey) 288 } 289 290 func constructLevelKey(dbName string, key []byte) []byte { 291 return append(append([]byte(dbName), dbNameKeySep...), key...) 292 } 293 294 func retrieveAppKey(levelKey []byte) []byte { 295 return bytes.SplitN(levelKey, dbNameKeySep, 2)[1] 296 }