github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/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/hyperledger/fabric/common/ledger/dataformat" 15 "github.com/syndtr/goleveldb/leveldb" 16 "github.com/syndtr/goleveldb/leveldb/iterator" 17 ) 18 19 // internalDBName is used to keep track of data related to internals such as data format 20 // _ is used as name because this is not allowed as a channelname 21 const internalDBName = "_" 22 23 var ( 24 dbNameKeySep = []byte{0x00} 25 lastKeyIndicator = byte(0x01) 26 formatVersionKey = []byte{'f'} // a single key in db whose value indicates the version of the data format 27 ) 28 29 // Conf configuration for `Provider` 30 // 31 // `ExpectedFormatVersion` is the expected value of the format key in the internal database. 32 // At the time of opening the db, A check is performed that 33 // either the db is empty (i.e., opening for the first time) or the value 34 // of the formatVersionKey is equal to `ExpectedFormatVersion`. Otherwise, an error is returned. 35 // A nil value for ExpectedFormatVersion indicates that the format is never set and hence there is no such record 36 type Conf struct { 37 DBPath string 38 ExpectedFormatVersion string 39 } 40 41 // Provider enables to use a single leveldb as multiple logical leveldbs 42 type Provider struct { 43 db *DB 44 45 mux sync.Mutex 46 dbHandles map[string]*DBHandle 47 } 48 49 // NewProvider constructs a Provider 50 func NewProvider(conf *Conf) (*Provider, error) { 51 db, err := openDBAndCheckFormat(conf) 52 if err != nil { 53 return nil, err 54 } 55 return &Provider{ 56 db: db, 57 dbHandles: make(map[string]*DBHandle), 58 }, nil 59 } 60 61 func openDBAndCheckFormat(conf *Conf) (d *DB, e error) { 62 db := CreateDB(conf) 63 db.Open() 64 65 defer func() { 66 if e != nil { 67 db.Close() 68 } 69 }() 70 71 internalDB := &DBHandle{ 72 db: db, 73 dbName: internalDBName, 74 } 75 76 dbEmpty, err := db.IsEmpty() 77 if err != nil { 78 return nil, err 79 } 80 81 if dbEmpty && conf.ExpectedFormatVersion != "" { 82 logger.Infof("DB is empty Setting db format as %s", conf.ExpectedFormatVersion) 83 if err := internalDB.Put(formatVersionKey, []byte(conf.ExpectedFormatVersion), true); err != nil { 84 return nil, err 85 } 86 return db, nil 87 } 88 89 formatVersion, err := internalDB.Get(formatVersionKey) 90 if err != nil { 91 return nil, err 92 } 93 logger.Debugf("Checking for db format at path [%s]", conf.DBPath) 94 95 if !bytes.Equal(formatVersion, []byte(conf.ExpectedFormatVersion)) { 96 logger.Errorf("The db at path [%s] contains data in unexpected format. expected data format = [%s] (%#v), data format = [%s] (%#v).", 97 conf.DBPath, conf.ExpectedFormatVersion, []byte(conf.ExpectedFormatVersion), formatVersion, formatVersion) 98 return nil, &dataformat.ErrVersionMismatch{ 99 ExpectedVersion: conf.ExpectedFormatVersion, 100 Version: string(formatVersion), 101 DBInfo: fmt.Sprintf("leveldb at [%s]", conf.DBPath), 102 } 103 } 104 logger.Debug("format is latest, nothing to do") 105 return db, nil 106 } 107 108 // GetDataFormat returns the format of the data 109 func (p *Provider) GetDataFormat() (string, error) { 110 f, err := p.GetDBHandle(internalDBName).Get(formatVersionKey) 111 return string(f), err 112 } 113 114 // GetDBHandle returns a handle to a named db 115 func (p *Provider) GetDBHandle(dbName string) *DBHandle { 116 p.mux.Lock() 117 defer p.mux.Unlock() 118 dbHandle := p.dbHandles[dbName] 119 if dbHandle == nil { 120 dbHandle = &DBHandle{dbName, p.db} 121 p.dbHandles[dbName] = dbHandle 122 } 123 return dbHandle 124 } 125 126 // Close closes the underlying leveldb 127 func (p *Provider) Close() { 128 p.db.Close() 129 } 130 131 // DBHandle is an handle to a named db 132 type DBHandle struct { 133 dbName string 134 db *DB 135 } 136 137 // Get returns the value for the given key 138 func (h *DBHandle) Get(key []byte) ([]byte, error) { 139 return h.db.Get(constructLevelKey(h.dbName, key)) 140 } 141 142 // Put saves the key/value 143 func (h *DBHandle) Put(key []byte, value []byte, sync bool) error { 144 return h.db.Put(constructLevelKey(h.dbName, key), value, sync) 145 } 146 147 // Delete deletes the given key 148 func (h *DBHandle) Delete(key []byte, sync bool) error { 149 return h.db.Delete(constructLevelKey(h.dbName, key), sync) 150 } 151 152 // WriteBatch writes a batch in an atomic way 153 func (h *DBHandle) WriteBatch(batch *UpdateBatch, sync bool) error { 154 if len(batch.KVs) == 0 { 155 return nil 156 } 157 levelBatch := &leveldb.Batch{} 158 for k, v := range batch.KVs { 159 key := constructLevelKey(h.dbName, []byte(k)) 160 if v == nil { 161 levelBatch.Delete(key) 162 } else { 163 levelBatch.Put(key, v) 164 } 165 } 166 if err := h.db.WriteBatch(levelBatch, sync); err != nil { 167 return err 168 } 169 return nil 170 } 171 172 // GetIterator gets an handle to iterator. The iterator should be released after the use. 173 // The resultset contains all the keys that are present in the db between the startKey (inclusive) and the endKey (exclusive). 174 // A nil startKey represents the first available key and a nil endKey represent a logical key after the last available key 175 func (h *DBHandle) GetIterator(startKey []byte, endKey []byte) *Iterator { 176 sKey := constructLevelKey(h.dbName, startKey) 177 eKey := constructLevelKey(h.dbName, endKey) 178 if endKey == nil { 179 // replace the last byte 'dbNameKeySep' by 'lastKeyIndicator' 180 eKey[len(eKey)-1] = lastKeyIndicator 181 } 182 logger.Debugf("Getting iterator for range [%#v] - [%#v]", sKey, eKey) 183 return &Iterator{h.db.GetIterator(sKey, eKey)} 184 } 185 186 // UpdateBatch encloses the details of multiple `updates` 187 type UpdateBatch struct { 188 KVs map[string][]byte 189 } 190 191 // NewUpdateBatch constructs an instance of a Batch 192 func NewUpdateBatch() *UpdateBatch { 193 return &UpdateBatch{make(map[string][]byte)} 194 } 195 196 // Put adds a KV 197 func (batch *UpdateBatch) Put(key []byte, value []byte) { 198 if value == nil { 199 panic("Nil value not allowed") 200 } 201 batch.KVs[string(key)] = value 202 } 203 204 // Delete deletes a Key and associated value 205 func (batch *UpdateBatch) Delete(key []byte) { 206 batch.KVs[string(key)] = nil 207 } 208 209 // Len returns the number of entries in the batch 210 func (batch *UpdateBatch) Len() int { 211 return len(batch.KVs) 212 } 213 214 // Iterator extends actual leveldb iterator 215 type Iterator struct { 216 iterator.Iterator 217 } 218 219 // Key wraps actual leveldb iterator method 220 func (itr *Iterator) Key() []byte { 221 return retrieveAppKey(itr.Iterator.Key()) 222 } 223 224 func constructLevelKey(dbName string, key []byte) []byte { 225 return append(append([]byte(dbName), dbNameKeySep...), key...) 226 } 227 228 func retrieveAppKey(levelKey []byte) []byte { 229 return bytes.SplitN(levelKey, dbNameKeySep, 2)[1] 230 }