github.com/true-sqn/fabric@v2.1.1+incompatible/core/ledger/kvledger/history/kv_encoding.go (about)

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