Skip to content

Commit

Permalink
deprioritize unreconcilable missingPvtData
Browse files Browse the repository at this point in the history
Signed-off-by: senthil <cendhu@gmail.com>
  • Loading branch information
cendhu committed Aug 24, 2020
1 parent 4fae6ed commit 9d2d7e3
Show file tree
Hide file tree
Showing 9 changed files with 1,012 additions and 393 deletions.
2 changes: 1 addition & 1 deletion core/ledger/kvledger/kv_ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,7 @@ func (l *kvLedger) CommitPvtDataOfOldBlocks(reconciledPvtdata []*ledger.Reconcil

logger.Debugf("[%s:] Committing pvtData of [%d] old blocks to the pvtdatastore", l.ledgerID, len(reconciledPvtdata))

err = l.pvtdataStore.CommitPvtDataOfOldBlocks(hashVerifiedPvtData)
err = l.pvtdataStore.CommitPvtDataOfOldBlocks(hashVerifiedPvtData, nil)
if err != nil {
return nil, err
}
Expand Down
31 changes: 22 additions & 9 deletions core/ledger/pvtdatastorage/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,25 +139,38 @@ func getOrCreateExpiryData(mapByExpiringBlk map[uint64]*ExpiryData, expiringBlk
}

// deriveKeys constructs dataKeys and missingDataKey from an expiryEntry
func deriveKeys(expiryEntry *expiryEntry) (dataKeys []*dataKey, missingDataKeys []*missingDataKey) {
func deriveKeys(expiryEntry *expiryEntry) ([]*dataKey, []*missingDataKey) {
var dataKeys []*dataKey
var missingDataKeys []*missingDataKey

for ns, colls := range expiryEntry.value.Map {
// 1. constructs dataKeys of expired existing pvt data
for coll, txNums := range colls.Map {
for _, txNum := range txNums.List {
dataKeys = append(dataKeys,
&dataKey{nsCollBlk{ns, coll, expiryEntry.key.committingBlk}, txNum})
&dataKey{
nsCollBlk: nsCollBlk{
ns: ns,
coll: coll,
blkNum: expiryEntry.key.committingBlk,
},
txNum: txNum,
})
}
}
// 2. constructs missingDataKeys of expired missing pvt data

for coll := range colls.MissingDataMap {
// one key for eligible entries and another for ieligible entries
missingDataKeys = append(missingDataKeys,
&missingDataKey{nsCollBlk{ns, coll, expiryEntry.key.committingBlk}, true})
missingDataKeys = append(missingDataKeys,
&missingDataKey{nsCollBlk{ns, coll, expiryEntry.key.committingBlk}, false})
&missingDataKey{
nsCollBlk: nsCollBlk{
ns: ns,
coll: coll,
blkNum: expiryEntry.key.committingBlk,
},
})
}
}
return

return dataKeys, missingDataKeys
}

func passesFilter(dataKey *dataKey, filter ledger.PvtNsCollFilter) bool {
Expand Down
128 changes: 64 additions & 64 deletions core/ledger/pvtdatastorage/kv_encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,30 @@ import (
)

var (
pendingCommitKey = []byte{0}
lastCommittedBlkkey = []byte{1}
pvtDataKeyPrefix = []byte{2}
expiryKeyPrefix = []byte{3}
eligibleMissingDataKeyPrefix = []byte{4}
ineligibleMissingDataKeyPrefix = []byte{5}
collElgKeyPrefix = []byte{6}
lastUpdatedOldBlocksKey = []byte{7}
pendingCommitKey = []byte{0}
lastCommittedBlkkey = []byte{1}
pvtDataKeyPrefix = []byte{2}
expiryKeyPrefix = []byte{3}
elgPrioritizedMissingDataGroup = []byte{4}
inelgMissingDataGroup = []byte{5}
collElgKeyPrefix = []byte{6}
lastUpdatedOldBlocksKey = []byte{7}
elgDeprioritizedMissingDataGroup = []byte{8}

nilByte = byte(0)
emptyValue = []byte{}
)

func getDataKeysForRangeScanByBlockNum(blockNum uint64) (startKey, endKey []byte) {
startKey = append(pvtDataKeyPrefix, version.NewHeight(blockNum, 0).ToBytes()...)
endKey = append(pvtDataKeyPrefix, version.NewHeight(blockNum+1, 0).ToBytes()...)
return
func getDataKeysForRangeScanByBlockNum(blockNum uint64) ([]byte, []byte) {
startKey := append(pvtDataKeyPrefix, version.NewHeight(blockNum, 0).ToBytes()...)
endKey := append(pvtDataKeyPrefix, version.NewHeight(blockNum+1, 0).ToBytes()...)
return startKey, endKey
}

func getExpiryKeysForRangeScan(minBlkNum, maxBlkNum uint64) (startKey, endKey []byte) {
startKey = append(expiryKeyPrefix, version.NewHeight(minBlkNum, 0).ToBytes()...)
endKey = append(expiryKeyPrefix, version.NewHeight(maxBlkNum+1, 0).ToBytes()...)
return
func getExpiryKeysForRangeScan(minBlkNum, maxBlkNum uint64) ([]byte, []byte) {
startKey := append(expiryKeyPrefix, version.NewHeight(minBlkNum, 0).ToBytes()...)
endKey := append(expiryKeyPrefix, version.NewHeight(maxBlkNum+1, 0).ToBytes()...)
return startKey, endKey
}

func encodeLastCommittedBlockVal(blockNum uint64) []byte {
Expand Down Expand Up @@ -107,47 +108,45 @@ func decodeDataValue(datavalueBytes []byte) (*rwset.CollectionPvtReadWriteSet, e
return collPvtdata, err
}

func encodeMissingDataKey(key *missingDataKey) []byte {
if key.isEligible {
// When missing pvtData reconciler asks for missing data info,
// it is necessary to pass the missing pvtdata info associated with
// the most recent block so that missing pvtdata in the state db can
// be fixed sooner to reduce the "private data matching public hash version
// is not available" error during endorserments. In order to give priority
// to missing pvtData in the most recent block, we use reverse order
// preserving encoding for the missing data key. This simplifies the
// implementation of GetMissingPvtDataInfoForMostRecentBlocks().
keyBytes := append(eligibleMissingDataKeyPrefix, encodeReverseOrderVarUint64(key.blkNum)...)
keyBytes = append(keyBytes, []byte(key.ns)...)
keyBytes = append(keyBytes, nilByte)
return append(keyBytes, []byte(key.coll)...)
}

keyBytes := append(ineligibleMissingDataKeyPrefix, []byte(key.ns)...)
keyBytes = append(keyBytes, nilByte)
keyBytes = append(keyBytes, []byte(key.coll)...)
keyBytes = append(keyBytes, nilByte)
return append(keyBytes, []byte(encodeReverseOrderVarUint64(key.blkNum))...)
func encodeElgMissingDataKey(group []byte, key *missingDataKey) []byte {
// When missing pvtData reconciler asks for missing data info,
// it is necessary to pass the missing pvtdata info associated with
// the most recent block so that missing pvtdata in the state db can
// be fixed sooner to reduce the "private data matching public hash version
// is not available" error during endorserments. In order to give priority
// to missing pvtData in the most recent block, we use reverse order
// preserving encoding for the missing data key. This simplifies the
// implementation of GetMissingPvtDataInfoForMostRecentBlocks().
encKey := append(group, encodeReverseOrderVarUint64(key.blkNum)...)
encKey = append(encKey, []byte(key.ns)...)
encKey = append(encKey, nilByte)
return append(encKey, []byte(key.coll)...)
}

func decodeMissingDataKey(keyBytes []byte) *missingDataKey {
func decodeElgMissingDataKey(keyBytes []byte) *missingDataKey {
key := &missingDataKey{nsCollBlk: nsCollBlk{}}
if keyBytes[0] == eligibleMissingDataKeyPrefix[0] {
blkNum, numBytesConsumed := decodeReverseOrderVarUint64(keyBytes[1:])

splittedKey := bytes.Split(keyBytes[numBytesConsumed+1:], []byte{nilByte})
key.ns = string(splittedKey[0])
key.coll = string(splittedKey[1])
key.blkNum = blkNum
key.isEligible = true
return key
}
blkNum, numBytesConsumed := decodeReverseOrderVarUint64(keyBytes[1:])
splittedKey := bytes.Split(keyBytes[numBytesConsumed+1:], []byte{nilByte})
key.ns = string(splittedKey[0])
key.coll = string(splittedKey[1])
key.blkNum = blkNum
return key
}

func encodeInelgMissingDataKey(key *missingDataKey) []byte {
encKey := append(inelgMissingDataGroup, []byte(key.ns)...)
encKey = append(encKey, nilByte)
encKey = append(encKey, []byte(key.coll)...)
encKey = append(encKey, nilByte)
return append(encKey, []byte(encodeReverseOrderVarUint64(key.blkNum))...)
}

func decodeInelgMissingDataKey(keyBytes []byte) *missingDataKey {
key := &missingDataKey{nsCollBlk: nsCollBlk{}}
splittedKey := bytes.SplitN(keyBytes[1:], []byte{nilByte}, 3) //encoded bytes for blknum may contain empty bytes
key.ns = string(splittedKey[0])
key.coll = string(splittedKey[1])
key.blkNum, _ = decodeReverseOrderVarUint64(splittedKey[2])
key.isEligible = false
return key
}

Expand Down Expand Up @@ -184,44 +183,45 @@ func decodeCollElgVal(b []byte) (*CollElgInfo, error) {
return m, nil
}

func createRangeScanKeysForEligibleMissingDataEntries(blkNum uint64) (startKey, endKey []byte) {
startKey = append(eligibleMissingDataKeyPrefix, encodeReverseOrderVarUint64(blkNum)...)
endKey = append(eligibleMissingDataKeyPrefix, encodeReverseOrderVarUint64(0)...)
func createRangeScanKeysForElgMissingData(blkNum uint64, group []byte) ([]byte, []byte) {
startKey := append(group, encodeReverseOrderVarUint64(blkNum)...)
endKey := append(group, encodeReverseOrderVarUint64(0)...)

return startKey, endKey
}

func createRangeScanKeysForIneligibleMissingData(maxBlkNum uint64, ns, coll string) (startKey, endKey []byte) {
startKey = encodeMissingDataKey(
func createRangeScanKeysForInelgMissingData(maxBlkNum uint64, ns, coll string) ([]byte, []byte) {
startKey := encodeInelgMissingDataKey(
&missingDataKey{
nsCollBlk: nsCollBlk{ns: ns, coll: coll, blkNum: maxBlkNum},
isEligible: false,
},
)
endKey = encodeMissingDataKey(
endKey := encodeInelgMissingDataKey(
&missingDataKey{
nsCollBlk: nsCollBlk{ns: ns, coll: coll, blkNum: 0},
isEligible: false,
},
)
return

return startKey, endKey
}

func createRangeScanKeysForCollElg() (startKey, endKey []byte) {
return encodeCollElgKey(math.MaxUint64),
encodeCollElgKey(0)
}

func datakeyRange(blockNum uint64) (startKey, endKey []byte) {
startKey = append(pvtDataKeyPrefix, version.NewHeight(blockNum, 0).ToBytes()...)
endKey = append(pvtDataKeyPrefix, version.NewHeight(blockNum, math.MaxUint64).ToBytes()...)
return
func datakeyRange(blockNum uint64) ([]byte, []byte) {
startKey := append(pvtDataKeyPrefix, version.NewHeight(blockNum, 0).ToBytes()...)
endKey := append(pvtDataKeyPrefix, version.NewHeight(blockNum, math.MaxUint64).ToBytes()...)
return startKey, endKey
}

func eligibleMissingdatakeyRange(blkNum uint64) (startKey, endKey []byte) {
startKey = append(eligibleMissingDataKeyPrefix, encodeReverseOrderVarUint64(blkNum)...)
endKey = append(eligibleMissingDataKeyPrefix, encodeReverseOrderVarUint64(blkNum-1)...)
return
func eligibleMissingdatakeyRange(blkNum uint64) ([]byte, []byte) {
startKey := append(elgPrioritizedMissingDataGroup, encodeReverseOrderVarUint64(blkNum)...)
endKey := append(elgPrioritizedMissingDataGroup, encodeReverseOrderVarUint64(blkNum-1)...)
return startKey, endKey
}

// encodeReverseOrderVarUint64 returns a byte-representation for a uint64 number such that
Expand Down
55 changes: 37 additions & 18 deletions core/ledger/pvtdatastorage/kv_encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func TestDataKeyEncoding(t *testing.T) {
require.Equal(t, dataKey1, datakey2)
}

func TestDatakeyRange(t *testing.T) {
func TestDataKeyRange(t *testing.T) {
blockNum := uint64(20)
startKey, endKey := datakeyRange(blockNum)
var txNum uint64
Expand Down Expand Up @@ -51,27 +51,39 @@ func TestDatakeyRange(t *testing.T) {
}
}

func TestEligibleMissingdataRange(t *testing.T) {
func TestEligibleMissingDataRange(t *testing.T) {
blockNum := uint64(20)
startKey, endKey := eligibleMissingdatakeyRange(blockNum)
var txNum uint64
for txNum = 0; txNum < 100; txNum++ {
keyOfBlock := encodeMissingDataKey(
keyOfBlock := encodeElgMissingDataKey(
elgPrioritizedMissingDataGroup,
&missingDataKey{
nsCollBlk: nsCollBlk{ns: "ns", coll: "coll", blkNum: blockNum},
isEligible: true,
nsCollBlk: nsCollBlk{
ns: "ns",
coll: "coll",
blkNum: blockNum,
},
},
)
keyOfPreviousBlock := encodeMissingDataKey(
keyOfPreviousBlock := encodeElgMissingDataKey(
elgPrioritizedMissingDataGroup,
&missingDataKey{
nsCollBlk: nsCollBlk{ns: "ns", coll: "coll", blkNum: blockNum - 1},
isEligible: true,
nsCollBlk: nsCollBlk{
ns: "ns",
coll: "coll",
blkNum: blockNum - 1,
},
},
)
keyOfNextBlock := encodeMissingDataKey(
keyOfNextBlock := encodeElgMissingDataKey(
elgPrioritizedMissingDataGroup,
&missingDataKey{
nsCollBlk: nsCollBlk{ns: "ns", coll: "coll", blkNum: blockNum + 1},
isEligible: true,
nsCollBlk: nsCollBlk{
ns: "ns",
coll: "coll",
blkNum: blockNum + 1,
},
},
)
require.Equal(t, bytes.Compare(keyOfNextBlock, startKey), -1)
Expand Down Expand Up @@ -99,19 +111,26 @@ func testEncodeDecodeMissingdataKey(t *testing.T, blkNum uint64) {

t.Run("ineligibileKey",
func(t *testing.T) {
key.isEligible = false
decodedKey := decodeMissingDataKey(
encodeMissingDataKey(key),
decodedKey := decodeInelgMissingDataKey(
encodeInelgMissingDataKey(key),
)
require.Equal(t, key, decodedKey)
},
)

t.Run("ineligibileKey",
t.Run("eligiblePrioritizedKey",
func(t *testing.T) {
decodedKey := decodeElgMissingDataKey(
encodeElgMissingDataKey(elgPrioritizedMissingDataGroup, key),
)
require.Equal(t, key, decodedKey)
},
)

t.Run("eligibleDeprioritizedKey",
func(t *testing.T) {
key.isEligible = true
decodedKey := decodeMissingDataKey(
encodeMissingDataKey(key),
decodedKey := decodeElgMissingDataKey(
encodeElgMissingDataKey(elgDeprioritizedMissingDataGroup, key),
)
require.Equal(t, key, decodedKey)
},
Expand Down
Loading

0 comments on commit 9d2d7e3

Please sign in to comment.