Skip to content

Commit c76b931

Browse files
manish-sethiwenjianqiao
authored andcommitted
[FAB-16302] Update historydb key format
The historydb code assumes that the keys do not contain a nil byte. In the presence of such keys, a historydb query may include wrong results due to key collision. This CR fixes this issue. However, it makes a slight change in the format of the keys that are persisted and hence will require dropping and rebuilding of existing historydb. Change-Id: I8b451fff10e15e22948b01f18fddb16911866d76 Signed-off-by: manish <manish.sethi@gmail.com> Signed-off-by: Wenjian Qiao <wenjianq@gmail.com>
1 parent d89ebb1 commit c76b931

File tree

6 files changed

+108
-420
lines changed

6 files changed

+108
-420
lines changed

core/ledger/kvledger/history/historydb/histmgr_helper.go

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,7 @@
11
/*
2-
Copyright IBM Corp. 2016 All Rights Reserved.
2+
Copyright IBM Corp. All Rights Reserved.
33
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.
4+
SPDX-License-Identifier: Apache-2.0
155
*/
166

177
package historydb
@@ -25,13 +15,15 @@ import (
2515
// CompositeKeySep is a nil byte used as a separator between different components of a composite key
2616
var CompositeKeySep = []byte{0x00}
2717

28-
//ConstructCompositeHistoryKey builds the History Key of namespace~key~blocknum~trannum
18+
// ConstructCompositeHistoryKey builds the History Key of namespace~len(key)~key~blocknum~trannum
2919
// using an order preserving encoding so that history query results are ordered by height
20+
// Note: this key format is different than the format in pre-v2.0 releases and requires
21+
// a historydb rebuild when upgrading an older version to v2.0.
3022
func ConstructCompositeHistoryKey(ns string, key string, blocknum uint64, trannum uint64) []byte {
31-
3223
var compositeKey []byte
3324
compositeKey = append(compositeKey, []byte(ns)...)
3425
compositeKey = append(compositeKey, CompositeKeySep...)
26+
compositeKey = append(compositeKey, util.EncodeOrderPreservingVarUint64(uint64(len(key)))...)
3527
compositeKey = append(compositeKey, []byte(key)...)
3628
compositeKey = append(compositeKey, CompositeKeySep...)
3729
compositeKey = append(compositeKey, util.EncodeOrderPreservingVarUint64(blocknum)...)
@@ -40,12 +32,13 @@ func ConstructCompositeHistoryKey(ns string, key string, blocknum uint64, trannu
4032
return compositeKey
4133
}
4234

43-
//ConstructPartialCompositeHistoryKey builds a partial History Key namespace~key~
35+
// ConstructPartialCompositeHistoryKey builds a partial History Key namespace~len(key)~key~
4436
// for use in history key range queries
4537
func ConstructPartialCompositeHistoryKey(ns string, key string, endkey bool) []byte {
4638
var compositeKey []byte
4739
compositeKey = append(compositeKey, []byte(ns)...)
4840
compositeKey = append(compositeKey, CompositeKeySep...)
41+
compositeKey = append(compositeKey, util.EncodeOrderPreservingVarUint64(uint64(len(key)))...)
4942
compositeKey = append(compositeKey, []byte(key)...)
5043
compositeKey = append(compositeKey, CompositeKeySep...)
5144
if endkey {
Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,66 @@
11
/*
2-
Copyright IBM Corp. 2016 All Rights Reserved.
2+
Copyright IBM Corp. All Rights Reserved.
33
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.
4+
SPDX-License-Identifier: Apache-2.0
155
*/
166

177
package historydb
188

199
import (
10+
"bytes"
2011
"testing"
2112

13+
"github.com/hyperledger/fabric/common/ledger/util"
2214
"github.com/stretchr/testify/assert"
2315
)
2416

2517
var strKeySep = string(CompositeKeySep)
2618

27-
func TestConstructCompositeKey(t *testing.T) {
28-
compositeKey := ConstructCompositeHistoryKey("ns1", "key1", 1, 1)
29-
assert.NotNil(t, compositeKey)
30-
//historyleveldb_test.go tests the actual output
31-
}
19+
func TestCompositeKeyConstruction(t *testing.T) {
20+
type keyComponents struct {
21+
ns, key string
22+
blkNum, tranNum uint64
23+
}
3224

33-
func TestConstructPartialCompositeKey(t *testing.T) {
34-
compositeStartKey := ConstructPartialCompositeHistoryKey("ns1", "key1", false)
35-
compositeEndKey := ConstructPartialCompositeHistoryKey("ns1", "key1", true)
25+
testData := []*keyComponents{
26+
{"ns1", "key1", 1, 0},
27+
{"ns1", "key1\x00", 1, 5},
28+
{"ns1", "key1\x00\x00", 100, 100},
29+
{"ns1", "key\x00\x001", 100, 100},
30+
{"ns1", "\x00key\x00\x001", 100, 100},
31+
}
3632

37-
assert.Equal(t, []byte("ns1"+strKeySep+"key1"+strKeySep), compositeStartKey)
38-
assert.Equal(t, []byte("ns1"+strKeySep+"key1"+strKeySep+string([]byte{0xff})), compositeEndKey)
33+
for _, testDatum := range testData {
34+
key := ConstructCompositeHistoryKey(testDatum.ns, testDatum.key, testDatum.blkNum, testDatum.tranNum)
35+
startKey := ConstructPartialCompositeHistoryKey(testDatum.ns, testDatum.key, false)
36+
endKey := ConstructPartialCompositeHistoryKey(testDatum.ns, testDatum.key, true)
37+
assert.Equal(t, bytes.Compare(startKey, key), -1) //startKey should be smaller than key
38+
assert.Equal(t, bytes.Compare(endKey, key), 1) //endKey should be greater than key
39+
}
40+
41+
for i, testDatum := range testData {
42+
for j, another := range testData {
43+
if i == j {
44+
continue
45+
}
46+
startKey := ConstructPartialCompositeHistoryKey(testDatum.ns, testDatum.key, false)
47+
endKey := ConstructPartialCompositeHistoryKey(testDatum.ns, testDatum.key, true)
48+
49+
anotherKey := ConstructCompositeHistoryKey(another.ns, another.key, another.blkNum, another.tranNum)
50+
assert.False(t, bytes.Compare(anotherKey, startKey) == 1 && bytes.Compare(anotherKey, endKey) == -1) //any key should not fall in the range of start/end key range query for any other key
51+
}
52+
}
3953
}
4054

4155
func TestSplitCompositeKey(t *testing.T) {
42-
compositeFullKey := []byte("ns1" + strKeySep + "key1" + strKeySep + "extra bytes to split")
56+
compositeFullKey := ConstructCompositeHistoryKey("ns1", "key1", 20, 200)
4357
compositePartialKey := ConstructPartialCompositeHistoryKey("ns1", "key1", false)
44-
4558
_, extraBytes := SplitCompositeHistoryKey(compositeFullKey, compositePartialKey)
59+
blkNum, bytesConsumed, err := util.DecodeOrderPreservingVarUint64(extraBytes)
60+
assert.NoError(t, err)
61+
txNum, _, err := util.DecodeOrderPreservingVarUint64(extraBytes[bytesConsumed:])
62+
assert.NoError(t, err)
4663
// second position should hold the extra bytes that were split off
47-
assert.Equal(t, []byte("extra bytes to split"), extraBytes)
64+
assert.Equal(t, blkNum, uint64(20))
65+
assert.Equal(t, txNum, uint64(200))
4866
}

core/ledger/kvledger/history/historydb/historyleveldb/fakes/historydb_logger.go

Lines changed: 0 additions & 193 deletions
This file was deleted.

core/ledger/kvledger/history/historydb/historyleveldb/fakes/historyleveldb_logger.go

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)