github.com/kaituanwang/hyperledger@v2.0.1+incompatible/core/ledger/kvledger/history/kv_encoding.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  SPDX-License-Identifier: Apache-2.0
     4  */
     5  
     6  package history
     7  
     8  import (
     9  	"bytes"
    10  
    11  	"github.com/hyperledger/fabric/common/ledger/util"
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  type dataKey []byte
    16  type rangeScan struct {
    17  	startKey, endKey []byte
    18  }
    19  
    20  var (
    21  	compositeKeySep = []byte{0x00} // used as a separator between different components of dataKey
    22  	dataKeyPrefix   = []byte{'d'}  // prefix added to dataKeys
    23  	savePointKey    = []byte{'s'}  // a single key in db for persisting savepoint
    24  	emptyValue      = []byte{}     // used to store as value for keys where only key needs to be stored (e.g., dataKeys)
    25  )
    26  
    27  // constructDataKey builds the key of the format namespace~len(key)~key~blocknum~trannum
    28  // using an order preserving encoding so that history query results are ordered by height
    29  // Note: this key format is different than the format in pre-v2.0 releases and requires
    30  //       a historydb rebuild when upgrading an older version to v2.0.
    31  func constructDataKey(ns string, key string, blocknum uint64, trannum uint64) dataKey {
    32  	k := append([]byte(ns), compositeKeySep...)
    33  	k = append(k, util.EncodeOrderPreservingVarUint64(uint64(len(key)))...)
    34  	k = append(k, []byte(key)...)
    35  	k = append(k, compositeKeySep...)
    36  	k = append(k, util.EncodeOrderPreservingVarUint64(blocknum)...)
    37  	k = append(k, util.EncodeOrderPreservingVarUint64(trannum)...)
    38  	return dataKey(k)
    39  }
    40  
    41  // constructRangescanKeys returns start and endKey for performing a range scan
    42  // that covers all the keys for <ns, key>.
    43  // startKey = namespace~len(key)~key~
    44  // endKey = namespace~len(key)~key~0xff
    45  func constructRangeScan(ns string, key string) *rangeScan {
    46  	k := append([]byte(ns), compositeKeySep...)
    47  	k = append(k, util.EncodeOrderPreservingVarUint64(uint64(len(key)))...)
    48  	k = append(k, []byte(key)...)
    49  	k = append(k, compositeKeySep...)
    50  
    51  	return &rangeScan{
    52  		startKey: k,
    53  		endKey:   append(k, 0xff),
    54  	}
    55  }
    56  
    57  func (r *rangeScan) decodeBlockNumTranNum(dataKey dataKey) (uint64, uint64, error) {
    58  	blockNumTranNumBytes := bytes.TrimPrefix(dataKey, r.startKey)
    59  	blockNum, blockBytesConsumed, err := util.DecodeOrderPreservingVarUint64(blockNumTranNumBytes)
    60  	if err != nil {
    61  		return 0, 0, err
    62  	}
    63  
    64  	tranNum, tranBytesConsumed, err := util.DecodeOrderPreservingVarUint64(blockNumTranNumBytes[blockBytesConsumed:])
    65  	if err != nil {
    66  		return 0, 0, err
    67  	}
    68  
    69  	// The following error should never happen. Keep the check just in case there is some unknown bug.
    70  	if blockBytesConsumed+tranBytesConsumed != len(blockNumTranNumBytes) {
    71  		return 0, 0, errors.Errorf("number of decoded bytes (%d) is not equal to the length of blockNumTranNumBytes (%d)",
    72  			blockBytesConsumed+tranBytesConsumed, len(blockNumTranNumBytes))
    73  	}
    74  	return blockNum, tranNum, nil
    75  }