You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@geode.apache.org by "Juan José Ramos Cassella (JIRA)" <ji...@apache.org> on 2019/06/05 17:58:00 UTC
[jira] [Reopened] (GEODE-6806) Wrong Results in multi OQL joins +
Indexes + LIMIT clause
[ https://issues.apache.org/jira/browse/GEODE-6806?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Juan José Ramos Cassella reopened GEODE-6806:
---------------------------------------------
The new test added seems to be [flaky|https://concourse.apachegeode-ci.info/teams/main/pipelines/apache-develop-main/jobs/WindowsCoreIntegrationTestOpenJDK8/builds/13] and shows that the changes didn't completely fix the issue, only reduced the likely of it happening.
> Wrong Results in multi OQL joins + Indexes + LIMIT clause
> ---------------------------------------------------------
>
> Key: GEODE-6806
> URL: https://issues.apache.org/jira/browse/GEODE-6806
> Project: Geode
> Issue Type: Bug
> Components: querying
> Reporter: Juan José Ramos Cassella
> Assignee: Juan José Ramos Cassella
> Priority: Major
> Labels: GeodeCommons
> Fix For: 1.10.0
>
> Time Spent: 40m
> Remaining Estimate: 0h
>
> When joining multiple regions with indexes defined on them, the results of the query might be wrong if the {{LIMIT}} keyword is used in the {{OQL}} and the intermediate result size of the query is greater than the actual {{LIMIT}} used.
> Internally we get the _partial_ results from the {{indexes}} and _cut down_ these intermediate results during the actual execution. With the goal of speeding things up, we use the {{LIMIT}} value to stop the iteration sooner but we do not know if the first X results (governed by the {{LIMIT}} value) might or might not fulfil the rest of the operands.
> The {{LIMIT}} clause is _disabled_ at the {{index}} level but still enabled in this intermediate step, which is causing the final result to not contain certain rows that should be included.
> The following example reproduces the issue (doesn't matter whether {{PDX}} is used or not):
> {code:java}
> private void populateTripleJointRegions(int expectedMatches, int extraEntitiesPerRegion, Cache cache, Region<String, Object> orderRegion, Region<String, Object> validationIssueRegion, Region<String, Object> validationIssueXRefRegion) {
> for (int i = 0; i < expectedMatches; i++) {
> PdxInstance orderPdx = cache
> .createPdxInstanceFactory("org.apache.geode.test.Order")
> .writeString("orderId", "orderId_" + i)
> .writeInt("version", i)
> .create();
> PdxInstance validationIssuePdx = cache
> .createPdxInstanceFactory("org.apache.geode.test.ValidationIssue")
> .writeString("issueId", "issueId_" + i)
> .writeDate("createdTime", Calendar.getInstance().getTime())
> .create();
> PdxInstance validationIssueXRefPdx = cache
> .createPdxInstanceFactory("org.apache.geode.test.OrderValidationIssueXRef")
> .writeString("validationIssueXRefID", "validationIssueXRefID_" + i)
> .writeString("referenceIssueId", "issueId_" + i)
> .writeString("referenceOrderId", "orderId_" + i)
> .writeInt("referenceOrderVersion", i)
> .create();
> orderRegion.put("orderId_" + i, orderPdx);
> validationIssueRegion.put("issueId_" + i , validationIssuePdx);
> validationIssueXRefRegion.put("validationIssueXRefID_" + i, validationIssueXRefPdx);
> }
> for (int i = 0; i < extraEntitiesPerRegion; i++) {
> PdxInstance orderPdx = cache
> .createPdxInstanceFactory("org.apache.geode.test.Order")
> .writeString("orderId", "orderId#" + i)
> .writeInt("version", i)
> .create();
> PdxInstance validationIssuePdx = cache
> .createPdxInstanceFactory("org.apache.geode.test.ValidationIssue")
> .writeString("referenceIssueId", "referenceIssueId#" + i)
> .writeDate("createdTime", Calendar.getInstance().getTime())
> .create();
> PdxInstance validationIssueXRefPdx = cache
> .createPdxInstanceFactory("org.apache.geode.test.OrderValidationIssueXRef")
> .writeString("validationIssueXRefID", "validationIssueXRefID#" + i)
> .writeString("referenceIssueId", "validationIssueID2#" + i)
> .writeString("referenceOrderId", "orderId#2" + i)
> .writeInt("referenceOrderVersion", i)
> .create();
> orderRegion.put("orderId#" + i, orderPdx);
> validationIssueRegion.put("issueId#" + i , validationIssuePdx );
> validationIssueXRefRegion.put("validationIssueXRefID#" + i, validationIssueXRefPdx);
> }
> }
> @Test
> public void joiningThreeRegionsWhenIntermediateResultSizeIsHigherThanLimitClauseShouldNotTrimResults() throws Exception {
> int matches = 10;
> int extraEntitiesPerRegion = 25;
> Cache cache = CacheUtils.getCache();
> QueryService queryService = cache.getQueryService();
> String queryString = "SELECT issue.issueId, issue.createdTime, o.orderId, o.version "
> + "FROM /ValidationIssue issue, /OrderValidationIssueXRef xRef, /Order o "
> + "WHERE "
> + "issue.issueId = xRef.referenceIssueId "
> + "AND "
> + "xRef.referenceOrderId = o.orderId "
> + "AND "
> + "xRef.referenceOrderVersion = o.version ";
> try {
> Region<String, Object> orderRegion = cache.<String, Object>createRegionFactory()
> .setDataPolicy(DataPolicy.REPLICATE).create("Order");
> Region<String, Object> validationIssueRegion = cache.<String, Object>createRegionFactory()
> .setDataPolicy(DataPolicy.REPLICATE).create("ValidationIssue");
> Region<String, Object> validationIssueXRefRegion = cache.<String, Object>createRegionFactory()
> .setDataPolicy(DataPolicy.REPLICATE).create("OrderValidationIssueXRef");
> populateTripleJointRegions(matches, extraEntitiesPerRegion, orderRegion, validationIssueRegion, validationIssueXRefRegion);
> SelectResults baseResults = (SelectResults) queryService.newQuery(queryString).execute();
> SelectResults resultsWithLimitOne = (SelectResults) queryService.newQuery(queryString + "LIMIT 2").execute();
> SelectResults resultsWithLimitTwo = (SelectResults) queryService.newQuery(queryString + "LIMIT 5").execute();
> assertThat(baseResults.size()).isEqualTo(matches);
> assertThat(resultsWithLimitOne.size()).isEqualTo(2);
> assertThat(resultsWithLimitTwo.size()).isEqualTo(5);
> // Add Indexes and test again
> cache.getQueryService().createIndex("order_orderID", "orderId", "/Order", null);
> cache.getQueryService().createIndex("validationIssue_issueID", "issueId", "/ValidationIssue", null);
> cache.getQueryService().createIndex("orderValidationIssueXRef_referenceOrderId", "referenceOrderId", "/OrderValidationIssueXRef", null);
> cache.getQueryService().createIndex("orderValidationIssueXRef_referenceIssueId", "referenceIssueId", "/OrderValidationIssueXRef", null);
> SelectResults baseResultsWithIndexes = (SelectResults) queryService.newQuery(queryString).execute();
> SelectResults resultsWithLimitOneWithIndexes = (SelectResults) queryService.newQuery(queryString + "LIMIT 2").execute();
> SelectResults resultsWithLimitTwoWithIndexes = (SelectResults) queryService.newQuery(queryString + "LIMIT 5").execute();
> assertThat(baseResultsWithIndexes.size()).isEqualTo(matches);
> // FAIL: the actual size will be 0 in both cases.
> assertThat(resultsWithLimitOneWithIndexes.size()).isEqualTo(2);
> assertThat(resultsWithLimitTwoWithIndexes.size()).isEqualTo(5);
> } finally {
> cache.getRegion("Order").destroyRegion();
> cache.getRegion("ValidationIssue").destroyRegion();
> cache.getRegion("OrderValidationIssueXRef").destroyRegion();
> }
> }
> {code}
--
This message was sent by Atlassian JIRA
(v7.6.3#76005)