Skip to content

Commit 7a1e9de

Browse files
committed
Allow TDB datasets to be opened in read-only mode
1 parent 42d1138 commit 7a1e9de

2 files changed

Lines changed: 54 additions & 16 deletions

File tree

src/ubic/basecode/ontology/jena/OntologyLoader.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import com.hp.hpl.jena.rdf.model.*;
2626
import com.hp.hpl.jena.shared.CannotCreateException;
2727
import com.hp.hpl.jena.shared.JenaException;
28-
import com.hp.hpl.jena.tdb.TDBFactory;
28+
import com.hp.hpl.jena.sparql.graph.GraphReadOnly;
2929
import org.apache.commons.io.FileUtils;
3030
import org.apache.commons.lang3.StringUtils;
3131
import org.apache.commons.lang3.time.StopWatch;
@@ -85,6 +85,16 @@ static OntModel createMemoryModel( String url, String name, @Nullable String cac
8585
return model;
8686
}
8787

88+
/**
89+
* ModelFactory.createMemModelMaker()
90+
* Get model that is entirely in memory.
91+
*/
92+
private static OntModel getModel( String name, boolean processImports, OntModelSpec spec ) {
93+
ModelMaker maker = ModelFactory.createMemModelMaker();
94+
Model base = maker.createModel( name, false );
95+
return getModel( maker, base, processImports, spec );
96+
}
97+
8898
private static void readModelFromUrl( OntModel model, String url, @Nullable String cacheName ) throws IOException {
8999
boolean attemptToLoadFromDisk = false;
90100
URLConnection urlc = null;
@@ -165,7 +175,7 @@ private static void readModelFromUrl( OntModel model, String url, @Nullable Stri
165175
* contains all the necessary definitions.
166176
* @param spec spec to use to create the ontology model
167177
*/
168-
public static OntModel createTdbModel( Dataset dataset, @Nullable String name, boolean processImports, OntModelSpec spec ) {
178+
public static OntModel createTdbModel( Dataset dataset, @Nullable String name, boolean processImports, OntModelSpec spec, boolean readOnly ) {
169179
ModelMaker maker = ModelFactory.createMemModelMaker();
170180
Model base;
171181
if ( name != null ) {
@@ -177,16 +187,9 @@ public static OntModel createTdbModel( Dataset dataset, @Nullable String name, b
177187
throw new IllegalStateException( String.format( "The %s at %s is empty.",
178188
name != null ? "named model " + name : "default model", dataset ) );
179189
}
180-
return getModel( maker, base, processImports, spec );
181-
}
182-
183-
/**
184-
* ModelFactory.createMemModelMaker()
185-
* Get model that is entirely in memory.
186-
*/
187-
private static OntModel getModel( String name, boolean processImports, OntModelSpec spec ) {
188-
ModelMaker maker = ModelFactory.createMemModelMaker();
189-
Model base = maker.createModel( name, false );
190+
if ( readOnly ) {
191+
base = ModelFactory.createModelForGraph( new GraphReadOnly( base.getGraph() ) );
192+
}
190193
return getModel( maker, base, processImports, spec );
191194
}
192195

src/ubic/basecode/ontology/jena/TdbOntologyService.java

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@
22

33
import com.hp.hpl.jena.query.Dataset;
44
import com.hp.hpl.jena.tdb.TDBFactory;
5+
import org.apache.commons.io.file.PathUtils;
56
import ubic.basecode.ontology.model.OntologyModel;
67

78
import javax.annotation.Nullable;
9+
import java.io.IOException;
810
import java.io.InputStream;
11+
import java.nio.file.Files;
912
import java.nio.file.Path;
13+
import java.util.Set;
14+
import java.util.stream.Collectors;
15+
import java.util.stream.Stream;
1016

1117
/**
1218
* An implementation based on Jena TDB.
@@ -16,22 +22,48 @@ public class TdbOntologyService extends AbstractOntologyService {
1622

1723
private final Path tdbDir;
1824
private final String modelName;
25+
private final boolean readOnly;
1926

2027
@Nullable
2128
private Dataset dataset;
2229

23-
public TdbOntologyService( String ontologyName, Path tdbDir, @Nullable String modelName, boolean ontologyEnabled, @Nullable String cacheName ) {
30+
/**
31+
* Temporary d
32+
*/
33+
private Path tempDir;
34+
35+
/**
36+
* @param readOnly open the TDB database in read-only mode, allowing multiple JVMs to share a common TDB. For this
37+
* to work safely, all the TDB files must not be writable. Additionally, a temporary directory with
38+
* symbolic links will be created since Jena will still be using a lock file.
39+
*/
40+
public TdbOntologyService( String ontologyName, Path tdbDir, @Nullable String modelName, boolean ontologyEnabled, @Nullable String cacheName, boolean readOnly ) {
2441
super( ontologyName, tdbDir.toUri().toString(), ontologyEnabled, cacheName );
2542
this.tdbDir = tdbDir;
2643
this.modelName = modelName;
44+
this.readOnly = readOnly;
2745
}
2846

2947
@Override
30-
protected OntologyModel loadModel( boolean processImports, LanguageLevel languageLevel, InferenceMode inferenceMode ) {
48+
protected OntologyModel loadModel( boolean processImports, LanguageLevel languageLevel, InferenceMode inferenceMode ) throws IOException {
3149
if ( dataset == null ) {
32-
dataset = TDBFactory.createDataset( tdbDir.toString() );
50+
if ( readOnly ) {
51+
Set<Path> filesToLink;
52+
try ( Stream<Path> z = Files.list( tdbDir ) ) {
53+
filesToLink = z.collect( Collectors.toSet() );
54+
}
55+
tempDir = Files.createTempDirectory( getOntologyName() + ".tdb" );
56+
for ( Path p : filesToLink ) {
57+
Files.createSymbolicLink( tempDir.resolve( p.getFileName() ), p );
58+
}
59+
log.info( "Reading read-only TDB model from {}.", tempDir );
60+
dataset = TDBFactory.createDataset( tempDir.toString() );
61+
62+
} else {
63+
dataset = TDBFactory.createDataset( tdbDir.toString() );
64+
}
3365
}
34-
return new OntologyModelImpl( OntologyLoader.createTdbModel( dataset, modelName, processImports, getSpec( languageLevel, inferenceMode ) ) );
66+
return new OntologyModelImpl( OntologyLoader.createTdbModel( dataset, modelName, processImports, getSpec( languageLevel, inferenceMode ), readOnly ) );
3567
}
3668

3769
@Override
@@ -47,6 +79,9 @@ public void close() throws Exception {
4779
if ( dataset != null ) {
4880
TDBFactory.release( dataset );
4981
}
82+
if ( tempDir != null ) {
83+
PathUtils.delete( tempDir );
84+
}
5085
}
5186
}
5287
}

0 commit comments

Comments
 (0)