From d670bba34ac01e6925afed58e5b667f96927b348 Mon Sep 17 00:00:00 2001 From: Andreas Schwarte Date: Tue, 31 Oct 2023 10:25:28 +0100 Subject: [PATCH] GH-4785: unit test for timeout / deadlock in FedX Join This commit provides a unit test that reproduces a deadlock scenario. The issue is somewhere caused in the join with NUnion, and specifically the union parts having relevant statements in multiple sources. Note that the dataset is really small (42 triples, 40 relevant ones contributing to the result) --- .../rdf4j/federated/LargeJoinTest.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/LargeJoinTest.java b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/LargeJoinTest.java index 8bd5b42ca80..b9f80afb542 100644 --- a/tools/federation/src/test/java/org/eclipse/rdf4j/federated/LargeJoinTest.java +++ b/tools/federation/src/test/java/org/eclipse/rdf4j/federated/LargeJoinTest.java @@ -23,6 +23,7 @@ import org.eclipse.rdf4j.model.vocabulary.FOAF; import org.eclipse.rdf4j.model.vocabulary.RDF; import org.eclipse.rdf4j.model.vocabulary.RDFS; +import org.eclipse.rdf4j.model.vocabulary.SKOS; import org.eclipse.rdf4j.query.BindingSet; import org.eclipse.rdf4j.query.TupleQuery; import org.eclipse.rdf4j.repository.Repository; @@ -122,6 +123,76 @@ public void testWithLocalRepositoryManager() throws Exception { } + @Test + public void testJoinWithNUnion() throws Exception { + + int N_LEFT_SIZE = 20; + + addNativeStore("repo1"); + addNativeStore("repo2"); + + try (RepositoryConnection conn = repoManager.getRepository("repo1").getConnection()) { + for (int i = 0; i < N_LEFT_SIZE; i++) { + conn.add(Values.iri("http://example.com/p" + i), RDF.TYPE, FOAF.PERSON); + } + } + + // add statements for the union + try (RepositoryConnection conn = repoManager.getRepository("repo1").getConnection()) { + for (int i = 0; i < N_LEFT_SIZE; i += 2) { + conn.add(Values.iri("http://example.com/p" + i), RDFS.LABEL, Values.literal("Person " + i)); + } + + // add dummy skos:prefLabel statement to avoid exclusive group + conn.add(Values.iri("http://example.com/subj1"), SKOS.PREF_LABEL, Values.literal("Subj1")); + + } + try (RepositoryConnection conn = repoManager.getRepository("repo2").getConnection()) { + for (int i = 1; i < N_LEFT_SIZE; i += 2) { + conn.add(Values.iri("http://example.com/p" + i), SKOS.PREF_LABEL, Values.literal("Person " + i)); + } + + // add dummy rdfs:label statement to avoid exclusive group + conn.add(Values.iri("http://example.com/subj2"), RDFS.LABEL, Values.literal("Subj2")); + } + + FedXConfig config = new FedXConfig(); + config.withDebugQueryPlan(true); + + FedXRepository repo = FedXFactory.newFederation() + .withResolvableEndpoint("repo1") + .withResolvableEndpoint("repo2") + .withRepositoryResolver(repoManager) + .withConfig(config) + .create(); + + try { + repo.init(); + try (RepositoryConnection conn = repo.getConnection()) { + TupleQuery tq = conn + .prepareTupleQuery( + "PREFIX rdf: \n" + + "PREFIX rdfs: \n" + + "PREFIX skos: \n" + + "PREFIX foaf: \n" + + "SELECT * WHERE { " + + " ?person a foaf:Person ." + + " ?person rdfs:label | skos:prefLabel ?label ." + + " }" + ); + + tq.setMaxExecutionTime(2); + + List res = Iterations.asList(tq.evaluate()); + Assertions.assertEquals(N_LEFT_SIZE, res.size()); + + } + } finally { + repo.shutDown(); + } + + } + protected void addNativeStore(String repoId) throws Exception { RepositoryImplConfig implConfig = new SailRepositoryConfig(new NativeStoreConfig());