From 8b3cbda97e58d1a4ff664219244ffd1d89d7fba8 Mon Sep 17 00:00:00 2001 From: Chris Elder Date: Mon, 10 Sep 2018 09:42:20 -0400 Subject: [PATCH] [FAB-11916] Fix remaining comments for pagination This change corrects the remaining review comments for paginated chaincode APIs See review comments for interfaces.go: https://gerrit.hyperledger.org/r/#/c/24755/47/core/chaincode/shim/interfaces.go Also there were some small remaining comments in peer chaincode handler and tests: https://gerrit.hyperledger.org/r/#/c/25071/ Change-Id: Ib2fe55612150b5496ebedea0bc117649ad383f54 Signed-off-by: Chris Elder --- core/chaincode/exectransaction_test.go | 2 +- core/chaincode/shim/interfaces.go | 24 ++++++------------- core/chaincode/transaction_context.go | 1 + examples/chaincode/go/map/map.go | 32 +++++++++++++------------- 4 files changed, 25 insertions(+), 34 deletions(-) diff --git a/core/chaincode/exectransaction_test.go b/core/chaincode/exectransaction_test.go index 7088de4d583..42c16e5e7eb 100644 --- a/core/chaincode/exectransaction_test.go +++ b/core/chaincode/exectransaction_test.go @@ -1287,7 +1287,7 @@ func TestQueries(t *testing.T) { return } - //The following rich query should return 5 marbles due to the queryLimit + //The following rich query should return 2 marbles due to the pagesize f = "queryByPage" args = util.ToChaincodeArgs(f, "{\"selector\":{\"owner\":\"jerry\"}}", "2", "") diff --git a/core/chaincode/shim/interfaces.go b/core/chaincode/shim/interfaces.go index 4486124eb50..93df6a64111 100644 --- a/core/chaincode/shim/interfaces.go +++ b/core/chaincode/shim/interfaces.go @@ -113,7 +113,7 @@ type ChaincodeStubInterface interface { // between the startKey (inclusive) and endKey (exclusive). // However, if the number of keys between startKey and endKey is greater than the // totalQueryLimit (defined in core.yaml), this iterator cannot be used - // to fetch all keys (results will be limited by the totalQueryLimit). + // to fetch all keys (results will be capped by the totalQueryLimit). // The keys are returned by the iterator in lexical order. Note // that startKey and endKey can be empty string, which implies unbounded range // query on start or end. @@ -132,14 +132,12 @@ type ChaincodeStubInterface interface { // the first `pageSize` keys between the bookmark (inclusive) and endKey (exclusive). // Note that only the bookmark present in a prior page of query results (ResponseMetadata) // can be used as a value to the bookmark argument. Otherwise, an empty string must - // be passed as bookmark. The `pageSize` cannot be greater than the totalQueryLimit (defined - // in the core.yaml). + // be passed as bookmark. // The keys are returned by the iterator in lexical order. Note // that startKey and endKey can be empty string, which implies unbounded range // query on start or end. // Call Close() on the returned StateQueryIteratorInterface object when done. - // The query is re-executed during validation phase to ensure result set - // has not changed since transaction endorsement (phantom reads detected). + // This call is only supported in a read only transaction. GetStateByRangeWithPagination(startKey, endKey string, pageSize int32, bookmark string) (StateQueryIteratorInterface, *pb.QueryResponseMetadata, error) @@ -169,14 +167,12 @@ type ChaincodeStubInterface interface { // composite key. // Note that only the bookmark present in a prior page of query result (ResponseMetadata) // can be used as a value to the bookmark argument. Otherwise, an empty string must - // be passed as bookmark. The `pageSize` cannot be greater than the totalQueryLimit (defined - // in the core.yaml). + // be passed as bookmark. // The `objectType` and attributes are expected to have only valid utf8 strings // and should not contain U+0000 (nil byte) and U+10FFFF (biggest and unallocated // code point). See related functions SplitCompositeKey and CreateCompositeKey. // Call Close() on the returned StateQueryIteratorInterface object when done. - // The query is re-executed during validation phase to ensure result set - // has not changed since transaction endorsement (phantom reads detected). + // This call is only supported in a read only transaction. GetStateByPartialCompositeKeyWithPagination(objectType string, keys []string, pageSize int32, bookmark string) (StateQueryIteratorInterface, *pb.QueryResponseMetadata, error) @@ -221,14 +217,8 @@ type ChaincodeStubInterface interface { // the first `pageSize` keys between the bookmark and the last key in the query result. // Note that only the bookmark present in a prior page of query results (ResponseMetadata) // can be used as a value to the bookmark argument. Otherwise, an empty string - // must be passed as bookmark. The `pageSize` cannot be greater than the totalQueryLimit - // (defined in the core.yaml). - // The query is NOT re-executed during validation phase, phantom reads are - // not detected. That is, other committed transactions may have added, - // updated, or removed keys that impact the result set, and this would not - // be detected at validation/commit time. Applications susceptible to this - // should therefore not use GetQueryResult as part of transactions that update - // ledger, and should limit use to read-only chaincode operations. + // must be passed as bookmark. + // This call is only supported in a read only transaction. GetQueryResultWithPagination(query string, pageSize int32, bookmark string) (StateQueryIteratorInterface, *pb.QueryResponseMetadata, error) diff --git a/core/chaincode/transaction_context.go b/core/chaincode/transaction_context.go index eec690c6a4b..b429dc4f214 100644 --- a/core/chaincode/transaction_context.go +++ b/core/chaincode/transaction_context.go @@ -92,6 +92,7 @@ func (t *TransactionContext) CleanupQueryContextWithBookmark(queryID string) str } delete(t.queryIteratorMap, queryID) delete(t.pendingQueryResults, queryID) + delete(t.totalReturnCount, queryID) return bookmark } diff --git a/examples/chaincode/go/map/map.go b/examples/chaincode/go/map/map.go index dfa60e58b76..af83a9acc40 100644 --- a/examples/chaincode/go/map/map.go +++ b/examples/chaincode/go/map/map.go @@ -209,7 +209,7 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { case "keys": if len(args) < 2 { - return shim.Error("put operation must include two arguments, a key and value") + return shim.Error("keys operation must include two arguments, a key and value") } startKey := args[0] endKey := args[1] @@ -253,7 +253,7 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { case "keysByPage": if len(args) < 4 { - return shim.Error("put operation must include four arguments, a key and value") + return shim.Error("paginated range query operation must include four arguments, a key, value, pageSize and a bookmark") } startKey := args[0] endKey := args[1] @@ -265,13 +265,13 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { //sleep needed to test peer's timeout behavior when using iterators stime := 0 - if len(args) > 2 { - stime, _ = strconv.Atoi(args[2]) + if len(args) > 4 { + stime, _ = strconv.Atoi(args[4]) } keysIter, resp, err := stub.GetStateByRangeWithPagination(startKey, endKey, int32(pageSize), bookmark) if err != nil { - return shim.Error(fmt.Sprintf("keys operation failed. Error accessing state: %s", err)) + return shim.Error(fmt.Sprintf("keysByPage operation failed. Error accessing state: %s", err)) } defer keysIter.Close() @@ -284,13 +284,13 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { response, iterErr := keysIter.Next() if iterErr != nil { - return shim.Error(fmt.Sprintf("keys operation failed. Error accessing state: %s", err)) + return shim.Error(fmt.Sprintf("keysByPage operation failed. Error accessing state: %s", err)) } keys = append(keys, response.Key) } - for key, value := range keys { - fmt.Printf("key %d contains %s\n", key, value) + for index, value := range keys { + fmt.Printf("key %d contains %s\n", index, value) } jsonResp := PageResponse{ @@ -300,7 +300,7 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { queryResp, err := json.Marshal(jsonResp) if err != nil { - return shim.Error(fmt.Sprintf("keys operation failed. Error marshaling JSON: %s", err)) + return shim.Error(fmt.Sprintf("keysByPage operation failed. Error marshaling JSON: %s", err)) } return shim.Success(queryResp) @@ -333,13 +333,13 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { query := args[0] pageSize, parserr := strconv.ParseInt(args[1], 10, 32) if parserr != nil { - return shim.Error(fmt.Sprintf("error parsing range pagesize: %s", parserr)) + return shim.Error(fmt.Sprintf("error parsing query pagesize: %s", parserr)) } bookmark := args[2] keysIter, resp, err := stub.GetQueryResultWithPagination(query, int32(pageSize), bookmark) if err != nil { - return shim.Error(fmt.Sprintf("query operation failed. Error accessing state: %s", err)) + return shim.Error(fmt.Sprintf("queryByPage operation failed. Error accessing state: %s", err)) } defer keysIter.Close() @@ -347,7 +347,7 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { for keysIter.HasNext() { response, iterErr := keysIter.Next() if iterErr != nil { - return shim.Error(fmt.Sprintf("query operation failed. Error accessing state: %s", err)) + return shim.Error(fmt.Sprintf("queryByPage operation failed. Error accessing state: %s", err)) } keys = append(keys, response.Key) } @@ -363,7 +363,7 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { queryResp, err := json.Marshal(jsonResp) if err != nil { - return shim.Error(fmt.Sprintf("keys operation failed. Error marshaling JSON: %s", err)) + return shim.Error(fmt.Sprintf("queryByPage operation failed. Error marshaling JSON: %s", err)) } return shim.Success(queryResp) @@ -372,7 +372,7 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { key := args[0] keysIter, err := stub.GetHistoryForKey(key) if err != nil { - return shim.Error(fmt.Sprintf("query operation failed. Error accessing state: %s", err)) + return shim.Error(fmt.Sprintf("get history operation failed. Error accessing state: %s", err)) } defer keysIter.Close() @@ -380,7 +380,7 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { for keysIter.HasNext() { response, iterErr := keysIter.Next() if iterErr != nil { - return shim.Error(fmt.Sprintf("query operation failed. Error accessing state: %s", err)) + return shim.Error(fmt.Sprintf("get history operation failed. Error accessing state: %s", err)) } keys = append(keys, response.TxId) } @@ -391,7 +391,7 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { jsonKeys, err := json.Marshal(keys) if err != nil { - return shim.Error(fmt.Sprintf("query operation failed. Error marshaling JSON: %s", err)) + return shim.Error(fmt.Sprintf("get history operation failed. Error marshaling JSON: %s", err)) } return shim.Success(jsonKeys)