You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2017/09/28 11:08:19 UTC
[03/50] [abbrv] jena git commit: Switchable conatiner datasets
Switchable conatiner datasets
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/d72f6961
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/d72f6961
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/d72f6961
Branch: refs/heads/jena-tdb2
Commit: d72f69611db396c556281da83de90db57c0c5387
Parents: 46862c3
Author: Andy Seaborne <an...@seaborne.org>
Authored: Wed Aug 30 18:43:32 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Wed Aug 30 18:43:32 2017 +0100
----------------------------------------------------------------------
.../transaction/txn/TransactionCoordinator.java | 8 +
.../java/org/seaborne/tdb2/DatabaseMgr.java | 119 ++++++++
.../java/org/seaborne/tdb2/TDB2Factory.java | 70 ++---
.../tdb2/assembler/DatasetAssemblerTDB.java | 4 +-
.../tdb2/graph/TransactionHandlerTDB.java | 47 ++-
.../org/seaborne/tdb2/repack/DatabaseMgr.java | 171 -----------
.../tdb2/repack/DatasetGraphSwitchable.java | 165 ++++++++++-
.../java/org/seaborne/tdb2/repack/sys/IOX.java | 278 ------------------
.../org/seaborne/tdb2/setup/TDBBuilder.java | 2 -
.../org/seaborne/tdb2/store/DatasetControl.java | 44 +++
.../seaborne/tdb2/store/DatasetControlMRSW.java | 144 +++++++++
.../seaborne/tdb2/store/DatasetControlNone.java | 48 +++
.../tdb2/store/DatasetControlReadOnly.java | 59 ++++
.../seaborne/tdb2/store/DatasetPrefixesTDB.java | 8 +-
.../tdb2/store/GraphPrefixesProjectionTDB.java | 9 +-
.../java/org/seaborne/tdb2/store/GraphTDB.java | 104 +------
.../seaborne/tdb2/store/PrefixMappingCache.java | 33 ++-
.../java/org/seaborne/tdb2/store/QuadTable.java | 1 -
.../java/org/seaborne/tdb2/store/TableBase.java | 1 -
.../org/seaborne/tdb2/store/TripleTable.java | 1 -
.../nodetable/TReadAppendFileTransport.java | 2 +-
.../store/nodetupletable/NodeTupleTable.java | 2 +-
.../nodetupletable/NodeTupleTableConcrete.java | 2 +-
.../nodetupletable/NodeTupleTableWrapper.java | 2 +-
.../seaborne/tdb2/sys/ConnectionTracker.java | 23 ++
.../seaborne/tdb2/sys/DatabaseConnection.java | 164 +++++++++++
.../java/org/seaborne/tdb2/sys/DatabaseOps.java | 261 +++++++++++++++++
.../org/seaborne/tdb2/sys/DatasetControl.java | 44 ---
.../seaborne/tdb2/sys/DatasetControlMRSW.java | 146 ---------
.../tdb2/sys/DatasetControlMutable.java | 54 ----
.../seaborne/tdb2/sys/DatasetControlNone.java | 48 ---
.../tdb2/sys/DatasetControlReadOnly.java | 59 ----
.../main/java/org/seaborne/tdb2/sys/IOX.java | 293 +++++++++++++++++++
.../java/org/seaborne/tdb2/TestTDBFactory.java | 62 ++--
.../test/java/org/seaborne/tdb2/junit/TL.java | 3 +-
.../tdb2/store/TestTransPromoteTDB.java | 4 +-
36 files changed, 1462 insertions(+), 1023 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionCoordinator.java
----------------------------------------------------------------------
diff --git a/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionCoordinator.java b/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionCoordinator.java
index 56cfbac..56104bf 100644
--- a/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionCoordinator.java
+++ b/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionCoordinator.java
@@ -459,6 +459,14 @@ public class TransactionCoordinator {
Objects.nonNull(readWrite) ;
checkActive() ;
+ // XXX Flag to bounce writers fpor long term "block writers"
+ if ( false /* bounceWritersAtTheMoment */) {
+ if ( readWrite == WRITE ) {
+ throw new TransactionException("Writers currently being rejected");
+ }
+ }
+
+
if ( canBlock )
exclusivitylock.readLock().lock() ;
else {
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/DatabaseMgr.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/DatabaseMgr.java b/tdb2/src/main/java/org/seaborne/tdb2/DatabaseMgr.java
new file mode 100644
index 0000000..33a4a6b
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/DatabaseMgr.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.seaborne.tdb2;
+
+import org.apache.commons.lang3.NotImplementedException ;
+import org.apache.jena.query.Dataset ;
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.seaborne.dboe.base.file.Location ;
+import org.seaborne.tdb2.repack.DatasetGraphSwitchable ;
+import org.seaborne.tdb2.store.DatasetGraphTDB ;
+import org.seaborne.tdb2.sys.DatabaseOps ;
+import org.seaborne.tdb2.sys.StoreConnection ;
+
+/** Operations for TDBS DatasetGraph, including admin operations
+ * See {@link TDB2Factory} for creating API-level {@link Dataset Datasets}.
+ *
+ * @see TDB2Factory
+ */
+public class DatabaseMgr {
+
+ // All creation of DatasetGraph for TDB2 goes through this method.
+ private static DatasetGraph DB_ConnectCreate(Location location) {
+ //return DatabaseOps.connectOrCreate(location);
+ // One level.
+ StoreConnection sConn = StoreConnection.connectCreate(location) ;
+ return sConn.getDatasetGraph() ;
+ }
+
+ /** Create or connect to a TDB2-backed dataset */
+ public static DatasetGraph connectDatasetGraph(Location location) {
+ return DB_ConnectCreate(location);
+ }
+
+ /** Create or connect to a TDB2-backed dataset */
+ public static DatasetGraph connectDatasetGraph(String location) {
+ return connectDatasetGraph(Location.create(location)) ;
+ }
+
+ /**
+ * Compact a datasets which must be a switchable TDB database.
+ * This is the normal dataset type for on-disk TDB2 databases.
+ *
+ * @param container
+ */
+ public static void compact(DatasetGraph container) {
+ DatasetGraphSwitchable dsg = requireSwitchable(container);
+ DatabaseOps.compact(dsg);
+ }
+
+ /**
+ * Create a backup for a switchable TDB database. This is the normal dataset type for
+ * on-disk TDB2 databases.
+ * <p>
+ * The backup is created in the databases folder, under "Backups".
+ * <p>
+ * Backup creates a consistent copy og the database. It is performed as a read-transaction
+ * and does not lock out other use of the dataset.
+ *
+ * @param container
+ */
+ public static void backup(DatasetGraph container) {
+ DatasetGraphSwitchable dsg = requireSwitchable(container);
+ throw new NotImplementedException("DatasetGraph backup not implemented yet");
+ }
+
+
+ /** Create an in-memory TDB2-backed dataset (for testing) */
+ public static DatasetGraph createDatasetGraph() {
+ return connectDatasetGraph(Location.mem()) ;
+ }
+
+ /** Return the location of a dataset if it is backed by TDB, else null */
+ public static boolean isBackedByTDB(DatasetGraph datasetGraph) {
+ DatasetGraphTDB dsg = requireDirect(datasetGraph);
+ if ( dsg == null )
+ return false ;
+ return true;
+ }
+
+ /** Return the location of a DatasetGraph if it is backed by TDB, else null */
+ public static Location location(DatasetGraph datasetGraph) {
+ DatasetGraphTDB dsg = requireDirect(datasetGraph);
+ if ( dsg == null )
+ return null ;
+ return dsg.getLocation();
+ }
+
+ private static DatasetGraphSwitchable requireSwitchable(DatasetGraph datasetGraph) {
+ if ( datasetGraph instanceof DatasetGraphSwitchable )
+ return (DatasetGraphSwitchable)datasetGraph;
+ throw new TDBException("Not a switchable TDB database");
+ }
+
+ static DatasetGraphTDB requireDirect(DatasetGraph datasetGraph) {
+ DatasetGraph dsg = datasetGraph;
+ if ( datasetGraph instanceof DatasetGraphSwitchable )
+ dsg = ((DatasetGraphSwitchable)datasetGraph).get();
+ if ( datasetGraph instanceof DatasetGraphTDB )
+ return ((DatasetGraphTDB)datasetGraph);
+ throw new TDBException("Not a TDB database (argument is neither a switchable nor direct TDB DatasetGraph)");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/TDB2Factory.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/TDB2Factory.java b/tdb2/src/main/java/org/seaborne/tdb2/TDB2Factory.java
index d784fa3..93cc3d2 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/TDB2Factory.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/TDB2Factory.java
@@ -21,26 +21,20 @@ import org.apache.jena.query.Dataset ;
import org.apache.jena.query.DatasetFactory ;
import org.apache.jena.sparql.core.DatasetGraph ;
import org.seaborne.dboe.base.file.Location ;
-import org.seaborne.tdb2.store.DatasetGraphTDB;
-import org.seaborne.tdb2.sys.StoreConnection ;
-/** Public factory for connecting to and creating datasets backed by TDB2 storage */
+/**
+ * Public factory for connecting to and creating datasets backed by TDB2 storage.
+ */
public class TDB2Factory
{
private TDB2Factory() {}
- /** @deprecated Use {@link #connectDatasetGraph(Location)} */
+ /** @deprecated Use {@link DatabaseMgr#connectDatasetGraph(Location)} */
@Deprecated
public static DatasetGraph createDatasetGraph(Location location) {
- return connectDatasetGraph(location);
+ return DatabaseMgr.connectDatasetGraph(location);
}
- /** Create or connect to a TDB2-backed dataset */
- public static DatasetGraph connectDatasetGraph(Location location) {
- StoreConnection sConn = StoreConnection.connectCreate(location) ;
- return sConn.getDatasetGraph() ;
- }
-
/** @deprecated Use {@link #connectDataset(Location)} */
@Deprecated
public static Dataset createDataset(Location location) {
@@ -49,21 +43,16 @@ public class TDB2Factory
/** Create or connect to a TDB2-backed dataset */
public static Dataset connectDataset(Location location) {
- DatasetGraph dsg = connectDatasetGraph(location) ;
+ DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(location) ;
return DatasetFactory.wrap(dsg) ;
}
- /** @deprecated Use {@link #connectDatasetGraph(String)} */
+ /** @deprecated Use {@link DatabaseMgr#connectDatasetGraph(String)} */
@Deprecated
public static DatasetGraph createDatasetGraph(String location) {
- return connectDatasetGraph(location);
+ return DatabaseMgr.connectDatasetGraph(location);
}
- /** Create or connect to a TDB2-backed dataset */
- public static DatasetGraph connectDatasetGraph(String location) {
- return connectDatasetGraph(Location.create(location)) ;
- }
-
/** @deprecated Use {@link #connectDataset(String)} */
@Deprecated
public static Dataset createDataset(String location) {
@@ -74,17 +63,19 @@ public class TDB2Factory
public static Dataset connectDataset(String location) {
return connectDataset(Location.create(location)) ; }
- /** Create an in-memory TDB2-backed dataset (for testing) */
- public static DatasetGraph createDatasetGraph() {
- return connectDatasetGraph(Location.mem()) ;
- }
+ /**
+ * Create an in-memory TDB2-backed dataset (for testing). In-memory TDB2 datasets are use
+ * a simple simulation of disk I/O to give exact semantics, which is useful to create
+ * tests that run fast where setup and teardown of datasets can be the major cost.
+ * <p>
+ * In-memory TDB2 datasets are not designed to scale, nor provide efficient execution for
+ * applications for long-term use.
+ */
+ public static Dataset createDataset() { return connectDataset(Location.mem()) ; }
- /** Create an in-memory TDB2-backed dataset (for testing) */
- public static Dataset createDataset() {
- return connectDataset(Location.mem()) ;
- }
-
-// /** Read the file and assembler a dataset */
+// /**
+// * Read the file and assembler a dataset
+// */
// public static Dataset assembleDataset(String assemblerFile) {
// return (Dataset)AssemblerUtils.build(assemblerFile, VocabTDB.tDatasetTDB) ;
// }
@@ -99,31 +90,16 @@ public class TDB2Factory
// _release(location(dataset)) ;
// }
- /** Return the location of a dataset if it is backed by TDB, else null */
+ /** Tes whether a dataset is backed by TDB or not. */
public static boolean isBackedByTDB(Dataset dataset) {
DatasetGraph dsg = dataset.asDatasetGraph() ;
- return isBackedByTDB(dsg) ;
+ return DatabaseMgr.isBackedByTDB(dsg) ;
}
- /** Return the location of a dataset if it is backed by TDB, else null */
- public static boolean isBackedByTDB(DatasetGraph datasetGraph) {
- if ( datasetGraph instanceof DatasetGraphTDB )
- // A transaction or the base storage.
- return true ;
- return false ;
- }
-
/** Return the location of a dataset if it is backed by TDB, else null */
public static Location location(Dataset dataset) {
DatasetGraph dsg = dataset.asDatasetGraph() ;
- return location(dsg) ;
- }
-
- /** Return the location of a DatasetGraph if it is backed by TDB, else null */
- public static Location location(DatasetGraph datasetGraph) {
- if ( datasetGraph instanceof DatasetGraphTDB )
- return ((DatasetGraphTDB)datasetGraph).getLocation() ;
- return null ;
+ return DatabaseMgr.location(dsg) ;
}
// /** Set the {@link StoreParams} for specific Location.
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/assembler/DatasetAssemblerTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/assembler/DatasetAssemblerTDB.java b/tdb2/src/main/java/org/seaborne/tdb2/assembler/DatasetAssemblerTDB.java
index ab2ba9c..dc2d67a 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/assembler/DatasetAssemblerTDB.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/assembler/DatasetAssemblerTDB.java
@@ -36,8 +36,8 @@ import org.apache.jena.sparql.core.assembler.DatasetAssembler ;
import org.apache.jena.sparql.expr.NodeValue ;
import org.apache.jena.system.JenaSystem ;
import org.seaborne.dboe.base.file.Location ;
+import org.seaborne.tdb2.DatabaseMgr ;
import org.seaborne.tdb2.TDB2 ;
-import org.seaborne.tdb2.TDB2Factory ;
public class DatasetAssemblerTDB extends DatasetAssembler
{
@@ -55,7 +55,7 @@ public class DatasetAssemblerTDB extends DatasetAssembler
String dir = getStringValue(root, pLocation) ;
Location loc = Location.create(dir) ;
- DatasetGraph dsg = TDB2Factory.connectDatasetGraph(loc) ;
+ DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(loc) ;
if ( root.hasProperty(pUnionDefaultGraph) ) {
Node b = root.getProperty(pUnionDefaultGraph).getObject().asNode() ;
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/graph/TransactionHandlerTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/graph/TransactionHandlerTDB.java b/tdb2/src/main/java/org/seaborne/tdb2/graph/TransactionHandlerTDB.java
index bcd5b3d..664b005 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/graph/TransactionHandlerTDB.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/graph/TransactionHandlerTDB.java
@@ -17,45 +17,44 @@
package org.seaborne.tdb2.graph;
-import org.apache.jena.graph.Graph ;
import org.apache.jena.graph.impl.TransactionHandlerBase ;
-import org.seaborne.tdb2.TDB2 ;
+import org.apache.jena.query.ReadWrite;
+import org.seaborne.dboe.transaction.txn.TransactionCoordinator;
+import org.seaborne.tdb2.store.DatasetGraphTDB;
import org.seaborne.tdb2.store.GraphTDB ;
-/** Support for when TDB is used non-transactionally. Does not support ACID transactions.
- * Flushes if commit is called although it denies supporting transactions
- */
-
public class TransactionHandlerTDB extends TransactionHandlerBase //implements TransactionHandler
{
- private final Graph graph ;
+ private final GraphTDB graph ;
+ private final DatasetGraphTDB dsg;
- public TransactionHandlerTDB(GraphTDB graph)
- {
- this.graph = graph ;
+ public TransactionHandlerTDB(GraphTDB graph) {
+ this.graph = graph;
+ this.dsg = graph.getDSG();
}
-
+
@Override
- public void abort()
- {
- // Not the Jena old-style transaction interface
- throw new UnsupportedOperationException("TDB: 'abort' of a transaction not supported") ;
- //log.warn("'Abort' of a transaction not supported - ignored") ;
+ public void abort() {
+ graph.getDSG().abort();
+ graph.getDSG().end();
}
@Override
- public void begin()
- {}
+ public void begin() {
+ if ( TransactionCoordinator.promotion )
+ dsg.begin(ReadWrite.READ);
+ else
+ dsg.begin(ReadWrite.WRITE);
+ }
@Override
- public void commit()
- {
- TDB2.sync(graph) ;
+ public void commit() {
+ dsg.commit();
+ dsg.end();
}
@Override
- public boolean transactionsSupported()
- {
- return false ;
+ public boolean transactionsSupported() {
+ return true;
}
}
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/repack/DatabaseMgr.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/repack/DatabaseMgr.java b/tdb2/src/main/java/org/seaborne/tdb2/repack/DatabaseMgr.java
deleted file mode 100644
index 30b01d6..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/repack/DatabaseMgr.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.seaborne.tdb2.repack;
-
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.List;
-
-import org.apache.jena.sparql.core.DatasetGraph;
-import org.seaborne.dboe.base.file.Location;
-import org.seaborne.dboe.transaction.txn.TransactionCoordinator;
-import org.seaborne.dboe.transaction.txn.TransactionalSystem;
-import org.seaborne.tdb2.TDBException;
-import org.seaborne.tdb2.repack.sys.CopyDSG;
-import org.seaborne.tdb2.repack.sys.FilenameUtils;
-import org.seaborne.tdb2.repack.sys.IOX;
-import org.seaborne.tdb2.repack.sys.Util;
-import org.seaborne.tdb2.setup.StoreParams;
-import org.seaborne.tdb2.store.DatasetGraphTDB;
-import org.seaborne.tdb2.sys.StoreConnection;
-
-/** Create TDB2 databases.
- *
- * TDB2 uses a hierarchical structure to manage on disk.
- *
- * If in-memory (non-scalable, not-performant, perfect simulation for functionality using a RAM disk, for testing mainly),
- * create a
- *
- *
- * Directory and files:
- * <ul>
- * <li> {@code Data-NNNN/} -- databases by version. Compacting creates a new directory, leaving
- * <li> store params, static (disk layout related - can not chnage once created) and dynamic (settings related to in-memory).
- * <li> {@code Backup-DATE/} -- backups.
- * <li> External indexes like {@code TextIndex/} -- the text index only applies to the current, latest database.
- * </ul>
- */
-public class DatabaseMgr {
- private static final String dbPrefix = "Data";
- private static final String SEP = "-";
- private static final String startCount = "0001";
-
- // ***** Need to share DatasetGraphSwitchable -> push down into StoreConnection.
-
- public static DatasetGraph connectOrCreate(Location location) {
- if ( location.isMem() )
- return StoreConnection.connectCreate(location).getDatasetGraph();
- // Exists?
- if ( ! location.exists() )
- throw new TDBException("No such location: "+location);
- Path path = IOX.asPath(location);
- // Scan for DBs
- Path db = findLocation(path, dbPrefix);
- // XXX [StoreParams]
- StoreParams params;
- if ( db == null ) {
- db = path.resolve(dbPrefix+SEP+startCount);
- IOX.createDirectory(db);
- }
- Location loc2 = IOX.asLocation(db);
- DatasetGraphTDB dsg = StoreConnection.connectCreate(loc2).getDatasetGraphTDB();
- DatasetGraph appDSG = new DatasetGraphSwitchable(path, dsg);
- return appDSG;
- }
-
- // JVM-wide :-(
- private static Object compactionLock = new Object();
-
- public static void compact(DatasetGraphSwitchable container) {
- synchronized(compactionLock) {
-
- Path base = container.getContainerPath();
-
- Location loc1a = ((DatasetGraphTDB)container.get()).getLocation();
-
- if ( loc1a.isMem() ) {}
- if ( ! loc1a.exists() )
- throw new TDBException("No such location: "+loc1a);
-
- // Checks
- Path db1 = findLocation(base, dbPrefix);
- Location loc1 = IOX.asLocation(db1);
- // Is this the same database location?
- if ( ! loc1.equals(loc1a) )
- throw new TDBException("Inconsistent (not latested?) : "+loc1a+" : "+loc1);
-
- // Version
- int v = IOX.extractIndex(db1.getFileName().toString(), dbPrefix, SEP);
- String next = FilenameUtils.filename(dbPrefix, SEP, v+1);
-
- Path db2 = db1.getParent().resolve(next);
- IOX.createDirectory(db2);
- Location loc2 = IOX.asLocation(db2);
- System.out.printf("Compact %s -> %s\n", db1.getFileName(), db2.getFileName());
-
- compact(container, loc1, loc2);
- }
- }
-
- // XXX Later - switch in a recording dataset, not block writers, and reply after
- // switch over before releasing the new dataset to the container.
- // Maybe copy indexes and switch the DSG over (drop switchable).
-
- /** Copy the latest version from one location to another. */
- private static void compact(DatasetGraphSwitchable container, Location loc1, Location loc2) {
- if ( loc1.isMem() || loc2.isMem() )
- throw new TDBException("Compact involves a memory location: "+loc1+" : "+loc2);
- StoreConnection srcConn = StoreConnection.connectExisting(loc1);
- if ( srcConn == null ) {
- throw new TDBException("No database at location : "+loc1);
- }
-
- DatasetGraphTDB dsgBase0 = (DatasetGraphTDB)container.get();
- if ( ! dsgBase0.getLocation().equals(loc1) )
- throw new TDBException("Inconsistent locations for base : "+dsgBase0.getLocation()+" , "+dsgBase0.getLocation());
-
- DatasetGraphTDB dsgBase = srcConn.getDatasetGraphTDB();
- if ( dsgBase != dsgBase0 )
- throw new TDBException("Inconsistent datasets : "+dsgBase0.getLocation()+" , "+dsgBase.getLocation());
-
- TransactionalSystem txnSystem = dsgBase.getTxnSystem();
- TransactionCoordinator txnMgr = dsgBase.getTxnSystem().getTxnMgr();
-
- // Stop update. On exit there are no writers and none will start until switched over.
- txnMgr.blockWriters();
-
- // Copy the latest generation.
- DatasetGraphTDB dsgCompact = StoreConnection.connectCreate(loc2).getDatasetGraphTDB();
- CopyDSG.copy(dsgBase, dsgCompact);
-
- TransactionCoordinator txnMgr2 = dsgCompact.getTxnSystem().getTxnMgr();
- txnMgr2.startExclusiveMode();
-
- txnMgr.startExclusiveMode();
-
- // No transactions on either database.
- // Switch.
- container.set(dsgCompact);
- txnMgr2.finishExclusiveMode();
- // New database running.
-
- // Clean-up.
- // txnMgr.finishExclusiveMode();
- // Don't call : txnMgr.startWriters();
- StoreConnection.release(dsgBase.getLocation());
- }
-
- private static Path findLocation(Path directory, String namebase) {
- if ( ! Files.exists(directory) )
- return null;
- // In-order, low to high.
- List<Path> maybe = IOX.scanForDirByPattern(directory, namebase, SEP);
- return Util.getLastOrNull(maybe);
- }
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/repack/DatasetGraphSwitchable.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/repack/DatasetGraphSwitchable.java b/tdb2/src/main/java/org/seaborne/tdb2/repack/DatasetGraphSwitchable.java
index 870f8af..642fb61 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/repack/DatasetGraphSwitchable.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/repack/DatasetGraphSwitchable.java
@@ -18,17 +18,30 @@
package org.seaborne.tdb2.repack;
import java.nio.file.Path;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
-import org.apache.jena.sparql.core.DatasetGraph ;
-import org.apache.jena.sparql.core.DatasetGraphWrapper ;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.Node;
+import org.apache.jena.shared.PrefixMapping;
+import org.apache.jena.shared.impl.PrefixMappingImpl;
+import org.apache.jena.sparql.core.*;
+import org.seaborne.tdb2.store.DatasetGraphTDB;
-final // Encourage the JIT!
+final
public class DatasetGraphSwitchable extends DatasetGraphWrapper
{
+ // QueryEngineFactoryWrapper has a QueryEngineFactory that is always loaded that
+ // executes on the unwrapped DSG (recursively). Unwrapping is via getBase, calling
+ // getWrapped() which is implemented with get().
+
+// static {
+// // QueryEngineRegistry.addFactory(factory());
+// }
+
private final AtomicReference<DatasetGraph> dsgx = new AtomicReference<>();
// Null for in-memory datasets.
- private final Path basePath;
+ private final Path basePath;
public DatasetGraphSwitchable(Path base, DatasetGraph dsg) {
// Don't use the slot in datasetGraphWrapper - use the AtomicReference
@@ -37,6 +50,11 @@ public class DatasetGraphSwitchable extends DatasetGraphWrapper
this.basePath = base;
}
+ /** Is this {@code DatasetGraphSwitchable} just a holder for a {@code DatasetGraph}?
+ * If so, it does not have a location on disk.
+ */
+ public boolean hasContainerPath() { return basePath != null; }
+
public Path getContainerPath() { return basePath; }
/** The dataset to use for redirection - can be overridden.
@@ -53,5 +71,144 @@ public class DatasetGraphSwitchable extends DatasetGraphWrapper
public DatasetGraph set(DatasetGraph dsg) {
return dsgx.getAndSet(dsg);
}
+
+ /** If and only if the current value is the given old value, set the base {@link DatasetGraph}
+ * Returns true if a swap happened.
+ */
+ public boolean change(DatasetGraph oldDSG, DatasetGraph newDSG) {
+ return dsgx.compareAndSet(oldDSG, newDSG);
+ }
+
+ // Used directly, Does not get prefix mapping right.
+ // GraphView has a private, empty prefix mapping
+
+ Graph dft = new GraphView(this, Quad.defaultGraphNodeGenerated) {
+ @Override
+ protected PrefixMapping createPrefixMapping() {
+ return prefixMapping(null);
+ }
+ };
+
+ @Override
+ public Graph getDefaultGraph() {
+ // Via the switchable.
+ return new GraphView(this, Quad.defaultGraphNodeGenerated) {
+ @Override
+ protected PrefixMapping createPrefixMapping() {
+ return prefixMapping(null);
+ }
+ };
+ }
+
+ @Override
+ public Graph getGraph(Node gn) {
+ if ( Quad.isUnionGraph(gn) )
+ return GraphView.createUnionGraph(get());
+
+ return new GraphView(this, gn) {
+ @Override
+ protected PrefixMapping createPrefixMapping() {
+ return prefixMapping(gn);
+ }
+ };
+ }
+
+ // TDB2 specific.
+ // Does not cope with blank nodes.
+ // A PrefixMapping sending operations via the switchable.
+ private PrefixMapping prefixMapping(Node graphName) {
+
+ String gn = (graphName == null) ? "" : graphName.getURI();
+
+ return new PrefixMappingImpl() {
+
+ DatasetPrefixStorage dps() {
+ return ((DatasetGraphTDB)dsgx.get()).getPrefixes();
+ }
+
+ Graph graph() {
+ DatasetGraphTDB dsg = (DatasetGraphTDB)dsgx.get();
+ if ( gn == null )
+ return dsg.getDefaultGraph();
+ else
+ return dsg.getGraph(graphName);
+ }
+
+ PrefixMapping prefixMapping() {
+ if ( gn == null )
+ return dps().getPrefixMapping();
+ else
+ return dps().getPrefixMapping(gn);
+ }
+
+ @Override
+ protected void set(String prefix, String uri) {
+ dps().insertPrefix(gn, prefix, uri);
+ super.set(prefix, uri);
+ }
+
+ @Override
+ protected String get(String prefix) {
+ return dps().readPrefix(gn, prefix);
+ }
+
+ @Override
+ protected void remove(String prefix) {
+ dps().getPrefixMapping().removeNsPrefix(prefix);
+ super.remove(prefix);
+ }
+
+ @Override
+ public Map<String, String> getNsPrefixMap() {
+ return prefixMapping().getNsPrefixMap();
+ //return graph().getPrefixMapping().getNsPrefixMap();
+ }
+ };
+ }
+
+ //static { register() ; }
+
+
+// static QueryEngineFactory factory() {
+// return new QueryEngineFactory() {
+// @Override
+// public boolean accept(Op op, DatasetGraph dataset, Context context) {
+// DatasetGraphSwitchable dsg = extract(dataset) ;
+// if ( dsg == null ) return false;
+// QueryEngineFactory f = QueryEngineRegistry.findFactory(op, dsg.get(), context);
+// return f.accept(op, dataset, context);
+// }
+//
+// @Override
+// public Plan create(Op op, DatasetGraph dataset, Binding inputBinding, Context context) {
+// DatasetGraphSwitchable dsg = extract(dataset) ;
+// if ( dsg == null ) return null;
+// QueryEngineFactory f = QueryEngineRegistry.findFactory(op, dsg.get(), context);
+// return f.create(op, dataset, inputBinding, context);
+// }
+//
+// private DatasetGraphSwitchable extract(DatasetGraph dataset) {
+// if ( dataset instanceof DatasetGraphSwitchable )
+// return (DatasetGraphSwitchable)dataset;
+// return null;
+// }
+//
+// @Override
+// public boolean accept(Query query, DatasetGraph dataset, Context context) {
+// DatasetGraphSwitchable dsg = extract(dataset) ;
+// if ( dsg == null ) return false;
+// QueryEngineFactory f = QueryEngineRegistry.findFactory(query, dsg.get(), context);
+// return f.accept(query, dataset, context);
+// }
+//
+// @Override
+// public Plan create(Query query, DatasetGraph dataset, Binding inputBinding, Context context) {
+// DatasetGraphSwitchable dsg = extract(dataset) ;
+// if ( dsg == null ) return null;
+// QueryEngineFactory f = QueryEngineRegistry.findFactory(query, dsg.get(), context);
+// return f.create(query, dataset, inputBinding, context);
+// }
+// };
+// }
}
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/IOX.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/IOX.java b/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/IOX.java
deleted file mode 100644
index 183ef30..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/IOX.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.seaborne.tdb2.repack.sys;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.file.*;
-import java.nio.file.attribute.FileAttribute;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.function.Function ;
-import java.util.regex.Pattern;
-
-import org.apache.jena.atlas.RuntimeIOException;
-import org.apache.jena.atlas.logging.FmtLog;
-import org.seaborne.dboe.DBOpEnvException;
-import org.seaborne.dboe.base.file.Location;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * PathX
- */
-public class IOX {
-
- public static Path currentDirectory = Paths.get(".");
-
- /** A Consumer that can throw {@link IOException}. */
- public interface IOConsumer<X> {
- void actionEx(X arg) throws IOException;
- }
-
- /** Convert an {@link IOException} into a {@link RuntimeIOException}.
- * <p>
- * Idiom:
- * <pre>
- * catch(IOException ex) { throw new exception(ex); }
- * </pre>
- * @param ioException
- * @return RuntimeIOException
- */
- public static RuntimeIOException exception(IOException ioException) {
- return new RuntimeIOException(ioException);
- }
-
- /** Write a file safely - the change happens (the function returns true) or
- * somthing went wrong (the function throws a runtime exception) and the file is not changed.
- * Note that the tempfile must be in the same direct as the actual file so an OS-atomic rename can be done.
- */
- public static boolean safeWrite(Path file, IOConsumer<OutputStream> writerAction) {
- Path tmp = createTempFile(file.getParent(), file.getFileName().toString(), ".tmp");
- return safeWrite(file, tmp, writerAction);
- }
-
- /** Write a file safely - the change happens (the function returns true) or
- * somthing went wrong (the function throws a runtime exception) and the file is not changed.
- * Note that the tempfile must be in the same direct as the actual file so an OS-atomic rename can be done.
- */
- public static boolean safeWrite(Path file, Path tmpFile, IOConsumer<OutputStream> writerAction) {
- try {
- try(OutputStream out = new BufferedOutputStream(Files.newOutputStream(tmpFile)) ) {
- writerAction.actionEx(out);
- }
- move(tmpFile, file);
- return true;
- } catch(IOException ex) { throw IOX.exception(ex); }
- }
-
- /** Delete a file. */
- public static void delete(Path path) {
- try { Files.delete(path); }
- catch (IOException ex) {
- FmtLog.error(IOX.class, ex, "IOException deleting %s", path);
- throw IOX.exception(ex);
- }
- }
-
- /** Atomically move a file. */
- public static void move(Path src, Path dst) {
- try { Files.move(src, dst, StandardCopyOption.ATOMIC_MOVE) ; }
- catch (IOException ex) {
- FmtLog.error(IOX.class, ex, "IOException moving %s to %s", src, dst);
- throw IOX.exception(ex);
- }
- }
-
- /** Copy a file, not atomic. *
- * Can copy to a directory or over an existing file.
- * @param srcFilename
- * @param dstFilename
- */
- public static void copy(String srcFilename, String dstFilename) {
- Path src = Paths.get(srcFilename);
- if ( ! Files.exists(src) )
- throw new RuntimeIOException("No such file: "+srcFilename);
-
- Path dst = Paths.get(dstFilename);
- if ( Files.isDirectory(dst) )
- dst = dst.resolve(src.getFileName());
-
- try { Files.copy(src, dst); }
- catch (IOException ex) {
- FmtLog.error(IOX.class, ex, "IOException copying %s to %s", srcFilename, dstFilename);
- throw IOX.exception(ex);
- }
- }
-
- /** Create a directory - thgrow a runtime exception if theer are any problems.
- * This function wraps {@code Files.createDirectory}.
- */
- public static void createDirectory(Path dir) {
- try { Files.createDirectory(dir); }
- catch (IOException ex) { throw IOX.exception(ex); }
- }
-
- /** Convert a {@link Path} to a {@link Location}. */
- public static Location asLocation(Path path) {
- if ( ! Files.isDirectory(path) )
- throw new RuntimeIOException("Path is not naming a directory: "+path);
- return Location.create(path.toString());
- }
-
-// /** Convert a {@link org.apache.jena.tdb.base.file.Location} to a {@link Path}. */
-// public static Path asPath(org.apache.jena.tdb.base.file.Location location) {
-// if ( location.isMem() )
-// throw new RuntimeIOException("Location is a memory location: "+location);
-// return Paths.get(location.getDirectoryPath());
-// }
-
- /** Convert a {@link Location} to a {@link Path}. */
- public static Path asPath(org.seaborne.dboe.base.file.Location location) {
- if ( location.isMem() )
- throw new RuntimeIOException("Location is a memory location: "+location);
- return Paths.get(location.getDirectoryPath());
- }
-
- /** Convert a {@link Location} to a {@link File}. */
- public static File asFile(Location loc) {
- return new File(loc.getDirectoryPath());
- }
-
- /** Read the whole of a file */
- public static byte[] readAll(Path pathname) {
- try {
- return Files.readAllBytes(pathname);
- } catch (IOException ex) { throw IOX.exception(ex); }
- }
-
- /** Write the whole of a file */
- public static void writeAll(Path pathname, byte[] value) {
- try {
- Files.write(pathname, value, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE);
- } catch (IOException ex) { throw IOX.exception(ex); }
- }
-
-// /**
-// * Ensure a directory exists, creating the directory and any missing
-// * directories on the path to it.
-// */
-// public static void ensureDirectory(Path dir, FileAttribute<? >... attrs) {
-// if ( Files.exists(dir) ) {
-// if ( ! Files.isDirectory(dir) )
-// throw new DeltaFileException("Exists but not a directory: "+dir);
-// }
-// try { Files.createDirectories(dir, attrs); }
-// catch (IOException ex) { new DeltaFileException("Failed to create directory: "+dir, ex);}
-// }
-//
-// /**
-// * Ensure a file exists - create an empty one if not. This operation does
-// * not create a directory path to the file.
-// */
-// public static void ensureFile(Path filePath, FileAttribute<? >... attrs) {
-// if ( Files.exists(filePath) ) {
-// if ( ! Files.isRegularFile(filePath) )
-// throw new DeltaFileException("Exists but not a regular file: "+filePath);
-// }
-// try { Files.createFile(filePath); }
-// catch (IOException ex) { new DeltaFileException("Failed to create file: "+filePath, ex);}
-// }
-
- /**
- * Return a temporary filename path.
- * <p>
- * This operation is thread-safe.
- */
- public static Path createTempFile(Path dir, String prefix, String suffix, FileAttribute<? >... attrs) {
- try {
- return Files.createTempFile(dir, prefix, suffix, attrs);
- } catch (IOException ex) { throw IOX.exception(ex); }
- }
-
- /** Generate a unique place related to path;
- * Optionally, provide a mapping of old name to new nae base.
- * This method always adds "-1", "-2" etc.
- */
- public static Path uniqueDerivedPath(Path path, Function<String, String> basenameMapping) {
- String base = path.getFileName().toString();
- if ( basenameMapping != null )
- base = basenameMapping.apply(base);
- // Some large limit "just in case"
- for(int x = 0 ; x < 10_000 ; x++ ) {
- String destname = base+"-"+x;
- Path destpath = path.resolveSibling(destname);
- if ( ! Files.exists(destpath) )
- return destpath;
- }
- return null ;
- }
-
- private static Logger LOG = LoggerFactory.getLogger(Util.class);
-
- /** Find the files in this directory that have namebase as a prefix and
- * are then numbered.
- * <p>
- * Returns a sorted list from, low to high index.
- */
- public static List<Path> scanForDirByPattern(Path directory, String namebase, String nameSep) {
- Pattern pattern = Pattern.compile(Pattern.quote(namebase)+
- Pattern.quote(nameSep)+
- "[\\d]+");
- List<Path> paths = new ArrayList<>();
- try (DirectoryStream<Path> stream = Files.newDirectoryStream(directory, namebase + "*")) {
- for ( Path entry : stream ) {
- if ( !pattern.matcher(entry.getFileName().toString()).matches() ) {
- throw new DBOpEnvException("Invalid filename for matching: "+entry.getFileName());
- // Alternative: Skip bad trailing parts but more likely there is a naming problem.
- // LOG.warn("Invalid filename for matching: {} skipped", entry.getFileName());
- // continue;
- }
- // Follows symbolic links.
- if ( !Files.isDirectory(entry) )
- throw new DBOpEnvException("Not a directory: "+entry);
- paths.add(entry);
- }
- }
- catch (IOException ex) {
- FmtLog.warn(LOG, "Can't inspect directory: (%s, %s)", directory, namebase);
- throw new DBOpEnvException(ex);
- }
- Comparator<Path> comp = (f1, f2) -> {
- int num1 = extractIndex(f1.getFileName().toString(), namebase, nameSep);
- int num2 = extractIndex(f2.getFileName().toString(), namebase, nameSep);
- return Integer.compare(num1, num2);
- };
- paths.sort(comp);
- //indexes.sort(Long::compareTo);
- return paths;
- }
-
- /** Given a filename in "base-NNNN" format, return the value of NNNN */
- public static int extractIndex(String name, String namebase, String nameSep) {
- int i = namebase.length()+nameSep.length();
- String numStr = name.substring(i);
- int num = Integer.parseInt(numStr);
- return num;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/setup/TDBBuilder.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/setup/TDBBuilder.java b/tdb2/src/main/java/org/seaborne/tdb2/setup/TDBBuilder.java
index 4490e3f..66c5c89 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/setup/TDBBuilder.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/setup/TDBBuilder.java
@@ -49,8 +49,6 @@ import org.seaborne.tdb2.store.nodetupletable.NodeTupleTable ;
import org.seaborne.tdb2.store.nodetupletable.NodeTupleTableConcrete ;
import org.seaborne.tdb2.store.tupletable.TupleIndex ;
import org.seaborne.tdb2.store.tupletable.TupleIndexRecord ;
-import org.seaborne.tdb2.sys.DatasetControl ;
-import org.seaborne.tdb2.sys.DatasetControlMRSW ;
import org.seaborne.tdb2.sys.SystemTDB ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControl.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControl.java b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControl.java
new file mode 100644
index 0000000..b283ed4
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControl.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * See the NOTICE file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+package org.seaborne.tdb2.store;
+
+import java.util.Iterator ;
+
+// Used in NodeTupleTables.
+
+/** A DatasetControl is an encapsulation of what to do on reads and writes.
+ * In addition, iterators returned can be tied back to the original request
+ * to check they are still valid.
+ */
+public interface DatasetControl
+{
+ /** Fine grained, internal update - start */
+ public void startUpdate() ;
+
+ /** Fine grained, internal update - finish */
+ public void finishUpdate();
+
+ /** Signal the start of an internal read operation */
+ public void startRead();
+
+ /** Signal the completion of an internal read operation */
+ public void finishRead();
+
+ /** An iterator being created. */
+ public <T> Iterator<T> iteratorControl(Iterator<T> iter) ;
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControlMRSW.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControlMRSW.java b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControlMRSW.java
new file mode 100644
index 0000000..d4c9f57
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControlMRSW.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * See the NOTICE file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+package org.seaborne.tdb2.store;
+
+import static java.lang.String.format ;
+
+import java.util.ConcurrentModificationException ;
+import java.util.Iterator ;
+import java.util.NoSuchElementException ;
+import java.util.concurrent.atomic.AtomicLong ;
+
+import org.apache.jena.atlas.iterator.Iter ;
+import org.apache.jena.atlas.lib.Closeable ;
+
+/** A policy that checks, but does not enforce, single writer or multiple writer locking policy */
+public class DatasetControlMRSW implements DatasetControl
+{
+ private final boolean concurrencyChecking = true ;
+ private final AtomicLong epoch = new AtomicLong(5) ; // Update counters, used to check iterators. No need to start at 0.
+ private final AtomicLong readCounter = new AtomicLong(0) ;
+ private final AtomicLong writeCounter = new AtomicLong(0) ;
+
+ public DatasetControlMRSW()
+ { }
+
+ @Override
+ public void startRead() {
+ readCounter.getAndIncrement() ;
+ checkConcurrency() ;
+ }
+
+ @Override
+ public void finishRead() {
+ readCounter.decrementAndGet() ;
+ }
+
+ @Override
+ public void startUpdate() {
+ epoch.getAndIncrement() ;
+ writeCounter.getAndIncrement() ;
+ checkConcurrency() ;
+ }
+
+ @Override
+ public void finishUpdate() {
+ writeCounter.decrementAndGet() ;
+ }
+
+ private void checkConcurrency() {
+ long R, W ;
+ synchronized (this) {
+ R = readCounter.get() ;
+ W = writeCounter.get() ;
+ }
+
+ if ( R > 0 && W > 0 )
+ policyError(R, W) ;
+ if ( W > 1 )
+ policyError(R, W) ;
+ }
+
+ @Override
+ public <T> Iterator<T> iteratorControl(Iterator<T> iter) { return new IteratorCheckNotConcurrent<>(iter, epoch) ; }
+
+ private static class IteratorCheckNotConcurrent<T> implements Iterator<T>, Closeable
+ {
+ private Iterator<T> iter ;
+ private AtomicLong eCount ;
+ private boolean finished = false ;
+ private long startEpoch ;
+
+ IteratorCheckNotConcurrent(Iterator<T> iter, AtomicLong eCount) {
+ // Assumes correct locking to set up, i.e. eCount not changing
+ // (writer on separate thread).
+ this.iter = iter ;
+ this.eCount = eCount ;
+ this.startEpoch = eCount.get() ;
+ }
+
+ private void checkConcurrentModification() {
+ if ( finished )
+ return ;
+
+ long now = eCount.get() ;
+ if ( now != startEpoch ) {
+ policyError(format("Iterator: started at %d, now %d", startEpoch, now)) ;
+ }
+ }
+
+ @Override
+ public boolean hasNext() {
+ checkConcurrentModification() ;
+ boolean b = iter.hasNext() ;
+ if ( !b )
+ close() ;
+ return b ;
+ }
+
+ @Override
+ public T next() {
+ checkConcurrentModification() ;
+ try { return iter.next() ; }
+ catch (NoSuchElementException ex) {
+ close() ;
+ throw ex ;
+ }
+ }
+
+ @Override
+ public void remove() {
+ checkConcurrentModification() ;
+ iter.remove() ;
+ }
+
+ @Override
+ public void close() {
+ finished = true ;
+ Iter.close(iter) ;
+ }
+ }
+
+ private static void policyError(long R, long W) {
+ policyError(format("Reader = %d, Writer = %d", R, W)) ;
+ }
+
+ private static void policyError(String message) {
+ throw new ConcurrentModificationException(message) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControlNone.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControlNone.java b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControlNone.java
new file mode 100644
index 0000000..b1bf51b
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControlNone.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * See the NOTICE file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+package org.seaborne.tdb2.store;
+
+import java.util.Iterator ;
+
+/** Concurrency policy that is a "free for all".
+ * No checking, no locking.
+ */
+public final class DatasetControlNone implements DatasetControl
+{
+ @Override
+ public void startUpdate()
+ {}
+
+ @Override
+ public void finishUpdate()
+ {}
+
+ @Override
+ public void startRead()
+ {}
+
+ @Override
+ public void finishRead()
+ {}
+
+ @Override
+ public <T> Iterator<T> iteratorControl(Iterator<T> iter)
+ {
+ return iter ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControlReadOnly.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControlReadOnly.java b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControlReadOnly.java
new file mode 100644
index 0000000..85b31be
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControlReadOnly.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * See the NOTICE file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+package org.seaborne.tdb2.store;
+
+import java.util.Iterator ;
+import java.util.concurrent.atomic.AtomicLong ;
+
+import org.seaborne.tdb2.TDBException ;
+
+/** A policy that provide read-only access */
+public class DatasetControlReadOnly implements DatasetControl
+{
+ private final AtomicLong readCounter = new AtomicLong(0) ;
+
+ public DatasetControlReadOnly()
+ { }
+
+ @Override
+ public void startRead()
+ {
+ readCounter.getAndIncrement() ;
+ }
+
+ @Override
+ public void finishRead()
+ {
+ readCounter.decrementAndGet() ;
+ }
+
+ @Override
+ public void startUpdate()
+ {
+ throw new TDBException("Read-only") ;
+ }
+
+ @Override
+ public void finishUpdate()
+ {
+ throw new TDBException("Read-only") ;
+ }
+
+ @Override
+ public <T> Iterator<T> iteratorControl(Iterator<T> iter) { return iter ; }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetPrefixesTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetPrefixesTDB.java b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetPrefixesTDB.java
index fe21cd7..0b7f072 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetPrefixesTDB.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetPrefixesTDB.java
@@ -36,11 +36,8 @@ import org.seaborne.tdb2.store.nodetupletable.NodeTupleTable ;
*/
public class DatasetPrefixesTDB implements DatasetPrefixStorage
{
- /*
- * Almost everything is cached in the prefix map asociated with the
- * graph or dataset so this table is the persistent form and
- * does not need a cache of it's own.
- */
+ // Consider a cache - like PrefixMappingCache was - but needs to respect transactions.
+ // See getPrefixMapping.
static final RecordFactory factory = new RecordFactory(3*NodeId.SIZE, 0) ;
static final String unamedGraphURI = "" ;
@@ -161,7 +158,6 @@ public class DatasetPrefixesTDB implements DatasetPrefixStorage
@Override
public PrefixMapping getPrefixMapping(String graphName) {
PrefixMapping pm = new GraphPrefixesProjectionTDB(graphName, this) ;
- pm = new PrefixMappingCache(pm) ;
return pm ;
}
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/store/GraphPrefixesProjectionTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/GraphPrefixesProjectionTDB.java b/tdb2/src/main/java/org/seaborne/tdb2/store/GraphPrefixesProjectionTDB.java
index 330ee20..2c50740 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/GraphPrefixesProjectionTDB.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/GraphPrefixesProjectionTDB.java
@@ -28,8 +28,8 @@ import org.apache.jena.sparql.core.DatasetPrefixStorage ;
public class GraphPrefixesProjectionTDB implements PrefixMapping {
// Despite the name "TDB" this is general replacement for
// PrefixMapping over DatasetPrefixStorage.
- private String graphName ;
- private DatasetPrefixStorage prefixes ;
+ private final String graphName ;
+ private final DatasetPrefixStorage prefixes ;
public GraphPrefixesProjectionTDB(String graphName, DatasetPrefixStorage prefixes)
{
@@ -113,10 +113,11 @@ public class GraphPrefixesProjectionTDB implements PrefixMapping {
@Override
public String qnameFor(String uri) {
int split = Util.splitNamespaceXML(uri) ;
- String ns = uri.substring(0, split), local = uri.substring(split) ;
+ String ns = uri.substring(0, split);
+ String local = uri.substring(split) ;
if ( local.equals("") )
return null ;
- String prefix = prefixes.readByURI(graphName, uri) ;
+ String prefix = prefixes.readByURI(graphName, ns) ;
return prefix == null ? null : prefix + ":" + local ;
}
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/store/GraphTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/GraphTDB.java b/tdb2/src/main/java/org/seaborne/tdb2/store/GraphTDB.java
index fc9c97f..a1e99ce 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/GraphTDB.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/GraphTDB.java
@@ -87,7 +87,7 @@ public class GraphTDB extends GraphView implements Closeable, Sync {
if ( iterQuads == null )
return org.apache.jena.util.iterator.NullIterator.instance() ;
// Can't be duplicates - fixed graph node..
- Iterator<Triple> iterTriples = new ProjectQuadsToTriples(Quad.defaultGraphIRI, iterQuads) ;
+ Iterator<Triple> iterTriples = projectQuadsToTriples(Quad.defaultGraphIRI, iterQuads) ;
return WrappedIterator.createNoRemove(iterTriples) ;
}
@@ -97,12 +97,11 @@ public class GraphTDB extends GraphView implements Closeable, Sync {
if ( isUnionGraph(gn) )
gn = Node.ANY ;
- Iterator<Quad> iter = dataset.getQuadTable().find(gn, m.getMatchSubject(), m.getMatchPredicate(),
- m.getMatchObject()) ;
+ Iterator<Quad> iter = dataset.getQuadTable().find(gn, m.getMatchSubject(), m.getMatchPredicate(), m.getMatchObject()) ;
if ( iter == null )
return org.apache.jena.util.iterator.NullIterator.instance() ;
- Iterator<Triple> iterTriples = new ProjectQuadsToTriples((gn == Node.ANY ? null : gn), iter) ;
+ Iterator<Triple> iterTriples = projectQuadsToTriples((gn == Node.ANY ? null : gn), iter) ;
if ( gn == Node.ANY )
iterTriples = Iter.distinct(iterTriples) ;
@@ -142,93 +141,18 @@ public class GraphTDB extends GraphView implements Closeable, Sync {
throw new TDBException("Expected a Tuple of 4, got: " + item);
return TupleFactory.tuple(item.get(1), item.get(2), item.get(3));
};
-
- // Convert from Iterator<Quad> to Iterator<Triple>
- static class ProjectQuadsToTriples implements Iterator<Triple> {
- private final Iterator<Quad> iter ;
- private final Node graphNode ;
-
- /**
- * Project quads to triples - check the graphNode is as expected if not
- * null
- */
- ProjectQuadsToTriples(Node graphNode, Iterator<Quad> iter) {
- this.graphNode = graphNode ;
- this.iter = iter ;
- }
-
- @Override
- public boolean hasNext() {
- return iter.hasNext() ;
- }
-
- @Override
- public Triple next() {
- Quad q = iter.next() ;
+
+ private static Iterator<Triple> projectQuadsToTriples(Node graphNode, Iterator<Quad> iter) {
+ // Checking.
+ Function<Quad, Triple> f = (q) -> {
if ( graphNode != null && !q.getGraph().equals(graphNode) )
- throw new InternalError("ProjectQuadsToTriples: Quads from unexpected graph (expected=" + graphNode
- + ", got=" + q.getGraph() + ")") ;
- return q.asTriple() ;
- }
-
- @Override
- public void remove() {
- iter.remove() ;
- }
- }
-
- @Override
- public Capabilities getCapabilities() {
- if ( capabilities == null )
- capabilities = new Capabilities() {
- @Override
- public boolean sizeAccurate() {
- return true ;
- }
-
- @Override
- public boolean addAllowed() {
- return true ;
- }
-
- @Override
- public boolean addAllowed(boolean every) {
- return true ;
- }
-
- @Override
- public boolean deleteAllowed() {
- return true ;
- }
-
- @Override
- public boolean deleteAllowed(boolean every) {
- return true ;
- }
-
- @Override
- public boolean canBeEmpty() {
- return true ;
- }
-
- @Override
- public boolean iteratorRemoveAllowed() {
- return false ;
- } /* ** */
-
- @Override
- public boolean findContractSafe() {
- return true ;
- }
-
- @Override
- public boolean handlesLiteralTyping() {
- return false ;
- } /* ** */
- } ;
-
- return super.getCapabilities() ;
- }
+ throw new InternalError("projectQuadsToTriples: Quads from unexpected graph (expected=" + graphNode + ", got=" + q.getGraph() + ")");
+ return q.asTriple();
+ };
+ // Without.
+ //Function<Quad, Triple> f = (q) -> q.asTriple();
+ return Iter.map(iter, f);
+ }
@Override
public TransactionHandler getTransactionHandler() {
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/store/PrefixMappingCache.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/PrefixMappingCache.java b/tdb2/src/main/java/org/seaborne/tdb2/store/PrefixMappingCache.java
index 5fbe278..ca950d7 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/PrefixMappingCache.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/PrefixMappingCache.java
@@ -21,12 +21,13 @@ import java.util.Map ;
import java.util.Optional ;
import java.util.Map.Entry ;
+import org.apache.jena.atlas.iterator.Iter;
import org.apache.jena.atlas.lib.Cache ;
import org.apache.jena.atlas.lib.CacheFactory ;
import org.apache.jena.rdf.model.impl.Util ;
import org.apache.jena.shared.PrefixMapping ;
-// Non-transactional cache.
+// Unsafe. Non-transactional cache.
public class PrefixMappingCache implements PrefixMapping {
private final PrefixMapping other ;
@@ -121,6 +122,7 @@ public class PrefixMappingCache implements PrefixMapping {
@Override
public Map<String, String> getNsPrefixMap() {
+ // Ignore cache - get everything from the provider.
return other.getNsPrefixMap() ;
}
@@ -128,22 +130,21 @@ public class PrefixMappingCache implements PrefixMapping {
// Libraryize?
@Override
public String expandPrefix(String prefixed) {
- {
- int colon = prefixed.indexOf(':') ;
- if ( colon < 0 )
- return prefixed ;
- else {
- String prefix = prefixed.substring(0, colon) ;
- String uri = getNsPrefixURI(prefix) ;
- return uri == null ? prefixed : uri + prefixed.substring(colon + 1) ;
- }
+ int colon = prefixed.indexOf(':');
+ if ( colon < 0 )
+ return prefixed;
+ else {
+ String prefix = prefixed.substring(0, colon);
+ String uri = getNsPrefixURI(prefix);
+ return uri == null ? prefixed : uri + prefixed.substring(colon + 1);
}
}
@Override
public String qnameFor(String uri) {
int split = Util.splitNamespaceXML(uri) ;
- String ns = uri.substring(0, split), local = uri.substring(split) ;
+ String ns = uri.substring(0, split);
+ String local = uri.substring(split) ;
if ( local.equals("") )
return null ;
String prefix = getNsURIPrefix(ns) ;
@@ -187,5 +188,15 @@ public class PrefixMappingCache implements PrefixMapping {
return other.numPrefixes() ;
}
+ private static String str(PrefixMapping pmap) {
+ return pmap.getNsPrefixMap().toString();
+ }
+
+ @Override
+ public String toString() {
+ // Problem : only prints the cache.
+ String x = Iter.iter(prefixToUri.keys()).map(k->k+"->"+prefixToUri.getIfPresent(k)).asString(", ");
+ return "pm cache: ["+prefixToUri.size()+"] "+x+" : " + str(other);
+ }
}
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/store/QuadTable.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/QuadTable.java b/tdb2/src/main/java/org/seaborne/tdb2/store/QuadTable.java
index 97dc784..15a14ff 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/QuadTable.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/QuadTable.java
@@ -27,7 +27,6 @@ import org.apache.jena.sparql.core.Quad ;
import org.seaborne.tdb2.lib.TupleLib ;
import org.seaborne.tdb2.store.nodetable.NodeTable ;
import org.seaborne.tdb2.store.tupletable.TupleIndex ;
-import org.seaborne.tdb2.sys.DatasetControl ;
/**
* Quad table - a collection of TupleIndexes for 4-tuples together with a node
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/store/TableBase.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/TableBase.java b/tdb2/src/main/java/org/seaborne/tdb2/store/TableBase.java
index 81a9593..05b80ab 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/TableBase.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/TableBase.java
@@ -23,7 +23,6 @@ import org.seaborne.tdb2.store.nodetable.NodeTable ;
import org.seaborne.tdb2.store.nodetupletable.NodeTupleTable ;
import org.seaborne.tdb2.store.nodetupletable.NodeTupleTableConcrete ;
import org.seaborne.tdb2.store.tupletable.TupleIndex ;
-import org.seaborne.tdb2.sys.DatasetControl ;
public class TableBase implements Sync, Closeable
{
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/store/TripleTable.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/TripleTable.java b/tdb2/src/main/java/org/seaborne/tdb2/store/TripleTable.java
index 2f17208..8e5aeb9 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/TripleTable.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/TripleTable.java
@@ -26,7 +26,6 @@ import org.apache.jena.graph.Triple ;
import org.seaborne.tdb2.lib.TupleLib ;
import org.seaborne.tdb2.store.nodetable.NodeTable ;
import org.seaborne.tdb2.store.tupletable.TupleIndex ;
-import org.seaborne.tdb2.sys.DatasetControl ;
/**
* TripleTable - a collection of TupleIndexes for 3-tuples together with a node
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/TReadAppendFileTransport.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/TReadAppendFileTransport.java b/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/TReadAppendFileTransport.java
index 140047c..34eebfb 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/TReadAppendFileTransport.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/TReadAppendFileTransport.java
@@ -22,7 +22,7 @@ import java.util.Objects ;
import org.apache.thrift.transport.TTransport ;
import org.seaborne.dboe.base.file.BinaryDataFile ;
-/** A file transport that support random access read and
+/** A file transport that supports random access read and
* buffered append write.
* <p>
* Adapter TTransport -> BinaryDataFile
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTable.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTable.java b/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTable.java
index 4a60695..89139c9 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTable.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTable.java
@@ -23,10 +23,10 @@ import org.apache.jena.atlas.lib.Closeable ;
import org.apache.jena.atlas.lib.Sync ;
import org.apache.jena.atlas.lib.tuple.Tuple ;
import org.apache.jena.graph.Node ;
+import org.seaborne.tdb2.store.DatasetControl ;
import org.seaborne.tdb2.store.NodeId ;
import org.seaborne.tdb2.store.nodetable.NodeTable ;
import org.seaborne.tdb2.store.tupletable.TupleTable ;
-import org.seaborne.tdb2.sys.DatasetControl ;
public interface NodeTupleTable extends Sync, Closeable
{
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableConcrete.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableConcrete.java b/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableConcrete.java
index 6d92abc..0d967f0 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableConcrete.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableConcrete.java
@@ -27,11 +27,11 @@ import org.apache.jena.atlas.lib.tuple.TupleFactory ;
import org.apache.jena.graph.Node ;
import org.seaborne.tdb2.TDBException ;
import org.seaborne.tdb2.lib.TupleLib ;
+import org.seaborne.tdb2.store.DatasetControl ;
import org.seaborne.tdb2.store.NodeId ;
import org.seaborne.tdb2.store.nodetable.NodeTable ;
import org.seaborne.tdb2.store.tupletable.TupleIndex ;
import org.seaborne.tdb2.store.tupletable.TupleTable ;
-import org.seaborne.tdb2.sys.DatasetControl ;
/** Group a tuple table and node table together to provide a real NodeTupleTable */
public class NodeTupleTableConcrete implements NodeTupleTable
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableWrapper.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableWrapper.java b/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableWrapper.java
index f47d78e..e54f964 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableWrapper.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableWrapper.java
@@ -21,10 +21,10 @@ import java.util.Iterator ;
import org.apache.jena.atlas.lib.tuple.Tuple ;
import org.apache.jena.graph.Node ;
+import org.seaborne.tdb2.store.DatasetControl ;
import org.seaborne.tdb2.store.NodeId ;
import org.seaborne.tdb2.store.nodetable.NodeTable ;
import org.seaborne.tdb2.store.tupletable.TupleTable ;
-import org.seaborne.tdb2.sys.DatasetControl ;
public class NodeTupleTableWrapper implements NodeTupleTable
{
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/sys/ConnectionTracker.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/ConnectionTracker.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/ConnectionTracker.java
new file mode 100644
index 0000000..f2950eb
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/ConnectionTracker.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.seaborne.tdb2.sys;
+
+abstract class ConnectionTracker<X> {
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseConnection.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseConnection.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseConnection.java
new file mode 100644
index 0000000..3fa4983
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseConnection.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.seaborne.tdb2.sys;
+
+import java.io.IOException ;
+import java.nio.file.Path ;
+import java.nio.file.Paths ;
+import java.util.Map ;
+import java.util.concurrent.ConcurrentHashMap ;
+
+import org.apache.jena.atlas.io.IO ;
+import org.apache.jena.atlas.lib.FileOps ;
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.seaborne.dboe.base.file.Location ;
+import org.seaborne.dboe.base.file.ProcessFileLock ;
+import org.seaborne.dboe.sys.Names ;
+import org.seaborne.tdb2.TDBException ;
+import org.seaborne.tdb2.repack.DatasetGraphSwitchable ;
+import org.seaborne.tdb2.setup.StoreParams ;
+
+// StoreConnection, DatabaseConnection < Connection<X>
+
+public class DatabaseConnection {
+ // ConnectionTracker<X>
+
+ private static Map<Location, DatabaseConnection> cache = new ConcurrentHashMap<>() ;
+
+ /** Get the {@code DatabaseConnection} to a location,
+ * creating the storage structures if it does not exist. */
+ public synchronized static DatabaseConnection connectCreate(Location location) {
+ return connectCreate(location, null) ;
+ }
+
+ /** Get the {@code DatabaseConnection} to a location,
+ * creating the storage structures if it does not exist.
+ * Use the provided {@link StoreParams} - any persistent setting
+ * already at the location take precedence.
+ */
+ public synchronized static DatabaseConnection connectCreate(Location location, StoreParams params) {
+ return make(location, params) ;
+ }
+
+ /**
+ * Return a {@code StoreConnection} for a particular location,
+ * creating it if it does not exist in storage.
+ */
+ private synchronized static DatabaseConnection make(Location location, StoreParams params) {
+ if ( location.isMemUnique() ) {
+ // Uncached, in-memory.
+ DatasetGraph dsg = DatabaseOps.create(location);
+ DatabaseConnection dbConn = new DatabaseConnection(dsg, location, null);
+ return dbConn;
+ }
+ // Cached by Location. Named in-memory or on-disk.
+ ProcessFileLock lock = null;
+ if (SystemTDB.DiskLocationMultiJvmUsagePrevention && ! location.isMem() ) {
+ lock = lockForLocation(location);
+ // Take the lock. This is atomic.
+ lock.lockEx();
+ }
+ final ProcessFileLock lock2 = lock;
+ DatabaseConnection dbConn = cache.computeIfAbsent(location, (loc)->buildForCache(loc, lock2, params));
+ return dbConn ;
+ }
+
+ private static DatabaseConnection buildForCache(Location location, ProcessFileLock lock, StoreParams params) {
+ if ( location.isMemUnique() ) {
+ throw new TDBException("Can't buildForCache a memory-unique location");
+ }
+ DatasetGraph dsg = DatabaseOps.create(location);
+ return new DatabaseConnection(dsg, location, lock) ;
+ }
+
+// private static DatasetGraph buildMem(Location location, StoreParams params) {
+// return StoreConnection.connectCreate(location, params).getDatasetGraph();
+// }
+//
+// private static DatasetGraph buildDisk(Location location, StoreParams params) {
+// return DatabaseOps.create(location);
+// }
+
+ // DRY
+ /** Create or fetch a {@link ProcessFileLock} for a Location */
+ public static ProcessFileLock lockForLocation(Location location) {
+ FileOps.ensureDir(location.getDirectoryPath());
+ String lockFilename = location.getPath(Names.TDB_LOCK_FILE);
+ Path path = Paths.get(lockFilename);
+ try {
+ path.toFile().createNewFile();
+ } catch(IOException ex) { IO.exception(ex); return null; }
+ return ProcessFileLock.create(lockFilename);
+ }
+
+ /** Stop managing a location. Use with great care (testing only). */
+ public static synchronized void expel(Location location, boolean force) {
+ DatabaseConnection dbConn = cache.get(location) ;
+ if (dbConn == null) return ;
+ cache.remove(location) ;
+ dbConn.isValid = false;
+ //dbConn.datasetGraph = null;
+ //dbConn.datasetGraphSwitchable = null;
+ StoreConnection.expel(location, force);
+
+ // if (!force && sConn.transactionManager.activeTransactions())
+ // throw new TDBTransactionException("Can't expel: Active transactions for location: " + location) ;
+
+ cache.remove(location) ;
+ // Release the lock after the cache is emptied.
+ if (SystemTDB.DiskLocationMultiJvmUsagePrevention && ! location.isMem() ) {
+ if ( ! dbConn.lock.isLockedHere() )
+ SystemTDB.errlog.warn("Location " + location.getDirectoryPath() + " was not locked by this process.");
+ dbConn.lock.unlock();
+ ProcessFileLock.release(dbConn.lock);
+ }
+ }
+
+ // One of the other.
+ private final DatasetGraphSwitchable datasetGraphSwitchable;
+ private final DatasetGraph datasetGraph;
+ // This is the location of the TDB2 container directory.
+ private final Location location ;
+ private final ProcessFileLock lock ;
+ private boolean isValid = true ;
+
+ private DatabaseConnection(DatasetGraph dsg, Location location, ProcessFileLock fileLock)
+ {
+ this.datasetGraph = dsg;
+ this.datasetGraphSwitchable = ( dsg instanceof DatasetGraphSwitchable ) ? (DatasetGraphSwitchable )dsg : null;
+ this.location = location ;
+ this.lock = fileLock;
+ }
+
+ public DatasetGraph getDatasetGraph() {
+ return datasetGraph;
+ }
+
+ public DatasetGraphSwitchable getDatasetGraphSwitchable() {
+ return datasetGraphSwitchable;
+ }
+
+ public Location getLocation() {
+ return location ;
+ }
+
+ public ProcessFileLock getLock() {
+ return lock ;
+ }
+}