Skip to content

Commit f4b189d

Browse files
committed
GH-4950 LMDB: fix filtering of unused ids
1 parent fcfda9d commit f4b189d

2 files changed

Lines changed: 127 additions & 11 deletions

File tree

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

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -594,8 +594,6 @@ protected void filterUsedIds(Collection<Long> ids) throws IOException {
594594
// TODO currently this does not test for contexts (component == 3)
595595
// because in most cases context indexes do not exist
596596
for (int component = 0; component <= 2; component++) {
597-
int c = component;
598-
599597
TripleIndex index = getBestIndex(component == 0 ? 1 : -1, component == 1 ? 1 : -1,
600598
component == 2 ? 1 : -1, component == 3 ? 1 : -1);
601599

@@ -632,19 +630,14 @@ protected void filterUsedIds(Collection<Long> ids) throws IOException {
632630
if (component != 2) {
633631
// optimization: ensure that literals are only tested if they appear in object
634632
// position
635-
switch (ValueIds.getIdType(id)) {
636-
case ValueIds.T_URI:
637-
case ValueIds.T_BNODE:
638-
case ValueIds.T_TRIPLE:
639-
// fall through
640-
default:
641-
// id is a literal, do not test it
633+
if (ValueIds.getIdType(id) == ValueIds.T_LITERAL) {
634+
// id is a literal, don't test it
642635
continue;
643636
}
644637
}
645638

646-
long subj = c == 0 ? id : -1, pred = c == 1 ? id : -1,
647-
obj = c == 2 ? id : -1, context = c == 3 ? id : -1;
639+
long subj = component == 0 ? id : -1, pred = component == 1 ? id : -1,
640+
obj = component == 2 ? id : -1, context = component == 3 ? id : -1;
648641

649642
GroupMatcher matcher = index.createMatcher(subj, pred, obj, context);
650643

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2026 Eclipse RDF4J contributors.
3+
*
4+
* All rights reserved. This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Distribution License v1.0
6+
* which accompanies this distribution, and is available at
7+
* http://www.eclipse.org/org/documents/edl-v10.php.
8+
*
9+
* SPDX-License-Identifier: BSD-3-Clause
10+
*******************************************************************************/
11+
12+
package org.eclipse.rdf4j.sail.lmdb;
13+
14+
import static org.junit.jupiter.api.Assertions.assertEquals;
15+
import static org.junit.jupiter.api.Assertions.assertTrue;
16+
17+
import java.io.File;
18+
import java.io.IOException;
19+
import java.util.List;
20+
21+
import org.eclipse.rdf4j.common.iteration.Iterations;
22+
import org.eclipse.rdf4j.common.transaction.IsolationLevels;
23+
import org.eclipse.rdf4j.model.IRI;
24+
import org.eclipse.rdf4j.model.Resource;
25+
import org.eclipse.rdf4j.model.Statement;
26+
import org.eclipse.rdf4j.model.ValueFactory;
27+
import org.eclipse.rdf4j.model.vocabulary.FOAF;
28+
import org.eclipse.rdf4j.model.vocabulary.RDF;
29+
import org.eclipse.rdf4j.repository.sail.SailRepository;
30+
import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection;
31+
import org.eclipse.rdf4j.sail.lmdb.config.LmdbStoreConfig;
32+
import org.junit.jupiter.api.AfterAll;
33+
import org.junit.jupiter.api.BeforeAll;
34+
import org.junit.jupiter.api.Test;
35+
import org.junit.rules.TemporaryFolder;
36+
37+
/**
38+
* Tests that values and statements correctly exists after (partial) removal and addition.
39+
*/
40+
public class RemoveAddTest {
41+
42+
private static SailRepository repository;
43+
44+
public static TemporaryFolder tempDir = new TemporaryFolder();
45+
static List<Statement> statementList;
46+
47+
@BeforeAll
48+
public static void beforeClass() throws IOException {
49+
tempDir.create();
50+
File file = tempDir.newFolder();
51+
52+
LmdbStoreConfig config = new LmdbStoreConfig("spoc,ospc,psoc");
53+
repository = new SailRepository(new LmdbStore(file, config));
54+
}
55+
56+
@AfterAll
57+
public static void afterClass() {
58+
repository.shutDown();
59+
tempDir.delete();
60+
tempDir = null;
61+
repository = null;
62+
statementList = null;
63+
}
64+
65+
@Test
66+
public void removeAndAdd() {
67+
IRI alice;
68+
IRI bob;
69+
int expectedTypeStatements;
70+
71+
try (SailRepositoryConnection connection = repository.getConnection()) {
72+
connection.begin(IsolationLevels.NONE);
73+
74+
ValueFactory vf = connection.getValueFactory();
75+
alice = vf.createIRI("urn:person:alice");
76+
bob = vf.createIRI("urn:person:bob");
77+
78+
connection.add(alice, RDF.TYPE, FOAF.PERSON);
79+
connection.add(alice, FOAF.NAME, vf.createLiteral("Alice"));
80+
connection.add(alice, FOAF.AGE, vf.createLiteral(34));
81+
connection.add(alice, FOAF.MBOX, vf.createIRI("mailto:alice@example.org"));
82+
connection.add(alice, FOAF.KNOWS, bob);
83+
84+
connection.add(bob, RDF.TYPE, FOAF.PERSON);
85+
connection.add(bob, FOAF.NAME, vf.createLiteral("Bob"));
86+
connection.add(bob, FOAF.AGE, vf.createLiteral(29));
87+
connection.add(bob, FOAF.MBOX, vf.createIRI("mailto:bob@example.org"));
88+
89+
connection.commit();
90+
91+
expectedTypeStatements = Iterations.asList(connection.getStatements(null, RDF.TYPE, null, false)).size();
92+
}
93+
94+
try (SailRepositoryConnection connection = repository.getConnection()) {
95+
statementList = Iterations.asList(connection.getStatements(null, RDF.TYPE, null, false));
96+
}
97+
98+
try (SailRepositoryConnection connection = repository.getConnection()) {
99+
connection.begin(IsolationLevels.NONE);
100+
connection.remove((Resource) null, RDF.TYPE, null);
101+
connection.commit();
102+
connection.begin(IsolationLevels.NONE);
103+
connection.add(statementList);
104+
connection.commit();
105+
}
106+
107+
try (SailRepositoryConnection connection = repository.getConnection()) {
108+
int typeStatementsAfterRestore = Iterations
109+
.asList(connection.getStatements(null, RDF.TYPE, null, false))
110+
.size();
111+
112+
assertEquals(expectedTypeStatements, typeStatementsAfterRestore,
113+
"rdf:type statements should be restored after remove-and-add");
114+
assertTrue(connection.hasStatement(alice, RDF.TYPE, FOAF.PERSON, false));
115+
assertTrue(connection.hasStatement(alice, FOAF.NAME, null, false));
116+
assertTrue(connection.hasStatement(alice, FOAF.AGE, null, false));
117+
assertTrue(connection.hasStatement(alice, FOAF.KNOWS, bob, false));
118+
assertTrue(connection.hasStatement(bob, RDF.TYPE, FOAF.PERSON, false));
119+
assertTrue(connection.hasStatement(bob, FOAF.NAME, null, false));
120+
assertTrue(connection.hasStatement(bob, FOAF.AGE, null, false));
121+
}
122+
}
123+
}

0 commit comments

Comments
 (0)