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  }