Skip to content

Commit 868a3e9

Browse files
committed
FAB-2462: Re-enable paging results for queries
Paging result sets is required in order to avoid failures related to large result sets. The Next() call on StateQueryIterator from Chaincode was failing in peer due to a corner case. This fix addresses the corner case (where the number of results is an exact multiple of shim batch size). This is done by keeping the HasMore flag in iterator accurate by pre-fetching the next batch of results when the last cached item from shim is accessed. This fix also adds the Namespace field to commonledger.KV type. The data returned to peer has namespace information. All state iterators return QueryResult with commonledger.KV type elements. Change-Id: Id872130db8a20ec5a59593b1fa004dce43ee36ac Signed-off-by: Balaji Viswanathan <[email protected]> Signed-off-by: denyeart <[email protected]>
1 parent 7f114bb commit 868a3e9

File tree

6 files changed

+189
-259
lines changed

6 files changed

+189
-259
lines changed

core/chaincode/exectransaction_test.go

+113-184
Original file line numberDiff line numberDiff line change
@@ -1055,160 +1055,41 @@ func TestQueries(t *testing.T) {
10551055
return
10561056
}
10571057

1058-
// Add 12 marbles for testing range queries and rich queries (for capable ledgers)
1058+
// Add 101 marbles for testing range queries and rich queries (for capable ledgers)
10591059
// The tests will test both range and rich queries and queries with query limits
1060-
f = "put"
1061-
args = util.ToChaincodeArgs(f, "marble01", "{\"docType\":\"marble\",\"name\":\"marble01\",\"color\":\"blue\",\"size\":35,\"owner\":\"tom\"}")
1062-
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1063-
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1064-
nextBlockNumber++
1065-
1066-
if err != nil {
1067-
t.Fail()
1068-
t.Logf("Error invoking <%s>: %s", ccID, err)
1069-
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1070-
return
1071-
}
1072-
1073-
f = "put"
1074-
args = util.ToChaincodeArgs(f, "marble02", "{\"docType\":\"marble\",\"name\":\"marble02\",\"color\":\"red\",\"size\":25,\"owner\":\"tom\"}")
1075-
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1076-
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1077-
nextBlockNumber++
1078-
1079-
if err != nil {
1080-
t.Fail()
1081-
t.Logf("Error invoking <%s>: %s", ccID, err)
1082-
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1083-
return
1084-
}
1085-
1086-
f = "put"
1087-
args = util.ToChaincodeArgs(f, "marble03", "{\"docType\":\"marble\",\"name\":\"marble03\",\"color\":\"green\",\"size\":15,\"owner\":\"tom\"}")
1088-
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1089-
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1090-
nextBlockNumber++
1091-
if err != nil {
1092-
t.Fail()
1093-
t.Logf("Error invoking <%s>: %s", ccID, err)
1094-
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1095-
return
1096-
}
1097-
1098-
f = "put"
1099-
args = util.ToChaincodeArgs(f, "marble04", "{\"docType\":\"marble\",\"name\":\"marble04\",\"color\":\"green\",\"size\":20,\"owner\":\"jerry\"}")
1100-
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1101-
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1102-
nextBlockNumber++
1103-
if err != nil {
1104-
t.Fail()
1105-
t.Logf("Error invoking <%s>: %s", ccID, err)
1106-
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1107-
return
1108-
}
1109-
1110-
f = "put"
1111-
args = util.ToChaincodeArgs(f, "marble05", "{\"docType\":\"marble\",\"name\":\"marble05\",\"color\":\"red\",\"size\":25,\"owner\":\"jerry\"}")
1112-
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1113-
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1114-
nextBlockNumber++
1115-
if err != nil {
1116-
t.Fail()
1117-
t.Logf("Error invoking <%s>: %s", ccID, err)
1118-
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1119-
return
1120-
}
1121-
1122-
f = "put"
1123-
args = util.ToChaincodeArgs(f, "marble06", "{\"docType\":\"marble\",\"name\":\"marble06\",\"color\":\"blue\",\"size\":35,\"owner\":\"jerry\"}")
1124-
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1125-
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1126-
nextBlockNumber++
1127-
if err != nil {
1128-
t.Fail()
1129-
t.Logf("Error invoking <%s>: %s", ccID, err)
1130-
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1131-
return
1132-
}
1133-
1134-
f = "put"
1135-
args = util.ToChaincodeArgs(f, "marble07", "{\"docType\":\"marble\",\"name\":\"marble07\",\"color\":\"yellow\",\"size\":20,\"owner\":\"jerry\"}")
1136-
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1137-
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1138-
nextBlockNumber++
1139-
if err != nil {
1140-
t.Fail()
1141-
t.Logf("Error invoking <%s>: %s", ccID, err)
1142-
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1143-
return
1144-
}
1145-
1146-
f = "put"
1147-
args = util.ToChaincodeArgs(f, "marble08", "{\"docType\":\"marble\",\"name\":\"marble08\",\"color\":\"green\",\"size\":40,\"owner\":\"jerry\"}")
1148-
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1149-
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1150-
nextBlockNumber++
1151-
if err != nil {
1152-
t.Fail()
1153-
t.Logf("Error invoking <%s>: %s", ccID, err)
1154-
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1155-
return
1156-
}
1060+
for i := 1; i <= 101; i++ {
1061+
f = "put"
11571062

1158-
f = "put"
1159-
args = util.ToChaincodeArgs(f, "marble09", "{\"docType\":\"marble\",\"name\":\"marble09\",\"color\":\"yellow\",\"size\":10,\"owner\":\"jerry\"}")
1160-
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1161-
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1162-
nextBlockNumber++
1163-
if err != nil {
1164-
t.Fail()
1165-
t.Logf("Error invoking <%s>: %s", ccID, err)
1166-
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1167-
return
1168-
}
1063+
// 51 owned by tom, 50 by jerry
1064+
owner := "tom"
1065+
if i%2 == 0 {
1066+
owner = "jerry"
1067+
}
11691068

1170-
f = "put"
1171-
args = util.ToChaincodeArgs(f, "marble10", "{\"docType\":\"marble\",\"name\":\"marble10\",\"color\":\"red\",\"size\":20,\"owner\":\"jerry\"}")
1172-
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1173-
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1174-
nextBlockNumber++
1175-
if err != nil {
1176-
t.Fail()
1177-
t.Logf("Error invoking <%s>: %s", ccID, err)
1178-
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1179-
return
1180-
}
1069+
// one marble color is red, 100 are blue
1070+
color := "blue"
1071+
if i == 12 {
1072+
color = "red"
1073+
}
11811074

1182-
f = "put"
1183-
args = util.ToChaincodeArgs(f, "marble11", "{\"docType\":\"marble\",\"name\":\"marble11\",\"color\":\"green\",\"size\":40,\"owner\":\"jerry\"}")
1184-
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1185-
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1186-
nextBlockNumber++
1187-
if err != nil {
1188-
t.Fail()
1189-
t.Logf("Error invoking <%s>: %s", ccID, err)
1190-
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1191-
return
1192-
}
1075+
key := fmt.Sprintf("marble%03d", i)
1076+
argsString := fmt.Sprintf("{\"docType\":\"marble\",\"name\":\"%s\",\"color\":\"%s\",\"size\":35,\"owner\":\"%s\"}", key, color, owner)
1077+
args = util.ToChaincodeArgs(f, key, argsString)
1078+
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1079+
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1080+
nextBlockNumber++
11931081

1194-
f = "put"
1195-
args = util.ToChaincodeArgs(f, "marble12", "{\"docType\":\"marble\",\"name\":\"marble12\",\"color\":\"red\",\"size\":30,\"owner\":\"jerry\"}")
1196-
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1197-
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1198-
nextBlockNumber++
1199-
if err != nil {
1200-
t.Fail()
1201-
t.Logf("Error invoking <%s>: %s", ccID, err)
1202-
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1203-
return
1082+
if err != nil {
1083+
t.Fail()
1084+
t.Logf("Error invoking <%s>: %s", ccID, err)
1085+
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1086+
return
1087+
}
12041088
}
12051089

1206-
//TODO - the following query tests for queryLimits may change due to future designs
1207-
// for batch "paging"
1208-
1209-
//The following range query for "marble01" to "marble11" should return 10 marbles
1090+
//The following range query for "marble001" to "marble011" should return 10 marbles
12101091
f = "keys"
1211-
args = util.ToChaincodeArgs(f, "marble01", "marble11")
1092+
args = util.ToChaincodeArgs(f, "marble001", "marble011")
12121093

12131094
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
12141095
_, _, retval, err := invoke(ctxt, chainID, spec, nextBlockNumber, nil)
@@ -1222,25 +1103,21 @@ func TestQueries(t *testing.T) {
12221103

12231104
var keys []interface{}
12241105
err = json.Unmarshal(retval, &keys)
1225-
1226-
//default query limit of 10000 is used, query should return all records that meet the criteria
12271106
if len(keys) != 10 {
12281107
t.Fail()
12291108
t.Logf("Error detected with the range query, should have returned 10 but returned %v", len(keys))
12301109
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
12311110
return
12321111
}
12331112

1234-
//Reset the query limit to 5
1235-
viper.Set("ledger.state.queryLimit", 5)
1236-
1237-
//The following range query for "marble01" to "marble11" should return 5 marbles due to the queryLimit
1113+
// querying for all marbles will return 101 marbles
1114+
// this query should return exactly 101 results (one call to Next())
1115+
//The following range query for "marble001" to "marble102" should return 101 marbles
12381116
f = "keys"
1239-
args = util.ToChaincodeArgs(f, "marble01", "marble11")
1117+
args = util.ToChaincodeArgs(f, "marble001", "marble102")
12401118

12411119
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
12421120
_, _, retval, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1243-
12441121
nextBlockNumber++
12451122
if err != nil {
12461123
t.Fail()
@@ -1252,46 +1129,52 @@ func TestQueries(t *testing.T) {
12521129
//unmarshal the results
12531130
err = json.Unmarshal(retval, &keys)
12541131

1255-
//check to see if there are 5 values
1256-
if len(keys) != 5 {
1132+
//check to see if there are 101 values
1133+
//default query limit of 10000 is used, this query is effectively unlimited
1134+
if len(keys) != 101 {
12571135
t.Fail()
1258-
t.Logf("Error detected with the range query, should have returned 5 but returned %v", len(keys))
1136+
t.Logf("Error detected with the range query, should have returned 101 but returned %v", len(keys))
12591137
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
12601138
return
12611139
}
12621140

1263-
//Reset the query limit to default
1264-
viper.Set("ledger.state.queryLimit", 10000)
1141+
// ExecuteQuery supported only for CouchDB and
1142+
// query limits apply for CouchDB range and rich queries only
1143+
if ledgerconfig.IsCouchDBEnabled() == true {
12651144

1266-
if ledgerconfig.IsHistoryDBEnabled() == true {
1145+
// corner cases for shim batching. currnt shim batch size is 100
1146+
// this query should return exactly 100 results (no call to Next())
1147+
f = "query"
1148+
args = util.ToChaincodeArgs(f, "{\"selector\":{\"color\":\"blue\"}}")
12671149

1268-
f = "put"
1269-
args = util.ToChaincodeArgs(f, "marble12", "{\"docType\":\"marble\",\"name\":\"marble12\",\"color\":\"red\",\"size\":30,\"owner\":\"jerry\"}")
12701150
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
12711151
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
12721152
nextBlockNumber++
1153+
12731154
if err != nil {
12741155
t.Fail()
12751156
t.Logf("Error invoking <%s>: %s", ccID, err)
12761157
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
12771158
return
12781159
}
12791160

1280-
f = "put"
1281-
args = util.ToChaincodeArgs(f, "marble12", "{\"docType\":\"marble\",\"name\":\"marble12\",\"color\":\"red\",\"size\":30,\"owner\":\"jerry\"}")
1282-
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1283-
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1284-
nextBlockNumber++
1285-
if err != nil {
1161+
//unmarshal the results
1162+
err = json.Unmarshal(retval, &keys)
1163+
1164+
//check to see if there are 100 values
1165+
if len(keys) != 100 {
12861166
t.Fail()
1287-
t.Logf("Error invoking <%s>: %s", ccID, err)
1167+
t.Logf("Error detected with the rich query, should have returned 100 but returned %v %s", len(keys), keys)
12881168
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
12891169
return
12901170
}
12911171

1292-
//The following history query for "marble12" should return 3 records
1293-
f = "history"
1294-
args = util.ToChaincodeArgs(f, "marble12")
1172+
//Reset the query limit to 5
1173+
viper.Set("ledger.state.queryLimit", 5)
1174+
1175+
//The following range query for "marble01" to "marble11" should return 5 marbles due to the queryLimit
1176+
f = "keys"
1177+
args = util.ToChaincodeArgs(f, "marble001", "marble011")
12951178

12961179
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
12971180
_, _, retval, err := invoke(ctxt, chainID, spec, nextBlockNumber, nil)
@@ -1303,22 +1186,21 @@ func TestQueries(t *testing.T) {
13031186
return
13041187
}
13051188

1306-
var history []interface{}
1307-
err = json.Unmarshal(retval, &history)
1189+
//unmarshal the results
1190+
err = json.Unmarshal(retval, &keys)
13081191

1309-
//default query limit of 10000 is used, query should return all records that meet the criteria
1310-
if len(history) != 3 {
1192+
//check to see if there are 5 values
1193+
if len(keys) != 5 {
13111194
t.Fail()
1312-
t.Logf("Error detected with the history query, should have returned 3 but returned %v", len(keys))
1195+
t.Logf("Error detected with the range query, should have returned 5 but returned %v", len(keys))
13131196
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
13141197
return
13151198
}
13161199

1317-
}
1318-
1319-
if ledgerconfig.IsCouchDBEnabled() == true {
1200+
//Reset the query limit to 10000
1201+
viper.Set("ledger.state.queryLimit", 10000)
13201202

1321-
//The following rich query for should return 9 marbles
1203+
//The following rich query for should return 50 marbles
13221204
f = "query"
13231205
args = util.ToChaincodeArgs(f, "{\"selector\":{\"owner\":\"jerry\"}}")
13241206

@@ -1336,9 +1218,9 @@ func TestQueries(t *testing.T) {
13361218
//unmarshal the results
13371219
err = json.Unmarshal(retval, &keys)
13381220

1339-
//check to see if there are 9 values
1221+
//check to see if there are 50 values
13401222
//default query limit of 10000 is used, this query is effectively unlimited
1341-
if len(keys) != 9 {
1223+
if len(keys) != 50 {
13421224
t.Fail()
13431225
t.Logf("Error detected with the rich query, should have returned 9 but returned %v", len(keys))
13441226
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
@@ -1354,7 +1236,7 @@ func TestQueries(t *testing.T) {
13541236

13551237
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
13561238
_, _, retval, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1357-
1239+
nextBlockNumber++
13581240
if err != nil {
13591241
t.Fail()
13601242
t.Logf("Error invoking <%s>: %s", ccID, err)
@@ -1375,6 +1257,53 @@ func TestQueries(t *testing.T) {
13751257

13761258
}
13771259

1260+
// modifications for history query
1261+
f = "put"
1262+
args = util.ToChaincodeArgs(f, "marble012", "{\"docType\":\"marble\",\"name\":\"marble012\",\"color\":\"red\",\"size\":30,\"owner\":\"jerry\"}")
1263+
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1264+
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1265+
nextBlockNumber++
1266+
if err != nil {
1267+
t.Fail()
1268+
t.Logf("Error invoking <%s>: %s", ccID, err)
1269+
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1270+
return
1271+
}
1272+
1273+
f = "put"
1274+
args = util.ToChaincodeArgs(f, "marble012", "{\"docType\":\"marble\",\"name\":\"marble012\",\"color\":\"red\",\"size\":30,\"owner\":\"jerry\"}")
1275+
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1276+
_, _, _, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1277+
nextBlockNumber++
1278+
if err != nil {
1279+
t.Fail()
1280+
t.Logf("Error invoking <%s>: %s", ccID, err)
1281+
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1282+
return
1283+
}
1284+
1285+
//The following history query for "marble12" should return 3 records
1286+
f = "history"
1287+
args = util.ToChaincodeArgs(f, "marble012")
1288+
spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}}
1289+
_, _, retval, err = invoke(ctxt, chainID, spec, nextBlockNumber, nil)
1290+
nextBlockNumber++
1291+
if err != nil {
1292+
t.Fail()
1293+
t.Logf("Error invoking <%s>: %s", ccID, err)
1294+
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1295+
return
1296+
}
1297+
1298+
var history []interface{}
1299+
err = json.Unmarshal(retval, &history)
1300+
if len(history) != 3 {
1301+
t.Fail()
1302+
t.Logf("Error detected with the history query, should have returned 3 but returned %v", len(keys))
1303+
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
1304+
return
1305+
}
1306+
13781307
theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
13791308
}
13801309

0 commit comments

Comments
 (0)