From 3367dc703e7af8ebd31c73ec445277c7338b31ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Avard=20Ottestad?= Date: Mon, 25 Jul 2022 14:33:12 +0200 Subject: [PATCH 1/3] GH-4068 update tests --- .../eclipse/rdf4j/federated/BindTests.java | 2 +- .../eclipse/rdf4j/federated/FedXBaseTest.java | 111 +++++++----------- .../rdf4j/federated/FedXFactoryTest.java | 6 +- .../rdf4j/federated/SPARQLBaseTest.java | 2 +- 4 files changed, 45 insertions(+), 76 deletions(-) diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/BindTests.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/BindTests.java index 91a3931eee7..70eed76f853 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/BindTests.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/BindTests.java @@ -24,7 +24,7 @@ public void testSimple() throws Exception { List res = runQuery( "SELECT * WHERE { BIND(20 AS ?age) . ?person foaf:age ?age }"); - assertContainsAll(res, "person", Sets.newHashSet(fullIri("http://namespace1.org/Person_1"))); + assertContainsAll(res, "person", Sets.newHashSet(iri("http://namespace1.org/", "Person_1"))); } @Test diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXBaseTest.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXBaseTest.java index b92d237c8a0..6ee86cbf77b 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXBaseTest.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXBaseTest.java @@ -34,7 +34,6 @@ import org.eclipse.rdf4j.query.QueryResults; import org.eclipse.rdf4j.query.TupleQuery; import org.eclipse.rdf4j.query.TupleQueryResult; -import org.eclipse.rdf4j.query.dawg.DAWGTestResultSetUtil; import org.eclipse.rdf4j.query.impl.ListBindingSet; import org.eclipse.rdf4j.query.impl.MutableTupleQueryResult; import org.eclipse.rdf4j.query.impl.TupleQueryResultBuilder; @@ -42,7 +41,6 @@ import org.eclipse.rdf4j.query.resultio.QueryResultFormat; import org.eclipse.rdf4j.query.resultio.QueryResultIO; import org.eclipse.rdf4j.query.resultio.TupleQueryResultParser; -import org.eclipse.rdf4j.repository.RepositoryConnection; import org.eclipse.rdf4j.repository.RepositoryException; import org.eclipse.rdf4j.rio.RDFFormat; import org.eclipse.rdf4j.rio.RDFParser; @@ -60,7 +58,7 @@ public abstract class FedXBaseTest { public static Logger log; @BeforeAll - public static void initLogging() throws Exception { + public static void initLogging() { if (System.getProperty("log4j.configurationFile") == null) { System.setProperty("log4j.configurationFile", "file:build/test/log4j-debug.properties"); @@ -83,7 +81,7 @@ public static void initLogging() throws Exception { * @param checkOrder * @throws Exception */ - protected void execute(RepositoryConnection conn, String queryFile, String expectedResultFile, boolean checkOrder) + protected void execute(String queryFile, String expectedResultFile, boolean checkOrder) throws Exception { String queryString = readQueryString(queryFile); @@ -91,6 +89,10 @@ protected void execute(RepositoryConnection conn, String queryFile, String expec Query query = queryManager().prepareQuery(queryString); if (query instanceof TupleQuery) { + // Some query results will automatically close themselves when they are exhausted. To properly test that + // query results are closed correctly we need to evaluate the query without retrieving any elements. + ((TupleQuery) query).evaluate().close(); + try (TupleQueryResult queryResult = ((TupleQuery) query).evaluate()) { TupleQueryResult expectedResult = readExpectedTupleQueryResult(expectedResultFile); @@ -99,6 +101,10 @@ protected void execute(RepositoryConnection conn, String queryFile, String expec } } else if (query instanceof GraphQuery) { + // Some query results will automatically close themselves when they are exhausted. To properly test that + // query results are closed correctly we need to evaluate the query without retrieving any elements. + ((GraphQuery) query).evaluate().close(); + try (GraphQueryResult gqr = ((GraphQuery) query).evaluate()) { Set queryResult = Iterations.asSet(gqr); @@ -108,7 +114,6 @@ protected void execute(RepositoryConnection conn, String queryFile, String expec } } else if (query instanceof BooleanQuery) { - boolean queryResult = ((BooleanQuery) query).evaluate(); boolean expectedResult = readExpectedBooleanQueryResult(expectedResultFile); Assertions.assertEquals(expectedResult, queryResult); @@ -117,18 +122,6 @@ protected void execute(RepositoryConnection conn, String queryFile, String expec } } - protected TupleQueryResult runSelectQueryFile(String queryFile) throws Exception { - String queryString = readQueryString(queryFile); - - Query query = queryManager().prepareQuery(queryString); - - if (query instanceof TupleQuery) { - return ((TupleQuery) query).evaluate(); - } - - throw new Exception("unexpected query: " + queryString); - } - protected void evaluateQueryPlan(String queryFile, String expectedPlanFile) throws Exception { String actualQueryPlan = federationContext().getQueryManager().getQueryPlan(readQueryString(queryFile)); @@ -158,7 +151,6 @@ protected Literal l(String value) { } /** - * * @param localName * @return the IRI in the instance's {@link #defaultNamespace} */ @@ -170,14 +162,10 @@ protected static IRI iri(String namespace, String localName) { return vf.createIRI(namespace, localName); } - protected static IRI fullIri(String fullIri) { - return vf.createIRI(fullIri); - } - /** * Read the query string from the specified resource * - * @param queryResource + * @param queryFile * @return * @throws RepositoryException * @throws IOException @@ -195,6 +183,7 @@ protected String readQueryString(String queryFile) throws RepositoryException, I */ protected String readResourceAsString(String resource) throws IOException { try (InputStream stream = FedXBaseTest.class.getResourceAsStream(resource)) { + assert stream != null; return IOUtil.readString(new InputStreamReader(stream, StandardCharsets.UTF_8)); } } @@ -202,32 +191,27 @@ protected String readResourceAsString(String resource) throws IOException { /** * Read the expected tuple query result from the specified resource * - * @param queryResource + * @param resultFile * @return * @throws RepositoryException * @throws IOException */ protected TupleQueryResult readExpectedTupleQueryResult(String resultFile) throws Exception { - QueryResultFormat tqrFormat = QueryResultIO.getParserFormatForFileName(resultFile).get(); + QueryResultFormat tqrFormat = QueryResultIO.getParserFormatForFileName(resultFile).orElseThrow(); - if (tqrFormat != null) { - InputStream in = SPARQLBaseTest.class.getResourceAsStream(resultFile); + InputStream in = SPARQLBaseTest.class.getResourceAsStream(resultFile); - try (in) { - if (in == null) { - throw new IOException("File could not be opened: " + resultFile); - } - TupleQueryResultParser parser = QueryResultIO.createTupleParser(tqrFormat); + try (in) { + if (in == null) { + throw new IOException("File could not be opened: " + resultFile); + } + TupleQueryResultParser parser = QueryResultIO.createTupleParser(tqrFormat); - TupleQueryResultBuilder qrBuilder = new TupleQueryResultBuilder(); - parser.setQueryResultHandler(qrBuilder); + TupleQueryResultBuilder qrBuilder = new TupleQueryResultBuilder(); + parser.setQueryResultHandler(qrBuilder); - parser.parseQueryResult(in); - return qrBuilder.getQueryResult(); - } - } else { - Set resultGraph = readExpectedGraphQueryResult(resultFile); - return DAWGTestResultSetUtil.toTupleQueryResult(resultGraph); + parser.parseQueryResult(in); + return qrBuilder.getQueryResult(); } } @@ -239,39 +223,30 @@ protected TupleQueryResult readExpectedTupleQueryResult(String resultFile) throw * @throws Exception */ protected Set readExpectedGraphQueryResult(String resultFile) throws Exception { - RDFFormat rdfFormat = Rio.getParserFormatForFileName(resultFile).get(); + RDFFormat rdfFormat = Rio.getParserFormatForFileName(resultFile).orElseThrow(); - if (rdfFormat != null) { - RDFParser parser = Rio.createParser(rdfFormat); - parser.setPreserveBNodeIDs(true); - parser.setValueFactory(SimpleValueFactory.getInstance()); + RDFParser parser = Rio.createParser(rdfFormat); + parser.setPreserveBNodeIDs(true); + parser.setValueFactory(SimpleValueFactory.getInstance()); - Set result = new LinkedHashSet<>(); - parser.setRDFHandler(new StatementCollector(result)); + Set result = new LinkedHashSet<>(); + parser.setRDFHandler(new StatementCollector(result)); - try (InputStream in = SPARQLBaseTest.class.getResourceAsStream(resultFile)) { - parser.parse(in, resultFile); - } - - return result; - } else { - throw new RuntimeException("Unable to determine file type of results file"); + try (InputStream in = SPARQLBaseTest.class.getResourceAsStream(resultFile)) { + parser.parse(in, resultFile); } + + return result; } protected boolean readExpectedBooleanQueryResult(String resultFile) throws Exception { QueryResultFormat bqrFormat = BooleanQueryResultParserRegistry.getInstance() .getFileFormatForFileName( resultFile) - .get(); + .orElseThrow(); - if (bqrFormat != null) { - try (InputStream in = SPARQLBaseTest.class.getResourceAsStream(resultFile)) { - return QueryResultIO.parseBoolean(in, bqrFormat); - } - } else { - Set resultGraph = readExpectedGraphQueryResult(resultFile); - return DAWGTestResultSetUtil.toBooleanQueryResult(resultGraph); + try (InputStream in = SPARQLBaseTest.class.getResourceAsStream(resultFile)) { + return QueryResultIO.parseBoolean(in, bqrFormat); } } @@ -280,7 +255,6 @@ protected SimpleTupleQueryResultBuilder tupleQueryResultBuilder(List bin } /** - * * Note: metod can only be used after initialization phase * * @return the current {@link FederationContext} @@ -297,11 +271,9 @@ protected QueryManager queryManager() { * @param queryResult * @param expectedResult * @param checkOrder - * @throws Exception */ protected void compareTupleQueryResults(TupleQueryResult queryResult, TupleQueryResult expectedResult, - boolean checkOrder) - throws Exception { + boolean checkOrder) { // Create MutableTupleQueryResult to be able to re-iterate over the // results MutableTupleQueryResult queryResultTable = new MutableTupleQueryResult(queryResult); @@ -376,7 +348,7 @@ protected void compareTupleQueryResults(TupleQueryResult queryResult, TupleQuery } message.append(" =======================\n"); - System.out.print(message.toString()); + System.out.print(message); } log.error(message.toString()); @@ -390,10 +362,8 @@ protected void compareTupleQueryResults(TupleQueryResult queryResult, TupleQuery * * @param queryResult * @param expectedResult - * @throws Exception */ - protected void compareGraphs(Set queryResult, Set expectedResult) - throws Exception { + protected void compareGraphs(Set queryResult, Set expectedResult) { if (!Models.isomorphic(expectedResult, queryResult)) { StringBuilder message = new StringBuilder(128); message.append("Expected result: \n"); @@ -417,7 +387,6 @@ protected void compareGraphs(Set queryResult, Set expected * A builder for {@link TupleQueryResult}s. * * @author as - * */ public static class SimpleTupleQueryResultBuilder { diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXFactoryTest.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXFactoryTest.java index 9d42385153f..869ea125ac1 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXFactoryTest.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXFactoryTest.java @@ -46,7 +46,7 @@ public void testFederationWithResolver() throws Exception { repo.init(); federationContext = repo.getFederationContext(); try (RepositoryConnection conn = repo.getConnection()) { - execute(conn, "/tests/medium/query01.rq", "/tests/medium/query01.srx", false); + execute("/tests/medium/query01.rq", "/tests/medium/query01.srx", false); } repo.shutDown(); @@ -75,7 +75,7 @@ public void testFederationWithResolver_writable() throws Exception { federationContext = repo.getFederationContext(); try (RepositoryConnection conn = repo.getConnection()) { - execute(conn, "/tests/medium/query01.rq", "/tests/medium/query01.srx", false); + execute("/tests/medium/query01.rq", "/tests/medium/query01.srx", false); } repo.shutDown(); @@ -102,7 +102,7 @@ public void testFederationWithResolver_DataConfig() throws Exception { repo.init(); federationContext = repo.getFederationContext(); try (RepositoryConnection conn = repo.getConnection()) { - execute(conn, "/tests/medium/query01.rq", "/tests/medium/query01.srx", false); + execute("/tests/medium/query01.rq", "/tests/medium/query01.srx", false); } repo.shutDown(); diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SPARQLBaseTest.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SPARQLBaseTest.java index 1c5da52fb37..b8ca7ddfc5f 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SPARQLBaseTest.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SPARQLBaseTest.java @@ -52,7 +52,7 @@ protected void initFedXConfig() { protected void execute(String queryFile, String expectedResultFile, boolean checkOrder) throws Exception { try (RepositoryConnection conn = fedxRule.getRepository().getConnection()) { - super.execute(conn, queryFile, expectedResultFile, checkOrder); + super.execute(queryFile, expectedResultFile, checkOrder); } } From e45d3536ddb9d9165ecbae66de2550650f8932d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Avard=20Ottestad?= Date: Mon, 25 Jul 2022 14:33:37 +0200 Subject: [PATCH 2/3] GH-4068 make sure iterations are closed --- .../sail/helpers/AbstractSailConnection.java | 30 ++-- .../sail/nativerdf/btree/RangeIterator.java | 32 ++-- .../repository/TupleQueryResultTest.java | 9 +- .../rdf4j/federated/FedXConnection.java | 137 ++++++++++-------- .../algebra/FedXStatementPattern.java | 1 - .../evaluation/SailTripleSource.java | 38 +++-- .../concurrent/FedXQueueCursor.java | 38 +++-- .../CloseDependentConnectionIteration.java | 33 ++--- .../iterator/ConsumingIteration.java | 3 +- .../iterator/FederatedDescribeIteration.java | 11 +- .../GraphToBindingSetConversionIteration.java | 4 + ...IndependentJoingroupBindingsIteration.java | 8 + ...ndependentJoingroupBindingsIteration2.java | 9 ++ ...ndependentJoingroupBindingsIteration3.java | 9 ++ .../iterator/QueryResultIteration.java | 11 +- ...opRemainingExecutionsOnCloseIteration.java | 15 +- .../rdf4j/federated/structures/QueryInfo.java | 37 +++-- .../eclipse/rdf4j/federated/BasicTests.java | 83 ++++++----- .../rdf4j/federated/BoundJoinTests.java | 6 +- .../rdf4j/federated/DistinctTests.java | 12 +- .../eclipse/rdf4j/federated/FedXBaseTest.java | 19 ++- .../rdf4j/federated/FedXFactoryTest.java | 6 +- .../eclipse/rdf4j/federated/FilterTests.java | 16 +- .../federated/MediumConcurrencyTest.java | 35 +---- .../eclipse/rdf4j/federated/MediumTests.java | 24 +-- .../rdf4j/federated/OptionalTests.java | 4 +- .../rdf4j/federated/QueryTimeoutTests.java | 2 +- .../rdf4j/federated/SPARQL1_1Tests.java | 4 +- .../rdf4j/federated/SPARQLBaseTest.java | 15 -- .../eclipse/rdf4j/federated/ServiceTests.java | 24 +-- .../rdf4j/federated/SubSelectTests.java | 2 +- .../TaskWrapperIntegrationTest.java | 4 +- .../rdf4j/federated/misc/PrefixTests.java | 6 +- .../performance/FedXPerformanceTest.java | 6 +- 34 files changed, 368 insertions(+), 325 deletions(-) diff --git a/core/sail/api/src/main/java/org/eclipse/rdf4j/sail/helpers/AbstractSailConnection.java b/core/sail/api/src/main/java/org/eclipse/rdf4j/sail/helpers/AbstractSailConnection.java index 3dc34d019ad..9d61639e455 100644 --- a/core/sail/api/src/main/java/org/eclipse/rdf4j/sail/helpers/AbstractSailConnection.java +++ b/core/sail/api/src/main/java/org/eclipse/rdf4j/sail/helpers/AbstractSailConnection.java @@ -955,30 +955,26 @@ private void forceCloseActiveOperations() throws SailException { if (debugEnabled) { - List toThrowExceptions = new ArrayList<>(); - var activeIterationsCopy = new IdentityHashMap<>(activeIterationsDebug); activeIterationsDebug.clear(); - for (var entry : activeIterationsCopy.entrySet()) { - var ci = entry.getKey(); - Throwable creatorTrace = entry.getValue(); - - try { - if (creatorTrace != null) { - logger.warn("Forced closing of unclosed iteration that was created in:", creatorTrace); + if (!activeIterationsCopy.isEmpty()) { + for (var entry : activeIterationsCopy.entrySet()) { + try { + logger.warn("Unclosed iteration", entry.getValue()); + entry.getKey().close(); + } catch (Exception ignored) { + logger.warn("Exception occurred while closing unclosed iterations.", ignored); } - ci.close(); - } catch (SailException e) { - toThrowExceptions.add(e); - } catch (Exception e) { - toThrowExceptions.add(new SailException(e)); } - } - if (!toThrowExceptions.isEmpty()) { - throw toThrowExceptions.get(0); + var entry = activeIterationsCopy.entrySet().stream().findAny().orElseThrow(); + + throw new SailException( + "Connection closed before all iterations were closed: " + entry.getKey().toString(), + entry.getValue()); } + } } diff --git a/core/sail/nativerdf/src/main/java/org/eclipse/rdf4j/sail/nativerdf/btree/RangeIterator.java b/core/sail/nativerdf/src/main/java/org/eclipse/rdf4j/sail/nativerdf/btree/RangeIterator.java index 081a0f54472..b0875249683 100644 --- a/core/sail/nativerdf/src/main/java/org/eclipse/rdf4j/sail/nativerdf/btree/RangeIterator.java +++ b/core/sail/nativerdf/src/main/java/org/eclipse/rdf4j/sail/nativerdf/btree/RangeIterator.java @@ -15,9 +15,6 @@ class RangeIterator implements RecordIterator, NodeListener { - /** - * - */ private final BTree tree; private final byte[] searchKey; @@ -46,6 +43,8 @@ class RangeIterator implements RecordIterator, NodeListener { private volatile int currentIdx; + private volatile boolean closed = false; + public RangeIterator(BTree tree, byte[] searchKey, byte[] searchMask, byte[] minValue, byte[] maxValue) { this.tree = tree; this.searchKey = searchKey; @@ -164,16 +163,23 @@ public void set(byte[] value) { } @Override - public synchronized void close() throws IOException { - tree.btreeLock.readLock().lock(); - try { - while (popStacks()) { + public void close() throws IOException { + if (!closed) { + synchronized (this) { + if (!closed) { + closed = true; + tree.btreeLock.readLock().lock(); + try { + while (popStacks()) { + } + + assert parentNodeStack.isEmpty(); + assert parentIndexStack.isEmpty(); + } finally { + tree.btreeLock.readLock().unlock(); + } + } } - - assert parentNodeStack.isEmpty(); - assert parentIndexStack.isEmpty(); - } finally { - tree.btreeLock.readLock().unlock(); } } @@ -185,7 +191,7 @@ private void pushStacks(Node newChildNode) { currentIdx = 0; } - private boolean popStacks() throws IOException { + private synchronized boolean popStacks() throws IOException { Node nextCurrentNode = currentNode; if (nextCurrentNode == null) { // There's nothing to pop diff --git a/testsuites/repository/src/main/java/org/eclipse/rdf4j/testsuite/repository/TupleQueryResultTest.java b/testsuites/repository/src/main/java/org/eclipse/rdf4j/testsuite/repository/TupleQueryResultTest.java index d49a742b9d5..e270c359e8d 100644 --- a/testsuites/repository/src/main/java/org/eclipse/rdf4j/testsuite/repository/TupleQueryResultTest.java +++ b/testsuites/repository/src/main/java/org/eclipse/rdf4j/testsuite/repository/TupleQueryResultTest.java @@ -8,6 +8,7 @@ package org.eclipse.rdf4j.testsuite.repository; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -144,7 +145,7 @@ public void testIterator() { count++; } - Assertions.assertTrue(count > 1, "query should have multiple results."); + assertTrue(count > 1, "query should have multiple results."); } } @@ -161,7 +162,7 @@ public void testCountMatchesAllSelect() { try (TupleQueryResult result = con.prepareTupleQuery("SELECT * WHERE {?s ?p ?o}").evaluate()) { long size = con.size(); for (int i = 0; i < size; i++) { - Assertions.assertTrue(result.hasNext()); + assertTrue(result.hasNext()); BindingSet next = result.next(); Assertions.assertNotNull(next); } @@ -236,6 +237,10 @@ public void testNotClosingResult() { for (int i = 0; i < 100; i++) { try (RepositoryConnection repCon = rep.getConnection()) { evaluateQueryWithoutClosing(repCon); + } catch (SailException e) { + assertTrue(e.toString() + .startsWith( + "org.eclipse.rdf4j.sail.SailException: Connection closed before all iterations were closed: org.eclipse.rdf4j.sail.helpers.SailBaseIteration@")); } } } diff --git a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/FedXConnection.java b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/FedXConnection.java index a9fa15d9276..8ccdc03c818 100644 --- a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/FedXConnection.java +++ b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/FedXConnection.java @@ -61,11 +61,11 @@ * Prior to evaluation various optimizations are performed, see * {@link org.eclipse.rdf4j.federated.optimizer.FedXOptimizer} for further details. *

- * + *

* Since 4.0 FedX supports write operations using the supplied {@link WriteStrategy}, e.g. by writing to a designated * federation member. Note: the {@link WriteStrategy} is initialized lazily upon first access to a write operation, see * {@link #getWriteStrategyInternal()}. - * + *

* Implementation notes: - not all methods are implemented as of now * * @author Andreas Schwarte @@ -101,45 +101,42 @@ protected CloseableIteration eva TupleExpr query, Dataset dataset, BindingSet bindings, boolean includeInferred) throws SailException { - final TupleExpr _orgQuery = query; + final TupleExpr originalQuery = query; FederationEvalStrategy strategy = federationContext.createStrategy(dataset); long start = 0; - QueryInfo queryInfo = null; - if (true) { - String queryString = getOriginalQueryString(bindings); - if (queryString == null) { - log.warn("Query string is null. Please check your FedX setup."); - } - queryInfo = new QueryInfo(queryString, getOriginalBaseURI(bindings), getOriginalQueryType(bindings), - getOriginalMaxExecutionTime(bindings), includeInferred, federationContext, strategy, dataset); - - // check if we have pass-through result handler information for single source queries - if (query instanceof PassThroughTupleExpr) { - PassThroughTupleExpr node = ((PassThroughTupleExpr) query); - queryInfo.setResultHandler(node.getResultHandler()); - query = node.getExpr(); - } + String queryString = getOriginalQueryString(bindings); + if (queryString == null) { + log.warn("Query string is null. Please check your FedX setup."); + } + QueryInfo queryInfo = new QueryInfo(queryString, getOriginalBaseURI(bindings), getOriginalQueryType(bindings), + getOriginalMaxExecutionTime(bindings), includeInferred, federationContext, strategy, dataset); + + // check if we have pass-through result handler information for single source queries + if (query instanceof PassThroughTupleExpr) { + PassThroughTupleExpr node = ((PassThroughTupleExpr) query); + queryInfo.setResultHandler(node.getResultHandler()); + query = node.getExpr(); + } - if (log.isDebugEnabled()) { - log.debug("Optimization start (Query: " + queryInfo.getQueryID() + ")"); - start = System.currentTimeMillis(); - } - try { - federationContext.getMonitoringService().monitorQuery(queryInfo); - FederationEvaluationStatistics stats = new FederationEvaluationStatistics(queryInfo, dataset); - query = strategy.optimize(query, stats, bindings); - } catch (Exception e) { - log.warn("Exception occured during optimization (Query: " + queryInfo.getQueryID() + "): " - + e.getMessage()); - log.debug("Details: ", e); - throw new SailException(e); - } - if (log.isDebugEnabled()) { - log.debug(("Optimization duration: " + ((System.currentTimeMillis() - start))) + " (Query: " - + queryInfo.getQueryID() + ")"); - } + if (log.isDebugEnabled()) { + log.debug("Optimization start (Query: " + queryInfo.getQueryID() + ")"); + start = System.currentTimeMillis(); + } + try { + federationContext.getMonitoringService().monitorQuery(queryInfo); + FederationEvaluationStatistics stats = new FederationEvaluationStatistics(queryInfo, dataset); + query = strategy.optimize(query, stats, bindings); + } catch (Exception e) { + log.warn("Exception occured during optimization (Query: " + queryInfo.getQueryID() + "): " + + e.getMessage()); + log.debug("Details: ", e); + throw new SailException(e); + } + if (log.isDebugEnabled()) { + log.debug(("Optimization duration: " + ((System.currentTimeMillis() - start))) + " (Query: " + + queryInfo.getQueryID() + ")"); } // log the optimized query plan, if Config#isLogQueryPlan(), otherwise void operation @@ -165,17 +162,26 @@ protected CloseableIteration eva }); queryBindings = actualQueryBindings; } - CloseableIteration res = strategy.evaluate(query, - queryBindings); - - // mark the query as PassedThrough, such that outer result handlers are aware of this - // Note: for SingleSourceQuery (i.e. where we use pass through) res is explicitly - // EmptyIteration. Thus we can use it as indicator - if (_orgQuery instanceof PassThroughTupleExpr && res instanceof EmptyIteration) { - ((PassThroughTupleExpr) _orgQuery).setPassedThrough(true); + + CloseableIteration res = null; + try { + res = strategy.evaluate(query, queryBindings); + + // mark the query as PassedThrough, such that outer result handlers are aware of this + // Note: for SingleSourceQuery (i.e. where we use pass through) res is explicitly + // EmptyIteration. Thus we can use it as indicator + if (originalQuery instanceof PassThroughTupleExpr && res instanceof EmptyIteration) { + ((PassThroughTupleExpr) originalQuery).setPassedThrough(true); + } + res = new StopRemainingExecutionsOnCloseIteration(res, queryInfo); + return res; + } catch (Throwable t) { + if (res != null) { + res.close(); + } + throw t; } - res = new StopRemainingExecutionsOnCloseIteration(res, queryInfo); - return res; + } catch (QueryEvaluationException e) { throw new SailException(e); } @@ -230,12 +236,11 @@ protected void commitInternal() throws SailException { protected CloseableIteration getContextIDsInternal() throws SailException { FederationEvalStrategy strategy = federationContext.createStrategy(new SimpleDataset()); - final WorkerUnionBase union = new SynchronousWorkerUnion<>( - new QueryInfo("getContextIDsInternal", null, QueryType.UNKNOWN, 0, - federationContext.getConfig().getIncludeInferredDefault(), federationContext, strategy, - new SimpleDataset())); + WorkerUnionBase union = new SynchronousWorkerUnion<>(new QueryInfo("getContextIDsInternal", null, + QueryType.UNKNOWN, 0, federationContext.getConfig().getIncludeInferredDefault(), federationContext, + strategy, new SimpleDataset())); - for (final Endpoint e : federation.getMembers()) { + for (Endpoint e : federation.getMembers()) { union.addTask(new ParallelTask<>() { @Override public CloseableIteration performTask() throws Exception { @@ -286,9 +291,8 @@ protected CloseableIteration getNamespacesIn } @Override - protected CloseableIteration getStatementsInternal( - Resource subj, IRI pred, Value obj, final boolean includeInferred, - final Resource... contexts) throws SailException { + protected CloseableIteration getStatementsInternal(Resource subj, IRI pred, + Value obj, boolean includeInferred, Resource... contexts) throws SailException { try { Dataset dataset = new SimpleDataset(); @@ -296,14 +300,22 @@ protected CloseableIteration getStatementsIn QueryInfo queryInfo = new QueryInfo(subj, pred, obj, 0, includeInferred, federationContext, strategy, dataset); federationContext.getMonitoringService().monitorQuery(queryInfo); - CloseableIteration res = strategy.getStatements(queryInfo, subj, pred, - obj, contexts); - return new ExceptionConvertingIteration<>(res) { - @Override - protected SailException convert(Exception e) { - return new SailException(e); + CloseableIteration res = null; + try { + res = strategy.getStatements(queryInfo, subj, pred, obj, contexts); + return new ExceptionConvertingIteration<>(res) { + @Override + protected SailException convert(Exception e) { + return new SailException(e); + } + }; + } catch (Throwable t) { + if (res != null) { + res.close(); } - }; + throw t; + } + } catch (RuntimeException e) { throw e; } catch (Exception e) { @@ -365,7 +377,7 @@ protected long sizeInternal(Resource... contexts) throws SailException { } } if (errorEndpoints.size() > 0) { - throw new SailException("Could not determine size for members " + errorEndpoints.toString() + + throw new SailException("Could not determine size for members " + errorEndpoints + "(Supported for NativeStore and RemoteRepository only). Computed size: " + size); } return size; @@ -448,7 +460,6 @@ private static int getOriginalMaxExecutionTime(BindingSet b) { * for the constructor call. * * @author as - * */ protected static class SailBaseDefaultImpl extends AbstractSail { diff --git a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/algebra/FedXStatementPattern.java b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/algebra/FedXStatementPattern.java index 97ddf4e0f07..6b0056d2550 100644 --- a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/algebra/FedXStatementPattern.java +++ b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/algebra/FedXStatementPattern.java @@ -8,7 +8,6 @@ package org.eclipse.rdf4j.federated.algebra; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.List; diff --git a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/SailTripleSource.java b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/SailTripleSource.java index e02ab138515..e173005b812 100644 --- a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/SailTripleSource.java +++ b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/SailTripleSource.java @@ -72,24 +72,30 @@ public CloseableIteration getStatements( RepositoryResult repoResult = conn.getStatements((Resource) subjValue, (IRI) predValue, objValue, queryInfo.getIncludeInferred(), FedXUtil.toContexts(stmt, queryInfo.getDataset())); - // XXX implementation remark and TODO taken from Sesame - // The same variable might have been used multiple times in this - // StatementPattern, verify value equality in those cases. - - // an iterator that converts the statements to var bindings - resultHolder.set(new StatementConversionIteration(repoResult, bindings, stmt)); - - // if filter is set, apply it - if (filterExpr != null) { - FilteringIteration filteredRes = new FilteringIteration(filterExpr, resultHolder.get(), - queryInfo.getStrategy()); - if (!filteredRes.hasNext()) { - filteredRes.close(); - resultHolder.set(new EmptyIteration<>()); - return; + try { + // XXX implementation remark and TODO taken from Sesame + // The same variable might have been used multiple times in this + // StatementPattern, verify value equality in those cases. + + // an iterator that converts the statements to var bindings + resultHolder.set(new StatementConversionIteration(repoResult, bindings, stmt)); + + // if filter is set, apply it + if (filterExpr != null) { + FilteringIteration filteredRes = new FilteringIteration(filterExpr, resultHolder.get(), + queryInfo.getStrategy()); + if (!filteredRes.hasNext()) { + filteredRes.close(); + resultHolder.set(new EmptyIteration<>()); + return; + } + resultHolder.set(filteredRes); } - resultHolder.set(filteredRes); + } catch (Throwable t) { + repoResult.close(); + throw t; } + }); } diff --git a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/concurrent/FedXQueueCursor.java b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/concurrent/FedXQueueCursor.java index a957b50d437..c36c06c0b84 100644 --- a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/concurrent/FedXQueueCursor.java +++ b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/concurrent/FedXQueueCursor.java @@ -14,6 +14,7 @@ import org.eclipse.rdf4j.common.iteration.CloseableIteration; import org.eclipse.rdf4j.query.QueryEvaluationException; import org.eclipse.rdf4j.query.impl.QueueCursor; +import org.eclipse.rdf4j.sail.SailException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,10 +22,8 @@ * Specialized variants of {@link QueueCursor} which avoids converting any exception if it is already of * type{@link QueryEvaluationException}. * - * - * @author Andreas Schwarte - * * @param + * @author Andreas Schwarte */ public class FedXQueueCursor extends QueueCursor> { @@ -61,25 +60,36 @@ protected QueryEvaluationException convert(Exception e) { public void handleClose() throws QueryEvaluationException { try { + Throwable throwable = null; + // consume all remaining elements from the queue and make sure to close them // Note: unfortunately we cannot access "afterLast" of the super class // => thus have to make a check whether the polled object is actually a // closable iteration - Object take = queueRef.poll(); - while (take != null) { - if (take instanceof CloseableIteration) { - @SuppressWarnings("unchecked") - CloseableIteration closable = (CloseableIteration) take; - try { - log.trace("Attempting to close non consumed inner iteration."); - closable.close(); - } catch (Throwable t) { - log.trace("Failed to close inner iteration: ", t); + while (!queueRef.isEmpty()) { + try { + Object take = queueRef.poll(); + if (take instanceof CloseableIteration) { + ((CloseableIteration) take).close(); } + } catch (Throwable t) { + if (throwable != null) { + t.addSuppressed(throwable); + } + throwable = t; } - take = queueRef.poll(); } done(); // re-add after-last + + if (throwable != null) { + if (throwable instanceof RuntimeException) { + throw ((RuntimeException) throwable); + } + if (throwable instanceof Error) { + throw ((Error) throwable); + } + throw new SailException(throwable); + } } finally { super.handleClose(); } diff --git a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/CloseDependentConnectionIteration.java b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/CloseDependentConnectionIteration.java index 74c499fd3e4..71d9af71291 100644 --- a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/CloseDependentConnectionIteration.java +++ b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/CloseDependentConnectionIteration.java @@ -18,20 +18,16 @@ * A wrapping iteration that attempts to close the dependent {@link RepositoryConnection} after consumption. * * @author Andreas Schwarte - * */ -public class CloseDependentConnectionIteration - extends AbstractCloseableIteration { +public class CloseDependentConnectionIteration extends AbstractCloseableIteration { - private static final Logger log = LoggerFactory.getLogger(CloseDependentConnectionIteration.class); + private static final Logger logger = LoggerFactory.getLogger(CloseDependentConnectionIteration.class); protected final CloseableIteration inner; protected final RepositoryConnection dependentConn; - public CloseDependentConnectionIteration( - CloseableIteration inner, + public CloseDependentConnectionIteration(CloseableIteration inner, RepositoryConnection dependentConn) { - super(); this.inner = inner; this.dependentConn = dependentConn; } @@ -41,15 +37,11 @@ public boolean hasNext() throws QueryEvaluationException { try { boolean res = inner.hasNext(); if (!res) { - try { - dependentConn.close(); - } catch (Throwable ignore) { - log.trace("Failed to close dependent connection:", ignore); - } + close(); } return res; } catch (Throwable t) { - dependentConn.close(); + close(); throw t; } } @@ -59,14 +51,19 @@ public T next() throws QueryEvaluationException { try { return inner.next(); } catch (Throwable t) { - dependentConn.close(); + close(); throw t; } } @Override public void remove() throws QueryEvaluationException { - inner.remove(); + try { + inner.remove(); + } catch (Throwable t) { + close(); + throw t; + } } @Override @@ -74,11 +71,7 @@ protected void handleClose() throws QueryEvaluationException { try { inner.close(); } finally { - try { - super.handleClose(); - } finally { - dependentConn.close(); - } + dependentConn.close(); } } diff --git a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/ConsumingIteration.java b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/ConsumingIteration.java index c6312d54e34..3020b8205e9 100644 --- a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/ConsumingIteration.java +++ b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/ConsumingIteration.java @@ -11,7 +11,6 @@ import java.util.NoSuchElementException; import org.eclipse.rdf4j.common.iteration.CloseableIteration; -import org.eclipse.rdf4j.common.iteration.Iterations; import org.eclipse.rdf4j.query.BindingSet; import org.eclipse.rdf4j.query.QueryEvaluationException; @@ -94,7 +93,7 @@ public void remove() throws QueryEvaluationException { @Override public void close() throws QueryEvaluationException { - Iterations.closeCloseable(innerIter); + innerIter.close(); } } diff --git a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/FederatedDescribeIteration.java b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/FederatedDescribeIteration.java index 04d199377cd..13dfbfcf410 100644 --- a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/FederatedDescribeIteration.java +++ b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/FederatedDescribeIteration.java @@ -81,7 +81,7 @@ protected CloseableIteration createNextIte // we need to make sure that subject or object are added to the binding set // Note: FedX uses prepared SELECT queries to evaluate a statement pattern and // thus does not add bound values to the result bindingset - return new ConvertingIteration(res) { + return new ConvertingIteration<>(res) { @Override protected BindingSet convert(BindingSet sourceObject) throws QueryEvaluationException { @@ -96,4 +96,13 @@ protected BindingSet convert(BindingSet sourceObject) throws QueryEvaluationExce } }; } + + @Override + protected void handleClose() throws QueryEvaluationException { + try { + super.handleClose(); + } finally { + queryInfo.close(); + } + } } diff --git a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/GraphToBindingSetConversionIteration.java b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/GraphToBindingSetConversionIteration.java index 18eec389915..3366bf17cba 100644 --- a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/GraphToBindingSetConversionIteration.java +++ b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/GraphToBindingSetConversionIteration.java @@ -68,4 +68,8 @@ protected BindingSet convert(Statement st) { return result; } + @Override + protected void handleClose() throws QueryEvaluationException { + graph.close(); + } } diff --git a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/IndependentJoingroupBindingsIteration.java b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/IndependentJoingroupBindingsIteration.java index 1442d37baa7..4b27eb9b021 100644 --- a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/IndependentJoingroupBindingsIteration.java +++ b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/IndependentJoingroupBindingsIteration.java @@ -93,4 +93,12 @@ protected ArrayList computeResult() throws QueryEvaluationException return res; } + @Override + protected void handleClose() throws QueryEvaluationException { + try { + super.handleClose(); + } finally { + iter.close(); + } + } } diff --git a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/IndependentJoingroupBindingsIteration2.java b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/IndependentJoingroupBindingsIteration2.java index 403455021fc..c93cb536f9a 100644 --- a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/IndependentJoingroupBindingsIteration2.java +++ b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/IndependentJoingroupBindingsIteration2.java @@ -119,6 +119,15 @@ protected ArrayList computeResult() throws QueryEvaluationException return res; } + @Override + protected void handleClose() throws QueryEvaluationException { + try { + super.handleClose(); + } finally { + iter.close(); + } + } + protected class BindingInfo { public final String name; public final int bindingsIdx; diff --git a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/IndependentJoingroupBindingsIteration3.java b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/IndependentJoingroupBindingsIteration3.java index af00a9b5c17..624922ac69c 100644 --- a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/IndependentJoingroupBindingsIteration3.java +++ b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/IndependentJoingroupBindingsIteration3.java @@ -130,6 +130,15 @@ protected ArrayList computeResult() throws QueryEvaluationException return res; } + @Override + protected void handleClose() throws QueryEvaluationException { + try { + super.handleClose(); + } finally { + iter.close(); + } + } + protected class BindingInfo { public final String name; public final int bindingsIdx; diff --git a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/QueryResultIteration.java b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/QueryResultIteration.java index 11825e0019c..6c5284a9581 100644 --- a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/QueryResultIteration.java +++ b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/QueryResultIteration.java @@ -76,8 +76,15 @@ public void remove() throws QueryEvaluationException { @Override protected void handleClose() throws QueryEvaluationException { - inner.close(); - abortQuery(); + try { + inner.close(); + } finally { + try { + abortQuery(); + } finally { + queryInfo.close(); + } + } } /** diff --git a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/StopRemainingExecutionsOnCloseIteration.java b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/StopRemainingExecutionsOnCloseIteration.java index eb7c30e710f..2da9ec26159 100644 --- a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/StopRemainingExecutionsOnCloseIteration.java +++ b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/iterator/StopRemainingExecutionsOnCloseIteration.java @@ -25,7 +25,6 @@ * @author Andreas Schwarte * @see QueryInfo#close() * @see ParallelTask#cancel() - * */ public class StopRemainingExecutionsOnCloseIteration extends AbstractCloseableIteration { @@ -58,12 +57,16 @@ public void remove() throws QueryEvaluationException { @Override protected void handleClose() throws QueryEvaluationException { try { - inner.close(); - } finally { super.handleClose(); - // make sure to close all scheduled / running parallel executions - // (e.g. if the query result is not fully consumed) - queryInfo.close(); + } finally { + try { + inner.close(); + } finally { + // make sure to close all scheduled / running parallel executions + // (e.g. if the query result is not fully consumed) + queryInfo.close(); + } + } } diff --git a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/structures/QueryInfo.java b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/structures/QueryInfo.java index 13b3885078e..1b2dc24002f 100644 --- a/tools/federation/src/main/java/org/eclipse/rdf4j/federated/structures/QueryInfo.java +++ b/tools/federation/src/main/java/org/eclipse/rdf4j/federated/structures/QueryInfo.java @@ -31,11 +31,10 @@ /** * Structure to maintain query information during evaluation, is attached to algebra nodes. Each instance is uniquely * attached to the query. - * + *

* The queryId can be used to abort tasks belonging to a particular evaluation. * * @author Andreas Schwarte - * */ public class QueryInfo { @@ -64,7 +63,6 @@ public class QueryInfo { protected Set> scheduledSubtasks = ConcurrentHashMap.newKeySet(); /** - * * @param query * @param queryType * @param maxExecutionTime the maximum explicit query time in seconds, if 0 use @@ -129,7 +127,6 @@ public String getBaseURI() { } /** - * * @return the {@link FederationEvalStrategy} active in the current query context */ public FederationEvalStrategy getStrategy() { @@ -137,7 +134,6 @@ public FederationEvalStrategy getStrategy() { } /** - * * @return the {@link FederationContext} in which this query is executed */ public FederationContext getFederationContext() { @@ -145,7 +141,6 @@ public FederationContext getFederationContext() { } /** - * * @return the maximum remaining time in ms until the query runs into a timeout. If negative, timeout has been * reached */ @@ -201,7 +196,6 @@ public void setResultHandler(TupleQueryResultHandler resultHandler) { /** * Mark the query as aborted and abort all scheduled (future) tasks known at this point in time. Also do not accept * any new scheduled tasks - * */ public synchronized void abort() { if (done) { @@ -215,7 +209,6 @@ public synchronized void abort() { /** * Close this query. If exists, all scheduled (future) tasks known at this point in time are aborted. Also do not * accept any new scheduled tasks - * */ public synchronized void close() { @@ -232,11 +225,27 @@ public synchronized void close() { */ protected void abortScheduledTasks() { + Throwable throwable = null; + for (ParallelTask task : scheduledSubtasks) { - task.cancel(); + try { + task.cancel(); + } catch (Throwable t) { + if (throwable != null) { + t.addSuppressed(throwable); + } + throwable = t; + } } scheduledSubtasks.clear(); + + if (throwable != null) { + if (throwable instanceof RuntimeException) { + throw ((RuntimeException) throwable); + } + throw ((Error) throwable); + } } @Override @@ -260,13 +269,9 @@ public boolean equals(Object obj) { } QueryInfo other = (QueryInfo) obj; if (queryID == null) { - if (other.queryID != null) { - return false; - } - } else if (!queryID.equals(other.queryID)) { - return false; - } - return true; + return other.queryID == null; + } else + return queryID.equals(other.queryID); } } diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/BasicTests.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/BasicTests.java index 92bc47c6dcf..d522d69f097 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/BasicTests.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/BasicTests.java @@ -39,49 +39,49 @@ public class BasicTests extends SPARQLBaseTest { @Test public void test1() throws Exception { prepareTest(Arrays.asList("/tests/basic/data01endpoint1.ttl", "/tests/basic/data01endpoint2.ttl")); - execute("/tests/basic/query01.rq", "/tests/basic/query01.srx", false); + execute("/tests/basic/query01.rq", "/tests/basic/query01.srx", false, true); } @Test public void test2() throws Exception { /* test a basic Construct query retrieving all triples */ prepareTest(Arrays.asList("/tests/basic/data01endpoint1.ttl", "/tests/basic/data01endpoint2.ttl")); - execute("/tests/basic/query02.rq", "/tests/basic/query02.ttl", false); + execute("/tests/basic/query02.rq", "/tests/basic/query02.ttl", false, true); } @Test public void testBooleanTrueSingleSource() throws Exception { /* test a basic boolean query (result true) */ prepareTest(Arrays.asList("/tests/basic/data01endpoint1.ttl", "/tests/basic/data01endpoint2.ttl")); - execute("/tests/basic/query03.rq", "/tests/basic/query03.srx", false); + execute("/tests/basic/query03.rq", "/tests/basic/query03.srx", false, true); } @Test public void testBooleanTrueMultipleSource() throws Exception { /* test a basic boolean query (result true) */ prepareTest(Arrays.asList("/tests/basic/data01endpoint1.ttl", "/tests/basic/data01endpoint2.ttl")); - execute("/tests/basic/query03a.rq", "/tests/basic/query03.srx", false); + execute("/tests/basic/query03a.rq", "/tests/basic/query03.srx", false, true); } @Test public void testBooleanFalse() throws Exception { /* test a basic boolean query (result false) */ prepareTest(Arrays.asList("/tests/basic/data01endpoint1.ttl", "/tests/basic/data01endpoint2.ttl")); - execute("/tests/basic/query04.rq", "/tests/basic/query04.srx", false); + execute("/tests/basic/query04.rq", "/tests/basic/query04.srx", false, true); } @Test public void testSingleSourceSelect() throws Exception { /* test a single source select query */ prepareTest(Arrays.asList("/tests/basic/data01endpoint1.ttl", "/tests/basic/data01endpoint2.ttl")); - execute("/tests/basic/query_singleSource01.rq", "/tests/basic/query_singleSource01.srx", false); + execute("/tests/basic/query_singleSource01.rq", "/tests/basic/query_singleSource01.srx", false, true); } @Test public void testSingleSourceConstruct() throws Exception { /* test a single source construct */ prepareTest(Arrays.asList("/tests/basic/data01endpoint1.ttl", "/tests/basic/data01endpoint2.ttl")); - execute("/tests/basic/query_singleSource02.rq", "/tests/basic/query_singleSource02.ttl", false); + execute("/tests/basic/query_singleSource02.rq", "/tests/basic/query_singleSource02.ttl", false, true); } @Test @@ -95,28 +95,28 @@ public void testGetStatements() throws Exception { public void testValuesClause() throws Exception { /* test query with values clause */ prepareTest(Arrays.asList("/tests/basic/data01endpoint1.ttl", "/tests/basic/data01endpoint2.ttl")); - execute("/tests/basic/query_values.rq", "/tests/basic/query_values.srx", false); + execute("/tests/basic/query_values.rq", "/tests/basic/query_values.srx", false, true); } @Test public void testQuotes() throws Exception { /* test query with new line in literal */ prepareTest(Arrays.asList("/tests/basic/data01endpoint1.ttl", "/tests/basic/data01endpoint3.ttl")); - execute("/tests/basic/query_quotes.rq", "/tests/basic/query_quotes.srx", false); + execute("/tests/basic/query_quotes.rq", "/tests/basic/query_quotes.srx", false, true); } @Test public void testQuotesDatatype() throws Exception { /* test query with new line in triple quotes and datatype */ prepareTest(Arrays.asList("/tests/basic/data01endpoint1.ttl", "/tests/basic/data01endpoint3.ttl")); - execute("/tests/basic/query_quotes_datatype.rq", "/tests/basic/query_quotes_datatype.srx", false); + execute("/tests/basic/query_quotes_datatype.rq", "/tests/basic/query_quotes_datatype.srx", false, true); } @Test public void testLanguageTag() throws Exception { /* test query with a language tag */ prepareTest(Arrays.asList("/tests/basic/data01endpoint1.ttl", "/tests/basic/data01endpoint4.ttl")); - execute("/tests/basic/query_lang.rq", "/tests/basic/query_lang.srx", false); + execute("/tests/basic/query_lang.rq", "/tests/basic/query_lang.srx", false, true); } @Test @@ -124,7 +124,7 @@ public void testBindClause() throws Exception { /* test query with bind clause */ prepareTest(Arrays.asList("/tests/basic/data01endpoint1.ttl", "/tests/basic/data01endpoint2.ttl")); - execute("/tests/basic/query_bind.rq", "/tests/basic/query_bind.srx", false); + execute("/tests/basic/query_bind.rq", "/tests/basic/query_bind.srx", false, true); } @Test @@ -137,39 +137,44 @@ public void testFederationSubSetQuery() throws Exception { try (RepositoryConnection conn = fedxRule.getRepository().getConnection()) { TupleQuery tq = conn .prepareTupleQuery("SELECT ?person WHERE { ?person a }"); - TupleQueryResult result = tq.evaluate(); - - TupleQueryResult expected = tupleQueryResultBuilder(List.of("person")) - .add(List.of(vf.createIRI(ns1, "Person_1"))) - .add(List.of(vf.createIRI(ns1, "Person_2"))) - .add(List.of(vf.createIRI(ns1, "Person_3"))) - .add(List.of(vf.createIRI(ns1, "Person_4"))) - .add(List.of(vf.createIRI(ns1, "Person_5"))) - .add(List.of(vf.createIRI(ns2, "Person_6"))) - .add(List.of(vf.createIRI(ns2, "Person_7"))) - .add(List.of(vf.createIRI(ns2, "Person_8"))) - .add(List.of(vf.createIRI(ns2, "Person_9"))) - .add(List.of(vf.createIRI(ns2, "Person_10"))) - .build(); - - compareTupleQueryResults(result, expected, false); + + try (TupleQueryResult result = tq.evaluate()) { + + try (TupleQueryResult expected = tupleQueryResultBuilder(List.of("person")) + .add(List.of(vf.createIRI(ns1, "Person_1"))) + .add(List.of(vf.createIRI(ns1, "Person_2"))) + .add(List.of(vf.createIRI(ns1, "Person_3"))) + .add(List.of(vf.createIRI(ns1, "Person_4"))) + .add(List.of(vf.createIRI(ns1, "Person_5"))) + .add(List.of(vf.createIRI(ns2, "Person_6"))) + .add(List.of(vf.createIRI(ns2, "Person_7"))) + .add(List.of(vf.createIRI(ns2, "Person_8"))) + .add(List.of(vf.createIRI(ns2, "Person_9"))) + .add(List.of(vf.createIRI(ns2, "Person_10"))) + .build()) { + + compareTupleQueryResults(result, expected, false); + } + } // evaluate against ep 1 and ep 3 only FedXDataset fedxDataset = new FedXDataset(tq.getDataset()); fedxDataset.addEndpoint(endpoints.get(0).getId()); fedxDataset.addEndpoint(endpoints.get(2).getId()); tq.setDataset(fedxDataset); - result = tq.evaluate(); + try (TupleQueryResult result = tq.evaluate()) { - expected = tupleQueryResultBuilder(List.of("person")) - .add(List.of(vf.createIRI(ns1, "Person_1"))) - .add(List.of(vf.createIRI(ns1, "Person_2"))) - .add(List.of(vf.createIRI(ns1, "Person_3"))) - .add(List.of(vf.createIRI(ns1, "Person_4"))) - .add(List.of(vf.createIRI(ns1, "Person_5"))) - .build(); + try (TupleQueryResult expected = tupleQueryResultBuilder(List.of("person")) + .add(List.of(vf.createIRI(ns1, "Person_1"))) + .add(List.of(vf.createIRI(ns1, "Person_2"))) + .add(List.of(vf.createIRI(ns1, "Person_3"))) + .add(List.of(vf.createIRI(ns1, "Person_4"))) + .add(List.of(vf.createIRI(ns1, "Person_5"))) + .build()) { - compareTupleQueryResults(result, expected, false); + compareTupleQueryResults(result, expected, false); + } + } } } @@ -458,7 +463,7 @@ public void testDescribe_SingleResource() throws Exception { /* test DESCRIBE query for a single resource (data in two members) */ prepareTest(Arrays.asList("/tests/basic/data01endpoint1.ttl", "/tests/basic/data01endpoint2.ttl")); - execute("/tests/basic/query_describe1.rq", "/tests/basic/query_describe1.ttl", false); + execute("/tests/basic/query_describe1.rq", "/tests/basic/query_describe1.ttl", false, true); } @Test @@ -466,6 +471,6 @@ public void testDescribe_MultipleResources() throws Exception { /* test DESCRIBE query for multiple resources (data in two members) */ prepareTest(Arrays.asList("/tests/basic/data01endpoint1.ttl", "/tests/basic/data01endpoint2.ttl")); - execute("/tests/basic/query_describe2.rq", "/tests/basic/query_describe2.ttl", false); + execute("/tests/basic/query_describe2.rq", "/tests/basic/query_describe2.ttl", false, true); } } diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/BoundJoinTests.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/BoundJoinTests.java index 90f07de0723..a8b08e33844 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/BoundJoinTests.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/BoundJoinTests.java @@ -19,14 +19,14 @@ public class BoundJoinTests extends SPARQLBaseTest { public void testSimpleUnion() throws Exception { /* test a simple bound join */ prepareTest(Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl")); - execute("/tests/boundjoin/query01.rq", "/tests/boundjoin/query01.srx", false); + execute("/tests/boundjoin/query01.rq", "/tests/boundjoin/query01.srx", false, true); } @Test public void testSimpleValues() throws Exception { /* test with VALUES clause based bound join */ prepareTest(Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl")); - execute("/tests/boundjoin/query01.rq", "/tests/boundjoin/query01.srx", false); + execute("/tests/boundjoin/query01.rq", "/tests/boundjoin/query01.srx", false, true); } @Test @@ -36,7 +36,7 @@ public void testBoundJoin_FailingEndpoint() throws Exception { repoSettings(2).setFailAfter(5); Assertions.assertThrows(QueryEvaluationException.class, () -> { - execute("/tests/boundjoin/query01.rq", "/tests/boundjoin/query01.srx", false); + execute("/tests/boundjoin/query01.rq", "/tests/boundjoin/query01.srx", false, true); }); } } diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/DistinctTests.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/DistinctTests.java index 932fc6c23f4..9cfb21ce93c 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/DistinctTests.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/DistinctTests.java @@ -16,41 +16,41 @@ public class DistinctTests extends SPARQLBaseTest { @Test public void test1() throws Exception { prepareTest(Arrays.asList("/tests/data/distinctTest.ttl", "/tests/data/distinctTest1.ttl")); - execute("/tests/basic/query_distinct01.rq", "/tests/basic/query_distinct01.srx", false); + execute("/tests/basic/query_distinct01.rq", "/tests/basic/query_distinct01.srx", false, true); } @Test public void test2() throws Exception { /* test more complex structure for distinct */ prepareTest(Arrays.asList("/tests/data/distinctTest02a.ttl", "/tests/data/distinctTest02b.ttl")); - execute("/tests/basic/query_distinct02.rq", "/tests/basic/query_distinct02.srx", false); + execute("/tests/basic/query_distinct02.rq", "/tests/basic/query_distinct02.srx", false, true); } @Test public void test3() throws Exception { /* test for subquery with no projection variables */ prepareTest(Arrays.asList("/tests/data/distinctTest03a.ttl", "/tests/data/distinctTest03b.ttl")); - execute("/tests/basic/query_distinct03.rq", "/tests/basic/query_distinct03.srx", false); + execute("/tests/basic/query_distinct03.rq", "/tests/basic/query_distinct03.srx", false, true); } @Test public void test4() throws Exception { /* test for subquery with Filter */ prepareTest(Arrays.asList("/tests/data/distinctTest03a.ttl", "/tests/data/distinctTest03b.ttl")); - execute("/tests/basic/query_distinct04.rq", "/tests/basic/query_distinct04.srx", false); + execute("/tests/basic/query_distinct04.rq", "/tests/basic/query_distinct04.srx", false, true); } @Test public void test5() throws Exception { /* test for fetching full data: no distinct in subqueries (fixed in FedX 3.0) */ prepareTest(Arrays.asList("/tests/data/distinctTest04a.ttl", "/tests/data/distinctTest04b.ttl")); - execute("/tests/basic/query_distinct05.rq", "/tests/basic/query_distinct05.srx", false); + execute("/tests/basic/query_distinct05.rq", "/tests/basic/query_distinct05.srx", false, true); } @Test public void test5a() throws Exception { /* test for fetching full data: no distinct in subqueries, with DISTINCT (fixed in FedX 3.0) */ prepareTest(Arrays.asList("/tests/data/distinctTest04a.ttl", "/tests/data/distinctTest04b.ttl")); - execute("/tests/basic/query_distinct05a.rq", "/tests/basic/query_distinct05a.srx", false); + execute("/tests/basic/query_distinct05a.rq", "/tests/basic/query_distinct05a.srx", false, true); } } diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXBaseTest.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXBaseTest.java index 6ee86cbf77b..26287828f4c 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXBaseTest.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXBaseTest.java @@ -79,9 +79,10 @@ public static void initLogging() { * @param queryFile * @param expectedResultFile * @param checkOrder + * @param doubleCheckClose double check that closing works as intended even if no results are retrieved * @throws Exception */ - protected void execute(String queryFile, String expectedResultFile, boolean checkOrder) + protected void execute(String queryFile, String expectedResultFile, boolean checkOrder, boolean doubleCheckClose) throws Exception { String queryString = readQueryString(queryFile); @@ -91,19 +92,22 @@ protected void execute(String queryFile, String expectedResultFile, boolean chec if (query instanceof TupleQuery) { // Some query results will automatically close themselves when they are exhausted. To properly test that // query results are closed correctly we need to evaluate the query without retrieving any elements. - ((TupleQuery) query).evaluate().close(); + if (doubleCheckClose) { + ((TupleQuery) query).evaluate().close(); + } try (TupleQueryResult queryResult = ((TupleQuery) query).evaluate()) { - - TupleQueryResult expectedResult = readExpectedTupleQueryResult(expectedResultFile); - - compareTupleQueryResults(queryResult, expectedResult, checkOrder); + try (TupleQueryResult expectedResult = readExpectedTupleQueryResult(expectedResultFile)) { + compareTupleQueryResults(queryResult, expectedResult, checkOrder); + } } } else if (query instanceof GraphQuery) { // Some query results will automatically close themselves when they are exhausted. To properly test that // query results are closed correctly we need to evaluate the query without retrieving any elements. - ((GraphQuery) query).evaluate().close(); + if (doubleCheckClose) { + ((GraphQuery) query).evaluate().close(); + } try (GraphQueryResult gqr = ((GraphQuery) query).evaluate()) { Set queryResult = Iterations.asSet(gqr); @@ -276,6 +280,7 @@ protected void compareTupleQueryResults(TupleQueryResult queryResult, TupleQuery boolean checkOrder) { // Create MutableTupleQueryResult to be able to re-iterate over the // results + MutableTupleQueryResult queryResultTable = new MutableTupleQueryResult(queryResult); MutableTupleQueryResult expectedResultTable = new MutableTupleQueryResult(expectedResult); diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXFactoryTest.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXFactoryTest.java index 869ea125ac1..5cdc6ebdc13 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXFactoryTest.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FedXFactoryTest.java @@ -46,7 +46,7 @@ public void testFederationWithResolver() throws Exception { repo.init(); federationContext = repo.getFederationContext(); try (RepositoryConnection conn = repo.getConnection()) { - execute("/tests/medium/query01.rq", "/tests/medium/query01.srx", false); + execute("/tests/medium/query01.rq", "/tests/medium/query01.srx", false, true); } repo.shutDown(); @@ -75,7 +75,7 @@ public void testFederationWithResolver_writable() throws Exception { federationContext = repo.getFederationContext(); try (RepositoryConnection conn = repo.getConnection()) { - execute("/tests/medium/query01.rq", "/tests/medium/query01.srx", false); + execute("/tests/medium/query01.rq", "/tests/medium/query01.srx", false, true); } repo.shutDown(); @@ -102,7 +102,7 @@ public void testFederationWithResolver_DataConfig() throws Exception { repo.init(); federationContext = repo.getFederationContext(); try (RepositoryConnection conn = repo.getConnection()) { - execute("/tests/medium/query01.rq", "/tests/medium/query01.srx", false); + execute("/tests/medium/query01.rq", "/tests/medium/query01.srx", false, true); } repo.shutDown(); diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FilterTests.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FilterTests.java index e9efaf56ef1..bcfaaa5899b 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FilterTests.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/FilterTests.java @@ -24,46 +24,46 @@ public class FilterTests extends SPARQLBaseTest { public void testSimpleFilter() throws Exception { prepareTest(Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl")); evaluateQueryPlan("/tests/filter/query01.rq", "/tests/filter/query01.qp"); - execute("/tests/filter/query01.rq", "/tests/filter/query01.srx", false); + execute("/tests/filter/query01.rq", "/tests/filter/query01.srx", false, true); } @Test public void testSimpleFilter_ExclusiveStatement() throws Exception { prepareTest(Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl")); evaluateQueryPlan("/tests/filter/query01a.rq", "/tests/filter/query01a.qp"); - execute("/tests/filter/query01a.rq", "/tests/filter/query01a.srx", false); + execute("/tests/filter/query01a.rq", "/tests/filter/query01a.srx", false, true); } @Test public void testOrFilter() throws Exception { prepareTest(Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl")); - execute("/tests/filter/query02.rq", "/tests/filter/query02.srx", false); + execute("/tests/filter/query02.rq", "/tests/filter/query02.srx", false, true); } @Test public void testAndFilter() throws Exception { prepareTest(Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl")); - execute("/tests/filter/query03.rq", "/tests/filter/query03.srx", false); + execute("/tests/filter/query03.rq", "/tests/filter/query03.srx", false, true); } @Test public void testAndFilter2() throws Exception { /* test insertion of resource filter into query */ prepareTest(Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl")); - execute("/tests/filter/query04.rq", "/tests/filter/query04.srx", false); + execute("/tests/filter/query04.rq", "/tests/filter/query04.srx", false, true); } @Test public void testAndFilter3() throws Exception { /* test range filter with integers */ prepareTest(Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl")); - execute("/tests/filter/query05.rq", "/tests/filter/query05.srx", false); + execute("/tests/filter/query05.rq", "/tests/filter/query05.srx", false, true); } @Test public void testFilterPushing() throws Exception { prepareTest(Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl", "/tests/data/data4.ttl")); - execute("/tests/filter/query06.rq", "/tests/filter/query06.srx", false); + execute("/tests/filter/query06.rq", "/tests/filter/query06.srx", false, true); } @Test @@ -93,7 +93,7 @@ public void testSimpleFilterExclusiveGroup() throws Exception { public void testFilter_ExclusiveGroup_Regex() throws Exception { prepareTest(Arrays.asList("/tests/data/data1.ttl", "/tests/data/data3.ttl")); - execute("/tests/filter/query07.rq", "/tests/filter/query07.srx", false); + execute("/tests/filter/query07.rq", "/tests/filter/query07.srx", false, true); evaluateQueryPlan("/tests/filter/query07.rq", "/tests/filter/query07.qp"); } } diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/MediumConcurrencyTest.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/MediumConcurrencyTest.java index dd9d87e0fc1..9416343f9cc 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/MediumConcurrencyTest.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/MediumConcurrencyTest.java @@ -18,10 +18,6 @@ import java.util.concurrent.Phaser; import java.util.concurrent.TimeUnit; -import org.eclipse.rdf4j.query.Query; -import org.eclipse.rdf4j.query.TupleQuery; -import org.eclipse.rdf4j.query.TupleQueryResult; -import org.eclipse.rdf4j.repository.RepositoryConnection; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; @@ -75,7 +71,7 @@ public void queryMix() throws Throwable { }); Assertions.assertEquals("OK", message); } catch (Throwable t) { - futures.stream().forEach(future -> future.cancel(true)); + futures.forEach(future -> future.cancel(true)); throw t; } @@ -110,7 +106,7 @@ public void testPhaser() throws Exception { protected Future submit(final String query, final int queryId) { return executor.submit(() -> { log.info("Executing query " + queryId + ": " + query); - execute("/tests/medium/" + query + ".rq", "/tests/medium/" + query + ".srx", false); + execute("/tests/medium/" + query + ".rq", "/tests/medium/" + query + ".srx", false, true); // uncomment to simulate canceling case // executeReadPartial("/tests/medium/" + query + ".rq"); @@ -118,31 +114,4 @@ protected Future submit(final String query, final int queryId) { }); } - /** - * Execute a testcase, both queryFile and expectedResultFile must be files - * - * @param queryFile - * @param expectedResultFile - * @param checkOrder - * @throws Exception - */ - protected void executeReadPartial(String queryFile) - throws Exception { - - String queryString = readQueryString(queryFile); - - Query query = queryManager().prepareQuery(queryString); - - if (query instanceof TupleQuery) { - try (RepositoryConnection conn = fedxRule.getRepository().getConnection()) { - try (TupleQueryResult queryResult = ((TupleQuery) query).evaluate()) { - // explicitly consume only 1 binding set before closing - queryResult.next(); - } - } - - } else { - throw new IllegalStateException(); - } - } } diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/MediumTests.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/MediumTests.java index 103cb427e00..9dca0652544 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/MediumTests.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/MediumTests.java @@ -19,7 +19,7 @@ public void test1() throws Exception { /* test select query retrieving all persons (2 endpoints) */ prepareTest(Arrays.asList("/tests/medium/data1.ttl", "/tests/medium/data2.ttl", "/tests/medium/data3.ttl", "/tests/medium/data4.ttl")); - execute("/tests/medium/query01.rq", "/tests/medium/query01.srx", false); + execute("/tests/medium/query01.rq", "/tests/medium/query01.srx", false, true); } @Test @@ -28,7 +28,7 @@ public void test2() throws Exception { /* test select query retrieving all projects (1 relevant endpoint) */ prepareTest(Arrays.asList("/tests/medium/data1.ttl", "/tests/medium/data2.ttl", "/tests/medium/data3.ttl", "/tests/medium/data4.ttl")); - execute("/tests/medium/query02.rq", "/tests/medium/query02.srx", false); + execute("/tests/medium/query02.rq", "/tests/medium/query02.srx", false, true); } @Test @@ -37,7 +37,7 @@ public void test3() throws Exception { /* test select query retrieving all projects (3 relevant endpoint) */ prepareTest(Arrays.asList("/tests/medium/data1.ttl", "/tests/medium/data2.ttl", "/tests/medium/data3.ttl", "/tests/medium/data4.ttl")); - execute("/tests/medium/query03.rq", "/tests/medium/query03.srx", false); + execute("/tests/medium/query03.rq", "/tests/medium/query03.srx", false, true); } @Test @@ -46,7 +46,7 @@ public void test4() throws Exception { /* test union query (2 relevant endpoint) */ prepareTest(Arrays.asList("/tests/medium/data1.ttl", "/tests/medium/data2.ttl", "/tests/medium/data3.ttl", "/tests/medium/data4.ttl")); - execute("/tests/medium/query04.rq", "/tests/medium/query04.srx", false); + execute("/tests/medium/query04.rq", "/tests/medium/query04.srx", false, true); } @Test @@ -55,7 +55,7 @@ public void test5() throws Exception { /* test union query (2 relevant endpoint) */ prepareTest(Arrays.asList("/tests/medium/data1.ttl", "/tests/medium/data2.ttl", "/tests/medium/data3.ttl", "/tests/medium/data4.ttl")); - execute("/tests/medium/query05.rq", "/tests/medium/query05.srx", false); + execute("/tests/medium/query05.rq", "/tests/medium/query05.srx", false, true); } @Test @@ -64,7 +64,7 @@ public void test6() throws Exception { /* test union query (2 relevant endpoint) */ prepareTest(Arrays.asList("/tests/medium/data1.ttl", "/tests/medium/data2.ttl", "/tests/medium/data3.ttl", "/tests/medium/data4.ttl")); - execute("/tests/medium/query06.rq", "/tests/medium/query06.srx", false); + execute("/tests/medium/query06.rq", "/tests/medium/query06.srx", false, true); } @Test @@ -73,7 +73,7 @@ public void test7() throws Exception { /* test union query (2 relevant endpoint) */ prepareTest(Arrays.asList("/tests/medium/data1.ttl", "/tests/medium/data2.ttl", "/tests/medium/data3.ttl", "/tests/medium/data4.ttl")); - execute("/tests/medium/query07.rq", "/tests/medium/query07.srx", false); + execute("/tests/medium/query07.rq", "/tests/medium/query07.srx", false, true); } @Test @@ -82,7 +82,7 @@ public void test8() throws Exception { /* test union query (2 relevant endpoint) */ prepareTest(Arrays.asList("/tests/medium/data1.ttl", "/tests/medium/data2.ttl", "/tests/medium/data3.ttl", "/tests/medium/data4.ttl")); - execute("/tests/medium/query08.rq", "/tests/medium/query08.srx", false); + execute("/tests/medium/query08.rq", "/tests/medium/query08.srx", false, true); } @Test @@ -91,7 +91,7 @@ public void test9() throws Exception { /* test union query (2 relevant endpoint) */ prepareTest(Arrays.asList("/tests/medium/data1.ttl", "/tests/medium/data2.ttl", "/tests/medium/data3.ttl", "/tests/medium/data4.ttl")); - execute("/tests/medium/query09.rq", "/tests/medium/query09.srx", false); + execute("/tests/medium/query09.rq", "/tests/medium/query09.srx", false, true); } @Test @@ -100,7 +100,7 @@ public void test10() throws Exception { /* test union query (2 relevant endpoint) */ prepareTest(Arrays.asList("/tests/medium/data1.ttl", "/tests/medium/data2.ttl", "/tests/medium/data3.ttl", "/tests/medium/data4.ttl")); - execute("/tests/medium/query10.rq", "/tests/medium/query10.srx", false); + execute("/tests/medium/query10.rq", "/tests/medium/query10.srx", false, true); } @Test @@ -109,7 +109,7 @@ public void test11() throws Exception { /* test union query (2 relevant endpoint) */ prepareTest(Arrays.asList("/tests/medium/data1.ttl", "/tests/medium/data2.ttl", "/tests/medium/data3.ttl", "/tests/medium/data4.ttl")); - execute("/tests/medium/query11.rq", "/tests/medium/query11.srx", false); + execute("/tests/medium/query11.rq", "/tests/medium/query11.srx", false, true); } @Test @@ -118,7 +118,7 @@ public void test12() throws Exception { /* test union query (2 relevant endpoint) */ prepareTest(Arrays.asList("/tests/medium/data1.ttl", "/tests/medium/data2.ttl", "/tests/medium/data3.ttl", "/tests/medium/data4.ttl")); - execute("/tests/medium/query12.rq", "/tests/medium/query12.srx", false); + execute("/tests/medium/query12.rq", "/tests/medium/query12.srx", false, true); } } diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/OptionalTests.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/OptionalTests.java index b048e27b16d..865a107e273 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/OptionalTests.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/OptionalTests.java @@ -36,14 +36,14 @@ public void before() { public void test1() throws Exception { prepareTest(Arrays.asList("/tests/data/optional1.ttl", "/tests/data/optional2.ttl")); - execute("/tests/basic/query_optional01.rq", "/tests/basic/query_optional01.srx", false); + execute("/tests/basic/query_optional01.rq", "/tests/basic/query_optional01.srx", false, true); } @Test public void test2() throws Exception { prepareTest(Arrays.asList("/tests/data/optional1.ttl", "/tests/data/optional2.ttl")); - execute("/tests/basic/query_optional02.rq", "/tests/basic/query_optional02.srx", false); + execute("/tests/basic/query_optional02.rq", "/tests/basic/query_optional02.srx", false, true); } @Test diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/QueryTimeoutTests.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/QueryTimeoutTests.java index 8162f64fdb3..97bd78e3283 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/QueryTimeoutTests.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/QueryTimeoutTests.java @@ -40,7 +40,7 @@ public void testGlobalTimeout() throws Exception { repoSettings(3).setLatencySimulator(latencySimulator(4000)); Assertions.assertThrows(QueryInterruptedException.class, () -> { - execute("/tests/medium/query05.rq", "/tests/medium/query05.srx", false); + execute("/tests/medium/query05.rq", "/tests/medium/query05.srx", false, true); }); } diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SPARQL1_1Tests.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SPARQL1_1Tests.java index 17ef4729d7b..bb863129e43 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SPARQL1_1Tests.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SPARQL1_1Tests.java @@ -18,7 +18,7 @@ public void test1() throws Exception { /* test select query with sum */ prepareTest(Arrays.asList("/tests/sparql1_1/data01endpoint1.ttl", "/tests/sparql1_1/data01endpoint2.ttl")); - execute("/tests/sparql1_1/query01.rq", "/tests/sparql1_1/query01.srx", false); + execute("/tests/sparql1_1/query01.rq", "/tests/sparql1_1/query01.srx", false, true); } @Test @@ -26,6 +26,6 @@ public void test2() throws Exception { /* test select query with concat */ prepareTest(Arrays.asList("/tests/sparql1_1/data01endpoint1.ttl", "/tests/sparql1_1/data01endpoint2.ttl")); - execute("/tests/sparql1_1/query02.rq", "/tests/sparql1_1/query02.srx", false); + execute("/tests/sparql1_1/query02.rq", "/tests/sparql1_1/query02.srx", false, true); } } diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SPARQLBaseTest.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SPARQLBaseTest.java index b8ca7ddfc5f..8a468d47d7e 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SPARQLBaseTest.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SPARQLBaseTest.java @@ -41,21 +41,6 @@ protected void initFedXConfig() { } - /** - * Execute a testcase, both queryFile and expectedResultFile must be files - * - * @param queryFile - * @param expectedResultFile - * @param checkOrder - * @throws Exception - */ - protected void execute(String queryFile, String expectedResultFile, boolean checkOrder) throws Exception { - - try (RepositoryConnection conn = fedxRule.getRepository().getConnection()) { - super.execute(queryFile, expectedResultFile, checkOrder); - } - } - protected Set getStatements(Resource subj, IRI pred, Value obj) throws Exception { Set res = new HashSet<>(); diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/ServiceTests.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/ServiceTests.java index 9ccb8f8041e..ff1475d6cd2 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/ServiceTests.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/ServiceTests.java @@ -52,7 +52,7 @@ public void test1() throws Exception { "/tests/data/data4.ttl")); evaluateQueryPlan("/tests/service/query01.rq", "/tests/service/query01.qp"); - execute("/tests/service/query01.rq", "/tests/service/query01.srx", false); + execute("/tests/service/query01.rq", "/tests/service/query01.srx", false, true); } @Test @@ -63,7 +63,7 @@ public void test1a_byName() throws Exception { "/tests/data/data4.ttl")); evaluateQueryPlan("/tests/service/query01a.rq", "/tests/service/query01.qp"); - execute("/tests/service/query01a.rq", "/tests/service/query01.srx", false); + execute("/tests/service/query01a.rq", "/tests/service/query01.srx", false, true); } @Test @@ -76,7 +76,7 @@ public void test2() throws Exception { "/tests/data/data4.ttl")); evaluateQueryPlan("/tests/service/query02.rq", "/tests/service/query02.qp"); - execute("/tests/service/query02.rq", "/tests/service/query02.srx", false); + execute("/tests/service/query02.rq", "/tests/service/query02.srx", false, true); } @Test @@ -92,7 +92,7 @@ public void test2_differentOrder() throws Exception { "/tests/data/data4.ttl")); evaluateQueryPlan("/tests/service/query02a.rq", "/tests/service/query02a.qp"); - execute("/tests/service/query02a.rq", "/tests/service/query02.srx", false); + execute("/tests/service/query02a.rq", "/tests/service/query02.srx", false, true); } @Test @@ -108,7 +108,7 @@ public void test3() throws Exception { "/tests/data/data4.ttl")); Endpoint endpoint1 = federationContext().getEndpointManager().getEndpointByName("http://endpoint1"); fedxRule.removeEndpoint(endpoint1); - execute("/tests/service/query03.rq", "/tests/service/query03.srx", false); + execute("/tests/service/query03.rq", "/tests/service/query03.srx", false, true); } @Test @@ -122,7 +122,7 @@ public void test4() throws Exception { "/tests/data/data4.ttl")); evaluateQueryPlan("/tests/service/query04.rq", "/tests/service/query04.qp"); - execute("/tests/service/query04.rq", "/tests/service/query04.srx", false); + execute("/tests/service/query04.rq", "/tests/service/query04.srx", false, true); } @Test @@ -133,7 +133,7 @@ public void test4a() throws Exception { "/tests/data/data4.ttl")); evaluateQueryPlan("/tests/service/query04a.rq", "/tests/service/query04.qp"); - execute("/tests/service/query04a.rq", "/tests/service/query04a.srx", false); + execute("/tests/service/query04a.rq", "/tests/service/query04a.srx", false, true); } @Test @@ -144,7 +144,7 @@ public void test5() throws Exception { /* two services, one becomes exclusive group, the other is evaluated as service (filter) */ prepareTest(Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl", "/tests/data/data3.ttl", "/tests/data/data4.ttl")); - execute("/tests/service/query05.rq", "/tests/service/query05.srx", false); + execute("/tests/service/query05.rq", "/tests/service/query05.srx", false, true); } @Test @@ -156,7 +156,7 @@ public void test6() throws Exception { */ prepareTest(Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl", "/tests/data/data3.ttl", "/tests/data/data4.ttl")); - execute("/tests/service/query06.rq", "/tests/service/query06.srx", false); + execute("/tests/service/query06.rq", "/tests/service/query06.srx", false, true); } @Test @@ -168,7 +168,7 @@ public void test7() throws Exception { /* two services, both evaluated as SERVICE (FILTER), uses name of federation member in SERVICE */ prepareTest(Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl", "/tests/data/data3.ttl", "/tests/data/data4.ttl")); - execute("/tests/service/query07.rq", "/tests/service/query07.srx", false); + execute("/tests/service/query07.rq", "/tests/service/query07.srx", false, true); } @Test @@ -183,7 +183,7 @@ public void test8() throws Exception { "/tests/data/data4.ttl")); evaluateQueryPlan("/tests/service/query08.rq", "/tests/service/query08.qp"); - execute("/tests/service/query08.rq", "/tests/service/query08.srx", false); + execute("/tests/service/query08.rq", "/tests/service/query08.srx", false, true); } @Test @@ -213,7 +213,7 @@ protected FederatedService createService(String serviceUrl) throws QueryEvaluati "/tests/data/data4.ttl")); Endpoint endpoint1 = federationContext().getEndpointManager().getEndpointByName("http://endpoint1"); fedxRule.removeEndpoint(endpoint1); - execute("/tests/service/query03.rq", "/tests/service/query03.srx", false); + execute("/tests/service/query03.rq", "/tests/service/query03.srx", false, false); Assertions.assertEquals(1, ((TestSparqlFederatedService) serviceResolver diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SubSelectTests.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SubSelectTests.java index e8a2dd0a165..1598d154170 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SubSelectTests.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/SubSelectTests.java @@ -18,6 +18,6 @@ public void test1() throws Exception { /* test select query retrieving all persons (2 endpoints) */ prepareTest(Arrays.asList("/tests/medium/data1.ttl", "/tests/medium/data4.ttl")); - execute("/tests/subselects/query01.rq", "/tests/subselects/query01.srx", false); + execute("/tests/subselects/query01.rq", "/tests/subselects/query01.srx", false, true); } } diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/evaluation/concurrent/TaskWrapperIntegrationTest.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/evaluation/concurrent/TaskWrapperIntegrationTest.java index d8ea8c39e65..fea34a3c5f2 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/evaluation/concurrent/TaskWrapperIntegrationTest.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/evaluation/concurrent/TaskWrapperIntegrationTest.java @@ -26,7 +26,7 @@ public void resetTaskCount() { @Test public void testTaskWrapper() throws Exception { prepareTest(Arrays.asList("/tests/basic/data01endpoint1.ttl", "/tests/basic/data01endpoint2.ttl")); - execute("/tests/basic/query01.rq", "/tests/basic/query01.srx", false); + execute("/tests/basic/query01.rq", "/tests/basic/query01.srx", false, true); Assertions.assertTrue(taskWrapper.taskCount.get() > 0); } @@ -35,7 +35,7 @@ public void testTaskWrapper_Union() throws Exception { /* test union query (2 relevant endpoint) */ prepareTest(Arrays.asList("/tests/medium/data1.ttl", "/tests/medium/data2.ttl", "/tests/medium/data3.ttl", "/tests/medium/data4.ttl")); - execute("/tests/medium/query04.rq", "/tests/medium/query04.srx", false); + execute("/tests/medium/query04.rq", "/tests/medium/query04.srx", false, true); Assertions.assertTrue(taskWrapper.taskCount.get() > 0); } diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/misc/PrefixTests.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/misc/PrefixTests.java index bb785527ac4..b9f3df73380 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/misc/PrefixTests.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/misc/PrefixTests.java @@ -27,7 +27,7 @@ public void test1() throws Exception { qm.addPrefixDeclaration("foaf", "http://xmlns.com/foaf/0.1/"); qm.addPrefixDeclaration("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); - execute("/tests/prefix/query.rq", "/tests/prefix/query.srx", false); + execute("/tests/prefix/query.rq", "/tests/prefix/query.srx", false, true); qm.addPrefixDeclaration("foaf", null); qm.addPrefixDeclaration("rdf", null); @@ -41,7 +41,7 @@ public void test2() throws Exception { try { prepareTest(Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl", "/tests/data/data3.ttl", "/tests/data/data4.ttl")); - execute("/tests/prefix/query.rq", "/tests/prefix/query.srx", false); + execute("/tests/prefix/query.rq", "/tests/prefix/query.srx", false, true); } catch (MalformedQueryException m) { // this exception is expected return; @@ -58,7 +58,7 @@ public void test3() throws Exception { QueryManager qm = federationContext().getQueryManager(); qm.addPrefixDeclaration("foaf", "http://xmlns.com/foaf/0.1/"); - execute("/tests/prefix/query2.rq", "/tests/prefix/query2.srx", false); + execute("/tests/prefix/query2.rq", "/tests/prefix/query2.srx", false, true); qm.addPrefixDeclaration("foaf", null); qm.addPrefixDeclaration("rdf", null); diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/performance/FedXPerformanceTest.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/performance/FedXPerformanceTest.java index 27c332e0ab8..6b34901dd27 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/performance/FedXPerformanceTest.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/performance/FedXPerformanceTest.java @@ -73,7 +73,7 @@ public void testPerformance() throws Throwable { // warm-up for (String query : queries) { long start = System.currentTimeMillis(); - execute(basePackage + query + ".rq", basePackage + query + ".srx", false); + execute(basePackage + query + ".rq", basePackage + query + ".srx", false, true); long duration = System.currentTimeMillis() - start; System.out.println("Warmup " + query + " (Duration: " + duration + ")"); } @@ -89,7 +89,7 @@ public void testPerformance() throws Throwable { SingleQueryRun queryRun = new SingleQueryRun(query); run.addRun(queryRun); long start = System.currentTimeMillis(); - execute(basePackage + query + ".rq", basePackage + query + ".srx", false); + execute(basePackage + query + ".rq", basePackage + query + ".srx", false, true); long duration = System.currentTimeMillis() - start; queryRun.duration = duration; } @@ -125,7 +125,7 @@ public void testRun() throws Exception { basePackage + "data4.ttl")); String query = "query12"; - execute(basePackage + query + ".rq", basePackage + query + ".srx", false); + execute(basePackage + query + ".rq", basePackage + query + ".srx", false, true); } static class Run { From fd23bc4ca01cd9ed36fc7b30f339ab7cfb2565e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Avard=20Ottestad?= Date: Wed, 27 Jul 2022 09:46:18 +0200 Subject: [PATCH 3/3] GH-4084 revert optimizer pipeline order --- .../StandardQueryOptimizerPipeline.java | 2 +- .../sail/memory/QueryPlanRetrievalTest.java | 740 ++++++++++-------- 2 files changed, 416 insertions(+), 326 deletions(-) diff --git a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/optimizer/StandardQueryOptimizerPipeline.java b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/optimizer/StandardQueryOptimizerPipeline.java index 4961e3f0684..3c8e96a55c2 100644 --- a/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/optimizer/StandardQueryOptimizerPipeline.java +++ b/core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/optimizer/StandardQueryOptimizerPipeline.java @@ -72,9 +72,9 @@ public Iterable getOptimizers() { UNION_SCOPE_CHANGE_OPTIMIZER, QUERY_MODEL_NORMALIZER, PROJECTION_REMOVAL_OPTIMIZER, // Make sure this is after the UnionScopeChangeOptimizer - FILTER_OPTIMIZER, new QueryJoinOptimizer(evaluationStatistics, strategy.isTrackResultSize()), ITERATIVE_EVALUATION_OPTIMIZER, + FILTER_OPTIMIZER, ORDER_LIMIT_OPTIMIZER, PARENT_REFERENCE_CLEANER ); diff --git a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/QueryPlanRetrievalTest.java b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/QueryPlanRetrievalTest.java index c91f1ea8a8c..8e7c24edec8 100644 --- a/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/QueryPlanRetrievalTest.java +++ b/core/sail/memory/src/test/java/org/eclipse/rdf4j/sail/memory/QueryPlanRetrievalTest.java @@ -134,39 +134,42 @@ public void testTupleQueryOptimized() { try (SailRepositoryConnection connection = sailRepository.getConnection()) { TupleQuery query = connection.prepareTupleQuery(TUPLE_QUERY); String actual = query.explain(Explanation.Level.Optimized).toString(); - - String expected = "Projection\n" - + "╠══ProjectionElemList\n" - + "║ ProjectionElem \"a\"\n" - + "╚══LeftJoin (LeftJoinIterator)\n" - + " ├──Join (JoinIterator)\n" - + " │ ╠══LeftJoin (new scope) (LeftJoinIterator) (costEstimate=6, resultSizeEstimate=12)\n" - + " │ ║ ├──SingletonSet\n" - + " │ ║ └──StatementPattern (resultSizeEstimate=12)\n" - + " │ ║ Var (name=d)\n" - + " │ ║ Var (name=e)\n" - + " │ ║ Var (name=f)\n" - + " │ ╚══Filter (costEstimate=8, resultSizeEstimate=16)\n" - + " │ ├──Compare (!=)\n" - + " │ │ Var (name=c)\n" - + " │ │ Var (name=d)\n" - + " │ └──Join (JoinIterator)\n" - + " │ ╠══StatementPattern (costEstimate=1, resultSizeEstimate=4)\n" - + " │ ║ Var (name=a)\n" - + " │ ║ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\n" - + " │ ║ Var (name=d)\n" - + " │ ╚══Filter (costEstimate=2, resultSizeEstimate=4)\n" - + " │ ├──Compare (!=)\n" - + " │ │ Var (name=c)\n" - + " │ │ ValueConstant (value=\"<\")\n" - + " │ └──StatementPattern (resultSizeEstimate=4)\n" - + " │ Var (name=a)\n" - + " │ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\n" - + " │ Var (name=c)\n" - + " └──StatementPattern (resultSizeEstimate=12)\n" - + " Var (name=d)\n" - + " Var (name=e)\n" - + " Var (name=f)\n"; + String expected = "Projection\n" + + "╠══ProjectionElemList\n" + + "║ ProjectionElem \"a\"\n" + + "╚══LeftJoin (LeftJoinIterator)\n" + + " ├──Join (JoinIterator)\n" + + " │ ╠══StatementPattern (costEstimate=1, resultSizeEstimate=4)\n" + + " │ ║ Var (name=a)\n" + + " │ ║ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)" + + "\n" + + + " │ ║ Var (name=d)\n" + + " │ ╚══Filter\n" + + " │ ├──Compare (!=)\n" + + " │ │ Var (name=c)\n" + + " │ │ Var (name=d)\n" + + " │ └──Join (HashJoinIteration)\n" + + " │ ╠══Filter\n" + + " │ ║ ├──Compare (!=)\n" + + " │ ║ │ Var (name=c)\n" + + " │ ║ │ ValueConstant (value=\"<\")\n" + + " │ ║ └──StatementPattern (costEstimate=2, resultSizeEstimate=4)\n" + + " │ ║ Var (name=a)\n" + + " │ ║ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)" + + "\n" + + + " │ ║ Var (name=c)\n" + + " │ ╚══LeftJoin (new scope) (costEstimate=5, resultSizeEstimate=12)\n" + + " │ ├──SingletonSet\n" + + " │ └──StatementPattern (resultSizeEstimate=12)\n" + + " │ Var (name=d)\n" + + " │ Var (name=e)\n" + + " │ Var (name=f)\n" + + " └──StatementPattern (resultSizeEstimate=12)\n" + + " Var (name=d)\n" + + " Var (name=e)\n" + + " Var (name=f)\n"; assertThat(actual).isEqualToNormalizingNewlines(expected); } @@ -211,38 +214,45 @@ public void testTupleQueryExecuted() { Query query = connection.prepareTupleQuery(TUPLE_QUERY); String actual = query.explain(Explanation.Level.Executed).toString(); - String expected = "Projection (resultSizeActual=2)\n" - + "╠══ProjectionElemList\n" - + "║ ProjectionElem \"a\"\n" - + "╚══LeftJoin (LeftJoinIterator) (resultSizeActual=2)\n" - + " ├──Join (JoinIterator) (resultSizeActual=2)\n" - + " │ ╠══LeftJoin (new scope) (LeftJoinIterator) (costEstimate=6, resultSizeEstimate=12, resultSizeActual=12)\n" - + " │ ║ ├──SingletonSet (resultSizeActual=1)\n" - + " │ ║ └──StatementPattern (resultSizeEstimate=12, resultSizeActual=12)\n" - + " │ ║ Var (name=d)\n" - + " │ ║ Var (name=e)\n" - + " │ ║ Var (name=f)\n" - + " │ ╚══Filter (costEstimate=8, resultSizeEstimate=16, resultSizeActual=2)\n" - + " │ ├──Compare (!=)\n" - + " │ │ Var (name=c)\n" - + " │ │ Var (name=d)\n" - + " │ └──Join (JoinIterator) (resultSizeActual=6)\n" - + " │ ╠══StatementPattern (costEstimate=1, resultSizeEstimate=4, resultSizeActual=4)\n" - + " │ ║ Var (name=a)\n" - + " │ ║ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\n" - + " │ ║ Var (name=d)\n" - + " │ ╚══Filter (costEstimate=2, resultSizeEstimate=4, resultSizeActual=6)\n" - + " │ ├──Compare (!=)\n" - + " │ │ Var (name=c)\n" - + " │ │ ValueConstant (value=\"<\")\n" - + " │ └──StatementPattern (resultSizeEstimate=4, resultSizeActual=6)\n" - + " │ Var (name=a)\n" - + " │ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\n" - + " │ Var (name=c)\n" - + " └──StatementPattern (resultSizeEstimate=12, resultSizeActual=2)\n" - + " Var (name=d)\n" - + " Var (name=e)\n" - + " Var (name=f)\n"; + String expected = "Projection (resultSizeActual=2)\n" + + "╠══ProjectionElemList\n" + + "║ ProjectionElem \"a\"\n" + + "╚══LeftJoin (LeftJoinIterator) (resultSizeActual=2)\n" + + " ├──Join (JoinIterator) (resultSizeActual=2)\n" + + " │ ╠══StatementPattern (costEstimate=1, resultSizeEstimate=4, resultSizeActual=4)\n" + + " │ ║ Var (name=a)\n" + + " │ ║ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)" + + "\n" + + + " │ ║ Var (name=d)\n" + + " │ ╚══Filter (resultSizeActual=2)\n" + + " │ ├──Compare (!=)\n" + + " │ │ Var (name=c)\n" + + " │ │ Var (name=d)\n" + + " │ └──Join (HashJoinIteration) (resultSizeActual=6)\n" + + " │ ╠══Filter (resultSizeActual=6)\n" + + " │ ║ ├──Compare (!=)\n" + + " │ ║ │ Var (name=c)\n" + + " │ ║ │ ValueConstant (value=\"<\")\n" + + " │ ║ └──StatementPattern (costEstimate=2, resultSizeEstimate=4, resultSizeActual=6)" + + "\n" + + " │ ║ Var (name=a)\n" + + " │ ║ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)" + + "\n" + + + " │ ║ Var (name=c)\n" + + " │ ╚══LeftJoin (new scope) (BadlyDesignedLeftJoinIterator) (costEstimate=5, resultSizeEstimate=12, resultSizeActual=4)" + + "\n" + + + " │ ├──SingletonSet (resultSizeActual=4)\n" + + " │ └──StatementPattern (resultSizeEstimate=12, resultSizeActual=48)\n" + + " │ Var (name=d)\n" + + " │ Var (name=e)\n" + + " │ Var (name=f)\n" + + " └──StatementPattern (resultSizeEstimate=12, resultSizeActual=2)\n" + + " Var (name=d)\n" + + " Var (name=e)\n" + + " Var (name=f)\n"; assertThat(actual).isEqualToNormalizingNewlines(expected); } @@ -259,38 +269,45 @@ public void testGenericPlanNode() { Query query = connection.prepareTupleQuery(TUPLE_QUERY); String actual = query.explain(Explanation.Level.Executed).toGenericPlanNode().toString(); - String expected = "Projection (resultSizeActual=2)\n" - + "╠══ProjectionElemList\n" - + "║ ProjectionElem \"a\"\n" - + "╚══LeftJoin (LeftJoinIterator) (resultSizeActual=2)\n" - + " ├──Join (JoinIterator) (resultSizeActual=2)\n" - + " │ ╠══LeftJoin (new scope) (LeftJoinIterator) (costEstimate=6, resultSizeEstimate=12, resultSizeActual=12)\n" - + " │ ║ ├──SingletonSet (resultSizeActual=1)\n" - + " │ ║ └──StatementPattern (resultSizeEstimate=12, resultSizeActual=12)\n" - + " │ ║ Var (name=d)\n" - + " │ ║ Var (name=e)\n" - + " │ ║ Var (name=f)\n" - + " │ ╚══Filter (costEstimate=8, resultSizeEstimate=16, resultSizeActual=2)\n" - + " │ ├──Compare (!=)\n" - + " │ │ Var (name=c)\n" - + " │ │ Var (name=d)\n" - + " │ └──Join (JoinIterator) (resultSizeActual=6)\n" - + " │ ╠══StatementPattern (costEstimate=1, resultSizeEstimate=4, resultSizeActual=4)\n" - + " │ ║ Var (name=a)\n" - + " │ ║ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\n" - + " │ ║ Var (name=d)\n" - + " │ ╚══Filter (costEstimate=2, resultSizeEstimate=4, resultSizeActual=6)\n" - + " │ ├──Compare (!=)\n" - + " │ │ Var (name=c)\n" - + " │ │ ValueConstant (value=\"<\")\n" - + " │ └──StatementPattern (resultSizeEstimate=4, resultSizeActual=6)\n" - + " │ Var (name=a)\n" - + " │ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\n" - + " │ Var (name=c)\n" - + " └──StatementPattern (resultSizeEstimate=12, resultSizeActual=2)\n" - + " Var (name=d)\n" - + " Var (name=e)\n" - + " Var (name=f)\n"; + String expected = "Projection (resultSizeActual=2)\n" + + "╠══ProjectionElemList\n" + + "║ ProjectionElem \"a\"\n" + + "╚══LeftJoin (LeftJoinIterator) (resultSizeActual=2)\n" + + " ├──Join (JoinIterator) (resultSizeActual=2)\n" + + " │ ╠══StatementPattern (costEstimate=1, resultSizeEstimate=4, resultSizeActual=4)\n" + + " │ ║ Var (name=a)\n" + + " │ ║ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)" + + "\n" + + + " │ ║ Var (name=d)\n" + + " │ ╚══Filter (resultSizeActual=2)\n" + + " │ ├──Compare (!=)\n" + + " │ │ Var (name=c)\n" + + " │ │ Var (name=d)\n" + + " │ └──Join (HashJoinIteration) (resultSizeActual=6)\n" + + " │ ╠══Filter (resultSizeActual=6)\n" + + " │ ║ ├──Compare (!=)\n" + + " │ ║ │ Var (name=c)\n" + + " │ ║ │ ValueConstant (value=\"<\")\n" + + " │ ║ └──StatementPattern (costEstimate=2, resultSizeEstimate=4, resultSizeActual=6)" + + "\n" + + " │ ║ Var (name=a)\n" + + " │ ║ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)" + + "\n" + + + " │ ║ Var (name=c)\n" + + " │ ╚══LeftJoin (new scope) (BadlyDesignedLeftJoinIterator) (costEstimate=5, resultSizeEstimate=12, resultSizeActual=4)" + + "\n" + + + " │ ├──SingletonSet (resultSizeActual=4)\n" + + " │ └──StatementPattern (resultSizeEstimate=12, resultSizeActual=48)\n" + + " │ Var (name=d)\n" + + " │ Var (name=e)\n" + + " │ Var (name=f)\n" + + " └──StatementPattern (resultSizeEstimate=12, resultSizeActual=2)\n" + + " Var (name=d)\n" + + " Var (name=e)\n" + + " Var (name=f)\n"; assertThat(actual).isEqualToNormalizingNewlines(expected); } @@ -307,114 +324,114 @@ public void testJsonPlanNode() { Query query = connection.prepareTupleQuery(TUPLE_QUERY); String actual = query.explain(Explanation.Level.Executed).toJson(); - - String expected = "{\n" - + " \"type\" : \"Projection\",\n" - + " \"resultSizeActual\" : 2,\n" - + " \"plans\" : [ {\n" - + " \"type\" : \"ProjectionElemList\",\n" - + " \"plans\" : [ {\n" - + " \"type\" : \"ProjectionElem \\\"a\\\"\"\n" - + " } ]\n" - + " }, {\n" - + " \"type\" : \"LeftJoin\",\n" - + " \"resultSizeActual\" : 2,\n" - + " \"algorithm\" : \"LeftJoinIterator\",\n" - + " \"plans\" : [ {\n" - + " \"type\" : \"Join\",\n" - + " \"resultSizeActual\" : 2,\n" - + " \"algorithm\" : \"JoinIterator\",\n" - + " \"plans\" : [ {\n" - + " \"type\" : \"LeftJoin\",\n" - + " \"costEstimate\" : 6.0,\n" - + " \"resultSizeEstimate\" : 12.0,\n" - + " \"resultSizeActual\" : 12,\n" - + " \"newScope\" : true,\n" - + " \"algorithm\" : \"LeftJoinIterator\",\n" - + " \"plans\" : [ {\n" - + " \"type\" : \"SingletonSet\",\n" - + " \"resultSizeActual\" : 1\n" - + " }, {\n" - + " \"type\" : \"StatementPattern\",\n" - + " \"resultSizeEstimate\" : 12.0,\n" - + " \"resultSizeActual\" : 12,\n" - + " \"plans\" : [ {\n" - + " \"type\" : \"Var (name=d)\"\n" - + " }, {\n" - + " \"type\" : \"Var (name=e)\"\n" - + " }, {\n" - + " \"type\" : \"Var (name=f)\"\n" - + " } ]\n" - + " } ]\n" - + " }, {\n" - + " \"type\" : \"Filter\",\n" - + " \"costEstimate\" : 8.0,\n" - + " \"resultSizeEstimate\" : 16.0,\n" - + " \"resultSizeActual\" : 2,\n" - + " \"plans\" : [ {\n" - + " \"type\" : \"Compare (!=)\",\n" - + " \"plans\" : [ {\n" - + " \"type\" : \"Var (name=c)\"\n" - + " }, {\n" - + " \"type\" : \"Var (name=d)\"\n" - + " } ]\n" - + " }, {\n" - + " \"type\" : \"Join\",\n" - + " \"resultSizeActual\" : 6,\n" - + " \"algorithm\" : \"JoinIterator\",\n" - + " \"plans\" : [ {\n" - + " \"type\" : \"StatementPattern\",\n" - + " \"costEstimate\" : 1.0,\n" - + " \"resultSizeEstimate\" : 4.0,\n" - + " \"resultSizeActual\" : 4,\n" - + " \"plans\" : [ {\n" - + " \"type\" : \"Var (name=a)\"\n" - + " }, {\n" - + " \"type\" : \"Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\"\n" - + " }, {\n" - + " \"type\" : \"Var (name=d)\"\n" - + " } ]\n" - + " }, {\n" - + " \"type\" : \"Filter\",\n" - + " \"costEstimate\" : 2.0,\n" - + " \"resultSizeEstimate\" : 4.0,\n" - + " \"resultSizeActual\" : 6,\n" - + " \"plans\" : [ {\n" - + " \"type\" : \"Compare (!=)\",\n" - + " \"plans\" : [ {\n" - + " \"type\" : \"Var (name=c)\"\n" - + " }, {\n" - + " \"type\" : \"ValueConstant (value=\\\"<\\\")\"\n" - + " } ]\n" - + " }, {\n" - + " \"type\" : \"StatementPattern\",\n" - + " \"resultSizeEstimate\" : 4.0,\n" - + " \"resultSizeActual\" : 6,\n" - + " \"plans\" : [ {\n" - + " \"type\" : \"Var (name=a)\"\n" - + " }, {\n" - + " \"type\" : \"Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\"\n" - + " }, {\n" - + " \"type\" : \"Var (name=c)\"\n" - + " } ]\n" - + " } ]\n" - + " } ]\n" - + " } ]\n" - + " } ]\n" - + " }, {\n" - + " \"type\" : \"StatementPattern\",\n" - + " \"resultSizeEstimate\" : 12.0,\n" - + " \"resultSizeActual\" : 2,\n" - + " \"plans\" : [ {\n" - + " \"type\" : \"Var (name=d)\"\n" - + " }, {\n" - + " \"type\" : \"Var (name=e)\"\n" - + " }, {\n" - + " \"type\" : \"Var (name=f)\"\n" - + " } ]\n" - + " } ]\n" - + " } ]\n" - + "}"; + String expected = "{\n" + + " \"type\" : \"Projection\",\n" + + " \"resultSizeActual\" : 2,\n" + + " \"plans\" : [ {\n" + + " \"type\" : \"ProjectionElemList\",\n" + + " \"plans\" : [ {\n" + + " \"type\" : \"ProjectionElem \\\"a\\\"\"\n" + + " } ]\n" + + " }, {\n" + + " \"type\" : \"LeftJoin\",\n" + + " \"resultSizeActual\" : 2,\n" + + " \"algorithm\" : \"LeftJoinIterator\",\n" + + " \"plans\" : [ {\n" + + " \"type\" : \"Join\",\n" + + " \"resultSizeActual\" : 2,\n" + + " \"algorithm\" : \"JoinIterator\",\n" + + " \"plans\" : [ {\n" + + " \"type\" : \"StatementPattern\",\n" + + " \"costEstimate\" : 1.3333333333333333,\n" + + " \"resultSizeEstimate\" : 4.0,\n" + + " \"resultSizeActual\" : 4,\n" + + " \"plans\" : [ {\n" + + " \"type\" : \"Var (name=a)\"\n" + + " }, {\n" + + " \"type\" : \"Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\"" + + "\n" + + + " }, {\n" + + " \"type\" : \"Var (name=d)\"\n" + + " } ]\n" + + " }, {\n" + + " \"type\" : \"Filter\",\n" + + " \"resultSizeActual\" : 2,\n" + + " \"plans\" : [ {\n" + + " \"type\" : \"Compare (!=)\",\n" + + " \"plans\" : [ {\n" + + " \"type\" : \"Var (name=c)\"\n" + + " }, {\n" + + " \"type\" : \"Var (name=d)\"\n" + + " } ]\n" + + " }, {\n" + + " \"type\" : \"Join\",\n" + + " \"resultSizeActual\" : 6,\n" + + " \"algorithm\" : \"HashJoinIteration\",\n" + + " \"plans\" : [ {\n" + + " \"type\" : \"Filter\",\n" + + " \"resultSizeActual\" : 6,\n" + + " \"plans\" : [ {\n" + + " \"type\" : \"Compare (!=)\",\n" + + " \"plans\" : [ {\n" + + " \"type\" : \"Var (name=c)\"\n" + + " }, {\n" + + " \"type\" : \"ValueConstant (value=\\\"<\\\")\"\n" + + " } ]\n" + + " }, {\n" + + " \"type\" : \"StatementPattern\",\n" + + " \"costEstimate\" : 2.0,\n" + + " \"resultSizeEstimate\" : 4.0,\n" + + " \"resultSizeActual\" : 6,\n" + + " \"plans\" : [ {\n" + + " \"type\" : \"Var (name=a)\"\n" + + " }, {\n" + + " \"type\" : \"Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\"" + + "\n" + + + " }, {\n" + + " \"type\" : \"Var (name=c)\"\n" + + " } ]\n" + + " } ]\n" + + " }, {\n" + + " \"type\" : \"LeftJoin\",\n" + + " \"costEstimate\" : 5.241482788417793,\n" + + " \"resultSizeEstimate\" : 12.0,\n" + + " \"resultSizeActual\" : 4,\n" + + " \"newScope\" : true,\n" + + " \"algorithm\" : \"BadlyDesignedLeftJoinIterator\",\n" + + " \"plans\" : [ {\n" + + " \"type\" : \"SingletonSet\",\n" + + " \"resultSizeActual\" : 4\n" + + " }, {\n" + + " \"type\" : \"StatementPattern\",\n" + + " \"resultSizeEstimate\" : 12.0,\n" + + " \"resultSizeActual\" : 48,\n" + + " \"plans\" : [ {\n" + + " \"type\" : \"Var (name=d)\"\n" + + " }, {\n" + + " \"type\" : \"Var (name=e)\"\n" + + " }, {\n" + + " \"type\" : \"Var (name=f)\"\n" + + " } ]\n" + + " } ]\n" + + " } ]\n" + + " } ]\n" + + " } ]\n" + + " }, {\n" + + " \"type\" : \"StatementPattern\",\n" + + " \"resultSizeEstimate\" : 12.0,\n" + + " \"resultSizeActual\" : 2,\n" + + " \"plans\" : [ {\n" + + " \"type\" : \"Var (name=d)\"\n" + + " }, {\n" + + " \"type\" : \"Var (name=e)\"\n" + + " }, {\n" + + " \"type\" : \"Var (name=f)\"\n" + + " } ]\n" + + " } ]\n" + + " } ]\n" + + "}"; assertThat(actual).isEqualToNormalizingNewlines(expected); } @@ -431,36 +448,39 @@ public void testAskQuery() { Query query = connection.prepareBooleanQuery(ASK_QUERY); String actual = query.explain(Explanation.Level.Executed).toString(); - String expected = "Slice (limit=1) (resultSizeActual=1)\n" - + " LeftJoin (LeftJoinIterator) (resultSizeActual=1)\n" - + " ├──Join (JoinIterator) (resultSizeActual=1)\n" - + " │ ╠══LeftJoin (new scope) (LeftJoinIterator) (costEstimate=6, resultSizeEstimate=12, resultSizeActual=1)\n" - + " │ ║ ├──SingletonSet (resultSizeActual=1)\n" - + " │ ║ └──StatementPattern (resultSizeEstimate=12, resultSizeActual=1)\n" - + " │ ║ Var (name=d)\n" - + " │ ║ Var (name=e)\n" - + " │ ║ Var (name=f)\n" - + " │ ╚══Filter (costEstimate=8, resultSizeEstimate=16, resultSizeActual=1)\n" - + " │ ├──Compare (!=)\n" - + " │ │ Var (name=c)\n" - + " │ │ Var (name=d)\n" - + " │ └──Join (JoinIterator) (resultSizeActual=3)\n" - + " │ ╠══StatementPattern (costEstimate=1, resultSizeEstimate=4, resultSizeActual=3)\n" - + " │ ║ Var (name=a)\n" - + " │ ║ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\n" - + " │ ║ Var (name=d)\n" - + " │ ╚══Filter (costEstimate=2, resultSizeEstimate=4, resultSizeActual=3)\n" - + " │ ├──Compare (!=)\n" - + " │ │ Var (name=c)\n" - + " │ │ ValueConstant (value=\"<\")\n" - + " │ └──StatementPattern (resultSizeEstimate=4, resultSizeActual=3)\n" - + " │ Var (name=a)\n" - + " │ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\n" - + " │ Var (name=c)\n" - + " └──StatementPattern (resultSizeEstimate=12, resultSizeActual=1)\n" - + " Var (name=d)\n" - + " Var (name=e)\n" - + " Var (name=f)\n"; + String expected = "Slice (limit=1) (resultSizeActual=1)\n" + + " LeftJoin (LeftJoinIterator) (resultSizeActual=1)\n" + + " ├──Join (JoinIterator) (resultSizeActual=1)\n" + + " │ ╠══StatementPattern (costEstimate=1, resultSizeEstimate=4, resultSizeActual=3)\n" + + " │ ║ Var (name=a)\n" + + " │ ║ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\n" + + + " │ ║ Var (name=d)\n" + + " │ ╚══Filter (resultSizeActual=1)\n" + + " │ ├──Compare (!=)\n" + + " │ │ Var (name=c)\n" + + " │ │ Var (name=d)\n" + + " │ └──Join (HashJoinIteration) (resultSizeActual=4)\n" + + " │ ╠══Filter (resultSizeActual=4)\n" + + " │ ║ ├──Compare (!=)\n" + + " │ ║ │ Var (name=c)\n" + + " │ ║ │ ValueConstant (value=\"<\")\n" + + " │ ║ └──StatementPattern (costEstimate=2, resultSizeEstimate=4, resultSizeActual=4)\n" + + " │ ║ Var (name=a)\n" + + " │ ║ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\n" + + + " │ ║ Var (name=c)\n" + + " │ ╚══LeftJoin (new scope) (BadlyDesignedLeftJoinIterator) (costEstimate=5, resultSizeEstimate=12, resultSizeActual=3)\n" + + + " │ ├──SingletonSet (resultSizeActual=3)\n" + + " │ └──StatementPattern (resultSizeEstimate=12, resultSizeActual=36)\n" + + " │ Var (name=d)\n" + + " │ Var (name=e)\n" + + " │ Var (name=f)\n" + + " └──StatementPattern (resultSizeEstimate=12, resultSizeActual=1)\n" + + " Var (name=d)\n" + + " Var (name=e)\n" + + " Var (name=f)\n"; assertThat(actual).isEqualToNormalizingNewlines(expected); } @@ -491,35 +511,41 @@ public void testConstructQuery() { + " Extension (resultSizeActual=2)\n" + " ╠══LeftJoin (LeftJoinIterator) (resultSizeActual=2)\n" + " ║ ├──Join (JoinIterator) (resultSizeActual=2)\n" - + " ║ │ ╠══LeftJoin (new scope) (LeftJoinIterator) (costEstimate=6, resultSizeEstimate=12, resultSizeActual=12)\n" - + " ║ │ ║ ├──SingletonSet (resultSizeActual=1)\n" - + " ║ │ ║ └──StatementPattern (resultSizeEstimate=12, resultSizeActual=12)\n" - + " ║ │ ║ Var (name=d)\n" - + " ║ │ ║ Var (name=e)\n" - + " ║ │ ║ Var (name=f)\n" - + " ║ │ ╚══Filter (costEstimate=8, resultSizeEstimate=16, resultSizeActual=2)\n" + + " ║ │ ╠══StatementPattern (costEstimate=1, resultSizeEstimate=4, resultSizeActual=4)" + + "\n" + + " ║ │ ║ Var (name=a)\n" + + " ║ │ ║ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)" + + "\n" + + " ║ │ ║ Var (name=d)\n" + + " ║ │ ╚══Filter (resultSizeActual=2)\n" + " ║ │ ├──Compare (!=)\n" + " ║ │ │ Var (name=c)\n" + " ║ │ │ Var (name=d)\n" - + " ║ │ └──Join (JoinIterator) (resultSizeActual=6)\n" - + " ║ │ ╠══StatementPattern (costEstimate=1, resultSizeEstimate=4, resultSizeActual=4)\n" - + " ║ │ ║ Var (name=a)\n" - + " ║ │ ║ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\n" - + " ║ │ ║ Var (name=d)\n" - + " ║ │ ╚══Filter (costEstimate=2, resultSizeEstimate=4, resultSizeActual=6)\n" - + " ║ │ ├──Compare (!=)\n" - + " ║ │ │ Var (name=c)\n" - + " ║ │ │ ValueConstant (value=\"<\")\n" - + " ║ │ └──StatementPattern (resultSizeEstimate=4, resultSizeActual=6)\n" - + " ║ │ Var (name=a)\n" - + " ║ │ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)\n" - + " ║ │ Var (name=c)\n" + + " ║ │ └──Join (HashJoinIteration) (resultSizeActual=6)\n" + + " ║ │ ╠══Filter (resultSizeActual=6)\n" + + " ║ │ ║ ├──Compare (!=)\n" + + " ║ │ ║ │ Var (name=c)\n" + + " ║ │ ║ │ ValueConstant (value=\"<\")\n" + + " ║ │ ║ └──StatementPattern (costEstimate=2, resultSizeEstimate=4, resultSizeActual=6)" + + "\n" + + " ║ │ ║ Var (name=a)\n" + + " ║ │ ║ Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)" + + "\n" + + " ║ │ ║ Var (name=c)\n" + + " ║ │ ╚══LeftJoin (new scope) (BadlyDesignedLeftJoinIterator) (costEstimate=5, resultSizeEstimate=12, resultSizeActual=4)" + + "\n" + + " ║ │ ├──SingletonSet (resultSizeActual=4)\n" + + " ║ │ └──StatementPattern (resultSizeEstimate=12, resultSizeActual=48)\n" + + " ║ │ Var (name=d)\n" + + " ║ │ Var (name=e)\n" + + " ║ │ Var (name=f)\n" + " ║ └──StatementPattern (resultSizeEstimate=12, resultSizeActual=2)\n" + " ║ Var (name=d)\n" + " ║ Var (name=e)\n" + " ║ Var (name=f)\n" + " ╚══ExtensionElem (_const_f5e5585a_uri)\n" + " ValueConstant (value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type)\n"; + assertThat(actual).isEqualToNormalizingNewlines(expected); } @@ -734,76 +760,140 @@ public void testDot() { String actual = explain.toDot(); actual = actual.replaceAll("UUID_\\w+", "UUID"); - String expected = "digraph Explanation {\n" - + " UUID [label=<
Projection
> shape=plaintext];\n" - + " UUID -> UUID [label=\"left\"] ;\n" - + " UUID -> UUID [label=\"right\"] ;\n" - + " UUID [label=<
ProjectionElemList
> shape=plaintext];\n" - + " UUID -> UUID [label=\"\"] ;\n" - + " UUID [label=<
ProjectionElem "a"
> shape=plaintext];\n" - + " UUID [label=<
LeftJoin
AlgorithmLeftJoinIterator
> shape=plaintext];\n" - + " UUID -> UUID [label=\"left\"] ;\n" - + " UUID -> UUID [label=\"right\"] ;\n" - + " UUID [label=<
Join
AlgorithmJoinIterator
> shape=plaintext];\n" - + " UUID -> UUID [label=\"left\"] ;\n" - + " UUID -> UUID [label=\"right\"] ;\n" - + " subgraph cluster_UUID {\n" - + " color=grey\n" - + "UUID [label=<
LeftJoin
AlgorithmLeftJoinIterator
New scopetrue
Cost estimate6
Result size estimate12
> shape=plaintext];\n" - + " UUID -> UUID [label=\"left\"] ;\n" - + " UUID -> UUID [label=\"right\"] ;\n" - + " UUID [label=<
SingletonSet
> shape=plaintext];\n" - + " UUID [label=<
StatementPattern
Result size estimate12
> shape=plaintext];\n" - + " UUID -> UUID [label=\"index 0\"] ;\n" - + " UUID -> UUID [label=\"index 1\"] ;\n" - + " UUID -> UUID [label=\"index 2\"] ;\n" - + " UUID [label=<
Var (name=d)
> shape=plaintext];\n" - + " UUID [label=<
Var (name=e)
> shape=plaintext];\n" - + " UUID [label=<
Var (name=f)
> shape=plaintext];\n" - + "\n" - + "}\n" - + " UUID [label=<
Filter
Cost estimate8
Result size estimate16
> shape=plaintext];\n" - + " UUID -> UUID [label=\"left\"] ;\n" - + " UUID -> UUID [label=\"right\"] ;\n" - + " UUID [label=<
Compare (!=)
> shape=plaintext];\n" - + " UUID -> UUID [label=\"left\"] ;\n" - + " UUID -> UUID [label=\"right\"] ;\n" - + " UUID [label=<
Var (name=c)
> shape=plaintext];\n" - + " UUID [label=<
Var (name=d)
> shape=plaintext];\n" - + " UUID [label=<
Join
AlgorithmJoinIterator
> shape=plaintext];\n" - + " UUID -> UUID [label=\"left\"] ;\n" - + " UUID -> UUID [label=\"right\"] ;\n" - + " UUID [label=<
StatementPattern
Cost estimate1
Result size estimate4
> shape=plaintext];\n" - + " UUID -> UUID [label=\"index 0\"] ;\n" - + " UUID -> UUID [label=\"index 1\"] ;\n" - + " UUID -> UUID [label=\"index 2\"] ;\n" - + " UUID [label=<
Var (name=a)
> shape=plaintext];\n" - + " UUID [label=<
Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)
> shape=plaintext];\n" - + " UUID [label=<
Var (name=d)
> shape=plaintext];\n" - + " UUID [label=<
Filter
Cost estimate2
Result size estimate4
> shape=plaintext];\n" - + " UUID -> UUID [label=\"left\"] ;\n" - + " UUID -> UUID [label=\"right\"] ;\n" - + " UUID [label=<
Compare (!=)
> shape=plaintext];\n" - + " UUID -> UUID [label=\"left\"] ;\n" - + " UUID -> UUID [label=\"right\"] ;\n" - + " UUID [label=<
Var (name=c)
> shape=plaintext];\n" - + " UUID [label=<
ValueConstant (value="<")
> shape=plaintext];\n" - + " UUID [label=<
StatementPattern
Result size estimate4
> shape=plaintext];\n" - + " UUID -> UUID [label=\"index 0\"] ;\n" - + " UUID -> UUID [label=\"index 1\"] ;\n" - + " UUID -> UUID [label=\"index 2\"] ;\n" - + " UUID [label=<
Var (name=a)
> shape=plaintext];\n" - + " UUID [label=<
Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)
> shape=plaintext];\n" - + " UUID [label=<
Var (name=c)
> shape=plaintext];\n" - + " UUID [label=<
StatementPattern
Result size estimate12
> shape=plaintext];\n" - + " UUID -> UUID [label=\"index 0\"] ;\n" - + " UUID -> UUID [label=\"index 1\"] ;\n" - + " UUID -> UUID [label=\"index 2\"] ;\n" - + " UUID [label=<
Var (name=d)
> shape=plaintext];\n" - + " UUID [label=<
Var (name=e)
> shape=plaintext];\n" - + " UUID [label=<
Var (name=f)
> shape=plaintext];\n" - + "\n" - + "}\n"; + String expected = "digraph Explanation {\n" + + " UUID [label=<
Projection
> shape=plaintext];" + + "\n" + + + " UUID -> UUID [label=\"left\"] ;\n" + + " UUID -> UUID [label=\"right\"] ;\n" + + " UUID [label=<
ProjectionElemList
> shape=plaintext];" + + "\n" + + + " UUID -> UUID [label=\"\"] ;\n" + + " UUID [label=<
ProjectionElem "a"
> shape=plaintext];" + + "\n" + + + " UUID [label=<
LeftJoin
AlgorithmLeftJoinIterator
> shape=plaintext];" + + "\n" + + + " UUID -> UUID [label=\"left\"] ;\n" + + " UUID -> UUID [label=\"right\"] ;\n" + + " UUID [label=<
Join
AlgorithmJoinIterator
> shape=plaintext];" + + "\n" + + + " UUID -> UUID [label=\"left\"] ;\n" + + " UUID -> UUID [label=\"right\"] ;\n" + + " UUID [label=<
StatementPattern
Cost estimate1
Result size estimate4
> shape=plaintext];" + + "\n" + + + " UUID -> UUID [label=\"index 0\"] ;\n" + + " UUID -> UUID [label=\"index 1\"] ;\n" + + " UUID -> UUID [label=\"index 2\"] ;\n" + + " UUID [label=<
Var (name=a)
> shape=plaintext];" + + "\n" + + + " UUID [label=<
Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)
> shape=plaintext];" + + "\n" + + + " UUID [label=<
Var (name=d)
> shape=plaintext];" + + "\n" + + + " UUID [label=<
Filter
> shape=plaintext];" + + "\n" + + + " UUID -> UUID [label=\"left\"] ;\n" + + " UUID -> UUID [label=\"right\"] ;\n" + + " UUID [label=<
Compare (!=)
> shape=plaintext];" + + "\n" + + + " UUID -> UUID [label=\"left\"] ;\n" + + " UUID -> UUID [label=\"right\"] ;\n" + + " UUID [label=<
Var (name=c)
> shape=plaintext];" + + "\n" + + + " UUID [label=<
Var (name=d)
> shape=plaintext];" + + "\n" + + + " UUID [label=<
Join
AlgorithmHashJoinIteration
> shape=plaintext];" + + "\n" + + + " UUID -> UUID [label=\"left\"] ;\n" + + " UUID -> UUID [label=\"right\"] ;\n" + + " UUID [label=<
Filter
> shape=plaintext];" + + "\n" + + + " UUID -> UUID [label=\"left\"] ;\n" + + " UUID -> UUID [label=\"right\"] ;\n" + + " UUID [label=<
Compare (!=)
> shape=plaintext];" + + "\n" + + + " UUID -> UUID [label=\"left\"] ;\n" + + " UUID -> UUID [label=\"right\"] ;\n" + + " UUID [label=<
Var (name=c)
> shape=plaintext];" + + "\n" + + + " UUID [label=<
ValueConstant (value="<")
> shape=plaintext];" + + "\n" + + + " UUID [label=<
StatementPattern
Cost estimate2
Result size estimate4
> shape=plaintext];" + + "\n" + + + " UUID -> UUID [label=\"index 0\"] ;\n" + + " UUID -> UUID [label=\"index 1\"] ;\n" + + " UUID -> UUID [label=\"index 2\"] ;\n" + + " UUID [label=<
Var (name=a)
> shape=plaintext];" + + "\n" + + + " UUID [label=<
Var (name=_const_f5e5585a_uri, value=http://www.w3.org/1999/02/22-rdf-syntax-ns#type, anonymous)
> shape=plaintext];" + + "\n" + + + " UUID [label=<
Var (name=c)
> shape=plaintext];" + + "\n" + + + " subgraph cluster_UUID {\n" + + " color=grey\n" + + "UUID [label=<
LeftJoin
New scopetrue
Cost estimate5
Result size estimate12
> shape=plaintext];" + + "\n" + + + " UUID -> UUID [label=\"left\"] ;\n" + + " UUID -> UUID [label=\"right\"] ;\n" + + " UUID [label=<
SingletonSet
> shape=plaintext];" + + "\n" + + + " UUID [label=<
StatementPattern
Result size estimate12
> shape=plaintext];" + + "\n" + + + " UUID -> UUID [label=\"index 0\"] ;\n" + + " UUID -> UUID [label=\"index 1\"] ;\n" + + " UUID -> UUID [label=\"index 2\"] ;\n" + + " UUID [label=<
Var (name=d)
> shape=plaintext];" + + "\n" + + + " UUID [label=<
Var (name=e)
> shape=plaintext];" + + "\n" + + + " UUID [label=<
Var (name=f)
> shape=plaintext];" + + "\n" + + + "\n" + + "}\n" + + " UUID [label=<
StatementPattern
Result size estimate12
> shape=plaintext];" + + "\n" + + + " UUID -> UUID [label=\"index 0\"] ;\n" + + " UUID -> UUID [label=\"index 1\"] ;\n" + + " UUID -> UUID [label=\"index 2\"] ;\n" + + " UUID [label=<
Var (name=d)
> shape=plaintext];" + + "\n" + + + " UUID [label=<
Var (name=e)
> shape=plaintext];" + + "\n" + + + " UUID [label=<
Var (name=f)
> shape=plaintext];" + + "\n" + + + "\n" + + "}\n"; assertThat(actual).isEqualToNormalizingNewlines(expected); }