Skip to content

Commit

Permalink
Merge "[FAB-7777] Suppress couchdb index creation errors"
Browse files Browse the repository at this point in the history
  • Loading branch information
denyeart authored and Gerrit Code Review committed Feb 16, 2018
2 parents 3fb84fa + 876b274 commit 5dcaee8
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 76 deletions.
40 changes: 17 additions & 23 deletions core/ledger/kvledger/txmgmt/statedb/statecouchdb/statecouchdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,65 +84,59 @@ func NewVersionedDBProvider() (*VersionedDBProvider, error) {
}

//HandleChaincodeDeploy initializes database artifacts for the database associated with the namespace
// This function delibrately suppresses the errors that occur during the creation of the indexes on couchdb.
// This is because, in the present code, we do not differentiate between the errors because of couchdb interaction
// and the errors because of bad index files - the later being unfixable by the admin. Note that the error suppression
// is acceptable since peer can continue in the committing role without the indexes. However, executing chaincode queries
// may be affected, until a new chaincode with fixed indexes is installed and instantiated
func (vdb *VersionedDB) HandleChaincodeDeploy(chaincodeDefinition *cceventmgmt.ChaincodeDefinition, dbArtifactsTar []byte) error {

logger.Debugf("Entering HandleChaincodeDeploy")

if chaincodeDefinition == nil {
return fmt.Errorf("chaincodeDefinition must not be nil")
return fmt.Errorf("chaincodeDefinition found nil while creating couchdb index on chain=%s", vdb.chainName)
}

db, err := vdb.getNamespaceDBHandle(chaincodeDefinition.Name)
if err != nil {
return err
}

//initialize a reader for the artifacts tar file
artifactReader := bytes.NewReader(dbArtifactsTar)
tarReader := tar.NewReader(artifactReader)

for {

//read the next header from the tar
tarHeader, err := tarReader.Next()

//if the EOF is detected, then exit
if err == io.EOF {
// end of tar archive
break
return nil
}
if err != nil {
return err
logger.Errorf("Error during reading db artifacts from tar file for chaincode=[%s] on chain=[%s]. Error=%s",
chaincodeDefinition, vdb.chainName, err)
return nil
}

logger.Debugf("Reading artifact from file: %s", tarHeader.Name)

//Ensure that this is not a directory
if !tarHeader.FileInfo().IsDir() {

//split the filename into directory and file name
dir, file := filepath.Split(tarHeader.Name)

if dir == "META-INF/statedb/couchdb/indexes/" {

logger.Debugf("Creating index from file file: %s", file)

logger.Debugf("Creating index from file: %s", file)
//read the tar entry into a byte array
indexData, err := ioutil.ReadAll(tarReader)
if err != nil {
return err
logger.Errorf("Error during extracting db artifacts file=[%s] from tar for chaincode=[%s] on chain=[%s]. Error=%s",
tarHeader.Name, chaincodeDefinition, vdb.chainName, err)
return nil
}

//create the index from the tar entry
err = db.CreateIndex(string(indexData))
if err != nil {
return err
if err := db.CreateIndex(string(indexData)); err != nil {
logger.Errorf("Error during creation of index from file=[%s] for chaincode=[%s] on chain=[%s]. Error=%s",
tarHeader.Name, chaincodeDefinition, vdb.chainName, err)
}
}
}
}

return nil
}

// GetDBHandle gets the handle to a named database
Expand Down
144 changes: 91 additions & 53 deletions core/ledger/kvledger/txmgmt/statedb/statecouchdb/statecouchdb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"archive/tar"
"bytes"
"fmt"
"log"
"os"
"testing"
"time"
Expand Down Expand Up @@ -328,34 +327,13 @@ func TestHandleChaincodeDeploy(t *testing.T) {
savePoint := version.NewHeight(2, 22)
db.ApplyUpdates(batch, savePoint)

//Create a buffer for the tar file
buffer := new(bytes.Buffer)
tarWriter := tar.NewWriter(buffer)

//Add 2 index definitions
var files = []struct {
Name, Body string
}{
{"META-INF/statedb/couchdb/indexes/indexColorSortName.json", "{\"index\":{\"fields\":[{\"color\":\"desc\"}]},\"ddoc\":\"indexColorSortName\",\"name\":\"indexColorSortName\",\"type\":\"json\"}"},
{"META-INF/statedb/couchdb/indexes/indexSizeSortName.json", "{\"index\":{\"fields\":[{\"size\":\"desc\"}]},\"ddoc\":\"indexSizeSortName\",\"name\":\"indexSizeSortName\",\"type\":\"json\"}"},
}
for _, file := range files {
tarHeader := &tar.Header{
Name: file.Name,
Mode: 0600,
Size: int64(len(file.Body)),
}
err := tarWriter.WriteHeader(tarHeader)
testutil.AssertNoError(t, err, "")

_, err = tarWriter.Write([]byte(file.Body))
testutil.AssertNoError(t, err, "")

}
// Make sure to check the error on Close.
if err := tarWriter.Close(); err != nil {
log.Fatalln(err)
}
//Create a tar file for test with 2 index definitions
dbArtifactsTarBytes := createTarBytesForTest(t,
[]*testFile{
{"META-INF/statedb/couchdb/indexes/indexColorSortName.json", `{"index":{"fields":[{"color":"desc"}]},"ddoc":"indexColorSortName","name":"indexColorSortName","type":"json"}`},
{"META-INF/statedb/couchdb/indexes/indexSizeSortName.json", `{"index":{"fields":[{"size":"desc"}]},"ddoc":"indexSizeSortName","name":"indexSizeSortName","type":"json"}`},
},
)

//Create a query
queryString := `{"selector":{"owner":"fred"}}`
Expand All @@ -369,38 +347,98 @@ func TestHandleChaincodeDeploy(t *testing.T) {
_, err = db.ExecuteQuery("ns1", queryString)
testutil.AssertError(t, err, "Error should have been thrown for a missing index")

if handleDefinition, ok := db.(cceventmgmt.ChaincodeLifecycleEventListener); ok {
handleDefinition, _ := db.(cceventmgmt.ChaincodeLifecycleEventListener)

chaincodeDef := &cceventmgmt.ChaincodeDefinition{Name: "ns1", Hash: nil, Version: ""}
chaincodeDef := &cceventmgmt.ChaincodeDefinition{Name: "ns1", Hash: nil, Version: ""}

//Test HandleChaincodeDefinition with a valid tar file
err := handleDefinition.HandleChaincodeDeploy(chaincodeDef, buffer.Bytes())
testutil.AssertNoError(t, err, "")
//Test HandleChaincodeDefinition with a valid tar file
err = handleDefinition.HandleChaincodeDeploy(chaincodeDef, dbArtifactsTarBytes)
testutil.AssertNoError(t, err, "")

//Test HandleChaincodeDefinition with a nil tar file
err = handleDefinition.HandleChaincodeDeploy(chaincodeDef, nil)
testutil.AssertNoError(t, err, "")
//Sleep to allow time for index creation
time.Sleep(100 * time.Millisecond)
//Create a query with a sort
queryString = `{"selector":{"owner":"fred"}, "sort": [{"size": "desc"}]}`

//Query should complete without error
_, err = db.ExecuteQuery("ns1", queryString)
testutil.AssertNoError(t, err, "")

//Query namespace "ns2", index is only created in "ns1". This should return an error.
_, err = db.ExecuteQuery("ns2", queryString)
testutil.AssertError(t, err, "Error should have been thrown for a missing index")

//Test HandleChaincodeDefinition with a bad tar file
err = handleDefinition.HandleChaincodeDeploy(chaincodeDef, []byte(`This is a really bad tar file`))
testutil.AssertError(t, err, "Error should have been thrown for a bad tar file")
//Test HandleChaincodeDefinition with a nil tar file
err = handleDefinition.HandleChaincodeDeploy(chaincodeDef, nil)
testutil.AssertNoError(t, err, "")

//Test HandleChaincodeDefinition with a nil chaincodeDef
err = handleDefinition.HandleChaincodeDeploy(nil, []byte(`This is a really bad tar file`))
testutil.AssertError(t, err, "Error should have been thrown for a nil chaincodeDefinition")
//Test HandleChaincodeDefinition with a bad tar file
err = handleDefinition.HandleChaincodeDeploy(chaincodeDef, []byte(`This is a really bad tar file`))
testutil.AssertNoError(t, err, "Error should not have been thrown for a bad tar file")

//Sleep to allow time for index creation
time.Sleep(100 * time.Millisecond)
//Create a query with a sort
queryString = `{"selector":{"owner":"fred"}, "sort": [{"size": "desc"}]}`
//Test HandleChaincodeDefinition with a nil chaincodeDef
err = handleDefinition.HandleChaincodeDeploy(nil, dbArtifactsTarBytes)
testutil.AssertError(t, err, "Error should have been thrown for a nil chaincodeDefinition")
}

//Query should complete without error
_, err = db.ExecuteQuery("ns1", queryString)
testutil.AssertNoError(t, err, "")
func TestHandleChaincodeDeployErroneousIndexFile(t *testing.T) {
channelName := "ch1"
env := NewTestVDBEnv(t)
env.Cleanup(channelName)
defer env.Cleanup(channelName)
db, err := env.DBProvider.GetDBHandle(channelName)
testutil.AssertNoError(t, err, "")
db.Open()
defer db.Close()

batch := statedb.NewUpdateBatch()
batch.Put("ns1", "key1", []byte(`{"asset_name": "marble1","color": "blue","size": 1,"owner": "tom"}`), version.NewHeight(1, 1))
batch.Put("ns1", "key2", []byte(`{"asset_name": "marble2","color": "blue","size": 2,"owner": "jerry"}`), version.NewHeight(1, 2))
ccEventListener, _ := db.(cceventmgmt.ChaincodeLifecycleEventListener)

// Create a tar file for test with 2 index definitions - one of them being errorneous
badSyntaxFileContent := `{"index":{"fields": This is a bad json}`
dbArtifactsTarBytes := createTarBytesForTest(t,
[]*testFile{
{"META-INF/statedb/couchdb/indexes/indexSizeSortName.json", `{"index":{"fields":[{"size":"desc"}]},"ddoc":"indexSizeSortName","name":"indexSizeSortName","type":"json"}`},
{"META-INF/statedb/couchdb/indexes/badSyntax.json", badSyntaxFileContent},
},
)
// Test HandleChaincodeDefinition with a bad tar file
chaincodeName := "ns1"
chaincodeVer := "1.0"
chaincodeDef := &cceventmgmt.ChaincodeDefinition{Name: chaincodeName, Hash: []byte("Hash for test chaincode"), Version: chaincodeVer}
err = ccEventListener.HandleChaincodeDeploy(chaincodeDef, dbArtifactsTarBytes)
testutil.AssertNoError(t, err, "A tar with a bad syntax file should not cause an error")
//Sleep to allow time for index creation
time.Sleep(100 * time.Millisecond)
//Query should complete without error
_, err = db.ExecuteQuery("ns1", `{"selector":{"owner":"fred"}, "sort": [{"size": "desc"}]}`)
testutil.AssertNoError(t, err, "")
}

//Query namespace "ns2", index is only created in "ns1". This should return an error.
_, err = db.ExecuteQuery("ns2", queryString)
testutil.AssertError(t, err, "Error should have been thrown for a missing index")
type testFile struct {
name, body string
}

func createTarBytesForTest(t *testing.T, testFiles []*testFile) []byte {
//Create a buffer for the tar file
buffer := new(bytes.Buffer)
tarWriter := tar.NewWriter(buffer)

for _, file := range testFiles {
tarHeader := &tar.Header{
Name: file.name,
Mode: 0600,
Size: int64(len(file.body)),
}
err := tarWriter.WriteHeader(tarHeader)
testutil.AssertNoError(t, err, "")

_, err = tarWriter.Write([]byte(file.body))
testutil.AssertNoError(t, err, "")
}
// Make sure to check the error on Close.
testutil.AssertNoError(t, tarWriter.Close(), "")
return buffer.Bytes()
}

0 comments on commit 5dcaee8

Please sign in to comment.