Skip to content

Commit 83b6bbe

Browse files
committed
GH-5553 Lazily compute LMDB index names on demand
1 parent a817430 commit 83b6bbe

6 files changed

Lines changed: 67 additions & 11 deletions

File tree

core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/impl/evaluationsteps/StatementPatternQueryEvaluationStep.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,8 @@ private JoinStatementWithBindingSetIterator getIteration(BindingSet bindings) {
276276
}
277277

278278
if (iteration instanceof IndexReportingIterator) {
279-
String indexName = ((IndexReportingIterator) iteration).getIndexName();
280-
statementPattern.setIndexName(indexName);
279+
statementPattern.setIndexNameSupplier(
280+
((IndexReportingIterator) iteration)::getIndexName);
281281
} else {
282282
statementPattern.setIndexName(null);
283283
}
@@ -332,8 +332,8 @@ private ConvertStatementToBindingSetIterator getIteration() {
332332
iteration = tripleSource.getStatements((Resource) subject, (IRI) predicate, object, contexts);
333333
}
334334
if (iteration instanceof IndexReportingIterator) {
335-
String indexName = ((IndexReportingIterator) iteration).getIndexName();
336-
statementPattern.setIndexName(indexName);
335+
statementPattern.setIndexNameSupplier(
336+
((IndexReportingIterator) iteration)::getIndexName);
337337
} else {
338338
statementPattern.setIndexName(null);
339339
}

core/queryalgebra/model/src/main/java/org/eclipse/rdf4j/query/algebra/StatementPattern.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.util.List;
1919
import java.util.Objects;
2020
import java.util.Set;
21+
import java.util.function.Supplier;
2122
import java.util.stream.Collectors;
2223

2324
import org.eclipse.rdf4j.common.annotation.Experimental;
@@ -65,6 +66,7 @@ public enum Scope {
6566
private StatementOrder statementOrder;
6667

6768
private String indexName;
69+
private transient Supplier<String> indexNameSupplier;
6870

6971
private Set<String> assuredBindingNames;
7072
private List<Var> varList;
@@ -537,11 +539,22 @@ public Var getOrder() {
537539

538540
@Experimental
539541
public String getIndexName() {
542+
if (indexNameSupplier != null) {
543+
indexName = indexNameSupplier.get();
544+
indexNameSupplier = null;
545+
}
540546
return indexName;
541547
}
542548

543549
@Experimental
544550
public void setIndexName(String indexName) {
545551
this.indexName = indexName;
552+
this.indexNameSupplier = null;
553+
}
554+
555+
@Experimental
556+
public void setIndexNameSupplier(Supplier<String> indexNameSupplier) {
557+
this.indexNameSupplier = indexNameSupplier;
558+
this.indexName = null;
546559
}
547560
}

core/queryalgebra/model/src/main/java/org/eclipse/rdf4j/query/algebra/helpers/QueryModelTreeToGenericPlanNode.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.eclipse.rdf4j.query.algebra.BinaryTupleOperator;
1818
import org.eclipse.rdf4j.query.algebra.QueryModelNode;
1919
import org.eclipse.rdf4j.query.algebra.QueryRoot;
20+
import org.eclipse.rdf4j.query.algebra.StatementPattern;
2021
import org.eclipse.rdf4j.query.algebra.VariableScopeChange;
2122
import org.eclipse.rdf4j.query.explanation.GenericPlanNode;
2223

@@ -44,6 +45,9 @@ public GenericPlanNode getGenericPlanNode() {
4445

4546
@Override
4647
protected void meetNode(QueryModelNode node) {
48+
if (node instanceof StatementPattern) {
49+
((StatementPattern) node).getIndexName();
50+
}
4751
GenericPlanNode genericPlanNode = new GenericPlanNode(node.getSignature());
4852
genericPlanNode.setCostEstimate(node.getCostEstimate());
4953
genericPlanNode.setResultSizeEstimate(node.getResultSizeEstimate());

core/sail/lmdb/src/main/java/org/eclipse/rdf4j/sail/lmdb/LmdbRecordIterator.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class LmdbRecordIterator implements RecordIterator {
5454

5555
private final TripleIndex index;
5656

57-
private final String indexName;
57+
private volatile String indexName;
5858

5959
private final long subj;
6060
private final long pred;
@@ -109,7 +109,6 @@ class LmdbRecordIterator implements RecordIterator {
109109
this.keyData = pool.getVal();
110110
this.valueData = pool.getVal();
111111
this.index = index;
112-
this.indexName = computeIndexName(index, subj, pred, obj, context);
113112
if (rangeSearch) {
114113
minKeyBuf = pool.getKeyBuffer();
115114
index.getMinKey(minKeyBuf, subj, pred, obj, context);
@@ -537,7 +536,17 @@ public long[] next() {
537536

538537
@Override
539538
public String getIndexName() {
540-
return indexName;
539+
String current = indexName;
540+
if (current == null) {
541+
synchronized (this) {
542+
current = indexName;
543+
if (current == null) {
544+
current = computeIndexName(index, subj, pred, obj, context);
545+
indexName = current;
546+
}
547+
}
548+
}
549+
return current;
541550
}
542551

543552
private boolean matches() {

core/sail/lmdb/src/main/java/org/eclipse/rdf4j/sail/lmdb/LmdbStatementIterator.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ class LmdbStatementIterator extends AbstractCloseableIteration<Statement> implem
3636
private final ValueStore valueStore;
3737
private Statement nextElement;
3838

39-
private final String indexName;
40-
4139
/*--------------*
4240
* Constructors *
4341
*--------------*/
@@ -48,7 +46,6 @@ class LmdbStatementIterator extends AbstractCloseableIteration<Statement> implem
4846
public LmdbStatementIterator(RecordIterator recordIt, ValueStore valueStore) {
4947
this.recordIt = recordIt;
5048
this.valueStore = valueStore;
51-
this.indexName = recordIt.getIndexName();
5249
}
5350

5451
/*---------*
@@ -142,6 +139,6 @@ public void remove() {
142139

143140
@Override
144141
public String getIndexName() {
145-
return indexName;
142+
return recordIt.getIndexName();
146143
}
147144
}

core/sail/lmdb/src/test/java/org/eclipse/rdf4j/sail/lmdb/LmdbExplainIndexRecommendationTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,22 @@ void recommendationPrefersIndexesWithHigherDemand() {
9999
assertThat(plan).contains("(scan; consider opcs)");
100100
}
101101

102+
@Test
103+
void trackerRemainsEmptyUntilIndexNameRequested() {
104+
runSelectQuery("psoc", PERSON_QUERY, connection -> connection.add(
105+
connection.getValueFactory().createIRI("http://example.com/alice"), RDF.TYPE, FOAF.PERSON));
106+
107+
ConcurrentMap<String, LongAdder> tracked = LmdbRecordIterator.getRecommendedIndexTracker();
108+
assertThat(tracked).isEmpty();
109+
110+
String plan = runExplainQuery("psoc", PERSON_QUERY, connection -> {
111+
connection.add(connection.getValueFactory().createIRI("http://example.com/bob"), RDF.TYPE, FOAF.PERSON);
112+
});
113+
114+
assertThat(plan).contains("(scan; consider posc)");
115+
assertThat(tracked).isNotEmpty();
116+
}
117+
102118
private static Stream<Arguments> allTripleIndexPermutations() {
103119
List<String> permutations = new ArrayList<>();
104120
permute("spoc".toCharArray(), new boolean[4], new StringBuilder(), permutations);
@@ -141,6 +157,23 @@ private String runExplainQuery(String index, String query, RepositoryConnectionC
141157
}
142158
}
143159

160+
private void runSelectQuery(String index, String query, RepositoryConnectionConsumer consumer) {
161+
File storeDir = new File(dataDir, index + "-select-" + query.hashCode() + "-" + System.nanoTime());
162+
storeDir.mkdirs();
163+
164+
SailRepository repository = new SailRepository(new LmdbStore(storeDir, new LmdbStoreConfig(index)));
165+
repository.init();
166+
167+
try (SailRepositoryConnection connection = repository.getConnection()) {
168+
consumer.accept(connection);
169+
connection.prepareTupleQuery(query).evaluate().close();
170+
} catch (RepositoryException e) {
171+
throw new RuntimeException(e);
172+
} finally {
173+
repository.shutDown();
174+
}
175+
}
176+
144177
@FunctionalInterface
145178
private interface RepositoryConnectionConsumer {
146179
void accept(SailRepositoryConnection connection) throws RepositoryException;

0 commit comments

Comments
 (0)