github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/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, nil 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 if err := index.db.WriteBatch(batch, false); err != nil { 160 return err 161 } 162 return nil 163 } 164 165 func (index *blockIndex) getBlockLocByHash(blockHash []byte) (*fileLocPointer, error) { 166 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockHash]; !ok { 167 return nil, blkstorage.ErrAttrNotIndexed 168 } 169 b, err := index.db.Get(constructBlockHashKey(blockHash)) 170 if err != nil { 171 return nil, err 172 } 173 if b == nil { 174 return nil, blkstorage.ErrNotFoundInIndex 175 } 176 blkLoc := &fileLocPointer{} 177 blkLoc.unmarshal(b) 178 return blkLoc, nil 179 } 180 181 func (index *blockIndex) getBlockLocByBlockNum(blockNum uint64) (*fileLocPointer, error) { 182 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockNum]; !ok { 183 return nil, blkstorage.ErrAttrNotIndexed 184 } 185 b, err := index.db.Get(constructBlockNumKey(blockNum)) 186 if err != nil { 187 return nil, err 188 } 189 if b == nil { 190 return nil, blkstorage.ErrNotFoundInIndex 191 } 192 blkLoc := &fileLocPointer{} 193 blkLoc.unmarshal(b) 194 return blkLoc, nil 195 } 196 197 func (index *blockIndex) getTxLoc(txID string) (*fileLocPointer, error) { 198 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrTxID]; !ok { 199 return nil, blkstorage.ErrAttrNotIndexed 200 } 201 b, err := index.db.Get(constructTxIDKey(txID)) 202 if err != nil { 203 return nil, err 204 } 205 if b == nil { 206 return nil, blkstorage.ErrNotFoundInIndex 207 } 208 txFLP := &fileLocPointer{} 209 txFLP.unmarshal(b) 210 return txFLP, nil 211 } 212 213 func (index *blockIndex) getBlockLocByTxID(txID string) (*fileLocPointer, error) { 214 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockTxID]; !ok { 215 return nil, blkstorage.ErrAttrNotIndexed 216 } 217 b, err := index.db.Get(constructBlockTxIDKey(txID)) 218 if err != nil { 219 return nil, err 220 } 221 if b == nil { 222 return nil, blkstorage.ErrNotFoundInIndex 223 } 224 txFLP := &fileLocPointer{} 225 txFLP.unmarshal(b) 226 return txFLP, nil 227 } 228 229 func (index *blockIndex) getTXLocByBlockNumTranNum(blockNum uint64, tranNum uint64) (*fileLocPointer, error) { 230 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockNumTranNum]; !ok { 231 return nil, blkstorage.ErrAttrNotIndexed 232 } 233 b, err := index.db.Get(constructBlockNumTranNumKey(blockNum, tranNum)) 234 if err != nil { 235 return nil, err 236 } 237 if b == nil { 238 return nil, blkstorage.ErrNotFoundInIndex 239 } 240 txFLP := &fileLocPointer{} 241 txFLP.unmarshal(b) 242 return txFLP, nil 243 } 244 245 func (index *blockIndex) getTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error) { 246 if _, ok := index.indexItemsMap[blkstorage.IndexableAttrTxValidationCode]; !ok { 247 return peer.TxValidationCode(-1), blkstorage.ErrAttrNotIndexed 248 } 249 250 raw, err := index.db.Get(constructTxValidationCodeIDKey(txID)) 251 252 if err != nil { 253 return peer.TxValidationCode(-1), err 254 } else if raw == nil { 255 return peer.TxValidationCode(-1), blkstorage.ErrAttrNotIndexed 256 } else if len(raw) != 1 { 257 return peer.TxValidationCode(-1), errors.New("Invalid value in indexItems") 258 } 259 260 result := peer.TxValidationCode(int32(raw[0])) 261 262 return result, nil 263 } 264 265 func constructBlockNumKey(blockNum uint64) []byte { 266 blkNumBytes := util.EncodeOrderPreservingVarUint64(blockNum) 267 return append([]byte{blockNumIdxKeyPrefix}, blkNumBytes...) 268 } 269 270 func constructBlockHashKey(blockHash []byte) []byte { 271 return append([]byte{blockHashIdxKeyPrefix}, blockHash...) 272 } 273 274 func constructTxIDKey(txID string) []byte { 275 return append([]byte{txIDIdxKeyPrefix}, []byte(txID)...) 276 } 277 278 func constructBlockTxIDKey(txID string) []byte { 279 return append([]byte{blockTxIDIdxKeyPrefix}, []byte(txID)...) 280 } 281 282 func constructTxValidationCodeIDKey(txID string) []byte { 283 return append([]byte{txValidationResultIdxKeyPrefix}, []byte(txID)...) 284 } 285 286 func constructBlockNumTranNumKey(blockNum uint64, txNum uint64) []byte { 287 blkNumBytes := util.EncodeOrderPreservingVarUint64(blockNum) 288 tranNumBytes := util.EncodeOrderPreservingVarUint64(txNum) 289 key := append(blkNumBytes, tranNumBytes...) 290 return append([]byte{blockNumTranNumIdxKeyPrefix}, key...) 291 } 292 293 func encodeBlockNum(blockNum uint64) []byte { 294 return proto.EncodeVarint(blockNum) 295 } 296 297 func decodeBlockNum(blockNumBytes []byte) uint64 { 298 blockNum, _ := proto.DecodeVarint(blockNumBytes) 299 return blockNum 300 } 301 302 type locPointer struct { 303 offset int 304 bytesLength int 305 } 306 307 func (lp *locPointer) String() string { 308 return fmt.Sprintf("offset=%d, bytesLength=%d", 309 lp.offset, lp.bytesLength) 310 } 311 312 // fileLocPointer 313 type fileLocPointer struct { 314 fileSuffixNum int 315 locPointer 316 } 317 318 func newFileLocationPointer(fileSuffixNum int, beginningOffset int, relativeLP *locPointer) *fileLocPointer { 319 flp := &fileLocPointer{fileSuffixNum: fileSuffixNum} 320 flp.offset = beginningOffset + relativeLP.offset 321 flp.bytesLength = relativeLP.bytesLength 322 return flp 323 } 324 325 func (flp *fileLocPointer) marshal() ([]byte, error) { 326 buffer := proto.NewBuffer([]byte{}) 327 e := buffer.EncodeVarint(uint64(flp.fileSuffixNum)) 328 if e != nil { 329 return nil, e 330 } 331 e = buffer.EncodeVarint(uint64(flp.offset)) 332 if e != nil { 333 return nil, e 334 } 335 e = buffer.EncodeVarint(uint64(flp.bytesLength)) 336 if e != nil { 337 return nil, e 338 } 339 return buffer.Bytes(), nil 340 } 341 342 func (flp *fileLocPointer) unmarshal(b []byte) error { 343 buffer := proto.NewBuffer(b) 344 i, e := buffer.DecodeVarint() 345 if e != nil { 346 return e 347 } 348 flp.fileSuffixNum = int(i) 349 350 i, e = buffer.DecodeVarint() 351 if e != nil { 352 return e 353 } 354 flp.offset = int(i) 355 i, e = buffer.DecodeVarint() 356 if e != nil { 357 return e 358 } 359 flp.bytesLength = int(i) 360 return nil 361 } 362 363 func (flp *fileLocPointer) String() string { 364 return fmt.Sprintf("fileSuffixNum=%d, %s", flp.fileSuffixNum, flp.locPointer.String()) 365 } 366 367 func (blockIdxInfo *blockIdxInfo) String() string { 368 369 var buffer bytes.Buffer 370 for _, txOffset := range blockIdxInfo.txOffsets { 371 buffer.WriteString("txId=") 372 buffer.WriteString(txOffset.txID) 373 buffer.WriteString(" locPointer=") 374 buffer.WriteString(txOffset.loc.String()) 375 buffer.WriteString("\n") 376 } 377 txOffsetsString := buffer.String() 378 379 return fmt.Sprintf("blockNum=%d, blockHash=%#v txOffsets=\n%s", blockIdxInfo.blockNum, blockIdxInfo.blockHash, txOffsetsString) 380 }