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 }