Skip to content

Commit b663a61

Browse files
committed
GH-4950 LMDB: add shared properties file for meta data
1 parent 99cf01d commit b663a61

9 files changed

Lines changed: 244 additions & 190 deletions

File tree

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,8 @@ abstract static class StatefulOperation implements Operation {
240240
/**
241241
* Creates a new {@link LmdbSailStore}.
242242
*/
243-
public LmdbSailStore(File dataDir, LmdbStoreConfig config) throws IOException, SailException {
243+
public LmdbSailStore(File dataDir, StoreProperties properties, LmdbStoreConfig config)
244+
throws IOException, SailException {
244245
this.setFactory = new PersistentSetFactory<>(dataDir);
245246
this.bulkOperationSize = config.getBulkOperationSize();
246247
Function<Long, byte[]> encode = element -> {
@@ -254,9 +255,9 @@ public LmdbSailStore(File dataDir, LmdbStoreConfig config) throws IOException, S
254255
boolean initialized = false;
255256
try {
256257
namespaceStore = new NamespaceStore(dataDir);
257-
var valueStore = new ValueStore(new File(dataDir, "values"), config);
258+
var valueStore = new ValueStore(new File(dataDir, "values"), properties, config);
258259
this.valueStore = valueStore;
259-
tripleStore = new TripleStore(new File(dataDir, "triples"), config, valueStore);
260+
tripleStore = new TripleStore(new File(dataDir, "triples"), properties, config, valueStore);
260261
mayHaveInferred = tripleStore.hasTriples(false);
261262
initialized = true;
262263
} finally {

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

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,26 @@
1212

1313
import java.io.File;
1414
import java.io.IOException;
15-
import java.nio.charset.StandardCharsets;
1615
import java.nio.file.Files;
1716
import java.nio.file.Path;
1817
import java.util.Comparator;
1918
import java.util.concurrent.locks.ReentrantLock;
2019
import java.util.function.Supplier;
2120
import java.util.stream.Stream;
2221

23-
import org.apache.commons.io.FileUtils;
2422
import org.eclipse.rdf4j.collection.factory.api.CollectionFactory;
2523
import org.eclipse.rdf4j.collection.factory.mapdb.MapDb3CollectionFactory;
2624
import org.eclipse.rdf4j.common.annotation.Experimental;
2725
import org.eclipse.rdf4j.common.concurrent.locks.Lock;
2826
import org.eclipse.rdf4j.common.concurrent.locks.LockManager;
29-
import org.eclipse.rdf4j.common.io.MavenUtil;
3027
import org.eclipse.rdf4j.common.transaction.IsolationLevel;
3128
import org.eclipse.rdf4j.common.transaction.IsolationLevels;
3229
import org.eclipse.rdf4j.model.ValueFactory;
3330
import org.eclipse.rdf4j.query.algebra.evaluation.EvaluationStrategy;
3431
import org.eclipse.rdf4j.query.algebra.evaluation.EvaluationStrategyFactory;
3532
import org.eclipse.rdf4j.query.algebra.evaluation.federation.FederatedServiceResolver;
3633
import org.eclipse.rdf4j.query.algebra.evaluation.federation.FederatedServiceResolverClient;
37-
import org.eclipse.rdf4j.query.algebra.evaluation.impl.StrictEvaluationStrategyFactory;
34+
import org.eclipse.rdf4j.query.algebra.evaluation.impl.DefaultEvaluationStrategyFactory;
3835
import org.eclipse.rdf4j.repository.sparql.federation.SPARQLServiceResolver;
3936
import org.eclipse.rdf4j.sail.InterruptedSailException;
4037
import org.eclipse.rdf4j.sail.NotifyingSailConnection;
@@ -62,8 +59,10 @@ public class LmdbStore extends AbstractNotifyingSail implements FederatedService
6259
/*-----------*
6360
* Variables *
6461
*-----------*/
65-
66-
private static final String VERSION = MavenUtil.loadVersion("org.eclipse.rdf4j", "rdf4j-sail-lmdb", "devel");
62+
/**
63+
* The current version of the LMDB store.
64+
*/
65+
static final int VERSION = 2;
6766

6867
/**
6968
* Specifies which triple indexes this lmdb store must use.
@@ -169,7 +168,7 @@ public void setDataDir(File dataDir) {
169168
*/
170169
public synchronized EvaluationStrategyFactory getEvaluationStrategyFactory() {
171170
if (evalStratFactory == null) {
172-
evalStratFactory = new StrictEvaluationStrategyFactory(getFederatedServiceResolver());
171+
evalStratFactory = new DefaultEvaluationStrategyFactory(getFederatedServiceResolver());
173172
}
174173
evalStratFactory.setQuerySolutionCacheThreshold(getIterationCacheSyncThreshold());
175174
evalStratFactory.setTrackResultSize(isTrackResultSize());
@@ -252,18 +251,33 @@ protected void initializeInternal() throws SailException {
252251
logger.debug("Data dir is " + dataDir);
253252

254253
try {
255-
File versionFile = new File(dataDir, "lmdbrdf.ver");
256-
String version = versionFile.exists() ? FileUtils.readFileToString(versionFile, StandardCharsets.UTF_8)
257-
: null;
258-
if (!VERSION.equals(version) && upgradeStore(dataDir, version)) {
259-
FileUtils.writeStringToFile(versionFile, VERSION, StandardCharsets.UTF_8);
254+
StoreProperties properties = new StoreProperties(dataDir);
255+
// ensure that it is an error if an unsupported version of LmdbStore already exists
256+
if (new File(dataDir, "lmdbrdf.ver").exists()) {
257+
throw new SailException("Directory contains data from an older unsupported version of LmdbStore");
258+
}
259+
boolean updateVersion = false;
260+
if (properties.load()) {
261+
if (!String.valueOf(VERSION).equals(properties.getVersion())) {
262+
updateVersion = upgradeStore(dataDir, properties.getVersion());
263+
}
264+
} else {
265+
properties.setVersion(String.valueOf(VERSION));
260266
}
261-
backingStore = new LmdbSailStore(dataDir, config);
262-
this.store = new SnapshotSailStore(backingStore, () -> new MemoryOverflowModel() {
267+
268+
backingStore = new LmdbSailStore(dataDir, properties, config);
269+
270+
// update version afer loading and potential internal migration within value and triple store
271+
if (updateVersion) {
272+
properties.setVersion(String.valueOf(VERSION));
273+
}
274+
properties.save();
275+
276+
this.store = new SnapshotSailStore(backingStore, () -> new MemoryOverflowModel(false) {
263277
@Override
264278
protected LmdbSailStore createSailStore(File dataDir) throws IOException, SailException {
265279
// Model can't fit into memory, use another LmdbSailStore to store delta
266-
LmdbSailStore lmdbSailStore = new LmdbSailStore(dataDir, config);
280+
LmdbSailStore lmdbSailStore = new LmdbSailStore(dataDir, new StoreProperties(), config);
267281
lmdbSailStore.enableMultiThreading = false;
268282
return lmdbSailStore;
269283
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
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+
package org.eclipse.rdf4j.sail.lmdb;
12+
13+
import java.io.File;
14+
import java.io.FileInputStream;
15+
import java.io.FileOutputStream;
16+
import java.io.IOException;
17+
import java.io.InputStream;
18+
import java.io.OutputStream;
19+
import java.util.Optional;
20+
import java.util.Properties;
21+
22+
class StoreProperties {
23+
/**
24+
* The file name for the properties file.
25+
*/
26+
static final String FILE_NAME = "store.properties";
27+
28+
/**
29+
* The key used to store the triple store version in the properties file.
30+
*/
31+
static final String VERSION_KEY = "version";
32+
/**
33+
* The key used to store the triple indexes specification that specifies which triple indexes exist.
34+
*/
35+
static final String INDEXES_KEY = "triple-indexes";
36+
37+
protected final Optional<File> propertiesFile;
38+
39+
protected String version;
40+
41+
protected String tripleIndexes;
42+
43+
protected boolean loaded;
44+
45+
protected boolean dirty;
46+
47+
StoreProperties() {
48+
this.propertiesFile = Optional.empty();
49+
}
50+
51+
StoreProperties(File dir) {
52+
this.propertiesFile = Optional.of(new File(dir, FILE_NAME));
53+
}
54+
55+
/**
56+
* Load from properties file.
57+
*
58+
* @return <code>true</code> if loaded from file, else <code>false</code>
59+
*/
60+
boolean load() {
61+
propertiesFile.filter(File::isFile).ifPresent(file -> {
62+
Properties properties = new Properties();
63+
try (InputStream in = new FileInputStream(file)) {
64+
properties.load(in);
65+
} catch (IOException e) {
66+
throw new IllegalStateException("Unable to load store properties from " + file, e);
67+
}
68+
version = properties.getProperty(VERSION_KEY);
69+
tripleIndexes = properties.getProperty(INDEXES_KEY);
70+
loaded = true;
71+
});
72+
return loaded;
73+
}
74+
75+
/**
76+
* Save to properties file.
77+
*/
78+
void save() {
79+
if (!dirty) {
80+
return;
81+
}
82+
propertiesFile.ifPresent(file -> {
83+
Properties properties = new Properties();
84+
if (version != null) {
85+
properties.setProperty(VERSION_KEY, version);
86+
}
87+
if (tripleIndexes != null) {
88+
properties.setProperty(INDEXES_KEY, tripleIndexes);
89+
}
90+
File parent = file.getParentFile();
91+
if (parent != null) {
92+
parent.mkdirs();
93+
}
94+
try (OutputStream out = new FileOutputStream(file)) {
95+
properties.store(out, "LmdbStore meta-data");
96+
dirty = false;
97+
} catch (IOException e) {
98+
throw new IllegalStateException("Unable to store properties to " + file, e);
99+
}
100+
});
101+
}
102+
103+
boolean isLoaded() {
104+
return loaded;
105+
}
106+
107+
String getVersion() {
108+
return version;
109+
}
110+
111+
StoreProperties setVersion(String version) {
112+
this.version = version;
113+
this.dirty = true;
114+
return this;
115+
}
116+
117+
String getTripleIndexes() {
118+
return tripleIndexes;
119+
}
120+
121+
StoreProperties setTripleIndexes(String tripleIndexes) {
122+
this.tripleIndexes = tripleIndexes;
123+
this.dirty = true;
124+
return this;
125+
}
126+
}

0 commit comments

Comments
 (0)