github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/common/ledger/blkstorage/fsblkstorage/blockindex.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package fsblkstorage 18 19 import ( 20 "bytes" 21 "errors" 22 "fmt" 23 24 "github.com/golang/protobuf/proto" 25 "github.com/hyperledger/fabric/common/ledger/blkstorage" 26 "github.com/hyperledger/fabric/common/ledger/util" 27 "github.com/hyperledger/fabric/common/ledger/util/leveldbhelper" 28 ledgerUtil "github.com/hyperledger/fabric/core/ledger/util" 29 "github.com/hyperledger/fabric/protos/common" 30 "github.com/hyperledger/fabric/protos/peer" 31 ) 32 33 const ( 34 blockNumIdxKeyPrefix = 'n' 35 blockHashIdxKeyPrefix = 'h' 36 txIDIdxKeyPrefix = 't' 37 blockNumTranNumIdxKeyPrefix = 'a' 38 blockTxIDIdxKeyPrefix = 'b' 39 txValidationResultIdxKeyPrefix = 'v' 40 indexCheckpointKeyStr = "indexCheckpointKey" 41 ) 42 43 var indexCheckpointKey = []byte(indexCheckpointKeyStr) 44 var errIndexEmpty = errors.New("NoBlockIndexed") 45 46 type index interface { 47 getLastBlockIndexed() (uint64, error) 48 indexBlock(blockIdxInfo *blockIdxInfo) error 49 getBlockLocByHash(blockHash []byte) (*fileLocPointer, error) 50 getBlockLocByBlockNum(blockNum uint64) (*fileLocPointer, error) 51 getTxLoc(txID string) (*fileLocPointer, error) 52 getTXLocByBlockNumTranNum(blockNum uint64, tranNum uint64) (*fileLocPointer, error) 53 getBlockLocByTxID(txID string) (*fileLocPointer, error) 54 getTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error) 55 } 56 57 type blockIdxInfo struct { 58 blockNum uint64 59 blockHash []byte 60 flp *fileLocPointer 61 txOffsets []*txindexInfo 62 metadata *common.BlockMetadata 63 } 64 65 type blockIndex struct { 66 indexItemsMap map[blkstorage.IndexableAttr]bool 67 db *leveldbhelper.DBHandle 68 } 69 70 func newBlockIndex(indexConfig *blkstorage.IndexConfig, db *leveldbhelper.DBHandle) *blockIndex { 71 indexItems := indexConfig.AttrsToIndex 72 logger.Debugf("newBlockIndex() - indexItems:[%s]", indexItems) 73 indexItemsMap := make(map[blkstorage.IndexableAttr]bool) 74 for _, indexItem := range indexItems { 75 indexItemsMap[indexItem] = true 76 } 77 return &blockIndex{indexItemsMap, db} 78 } 79 80 func (index *blockIndex) getLastBlockIndexed() (uint64, error) { 81 var blockNumBytes []byte 82 var err error 83 if blockNumBytes, err = index.db.Get(indexCheckpointKey); err != nil { 84 return 0, err 85 } 86 if blockNumBytes == nil { 87 return 0, errIndexEmpty 88 } 89 return decodeBlockNum(blockNumBytes), nil 90 } 91 92 func (index *blockIndex) indexBlock(blockIdxInfo *blockIdxInfo) error { 93 // do not index anything 94 if len(index.indexItemsMap) == 0 { 95 logger.Debug("Not indexing block... as nothing to index") 96 return nil 97 } 98 logger.Debugf("Indexing block [%s]", blockIdxInfo) 99 flp := blockIdxInfo.flp 100 txOffsets := blockIdxInfo.txOffsets 101 txsfltr := ledgerUtil.TxValidationFlags(blockIdxInfo.metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 102 batch := leveldbhelper.NewUpdateBatch() 103 flpBytes, err := flp.marshal() 104 if err != nil { 105 return err 106 } 107 108 //Index1 109 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockHash]; ok { 110 batch.Put(constructBlockHashKey(blockIdxInfo.blockHash), flpBytes) 111 } 112 113 //Index2 114 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockNum]; ok { 115 batch.Put(constructBlockNumKey(blockIdxInfo.blockNum), flpBytes) 116 } 117 118 //Index3 Used to find a transaction by it's transaction id 119 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrTxID]; ok { 120 for _, txoffset := range txOffsets { 121 txFlp := newFileLocationPointer(flp.fileSuffixNum, flp.offset, txoffset.loc) 122 logger.Debugf("Adding txLoc [%s] for tx ID: [%s] to index", txFlp, txoffset.txID) 123 txFlpBytes, marshalErr := txFlp.marshal() 124 if marshalErr != nil { 125 return marshalErr 126 } 127 batch.Put(constructTxIDKey(txoffset.txID), txFlpBytes) 128 } 129 } 130 131 //Index4 - Store BlockNumTranNum will be used to query history data 132 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockNumTranNum]; ok { 133 for txIterator, txoffset := range txOffsets { 134 txFlp := newFileLocationPointer(flp.fileSuffixNum, flp.offset, txoffset.loc) 135 logger.Debugf("Adding txLoc [%s] for tx number:[%d] ID: [%s] to blockNumTranNum index", txFlp, txIterator, txoffset.txID) 136 txFlpBytes, marshalErr := txFlp.marshal() 137 if marshalErr != nil { 138 return marshalErr 139 } 140 batch.Put(constructBlockNumTranNumKey(blockIdxInfo.blockNum, uint64(txIterator)), txFlpBytes) 141 } 142 } 143 144 // Index5 - Store BlockNumber will be used to find block by transaction id 145 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockTxID]; ok { 146 for _, txoffset := range txOffsets { 147 batch.Put(constructBlockTxIDKey(txoffset.txID), flpBytes) 148 } 149 } 150 151 // Index6 - Store transaction validation result by transaction id 152 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrTxValidationCode]; ok { 153 for idx, txoffset := range txOffsets { 154 batch.Put(constructTxValidationCodeIDKey(txoffset.txID), []byte{byte(txsfltr.Flag(idx))}) 155 } 156 } 157 158 batch.Put(indexCheckpointKey, encodeBlockNum(blockIdxInfo.blockNum)) 159 // Setting snyc to true as a precaution, false may be an ok optimization after further testing. 160 if err := index.db.WriteBatch(batch, true); err != nil { 161 return err 162 } 163 return nil 164 } 165 166 func (index *blockIndex) getBlockLocByHash(blockHash []byte) (*fileLocPointer, error) { 167 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockHash]; !ok { 168 return nil, blkstorage.ErrAttrNotIndexed 169 } 170 b, err := index.db.Get(constructBlockHashKey(blockHash)) 171 if err != nil { 172 return nil, err 173 } 174 if b == nil { 175 return nil, blkstorage.ErrNotFoundInIndex 176 } 177 blkLoc := &fileLocPointer{} 178 blkLoc.unmarshal(b) 179 return blkLoc, nil 180 } 181 182 func (index *blockIndex) getBlockLocByBlockNum(blockNum uint64) (*fileLocPointer, error) { 183 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockNum]; !ok { 184 return nil, blkstorage.ErrAttrNotIndexed 185 } 186 b, err := index.db.Get(constructBlockNumKey(blockNum)) 187 if err != nil { 188 return nil, err 189 } 190 if b == nil { 191 return nil, blkstorage.ErrNotFoundInIndex 192 } 193 blkLoc := &fileLocPointer{} 194 blkLoc.unmarshal(b) 195 return blkLoc, nil 196 } 197 198 func (index *blockIndex) getTxLoc(txID string) (*fileLocPointer, error) { 199 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrTxID]; !ok { 200 return nil, blkstorage.ErrAttrNotIndexed 201 } 202 b, err := index.db.Get(constructTxIDKey(txID)) 203 if err != nil { 204 return nil, err 205 } 206 if b == nil { 207 return nil, blkstorage.ErrNotFoundInIndex 208 } 209 txFLP := &fileLocPointer{} 210 txFLP.unmarshal(b) 211 return txFLP, nil 212 } 213 214 func (index *blockIndex) getBlockLocByTxID(txID string) (*fileLocPointer, error) { 215 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockTxID]; !ok { 216 return nil, blkstorage.ErrAttrNotIndexed 217 } 218 b, err := index.db.Get(constructBlockTxIDKey(txID)) 219 if err != nil { 220 return nil, err 221 } 222 if b == nil { 223 return nil, blkstorage.ErrNotFoundInIndex 224 } 225 txFLP := &fileLocPointer{} 226 txFLP.unmarshal(b) 227 return txFLP, nil 228 } 229 230 func (index *blockIndex) getTXLocByBlockNumTranNum(blockNum uint64, tranNum uint64) (*fileLocPointer, error) { 231 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockNumTranNum]; !ok { 232 return nil, blkstorage.ErrAttrNotIndexed 233 } 234 b, err := index.db.Get(constructBlockNumTranNumKey(blockNum, tranNum)) 235 if err != nil { 236 return nil, err 237 } 238 if b == nil { 239 return nil, blkstorage.ErrNotFoundInIndex 240 } 241 txFLP := &fileLocPointer{} 242 txFLP.unmarshal(b) 243 return txFLP, nil 244 } 245 246 func (index *blockIndex) getTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error) { 247 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrTxValidationCode]; !ok { 248 return peer.TxValidationCode(-1), blkstorage.ErrAttrNotIndexed 249 } 250 251 raw, err := index.db.Get(constructTxValidationCodeIDKey(txID)) 252 253 if err != nil { 254 return peer.TxValidationCode(-1), err 255 } else if raw == nil { 256 return peer.TxValidationCode(-1), blkstorage.ErrNotFoundInIndex 257 } else if len(raw) != 1 { 258 return peer.TxValidationCode(-1), errors.New("Invalid value in indexItems") 259 } 260 261 result := peer.TxValidationCode(int32(raw[0])) 262 263 return result, nil 264 } 265 266 func constructBlockNumKey(blockNum uint64) []byte { 267 blkNumBytes := util.EncodeOrderPreservingVarUint64(blockNum) 268 return append([]byte{blockNumIdxKeyPrefix}, blkNumBytes...) 269 } 270 271 func constructBlockHashKey(blockHash []byte) []byte { 272 return append([]byte{blockHashIdxKeyPrefix}, blockHash...) 273 } 274 275 func constructTxIDKey(txID string) []byte { 276 return append([]byte{txIDIdxKeyPrefix}, []byte(txID)...) 277 } 278 279 func constructBlockTxIDKey(txID string) []byte { 280 return append([]byte{blockTxIDIdxKeyPrefix}, []byte(txID)...) 281 } 282 283 func constructTxValidationCodeIDKey(txID string) []byte { 284 return append([]byte{txValidationResultIdxKeyPrefix}, []byte(txID)...) 285 } 286 287 func constructBlockNumTranNumKey(blockNum uint64, txNum uint64) []byte { 288 blkNumBytes := util.EncodeOrderPreservingVarUint64(blockNum) 289 tranNumBytes := util.EncodeOrderPreservingVarUint64(txNum) 290 key := append(blkNumBytes, tranNumBytes...) 291 return append([]byte{blockNumTranNumIdxKeyPrefix}, key...) 292 } 293 294 func encodeBlockNum(blockNum uint64) []byte { 295 return proto.EncodeVarint(blockNum) 296 } 297 298 func decodeBlockNum(blockNumBytes []byte) uint64 { 299 blockNum, _ := proto.DecodeVarint(blockNumBytes) 300 return blockNum 301 } 302 303 type locPointer struct { 304 offset int 305 bytesLength int 306 } 307 308 func (lp *locPointer) String() string { 309 return fmt.Sprintf("offset=%d, bytesLength=%d", 310 lp.offset, lp.bytesLength) 311 } 312 313 // fileLocPointer 314 type fileLocPointer struct { 315 fileSuffixNum int 316 locPointer 317 } 318 319 func newFileLocationPointer(fileSuffixNum int, beginningOffset int, relativeLP *locPointer) *fileLocPointer { 320 flp := &fileLocPointer{fileSuffixNum: fileSuffixNum} 321 flp.offset = beginningOffset + relativeLP.offset 322 flp.bytesLength = relativeLP.bytesLength 323 return flp 324 } 325 326 func (flp *fileLocPointer) marshal() ([]byte, error) { 327 buffer := proto.NewBuffer([]byte{}) 328 e := buffer.EncodeVarint(uint64(flp.fileSuffixNum)) 329 if e != nil { 330 return nil, e 331 } 332 e = buffer.EncodeVarint(uint64(flp.offset)) 333 if e != nil { 334 return nil, e 335 } 336 e = buffer.EncodeVarint(uint64(flp.bytesLength)) 337 if e != nil { 338 return nil, e 339 } 340 return buffer.Bytes(), nil 341 } 342 343 func (flp *fileLocPointer) unmarshal(b []byte) error { 344 buffer := proto.NewBuffer(b) 345 i, e := buffer.DecodeVarint() 346 if e != nil { 347 return e 348 } 349 flp.fileSuffixNum = int(i) 350 351 i, e = buffer.DecodeVarint() 352 if e != nil { 353 return e 354 } 355 flp.offset = int(i) 356 i, e = buffer.DecodeVarint() 357 if e != nil { 358 return e 359 } 360 flp.bytesLength = int(i) 361 return nil 362 } 363 364 func (flp *fileLocPointer) String() string { 365 return fmt.Sprintf("fileSuffixNum=%d, %s", flp.fileSuffixNum, flp.locPointer.String()) 366 } 367 368 func (blockIdxInfo *blockIdxInfo) String() string { 369 370 var buffer bytes.Buffer 371 for _, txOffset := range blockIdxInfo.txOffsets { 372 buffer.WriteString("txId=") 373 buffer.WriteString(txOffset.txID) 374 buffer.WriteString(" locPointer=") 375 buffer.WriteString(txOffset.loc.String()) 376 buffer.WriteString("\n") 377 } 378 txOffsetsString := buffer.String() 379 380 return fmt.Sprintf("blockNum=%d, blockHash=%#v txOffsets=\n%s", blockIdxInfo.blockNum, blockIdxInfo.blockHash, txOffsetsString) 381 }