Skip to content

Commit

Permalink
[FAB-2498] Fix Panic upon Recover (CouchdB)
Browse files Browse the repository at this point in the history
If peers starts up and there is no CouchDB state database,
there is a nil pointer panic due to nil savepoint.

This changeset fixes it by returning nil height
when there is nil savepont.  Nil height for savepoint
will trigger full state db recovery upon peer startup.

Added test to ensure nil height is returned in these cases.

Ensured that leveldb and couchdb behave consistently now.

Tested recovery on both leveldb and couchdb.

Change-Id: I0f2f2f89d7d3176fcf4a560d20665bd59c4d8a5d
Signed-off-by: denyeart <enyeart@us.ibm.com>
  • Loading branch information
denyeart committed Feb 27, 2017
1 parent 7134f9f commit 8b172f5
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ func TestBasicRW(t *testing.T, dbProvider statedb.VersionedDBProvider) {
db, err := dbProvider.GetDBHandle("testbasicrw")
testutil.AssertNoError(t, err, "")

// Test that savepoint is nil for a new state db
sp, err := db.GetLatestSavePoint()
testutil.AssertNoError(t, err, "Error upon GetLatestSavePoint()")
testutil.AssertNil(t, sp)

// Test retrieval of non-existent key - returns nil rather than error
// For more details see https://github.com/hyperledger-archives/fabric/issues/936.
val, err := db.GetState("ns", "key1")
Expand All @@ -54,7 +59,7 @@ func TestBasicRW(t *testing.T, dbProvider statedb.VersionedDBProvider) {
vv, _ = db.GetState("ns2", "key4")
testutil.AssertEquals(t, vv, &vv4)

sp, err := db.GetLatestSavePoint()
sp, err = db.GetLatestSavePoint()
testutil.AssertNoError(t, err, "")
testutil.AssertEquals(t, sp, savePoint)
}
Expand Down
13 changes: 5 additions & 8 deletions core/ledger/kvledger/txmgmt/statedb/statecouchdb/statecouchdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,9 +277,6 @@ func (vdb *VersionedDB) ApplyUpdates(batch *statedb.UpdateBatch, height *version
attachment.AttachmentBytes = vv.Value
attachment.ContentType = "application/octet-stream"
attachment.Name = binaryWrapper

attachments := []couchdb.Attachment{}
attachments = append(attachments, *attachment)
couchDoc.Attachments = append(couchDoc.Attachments, *attachment)
couchDoc.JSONValue = addVersionAndChainCodeID(nil, ns, vv.Version)
}
Expand Down Expand Up @@ -398,19 +395,19 @@ func (vdb *VersionedDB) GetLatestSavePoint() (*version.Height, error) {
couchDoc, _, err := vdb.db.ReadDoc(savepointDocID)
if err != nil {
logger.Errorf("Failed to read savepoint data %s\n", err.Error())
return &version.Height{BlockNum: 0, TxNum: 0}, err
return nil, err
}

// ReadDoc() not found (404) will result in nil response, in these cases return height 0
if couchDoc.JSONValue == nil {
return &version.Height{BlockNum: 0, TxNum: 0}, nil
// ReadDoc() not found (404) will result in nil response, in these cases return height nil
if couchDoc == nil || couchDoc.JSONValue == nil {
return nil, nil
}

savepointDoc := &couchSavepointData{}
err = json.Unmarshal(couchDoc.JSONValue, &savepointDoc)
if err != nil {
logger.Errorf("Failed to unmarshal savepoint data %s\n", err.Error())
return &version.Height{BlockNum: 0, TxNum: 0}, err
return nil, err
}

return &version.Height{BlockNum: savepointDoc.BlockNum, TxNum: savepointDoc.TxNum}, nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@ func TestMain(m *testing.M) {

//call a helper method to load the core.yaml, will be used to detect if CouchDB is enabled
ledgertestutil.SetupCoreYAMLConfig("./../../../../../../peer")
viper.Set("peer.fileSystemPath", "/tmp/fabric/ledgertests/kvledger/txmgmt/statedb/statecouchdb")
viper.Set("ledger.state.stateDatabase", "CouchDB")

// both vagrant and CI have couchdb configured at host "couchdb"
viper.Set("ledger.state.couchDBConfig.couchDBAddress", "couchdb:5984")
viper.Set("peer.fileSystemPath", "/tmp/fabric/ledgertests/kvledger/txmgmt/statedb/statecouchdb")

result := m.Run()
viper.Set("ledger.state.stateDatabase", "goleveldb")
os.Exit(result)
Expand Down
3 changes: 2 additions & 1 deletion core/ledger/kvledger/txmgmt/txmgr/commontests/pkg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ func (env *couchDBLockBasedEnv) getName() string {

func (env *couchDBLockBasedEnv) init(t *testing.T) {
viper.Set("peer.fileSystemPath", testFilesystemPath)
viper.Set("ledger.state.couchDBConfig.couchDBAddress", "127.0.0.1:5984")
// both vagrant and CI have couchdb configured at host "couchdb"
viper.Set("ledger.state.couchDBConfig.couchDBAddress", "couchdb:5984")
testDBEnv := statecouchdb.NewTestVDBEnv(t)
testDB, err := testDBEnv.DBProvider.GetDBHandle(couchTestChainID)
testutil.AssertNoError(t, err, "")
Expand Down
4 changes: 2 additions & 2 deletions peer/core.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,9 @@ peer:
Hash: SHA2
Security: 256
# Location of Key Store, can be subdirectory of SbftLocal.DataDir
FileKeyStore:
FileKeyStore:
# If "", defaults to 'mspConfigPath'/keystore
KeyStore:
KeyStore:

# Path on the file system where peer will find MSP local configurations
mspConfigPath: msp/sampleconfig
Expand Down

0 comments on commit 8b172f5

Please sign in to comment.