Skip to content

Commit 836fdc6

Browse files
committed
This commit changes the versioning scheme for the keys
https://jira.hyperledger.org/browse/FAB-601 The height based versioning scheme assigns a version to the key equal to the height of the transaction that committed it last. The benefits include - 1) We do not need to maintain delete markers for the deleted keys 2) Makes recovery of state db easier, particularly for couchdb 3) Enables efficient validation - (in future - does not require validating against latest state has potential for in-memory validation) 4) Has potential for providing snapshot isolation across sharded data nodes in the future Change-Id: I5a079c9be5966c349b7bb6c8df6e1a45d9889f1f Signed-off-by: manish <[email protected]>
1 parent 718924c commit 836fdc6

File tree

8 files changed

+217
-95
lines changed

8 files changed

+217
-95
lines changed

core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb_txmgr.go

+14-25
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/hyperledger/fabric/core/ledger/util/db"
2727
"github.com/op/go-logging"
2828

29+
"github.com/hyperledger/fabric/core/ledger/kvledger/version"
2930
"github.com/hyperledger/fabric/protos/common"
3031
pb "github.com/hyperledger/fabric/protos/peer"
3132
putils "github.com/hyperledger/fabric/protos/utils"
@@ -40,7 +41,7 @@ type Conf struct {
4041

4142
type versionedValue struct {
4243
value []byte
43-
version uint64
44+
version *version.Height
4445
}
4546

4647
type updateSet struct {
@@ -126,7 +127,7 @@ func (txmgr *CouchDBTxMgr) ValidateAndPrepare(block *common.Block) (*common.Bloc
126127
var valid bool
127128
txmgr.updateSet = newUpdateSet()
128129
logger.Debugf("Validating a block with [%d] transactions", len(block.Data.Data))
129-
for _, envBytes := range block.Data.Data {
130+
for txIndex, envBytes := range block.Data.Data {
130131
// extract actions from the envelope message
131132
respPayload, err := putils.GetActionFromEnvelope(envBytes)
132133
if err != nil {
@@ -157,7 +158,7 @@ func (txmgr *CouchDBTxMgr) ValidateAndPrepare(block *common.Block) (*common.Bloc
157158
}
158159

159160
if valid {
160-
if err := txmgr.addWriteSetToBatch(txRWSet); err != nil {
161+
if err := txmgr.addWriteSetToBatch(txRWSet, version.NewHeight(block.Header.Number, uint64(txIndex+1))); err != nil {
161162
return nil, nil, err
162163
}
163164
} else {
@@ -177,7 +178,7 @@ func (txmgr *CouchDBTxMgr) Shutdown() {
177178
func (txmgr *CouchDBTxMgr) validateTx(txRWSet *txmgmt.TxReadWriteSet) (bool, error) {
178179

179180
var err error
180-
var currentVersion uint64
181+
var currentVersion *version.Height
181182

182183
for _, nsRWSet := range txRWSet.NsRWs {
183184
ns := nsRWSet.NameSpace
@@ -189,7 +190,7 @@ func (txmgr *CouchDBTxMgr) validateTx(txRWSet *txmgmt.TxReadWriteSet) (bool, err
189190
if currentVersion, err = txmgr.getCommitedVersion(ns, kvRead.Key); err != nil {
190191
return false, err
191192
}
192-
if currentVersion != kvRead.Version {
193+
if !version.AreSame(currentVersion, kvRead.Version) {
193194
logger.Debugf("Version mismatch for key [%s:%s]. Current version = [%d], Version in readSet [%d]",
194195
ns, kvRead.Key, currentVersion, kvRead.Version)
195196
return false, nil
@@ -199,27 +200,15 @@ func (txmgr *CouchDBTxMgr) validateTx(txRWSet *txmgmt.TxReadWriteSet) (bool, err
199200
return true, nil
200201
}
201202

202-
func (txmgr *CouchDBTxMgr) addWriteSetToBatch(txRWSet *txmgmt.TxReadWriteSet) error {
203-
var err error
204-
var currentVersion uint64
205-
203+
func (txmgr *CouchDBTxMgr) addWriteSetToBatch(txRWSet *txmgmt.TxReadWriteSet, txHeight *version.Height) error {
206204
if txmgr.updateSet == nil {
207205
txmgr.updateSet = newUpdateSet()
208206
}
209207
for _, nsRWSet := range txRWSet.NsRWs {
210208
ns := nsRWSet.NameSpace
211209
for _, kvWrite := range nsRWSet.Writes {
212210
compositeKey := constructCompositeKey(ns, kvWrite.Key)
213-
versionedVal := txmgr.updateSet.get(compositeKey)
214-
if versionedVal != nil {
215-
currentVersion = versionedVal.version
216-
} else {
217-
currentVersion, err = txmgr.getCommitedVersion(ns, kvWrite.Key)
218-
if err != nil {
219-
return err
220-
}
221-
}
222-
txmgr.updateSet.add(compositeKey, &versionedValue{kvWrite.Value, currentVersion + 1})
211+
txmgr.updateSet.add(compositeKey, &versionedValue{kvWrite.Value, txHeight})
223212
}
224213
}
225214
return nil
@@ -285,16 +274,16 @@ func (txmgr *CouchDBTxMgr) Rollback() {
285274
txmgr.updateSet = nil
286275
}
287276

288-
func (txmgr *CouchDBTxMgr) getCommitedVersion(ns string, key string) (uint64, error) {
277+
func (txmgr *CouchDBTxMgr) getCommitedVersion(ns string, key string) (*version.Height, error) {
289278
var err error
290-
var version uint64
279+
var version *version.Height
291280
if _, version, err = txmgr.getCommittedValueAndVersion(ns, key); err != nil {
292-
return 0, err
281+
return nil, err
293282
}
294283
return version, nil
295284
}
296285

297-
func (txmgr *CouchDBTxMgr) getCommittedValueAndVersion(ns string, key string) ([]byte, uint64, error) {
286+
func (txmgr *CouchDBTxMgr) getCommittedValueAndVersion(ns string, key string) ([]byte, *version.Height, error) {
298287

299288
compositeKey := constructCompositeKey(ns, key)
300289

@@ -309,8 +298,8 @@ func (txmgr *CouchDBTxMgr) getCommittedValueAndVersion(ns string, key string) ([
309298
}
310299
}
311300

312-
var version uint64 = 1 //TODO - version hardcoded to 1 is a temporary value for the prototype
313-
return docBytes, version, nil
301+
ver := version.NewHeight(1, 1) //TODO - version hardcoded to 1 is a temporary value for the prototype
302+
return docBytes, ver, nil
314303
}
315304

316305
func encodeValue(value []byte, version uint64) []byte {

core/ledger/kvledger/txmgmt/lockbasedtxmgmt/lockbased_txmgmt_test.go

+16-17
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"testing"
2222

2323
"github.com/hyperledger/fabric/core/ledger"
24+
"github.com/hyperledger/fabric/core/ledger/kvledger/version"
2425
"github.com/hyperledger/fabric/core/ledger/testutil"
2526
)
2627

@@ -65,7 +66,7 @@ func TestTxSimulatorWithExistingData(t *testing.T) {
6566
isValid, err := txMgr.validateTx(txRWSet)
6667
testutil.AssertNoError(t, err, fmt.Sprintf("Error in validateTx(): %s", err))
6768
testutil.AssertSame(t, isValid, true)
68-
txMgr.addWriteSetToBatch(txRWSet)
69+
txMgr.addWriteSetToBatch(txRWSet, version.NewHeight(1, 1))
6970
err = txMgr.Commit()
7071
testutil.AssertNoError(t, err, fmt.Sprintf("Error while calling commit(): %s", err))
7172

@@ -82,7 +83,7 @@ func TestTxSimulatorWithExistingData(t *testing.T) {
8283
txRWSet = s2.(*LockBasedTxSimulator).getTxReadWriteSet()
8384
isValid, err = txMgr.validateTx(txRWSet)
8485
testutil.AssertSame(t, isValid, true)
85-
txMgr.addWriteSetToBatch(txRWSet)
86+
txMgr.addWriteSetToBatch(txRWSet, version.NewHeight(2, 1))
8687
txMgr.Commit()
8788

8889
// simulate tx3
@@ -95,11 +96,9 @@ func TestTxSimulatorWithExistingData(t *testing.T) {
9596

9697
// verify the versions of keys in persistence
9798
ver, _ := txMgr.getCommitedVersion("ns1", "key1")
98-
testutil.AssertEquals(t, ver, uint64(2))
99+
testutil.AssertEquals(t, ver, version.NewHeight(2, 1))
99100
ver, _ = txMgr.getCommitedVersion("ns1", "key2")
100-
testutil.AssertEquals(t, ver, uint64(1))
101-
ver, _ = txMgr.getCommitedVersion("ns2", "key3")
102-
testutil.AssertEquals(t, ver, uint64(2))
101+
testutil.AssertEquals(t, ver, version.NewHeight(1, 1))
103102
}
104103

105104
func TestTxValidation(t *testing.T) {
@@ -120,7 +119,7 @@ func TestTxValidation(t *testing.T) {
120119
isValid, err := txMgr.validateTx(txRWSet)
121120
testutil.AssertNoError(t, err, fmt.Sprintf("Error in validateTx(): %s", err))
122121
testutil.AssertSame(t, isValid, true)
123-
txMgr.addWriteSetToBatch(txRWSet)
122+
txMgr.addWriteSetToBatch(txRWSet, version.NewHeight(1, 1))
124123
err = txMgr.Commit()
125124
testutil.AssertNoError(t, err, fmt.Sprintf("Error while calling commit(): %s", err))
126125

@@ -161,7 +160,7 @@ func TestTxValidation(t *testing.T) {
161160
isValid, err = txMgr.validateTx(txRWSet)
162161
testutil.AssertNoError(t, err, fmt.Sprintf("Error in validateTx(): %s", err))
163162
testutil.AssertSame(t, isValid, true)
164-
txMgr.addWriteSetToBatch(txRWSet)
163+
txMgr.addWriteSetToBatch(txRWSet, version.NewHeight(2, 1))
165164
txMgr.Commit()
166165

167166
//RWSet for tx3 and tx4 should not be invalid now
@@ -183,11 +182,11 @@ func TestTxValidation(t *testing.T) {
183182
}
184183

185184
func TestEncodeDecodeValueAndVersion(t *testing.T) {
186-
testValueAndVersionEncodeing(t, []byte("value1"), uint64(1))
187-
testValueAndVersionEncodeing(t, nil, uint64(2))
185+
testValueAndVersionEncodeing(t, []byte("value1"), version.NewHeight(1, 2))
186+
testValueAndVersionEncodeing(t, []byte{}, version.NewHeight(50, 50))
188187
}
189188

190-
func testValueAndVersionEncodeing(t *testing.T, value []byte, version uint64) {
189+
func testValueAndVersionEncodeing(t *testing.T, value []byte, version *version.Height) {
191190
encodedValue := encodeValue(value, version)
192191
val, ver := decodeValue(encodedValue)
193192
testutil.AssertEquals(t, val, value)
@@ -221,7 +220,7 @@ func testIterator(t *testing.T, numKeys int, startKeyNum int, endKeyNum int) {
221220
isValid, err := txMgr.validateTx(txRWSet)
222221
testutil.AssertNoError(t, err, "")
223222
testutil.AssertSame(t, isValid, true)
224-
txMgr.addWriteSetToBatch(txRWSet)
223+
txMgr.addWriteSetToBatch(txRWSet, version.NewHeight(1, 1))
225224
err = txMgr.Commit()
226225
testutil.AssertNoError(t, err, "")
227226

@@ -286,7 +285,7 @@ func TestIteratorWithDeletes(t *testing.T) {
286285
isValid, err := txMgr.validateTx(txRWSet)
287286
testutil.AssertNoError(t, err, "")
288287
testutil.AssertSame(t, isValid, true)
289-
txMgr.addWriteSetToBatch(txRWSet)
288+
txMgr.addWriteSetToBatch(txRWSet, version.NewHeight(1, 1))
290289
err = txMgr.Commit()
291290
testutil.AssertNoError(t, err, "")
292291

@@ -298,7 +297,7 @@ func TestIteratorWithDeletes(t *testing.T) {
298297
isValid, err = txMgr.validateTx(txRWSet)
299298
testutil.AssertNoError(t, err, "")
300299
testutil.AssertSame(t, isValid, true)
301-
txMgr.addWriteSetToBatch(txRWSet)
300+
txMgr.addWriteSetToBatch(txRWSet, version.NewHeight(2, 1))
302301
err = txMgr.Commit()
303302
testutil.AssertNoError(t, err, "")
304303

@@ -332,7 +331,7 @@ func TestTxValidationWithItr(t *testing.T) {
332331
isValid, err := txMgr.validateTx(txRWSet)
333332
testutil.AssertNoError(t, err, "")
334333
testutil.AssertSame(t, isValid, true)
335-
txMgr.addWriteSetToBatch(txRWSet)
334+
txMgr.addWriteSetToBatch(txRWSet, version.NewHeight(1, 1))
336335
err = txMgr.Commit()
337336
testutil.AssertNoError(t, err, "")
338337

@@ -364,7 +363,7 @@ func TestTxValidationWithItr(t *testing.T) {
364363
isValid, err = txMgr.validateTx(txRWSet)
365364
testutil.AssertNoError(t, err, fmt.Sprintf("Error in validateTx(): %s", err))
366365
testutil.AssertSame(t, isValid, true)
367-
txMgr.addWriteSetToBatch(txRWSet)
366+
txMgr.addWriteSetToBatch(txRWSet, version.NewHeight(2, 1))
368367
txMgr.Commit()
369368

370369
//RWSet tx3 should not be invalid now
@@ -399,7 +398,7 @@ func TestGetSetMultipeKeys(t *testing.T) {
399398
isValid, err := txMgr.validateTx(txRWSet)
400399
testutil.AssertNoError(t, err, "")
401400
testutil.AssertSame(t, isValid, true)
402-
txMgr.addWriteSetToBatch(txRWSet)
401+
txMgr.addWriteSetToBatch(txRWSet, version.NewHeight(1, 1))
403402
err = txMgr.Commit()
404403
testutil.AssertNoError(t, err, "")
405404

0 commit comments

Comments
 (0)