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:17 UTC
[01/50] [abbrv] jena git commit: Version 0.3.0-SNAPSHOT
Repository: jena
Updated Branches:
refs/heads/jena-tdb2 3fbbfccf0 -> d9da3592f
Version 0.3.0-SNAPSHOT
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/46862c3d
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/46862c3d
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/46862c3d
Branch: refs/heads/jena-tdb2
Commit: 46862c3d01043880f900405d061f46206023c654
Parents: cd88ede
Author: Andy Seaborne <an...@seaborne.org>
Authored: Sun Aug 20 22:01:48 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Sun Aug 20 22:14:03 2017 +0100
----------------------------------------------------------------------
dboe-base/pom.xml | 2 +-
dboe-index-test/pom.xml | 4 ++--
dboe-index/pom.xml | 4 ++--
dboe-trans-data/pom.xml | 10 +++++-----
dboe-transaction/pom.xml | 4 ++--
fuseki-tdb2/pom.xml | 4 ++--
pom.xml | 2 +-
tdb2-cmds/pom.xml | 4 ++--
tdb2/pom.xml | 4 ++--
9 files changed, 19 insertions(+), 19 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/46862c3d/dboe-base/pom.xml
----------------------------------------------------------------------
diff --git a/dboe-base/pom.xml b/dboe-base/pom.xml
index be06a45..1843969 100644
--- a/dboe-base/pom.xml
+++ b/dboe-base/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</parent>
<dependencies>
http://git-wip-us.apache.org/repos/asf/jena/blob/46862c3d/dboe-index-test/pom.xml
----------------------------------------------------------------------
diff --git a/dboe-index-test/pom.xml b/dboe-index-test/pom.xml
index 63bb38f..658d621 100644
--- a/dboe-index-test/pom.xml
+++ b/dboe-index-test/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</parent>
<dependencies>
@@ -34,7 +34,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-index</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/jena/blob/46862c3d/dboe-index/pom.xml
----------------------------------------------------------------------
diff --git a/dboe-index/pom.xml b/dboe-index/pom.xml
index 5b7eaae..2b21bbe 100644
--- a/dboe-index/pom.xml
+++ b/dboe-index/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</parent>
<dependencies>
@@ -34,7 +34,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-base</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</dependency>
</dependencies>
http://git-wip-us.apache.org/repos/asf/jena/blob/46862c3d/dboe-trans-data/pom.xml
----------------------------------------------------------------------
diff --git a/dboe-trans-data/pom.xml b/dboe-trans-data/pom.xml
index 97ae961..08bd822 100644
--- a/dboe-trans-data/pom.xml
+++ b/dboe-trans-data/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</parent>
<dependencies>
@@ -33,26 +33,26 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-transaction</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-index</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-index-test</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-base</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
http://git-wip-us.apache.org/repos/asf/jena/blob/46862c3d/dboe-transaction/pom.xml
----------------------------------------------------------------------
diff --git a/dboe-transaction/pom.xml b/dboe-transaction/pom.xml
index eed36d7..76b7902 100644
--- a/dboe-transaction/pom.xml
+++ b/dboe-transaction/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</parent>
<dependencies>
@@ -33,7 +33,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-base</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</dependency>
</dependencies>
http://git-wip-us.apache.org/repos/asf/jena/blob/46862c3d/fuseki-tdb2/pom.xml
----------------------------------------------------------------------
diff --git a/fuseki-tdb2/pom.xml b/fuseki-tdb2/pom.xml
index 4c1d368..248881c 100644
--- a/fuseki-tdb2/pom.xml
+++ b/fuseki-tdb2/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</parent>
<packaging>jar</packaging>
@@ -36,7 +36,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>tdb2</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/jena/blob/46862c3d/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 5c67470..77a2033 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
<artifactId>mantis</artifactId>
<packaging>pom</packaging>
<url>https://github.com/afs/mantis</url>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
<name>Mantis :: Database Operation Environment</name>
<description>Mantis :: Database Operation Environment</description>
http://git-wip-us.apache.org/repos/asf/jena/blob/46862c3d/tdb2-cmds/pom.xml
----------------------------------------------------------------------
diff --git a/tdb2-cmds/pom.xml b/tdb2-cmds/pom.xml
index 7ab19bd..9cd77bf 100644
--- a/tdb2-cmds/pom.xml
+++ b/tdb2-cmds/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</parent>
<dependencies>
@@ -35,7 +35,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>tdb2</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/jena/blob/46862c3d/tdb2/pom.xml
----------------------------------------------------------------------
diff --git a/tdb2/pom.xml b/tdb2/pom.xml
index e3d08b9..0dd7f62 100644
--- a/tdb2/pom.xml
+++ b/tdb2/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</parent>
<dependencies>
@@ -43,7 +43,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-trans-data</artifactId>
- <version>0.2.1-SNAPSHOT</version>
+ <version>0.3.0-SNAPSHOT</version>
</dependency>
<dependency>
[30/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableOps.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableOps.java
index 0000000,0000000..378bdfc
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableOps.java
@@@ -1,0 -1,0 +1,50 @@@
++/*
++ * 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.nodetable;
++
++import java.util.ArrayList ;
++import java.util.List ;
++
++import org.apache.jena.graph.Node ;
++import org.seaborne.tdb2.store.NodeId ;
++
++public class NodeTableOps {
++
++ /** Convert a bulk operation into a loop */
++ public static List<NodeId> bulkNodeToNodeIdImpl(NodeTable nt, List<Node> nodes, boolean withAllocation) {
++ List<NodeId> nodeIds = new ArrayList<>(nodes.size()) ;
++ for ( Node node : nodes ) {
++ NodeId nid = withAllocation ? nt.getAllocateNodeId(node) : nt.getNodeIdForNode(node) ;
++ nodeIds.add(nid) ;
++ }
++ return nodeIds ;
++ }
++
++ /** Convert a bulk operation into a loop */
++ public static List<Node> bulkNodeIdToNodeImpl(NodeTable nt, List<NodeId> nodeIds) {
++ List<Node> nodes = new ArrayList<>(nodeIds.size()) ;
++ for ( NodeId nodeId : nodeIds ) {
++ Node n = nt.getNodeForNodeId(nodeId) ;
++ nodes.add(n) ;
++ }
++ return nodes ;
++ }
++
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableTRDF.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableTRDF.java
index 0000000,0000000..44f71d4
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableTRDF.java
@@@ -1,0 -1,0 +1,108 @@@
++/*
++ * 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.nodetable ;
++
++import org.apache.jena.atlas.logging.Log ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.riot.thrift.RiotThriftException ;
++import org.apache.jena.riot.thrift.TRDF ;
++import org.apache.jena.riot.thrift.ThriftConvert ;
++import org.apache.jena.riot.thrift.wire.RDF_Term ;
++import org.apache.thrift.TException ;
++import org.apache.thrift.protocol.TProtocol ;
++import org.seaborne.dboe.base.file.BinaryDataFile ;
++import org.seaborne.dboe.index.Index ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.store.NodeIdFactory;
++
++/** NodeTable using Thrift for the I/O and storage. */
++
++public class NodeTableTRDF extends NodeTableNative {
++ // Write buffering is done in the underlying BinaryDataFile
++ BinaryDataFile diskFile ;
++ private TReadAppendFileTransport transport ;
++ private final TProtocol protocol ;
++
++ public NodeTableTRDF(Index nodeToId, BinaryDataFile objectFile) {
++ super(nodeToId) ;
++ try {
++ this.diskFile = objectFile ;
++ transport = new TReadAppendFileTransport(diskFile) ;
++ if ( ! transport.isOpen() )
++ transport.open();
++ this.protocol = TRDF.protocol(transport) ;
++ }
++ catch (Exception ex) {
++ throw new TDBException("NodeTableTRDF", ex) ;
++ }
++ }
++
++ @Override
++ protected NodeId writeNodeToTable(Node node) {
++ RDF_Term term = ThriftConvert.convert(node, true) ;
++ try {
++ long x = diskFile.length() ;
++ // Paired : [*]
++ NodeId nid = NodeIdFactory.createPtr(x);
++ term.write(protocol) ;
++ //transport.flush() ;
++ return nid ;
++ }
++ catch (Exception ex) {
++ throw new TDBException("NodeTableThrift/Write", ex) ;
++ }
++ }
++
++ @Override
++ protected Node readNodeFromTable(NodeId id) {
++ try {
++ // Paired : [*]
++ long x = id.getPtrLocation();
++ transport.readPosition(x) ;
++ RDF_Term term = new RDF_Term() ;
++ term.read(protocol) ;
++ Node n = ThriftConvert.convert(term) ;
++ return n ;
++ }
++ catch (TException ex) {
++ throw new TDBException("NodeTableTRDF/Read", ex) ;
++ }
++ catch (RiotThriftException ex) {
++ Log.error(this, "Bad encoding: NodeId = "+id) ;
++ throw ex ;
++ }
++ }
++
++ @Override
++ protected void syncSub() {
++ try { transport.flush(); }
++ catch (Exception ex) { throw new TDBException("NodeTableTRDF", ex) ; }
++ }
++
++ @Override
++ protected void closeSub() {
++ if ( transport.isOpen() ) {
++ try { transport.close() ; }
++ catch (Exception ex) { throw new TDBException("NodeTableTRDF", ex) ; }
++ }
++ }
++
++ public Index getIndex() { return nodeHashToId ; }
++ public BinaryDataFile getData() { return diskFile ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableWrapper.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableWrapper.java
index 0000000,0000000..f18203d
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableWrapper.java
@@@ -1,0 -1,0 +1,93 @@@
++/*
++ * 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.nodetable ;
++
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.apache.jena.atlas.lib.Pair ;
++import org.apache.jena.graph.Node ;
++import org.seaborne.tdb2.store.NodeId ;
++
++public class NodeTableWrapper implements NodeTable {
++ protected final NodeTable nodeTable ;
++
++ @Override
++ public final NodeTable wrapped() {
++ return nodeTable ;
++ }
++
++ protected NodeTableWrapper(NodeTable nodeTable) {
++ this.nodeTable = nodeTable ;
++ }
++
++ @Override
++ public NodeId getAllocateNodeId(Node node) {
++ return nodeTable.getAllocateNodeId(node) ;
++ }
++
++ @Override
++ public NodeId getNodeIdForNode(Node node) {
++ return nodeTable.getNodeIdForNode(node) ;
++ }
++
++ @Override
++ public Node getNodeForNodeId(NodeId id) {
++ return nodeTable.getNodeForNodeId(id) ;
++ }
++
++ @Override
++ public boolean containsNode(Node node) {
++ return nodeTable.containsNode(node) ;
++ }
++
++ @Override
++ public boolean containsNodeId(NodeId nodeId) {
++ return nodeTable.containsNodeId(nodeId) ;
++ }
++
++ @Override
++ public List<NodeId> bulkNodeToNodeId(List<Node> nodes, boolean withAllocation) {
++ return nodeTable.bulkNodeToNodeId(nodes, withAllocation) ;
++ }
++
++ @Override
++ public List<Node> bulkNodeIdToNode(List<NodeId> nodeIds) {
++ return nodeTable.bulkNodeIdToNode(nodeIds) ;
++ }
++
++ @Override
++ public Iterator<Pair<NodeId, Node>> all() {
++ return nodeTable.all() ;
++ }
++
++ @Override
++ public boolean isEmpty() {
++ return nodeTable.isEmpty() ;
++ }
++
++ @Override
++ public void sync() {
++ nodeTable.sync() ;
++ }
++
++ @Override
++ public void close() {
++ nodeTable.close() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/TReadAppendFileTransport.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/TReadAppendFileTransport.java
index 0000000,0000000..34eebfb
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/TReadAppendFileTransport.java
@@@ -1,0 -1,0 +1,85 @@@
++/*
++ * 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.nodetable;
++
++import java.util.Objects ;
++
++import org.apache.thrift.transport.TTransport ;
++import org.seaborne.dboe.base.file.BinaryDataFile ;
++
++/** A file transport that supports random access read and
++ * buffered append write.
++ * <p>
++ * Adapter TTransport -> BinaryDataFile
++ */
++public class TReadAppendFileTransport extends TTransport {
++ private BinaryDataFile file ;
++ private long readPosn = -1 ;
++
++ public TReadAppendFileTransport(BinaryDataFile file) {
++ Objects.requireNonNull(file) ;
++ this.file = file ;
++ }
++
++ @Override
++ public boolean isOpen() {
++ return file.isOpen() ;
++ }
++
++ @Override
++ public void open() {
++ file.open() ;
++ }
++
++ @Override
++ public void close() {
++ file.close() ;
++ }
++
++ public void truncate(long posn) {
++ file.truncate(posn);
++ }
++
++ public BinaryDataFile getBinaryDataFile() { return file ; }
++
++ public long readPosition() {
++ return readPosn ;
++ }
++
++ public void readPosition(long posn) {
++ readPosn = posn ;
++ }
++
++ @Override
++ public int read(byte[] buf, int off, int len) {
++ int x = file.read(readPosn, buf, off, len) ;
++ readPosn += x ;
++ return x ;
++ }
++
++ @Override
++ public void write(byte[] buf, int off, int len) {
++ file.write(buf, off, len) ;
++ }
++
++ @Override
++ public void flush() {
++ file.sync();
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTable.java
index 0000000,0000000..4d48189
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTable.java
@@@ -1,0 -1,0 +1,71 @@@
++/*
++ * 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.nodetupletable ;
++
++import java.util.Iterator ;
++
++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.NodeId ;
++import org.seaborne.tdb2.store.nodetable.NodeTable ;
++import org.seaborne.tdb2.store.tupletable.TupleTable ;
++
++public interface NodeTupleTable extends Sync, Closeable
++{
++ public void addRow(Node... nodes) ;
++
++ public void deleteRow(Node... nodes) ;
++
++ /** Find by node. */
++ public Iterator<Tuple<Node>> find(Node... nodes) ;
++
++ /** Find by node - return an iterator of NodeIds. Can return "null" for not found as well as NullIterator */
++ public Iterator<Tuple<NodeId>> findAsNodeIds(Node... nodes) ;
++
++ /** Find by NodeId. */
++ public Iterator<Tuple<NodeId>> find(NodeId... ids) ;
++
++ /** Find by NodeId. */
++ public Iterator<Tuple<NodeId>> find(Tuple<NodeId> ids) ;
++
++ /** Find all tuples */
++ public Iterator<Tuple<NodeId>> findAll() ;
++
++ /** Return the undelying tuple table - used with great care by tools
++ * that directly manipulate internal structures.
++ */
++ public TupleTable getTupleTable() ;
++
++ /** Return the node table */
++ public NodeTable getNodeTable() ;
++
++ public boolean isEmpty() ;
++
++ /** Clear the tuple table. After this operation, find* will find nothing.
++ * This does not mean all data has been removed - for example, it does not mean
++ * that any node table has been emptied.
++ */
++ public void clear() ;
++
++ // No clear operation - need to manage the tuple table
++ // and node tables separately.
++
++ public long size() ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableConcrete.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableConcrete.java
index 0000000,0000000..e2fc5a9
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableConcrete.java
@@@ -1,0 -1,0 +1,240 @@@
++/*
++ * 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.nodetupletable ;
++
++import static java.lang.String.format ;
++
++import java.util.Iterator ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++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.NodeId ;
++import org.seaborne.tdb2.store.nodetable.NodeTable ;
++import org.seaborne.tdb2.store.tupletable.TupleIndex ;
++import org.seaborne.tdb2.store.tupletable.TupleTable ;
++
++/** Group a tuple table and node table together to provide a real NodeTupleTable */
++public class NodeTupleTableConcrete implements NodeTupleTable
++{
++ protected final NodeTable nodeTable ;
++ protected final TupleTable tupleTable ;
++
++ /*
++ * Concurrency checking: Everything goes through one of
++ * addRow, deleteRow or find*
++ */
++
++ public NodeTupleTableConcrete(int N, TupleIndex[] indexes, NodeTable nodeTable)
++ {
++ if (indexes.length == 0 || indexes[0] == null) throw new TDBException("A primary index is required") ;
++ for (TupleIndex index : indexes)
++ {
++ if (N != index.getTupleLength())
++ throw new TDBException(format("Inconsistent: TupleTable width is %d but index %s is %d",
++ N, index.getMappingStr(), index.getTupleLength())) ;
++ }
++
++ this.tupleTable = new TupleTable(N, indexes) ;
++ this.nodeTable = nodeTable ;
++ }
++
++ private void startWrite() { }
++
++ private void finishWrite() { }
++
++ private void startRead() { }
++
++ private void finishRead() { }
++
++ @Override
++ public void addRow(Node... nodes)
++ {
++ try {
++ startWrite() ;
++ NodeId n[] = new NodeId[nodes.length] ;
++ for (int i = 0; i < nodes.length; i++)
++ n[i] = nodeTable.getAllocateNodeId(nodes[i]) ;
++
++ Tuple<NodeId> t = TupleFactory.create(n) ;
++ tupleTable.add(t) ;
++ } finally
++ {
++ finishWrite() ;
++ }
++ }
++
++ @Override
++ public void deleteRow(Node... nodes)
++ {
++ try
++ {
++ startWrite() ;
++ NodeId n[] = new NodeId[nodes.length] ;
++ for (int i = 0; i < nodes.length; i++)
++ {
++ NodeId id = idForNode(nodes[i]) ;
++ if (NodeId.isDoesNotExist(id)) return ;
++ n[i] = id ;
++ }
++
++ Tuple<NodeId> t = TupleFactory.create(n) ;
++ tupleTable.delete(t) ;
++ } finally
++ {
++ finishWrite() ;
++ }
++ }
++
++ /** Find by node. */
++ @Override
++ public Iterator<Tuple<Node>> find(Node... nodes)
++ {
++ try {
++ startRead() ;
++ Iterator<Tuple<NodeId>> iter1 = findAsNodeIds(nodes) ; // **public call
++ if (iter1 == null)
++ return Iter.nullIterator() ;
++ Iterator<Tuple<Node>> iter2 = TupleLib.convertToNodes(nodeTable, iter1) ;
++ return iteratorControl(iter2) ;
++ } finally { finishRead() ; }
++ }
++
++ /**
++ * Find by node - return an iterator of NodeIds.
++ * Can return "null" (when a node is known to be unknown)
++ * for not found as well as NullIterator (when
++ * no tuples are found (unknown unknown).
++ */
++ @Override
++ public Iterator<Tuple<NodeId>> findAsNodeIds(Node... nodes)
++ {
++ NodeId n[] = new NodeId[nodes.length] ;
++ try {
++ startRead() ;
++ for (int i = 0; i < nodes.length; i++)
++ {
++ NodeId id = idForNode(nodes[i]) ;
++ if (NodeId.isDoesNotExist(id))
++ return Iter.nullIterator() ;
++ n[i] = id ;
++ }
++ return find(n) ; // **public call
++ } finally { finishRead() ; }
++ }
++
++ /** Find by NodeId. */
++ @Override
++ public Iterator<Tuple<NodeId>> find(NodeId... ids)
++ {
++ Tuple<NodeId> tuple = TupleFactory.create(ids) ;
++ return find(tuple) ;
++ }
++
++ /** Find by NodeId. */
++ @Override
++ public Iterator<Tuple<NodeId>> find(Tuple<NodeId> tuple)
++ {
++ // All find/*, except findAll, comes through this operation so startRead/finishRead/checkIterator only needs to happen here.
++ try {
++ startRead() ;
++ // find worker - need also protect iterators that access the node table.
++ Iterator<Tuple<NodeId>> iter = tupleTable.find(tuple) ;
++ return iteratorControl(iter) ;
++ } finally { finishRead() ; }
++ }
++
++ @Override
++ public Iterator<Tuple<NodeId>> findAll()
++ {
++ try {
++ startRead() ;
++ return iteratorControl(tupleTable.getIndex(0).all()) ;
++ } finally { finishRead() ; }
++ }
++
++ // ==== Node
++
++ protected final NodeId idForNode(Node node) {
++ if ( node == null || node == Node.ANY )
++ return NodeId.NodeIdAny ;
++ if ( node.isVariable() )
++ throw new TDBException("Can't pass variables to NodeTupleTable.find*") ;
++ return nodeTable.getNodeIdForNode(node) ;
++ }
++
++ // ==== Accessors
++
++ /**
++ * Return the undelying tuple table - used with great care by tools that directly
++ * manipulate internal structures.
++ */
++ @Override
++ public final TupleTable getTupleTable() {
++ return tupleTable ;
++ }
++
++ /** Return the node table */
++ @Override
++ public final NodeTable getNodeTable() {
++ return nodeTable ;
++ }
++
++ @Override
++ public boolean isEmpty() {
++ return tupleTable.isEmpty() ;
++ }
++
++ /** Clear the tuple table - does not clear the node table */
++ @Override
++ public void clear() {
++ try {
++ startWrite() ;
++ tupleTable.clear() ;
++ } finally { finishWrite() ; }
++ }
++
++ @Override
++ public long size() {
++ return tupleTable.size() ;
++ }
++
++ @Override
++ public final void close() {
++ try {
++ startWrite() ;
++ tupleTable.close() ;
++ nodeTable.close() ;
++ } finally { finishWrite() ; }
++ }
++
++ @Override
++ public final void sync() {
++ try {
++ startWrite() ;
++ tupleTable.sync() ;
++ nodeTable.sync() ;
++ } finally { finishWrite() ; }
++ }
++
++ // Add any iterator checking.
++ private <T> Iterator<T> iteratorControl(Iterator<T> iter) { return iter; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableView.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableView.java
index 0000000,0000000..ea24558
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableView.java
@@@ -1,0 -1,0 +1,112 @@@
++/*
++ * 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.nodetupletable;
++
++import java.util.Iterator ;
++
++import org.apache.jena.atlas.lib.ArrayUtils ;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.graph.Node ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.store.tupletable.TupleTable ;
++
++/** (Read-only?) projection of another NodeTupleTable.
++ * This will not reduce a N-wide tuple to N-1 when find*() used.
++ */
++public class NodeTupleTableView extends NodeTupleTableWrapper
++{
++ private Node prefix ;
++ private NodeId prefixId ;
++ //private boolean readOnly = false ;
++
++ public NodeTupleTableView(NodeTupleTable ntt, Node prefix)
++ {
++ super(ntt) ;
++ this.prefix = prefix ;
++ this.prefixId = ntt.getNodeTable().getNodeIdForNode(prefix) ;
++ }
++
++ @Override
++ public void addRow(Node... nodes)
++ {
++ nodes = push(Node.class, prefix, nodes) ;
++ super.addRow(nodes) ;
++ }
++
++ @Override
++ public void deleteRow(Node... nodes)
++ {
++ nodes = push(Node.class, prefix, nodes) ;
++ super.deleteRow(nodes) ;
++ }
++
++ @Override
++ public Iterator<Tuple<Node>> find(Node... nodes)
++ {
++ nodes = push(Node.class, prefix, nodes) ;
++ return nodeTupleTable.find(nodes) ;
++ }
++
++ private static <T> T[] push(Class<T> cls, T x, T[] array)
++ {
++ T[] array2 = ArrayUtils.alloc(cls, array.length+1) ;
++ System.arraycopy(array, 0, array2, 1, array.length) ;
++ array2[0] = x ;
++ return array2 ;
++ }
++
++ private static <T> T[] push(Class<T> cls, T x, Tuple<T> tuple)
++ {
++ T[] array2 = ArrayUtils.alloc(cls, tuple.len()+1) ;
++ tuple.copyInto(array2, 1);
++ array2[0] = x ;
++ return array2 ;
++ }
++
++ @Override
++ public Iterator<Tuple<NodeId>> find(NodeId... ids)
++ {
++ ids = push(NodeId.class, prefixId, ids) ;
++ return nodeTupleTable.find(ids) ;
++ }
++
++ @Override
++ public Iterator<Tuple<NodeId>> find(Tuple<NodeId> ids)
++ {
++ NodeId[] ids2 = push(NodeId.class, prefixId, ids) ;
++ return nodeTupleTable.find(ids2) ;
++ }
++
++ @Override
++ public Iterator<Tuple<NodeId>> findAsNodeIds(Node... nodes)
++ {
++ nodes = push(Node.class, prefix, nodes) ;
++ return nodeTupleTable.findAsNodeIds(nodes) ;
++ }
++
++// @Override
++// public boolean isReadOnly() { return readOnly ; }
++//
++// @Override
++// public void setReadOnly(boolean mode) { readOnly = mode ; }
++
++ @Override
++ public TupleTable getTupleTable()
++ // Need a projection of this?
++ { return super.getTupleTable() ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableWrapper.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableWrapper.java
index 0000000,0000000..952dda9
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetupletable/NodeTupleTableWrapper.java
@@@ -1,0 -1,0 +1,97 @@@
++/*
++ * 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.nodetupletable;
++
++import java.util.Iterator ;
++
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.graph.Node ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.store.nodetable.NodeTable ;
++import org.seaborne.tdb2.store.tupletable.TupleTable ;
++
++public class NodeTupleTableWrapper implements NodeTupleTable
++{
++ protected NodeTupleTable nodeTupleTable ;
++
++ public NodeTupleTableWrapper(NodeTupleTable ntt) {
++ setNodeTupleTable(ntt) ;
++ }
++
++ protected NodeTupleTable setNodeTupleTable(NodeTupleTable ntt) {
++ NodeTupleTable old = nodeTupleTable ;
++ nodeTupleTable = ntt ;
++ return old ;
++ }
++
++ @Override
++ public void addRow(Node... nodes)
++ { nodeTupleTable.addRow(nodes) ; }
++
++ @Override
++ public void deleteRow(Node... nodes)
++ { nodeTupleTable.deleteRow(nodes) ; }
++
++ @Override
++ public Iterator<Tuple<Node>> find(Node... nodes)
++ { return nodeTupleTable.find(nodes) ; }
++
++ @Override
++ public Iterator<Tuple<NodeId>> find(NodeId... ids)
++ { return nodeTupleTable.find(ids) ; }
++
++ @Override
++ public Iterator<Tuple<NodeId>> find(Tuple<NodeId> tuple)
++ { return nodeTupleTable.find(tuple) ; }
++
++ @Override
++ public Iterator<Tuple<NodeId>> findAsNodeIds(Node... nodes)
++ { return nodeTupleTable.findAsNodeIds(nodes) ; }
++
++ @Override
++ public Iterator<Tuple<NodeId>> findAll()
++ { return nodeTupleTable.findAll() ; }
++
++ @Override
++ public NodeTable getNodeTable()
++ { return nodeTupleTable.getNodeTable() ; }
++
++ @Override
++ public TupleTable getTupleTable()
++ { return nodeTupleTable.getTupleTable() ; }
++
++ @Override
++ public boolean isEmpty()
++ { return nodeTupleTable.isEmpty() ; }
++
++ @Override
++ public void clear()
++ { nodeTupleTable.clear(); }
++
++ @Override
++ public long size()
++ { return nodeTupleTable.size() ; }
++
++ @Override
++ public void sync()
++ { nodeTupleTable.sync() ; }
++
++ @Override
++ public void close()
++ { nodeTupleTable.close() ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleIndex.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleIndex.java
index 0000000,0000000..e3c8b47
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleIndex.java
@@@ -1,0 -1,0 +1,87 @@@
++/*
++ * 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.tupletable;
++
++import java.util.Collection ;
++import java.util.Iterator ;
++
++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.atlas.lib.tuple.TupleMap ;
++import org.seaborne.tdb2.store.NodeId ;
++
++public interface TupleIndex extends Sync, Closeable
++{
++ /** Insert a tuple */
++ public void add(Tuple<NodeId> tuple) ;
++
++ /** Delete a tuple */
++ public void delete(Tuple<NodeId> tuple) ;
++
++ /** Insert tuples */
++ public void addAll(Collection<Tuple<NodeId>> tuples) ;
++
++ /** Delete tuples */
++ public void deleteAll(Collection<Tuple<NodeId>> tuples) ;
++
++ /** Get a convenient display string for the index - do not rely on the format */
++ public String getName() ;
++
++ /** Get a convenient display string based on the details of the column map - do not rely on the format */
++ public String getMappingStr() ;
++
++ /** Get the mapping of tuples used by this index */
++ public TupleMap getMapping() ;
++
++ /** Find all matching tuples - a slot of NodeId.NodeIdAny (or null) means match any.
++ * Input pattern in natural order, not index order.
++ */
++ public Iterator<Tuple<NodeId>> find(Tuple<NodeId> pattern) ;
++
++ /** return an iterator of everything */
++ public Iterator<Tuple<NodeId>> all() ;
++
++ /** Weight a pattern - specified in normal order (not index order).
++ * Large numbers means better match. */
++ public int weight(Tuple<NodeId> pattern) ;
++
++ /** Length of tuple supported */
++ public int getTupleLength() ;
++
++ /** Size of index (number of slots). May be an estimate and not exact. -1 for unknown. */
++ public long size() ;
++
++ /** Answer whether empty or not */
++ public boolean isEmpty() ;
++
++ /** Clear the index */
++ public void clear() ;
++
++ /** Return a TupleIndex if this instance wraps another, else return null */
++ public TupleIndex wrapped() ;
++
++ default public TupleIndex baseTupleIndex() {
++ TupleIndex index = this ;
++ TupleIndex index2 = null ;
++ while( (index2 = index.wrapped()) != null ) {
++ index = index2 ;
++ }
++ return index ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleIndexBase.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleIndexBase.java
index 0000000,0000000..911950b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleIndexBase.java
@@@ -1,0 -1,0 +1,123 @@@
++/*
++ * 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.tupletable;
++
++import java.util.Iterator ;
++
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.atlas.lib.tuple.TupleMap ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.store.NodeId ;
++
++public abstract class TupleIndexBase implements TupleIndex
++{
++ private static final boolean Check = false ;
++
++ protected final TupleMap tupleMap ;
++ protected final int tupleLength ;
++
++ private final String name ;
++
++ protected TupleIndexBase(int N, TupleMap indexMapping, String name)
++ {
++ this.tupleLength = N ;
++ this.tupleMap = indexMapping ;
++ this.name = name ;
++ }
++
++ @Override
++ public TupleIndex wrapped() {
++ return null ;
++ }
++
++ /** Add tuple worker: Tuple passed in unmapped (untouched) order */
++ protected abstract void performAdd(Tuple<NodeId> tuple) ;
++
++ /** Delete tuple worker: Tuple passed in unmapped (untouched) order */
++ protected abstract void performDelete(Tuple<NodeId> tuple) ;
++
++ /** Find tuples worker: Tuple passed in unmaped (untouched) order */
++ protected abstract Iterator<Tuple<NodeId>> performFind(Tuple<NodeId> tuple) ;
++
++ /** Insert a tuple */
++ @Override
++ public final void add(Tuple<NodeId> tuple)
++ {
++ if ( Check ) {
++ if ( tupleLength != tuple.len() )
++ throw new TDBException(String.format("Mismatch: tuple length %d / index for length %d", tuple.len(), tupleLength));
++ }
++ performAdd(tuple) ;
++ }
++ /** Delete a tuple */
++ @Override
++ public final void delete(Tuple<NodeId> tuple)
++ {
++ if ( Check ) {
++ if ( tupleLength != tuple.len() )
++ throw new TDBException(String.format("Mismatch: tuple length %d / index for length %d", tuple.len(), tupleLength));
++ }
++
++ performDelete(tuple) ;
++ }
++
++ /** Find all matching tuples - a slot of NodeId.NodeIdAny (or null) means match any.
++ * Input pattern in natural order, not index order.
++ */
++ @Override
++ public final Iterator<Tuple<NodeId>> find(Tuple<NodeId> pattern)
++ {
++ if ( Check ) {
++ if ( tupleLength != pattern.len() )
++ throw new TDBException(String.format("Mismatch: tuple length %d / index for length %d", pattern.len(), tupleLength));
++ }
++ // null to NodeId.NodIdAny ??
++ return performFind(pattern) ;
++ }
++
++ @Override
++ public final int weight(Tuple<NodeId> pattern)
++ {
++ for ( int i = 0 ; i < tupleLength ; i++ )
++ {
++ NodeId X = tupleMap.mapSlot(i, pattern) ;
++ if ( undef(X) )
++ // End of fixed terms
++ return i ;
++ }
++ return tupleLength ;
++ }
++
++ @Override
++ public final String getMappingStr() { return tupleMap.getLabel() ; }
++
++ @Override
++ public final String getName() { return name ; }
++
++ @Override
++ public final int getTupleLength() { return tupleLength ; }
++
++ @Override
++ public final TupleMap getMapping() { return tupleMap ; }
++
++ protected final boolean undef(NodeId x)
++ { return NodeId.isAny(x) ; }
++
++ @Override
++ public String toString() { return "index:"+getName() ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleIndexRecord.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleIndexRecord.java
index 0000000,0000000..c723472
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleIndexRecord.java
@@@ -1,0 -1,0 +1,237 @@@
++/*
++ * 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.tupletable;
++
++import static java.lang.String.format ;
++import static org.seaborne.tdb2.sys.SystemTDB.SizeOfNodeId ;
++
++import java.util.Collection ;
++import java.util.Iterator ;
++import java.util.function.Predicate ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import org.apache.jena.atlas.iterator.NullIterator ;
++import org.apache.jena.atlas.iterator.SingletonIterator ;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.atlas.lib.tuple.TupleMap ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.index.RangeIndex ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.lib.TupleLib ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.store.NodeIdFactory;
++
++public class TupleIndexRecord extends TupleIndexBase
++{
++ private static final boolean Check = false ;
++ private RangeIndex index ;
++ private RecordFactory factory ;
++
++ public TupleIndexRecord(int N, TupleMap tupleMapping, String name, RecordFactory factory, RangeIndex index)
++ {
++ super(N, tupleMapping, name) ;
++ this.factory = factory ;
++ this.index = index ;
++
++ if ( factory.keyLength() != N*SizeOfNodeId)
++ throw new TDBException(format("Mismatch: TupleIndex of length %d is not comparative with a factory for key length %d", N, factory.keyLength())) ;
++ }
++
++ /** Insert a tuple */
++ @Override
++ protected void performAdd(Tuple<NodeId> tuple) {
++ Record r = TupleLib.record(factory, tuple, tupleMap) ;
++ index.insert(r) ;
++ }
++
++ /** Delete a tuple */
++ @Override
++ protected void performDelete(Tuple<NodeId> tuple) {
++ Record r = TupleLib.record(factory, tuple, tupleMap) ;
++ index.delete(r) ;
++ }
++
++ /** Insert tuples */
++ @Override
++ public void addAll(Collection<Tuple<NodeId>> tuples) {
++ for ( Tuple<NodeId> t : tuples )
++ add(t) ;
++ }
++
++ /** Delete tuples */
++ @Override
++ public void deleteAll(Collection<Tuple<NodeId>> tuples) {
++ for ( Tuple<NodeId> t : tuples )
++ delete(t) ;
++ }
++
++ /** Find all matching tuples - a slot of NodeId.NodeIdAny (or null) means match any.
++ * Input pattern in natural order, not index order.
++ */
++
++ @Override
++ protected Iterator<Tuple<NodeId>> performFind(Tuple<NodeId> pattern) {
++ return findOrScan(pattern) ;
++ }
++
++ // Package visibility for testing.
++ final Iterator<Tuple<NodeId>> findOrScan(Tuple<NodeId> pattern) {
++ return findWorker(pattern, true, true) ;
++ }
++
++ final Iterator<Tuple<NodeId>> findOrPartialScan(Tuple<NodeId> pattern) {
++ return findWorker(pattern, true, false) ;
++ }
++
++ final Iterator<Tuple<NodeId>> findByIndex(Tuple<NodeId> pattern) {
++ return findWorker(pattern, false, false) ;
++ }
++
++ private Iterator<Tuple<NodeId>> findWorker(Tuple<NodeId> patternNaturalOrder, boolean partialScanAllowed, boolean fullScanAllowed) {
++ if ( Check )
++ {
++ if ( tupleLength != patternNaturalOrder.len() )
++ throw new TDBException(String.format("Mismatch: tuple length %d / index for length %d", patternNaturalOrder.len(), tupleLength)) ;
++ }
++
++ // Convert to index order.
++ Tuple<NodeId> pattern = tupleMap.map(patternNaturalOrder) ;
++
++ // Canonical form.
++ int numSlots = 0 ;
++ int leadingIdx = -2; // Index of last leading pattern NodeId. Start less than numSlots-1
++ boolean leading = true ;
++
++ // Records.
++ Record minRec = factory.createKeyOnly() ;
++ Record maxRec = factory.createKeyOnly() ;
++
++ // Set the prefixes.
++ for ( int i = 0 ; i < pattern.len() ; i++ ) {
++ NodeId X = pattern.get(i) ;
++ if ( NodeId.isAny(X) ) {
++ X = null ;
++ // No longer seting leading key slots.
++ leading = false ;
++ continue ;
++ }
++// if ( NodeId.isDoesNotExist(X) )
++// return Iter.nullIterator();
++
++ numSlots++ ;
++ if ( leading ) {
++ leadingIdx = i ;
++ NodeIdFactory.set(X, minRec.getKey(), i*SizeOfNodeId) ;
++ NodeIdFactory.set(X, maxRec.getKey(), i*SizeOfNodeId) ;
++ }
++ }
++
++ // Is it a simple existence test?
++ if ( numSlots == pattern.len() ) {
++ if ( index.contains(minRec) )
++ return new SingletonIterator<>(pattern) ;
++ else
++ return new NullIterator<>() ;
++ }
++
++ Iterator<Record> iter = null ;
++
++ if ( leadingIdx < 0 ) {
++ if ( ! fullScanAllowed )
++ return null ;
++ //System.out.println("Full scan") ;
++ // Full scan necessary
++ iter = index.iterator() ;
++ } else {
++ // Adjust the maxRec.
++ NodeId X = pattern.get(leadingIdx) ;
++ // Set the max Record to the leading NodeIds, +1.
++ // Example, SP? inclusive to S(P+1)? exclusive where ? is zero.
++ NodeIdFactory.setNext(X, maxRec.getKey(), leadingIdx*SizeOfNodeId) ;
++ iter = index.iterator(minRec, maxRec) ;
++ }
++
++ Iterator<Tuple<NodeId>> tuples = Iter.map(iter, item -> TupleLib.tuple(item, tupleMap)) ;
++
++ if ( leadingIdx < numSlots-1 ) {
++ if ( ! partialScanAllowed )
++ return null ;
++ // Didn't match all defined slots in request.
++ // Partial or full scan needed.
++ //pattern.unmap(colMap) ;
++ tuples = scan(tuples, patternNaturalOrder) ;
++ }
++
++ return tuples ;
++ }
++
++ @Override
++ public Iterator<Tuple<NodeId>> all()
++ {
++ Iterator<Record> iter = index.iterator() ;
++ return Iter.map(iter, item -> TupleLib.tuple(item, tupleMap)) ;
++ }
++
++ private Iterator<Tuple<NodeId>> scan(Iterator<Tuple<NodeId>> iter, Tuple<NodeId> pattern) {
++ Predicate<Tuple<NodeId>> filter = (item) -> {
++ // Check on pattern and item (both in natural order)
++ for ( int i = 0 ; i < tupleLength ; i++ ) {
++ NodeId n = pattern.get(i) ;
++ // The pattern must be null/Any or match the tuple being tested.
++ if ( ! NodeId.isAny(n) )
++ if ( ! item.get(i).equals(n) )
++ return false ;
++ }
++ return true ;
++ } ;
++
++ return Iter.filter(iter, filter) ;
++ }
++
++ @Override
++ public void close() {
++ index.close() ;
++ }
++
++ @Override
++ public void sync() {
++ index.sync() ;
++ }
++
++ public final RangeIndex getRangeIndex() {
++ return index ;
++ }
++
++ //protected final RecordFactory getRecordFactory() { return factory ; }
++
++ @Override
++ public boolean isEmpty() {
++ return index.isEmpty() ;
++ }
++
++ @Override
++ public void clear() {
++ index.clear() ;
++ }
++
++ @Override
++ public long size() {
++ return index.size() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleIndexRecordAsyncBulkAdd.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleIndexRecordAsyncBulkAdd.java
index 0000000,0000000..242232e
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleIndexRecordAsyncBulkAdd.java
@@@ -1,0 -1,0 +1,262 @@@
++/*
++ * 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.tupletable;
++
++import static java.lang.String.format ;
++import static org.seaborne.tdb2.sys.SystemTDB.SizeOfNodeId ;
++
++import java.util.Collection ;
++import java.util.Iterator ;
++import java.util.function.Predicate ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import org.apache.jena.atlas.iterator.NullIterator ;
++import org.apache.jena.atlas.iterator.SingletonIterator ;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.atlas.lib.tuple.TupleMap ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.index.RangeIndex ;
++import org.seaborne.dboe.transaction.txn.Transaction ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.lib.Async ;
++import org.seaborne.tdb2.lib.TupleLib ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.store.NodeIdFactory;
++
++// Async addAll
++public class TupleIndexRecordAsyncBulkAdd extends TupleIndexBase
++{
++ private static final boolean Check = false ;
++ private RangeIndex index ;
++ private RecordFactory factory ;
++
++ public TupleIndexRecordAsyncBulkAdd(int N, TupleMap tupleMapping, String name, RecordFactory factory, RangeIndex index)
++ {
++ super(N, tupleMapping, name) ;
++ this.factory = factory ;
++ this.index = index ;
++
++ if ( factory.keyLength() != N*SizeOfNodeId)
++ throw new TDBException(format("Mismatch: TupleIndex of length %d is not comparative with a factory for key length %d", N, factory.keyLength())) ;
++ }
++
++ /** Insert a tuple */
++ @Override
++ protected void performAdd(Tuple<NodeId> tuple) {
++ switchToSync() ;
++ Record r = TupleLib.record(factory, tuple, tupleMap) ;
++ index.insert(r) ;
++ }
++
++ /** Delete a tuple */
++ @Override
++ protected void performDelete(Tuple<NodeId> tuple) {
++ switchToSync() ;
++ Record r = TupleLib.record(factory, tuple, tupleMap) ;
++ index.delete(r) ;
++ }
++
++ private void switchToSync() {
++ async.completeAsyncOperations();
++ }
++
++ Async async = new Async(1,2) ;
++ Object lock = new Object() ;
++
++ /** Insert tuples */
++ @Override
++ public void addAll(Collection<Tuple<NodeId>> tuples) {
++ Transaction txn = null ;
++ // pass into async block.
++
++ async.execAsync(lock, () -> {
++ // Transaction?
++
++ System.out.println(">>Async") ;
++ for ( Tuple<NodeId> t : tuples ) {
++ Record r = TupleLib.record(factory, t, tupleMap) ;
++ index.insert(r) ;
++ }
++ System.out.println("<<Async") ;
++ }) ;
++ }
++
++ /** Delete tuples */
++ @Override
++ public void deleteAll(Collection<Tuple<NodeId>> tuples) {
++ tuples.stream().forEach(this::delete);
++ }
++
++ /** Find all matching tuples - a slot of NodeId.NodeIdAny (or null) means match any.
++ * Input pattern in natural order, not index order.
++ */
++
++ @Override
++ protected Iterator<Tuple<NodeId>> performFind(Tuple<NodeId> pattern) {
++ switchToSync() ;
++ return findOrScan(pattern) ;
++ }
++
++ // Package visibility for testing.
++ final Iterator<Tuple<NodeId>> findOrScan(Tuple<NodeId> pattern) {
++ return findWorker(pattern, true, true) ;
++ }
++
++ final Iterator<Tuple<NodeId>> findOrPartialScan(Tuple<NodeId> pattern) {
++ return findWorker(pattern, true, false) ;
++ }
++
++ final Iterator<Tuple<NodeId>> findByIndex(Tuple<NodeId> pattern) {
++ return findWorker(pattern, false, false) ;
++ }
++
++ private Iterator<Tuple<NodeId>> findWorker(Tuple<NodeId> patternNaturalOrder, boolean partialScanAllowed, boolean fullScanAllowed) {
++ switchToSync();
++ if ( Check && tupleLength != patternNaturalOrder.len() )
++ throw new TDBException(String.format("Mismatch: tuple length %d / index for length %d", patternNaturalOrder.len(), tupleLength));
++
++ // Convert to index order.
++ Tuple<NodeId> pattern = tupleMap.map(patternNaturalOrder) ;
++
++ // Canonical form.
++ int numSlots = 0 ;
++ int leadingIdx = -2; // Index of last leading pattern NodeId. Start less than numSlots-1
++ boolean leading = true ;
++
++ // Records.
++ Record minRec = factory.createKeyOnly() ;
++ Record maxRec = factory.createKeyOnly() ;
++
++ // Set the prefixes.
++ for ( int i = 0 ; i < pattern.len() ; i++ ) {
++ NodeId X = pattern.get(i) ;
++ if ( NodeId.isAny(X) ) {
++ X = null ;
++ // No longer setting leading key slots.
++ leading = false ;
++ continue ;
++ }
++
++ numSlots++ ;
++ if ( leading ) {
++ leadingIdx = i ;
++ NodeIdFactory.set(X, minRec.getKey(), i*SizeOfNodeId) ;
++ NodeIdFactory.set(X, maxRec.getKey(), i*SizeOfNodeId) ;
++ }
++ }
++
++ // Is it a simple existence test?
++ if ( numSlots == pattern.len() ) {
++ if ( index.contains(minRec) )
++ return new SingletonIterator<>(pattern) ;
++ else
++ return new NullIterator<>() ;
++ }
++
++ Iterator<Record> iter = null ;
++
++ if ( leadingIdx < 0 ) {
++ if ( ! fullScanAllowed )
++ return null ;
++ //System.out.println("Full scan") ;
++ // Full scan necessary
++ iter = index.iterator() ;
++ } else {
++ // Adjust the maxRec.
++ NodeId X = pattern.get(leadingIdx) ;
++ // Set the max Record to the leading NodeIds, +1.
++ // Example, SP? inclusive to S(P+1)? exclusive where ? is zero.
++ NodeIdFactory.setNext(X, maxRec.getKey(), leadingIdx*SizeOfNodeId) ;
++ iter = index.iterator(minRec, maxRec) ;
++ }
++
++ Iterator<Tuple<NodeId>> tuples = Iter.map(iter, item -> TupleLib.tuple(item, tupleMap)) ;
++
++ if ( leadingIdx < numSlots-1 ) {
++ if ( ! partialScanAllowed )
++ return null ;
++ // Didn't match all defined slots in request.
++ // Partial or full scan needed.
++ //pattern.unmap(colMap) ;
++ tuples = scan(tuples, patternNaturalOrder) ;
++ }
++
++ return tuples ;
++ }
++
++ @Override
++ public Iterator<Tuple<NodeId>> all()
++ {
++ switchToSync() ;
++ Iterator<Record> iter = index.iterator() ;
++ return Iter.map(iter, item -> TupleLib.tuple(item, tupleMap)) ;
++ }
++
++ private Iterator<Tuple<NodeId>> scan(Iterator<Tuple<NodeId>> iter, Tuple<NodeId> pattern) {
++ Predicate<Tuple<NodeId>> filter = (item) -> {
++ // Check on pattern and item (both in natural order)
++ for ( int i = 0 ; i < tupleLength ; i++ ) {
++ NodeId n = pattern.get(i) ;
++ // The pattern must be null/Any or match the tuple being tested.
++ if ( ! NodeId.isAny(n) )
++ if ( ! item.get(i).equals(n) )
++ return false ;
++ }
++ return true ;
++ } ;
++
++ return Iter.filter(iter, filter) ;
++ }
++
++ @Override
++ public void close() {
++ switchToSync() ;
++ index.close() ;
++ }
++
++ @Override
++ public void sync() {
++ switchToSync() ;
++ index.sync() ;
++ }
++
++ public final RangeIndex getRangeIndex() {
++ return index ;
++ }
++
++ //protected final RecordFactory getRecordFactory() { return factory ; }
++
++ @Override
++ public boolean isEmpty() {
++ switchToSync() ;
++ return index.isEmpty() ;
++ }
++
++ @Override
++ public void clear() {
++ switchToSync() ;
++ index.clear() ;
++ }
++
++ @Override
++ public long size() {
++ switchToSync() ;
++ return index.size() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleIndexWrapper.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleIndexWrapper.java
index 0000000,0000000..43f4b72
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleIndexWrapper.java
@@@ -1,0 -1,0 +1,117 @@@
++/*
++ * 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.tupletable;
++
++import java.util.Collection ;
++import java.util.Iterator ;
++
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.atlas.lib.tuple.TupleMap ;
++import org.seaborne.tdb2.store.NodeId ;
++
++public class TupleIndexWrapper implements TupleIndex
++{
++ protected final TupleIndex index ;
++
++ public TupleIndexWrapper(TupleIndex index) { this.index = index ; }
++
++ @Override
++ public final TupleIndex wrapped() {
++ return index ;
++ }
++
++ @Override
++ public void add(Tuple<NodeId> tuple) {
++ index.add(tuple) ;
++ }
++
++ @Override
++ public void addAll(Collection<Tuple<NodeId>> tuples) {
++ index.addAll(tuples) ;
++ }
++
++ @Override
++ public void delete(Tuple<NodeId> tuple) {
++ index.delete(tuple) ;
++ }
++
++ @Override
++ public void deleteAll(Collection<Tuple<NodeId>> tuples) {
++ index.deleteAll(tuples);
++ }
++
++ @Override
++ public Iterator<Tuple<NodeId>> find(Tuple<NodeId> pattern) {
++ return index.find(pattern) ;
++ }
++
++ @Override
++ public Iterator<Tuple<NodeId>> all() {
++ return index.all() ;
++ }
++
++ @Override
++ public int getTupleLength() {
++ return index.getTupleLength() ;
++ }
++
++ @Override
++ public String getMappingStr() {
++ return index.getMappingStr() ;
++ }
++
++ @Override
++ public TupleMap getMapping() {
++ return index.getMapping() ;
++ }
++
++ @Override
++ public String getName() {
++ return index.getName() ;
++ }
++
++ @Override
++ public int weight(Tuple<NodeId> pattern) {
++ return index.weight(pattern) ;
++ }
++
++ @Override
++ public long size() {
++ return index.size() ;
++ }
++
++ @Override
++ public boolean isEmpty() {
++ return index.isEmpty() ;
++ }
++
++ @Override
++ public void clear() {
++ index.clear() ;
++ }
++
++ @Override
++ public void sync() {
++ index.sync() ;
++ }
++
++ @Override
++ public void close() {
++ index.close() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleTable.java
index 0000000,0000000..d02df70
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/tupletable/TupleTable.java
@@@ -1,0 -1,0 +1,218 @@@
++/*
++ * 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.tupletable;
++
++import static java.lang.String.format ;
++
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.apache.jena.atlas.iterator.Iter;
++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.atlas.logging.Log ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/** A TupleTable is a set of TupleIndexes. The first TupleIndex is the "primary" index and must exist */
++public class TupleTable implements Sync, Closeable
++{
++ private static Logger log = LoggerFactory.getLogger(TupleTable.class) ;
++
++ private final TupleIndex[] indexes ;
++ private final TupleIndex scanAllIndex ; // Use this index if a complete scan is needed.
++ private final int tupleLen ;
++ private boolean syncNeeded = false ;
++
++ public TupleTable(int tupleLen, TupleIndex[] indexes)
++ {
++ this.tupleLen = tupleLen ;
++ this.indexes = indexes ;
++ if ( indexes[0] == null )
++ throw new TDBException("TupleTable: no primary index") ;
++ for ( TupleIndex index : indexes )
++ {
++ if ( index != null && index.getTupleLength() != tupleLen )
++ throw new TDBException("Incompatible index: "+index.getMappingStr()) ;
++ }
++ scanAllIndex = chooseScanAllIndex(tupleLen, indexes) ;
++ }
++
++ /** Choose an index to scan in case we are asked for everything
++ * This needs to be ???G for the distinctAdjacent filter in union query to work.
++ */
++ private static TupleIndex chooseScanAllIndex(int tupleLen, TupleIndex[] indexes)
++ {
++ if ( tupleLen != 4 )
++ return indexes[0] ;
++
++ for ( TupleIndex index : indexes )
++ {
++ // First look for SPOG
++ if ( index.getName().equals("SPOG") )
++ return index ;
++ }
++
++ for ( TupleIndex index : indexes )
++ {
++ // Then look for any ???G
++ if ( index.getName().endsWith("G") )
++ return index ;
++ }
++
++ Log.warn(SystemTDB.errlog, "Did not find a ???G index for full scans") ;
++ return indexes[0] ;
++ }
++
++ /** Insert a tuple */
++ public void add(Tuple<NodeId> t) {
++ // A "contains test" could be used to avoid needing to hit all
++ // the indexes when the triple is already present.
++ if ( tupleLen != t.len() )
++ throw new TDBException(format("Mismatch: inserting tuple of length %d into a table of tuples of length %d", t.len(), tupleLen)) ;
++ for ( int i = 0 ; i < indexes.length ; i++ ) {
++ if ( indexes[i] == null ) continue ;
++ indexes[i].add(t) ;
++ syncNeeded = true ;
++ }
++ }
++
++ /** Insert tuples */
++ public void addAll(List<Tuple<NodeId>> t) {
++ // Parallel.
++ for ( int i = 0 ; i < indexes.length ; i++ ) {
++ if ( indexes[i] == null ) continue ;
++ indexes[i].addAll(t) ;
++ syncNeeded = true ;
++ }
++ }
++
++ /** Delete a tuple */
++ public void delete( Tuple<NodeId> t ) {
++ if ( tupleLen != t.len() )
++ throw new TDBException(format("Mismatch: deleting tuple of length %d from a table of tuples of length %d", t.len(), tupleLen)) ;
++
++ for ( TupleIndex index : indexes ) {
++ if ( index == null )
++ continue;
++ index.delete( t );
++ }
++ }
++
++ /** Delete tuples */
++ public void deleteAll(List<Tuple<NodeId>> t) {
++ // Parallel.
++ for ( int i = 0 ; i < indexes.length ; i++ ) {
++ if ( indexes[i] == null ) continue ;
++ indexes[i].deleteAll(t) ;
++ syncNeeded = true ;
++ }
++ }
++
++ /** Find all matching tuples - a slot of NodeId.NodeIdAny means match any */
++ public Iterator<Tuple<NodeId>> find(Tuple<NodeId> pattern) {
++ if ( tupleLen != pattern.len() )
++ throw new TDBException(format("Mismatch: finding tuple of length %d in a table of tuples of length %d", pattern.len(), tupleLen)) ;
++
++ int numSlots = 0 ;
++ // Canonical form.
++ for ( int i = 0 ; i < tupleLen ; i++ ) {
++ NodeId x = pattern.get(i) ;
++ if ( ! NodeId.isAny(x) )
++ numSlots++ ;
++ if ( NodeId.isDoesNotExist(x))
++ return Iter.nullIterator();
++ }
++
++ if ( numSlots == 0 )
++ return scanAllIndex.all() ;
++
++ int indexNumSlots = 0 ;
++ TupleIndex index = null ;
++ for ( TupleIndex idx : indexes ) {
++ if ( idx != null ) {
++ int w = idx.weight( pattern );
++ if ( w > indexNumSlots ) {
++ indexNumSlots = w;
++ index = idx;
++ }
++ }
++ }
++
++ if ( index == null )
++ // No index at all. Scan.
++ index = indexes[0] ;
++ return index.find(pattern) ;
++ }
++
++ @Override
++ final public void close() {
++ for ( TupleIndex idx : indexes ) {
++ if ( idx != null )
++ idx.close();
++ }
++ }
++
++ @Override
++ public void sync() {
++ if ( syncNeeded ) {
++ for ( TupleIndex idx : indexes ) {
++ if ( idx != null )
++ idx.sync() ;
++ }
++ syncNeeded = false ;
++ }
++ }
++
++ public boolean isEmpty() { return indexes[0].isEmpty() ; }
++
++ public void clear() {
++ for ( TupleIndex idx : indexes ) {
++ if ( idx != null )
++ idx.clear() ;
++ }
++ syncNeeded = true ;
++ }
++
++ public long size() {
++ return indexes[0].size() ;
++ }
++
++ /** Get i'th index */
++ public TupleIndex getIndex(int i) { return indexes[i] ; }
++
++ /** Get all indexes - for code that maipulates internal structures directly - use with care */
++ public TupleIndex[] getIndexes() { return indexes ; }
++
++ /** Get the width of tuples in indexes in this table */
++ public int getTupleLen() { return tupleLen ; }
++
++ /** Set index - for code that manipulates internal structures directly - use with care */
++ public void setTupleIndex(int i, TupleIndex index) {
++ if ( index != null && index.getTupleLength() != tupleLen )
++ throw new TDBException("Incompatible index: " + index.getMappingStr()) ;
++ indexes[i] = index ;
++ }
++
++ /** Number of indexes on this tuple table */
++ public int numIndexes() { return indexes.length ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/DateTimeNode.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/DateTimeNode.java
index 0000000,0000000..0853938
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/DateTimeNode.java
@@@ -1,0 -1,0 +1,253 @@@
++/*
++ * 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.value;
++
++import java.math.BigDecimal ;
++
++import javax.xml.datatype.DatatypeConfigurationException ;
++import javax.xml.datatype.DatatypeConstants ;
++import javax.xml.datatype.DatatypeFactory ;
++import javax.xml.datatype.XMLGregorianCalendar ;
++
++import org.apache.jena.atlas.lib.BitsInt ;
++import org.apache.jena.atlas.lib.BitsLong ;
++import org.apache.jena.atlas.lib.NumberUtils ;
++import org.seaborne.tdb2.TDBException ;
++
++public class DateTimeNode
++{
++ // ---- Layout
++ // Epoch base: 0000-01-01T00:00:00
++
++ // Layout:
++ // Bits 56-63 : type
++
++ // Bits 49-55 (7 bits) : timezone -- 15 min precision + special for Z and no timezone.
++ // Bits 27-48 (22 bits) : date, year is 13 bits = 8000 years (0 to 7999)
++ // Bits 0-26 (27 bits) : time, to milliseconds
++
++ // Layout:
++ // Hi: TZ YYYY MM DD HH MM SS.sss Lo:
++ // Looses the distinction between 00:00:00 vs 24:00:00 (of the day before).
++
++ // Const-ize
++ // 13 bits year, 4 bits month, 5 bits day => 22 bits
++ static final int DATE_LEN = 22;
++ // 5 bits hour + 6 bits minute + 16 bits seconds (to millisecond)
++ static final int TIME_LEN = 27;
++
++ static final int MILLI = 0;
++ static final int MILLI_LEN = 16;
++
++ static final int MINUTES = MILLI_LEN;
++ static final int MINUTES_LEN = 6;
++
++ static final int HOUR = MILLI_LEN + MINUTES_LEN;
++ static final int HOUR_LEN = 5;
++
++ static final int DAY = TIME_LEN;
++ static final int DAY_LEN = 5;
++
++ static final int MONTH = TIME_LEN + DAY_LEN;
++ static final int MONTH_LEN = 4;
++
++ static final int YEAR = TIME_LEN + MONTH_LEN + DAY_LEN;
++ static final int YEAR_LEN = 13;
++
++ static final int TZ = TIME_LEN + DATE_LEN;
++ static final int TZ_LEN = 7;
++ // Value for Z
++ static final int TZ_Z = 0x7F;
++ // Value for no timezone.
++ static final int TZ_NONE = 0x7E;
++
++ static DatatypeFactory datatypeFactory = null;
++ static {
++ try {
++ datatypeFactory = DatatypeFactory.newInstance();
++ }
++ catch (DatatypeConfigurationException ex) {
++ throw new TDBException("DateTimeNode", ex);
++ }
++ }
++
++ // Packed in correct place.
++ static long time(long v, int hour, int mins, int millisec) {
++ // And bit offset for direct packing?
++ // HH:MM:SS.ssss => 5 bits H, 6 bits M, 16 bits S ==> 27 bits
++ v = BitsLong.pack(v, hour, HOUR, HOUR + HOUR_LEN);
++ v = BitsLong.pack(v, mins, MINUTES, MINUTES + MINUTES_LEN);
++ v = BitsLong.pack(v, millisec, MILLI, MILLI + MILLI_LEN);
++ return v;
++ }
++
++ // Packed in correct place.
++ static long date(long v, int year, int month, int day) {
++ // YYYY:MM:DD => 13 bits year, 4 bits month, 5 bits day => 22 bits
++ v = BitsLong.pack(v, year, YEAR, YEAR + YEAR_LEN);
++ v = BitsLong.pack(v, month, MONTH, MONTH + MONTH_LEN);
++ v = BitsLong.pack(v, day, DAY, DAY + DAY_LEN);
++ return v;
++ }
++
++ static long tz(long v, int tz_in_quarters) {
++ v = BitsLong.pack(v, tz_in_quarters, TZ, TZ + TZ_LEN);
++ return v;
++ }
++
++ // From string. Assumed legal. Retains all info this way.
++ // returns -1 for unpackable.
++ public static long packDate(String lex) {
++ return packDateTime(lex);
++ }
++
++ // From string. Assumed legal.
++ // Returns -1 for unpackable.
++
++ public static long packDateTime(String lex) {
++ try {
++ return packDateTime$(lex);
++ }
++ catch (Exception ex) {
++ return -1;
++ }
++ }
++
++ private static long packDateTime$(String lex) {
++ long v = 0;
++ // Whitespace facet processing.
++ lex = lex.trim();
++
++ boolean containsZ = (lex.indexOf('Z') > 0);
++
++ // Bug in Java 1.6 (build 5 at least)
++ // T24:00:00 not accepted.
++ // See also TestNodeId.nodeId_date_time_7
++
++ XMLGregorianCalendar xcal = datatypeFactory.newXMLGregorianCalendar(lex);
++
++ if ( xcal.getFractionalSecond() != null ) {
++ BigDecimal fs = xcal.getFractionalSecond();
++ // Were there sub-millisecond resolution fractional seconds?
++ // This isn't perfect but it needs a very long fractional part to break it,
++ // less than observable quantum of time.
++ if ( fs.doubleValue() != xcal.getMillisecond() / 1000.0 )
++ return -1;
++ }
++
++ int y = xcal.getYear();
++
++ if ( y < 0 || y >= 8000 )
++ return -1;
++
++ v = date(v, xcal.getYear(), xcal.getMonth(), xcal.getDay());
++ v = time(v, xcal.getHour(), xcal.getMinute(), xcal.getSecond() * 1000 + xcal.getMillisecond());
++
++ if ( containsZ )
++ return tz(v, TZ_Z);
++
++ int tz = xcal.getTimezone();
++ if ( tz == DatatypeConstants.FIELD_UNDEFINED )
++ return tz(v, TZ_NONE);
++
++ // Timezone is weird.
++ if ( tz % 15 != 0 )
++ return -1;
++
++ tz = tz / 15;
++ return tz(v, tz);
++ }
++
++ public static String unpackDateTime(long v) {
++ return unpack(v, true);
++ }
++
++ public static String unpackDate(long v) {
++ return unpack(v, false);
++ }
++
++ // Avoid calls to String.format
++ private static String unpack(long v, boolean isDateTime) {
++ // YYYY:MM:DD => 13 bits year, 4 bits month, 5 bits day => 22 bits
++ int years = (int)BitsLong.unpack(v, YEAR, YEAR + YEAR_LEN);
++ int months = (int)BitsLong.unpack(v, MONTH, MONTH + MONTH_LEN);
++ int days = (int)BitsLong.unpack(v, DAY, DAY + DAY_LEN);
++
++ // Hours: 5, mins 6, milli 16, TZ 7 => 34 bits
++ int hours = (int)BitsLong.unpack(v, HOUR, HOUR + HOUR_LEN);
++ int minutes = (int)BitsLong.unpack(v, MINUTES, MINUTES + MINUTES_LEN);
++ int milliSeconds = (int)BitsLong.unpack(v, MILLI, MILLI + MILLI_LEN);
++
++ int tz = (int)BitsLong.unpack(v, TZ, TZ + TZ_LEN);
++
++ int sec = milliSeconds / 1000;
++ int fractionSec = milliSeconds % 1000;
++
++ StringBuilder sb = new StringBuilder(50);
++ NumberUtils.formatInt(sb, years, 4);
++ sb.append('-');
++ NumberUtils.formatInt(sb, months, 2);
++ sb.append('-');
++ NumberUtils.formatInt(sb, days, 2);
++ if ( isDateTime ) {
++ sb.append('T');
++ NumberUtils.formatInt(sb, hours, 2);
++ sb.append(':');
++ NumberUtils.formatInt(sb, minutes, 2);
++ sb.append(':');
++ NumberUtils.formatInt(sb, sec, 2);
++
++ // Formatting needed : int->any
++ if ( fractionSec != 0 ) {
++ sb.append(".");
++ if ( fractionSec % 100 == 0 )
++ NumberUtils.formatInt(sb, fractionSec / 100, 1);
++ else if ( fractionSec % 10 == 0 )
++ NumberUtils.formatInt(sb, fractionSec / 10, 2);
++ else
++ NumberUtils.formatInt(sb, fractionSec, 3);
++ }
++ }
++ // tz in 15min units
++ // Special values.
++ if ( tz == TZ_Z ) {
++ sb.append("Z");
++ return sb.toString();
++ }
++
++ if ( tz == TZ_NONE )
++ return sb.toString();
++
++ // Sign extend.
++ if ( BitsLong.isSet(v, TZ + TZ_LEN - 1) )
++ tz = BitsInt.set(tz, TZ_LEN, 32);
++
++ if ( tz < 0 ) {
++ tz = -tz;
++ sb.append('-');
++ } else
++ sb.append('+');
++
++ int tzH = tz / 4;
++ int tzM = (tz % 4) * 15;
++ NumberUtils.formatUnsignedInt(sb, tzH, 2);
++ sb.append(':');
++ NumberUtils.formatUnsignedInt(sb, tzM, 2);
++ return sb.toString();
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/DecimalNode.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/DecimalNode.java
index 0000000,0000000..2e03d96
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/DecimalNode.java
@@@ -1,0 -1,0 +1,22 @@@
++/*
++ * 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.value;
++
++/** Placeholder for a full length decimal , using int+long.*/
++public class DecimalNode {
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/DecimalNode56.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/DecimalNode56.java
index 0000000,0000000..c36e5c5
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/DecimalNode56.java
@@@ -1,0 -1,0 +1,140 @@@
++/*
++ * 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.value;
++
++import java.math.BigDecimal;
++import java.math.BigInteger;
++
++import org.apache.jena.atlas.lib.BitsLong ;
++
++
++// Decimal packed into 56 bits.
++public class DecimalNode56
++{
++ //private static Logger log = LoggerFactory.getLogger(DecimalNode.class) ;
++
++ BigDecimal decimal = null ;
++
++ // signed 8 bits of scale, signed 48 bits of value.
++ // Decimal precision is 47 bits (it's signed) or around 14 places.
++ // Not finance industry accuracy nor XSD (18 places minimum) but still useful.
++
++ static final int SCALE_LEN = 8;
++ static final int VALUE_LEN = 48;
++ static final int ENC_LEN = 48 + SCALE_LEN;
++
++ static final long MAX_VALUE = (1L << (VALUE_LEN - 1)) - 1;
++ static final long MIN_VALUE = -(1L << (VALUE_LEN - 1));
++
++ static final int MAX_SCALE = (1 << (SCALE_LEN - 1)) - 1;
++ static final int MIN_SCALE = -(1 << (SCALE_LEN - 1));
++
++ static final BigInteger MAX_I = BigInteger.valueOf(MAX_VALUE);
++ static final BigInteger MIN_I = BigInteger.valueOf(MIN_VALUE);
++
++ // Bits counts
++ static private int SCALE_LO = 56 - SCALE_LEN;
++ static private int SCALE_HI = 56; // Exclusive
++ // index
++
++ static private int VALUE_LO = 0;
++ static private int VALUE_HI = VALUE_LO + VALUE_LEN;
++
++ private int scale;
++ private long value;
++
++ public static DecimalNode56 valueOf(BigDecimal decimal) {
++ int scale = decimal.scale();
++ BigInteger bigInt = decimal.unscaledValue();
++
++ //decimal.longValueExact(); // Throws exception
++ //new BigDecimal(long);
++
++ if ( bigInt.compareTo(MAX_I) > 0 || bigInt.compareTo(MIN_I) < 0 )
++ // This check makes sure that bigInt.longValue() is safe
++ return null;
++ return valueOf(bigInt.longValue(), scale);
++ }
++
++ public static DecimalNode56 valueOf(long binValue, int scale) {
++ if ( scale < MIN_SCALE || scale > MAX_SCALE ) {
++ // log.warn("Scale out of range: ("+binValue+","+scale+")") ;
++ return null;
++ }
++
++ if ( binValue < MIN_VALUE || binValue > MAX_VALUE ) {
++ // log.warn("Value out of range: ("+binValue+","+scale+")") ;
++ return null;
++ }
++
++ return new DecimalNode56(binValue, scale);
++ }
++
++ private DecimalNode56(long value, int scale) {
++ this.scale = scale;
++ this.value = value;
++ }
++
++ public long pack() {
++ return pack(value, scale);
++ }
++
++ /** Create the long value */
++ public static long pack(long value, int scale) {
++ // pack : scale, value
++ long v = 0;
++ v = BitsLong.pack(0L, scale, SCALE_LO, SCALE_HI);
++ v = BitsLong.pack(v, value, VALUE_LO, VALUE_HI);
++ // No need to do something about negative numbers
++ return v;
++ }
++
++ public static DecimalNode56 unpack(long v) {
++ int scale = (int)BitsLong.unpack(v, SCALE_LO, SCALE_HI);
++ long value = BitsLong.unpack(v, VALUE_LO, VALUE_HI);
++ return new DecimalNode56(value, scale);
++ }
++
++ public static BigDecimal unpackAsBigDecimal(long v) {
++ int scale = (int)BitsLong.unpack(v, SCALE_LO, SCALE_HI);
++ long value = BitsLong.unpack(v, VALUE_LO, VALUE_HI);
++ // Sign extend value.
++ if ( BitsLong.isSet(value, VALUE_HI - 1) )
++ value = value | -1L << (VALUE_HI);
++ return BigDecimal.valueOf(value, scale);
++ }
++
++ public BigDecimal get() {
++ if ( decimal == null )
++ decimal = BigDecimal.valueOf(value, scale);
++ return decimal;
++ }
++
++ @Override
++ public String toString() {
++ return get().toPlainString();
++ }
++
++ public int getScale() {
++ return scale;
++ }
++
++ public long getValue() {
++ return value;
++ }
++}
[09/50] [abbrv] jena git commit: Formatting
Posted by an...@apache.org.
Formatting
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/10f2bb16
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/10f2bb16
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/10f2bb16
Branch: refs/heads/jena-tdb2
Commit: 10f2bb16994c0c8973205accda4a52500c065916
Parents: 7624f54
Author: Andy Seaborne <an...@seaborne.org>
Authored: Sun Sep 3 17:14:07 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Sun Sep 3 17:14:07 2017 +0100
----------------------------------------------------------------------
.../seaborne/dboe/base/file/ChannelManager.java | 62 ++++++++------------
.../transaction/txn/TransactionCoordinator.java | 1 -
2 files changed, 26 insertions(+), 37 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/10f2bb16/dboe-base/src/main/java/org/seaborne/dboe/base/file/ChannelManager.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/main/java/org/seaborne/dboe/base/file/ChannelManager.java b/dboe-base/src/main/java/org/seaborne/dboe/base/file/ChannelManager.java
index 8738dd5..7b1d041 100644
--- a/dboe-base/src/main/java/org/seaborne/dboe/base/file/ChannelManager.java
+++ b/dboe-base/src/main/java/org/seaborne/dboe/base/file/ChannelManager.java
@@ -33,42 +33,36 @@ public class ChannelManager
// ChannelManager
// FileBase ==> OpenFileRef, ChannelRef
-
- public static FileChannel acquire(String filename)
- {
+
+ public static FileChannel acquire(String filename) {
return acquire(filename, "rw") ;
}
-
- public static FileChannel acquire(String filename, String mode)
- {
+
+ public static FileChannel acquire(String filename, String mode) {
return openref$(filename, mode) ;
}
-
+
static private Map<String, FileChannel> name2channel = new HashMap<>() ;
static private Map<FileChannel, String> channel2name = new HashMap<>() ;
-
- private static FileChannel openref$(String filename, String mode)
- {
+
+ private static FileChannel openref$(String filename, String mode) {
// Temp - for now, only journal files are tracked.
- if ( ! filename.endsWith(".jrnl") )
- {
+ if ( !filename.endsWith(".jrnl") ) {
return open$(filename, mode) ;
}
-
+
FileChannel chan = name2channel.get(filename) ;
- if ( chan != null )
- {
+ if ( chan != null ) {
// Scream - it's currently open.
- throw new FileException("Already open: "+filename) ;
+ throw new FileException("Already open: " + filename) ;
}
chan = open$(filename, mode) ;
name2channel.put(filename, chan) ;
channel2name.put(chan, filename) ;
return chan ;
}
-
- private static FileChannel open$(String filename, String mode)
- {
+
+ private static FileChannel open$(String filename, String mode) {
try {
// "rwd" - Syncs only the file contents
// "rws" - Syncs the file contents and metadata
@@ -81,36 +75,33 @@ public class ChannelManager
} catch (IOException ex) { throw new FileException("Failed to open: "+filename+" (mode="+mode+")", ex) ; }
}
- public static void release(String filename)
- {
+ public static void release(String filename) {
FileChannel channel = name2channel.get(filename) ;
if ( channel != null )
release(channel) ;
}
-
- public static void release(FileChannel chan)
- {
+
+ public static void release(FileChannel chan) {
// Always close even if not managed.
- try { chan.close() ; } catch (Exception ex) {}
+ try {
+ chan.close() ;
+ }
+ catch (Exception ex) {}
String name = channel2name.remove(chan) ;
if ( name != null )
name2channel.remove(name) ;
}
-
- public static void reset()
- {
+
+ public static void reset() {
releaseAll(null) ;
}
- /** Shutdown all the files matching the prefix (typically a directory) */
- public static void releaseAll(String prefix)
- {
+ /** Shutdown all the files matching the prefix (typically a directory) */
+ public static void releaseAll(String prefix) {
// Use an iterator explicitly so we can remove from the map.
List<FileChannel> x = new ArrayList<>() ;
- for ( String fn : name2channel.keySet() )
- {
- if ( prefix == null || fn.startsWith(prefix) )
- {
+ for ( String fn : name2channel.keySet() ) {
+ if ( prefix == null || fn.startsWith(prefix) ) {
x.add(name2channel.get(fn)) ;
// Don't call release here - potential CME problems.
// Could use an explicit iterator on teh keySet and .remove from that but
@@ -121,4 +112,3 @@ public class ChannelManager
release(chan) ;
}
}
-
http://git-wip-us.apache.org/repos/asf/jena/blob/10f2bb16/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 56104bf..cede020 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
@@ -465,7 +465,6 @@ public class TransactionCoordinator {
throw new TransactionException("Writers currently being rejected");
}
}
-
if ( canBlock )
exclusivitylock.readLock().lock() ;
[22/50] [abbrv] jena git commit: Remove SSE node table support in
favour of binary node table.
Posted by an...@apache.org.
Remove SSE node table support in favour of binary node table.
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/73e2cced
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/73e2cced
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/73e2cced
Branch: refs/heads/jena-tdb2
Commit: 73e2ccedfc9b54aa3baad9e8fd64ef075b6a03a6
Parents: 67b69b5
Author: Andy Seaborne <an...@seaborne.org>
Authored: Wed Sep 13 14:49:00 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Wed Sep 13 14:49:00 2017 +0100
----------------------------------------------------------------------
.../tdb2/store/nodetable/NodeTableSSE.java | 304 -------------------
1 file changed, 304 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/73e2cced/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableSSE.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableSSE.java b/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableSSE.java
deleted file mode 100644
index ed4577f..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableSSE.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * 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.nodetable;
-
-import java.nio.ByteBuffer ;
-
-import org.apache.jena.atlas.io.BlockUTF8 ;
-import org.apache.jena.atlas.lib.StrUtils ;
-import org.apache.jena.graph.Node ;
-import org.apache.jena.graph.NodeFactory ;
-import org.apache.jena.riot.RiotException ;
-import org.apache.jena.riot.out.NodeFmtLib ;
-import org.apache.jena.riot.system.PrefixMap ;
-import org.apache.jena.riot.system.PrefixMapNull ;
-import org.apache.jena.riot.tokens.Token ;
-import org.apache.jena.riot.tokens.Tokenizer ;
-import org.apache.jena.riot.tokens.TokenizerFactory ;
-import org.apache.jena.riot.web.LangTag ;
-import org.apache.jena.shared.PrefixMapping ;
-import org.apache.jena.sparql.util.NodeUtils ;
-import org.seaborne.dboe.base.block.Block ;
-import org.seaborne.dboe.base.file.BufferChannel ;
-import org.seaborne.dboe.base.file.BufferChannelFile ;
-import org.seaborne.dboe.base.objectfile.ObjectFile ;
-import org.seaborne.dboe.base.objectfile.ObjectFileStorage ;
-import org.seaborne.dboe.index.Index ;
-import org.seaborne.tdb2.TDBException ;
-import org.seaborne.tdb2.store.NodeId ;
-import org.seaborne.tdb2.store.NodeIdFactory;
-
-// For reference only.
-public class NodeTableSSE extends NodeTableNative {
-
- private long position ;
- private ObjectFile objects ;
- //private final Index nodeToId ;
-
- private /*public*/ NodeTableSSE(Index nodeToId, String filename)
- {
- super(nodeToId);
- BufferChannel file = BufferChannelFile.create(filename) ;
- this.objects = new ObjectFileStorage(file) ;
- }
-
- @Override
- protected final NodeId writeNodeToTable(Node node)
- {
- // Synchronized in accessIndex
- long x = encodeStore(node, objects) ;
- // Paired : [*]
- return NodeIdFactory.createPtr(x);
- }
-
- @Override
- protected final Node readNodeFromTable(NodeId id)
- {
- // Paired : [*]
- long x = id.getPtrLocation();
- if ( x >= objects.length() )
- return null ;
- return fetchDecode(x, objects) ;
- }
-
- private static Nodec nodec = new NodecSSE() ;
-
- private static long encodeStore(Node node, ObjectFile file)
- {
- // Buffer pool?
-
- // Nodes can be writtern during reads.
- // Make sure this operation is sync'ed.
- int maxSize = nodec.maxSize(node) ;
- Block block = file.allocWrite(maxSize) ;
- try {
- int len = nodec.encode(node, block.getByteBuffer(), null) ;
- file.completeWrite(block) ;
- return block.getId() ;
- } catch (TDBException ex)
- {
- file.abortWrite(block) ;
- throw ex ;
- }
- }
-
- private static Node fetchDecode(long id, ObjectFile file)
- {
- ByteBuffer bb = file.read(id) ;
- if ( bb == null )
- return null ;
- return decode(bb) ;
- }
-
- /**
- * Encode a node - it is better to use encodeStore which may avoid
- * anadditional copy in getting the node into the ObjectFile
- */
- public static ByteBuffer encode(Node node)
- {
- int maxSize = nodec.maxSize(node) ;
- ByteBuffer bb = ByteBuffer.allocate(maxSize) ;
- int len = nodec.encode(node, bb, null) ;
- bb.limit(len) ;
- bb.position(0) ;
- return bb ;
- }
-
- /**
- * Decode a node - it is better to use fetchDecode which may avoid an
- * additional copy in getting the node from the ObjectFile.
- */
- public static Node decode(ByteBuffer bb)
- {
- bb.position(0) ;
- Node n = nodec.decode(bb, null) ;
- return n ;
- }
-
- @Override
- protected void syncSub() { objects.sync(); }
-
- @Override
- protected void closeSub() { objects.close(); }
-
- /** Encode/decode for Nodes into bytes */
- public interface Nodec {
- /**
- * Calculate the maximum number of bytes needed for a Node. This needs to be
- * an overestimate and is used to ensure there is space in the bytebuffer
- * passed to encode.
- */
- public int maxSize(Node node) ;
-
- /**
- * Encode the node into the byte buffer, starting at the given offset. The
- * ByteBuffer will have position/limit around the space used on return,
- * <b>without a length code<b>.
- *
- * @param node Node to encode.
- * @param bb ByteBuffer
- * @param pmap Optional prefix mapping. Can be null.
- * @return Length of byte buffer used for the whole encoding.
- */
- public int encode(Node node, ByteBuffer bb, PrefixMapping pmap) ;
-
- /**
- * Decode the node from the byte buffer. The ByteBuffer position should be
- * the start of the encoding (no binary length for example)
- *
- * @param bb ByteBuffer
- * @param pmap Optional prefix mapping. Can be null.
- * @return the decoded Node.
- */
- public Node decode(ByteBuffer bb, PrefixMapping pmap) ;
- }
-
- private static class NodecSSE implements Nodec
- {
- private static boolean SafeChars = false ;
- // Characters in IRIs that are illegal and cause SSE problems, but we wish to keep.
- final private static char MarkerChar = '_' ;
- final private static char[] invalidIRIChars = { MarkerChar , ' ' } ;
-
- public NodecSSE() {}
-
- @Override
- public int maxSize(Node node)
- {
- return maxLength(node) ;
- }
-
- private static final PrefixMap pmap0 = PrefixMapNull.empty ;
- private static final boolean onlySafeBNodeLabels = false ;
- @Override
- public int encode(Node node, ByteBuffer bb, PrefixMapping pmap)
- {
- String str = null ;
-
- if ( node.isURI() )
- {
- // Pesky spaces etc
- String x = StrUtils.encodeHex(node.getURI(), MarkerChar, invalidIRIChars) ;
- if ( x != node.getURI() )
- node = NodeFactory.createURI(x) ;
- }
-
- if ( node.isLiteral() && NodeUtils.isLangString(node) )
- {
- // Check syntactically valid.
- String lang = node.getLiteralLanguage() ;
- if ( ! LangTag.check(lang) )
- throw new TDBException("bad language tag: "+node) ;
- }
-
- if ( node.isBlank() && ! onlySafeBNodeLabels ) {
- // Special case.
- str = "_:"+node.getBlankNodeLabel() ;
- }
-
- // Node->String
- if ( str == null )
- str = NodeFmtLib.str(node, (String)null, pmap0) ;
- // String -> bytes ;
- BlockUTF8.fromChars(str, bb) ;
- bb.flip() ;
- return bb.limit() ;
- }
-
- @Override
- public Node decode(ByteBuffer bb, PrefixMapping pmap)
- {
- // Ideally, this would be straight from the byte buffer.
- // But currently we go bytes -> string -> node
-
- // Byte -> String
- String str = BlockUTF8.toString(bb) ;
- //OLD
- //String str = Bytes.fromByteBuffer(bb) ;
- // String -> Node
-
- // Easy cases.
- if ( str.startsWith("_:") )
- {
- // Must be done this way.
- // In particular, bnode labels can contain ":" from Jena
- // TokenizerText does not recognize these.
- str = str.substring(2) ;
- return NodeFactory.createBlankNode(str) ;
- }
-
- if ( str.startsWith("<") )
- {
- // Do directly.
- // (is it quicker?)
- str = str.substring(1,str.length()-1) ;
- str = StrUtils.unescapeString(str) ;
- str = StrUtils.decodeHex(str, MarkerChar) ;
- return NodeFactory.createURI(str) ;
- }
-
- Tokenizer tokenizer = TokenizerFactory.makeTokenizerString(str) ;
- if ( ! tokenizer.hasNext() )
- throw new TDBException("Failed to tokenise: "+str) ;
- Token t = tokenizer.next() ;
-
- try {
- Node n = t.asNode() ;
- if ( n == null ) throw new TDBException("Not a node: "+str) ;
- return n ;
- } catch (RiotException ex)
- {
- throw new TDBException("Bad string for node: "+str) ;
- }
- }
-
- // Over-estimate the length of the encoding.
- private static int maxLength(Node node)
- {
- if ( node.isBlank() )
- // "_:"
- return 2+maxLength(node.getBlankNodeLabel()) ;
- if ( node.isURI() )
- // "<>"
- return 2+maxLength(node.getURI()) ;
- if ( node.isLiteral() )
- {
- int len = 2+maxLength(node.getLiteralLexicalForm()) ;
- if ( NodeUtils.isLangString(node) )
- // Space for @ (language tag is ASCII)
- len = len + 3 + node.getLiteralLanguage().length() ;
- else if ( ! NodeUtils.isSimpleString(node) )
- // The quotes and also space for ^^<>
- len = len + 4 + maxLength(node.getLiteralDatatypeURI()) ;
- return len ;
- }
- if ( node.isVariable() )
- // "?"
- return 1+maxLength(node.getName()) ;
- throw new TDBException("Unrecognized node type: "+node) ;
- }
-
- private static int maxLength(String string)
- {
- // Very worse case for UTF-8 - and then some.
- // Encoding every character as _XX or bad UTF-8 conversion (3 bytes)
- // Max 3 bytes UTF-8 for up to 10FFFF (NB Java treats above 16bites as surrogate pairs only).
- return string.length()*3 ;
- }
- }
- }
\ No newline at end of file
[32/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/StageMatchTuple.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/StageMatchTuple.java
index 0000000,0000000..aa5103d
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/StageMatchTuple.java
@@@ -1,0 -1,0 +1,195 @@@
++/*
++ * 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.solver;
++
++import java.util.Iterator ;
++import java.util.List ;
++import java.util.function.Function ;
++import java.util.function.Predicate ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import org.apache.jena.atlas.iterator.RepeatApplyIterator ;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.atlas.lib.tuple.TupleFactory ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.sparql.core.Var ;
++import org.apache.jena.sparql.engine.ExecutionContext ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.store.nodetable.NodeTable ;
++import org.seaborne.tdb2.store.nodetupletable.NodeTupleTable ;
++
++public class StageMatchTuple extends RepeatApplyIterator<BindingNodeId>
++{
++ private final NodeTupleTable nodeTupleTable ;
++ private final Tuple<Node> patternTuple ;
++
++ private final ExecutionContext execCxt ;
++ private boolean anyGraphs ;
++ private Predicate<Tuple<NodeId>> filter ;
++
++ public StageMatchTuple(NodeTupleTable nodeTupleTable, Iterator<BindingNodeId> input,
++ Tuple<Node> tuple, boolean anyGraphs,
++ Predicate<Tuple<NodeId>> filter,
++ ExecutionContext execCxt)
++ {
++ super(input) ;
++ this.filter = filter ;
++ this.nodeTupleTable = nodeTupleTable ;
++ this.patternTuple = tuple ;
++ this.execCxt = execCxt ;
++ this.anyGraphs = anyGraphs ;
++ }
++
++ /** Prepare a pattern (tuple of nodes), and an existing binding of NodeId, into NodeIds and Variables.
++ * A variable in the pattern is replaced by its binding or null in the Nodeids.
++ * A variable that is not bound by the binding is placed in the var array.
++ * Return false if preparation detechs the pattern can not match.
++ */
++ public static boolean prepare(NodeTable nodeTable, Tuple<Node> patternTuple, BindingNodeId input, NodeId ids[], Var[] var)
++ {
++ // Process the Node to NodeId conversion ourselves because
++ // we wish to abort if an unknown node is seen.
++ for ( int i = 0 ; i < patternTuple.len() ; i++ )
++ {
++ Node n = patternTuple.get(i) ;
++ // Substitution and turning into NodeIds
++ // Variables unsubstituted are null NodeIds
++ NodeId nId = idFor(nodeTable, input, n) ;
++ if ( NodeId.isDoesNotExist(nId) )
++ return false;
++ ids[i] = nId ;
++ if ( nId == null )
++ var[i] = asVar(n) ;
++ }
++ return true ;
++ }
++
++ @Override
++ protected Iterator<BindingNodeId> makeNextStage(final BindingNodeId input)
++ {
++ // ---- Convert to NodeIds
++ NodeId ids[] = new NodeId[patternTuple.len()] ;
++ // Variables for this tuple after subsitution
++ final Var[] var = new Var[patternTuple.len()] ;
++
++ boolean b = prepare(nodeTupleTable.getNodeTable(), patternTuple, input, ids, var) ;
++ if ( !b )
++ // Short cut - known unknown NodeId
++ return Iter.nullIterator();
++
++ Iterator<Tuple<NodeId>> iterMatches = nodeTupleTable.find(TupleFactory.create(ids)) ;
++
++ // ** Allow a triple or quad filter here.
++ if ( filter != null )
++ iterMatches = Iter.filter(iterMatches, filter) ;
++
++ // If we want to reduce to RDF semantics over quads,
++ // we need to reduce the quads to unique triples.
++ // We do that by having the graph slot as "any", then running
++ // through a distinct-ifier.
++ // Assumes quads are GSPO - zaps the first slot.
++ // Assumes that tuples are not shared.
++ if ( anyGraphs )
++ {
++ iterMatches = Iter.map(iterMatches, quadsToAnyTriples) ;
++ //Guaranteed
++ //iterMatches = Iter.distinct(iterMatches) ;
++
++ // This depends on the way indexes are chosen and
++ // the indexing pattern. It assumes that the index
++ // chosen ends in G so same triples are adjacent
++ // in a union query.
++ //
++ // If any slot is defined, then the index will be X??G.
++ // If no slot is defined, then the index will be ???G.
++ // But the TupleTable
++ // See TupleTable.scanAllIndex that ensures the latter.
++ // No G part way through.
++ iterMatches = Iter.distinctAdjacent(iterMatches) ;
++ }
++
++ // Map Tuple<NodeId> to BindingNodeId
++ Function<Tuple<NodeId>, BindingNodeId> binder = tuple ->
++ {
++ BindingNodeId output = new BindingNodeId(input) ;
++ for ( int i = 0 ; i < var.length ; i++ )
++ {
++ Var v = var[i] ;
++ if ( v == null )
++ continue ;
++ NodeId id = tuple.get(i) ;
++ if ( reject(output, v, id) )
++ return null ;
++ output.put(v, id) ;
++ }
++ return output ;
++ } ;
++
++ return Iter.iter(iterMatches).map(binder).removeNulls() ;
++ }
++
++ private static Iterator<Tuple<NodeId>> print(Iterator<Tuple<NodeId>> iter)
++ {
++ if ( ! iter.hasNext() )
++ System.err.println("<empty>") ;
++ else
++ {
++ List<Tuple<NodeId>> r = Iter.toList(iter) ;
++ String str = Iter.asString(r, "\n") ;
++ System.err.println(str) ;
++ // Reset iter
++ iter = Iter.iter(r) ;
++ }
++ return iter ;
++ }
++
++ private static boolean reject(BindingNodeId output , Var var, NodeId value)
++ {
++ if ( ! output.containsKey(var) )
++ return false ;
++
++ if ( output.get(var).equals(value) )
++ return false ;
++
++ return true ;
++ }
++
++ private static Var asVar(Node node)
++ {
++ if ( Var.isVar(node) )
++ return Var.alloc(node) ;
++ return null ;
++ }
++
++ /** Return null for variables, and for nodes, the node id or NodeDoesNotExist */
++ private static NodeId idFor(NodeTable nodeTable, BindingNodeId input, Node node)
++ {
++ if ( Var.isVar(node) )
++ {
++ NodeId n = input.get((Var.alloc(node))) ;
++ // Bound to NodeId or null.
++ return n ;
++ }
++ // May return NodeId.NodeDoesNotExist which must not be null.
++ return nodeTable.getNodeIdForNode(node) ;
++ }
++
++ private static Function<Tuple<NodeId>, Tuple<NodeId>> quadsToAnyTriples = item -> {
++ return TupleFactory.create4(NodeId.NodeIdAny, item.get(1), item.get(2), item.get(3) ) ;
++ } ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/stats/Stats.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/stats/Stats.java
index 0000000,0000000..c1b59b0
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/stats/Stats.java
@@@ -1,0 -1,0 +1,137 @@@
++/*
++ * 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.solver.stats;
++
++import static org.apache.jena.sparql.sse.Item.addPair ;
++import static org.apache.jena.sparql.sse.Item.createTagged ;
++
++import java.io.BufferedOutputStream ;
++import java.io.FileOutputStream ;
++import java.io.IOException ;
++import java.io.OutputStream ;
++import java.util.Iterator ;
++import java.util.Map ;
++import java.util.Map.Entry ;
++
++import org.apache.jena.atlas.lib.DateTimeUtils ;
++import org.apache.jena.atlas.logging.Log ;
++import org.apache.jena.graph.Graph ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.graph.Triple ;
++import org.apache.jena.sparql.engine.optimizer.StatsMatcher ;
++import org.apache.jena.sparql.graph.NodeConst ;
++import org.apache.jena.sparql.sse.Item ;
++import org.apache.jena.sparql.sse.ItemList ;
++import org.apache.jena.sparql.sse.ItemWriter ;
++import org.apache.jena.sparql.util.NodeFactoryExtra ;
++
++public class Stats
++{
++ static Item ZERO = Item.createNode(NodeFactoryExtra.intToNode(0)) ;
++
++ /** Write statistics */
++ static public void write(String filename, StatsResults stats)
++ {
++ write(filename, stats.getPredicates(), stats.getTypes(), stats.getCount()) ;
++ }
++
++ /** Write statistics */
++ static public void write(OutputStream output, StatsResults stats)
++ {
++ write(output, stats.getPredicates(), stats.getTypes(), stats.getCount()) ;
++ }
++
++ static private void write(String filename, Map<Node, Integer> predicateStats, Map<Node, Integer> typeStats, long statsTotal)
++ {
++ // Write out the stats
++ try (OutputStream statsOut = new BufferedOutputStream(new FileOutputStream(filename))) {
++ write(statsOut, predicateStats, typeStats, statsTotal) ;
++ } catch (IOException ex)
++ { Log.warn(Stats.class, "Problem when writing stats file", ex) ; }
++ }
++
++ static private void write(OutputStream output, Map<Node, Integer> predicateStats, Map<Node, Integer> typeStats, long statsTotal)
++ {
++ Item item = format(predicateStats, typeStats, statsTotal) ;
++ ItemWriter.write(output, item) ;
++ }
++
++
++ /** Gather statistics, any graph */
++ public static StatsCollector gather(Graph graph)
++ {
++ StatsCollector stats = new StatsCollector() ;
++
++ Iterator<Triple> iter = graph.find(Node.ANY, Node.ANY, Node.ANY) ;
++ for ( ; iter.hasNext() ; )
++ {
++ Triple t = iter.next();
++ stats.record(null, t.getSubject(), t.getPredicate(), t.getObject()) ;
++ }
++
++ return stats ;
++ }
++
++ public static Item format(StatsResults stats)
++ {
++ return format(stats.getPredicates(), stats.getTypes(), stats.getCount()) ;
++ }
++
++ private static Item format(Map<Node, Integer> predicates, Map<Node, Integer> types, long count)
++ {
++ Item stats = Item.createList() ;
++ ItemList statsList = stats.getList() ;
++ statsList.add("stats") ;
++
++ Item meta = createTagged(StatsMatcher.META) ;
++ addPair(meta.getList(), "timestamp", NodeFactoryExtra.nowAsDateTime()) ;
++ addPair(meta.getList(), "run@", DateTimeUtils.nowAsString()) ;
++ if ( count >= 0 )
++ addPair(meta.getList(), StatsMatcher.COUNT, NodeFactoryExtra.intToNode((int)count)) ;
++ statsList.add(meta) ;
++
++ for ( Entry<Node, Integer> entry : types.entrySet() )
++ {
++ Node type = entry.getKey() ;
++ addTypeTriple(statsList, type, NodeFactoryExtra.intToNode(entry.getValue()) ) ;
++ }
++
++ for ( Entry<Node, Integer> entry : predicates.entrySet() )
++ {
++ Node node = entry.getKey() ;
++ // Skip these - they just clog things up!
++ if ( node.getURI().startsWith("http://www.w3.org/1999/02/22-rdf-syntax-ns#_") )
++ continue ;
++ addPair(statsList, node, NodeFactoryExtra.intToNode(entry.getValue())) ;
++ }
++
++ // Add a default rule.
++ addPair(statsList, StatsMatcher.OTHER, ZERO) ;
++
++ return stats ;
++ }
++
++ private static void addTypeTriple(ItemList statsList, Node type, Node intCount)
++ {
++ ItemList triple = new ItemList() ;
++ triple.add("VAR") ;
++ triple.add(NodeConst.nodeRDFType) ;
++ triple.add(type) ;
++ addPair(statsList, Item.createList(triple), Item.createNode(intCount)) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/stats/StatsCollector.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/stats/StatsCollector.java
index 0000000,0000000..0766cc3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/stats/StatsCollector.java
@@@ -1,0 -1,0 +1,35 @@@
++/*
++ * 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.solver.stats;
++
++import java.util.Map ;
++
++import org.apache.jena.graph.Node ;
++import org.apache.jena.sparql.graph.NodeConst ;
++
++/** Statistics collector, general purpose, uses Nodes */
++public class StatsCollector extends StatsCollectorBase<Node>
++{
++ public StatsCollector() { super(NodeConst.nodeRDFType) ; }
++
++ @Override
++ protected Map<Node, Integer> convert(Map<Node, Integer> map)
++ {
++ return map ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/stats/StatsCollectorBase.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/stats/StatsCollectorBase.java
index 0000000,0000000..9722e82
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/stats/StatsCollectorBase.java
@@@ -1,0 -1,0 +1,53 @@@
++/*
++ * 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.solver.stats;
++
++
++import java.util.HashMap ;
++import java.util.Map ;
++
++import org.apache.jena.graph.Node ;
++
++/** Statistics collector, general purpose */
++abstract class StatsCollectorBase<T>
++{
++ private long count = 0 ;
++ private Map<T, Integer> predicates = new HashMap<>(10000) ;
++ private Map<T, Integer> types = new HashMap<>(10000) ;
++ private T typeTrigger ;
++
++ protected StatsCollectorBase(T typeTrigger)
++ {
++ this.typeTrigger = typeTrigger ;
++ }
++
++ public void record(T g, T s, T p, T o)
++ {
++ count++ ;
++ predicates.put(p, predicates.getOrDefault(p, 0) + 1);
++ if ( typeTrigger != null && typeTrigger.equals(p) )
++ types.put(o, types.getOrDefault(o, 0) + 1);
++ }
++
++ protected abstract Map<Node, Integer> convert(Map<T, Integer> map) ;
++
++ public StatsResults results()
++ {
++ return new StatsResults(convert(predicates), convert(types), count) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/stats/StatsCollectorNodeId.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/stats/StatsCollectorNodeId.java
index 0000000,0000000..6b8ee95
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/stats/StatsCollectorNodeId.java
@@@ -1,0 -1,0 +1,55 @@@
++/*
++ * 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.solver.stats;
++
++import java.util.HashMap ;
++import java.util.Map ;
++
++import org.apache.jena.graph.Node ;
++import org.apache.jena.sparql.graph.NodeConst ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.store.nodetable.NodeTable ;
++
++/** Statistics collector, aggregates based on NodeId */
++public class StatsCollectorNodeId extends StatsCollectorBase<NodeId>
++{
++ private NodeTable nodeTable ;
++
++ public StatsCollectorNodeId(NodeTable nodeTable)
++ {
++ super(findRDFType(nodeTable)) ;
++ this.nodeTable = nodeTable ;
++ }
++
++ private static NodeId findRDFType(NodeTable nodeTable2)
++ {
++ return nodeTable2.getAllocateNodeId(NodeConst.nodeRDFType) ;
++ }
++
++ @Override
++ protected Map<Node, Integer> convert(Map<NodeId, Integer> stats)
++ {
++ Map<Node, Integer> statsNodes = new HashMap<>(1000) ;
++ for ( NodeId p : stats.keySet() )
++ {
++ Node n = nodeTable.getNodeForNodeId(p) ;
++ statsNodes.put(n, stats.get(p)) ;
++ }
++ return statsNodes ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/stats/StatsResults.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/stats/StatsResults.java
index 0000000,0000000..322d251
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/stats/StatsResults.java
@@@ -1,0 -1,0 +1,52 @@@
++/*
++ * 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.solver.stats;
++
++import java.util.Map ;
++
++import org.apache.jena.graph.Node ;
++
++/** Statistics collector */
++public class StatsResults
++{
++ private final Map<Node, Integer> predicates ;
++ private final Map<Node, Integer> types ;
++ private final long count ;
++
++ StatsResults(Map<Node, Integer> predicates, Map<Node, Integer> types, long count)
++ {
++ this.count = count ;
++ this.predicates = predicates ;
++ this.types = types ;
++ }
++
++ public Map<Node, Integer> getPredicates()
++ {
++ return predicates ;
++ }
++
++ public Map<Node, Integer> getTypes()
++ {
++ return types ;
++ }
++
++ public long getCount()
++ {
++ return count ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphSwitchable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphSwitchable.java
index 0000000,0000000..9469a1d
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphSwitchable.java
@@@ -1,0 -1,0 +1,203 @@@
++/*
++ * 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.nio.file.Path;
++import java.util.Map;
++import java.util.concurrent.atomic.AtomicReference;
++
++import org.apache.jena.atlas.lib.Cache ;
++import org.apache.jena.atlas.lib.CacheFactory ;
++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.DatasetGraph ;
++import org.apache.jena.sparql.core.DatasetPrefixStorage ;
++import org.seaborne.dboe.base.file.Location ;
++
++final
++public class DatasetGraphSwitchable extends DatasetGraphWrapperTxn /* Until ARQ catches up with promote */
++{
++ // 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 Location location ;
++
++ public DatasetGraphSwitchable(Path base, Location location, DatasetGraph dsg) {
++ // Don't use the slot in datasetGraphWrapper - use the AtomicReference
++ super(null) ;
++ dsgx.set(dsg);
++ this.basePath = base;
++ this.location = location;
++ }
++
++ /** 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; }
++
++ public Location getLocation() { return location; }
++
++ /** The dataset to use for redirection - can be overridden.
++ * It is also guaranteed that this is called only once per
++ * delegated call. Changes to the wrapped object can be
++ * made based on that contract.
++ */
++ @Override
++ public DatasetGraph get() { return dsgx.get(); }
++
++ /** Set the base {@link DatasetGraph}.
++ * Returns the old value.
++ */
++ 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) {
++ // No need to clear. ngCache.clear();
++ return dsgx.compareAndSet(oldDSG, newDSG);
++ }
++
++ private Graph dftGraph = GraphViewSwitchable.createDefaultGraph(this);
++
++ @Override
++ public Graph getDefaultGraph() {
++ return dftGraph;
++ }
++
++// private Cache<Node, Graph> ngCache = CacheFactory.createCache(10);
++ private Cache<Node, Graph> ngCache = CacheFactory.createOneSlotCache();
++
++ @Override
++ public Graph getGraph(Node gn) {
++ return ngCache.getOrFill(gn, ()->GraphViewSwitchable.createNamedGraph(this, 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/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphTDB.java
index 0000000,0000000..5eb3053
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphTDB.java
@@@ -1,0 -1,0 +1,480 @@@
++/*
++ * 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 org.apache.jena.sparql.util.graph.GraphUtils.triples2quads ;
++
++import java.util.Iterator ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import org.apache.jena.atlas.lib.Closeable ;
++import org.apache.jena.atlas.lib.InternalErrorException ;
++import org.apache.jena.atlas.lib.Sync ;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.graph.Graph ;
++import org.apache.jena.graph.GraphUtil ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.graph.Triple ;
++import org.apache.jena.query.ReadWrite ;
++import org.apache.jena.sparql.core.* ;
++import org.apache.jena.sparql.engine.optimizer.reorder.ReorderTransformation ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.transaction.TransactionalMonitor ;
++import org.seaborne.dboe.transaction.txn.Transaction ;
++import org.seaborne.dboe.transaction.txn.TransactionException ;
++import org.seaborne.dboe.transaction.txn.TransactionalSystem ;
++import org.seaborne.dboe.transaction.txn.TxnId;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.lib.NodeLib ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.store.nodetupletable.NodeTupleTable ;
++import org.seaborne.tdb2.sys.StoreConnection ;
++/** This is the class that provides creates a dataset over the storage via
++ * TripleTable, QuadTable and prefixes.
++ * This is the coordination of the storage.
++ * @see DatasetGraphTxn for the Transaction form.
++ */
++final
++public class DatasetGraphTDB extends DatasetGraphTriplesQuads
++ implements DatasetGraphTxn, Sync, Closeable
++{
++ private StorageTDB storage;
++// // SWITCHING.
++// private TripleTable tripleTable ;
++// private QuadTable quadTable ;
++// private DatasetPrefixStorage prefixes ;
++// private Location location ;
++// private StoreParams storeParams ;
++// // SWITCHING.
++ private TransactionalSystem txnSystem ;
++ private final ReorderTransformation transform ;
++
++ private GraphTDB defaultGraphTDB ;
++ private final boolean checkForChange = false ;
++ private boolean closed = false ;
++
++ /** Application should not create a {@code DatasetGraphTDB} directly */
++ public DatasetGraphTDB(TransactionalSystem txnSystem,
++ TripleTable tripleTable, QuadTable quadTable, DatasetPrefixStorage prefixes,
++ ReorderTransformation transform, Location location, StoreParams params) {
++ reset(txnSystem, tripleTable, quadTable, prefixes, location, params) ;
++ this.transform = transform ;
++ this.defaultGraphTDB = getDefaultGraphTDB() ;
++ }
++
++ public void reset(TransactionalSystem txnSystem,
++ TripleTable tripleTable, QuadTable quadTable, DatasetPrefixStorage prefixes,
++ Location location, StoreParams params) {
++// this.tripleTable = tripleTable ;
++// this.quadTable = quadTable ;
++// this.location = location ;
++// this.prefixes = prefixes ;
++// this.storeParams = params ;
++ this.txnSystem = txnSystem ;
++ // XXX Threading?
++ // XXX (re)set transaction components in TransactionCoordinator??
++ this.storage = new StorageTDB(tripleTable, quadTable, prefixes, location, params);
++ this.defaultGraphTDB = getDefaultGraphTDB();
++ }
++
++ public QuadTable getQuadTable() { checkNotClosed(); return storage.quadTable; }
++ public TripleTable getTripleTable() { checkNotClosed(); return storage.tripleTable; }
++
++ /** Low level manipulation. */
++ public StorageTDB getStorage() { return storage; }
++ /** Low level manipulation.
++ * <b>Do not use unless in exclusive mode.</b>
++ */
++ public void setStorage(StorageTDB storage) { this.storage = storage; }
++
++ @Override
++ protected Iterator<Quad> findInDftGraph(Node s, Node p, Node o) {
++ checkNotClosed() ;
++ return isolate(triples2quadsDftGraph(getTripleTable().find(s, p, o))) ;
++ }
++
++ @Override
++ protected Iterator<Quad> findInSpecificNamedGraph(Node g, Node s, Node p, Node o) {
++ checkNotClosed();
++ return isolate(getQuadTable().find(g, s, p, o));
++ }
++
++ @Override
++ protected Iterator<Quad> findInAnyNamedGraphs(Node s, Node p, Node o) {
++ checkNotClosed();
++ return isolate(getQuadTable().find(Node.ANY, s, p, o));
++ }
++
++ protected Iterator<Quad> triples2quadsDftGraph(Iterator<Triple> iter)
++ { return isolate(triples2quads(Quad.defaultGraphIRI, iter)); }
++
++ private static final boolean CHECK_TXN = true;
++
++ private <T> Iterator<T> isolate(Iterator<T> iterator) {
++ if ( txnSystem.isInTransaction() ) {
++ TxnId txnId = txnSystem.getThreadTransaction().getTxnId();
++ // Add transaction protection.
++ return new IteratorTxnTracker<>(iterator, txnSystem, txnId);
++ }
++ // Risk the hidden arraylist is copied on growth.
++ return Iter.iterator(iterator);
++ }
++
++ @Override
++ protected void addToDftGraph(Node s, Node p, Node o) {
++ checkNotClosed() ;
++ requireWriteTxn() ;
++ notifyAdd(null, s, p, o) ;
++ getTripleTable().add(s,p,o) ;
++ }
++
++ @Override
++ protected void addToNamedGraph(Node g, Node s, Node p, Node o) {
++ checkNotClosed() ;
++ requireWriteTxn() ;
++ notifyAdd(g, s, p, o) ;
++ getQuadTable().add(g, s, p, o) ;
++ }
++
++ @Override
++ protected void deleteFromDftGraph(Node s, Node p, Node o) {
++ checkNotClosed() ;
++ requireWriteTxn() ;
++ notifyDelete(null, s, p, o) ;
++ getTripleTable().delete(s, p, o) ;
++ }
++
++ @Override
++ protected void deleteFromNamedGraph(Node g, Node s, Node p, Node o) {
++ checkNotClosed() ;
++ requireWriteTxn() ;
++ notifyDelete(g, s, p, o) ;
++ getQuadTable().delete(g, s, p, o) ;
++ }
++
++ // Promotion
++ private void requireWriteTxn() {
++ Transaction txn = txnSystem.getThreadTransaction() ;
++ if ( txn == null )
++ throw new TransactionException("Not in a transaction") ;
++
++ if ( txn.isWriteTxn() )
++ return ;
++ // Transaction.promoteOrException
++ boolean b = txn.promote() ;
++ if ( !b )
++ throw new TransactionException("Can't write") ;
++ }
++
++ // TODO ?? Optimize by integrating with add/delete operations.
++ private final void notifyAdd(Node g, Node s, Node p, Node o) {
++ if ( monitor == null )
++ return ;
++ QuadAction action = QuadAction.ADD ;
++ if ( checkForChange ) {
++ if ( contains(g,s,p,o) )
++ action = QuadAction.NO_ADD ;
++ }
++ monitor.change(action, g, s, p, o);
++ }
++
++ private final void notifyDelete(Node g, Node s, Node p, Node o) {
++ if ( monitor == null )
++ return ;
++ QuadAction action = QuadAction.DELETE ;
++ if ( checkForChange ) {
++ if ( ! contains(g,s,p,o) )
++ action = QuadAction.NO_DELETE ;
++ }
++ monitor.change(action, g, s, p, o);
++ }
++
++ /** No-op. There is no need to close datasets.
++ * Use {@link StoreConnection#release(Location)}.
++ * (Datasets can not be reopened on MS Windows).
++ */
++ @Override
++ public void close() {
++ if ( closed )
++ return ;
++ closed = true ;
++ }
++
++ private void checkNotClosed() {
++ if ( closed )
++ throw new TDBException("dataset closed") ;
++ }
++
++ /** Release resources.
++ * Do not call directly - this is called from StoreConnection.
++ * Use {@link StoreConnection#release(Location)}.
++ */
++ public void shutdown() {
++ close();
++ storage.tripleTable.close() ;
++ storage.quadTable.close() ;
++ storage.prefixes.close();
++ txnSystem.getTxnMgr().shutdown();
++ }
++
++ @Override
++ // Empty graphs don't "exist"
++ public boolean containsGraph(Node graphNode) {
++ checkNotClosed() ;
++ if ( Quad.isDefaultGraphExplicit(graphNode) || Quad.isUnionGraph(graphNode) )
++ return true ;
++ return _containsGraph(graphNode) ;
++ }
++
++ private boolean _containsGraph(Node graphNode) {
++ // Have to look explicitly, which is a bit of a nuisance.
++ // But does not normally happen for GRAPH <g> because that's rewritten to quads.
++ // Only pattern with complex paths go via GRAPH.
++ Iterator<Tuple<NodeId>> x = storage.quadTable.getNodeTupleTable().findAsNodeIds(graphNode, null, null, null) ;
++ if ( x == null )
++ return false ;
++ boolean result = x.hasNext() ;
++ return result ;
++ }
++
++ @Override
++ public void addGraph(Node graphName, Graph graph) {
++ checkNotClosed() ;
++ removeGraph(graphName) ;
++ GraphUtil.addInto(getGraph(graphName), graph) ;
++ }
++
++ @Override
++ public final void removeGraph(Node graphName) {
++ checkNotClosed() ;
++ deleteAny(graphName, Node.ANY, Node.ANY, Node.ANY) ;
++ }
++
++ @Override
++ public Graph getDefaultGraph() {
++ checkNotClosed() ;
++ return new GraphTDB(this, null) ;
++ }
++
++ public GraphTDB getDefaultGraphTDB() {
++ checkNotClosed();
++ return (GraphTDB)getDefaultGraph();
++ }
++
++ @Override
++ public Graph getGraph(Node graphNode) {
++ checkNotClosed();
++ return new GraphTDB(this, graphNode);
++ }
++
++ public GraphTDB getGraphTDB(Node graphNode) {
++ checkNotClosed();
++ return (GraphTDB)getGraph(graphNode);
++ }
++
++ public StoreParams getStoreParams() {
++ checkNotClosed();
++ return storage.storeParams;
++ }
++
++ public ReorderTransformation getReorderTransform() {
++ checkNotClosed();
++ return transform;
++ }
++
++ public DatasetPrefixStorage getPrefixes() {
++ checkNotClosed();
++ return storage.prefixes;
++ }
++
++ @Override
++ public Iterator<Node> listGraphNodes() {
++ checkNotClosed();
++ Iterator<Tuple<NodeId>> x = storage.quadTable.getNodeTupleTable().findAll();
++ Iterator<NodeId> z = Iter.iter(x).map(t -> t.get(0)).distinct();
++ return NodeLib.nodes(storage.quadTable.getNodeTupleTable().getNodeTable(), z);
++ }
++
++ @Override
++ public long size() {
++ checkNotClosed();
++ return Iter.count(listGraphNodes());
++ }
++
++ @Override
++ public boolean isEmpty() {
++ checkNotClosed();
++ return getTripleTable().isEmpty() && getQuadTable().isEmpty();
++ }
++
++ @Override
++ public void clear() {
++ checkNotClosed() ;
++ // Leave the node table alone.
++ getTripleTable().clearTriples() ;
++ getQuadTable().clearQuads() ;
++ }
++
++ public NodeTupleTable chooseNodeTupleTable(Node graphNode) {
++ checkNotClosed() ;
++
++ if ( graphNode == null || Quad.isDefaultGraph(graphNode) )
++ return getTripleTable().getNodeTupleTable() ;
++ else
++ // Includes Node.ANY and union graph
++ return getQuadTable().getNodeTupleTable() ;
++ }
++
++ private static final int sliceSize = 1000 ;
++
++ @Override
++ public void deleteAny(Node g, Node s, Node p, Node o) {
++ // Delete in batches.
++ // That way, there is no active iterator when a delete
++ // from the indexes happens.
++ checkNotClosed() ;
++
++ if ( monitor != null ) {
++ // Need to do by nodes because we will log the deletes.
++ super.deleteAny(g, s, p, o);
++ return ;
++ }
++
++ // Not logging - do by working as NodeIds.
++ NodeTupleTable t = chooseNodeTupleTable(g) ;
++ @SuppressWarnings("unchecked")
++ Tuple<NodeId>[] array = (Tuple<NodeId>[])new Tuple<?>[sliceSize] ;
++
++ while (true) { // Convert/cache s,p,o?
++ // The Node Cache will catch these so don't worry unduely.
++ Iterator<Tuple<NodeId>> iter = null ;
++ if ( g == null )
++ iter = t.findAsNodeIds(s, p, o) ;
++ else
++ iter = t.findAsNodeIds(g, s, p, o) ;
++
++ if ( iter == null || ! iter.hasNext() )
++ return ;
++
++ // Get a slice
++ int len = 0 ;
++ for (; len < sliceSize; len++) {
++ if ( !iter.hasNext() )
++ break ;
++ array[len] = iter.next() ;
++ }
++
++ // Delete the NodeId Tuples
++ for (int i = 0; i < len; i++) {
++ t.getTupleTable().delete(array[i]) ;
++ array[i] = null ;
++ }
++ // Finished?
++ if ( len < sliceSize )
++ break ;
++ }
++ }
++
++ public Location getLocation() { return storage.location ; }
++
++ @Override
++ public void sync() {
++ checkNotClosed();
++ storage.tripleTable.sync();
++ storage.quadTable.sync();
++ storage.prefixes.sync();
++ }
++
++ @Override
++ public void setDefaultGraph(Graph g) {
++ throw new UnsupportedOperationException("Can't set default graph on a TDB-backed dataset") ;
++ }
++
++ @Override
++ public boolean isInTransaction() {
++ return txnSystem.isInTransaction() ;
++ }
++
++ // txnSystem with monitor?
++ @Override
++ public void begin(ReadWrite readWrite) {
++ if ( txnMonitor != null ) txnMonitor.startBegin(readWrite);
++ txnSystem.begin(readWrite) ;
++ if ( txnMonitor != null ) txnMonitor.finishBegin(readWrite);
++ }
++
++ @Override
++ public boolean promote() {
++ if ( txnMonitor != null ) txnMonitor.startPromote();
++ try {
++ return txnSystem.promote() ;
++ } finally { if ( txnMonitor != null ) txnMonitor.finishPromote(); }
++ }
++
++ @Override
++ public void commit() {
++ if ( txnMonitor != null ) txnMonitor.startCommit();
++ txnSystem.commit() ;
++ if ( txnMonitor != null ) txnMonitor.finishCommit();
++ }
++
++ @Override
++ public void abort() {
++ if ( txnMonitor != null ) txnMonitor.startAbort() ;
++ txnSystem.abort() ;
++ if ( txnMonitor != null ) txnMonitor.finishAbort() ;
++ }
++
++ @Override
++ public void end() {
++ if ( txnMonitor != null ) txnMonitor.startEnd();
++ txnSystem.end() ;
++ if ( txnMonitor != null ) txnMonitor.finishEnd();
++ }
++
++ public TransactionalSystem getTxnSystem() {
++ return txnSystem ;
++ }
++
++ // Watching changes (add, delete, deleteAny)
++
++ private DatasetChanges monitor = null ;
++ public void setMonitor(DatasetChanges changes) {
++ monitor = changes ;
++ }
++
++ public void removeMonitor(DatasetChanges changes) {
++ if ( monitor != changes )
++ throw new InternalErrorException() ;
++ monitor = null ;
++ }
++
++ // Watching Transactional
++
++ private TransactionalMonitor txnMonitor = null ;
++ public void setTransactionalMonitor(TransactionalMonitor changes) {
++ txnMonitor = changes ;
++ }
++
++ public void removeTransactionalMonitor(TransactionalMonitor changes) {
++ if ( txnMonitor != changes )
++ throw new InternalErrorException() ;
++ txnMonitor = null ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphTxn.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphTxn.java
index 0000000,0000000..0915ff0
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphTxn.java
@@@ -1,0 -1,0 +1,34 @@@
++/*
++ * 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 org.apache.jena.sparql.core.DatasetGraph ;
++import org.seaborne.dboe.transaction.Transactional ;
++
++/** Transaction representation of a DatasetGraph */
++public interface DatasetGraphTxn extends DatasetGraph, Transactional {
++ // Combines org.seaborne.dboe.transaction.Transactional and org.apache.jena.sparql.core.Transactional.
++ // o.s.dboe.Transactional add promote()
++
++ @Override
++ public default boolean supportsTransactions() { return true ; }
++
++ @Override
++ public default boolean supportsTransactionAbort() { return true ; }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphWrapperTxn.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphWrapperTxn.java
index 0000000,0000000..e172c90
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphWrapperTxn.java
@@@ -1,0 -1,0 +1,34 @@@
++/*
++ * 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.store;
++
++import org.apache.jena.sparql.core.DatasetGraphWrapper ;
++
++public class DatasetGraphWrapperTxn extends DatasetGraphWrapper implements DatasetGraphTxn {
++
++ public DatasetGraphWrapperTxn(DatasetGraphTxn dsg) {
++ super(dsg) ;
++ }
++
++ @Override
++ public boolean promote() {
++ return ((DatasetGraphTxn)get()).promote() ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetPrefixesTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetPrefixesTDB.java
index 0000000,0000000..0b7f072
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetPrefixesTDB.java
@@@ -1,0 -1,0 +1,173 @@@
++/*
++ * 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.* ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.atlas.logging.Log ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.graph.NodeFactory ;
++import org.apache.jena.shared.PrefixMapping ;
++import org.apache.jena.sparql.core.DatasetPrefixStorage ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.tdb2.store.nodetupletable.NodeTupleTable ;
++
++/**
++ * Dataset prefixes; a table of nodes with prefix-centric operations. The table
++ * is G-P-U where G is a graph name ("" is used for the default graph), P is a
++ * string (the prefix) and U is the IRI.
++ */
++public class DatasetPrefixesTDB implements DatasetPrefixStorage
++{
++ // 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 = "" ;
++
++ private final NodeTupleTable nodeTupleTable ;
++
++ public DatasetPrefixesTDB(NodeTupleTable nodeTupleTable) {
++ this.nodeTupleTable = nodeTupleTable ;
++ }
++
++ @Override
++ public void loadPrefixMapping(String graphName, PrefixMapping pmap) {
++ Node g = NodeFactory.createURI(graphName) ;
++ Iterator<Tuple<Node>> iter = nodeTupleTable.find(g, null, null) ;
++ iter.forEachRemaining(tuple->{
++ Node prefix = tuple.get(1) ;
++ Node uri = tuple.get(2) ;
++ pmap.setNsPrefix(prefix.getLiteralLexicalForm(), uri.getURI()) ;
++ }) ;
++ }
++
++ @Override
++ public synchronized void insertPrefix(String graphName, String prefix, String uri) {
++ Node g = NodeFactory.createURI(graphName) ;
++ Node p = NodeFactory.createLiteral(prefix) ;
++ Node u = NodeFactory.createURI(uri) ;
++
++ nodeTupleTable.addRow(g,p,u) ;
++ }
++
++ @Override
++ public Set<String> graphNames() {
++ Iterator<Tuple<Node>> iter = nodeTupleTable.find((Node)null, null, null) ;
++ Set <String> x = new HashSet<>() ;
++ for ( ; iter.hasNext() ; )
++ x.add(iter.next().get(0).getURI()) ;
++ Iter.close(iter) ;
++ return x ;
++ }
++
++ @Override
++ public synchronized String readPrefix(String graphName, String prefix) {
++ Node g = NodeFactory.createURI(graphName) ;
++ Node p = NodeFactory.createLiteral(prefix) ;
++
++ Iterator<Tuple<Node>> iter = nodeTupleTable.find(g, p, null) ;
++ try {
++ if ( ! iter.hasNext() )
++ return null ;
++ Tuple<Node> t = iter.next() ;
++ Node uri = t.get(2) ;
++ return uri.getURI() ;
++ } finally { Iter.close(iter) ; }
++ }
++
++ @Override
++ public synchronized String readByURI(String graphName, String uriStr) {
++ Node g = NodeFactory.createURI(graphName) ;
++ Node u = NodeFactory.createURI(uriStr) ;
++ Iterator<Tuple<Node>> iter = nodeTupleTable.find(g, null, u) ;
++ if ( ! iter.hasNext() )
++ return null ;
++ Node prefix = iter.next().get(1) ;
++ Iter.close(iter) ;
++ return prefix.getLiteralLexicalForm() ;
++ }
++
++ @Override
++ public synchronized Map<String, String> readPrefixMap(String graphName) {
++ Map<String, String> map = new HashMap<>() ;
++ Node g = NodeFactory.createURI(graphName) ;
++ Iterator<Tuple<Node>> iter = nodeTupleTable.find(g, null, null) ;
++ for ( ; iter.hasNext() ; ) {
++ try {
++ Tuple<Node> t = iter.next() ;
++ String prefix = t.get(1).getLiteralLexicalForm() ;
++ String uri = t.get(2).getURI() ;
++ map.put(prefix, uri) ;
++ }
++ catch (Exception ex) {
++ Log.warn(this, "Mangled prefix map: graph name=" + graphName, ex) ;
++ }
++ }
++ Iter.close(iter) ;
++ return map ;
++ }
++
++ @Override
++ public void removeFromPrefixMap(String graphName, String prefix) {
++ Node g = NodeFactory.createURI(graphName) ;
++ Node p = NodeFactory.createLiteral(prefix) ;
++ removeAll(g, p, null) ;
++ }
++
++ @Override
++ public void removeAllFromPrefixMap(String graphName) {
++ Node g = NodeFactory.createURI(graphName) ;
++ removeAll(g, null, null) ;
++ }
++
++ /** Remove by pattern */
++ private synchronized void removeAll(Node g, Node p, Node uri) {
++ Iterator<Tuple<Node>> iter = nodeTupleTable.find(g, p, uri) ;
++ List<Tuple<Node>> list = Iter.toList(iter) ; // Materialize.
++ Iter.close(iter) ;
++ for ( Tuple<Node> tuple : list )
++ nodeTupleTable.deleteRow(tuple.get(0), tuple.get(1), tuple.get(2)) ;
++ }
++
++ public NodeTupleTable getNodeTupleTable() { return nodeTupleTable ; }
++
++ /** Return a PrefixMapping for the unamed graph */
++ @Override
++ public PrefixMapping getPrefixMapping()
++ { return getPrefixMapping(unamedGraphURI) ; }
++
++ /** Return a PrefixMapping for a named graph */
++ @Override
++ public PrefixMapping getPrefixMapping(String graphName) {
++ PrefixMapping pm = new GraphPrefixesProjectionTDB(graphName, this) ;
++ return pm ;
++ }
++
++ @Override
++ public void close() {
++ nodeTupleTable.close() ;
++ }
++
++ @Override
++ public void sync() {
++ nodeTupleTable.sync() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/GraphPrefixesProjectionTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/GraphPrefixesProjectionTDB.java
index 0000000,0000000..2c50740
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/GraphPrefixesProjectionTDB.java
@@@ -1,0 -1,0 +1,163 @@@
++/*
++ * 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.Map ;
++import java.util.Map.Entry ;
++import java.util.Optional ;
++
++import org.apache.jena.rdf.model.impl.Util ;
++import org.apache.jena.shared.PrefixMapping ;
++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 final String graphName ;
++ private final DatasetPrefixStorage prefixes ;
++
++ public GraphPrefixesProjectionTDB(String graphName, DatasetPrefixStorage prefixes)
++ {
++ this.graphName = graphName ;
++ this.prefixes = prefixes ;
++ }
++
++ @Override
++ public PrefixMapping setNsPrefix(String prefix, String uri) {
++ prefixes.insertPrefix(graphName, prefix, uri);
++ return this ;
++ }
++
++ @Override
++ public PrefixMapping removeNsPrefix(String prefix) {
++ prefixes.removeFromPrefixMap(graphName, prefix);
++ return this ;
++ }
++
++ @Override
++ public PrefixMapping clearNsPrefixMap() {
++ prefixes.removeAllFromPrefixMap(graphName);
++ return this ;
++ }
++
++ @Override
++ public PrefixMapping setNsPrefixes(PrefixMapping other) {
++ setNsPrefixes(other.getNsPrefixMap()) ;
++ return this ;
++ }
++
++ @Override
++ public PrefixMapping setNsPrefixes(Map<String, String> map) {
++ map.entrySet().forEach(entry->{
++ setNsPrefix(entry.getKey(), entry.getValue()) ;
++ });
++ return this ;
++ }
++
++ @Override
++ public PrefixMapping withDefaultMappings(PrefixMapping other) {
++ other.getNsPrefixMap().entrySet().forEach(entry->{
++ String prefix = entry.getKey() ;
++ String uri = entry.getValue();
++ if (getNsPrefixURI( prefix ) == null && getNsURIPrefix( uri ) == null)
++ setNsPrefix( prefix, uri );
++ }) ;
++ return this ;
++ }
++
++ @Override
++ public String getNsPrefixURI(String prefix) {
++ return prefixes.readPrefix(graphName, prefix) ;
++ }
++
++ @Override
++ public String getNsURIPrefix(String uri) {
++ return prefixes.readByURI(graphName, uri) ;
++ }
++
++ @Override
++ public Map<String, String> getNsPrefixMap() {
++ return prefixes.readPrefixMap(graphName) ;
++ }
++
++ // From PrefixMappingImpl
++ @Override
++ public String expandPrefix(String prefixed) {
++ {
++ int colon = prefixed.indexOf(':') ;
++ if ( colon < 0 )
++ return prefixed ;
++ else {
++ String prefix = prefixed.substring(0, colon) ;
++ String uri = prefixes.readPrefix(graphName, 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);
++ String local = uri.substring(split) ;
++ if ( local.equals("") )
++ return null ;
++ String prefix = prefixes.readByURI(graphName, ns) ;
++ return prefix == null ? null : prefix + ":" + local ;
++ }
++
++ @Override
++ public String shortForm(String uri) {
++ Optional<Entry<String, String>> e = findMapping(uri, true) ;
++ if ( ! e.isPresent() )
++ return uri ;
++ return e.get().getKey() + ":" + uri.substring((e.get().getValue()).length()) ;
++ }
++
++ // Do better?
++
++ @Override
++ public boolean hasNoMappings() { return getNsPrefixMap().isEmpty() ; }
++
++ @Override
++ public int numPrefixes() {
++ return getNsPrefixMap().size() ;
++ }
++
++ private Optional<Entry<String, String>> findMapping( String uri, boolean partial )
++ {
++ return getNsPrefixMap().entrySet().stream().sequential().filter(e->{
++ String ss = e.getValue();
++ if (uri.startsWith( ss ) && (partial || ss.length() == uri.length()))
++ return true;
++ return false ;
++ }).findFirst() ;
++ }
++
++ @Override
++ public PrefixMapping lock() {
++ return this ;
++ }
++
++ @Override
++ public boolean samePrefixMappingAs(PrefixMapping other) {
++ return this.getNsPrefixMap().equals(other.getNsPrefixMap()) ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/GraphTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/GraphTDB.java
index 0000000,0000000..a1e99ce
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/GraphTDB.java
@@@ -1,0 -1,0 +1,180 @@@
++/*
++ * 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.function.Function;
++
++import org.apache.jena.atlas.iterator.Iter ;
++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.atlas.lib.tuple.TupleFactory ;
++import org.apache.jena.graph.* ;
++import org.apache.jena.riot.other.GLib ;
++import org.apache.jena.shared.PrefixMapping ;
++import org.apache.jena.sparql.core.GraphView ;
++import org.apache.jena.sparql.core.Quad ;
++import org.apache.jena.util.iterator.ExtendedIterator ;
++import org.apache.jena.util.iterator.WrappedIterator ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.graph.TransactionHandlerTDB ;
++import org.seaborne.tdb2.store.nodetupletable.NodeTupleTable ;
++
++/**
++ * General operations for TDB graphs (free-standing graph, default graph and
++ * named graphs)
++ */
++public class GraphTDB extends GraphView implements Closeable, Sync {
++ private final TransactionHandler transactionHandler = new TransactionHandlerTDB(this) ;
++
++ // Switch this to DatasetGraphTransaction
++ private final DatasetGraphTDB dataset ;
++
++ public GraphTDB(DatasetGraphTDB dataset, Node graphName) {
++ super(dataset, graphName) ;
++ this.dataset = dataset ;
++ }
++
++ /** get the current TDB dataset graph - changes for transactions */
++ public DatasetGraphTDB getDSG() {
++ return dataset ;
++ }
++
++ /** The NodeTupleTable for this graph */
++ public NodeTupleTable getNodeTupleTable() {
++ return getDSG().chooseNodeTupleTable(getGraphName()) ;
++ }
++
++ @Override
++ protected PrefixMapping createPrefixMapping() {
++ if ( isDefaultGraph() )
++ return getDSG().getPrefixes().getPrefixMapping() ;
++ if ( isUnionGraph() )
++ return getDSG().getPrefixes().getPrefixMapping() ;
++ return getDSG().getPrefixes().getPrefixMapping(getGraphName().getURI()) ;
++ }
++
++ @Override
++ public final void sync() {
++ dataset.sync() ;
++ }
++
++ @Override
++ final public void close() {
++ sync() ;
++ // Don't close the GraphBase.
++ //super.close() ;
++ }
++
++ protected static ExtendedIterator<Triple> graphBaseFindDft(DatasetGraphTDB dataset, Triple triple) {
++ Iterator<Quad> iterQuads = dataset.find(Quad.defaultGraphIRI, triple.getSubject(), triple.getPredicate(), triple.getObject()) ;
++ if ( iterQuads == null )
++ return org.apache.jena.util.iterator.NullIterator.instance() ;
++ // Can't be duplicates - fixed graph node..
++ Iterator<Triple> iterTriples = projectQuadsToTriples(Quad.defaultGraphIRI, iterQuads) ;
++ return WrappedIterator.createNoRemove(iterTriples) ;
++ }
++
++ protected static ExtendedIterator<Triple> graphBaseFindNG(DatasetGraphTDB dataset, Node graphNode, Triple m) {
++ Node gn = graphNode ;
++ // Explicitly named union graph.
++ if ( isUnionGraph(gn) )
++ gn = Node.ANY ;
++
++ 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 = projectQuadsToTriples((gn == Node.ANY ? null : gn), iter) ;
++
++ if ( gn == Node.ANY )
++ iterTriples = Iter.distinct(iterTriples) ;
++ return WrappedIterator.createNoRemove(iterTriples) ;
++ }
++
++ @Override
++ protected ExtendedIterator<Triple> graphUnionFind(Node s, Node p, Node o) {
++ Node g = Quad.unionGraph ;
++ Iterator<Quad> iterQuads = getDSG().find(g, s, p, o) ;
++ Iterator<Triple> iter = GLib.quads2triples(iterQuads) ;
++ // Suppress duplicates after projecting to triples.
++ // TDB guarantees that duplicates are adjacent.
++ // See SolverLib.
++ iter = Iter.distinctAdjacent(iter) ;
++ return WrappedIterator.createNoRemove(iter) ;
++ }
++
++ @Override
++ protected final int graphBaseSize() {
++ if ( isDefaultGraph() )
++ return (int)getNodeTupleTable().size() ;
++
++ Node gn = getGraphName() ;
++ boolean unionGraph = isUnionGraph(gn) ;
++ gn = unionGraph ? Node.ANY : gn ;
++ Iterator<Tuple<NodeId>> iter = getDSG().getQuadTable().getNodeTupleTable().findAsNodeIds(gn, null, null, null) ;
++ if ( unionGraph ) {
++ iter = Iter.map(iter, project4TupleTo3Tuple) ;
++ iter = Iter.distinctAdjacent(iter) ;
++ }
++ return (int)Iter.count(iter) ;
++ }
++
++ private static Function<Tuple<NodeId>, Tuple<NodeId>> project4TupleTo3Tuple = item -> {
++ if (item.len() != 4)
++ throw new TDBException("Expected a Tuple of 4, got: " + item);
++ return TupleFactory.tuple(item.get(1), item.get(2), item.get(3));
++ };
++
++ 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();
++ };
++ // Without.
++ //Function<Quad, Triple> f = (q) -> q.asTriple();
++ return Iter.map(iter, f);
++ }
++
++ @Override
++ public TransactionHandler getTransactionHandler() {
++ return transactionHandler ;
++ }
++
++ @Override
++ public void clear() {
++ dataset.deleteAny(getGraphName(), Node.ANY, Node.ANY, Node.ANY) ;
++ getEventManager().notifyEvent(this, GraphEvents.removeAll) ;
++ }
++
++ @Override
++ public void remove(Node s, Node p, Node o) {
++ if ( getEventManager().listening() ) {
++ // Have to do it the hard way so that triple events happen.
++ super.remove(s, p, o) ;
++ return ;
++ }
++
++ dataset.deleteAny(getGraphName(), s, p, o) ;
++ // We know no one is listening ...
++ // getEventManager().notifyEvent(this, GraphEvents.remove(s, p, o) ) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/GraphViewSwitchable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/GraphViewSwitchable.java
index 0000000,0000000..d52f7a0
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/GraphViewSwitchable.java
@@@ -1,0 -1,0 +1,139 @@@
++/*
++ * 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.store;
++
++import java.util.Map ;
++
++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.DatasetPrefixStorage ;
++import org.apache.jena.sparql.core.GraphView ;
++import org.apache.jena.sparql.core.Quad ;
++
++/** A GraphView that is sensitive to {@link DatasetGraphSwitchable} switching.
++ */
++public class GraphViewSwitchable extends GraphView {
++ // Fixups for GraphView
++ // Prefixes.
++ // Transaction handler.
++ // Long term - ensure that GraphView uses get() always, inc prefixes, transaction handlers
++
++ // Factory style.
++ public static GraphViewSwitchable createDefaultGraph(DatasetGraphSwitchable dsg)
++ { return new GraphViewSwitchable(dsg, Quad.defaultGraphNodeGenerated) ; }
++
++ public static GraphView createNamedGraph(DatasetGraphSwitchable dsg, Node graphIRI)
++ { return new GraphViewSwitchable(dsg, graphIRI) ; }
++
++ public static GraphViewSwitchable createUnionGraph(DatasetGraphSwitchable dsg)
++ { return new GraphViewSwitchable(dsg, Quad.unionGraph) ; }
++
++ private final DatasetGraphSwitchable dsgx;
++ protected DatasetGraphSwitchable getx() { return dsgx; }
++
++ protected GraphViewSwitchable(DatasetGraphSwitchable dsg, Node gn) {
++ super(dsg, gn) ;
++ this.dsgx = dsg;
++ }
++
++// @Override
++// public TransactionHandler getTransactionHandler() {
++// // XXX Awiting for promote to be enabled.
++// return super.getTransactionHandler();
++// }
++
++ @Override
++ protected PrefixMapping createPrefixMapping() {
++ Node gn = super.getGraphName();
++ if ( gn == Quad.defaultGraphNodeGenerated )
++ gn = null;
++ if ( Quad.isUnionGraph(gn) ) {
++ // Read-only wrapper would be better that a copy.
++ PrefixMapping pmap = new PrefixMappingImpl();
++ pmap.setNsPrefixes(prefixMapping(null));
++ return pmap;
++ }
++ return prefixMapping(gn);
++ }
++
++ /** Return the {@code DatasetGraphSwitchable} we are viewing. */
++ @Override
++ public DatasetGraphSwitchable getDataset() {
++ return getx() ;
++ }
++
++ // TDB2 specific.
++ // Does not cope with blank nodes.
++ // A PrefixMapping sending operations via the switchable.
++ // Long term, rework as PrefixMapping over PrefixMap over DatasetPrefixStorage
++ private PrefixMapping prefixMapping(Node graphName) {
++
++ String gn = (graphName == null) ? "" : graphName.getURI();
++
++ return new PrefixMappingImpl() {
++
++ DatasetPrefixStorage dps() {
++ return ((DatasetGraphTDB)(getx().get())).getPrefixes();
++ }
++
++ Graph graph() {
++ DatasetGraphTDB dsg = (DatasetGraphTDB)getx().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) {
++ //Ignore. String x = super.get(prefix);
++ // (Ignore more?)
++ 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();
++ }
++ };
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/Hash.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/Hash.java
index 0000000,0000000..6692325
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/Hash.java
@@@ -1,0 -1,0 +1,56 @@@
++/*
++ * 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.Arrays;
++
++import org.apache.jena.atlas.lib.Bytes ;
++
++
++/** Hash values. */
++public class Hash
++{
++ private byte [] bytes ;
++ public Hash(int len) { bytes = new byte[len] ; }
++ public int getLen() { return bytes.length ; }
++ public byte [] getBytes() { return bytes ; }
++
++ @Override
++ public int hashCode()
++ {
++ return Arrays.hashCode(bytes) ;
++ }
++
++ @Override
++ public boolean equals(Object other)
++ {
++ if ( this == other ) return true ;
++ if ( ! (other instanceof Hash) )
++ return false ;
++ boolean b = Arrays.equals(bytes, ((Hash)other).bytes) ;
++ return b ;
++ }
++
++ @Override
++ public String toString()
++ {
++ return "hash:"+Bytes.asHex(bytes) ;
++ }
++
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/IteratorCheckNotConcurrent.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/IteratorCheckNotConcurrent.java
index 0000000,0000000..0aa4182
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/IteratorCheckNotConcurrent.java
@@@ -1,0 -1,0 +1,93 @@@
++/*
++ * 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.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 ;
++
++/** Wrapper to check an iterator has not been used across some write operation. */
++class IteratorCheckNotConcurrent<T> implements Iterator<T>, Closeable
++{
++ private Iterator<T> iter ;
++ private AtomicLong eCount ; // Needs fixing to be per thera in some way - either from the caller or here.
++ 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)) ;
++ }
++ }
++
++ private static void policyError(String message) {
++ throw new ConcurrentModificationException(message) ;
++ }
++
++ @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() ;
++ // Reset the epoch.
++ startEpoch = eCount.get() ;
++ }
++
++ @Override
++ public void close() {
++ finished = true ;
++ Iter.close(iter) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/IteratorTxnTracker.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/IteratorTxnTracker.java
index 0000000,0000000..d56fb0d
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/IteratorTxnTracker.java
@@@ -1,0 -1,0 +1,55 @@@
++/*
++ * 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.store;
++
++import java.util.Iterator;
++import java.util.Objects;
++
++import org.apache.jena.atlas.iterator.IteratorWrapper;
++import org.seaborne.dboe.transaction.txn.Transaction;
++import org.seaborne.dboe.transaction.txn.TransactionException;
++import org.seaborne.dboe.transaction.txn.TransactionalSystem;
++import org.seaborne.dboe.transaction.txn.TxnId;
++
++/** Wrapper to check that an iterator is used inside its originating transaction. */
++public class IteratorTxnTracker<T> extends IteratorWrapper<T> {
++ private final TransactionalSystem txnSystem;
++ private final TxnId txnId;
++
++ public IteratorTxnTracker(Iterator<T> iterator, TransactionalSystem txnSystem, TxnId txnId) {
++ super(iterator);
++ this.txnSystem = Objects.requireNonNull(txnSystem, "TransactionalSystem");
++ this.txnId = Objects.requireNonNull(txnId, "TxnId") ;
++ }
++
++ @Override public boolean hasNext() { check() ; return super.hasNext() ; }
++
++ @Override public T next() { check() ; return super.next() ; }
++
++ @Override public void remove() { check() ; super.remove() ; }
++
++ private void check() {
++ Transaction txn = txnSystem.getThreadTransaction();
++ if ( txn == null )
++ throw new TransactionException("Iterator used outside its original transaction");
++ if ( txn != null && txnId.equals(txn.getTxnId()) )
++ return ;
++ throw new TransactionException("Iterator used inside a different transaction");
++ }
++}
[29/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/DoubleNode62.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/DoubleNode62.java
index 0000000,0000000..b65d5eb
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/DoubleNode62.java
@@@ -1,0 -1,0 +1,241 @@@
++/*
++ * 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.store.value;
++
++import org.apache.jena.atlas.lib.BitsLong;
++
++/**
++ * Doubles packed into 62 bits.
++ * <p>
++ * Uses java's 64 bit long format (which is IEEE754 binary64) except that 2 bits are taken
++ * from the exponent. This keeps the precision but reduces the range.
++ * <p>
++ * <b>Java
++ * (<a href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format">IEEE
++ * 754 binary64</a>)</b>
++ *
++ * <pre>
++ * bit 63 : sign bit
++ * bits 52-62 : exponent, 11 bits, the power of 2, bias -1023.
++ * bits 0-51 : mantissa (significand) 52 bits (the leading one is not stored).
++ *
++ * Exponents are 11 bits, with values -1022 to +1023 held as 1 to 2046 (11 bits, bias -1023)
++ * 0x000 is signed zero.
++ * 0x7FF is +/- infinity.
++ * </pre>
++ *
++ * for a maximum value of 1.797693e+308 = (2-2^-52)*2^1023 and smallest denormlized of
++ * (1-2^-52)*2^-1022 = 2.225...e-308.
++ * <p>
++ * <b>DoubleNode62</b>
++ * <p>
++ * In a 62 bit double:
++ *
++ * <pre>
++ * bit 63 : pointer bit.
++ * bit 62 : double type bit.
++ * bit 61 : sign bit
++ * bits 52-60 : exponent, 9 bits, the power of 2, bias -255
++ * bits 0-51 : mantissa (significand) 52 bits (the leading one is not stored).
++ *
++ * Exponents are 9 bits, with values -254 to 255, held as 1 to 512 (9 bits, bias -255)
++ * 0x000 is signed zero.
++ * 0x1FF is +/- infinity.
++ * </pre>
++ *
++ * for a maximum value of (2-2^-52)*2^255 = 1.157921e+77 and smallest denormlized of
++ * (1-2^-52)*2^-254 = 3.4544674e-77
++ * <p>
++ * 0 is not a legal encoding because the high bit is the pointer/value bit.
++ * <p>
++ * "No encoding" is 0xFF00_0000_0000_0000L which would otherwise be the smallest (most negative) denormalized value:
++ * -3.5336941295567687E72
++ * <p>All unencodeable numbers wil endup in the node table in full lexical form.
++ */
++public class DoubleNode62 {
++ /**
++ * An encoded value that is not possible.
++ * (it has high bits set).
++ */
++ public static long NO_ENCODING = 0xFF00_0000_0000_0000L;
++
++ /** Encode as a 62 bit long.
++ * Return {@link #NO_ENCODING} for "not possible".
++ * The top two bits are zero if packing was possible.
++ */
++ public static long pack(double v) {
++ long x = Double.doubleToRawLongBits(v);
++ long sign = BitsLong.unpack(x, 63, 64);
++ long exp11 = BitsLong.unpack(x, 52, 63);
++ long exp9 = encode11to9(exp11);
++ if ( exp9 == -1 )
++ return NO_ENCODING;
++ long significand = BitsLong.unpack(x, 0, 52);
++ // Do not set the value bit or double bit.
++ // This is done when outting into bytes.
++ long z = 0;
++ z = BitsLong.pack(z, sign, 61, 62);
++ z = BitsLong.pack(z, exp9, 52, 61);
++ z = BitsLong.pack(z, significand, 0, 52);
++ return z;
++ }
++
++ public static long insertType(long x) {
++ // bits 63 1 (pointer/value), bit 62 1(double)
++ return x | 0x3L<<62;
++ }
++
++ public static long removeType(long x) {
++ // bits 63 1 (pointer/value), bit 62 1(double)
++ return x & ~(0x3L<<62);
++ }
++
++ public static double unpack(long x) {
++ if ( x == NO_ENCODING )
++ throw new IllegalArgumentException("No encoding inline");
++ long sign = BitsLong.unpack(x, 61, 62);
++ long exp9 = BitsLong.unpack(x, 52, 61);
++ long significand = BitsLong.unpack(x, 0, 52);
++ long exp11 = decode9to11(exp9);
++ long z = 0;
++ z = BitsLong.pack(z, sign, 63, 64);
++ z = BitsLong.pack(z, exp11, 52, 63);
++ z = BitsLong.pack(z, significand, 0, 52);
++ double d = Double.longBitsToDouble(z);
++ return d;
++ }
++
++ // Exponent: returns -1 for out of inlien range.
++ private static long encode11to9(long exp11) {
++ if ( exp11 == 0 )
++ return 0L;
++ if ( exp11 == 0x7FF )
++ return 0x3FFL;
++
++ // Remove bias.
++ long expRebase = exp11 - 1023;
++ if ( expRebase < -254 || expRebase > 255 )
++ // Out of range.
++ return -1;
++ long exp9 = expRebase + 255;
++ return exp9;
++ }
++
++ // Exponent
++ private static long decode9to11(long exp9) {
++ if ( exp9 == 0 )
++ return 0L;
++ else if ( exp9 == 0x1FF )
++ return 0x7FFL;
++ long expRebase = exp9 - 255;
++ long exp11 = expRebase + 1023;
++ return exp11;
++
++ }
++
++ // ---- Constants without type bits (so bits 62 and 63 are zero).
++ /**
++ * 0x1ff0000000000000L
++ * @see Double#POSITIVE_INFINITY
++ */
++ public static final long POSITIVE_INFINITY_BITS = pack(Double.POSITIVE_INFINITY);
++
++ /**
++ * @see Double#POSITIVE_INFINITY
++ */
++ public static final double POSITIVE_INFINITY = unpack(POSITIVE_INFINITY_BITS);
++
++ /**
++ * 0x3ff0000000000000L
++ * @see Double#NEGATIVE_INFINITY
++ */
++ public static final long NEGATIVE_INFINITY_BITS = pack(Double.NEGATIVE_INFINITY);
++
++ /**
++ * @see Double#NEGATIVE_INFINITY
++ */
++ public static final double NEGATIVE_INFINITY = unpack(NEGATIVE_INFINITY_BITS);
++
++ /**
++ * 0x1ff8000000000000L
++ * @see Double#NaN
++ */
++ public static final long NaN_BITS = pack(Double.NaN);
++
++ /**
++ * @see Double#NaN
++ */
++ public static final double NaN = unpack(NaN_BITS);
++
++ /**
++ * 0x3fefffffffffffffL
++ * <br/>
++ * (2-2<sup>-52</sup>)·2<sup>255</sup>.
++ *
++ * @see Double#MAX_VALUE
++ */
++ public static final long MAX_VALUE_BITS = 0x3fefffffffffffffL;
++
++ /**
++ * 0x3fefffffffffffffL
++ * <br/>
++ * (2-2<sup>-52</sup>)·2<sup>255</sup>.
++ *
++ * @see Double#MAX_VALUE
++ */
++ public static final double MAX_VALUE = unpack(MAX_VALUE_BITS);
++
++ /**
++ * 0x0010000000000000L
++ * @see Double#MIN_NORMAL
++ */
++ public static final long MIN_NORMAL_BITS = 0x0010000000000000L;
++
++ /**
++ * @see Double#MIN_NORMAL
++ */
++ public static final double MIN_NORMAL = unpack(0x0010000000000000L);
++
++ /**
++ * 0x01L
++ * @see Double#MIN_VALUE
++ */
++ public static final long MIN_VALUE_BITS = 0x01L;
++
++ /**
++ * 0x01L
++ * @see Double#MIN_VALUE
++ */
++ public static final double MIN_VALUE = unpack(MIN_VALUE_BITS);
++
++ /**
++ * @see Double#MAX_EXPONENT
++ */
++ public static final int MAX_EXPONENT = 255;
++
++ /**
++ * @see Double#MIN_EXPONENT
++ */
++ public static final int MIN_EXPONENT = -254;
++
++ /**
++ * @see Double#SIZE
++ */
++ public static final int SIZE = 62;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/FloatNode.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/FloatNode.java
index 0000000,0000000..4dc1c0a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/FloatNode.java
@@@ -1,0 -1,0 +1,31 @@@
++/*
++ * 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.value;
++
++public class FloatNode {
++ // 32 bits of value; collapses NaNs to a single value.
++
++ public static long pack(float v) {
++ return Float.floatToIntBits(v);
++ }
++
++ public static float unpack(long v) {
++ return Float.intBitsToFloat((int)v);
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/IntegerNode.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/IntegerNode.java
index 0000000,0000000..9df7352
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/value/IntegerNode.java
@@@ -1,0 -1,0 +1,63 @@@
++/*
++ * 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.value;
++
++import org.apache.jena.atlas.lib.BitsLong;
++
++public class IntegerNode {
++ // 56 bits of value, including sign bit.
++ public static int LEN = 56;
++ public static int LBITS = Long.SIZE;
++ public static long MAX = (1L << (LEN - 1)) - 1;
++ public static long MIN = -(1L << (LEN - 1));
++
++ public static long pack(long v) {
++ if ( v >= MIN && v <= MAX ) {
++ v = BitsLong.clear(v, LEN, LBITS);
++ return v;
++ } else
++ return -1;
++ }
++
++ public static long unpack(long v) {
++ long val = BitsLong.clear(v, LEN, LBITS);
++ // Sign extends to 64 bits.
++ if ( BitsLong.isSet(val, LEN - 1) )
++ val = BitsLong.set(v, LEN, LBITS);
++ return val;
++ }
++
++ // Same - renamed.
++
++ public static long pack56(long v) {
++ if ( v >= MIN && v <= MAX ) {
++ v = BitsLong.clear(v, LEN, LBITS);
++ return v;
++ } else
++ return -1;
++ }
++
++ public static long unpack56(long v) {
++ long val = BitsLong.clear(v, LEN, LBITS);
++ // Sign extends to 64 bits.
++ if ( BitsLong.isSet(val, LEN - 1) )
++ val = BitsLong.set(v, LEN, LBITS);
++ return val;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/ConnectionTracker.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/ConnectionTracker.java
index 0000000,0000000..f2950eb
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/ConnectionTracker.java
@@@ -1,0 -1,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/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/CopyDSG.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/CopyDSG.java
index 0000000,0000000..4e53ea3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/CopyDSG.java
@@@ -1,0 -1,0 +1,53 @@@
++/*
++ * 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.util.Iterator;
++import java.util.List;
++
++import org.apache.jena.atlas.iterator.Iter;
++import org.apache.jena.graph.Graph;
++import org.apache.jena.graph.Node;
++import org.apache.jena.sparql.core.DatasetGraph;
++import org.apache.jena.sparql.core.Quad;
++import org.seaborne.dboe.jenax.Txn;
++
++/** Copy operations of any {@link DatasetGraph} */
++public class CopyDSG {
++
++ public static void copy(DatasetGraph dsgSrc, DatasetGraph dsgDst) {
++ Txn.executeRead(dsgSrc, ()->{
++ Txn.executeWrite(dsgDst, () -> {
++ Iterator<Quad> iter = dsgSrc.find();
++ iter.forEachRemaining(dsgDst::add);
++ copyPrefixes(dsgSrc, dsgDst);
++ });
++ });
++ }
++
++ public static void copyPrefixes(DatasetGraph dsgSrc, DatasetGraph dsgDst) {
++ List<Node> graphNames = Iter.toList(dsgSrc.listGraphNodes());
++ copyPrefixes(dsgSrc.getDefaultGraph(), dsgDst.getDefaultGraph());
++ graphNames.forEach((gn)->copyPrefixes(dsgSrc.getGraph(gn), dsgDst.getGraph(gn)));
++ }
++
++ public static void copyPrefixes(Graph srcGraph, Graph dstGraph) {
++ dstGraph.getPrefixMapping().setNsPrefixes(srcGraph.getPrefixMapping());
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseConnection.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseConnection.java
index 0000000,0000000..e9e6c27
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseConnection.java
@@@ -1,0 -1,0 +1,180 @@@
++/*
++ * 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.HashSet ;
++import java.util.Map ;
++import java.util.Set ;
++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.setup.StoreParams ;
++import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
++
++// 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.
++ DatabaseConnection dbConn = cache.computeIfAbsent(location, (loc)->buildForCache(loc, params));
++ return dbConn ;
++ }
++
++ private static DatabaseConnection buildForCache(Location location, StoreParams params) {
++ if ( location.isMemUnique() ) {
++ throw new TDBException("Can't buildForCache a memory-unique location");
++ }
++ ProcessFileLock lock = null;
++ if (SystemTDB.DiskLocationMultiJvmUsagePrevention && ! location.isMem() ) {
++ lock = lockForLocation(location);
++ // Take the lock. This is atomic.
++ lock.lockEx();
++ }
++ 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);
++ }
++
++ /** Use via {@link TDBInternal#expel} wherever possible.
++ * <p>
++ * Stop managing a location. Use with great care (testing only).<br/>
++ * Does not expel from {@link StoreConnection}.
++ */
++ public static synchronized void internalExpel(Location location, boolean force) {
++ // ** Check it is a container location
++ DatabaseConnection dbConn = cache.get(location) ;
++ if ( dbConn == null )
++ return ;
++ dbConn.isValid = false;
++ //dbConn.datasetGraph = null;
++ //dbConn.datasetGraphSwitchable = null;
++ 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);
++ }
++ }
++
++ /**
++ * Stop managing all locations.
++ * Use with extreme care.
++ * This is intended to support internal testing.
++ */
++ public static synchronized void internalReset() {
++ // Copy to avoid potential CME.
++ Set<Location> x = new HashSet<>(cache.keySet()) ;
++ for (Location loc : x)
++ internalExpel(loc, true) ;
++ if ( ! cache.isEmpty() )
++ System.err.println("DatabaseConnection: Cache not empty!");
++ cache.clear() ;
++ }
++
++ // 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 ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
index 0000000,0000000..bb34ed3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
@@@ -1,0 -1,0 +1,264 @@@
++/*
++ * 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.BufferedOutputStream ;
++import java.io.IOException ;
++import java.io.OutputStream ;
++import java.nio.file.* ;
++import java.util.List;
++import java.util.zip.GZIPOutputStream ;
++
++import org.apache.jena.atlas.RuntimeIOException ;
++import org.apache.jena.atlas.lib.DateTimeUtils ;
++import org.apache.jena.atlas.lib.Pair ;
++import org.apache.jena.atlas.logging.Log;
++import org.apache.jena.riot.Lang ;
++import org.apache.jena.riot.RDFDataMgr ;
++import org.apache.jena.sparql.core.DatasetGraph;
++import org.seaborne.dboe.base.file.Location;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.dboe.transaction.txn.TransactionCoordinator;
++import org.seaborne.dboe.transaction.txn.TransactionalSystem;
++import org.seaborne.tdb2.TDBException;
++import org.seaborne.tdb2.setup.StoreParams;
++import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
++import org.seaborne.tdb2.store.DatasetGraphTDB;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/** Operations on and about TDB2 databases.
++ * <p>
++ * TDB2 uses a hierarchical structure to manage on disk.
++ * <p>
++ * If in-memory (non-scalable, not-performant, perfect simulation for functionality using a RAM disk, for testing mainly),
++ * then the switchable layer is just a covenience. DatasetGrapOps such as {@link #compact}
++ * and {@link #backup} do not apply.
++ * <p>
++ * Directory and files on disk:
++ * <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 Backups/} -- backups.
++ * <li> External indexes like {@code TextIndex/} -- the text index only applies to the current, latest database.
++ * </ul>
++ */
++public class DatabaseOps {
++ private static Logger LOG = LoggerFactory.getLogger(DatabaseOps.class);
++ private static final String dbPrefix = "Data";
++ private static final String SEP = "-";
++ private static final String startCount = "0001";
++
++ private static final String BACKUPS_DIR = "Backups";
++ // Basename of the backup file. "backup_{DateTime}.nq.gz
++ private static final String BACKUPS_FN = "backup";
++
++ /** Create a fresh database - called by {@code DatabaseMgr}.
++ * It is important to go via {@code DatabaseConnection} to avoid
++ * duplicate {@code DatasetGraphSwitchable}s for the same location.
++ */
++ /*package*/ static DatasetGraph create(Location location) {
++ // Hide implementation class.
++ return createSwitchable(location);
++ }
++
++ private static DatasetGraphSwitchable createSwitchable(Location location) {
++ if ( location.isMem() ) {
++ DatasetGraph dsg = StoreConnection.connectCreate(location).getDatasetGraph();
++ return new DatasetGraphSwitchable(null, location, dsg);
++ }
++ // 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();
++ DatasetGraphSwitchable appDSG = new DatasetGraphSwitchable(path, location, dsg);
++ return appDSG;
++ }
++
++ public static String backup(DatasetGraphSwitchable container) {
++ checkSupportsAdmin(container);
++ Path dbPath = container.getContainerPath();
++ Path backupDir = dbPath.resolve(BACKUPS_DIR);
++ if ( ! Files.exists(backupDir) )
++ IOX.createDirectory(backupDir);
++
++ DatasetGraph dsg = container;
++
++// // Per backup source lock.
++// synchronized(activeBackups) {
++// // Atomically check-and-set
++// if ( activeBackups.contains(dsg) )
++// Log.warn(Fuseki.serverLog, "Backup already in progress") ;
++// activeBackups.add(dsg) ;
++// }
++
++ Pair<OutputStream, Path> x = openUniqueFileForWriting(backupDir, BACKUPS_FN, "nq.gz");
++ try (OutputStream out2 = x.getLeft();
++ OutputStream out1 = new GZIPOutputStream(out2, 8 * 1024) ;
++ OutputStream out = new BufferedOutputStream(out1)) {
++ Txn.executeRead(dsg, ()->RDFDataMgr.write(out, dsg, Lang.NQUADS));
++ } catch (IOException e) {
++ throw IOX.exception(e) ;
++ }
++ return x.getRight().toString();
++ }
++
++ private static void checkSupportsAdmin(DatasetGraphSwitchable container) {
++ if ( ! container.hasContainerPath() )
++ throw new TDBException("Dataset does not support admin operations");
++ }
++
++ //private static void logWarn(String msg) {}
++
++
++ // --> IOX
++ private static Pair<OutputStream, Path> openUniqueFileForWriting(Path dirPath, String basename, String ext) {
++ if ( ! Files.isDirectory(dirPath) )
++ throw new IllegalArgumentException("Not a directory: "+dirPath);
++ if ( basename.contains("/") || basename.contains("\\") )
++ throw new IllegalArgumentException("Basename must not contain a file path separator (\"/\" or \"\\\")");
++
++ String timestamp = DateTimeUtils.nowAsString("yyyy-MM-dd_HH:mm:ss") ;
++ String filename = basename + "_" + timestamp ;
++ Path p = dirPath.resolve(filename+"."+ext);
++ int x = 0 ;
++ for(;;) {
++ try {
++ OutputStream out = Files.newOutputStream(p, StandardOpenOption.CREATE_NEW);
++ return Pair.create(out, p);
++ } catch (AccessDeniedException ex) {
++ throw IOX.exception("Access denied", ex);
++ } catch (FileAlreadyExistsException ex) {
++ // Drop through and try again.
++ } catch (IOException ex) {
++ throw IOX.exception(ex) ;
++ }
++ // Try again.
++ x++;
++ if ( x >= 5 )
++ throw new RuntimeIOException("Can't create the unique name: number of attempts exceeded");
++ p = dirPath.resolve(filename+"_"+x+"."+ext);
++ }
++ }
++
++
++ // JVM-wide :-(
++ private static Object compactionLock = new Object();
++
++ public static void compact(DatasetGraphSwitchable container) {
++ checkSupportsAdmin(container);
++ synchronized(compactionLock) {
++ Path base = container.getContainerPath();
++ Path db1 = findLocation(base, dbPrefix);
++ Location loc1 = IOX.asLocation(db1);
++
++ // -- Checks
++ Location loc1a = ((DatasetGraphTDB)container.get()).getLocation();
++ if ( loc1a.isMem() ) {}
++ if ( ! loc1a.exists() )
++ throw new TDBException("No such location: "+loc1a);
++
++ // Is this the same database location?
++ if ( ! loc1.equals(loc1a) )
++ throw new TDBException("Inconsistent (not latested?) : "+loc1a+" : "+loc1);
++ // -- Checks
++
++ // 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);
++ LOG.debug(String.format("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 dsgCurrent = (DatasetGraphTDB)container.get();
++ if ( ! dsgCurrent.getLocation().equals(loc1) )
++ throw new TDBException("Inconsistent locations for base : "+dsgCurrent.getLocation()+" , "+dsgCurrent.getLocation());
++
++ DatasetGraphTDB dsgBase = srcConn.getDatasetGraphTDB();
++ if ( dsgBase != dsgCurrent )
++ throw new TDBException("Inconsistent datasets : "+dsgCurrent.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.tryBlockWriters();
++ // txnMgr.begin(WRITE, false) will now bounce.
++
++ // 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.
++ if ( ! container.change(dsgCurrent, dsgCompact) ) {
++ Log.warn(DatabaseOps.class, "Inconistent: old datasetgraph not as expected");
++ 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/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/EnvTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/EnvTDB.java
index 0000000,0000000..449853e
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/EnvTDB.java
@@@ -1,0 -1,0 +1,61 @@@
++/*
++ * 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.sys;
++
++import java.util.Properties ;
++import java.util.Set ;
++
++import org.apache.jena.sparql.util.Context ;
++import org.apache.jena.sparql.util.Symbol ;
++import org.seaborne.tdb2.TDB2 ;
++
++public class EnvTDB
++{
++ public static void processGlobalSystemProperties()
++ {
++ Context context = processProperties(System.getProperties()) ;
++ TDB2.getContext().putAll(context) ;
++ }
++
++ static final String prefix = SystemTDB.tdbSymbolPrefix+":" ;
++ public static Context processProperties(Properties properties)
++ {
++ Context context = new Context() ;
++ Set<Object> keys = properties.keySet() ;
++ for ( Object key : keys )
++ {
++ if ( key instanceof String )
++ {
++ String keyStr = (String)key ;
++ if ( keyStr.startsWith(prefix) )
++ keyStr = SystemTDB.symbolNamespace+keyStr.substring(prefix.length()) ;
++
++
++ if ( ! keyStr.startsWith(SystemTDB.symbolNamespace) )
++ continue ;
++
++ Object value = properties.get(key) ;
++
++ Symbol symbol = Symbol.create(keyStr) ;
++
++ context.set(symbol, value) ;
++ }
++ }
++ return context ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/FilenameUtils.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/FilenameUtils.java
index 0000000,0000000..623ac99
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/FilenameUtils.java
@@@ -1,0 -1,0 +1,102 @@@
++/*
++ * 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.DirectoryStream;
++import java.nio.file.Files;
++import java.nio.file.Path;
++import java.util.ArrayList;
++import java.util.Comparator;
++import java.util.List;
++import java.util.regex.Pattern;
++
++import org.apache.jena.atlas.logging.FmtLog;
++import org.seaborne.dboe.DBOpEnvException;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++
++public class FilenameUtils {
++
++ static Logger LOG = LoggerFactory.getLogger(FilenameUtils.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 + nameSep + "*")) {
++ 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;
++ }
++
++ /**
++ * Extract the inde from a version-ed filename. (Base-NNNN format).
++ * @param name
++ * @param namebase
++ * @param nameSep
++ */
++ 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;
++ }
++
++ /** Construct a filename */
++ public static String filename(String prefix, String sep, int N) {
++ return String.format("%s%s%04d", prefix, sep, N);
++ }
++
++ /** Construct a filename */
++ public static String filename(String prefix, String sep, String index) {
++ return String.format("%s%s%s", prefix, sep, index);
++ }
++
++
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/IOX.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/IOX.java
index 0000000,0000000..ed78f88
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/IOX.java
@@@ -1,0 -1,0 +1,292 @@@
++/*
++ * 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.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);
++ }
++
++ /** Convert an {@link IOException} into a {@link RuntimeIOException}.
++ * <p>
++ * Idiom:
++ * <pre>
++ * catch(IOException ex) { throw new exception("Oh dear", ex); }
++ * </pre>
++ * @param message
++ * @param ioException
++ * @return RuntimeIOException
++ */
++ public static RuntimeIOException exception(String message, IOException ioException) {
++ return new RuntimeIOException(message, 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/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/InitTDB2.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/InitTDB2.java
index 0000000,0000000..5d82fe3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/InitTDB2.java
@@@ -1,0 -1,0 +1,40 @@@
++/*
++ * 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.sys;
++
++import org.apache.jena.system.JenaSubsystemLifecycle ;
++import org.seaborne.tdb2.TDB2 ;
++
++public class InitTDB2 implements JenaSubsystemLifecycle {
++
++ @Override
++ public void start() {
++ TDB2.init() ;
++ }
++
++ @Override
++ public void stop() {
++ // This is savage and does not take account of in-flight transactions.
++ TDB2.closedown() ;
++ }
++
++ @Override
++ public int level() {
++ return 42 ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/LockMRSWLite.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/LockMRSWLite.java
index 0000000,0000000..cf381ef
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/LockMRSWLite.java
@@@ -1,0 -1,0 +1,69 @@@
++/*
++ * 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.sys;
++
++import java.util.concurrent.locks.ReadWriteLock ;
++import java.util.concurrent.locks.ReentrantReadWriteLock ;
++
++import org.apache.jena.shared.JenaException ;
++import org.apache.jena.shared.Lock ;
++
++/** Light weight (?) MRSW lock implementation that assumes
++ * correct use of enterCriticalSection/leaveCriticalSection.
++ * That is, there is no real checking.
++ */
++public class LockMRSWLite implements Lock
++{
++ public LockMRSWLite() {}
++
++ private ReadWriteLock mrswLock = new ReentrantReadWriteLock() ;
++ // >0 for read lock, -1 for write lock.
++ private int count = 0 ;
++
++ @Override
++ public synchronized void enterCriticalSection(boolean readLockRequested)
++ {
++ // Once we have the lock, we can record the lock state
++ // because we know whether the actiev thread (us) is a read or write
++ // operation, then a valid leaveCriticalSection can only be read or
++ // write.
++ if ( readLockRequested ) {
++ mrswLock.readLock().lock() ;
++ count++ ;
++ } else {
++ mrswLock.writeLock().lock() ;
++ count = -1 ;
++ }
++ }
++
++ @Override
++ public synchronized void leaveCriticalSection()
++ {
++ if ( count == 0 )
++ throw new JenaException("Bad lock release - don't appear to be in a critical section") ;
++
++ if ( count < 0 ) {
++ mrswLock.writeLock().unlock() ;
++ count = 0 ;
++ return ;
++ } else {
++ mrswLock.readLock().unlock() ;
++ count-- ;
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java
index 0000000,0000000..21d5377
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java
@@@ -1,0 -1,0 +1,194 @@@
++/*
++ * 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.sys ;
++
++import java.io.IOException;
++import java.nio.file.Path;
++import java.nio.file.Paths;
++import java.util.HashSet ;
++import java.util.Map ;
++import java.util.Set ;
++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.ChannelManager ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.base.file.ProcessFileLock;
++import org.seaborne.dboe.sys.Names;
++import org.seaborne.dboe.transaction.txn.TransactionCoordinator ;
++import org.seaborne.dboe.transaction.txn.TransactionException ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.setup.TDBBuilder ;
++import org.seaborne.tdb2.store.DatasetGraphTDB ;
++
++/** A StoreConnection is the reference to the underlying storage.
++ * There is JVM-wide cache of backing datasets.
++ */
++public class StoreConnection
++{
++ private static Map<Location, StoreConnection> cache = new ConcurrentHashMap<>() ;
++
++ /** Get the {@code StoreConnection} to a location,
++ * creating the storage structures if it does not exist. */
++ public synchronized static StoreConnection connectCreate(Location location) {
++ return connectCreate(location, null) ;
++ }
++
++ /** Get the {@code StoreConnection} 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 StoreConnection connectCreate(Location location, StoreParams params) {
++ return make(location, params) ;
++ }
++
++ /** Get the {@code StoreConnection} for a location, but do not create it.
++ * Returns null for "not setup".
++ */
++ public synchronized static StoreConnection connectExisting(Location location) {
++ StoreConnection sConn = cache.get(location) ;
++ return sConn ;
++ }
++
++ public synchronized static boolean isSetup(Location location) {
++ return cache.containsKey(location) ;
++ }
++
++ /**
++ * Return a {@code StoreConnection} for a particular location,
++ * creating it if it does not exist in storage.
++ */
++ private synchronized static StoreConnection make(Location location, StoreParams params) {
++ StoreConnection sConn = cache.get(location) ;
++ if ( sConn == null ) {
++ ProcessFileLock lock = null;
++ if (SystemTDB.DiskLocationMultiJvmUsagePrevention && ! location.isMem() ) {
++ lock = lockForLocation(location);
++ // Take the lock. This is atomic.
++ lock.lockEx();
++ }
++
++ // Recovery happens when TransactionCoordinator.start is called
++ // during the building of the DatasetGraphTxn.
++
++ DatasetGraphTDB dsg = (DatasetGraphTDB)TDBBuilder.build(location, params) ;
++
++ sConn = new StoreConnection(dsg, lock) ;
++ if (!location.isMemUnique())
++ cache.put(location, sConn) ;
++ }
++ return sConn ;
++ }
++
++ /**
++ * Stop managing all locations.
++ * Use with extreme care.
++ * This is intended to support internal testing.
++ */
++ public static synchronized void internalReset() {
++ // Copy to avoid potential CME.
++ Set<Location> x = new HashSet<>(cache.keySet()) ;
++ for (Location loc : x)
++ internalExpel(loc, true) ;
++ cache.clear() ;
++ ChannelManager.reset();
++ }
++
++ /** Stop managing a location. There should be no transactions running. */
++ public static synchronized void release(Location location) {
++ internalExpel(location, false) ;
++ }
++
++ /** Use via {@link TDBInternal#expel} wherever possible.
++ * <p>
++ * Stop managing a location.<br/>
++ * Use with great care (testing only).
++ */
++ public static synchronized void internalExpel(Location location, boolean force) {
++ StoreConnection sConn = cache.get(location) ;
++ if (sConn == null) return ;
++
++ TransactionCoordinator txnCoord = sConn.getDatasetGraphTDB().getTxnSystem().getTxnMgr();
++ if (!force && txnCoord.countActive() > 0 )
++ throw new TransactionException("Can't expel: Active transactions for location: " + location) ;
++
++ // No transactions at this point
++ // (or we don't care and are clearing up forcefully.)
++
++ sConn.getDatasetGraphTDB().shutdown() ;
++ // Done by DatasetGraphTDB()
++ //txnCoord.shutdown();
++
++ sConn.isValid = false ;
++ cache.remove(location) ;
++
++ // Release the lock after the cache is emptied.
++ if (SystemTDB.DiskLocationMultiJvmUsagePrevention && ! location.isMem() ) {
++ if ( ! sConn.lock.isLockedHere() )
++ SystemTDB.errlog.warn("Location " + location.getDirectoryPath() + " was not locked by this process.");
++ sConn.lock.unlock();
++ ProcessFileLock.release(sConn.lock);
++ }
++ }
++
++ /** 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);
++ }
++
++ private final DatasetGraphTDB datasetGraph ;
++ // This is the location of the database itself, not the TDB2 container directory.
++ private final Location location ;
++ private final ProcessFileLock lock ;
++ private boolean isValid = true ;
++ private volatile boolean haveUsedInTransaction = false ;
++
++ private StoreConnection(DatasetGraphTDB dsg, ProcessFileLock fileLock)
++ {
++ this.datasetGraph = dsg ;
++ this.location = dsg.getLocation() ;
++ this.lock = fileLock;
++ }
++
++ public DatasetGraph getDatasetGraph() {
++ return datasetGraph;
++ }
++
++ public DatasetGraphTDB getDatasetGraphTDB() {
++ return datasetGraph;
++ }
++
++ public Location getLocation() {
++ return location ;
++ }
++
++ public ProcessFileLock getLock() {
++ return lock ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/SystemTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/SystemTDB.java
index 0000000,0000000..51ef995
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/SystemTDB.java
@@@ -1,0 -1,0 +1,416 @@@
++/*
++ * 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.sys;
++
++import java.io.FileNotFoundException ;
++import java.io.IOException ;
++import java.util.Properties ;
++
++import org.apache.jena.atlas.io.IO ;
++import org.apache.jena.atlas.lib.PropertyUtils ;
++import org.apache.jena.atlas.logging.Log ;
++import org.apache.jena.query.ARQ ;
++import org.apache.jena.sparql.engine.optimizer.reorder.ReorderLib ;
++import org.apache.jena.sparql.engine.optimizer.reorder.ReorderTransformation ;
++import org.apache.jena.sparql.util.Symbol ;
++import org.apache.jena.system.JenaSystem ;
++import org.seaborne.dboe.base.block.FileMode ;
++import org.seaborne.dboe.base.file.ProcessFileLock;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.sys.Sys;
++import org.seaborne.tdb2.TDB2 ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++public class SystemTDB
++{
++ static { JenaSystem.init(); }
++
++ // NB Same logger as the TDB class because this class is the system info but kept out of TDB javadoc.
++ // It's visibility is TDB, not really public.
++ private static final Logger log = LoggerFactory.getLogger(TDB2.class) ;
++
++ /** TDB System log - use for general messages (a few) and warnings.
++ * Generally, do not log events unless you want every user to see them every time.
++ * TDB is an embedded database - libraries and embedded systems should be seen and not heard.
++ * @see #errlog
++ */
++ // This was added quite late in TDB so need to check it's used appropriately - check for Log.*
++ public static final Logger syslog = LoggerFactory.getLogger("TDB") ;
++ /** Send warnings and error */
++ public static final Logger errlog = LoggerFactory.getLogger("TDB") ;
++
++ // ---- Constants that can't be changed without invalidating on-disk data.
++
++// /** Size, in bytes, of a Java long */
++// public static final int SizeOfLong = Long.SIZE/Byte.SIZE ;
++//
++// /** Size, in bytes, of a Java int */
++// public static final int SizeOfInt = Integer.SIZE/Byte.SIZE ;
++
++ /** Size, in bytes, of the persistent representation of a node id */
++ public static final int SizeOfNodeId = NodeId.SIZE ;
++
++ /** Size, in bytes, of a pointer between blocks */
++ public static final int SizeOfPointer = Sys.SizeOfInt ;
++
++ // ---- Node table related
++
++ /** Size, in bytes, of a triple index record. */
++ public static final int LenIndexTripleRecord = 3 * NodeId.SIZE ;
++ /** Size, in bytes, of a quad index record. */
++ public static final int LenIndexQuadRecord = 4 * NodeId.SIZE ;
++
++ /** Size, in bytes, of a Node hash.
++ * In TDB 0.7.X and before this was 8 bytes (64/8).
++ * In TDB 0.8.0 and above it is 16 bytes (128/8).
++ * These two systems are not compatible.
++ */
++ //public static final int LenNodeHash = SizeOfLong ; // TDB <= 0.7.X
++ public static final int LenNodeHash = 128/8 ; // TDB >= 0.8.0
++
++ // ---- Symbols and similar
++
++ // ---- Record factories
++ public final static RecordFactory indexRecordTripleFactory = new RecordFactory(LenIndexTripleRecord, 0) ;
++ public final static RecordFactory indexRecordQuadFactory = new RecordFactory(LenIndexQuadRecord, 0) ;
++ public final static RecordFactory nodeRecordFactory = new RecordFactory(LenNodeHash, SizeOfNodeId) ;
++
++ // Test show no visable effect.
++// /** Unit of flushing the data when loading - data phase. -1 means off, sync at end of load only. */
++// public final static long LoadFlushTickPrimary = -1 ; // 10*1000*1000 ;
++// /** Unit of flushing the data when loading - index phase -1 means off, sync at end of load only. */
++// public final static long LoadFlushTickSecondary = -1 ; // 10*1000*1000 ;
++
++ /** Root of TDB-defined parameter names */
++ public static final String symbolNamespace = "http://jena.hpl.hp.com/TDB#" ;
++
++ /** Root of TDB-defined parameter short names */
++ public static final String tdbSymbolPrefix = "tdb" ;
++
++ /** Root of any TDB-defined Java system properties */
++ public static final String tdbPropertyRoot = "org.apache.jena.tdb" ;
++
++ /** Log duplicates during loading */
++ public static final Symbol symLogDuplicates = allocSymbol("logDuplicates") ;
++
++ /** File mode : one of "direct", "mapped", "default" */
++ public static final Symbol symFileMode = allocSymbol("fileMode") ;
++
++ /** Index type */
++ public static final Symbol symIndexType = allocSymbol("indexType") ;
++
++ /** Experimental : triple and quad filtering at scan level */
++ public static final Symbol symTupleFilter = allocSymbol("tupleFilter") ;
++
++ private static final String propertyFileKey1 = tdbPropertyRoot+".settings" ;
++ private static final String propertyFileKey2 = tdbSymbolPrefix+":settings" ;
++
++ private static String propertyFileName = null ;
++ static {
++ propertyFileName = System.getProperty(propertyFileKey1) ;
++ if ( propertyFileName == null )
++ propertyFileName = System.getProperty(propertyFileKey2) ;
++ }
++
++ public static final boolean is64bitSystem = determineIf64Bit() ;
++
++ private static Properties properties = readPropertiesFile() ;
++
++ // To make the class initialize
++ static public void init() {}
++
++ /** Size, in bytes, of a block */
++ public static final int BlockSize = 8*1024 ; // intValue("BlockSize", 8*1024) ;
++
++ /** Size, in bytes, of a block for testing */
++ public static final int BlockSizeTest = 1024 ; // intValue("BlockSizeTest", 1024) ;
++
++ /** Size, in bytes, of a block for testing */
++ public static final int BlockSizeTestMem = 500 ;
++
++// /** Size, in bytes, of a memory block */
++// public static final int BlockSizeMem = 32*8 ; //intValue("BlockSizeMem", 32*8 ) ;
++
++ /** order of an in-memory BTree or B+Tree */
++ public static final int OrderMem = 5 ; // intValue("OrderMem", 5) ;
++
++ /** Size, in bytes, of a segment (used for memory mapped files) */
++ public static final int SegmentSize = 8*1024*1024 ; // intValue("SegmentSize", 8*1024*1024) ;
++
++ // ---- Cache sizes (within the JVM)
++
++ public static final int ObjectFileWriteCacheSize = 8*1024 ;
++
++ /** Size of Node to NodeId cache.
++ * Used to map from Node to NodeId spaces.
++ * Used for loading and for query preparation.
++ */
++ public static final int Node2NodeIdCacheSize = intValue("Node2NodeIdCacheSize", ( is64bitSystem ? 200*1000 : 20*1000 )) ;
++
++ /** Size of NodeId to Node cache.
++ * Used to map from NodeId to Node spaces.
++ * Used for retriveing results.
++ */
++ public static final int NodeId2NodeCacheSize = intValue("NodeId2NodeCacheSize", ( is64bitSystem ? 750*1000 : 20*1000 ) ) ;
++
++ /** Size of Node lookup miss cache. */
++ public static final int NodeMissCacheSize = 1000 ;
++
++ /** Size of the delayed-write block cache (32 bit systems only). Per file. */
++ public static final int BlockWriteCacheSize = intValue("BlockWriteCacheSize", 1000) ;
++
++ /** Size of read block cache (32 bit systems only). Per file. */
++ public static final int BlockReadCacheSize = intValue("BlockReadCacheSize", 5*1000) ;
++
++ // ---- Misc
++
++// /** Number of adds/deletes between calls to sync (-ve to disable) */
++// public static final int SyncTick = intValue("SyncTick", -1) ;
++
++ /** Default BGP optimizer */
++ public static ReorderTransformation defaultReorderTransform = ReorderLib.fixed() ;
++
++ /** Unsupported (for non-standard setups)
++ * @see #enableInlineLiterals
++ */
++ private static String propertyEnableInlineLiterals1 = "org.apache.jena.tdb.store.enableInlineLiterals" ;
++ /** Unsupported (for non-standard setups)
++ * @see #enableInlineLiterals
++ */
++ private static String propertyEnableInlineLiterals2 = "tdb:store.enableInlineLiterals" ;
++ /** <b>Unsupported</b> (for non-standard setups).
++ * This controls whether literal values are inlined into NodeIds.
++ * This is a major efficiency boost and is the default setting.
++ * It can be set false with {@code -Dtdb:store.enableInlineLiterals=false}.
++ * Do not mix databases created with this set to different values.
++ * Chaos and incorrect results will result.
++ * Use with care. No support.
++ * Default setting is {@code true}
++ */
++ public static final boolean enableInlineLiterals ;
++ static { // Set enableInlineLiterals from system properties.
++ Properties sysProperties = System.getProperties() ;
++ String key = null ;
++ if ( sysProperties.containsKey(propertyEnableInlineLiterals1) )
++ key = propertyFileKey1 ;
++ else if ( sysProperties.containsKey(propertyEnableInlineLiterals2) )
++ key = propertyFileKey2 ;
++ if ( key == null )
++ enableInlineLiterals = true ; // Normal value.
++ else
++ enableInlineLiterals = Boolean.valueOf(sysProperties.getProperty(key)) ;
++ }
++
++// public static void setNullOut(boolean nullOut)
++// { SystemTDB.NullOut = nullOut ; }
++//
++// /** Are we nulling out unused space in bytebuffers (records, points etc) */
++// public static boolean getNullOut()
++// { return SystemTDB.NullOut ; }
++
++ /** null out (with the FillByte) freed up space in buffers */
++ public static boolean NullOut = false ;
++
++ /** FillByte value for NullOut */
++ public static final byte FillByte = (byte)0xFF ;
++
++ public static boolean Checking = false ; // This isn't used enough!
++
++ /**
++ * When enabled, a {@link ProcessFileLock} is used to block over rpcoesses oening this database.
++ */
++ public static boolean DiskLocationMultiJvmUsagePrevention = true;
++
++ public static void panic(Class<?> clazz, String string)
++ {
++ Log.error(clazz, string) ;
++ throw new TDBException(string) ;
++ }
++
++ public static Symbol allocSymbol(String shortName)
++ {
++ if ( shortName.startsWith(SystemTDB.tdbSymbolPrefix))
++ throw new TDBException("Symbol short name begins with the TDB namespace prefix: "+shortName) ;
++ if ( shortName.startsWith("http:"))
++ throw new TDBException("Symbol short name begins with http: "+shortName) ;
++ return allocSymbol(SystemTDB.symbolNamespace, shortName) ;
++ }
++
++ private static Symbol allocSymbol(String namespace, String shortName)
++ {
++ return Symbol.create(namespace+shortName) ;
++ }
++
++ // ----
++
++ private static int intValue(String prefix, String name, int defaultValue)
++ {
++ if ( ! prefix.endsWith(".") )
++ name = prefix+"."+name ;
++ else
++ name = prefix+name ;
++ return intValue(name, defaultValue) ;
++ }
++
++ private static int intValue(String name, int defaultValue)
++ {
++ if ( name == null ) return defaultValue ;
++ if ( name.length() == 0 ) throw new TDBException("Empty string for value name") ;
++
++ if ( properties == null )
++ return defaultValue ;
++
++ String x = properties.getProperty(name) ;
++ if ( x == null )
++ return defaultValue ;
++ TDB2.logInfo.info("Set: "+name+" = "+x) ;
++ int v = Integer.parseInt(x) ;
++ return v ;
++ }
++
++ private static Properties readPropertiesFile()
++ {
++ if ( propertyFileName == null )
++ return null ;
++
++ Properties p = new Properties() ;
++ try
++ {
++ TDB2.logInfo.info("Using properties from '"+propertyFileName+"'") ;
++ PropertyUtils.loadFromFile(p, propertyFileName) ;
++ } catch (FileNotFoundException ex)
++ {
++ log.debug("No system properties file ("+propertyFileName+")") ;
++ return null ;
++ } catch (IOException ex) { IO.exception(ex) ; }
++ return p ;
++ }
++
++ // --------
++
++ public static final boolean isWindows = determineIfWindows() ; // Memory mapped files behave differently.
++
++ //Or look in File.listRoots.
++ //Alternative method:
++ // http://stackoverflow.com/questions/1293533/name-of-the-operating-system-in-java-not-os-name
++
++ private static boolean determineIfWindows() {
++ String s = System.getProperty("os.name") ;
++ if ( s == null )
++ return false ;
++ return s.startsWith("Windows ") ;
++ }
++
++ private static boolean determineIf64Bit()
++ {
++ String s = System.getProperty("sun.arch.data.model") ;
++ if ( s != null )
++ {
++ boolean b = s.equals("64") ;
++ TDB2.logInfo.debug("System architecture: "+(b?"64 bit":"32 bit")) ;
++ return b ;
++ }
++ // Not a SUN VM
++ s = System.getProperty("java.vm.info") ;
++ if ( s == null )
++ {
++ log.warn("Can't determine the data model") ;
++ return false ;
++ }
++ log.debug("Can't determine the data model from 'sun.arch.data.model' - using java.vm.info") ;
++ boolean b = s.contains("64") ;
++ TDB2.logInfo.debug("System architecture: (from java.vm.info) "+(b?"64 bit":"32 bit")) ;
++ return b ;
++ }
++
++ // ---- File mode
++
++ private static FileMode fileMode = null ;
++ public static FileMode fileMode()
++ {
++ if ( fileMode == null )
++ fileMode = determineFileMode() ;
++ return fileMode ;
++ }
++
++ public static void setFileMode(FileMode newFileMode)
++ {
++ if ( fileMode != null )
++ {
++ log.warn("System file mode already determined - setting it has no effect") ;
++ return ;
++ }
++ fileMode = newFileMode ;
++ }
++
++ // So the test suite can setup thing up ... very carefully.
++ /*package*/ static void internalSetFileMode(FileMode newFileMode)
++ {
++ fileMode = newFileMode ;
++ }
++
++ private static FileMode determineFileMode()
++ {
++ // Be careful that this is not called very, very early, before --set might be seen.
++ // Hence delayed access above in fileMode().
++
++ String x = ARQ.getContext().getAsString(SystemTDB.symFileMode, "default") ;
++
++ if ( x.equalsIgnoreCase("direct") )
++ {
++ TDB2.logInfo.info("File mode: direct (forced)") ;
++ return FileMode.direct ;
++ }
++ if ( x.equalsIgnoreCase("mapped") )
++ {
++ TDB2.logInfo.info("File mode: mapped (forced)") ;
++ return FileMode.mapped ;
++ }
++
++ if ( x.equalsIgnoreCase("default") )
++ {
++ if ( is64bitSystem )
++ {
++ TDB2.logInfo.debug("File mode: Mapped") ;
++ return FileMode.mapped ;
++ }
++ TDB2.logInfo.debug("File mode: Direct") ;
++ return FileMode.direct ;
++ }
++ throw new TDBException("Unrecognized file mode (not one of 'default', 'direct' or 'mapped': "+x) ;
++ }
++
++// public static Dataset setNonTransactional(Dataset dataset) {
++// if ( dataset.isInTransaction() )
++// return dataset ; // And hope it's a write transaction.
++// dataset.begin(ReadWrite.WRITE);
++// //Or wrap DatasetGraphTDB?
++// return dataset ;
++// }
++//
++// public static DatasetGraph setNonTransactional(DatasetGraph dataset) {
++// if ( dataset.isInTransaction() )
++// return dataset ;
++// dataset.begin(ReadWrite.WRITE);
++// return dataset ;
++// }
++
++}
[50/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
JENA-1396: Merge //github/afs/mantis as subdirectory jena-db/
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/d9da3592
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/d9da3592
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/d9da3592
Branch: refs/heads/jena-tdb2
Commit: d9da3592ff723d28b961de3c1591704ae0616cdd
Parents: 3fbbfcc 71a70fd
Author: Andy Seaborne <an...@apache.org>
Authored: Thu Sep 28 12:06:15 2017 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Thu Sep 28 12:06:15 2017 +0100
----------------------------------------------------------------------
jena-db/.gitignore | 46 +
jena-db/.travis.yml | 17 +
jena-db/LICENSE | 202 +++
jena-db/NOTICE | 10 +
jena-db/README.md | 64 +
jena-db/dboe-base/.gitignore | 4 +
jena-db/dboe-base/README.md | 1 +
jena-db/dboe-base/pom.xml | 64 +
.../org/seaborne/dboe/DBOpEnvException.java | 28 +
.../seaborne/dboe/base/StorageException.java | 26 +
.../org/seaborne/dboe/base/block/Block.java | 165 ++
.../dboe/base/block/BlockException.java | 28 +
.../org/seaborne/dboe/base/block/BlockMgr.java | 99 ++
.../seaborne/dboe/base/block/BlockMgrBase.java | 51 +
.../dboe/base/block/BlockMgrBuilder.java | 24 +
.../dboe/base/block/BlockMgrBuilderStd.java | 28 +
.../seaborne/dboe/base/block/BlockMgrCache.java | 325 ++++
.../dboe/base/block/BlockMgrFactory.java | 150 ++
.../dboe/base/block/BlockMgrFileAccess.java | 168 ++
.../dboe/base/block/BlockMgrFreeChain.java | 83 +
.../dboe/base/block/BlockMgrLogger.java | 180 +++
.../dboe/base/block/BlockMgrReadonly.java | 44 +
.../dboe/base/block/BlockMgrSwitcher.java | 39 +
.../seaborne/dboe/base/block/BlockMgrSync.java | 148 ++
.../dboe/base/block/BlockMgrTracker.java | 413 +++++
.../dboe/base/block/BlockMgrWrapper.java | 148 ++
.../seaborne/dboe/base/block/BlockParams.java | 26 +
.../org/seaborne/dboe/base/block/BlockType.java | 68 +
.../org/seaborne/dboe/base/block/FileMode.java | 26 +
.../seaborne/dboe/base/buffer/BufferBase.java | 262 +++
.../dboe/base/buffer/BufferException.java | 26 +
.../seaborne/dboe/base/buffer/PtrBuffer.java | 124 ++
.../seaborne/dboe/base/buffer/RecordBuffer.java | 235 +++
.../dboe/base/buffer/RecordBufferIterator.java | 97 ++
.../seaborne/dboe/base/file/AlreadyLocked.java | 29 +
.../seaborne/dboe/base/file/BinaryDataFile.java | 99 ++
.../dboe/base/file/BinaryDataFileMem.java | 114 ++
.../base/file/BinaryDataFileRandomAccess.java | 148 ++
.../dboe/base/file/BinaryDataFileSync.java | 82 +
.../dboe/base/file/BinaryDataFileWrapper.java | 67 +
.../base/file/BinaryDataFileWriteBuffered.java | 162 ++
.../seaborne/dboe/base/file/BlockAccess.java | 64 +
.../dboe/base/file/BlockAccessBase.java | 175 ++
.../dboe/base/file/BlockAccessByteArray.java | 129 ++
.../dboe/base/file/BlockAccessDirect.java | 130 ++
.../dboe/base/file/BlockAccessMapped.java | 267 ++++
.../seaborne/dboe/base/file/BlockAccessMem.java | 188 +++
.../seaborne/dboe/base/file/BufferChannel.java | 95 ++
.../dboe/base/file/BufferChannelFile.java | 171 ++
.../dboe/base/file/BufferChannelMem.java | 240 +++
.../seaborne/dboe/base/file/ChannelManager.java | 114 ++
.../seaborne/dboe/base/file/FileException.java | 28 +
.../seaborne/dboe/base/file/FileFactory.java | 48 +
.../org/seaborne/dboe/base/file/FileSet.java | 115 ++
.../org/seaborne/dboe/base/file/Location.java | 264 +++
.../org/seaborne/dboe/base/file/MetaFile.java | 364 +++++
.../dboe/base/file/ProcessFileLock.java | 215 +++
.../dboe/base/file/SegmentedMemBuffer.java | 279 ++++
.../seaborne/dboe/base/page/BlockConverter.java | 34 +
.../java/org/seaborne/dboe/base/page/Page.java | 44 +
.../org/seaborne/dboe/base/page/PageBase.java | 57 +
.../seaborne/dboe/base/page/PageBlockMgr.java | 212 +++
.../org/seaborne/dboe/base/record/Record.java | 188 +++
.../dboe/base/record/RecordException.java | 26 +
.../dboe/base/record/RecordFactory.java | 183 +++
.../seaborne/dboe/base/record/RecordMapper.java | 30 +
.../base/recordbuffer/RecordBufferPage.java | 100 ++
.../base/recordbuffer/RecordBufferPageBase.java | 105 ++
.../base/recordbuffer/RecordBufferPageMgr.java | 90 ++
.../base/recordbuffer/RecordRangeIterator.java | 161 ++
.../main/java/org/seaborne/dboe/jenax/Txn.java | 41 +
.../main/java/org/seaborne/dboe/migrate/L.java | 206 +++
.../java/org/seaborne/dboe/sys/FileLib.java | 85 +
.../main/java/org/seaborne/dboe/sys/Names.java | 150 ++
.../org/seaborne/dboe/sys/ProcessUtils.java | 156 ++
.../main/java/org/seaborne/dboe/sys/Sys.java | 96 ++
.../java/org/seaborne/dboe/sys/SystemFile.java | 23 +
.../java/org/seaborne/dboe/sys/SystemIndex.java | 149 ++
.../org/seaborne/dboe/test/BufferTestLib.java | 62 +
.../java/org/seaborne/dboe/test/RecordLib.java | 109 ++
.../java/org/seaborne/dboe/ConfigTestDBOE.java | 76 +
.../test/java/org/seaborne/dboe/TC_DBOE_IO.java | 60 +
.../dboe/base/block/AbstractTestBlockMgr.java | 133 ++
.../org/seaborne/dboe/base/block/TS_Block.java | 33 +
.../dboe/base/block/TestBlockMgrDirect.java | 48 +
.../dboe/base/block/TestBlockMgrMapped.java | 63 +
.../dboe/base/block/TestBlockMgrMem.java | 30 +
.../dboe/base/block/TestBlockMgrTracked.java | 141 ++
.../seaborne/dboe/base/buffer/TS_Buffer.java | 31 +
.../dboe/base/buffer/TestPtrBuffer.java | 315 ++++
.../dboe/base/buffer/TestRecordBuffer.java | 345 ++++
.../base/file/AbstractTestBinaryDataFile.java | 83 +
.../file/AbstractTestBlockAccessFixedSize.java | 101 ++
.../file/AbstractTestBlockAccessVarSize.java | 49 +
.../dboe/base/file/AbstractTestChannel.java | 144 ++
.../org/seaborne/dboe/base/file/TS_File.java | 48 +
.../TestBinaryDataFileWriteBufferedFile.java | 35 +
.../TestBinaryDataFileWriteBufferedMem.java | 31 +
.../dboe/base/file/TestBinaryDataMem.java | 31 +
.../dboe/base/file/TestBinaryDataRAF.java | 33 +
.../base/file/TestBinaryDataRAFInitial.java | 57 +
.../base/file/TestBlockAccessByteArray.java | 32 +
.../dboe/base/file/TestBlockAccessDirect.java | 44 +
.../dboe/base/file/TestBlockAccessMapped.java | 48 +
.../dboe/base/file/TestBlockAccessMem.java | 37 +
.../dboe/base/file/TestChannelFile.java | 38 +
.../seaborne/dboe/base/file/TestChannelMem.java | 34 +
.../seaborne/dboe/base/file/TestMetaFile.java | 74 +
.../dboe/base/file/TestProcessFileLock.java | 107 ++
.../dboe/base/file/TestSegmentedMemBuffer.java | 158 ++
.../seaborne/dboe/base/record/TS_Record.java | 34 +
.../seaborne/dboe/base/record/TestRecord.java | 77 +
.../dboe/base/recordfile/TS_RecordFile.java | 31 +
.../base/recordfile/TestRecordBufferPage.java | 124 ++
.../src/test/resources/log4j.properties | 6 +
jena-db/dboe-index-test/.gitignore | 1 +
jena-db/dboe-index-test/README.md | 1 +
jena-db/dboe-index-test/pom.xml | 54 +
.../java/org/seaborne/dboe/index/TS_Index.java | 29 +
.../org/seaborne/dboe/index/TestIndexMem.java | 34 +
.../dboe/index/test/AbstractTestIndex.java | 159 ++
.../dboe/index/test/AbstractTestRangeIndex.java | 434 +++++
.../seaborne/dboe/index/test/BaseSoakTest.java | 140 ++
.../seaborne/dboe/index/test/IndexMaker.java | 26 +
.../dboe/index/test/IndexTestGenerator.java | 44 +
.../seaborne/dboe/index/test/IndexTestLib.java | 218 +++
.../dboe/index/test/RangeIndexMaker.java | 27 +
.../src/test/resources/log4j.properties | 6 +
jena-db/dboe-index/pom.xml | 42 +
.../java/org/seaborne/dboe/index/Index.java | 91 ++
.../org/seaborne/dboe/index/IndexChange.java | 40 +
.../org/seaborne/dboe/index/IndexConst.java | 52 +
.../org/seaborne/dboe/index/IndexLogger.java | 64 +
.../java/org/seaborne/dboe/index/IndexMap.java | 171 ++
.../org/seaborne/dboe/index/IndexParams.java | 37 +
.../org/seaborne/dboe/index/IndexWrapper.java | 91 ++
.../org/seaborne/dboe/index/RangeIndex.java | 38 +
.../seaborne/dboe/index/RangeIndexLogger.java | 71 +
.../seaborne/dboe/index/RangeIndexWrapper.java | 105 ++
.../src/test/resources/log4j.properties | 6 +
jena-db/dboe-trans-data/pom.xml | 63 +
jena-db/dboe-trans-data/randtest | 57 +
.../dboe/trans/bplustree/AccessPath.java | 69 +
.../org/seaborne/dboe/trans/bplustree/BPT.java | 248 +++
.../dboe/trans/bplustree/BPTStateMgr.java | 89 ++
.../dboe/trans/bplustree/BPTreeException.java | 26 +
.../dboe/trans/bplustree/BPTreeNode.java | 1507 ++++++++++++++++++
.../dboe/trans/bplustree/BPTreeNodeMgr.java | 228 +++
.../dboe/trans/bplustree/BPTreePage.java | 135 ++
.../trans/bplustree/BPTreeRangeIterator.java | 152 ++
.../dboe/trans/bplustree/BPTreeRecords.java | 388 +++++
.../dboe/trans/bplustree/BPTreeRecordsMgr.java | 115 ++
.../dboe/trans/bplustree/BPlusTree.java | 544 +++++++
.../dboe/trans/bplustree/BPlusTreeFactory.java | 332 ++++
.../dboe/trans/bplustree/BPlusTreeParams.java | 235 +++
.../dboe/trans/bplustree/BPlusTreeTools.java | 148 ++
.../dboe/trans/bplustree/BlockTracker.java | 426 +++++
.../dboe/trans/bplustree/BptTxnState.java | 63 +
.../org/seaborne/dboe/trans/bplustree/Mode.java | 53 +
.../bplustree/rewriter/BPTreeNodeBuilder.java | 180 +++
.../bplustree/rewriter/BPlusTreeRewriter.java | 361 +++++
.../rewriter/BPlusTreeRewriterUtils.java | 104 ++
.../rewriter/RecordBufferPageLinker.java | 81 +
.../rewriter/RecordBufferPagePacker.java | 90 ++
.../dboe/trans/data/TransBinaryDataFile.java | 237 +++
.../org/seaborne/dboe/trans/data/TransBlob.java | 209 +++
.../org/seaborne/dboe/trans/TC_TransData.java | 33 +
.../dboe/trans/bplustree/BPlusTreeMaker.java | 55 +
.../dboe/trans/bplustree/TS_TxnBPTree.java | 41 +
.../dboe/trans/bplustree/TestBPTreeModes.java | 77 +
.../bplustree/TestBPTreeRecordsNonTxn.java | 326 ++++
.../bplustree/TestBPlusTreeIndexNonTxn.java | 60 +
.../trans/bplustree/TestBPlusTreeNonTxn.java | 90 ++
.../dboe/trans/bplustree/TestBPlusTreeTxn.java | 205 +++
.../rewriter/TestBPlusTreeRewriterNonTxn.java | 179 +++
.../trans/bplustree/soak/CmdTestBPlusTree.java | 104 ++
.../soak/CmdTestBPlusTreeRewriter.java | 67 +
.../seaborne/dboe/trans/data/TS_TransData.java | 34 +
.../trans/data/TestTransBinaryDataFile.java | 219 +++
.../data/TestTransBinaryDataFileGeneral.java | 58 +
.../seaborne/dboe/trans/data/TestTransBlob.java | 129 ++
.../trans/data/TestTransBlobPersistent.java | 116 ++
.../dboe/trans/data/TestTransIndexMem.java | 34 +
.../dboe/trans/recovery/TestRecovery.java | 126 ++
.../src/test/resources/log4j.properties | 6 +
jena-db/dboe-transaction/pom.xml | 41 +
.../dboe/transaction/ComponentIdRegistry.java | 92 ++
.../seaborne/dboe/transaction/ThreadTxn.java | 144 ++
.../seaborne/dboe/transaction/TransInteger.java | 242 +++
.../seaborne/dboe/transaction/TransLogger.java | 151 ++
.../seaborne/dboe/transaction/TransMonitor.java | 191 +++
.../dboe/transaction/Transactional.java | 98 ++
.../dboe/transaction/TransactionalFactory.java | 59 +
.../dboe/transaction/TransactionalMonitor.java | 38 +
.../dboe/transaction/txn/ComponentGroup.java | 77 +
.../dboe/transaction/txn/ComponentId.java | 123 ++
.../dboe/transaction/txn/ComponentIds.java | 61 +
.../dboe/transaction/txn/PrepareState.java | 40 +
.../dboe/transaction/txn/QuorumGenerator.java | 27 +
.../dboe/transaction/txn/StateMgrBase.java | 175 ++
.../dboe/transaction/txn/StateMgrData.java | 87 +
.../dboe/transaction/txn/StateMgrDataIdx.java | 44 +
.../seaborne/dboe/transaction/txn/SysTrans.java | 52 +
.../dboe/transaction/txn/SysTransState.java | 35 +
.../dboe/transaction/txn/Transaction.java | 294 ++++
.../transaction/txn/TransactionCoordinator.java | 804 ++++++++++
.../txn/TransactionCoordinatorState.java | 33 +
.../transaction/txn/TransactionException.java | 29 +
.../dboe/transaction/txn/TransactionInfo.java | 75 +
.../dboe/transaction/txn/TransactionalBase.java | 249 +++
.../transaction/txn/TransactionalComponent.java | 175 ++
.../txn/TransactionalComponentBase.java | 76 +
.../txn/TransactionalComponentLifecycle.java | 480 ++++++
.../txn/TransactionalComponentWrapper.java | 107 ++
.../dboe/transaction/txn/TransactionalMRSW.java | 136 ++
.../transaction/txn/TransactionalSystem.java | 82 +
.../seaborne/dboe/transaction/txn/TxnId.java | 63 +
.../dboe/transaction/txn/TxnIdFactory.java | 60 +
.../dboe/transaction/txn/TxnIdGenerator.java | 38 +
.../dboe/transaction/txn/TxnIdSimple.java | 83 +
.../dboe/transaction/txn/TxnIdUuid.java | 108 ++
.../seaborne/dboe/transaction/txn/TxnState.java | 21 +
.../dboe/transaction/txn/journal/Journal.java | 333 ++++
.../transaction/txn/journal/JournalControl.java | 296 ++++
.../transaction/txn/journal/JournalEntry.java | 89 ++
.../txn/journal/JournalEntryType.java | 57 +
.../dboe/transaction/txn/package-info.java | 12 +
.../dboe/transaction/AbstractTestTxn.java | 63 +
.../dboe/transaction/TS_Transactions.java | 43 +
.../seaborne/dboe/transaction/TestJournal.java | 149 ++
.../dboe/transaction/TestStateMgrData.java | 75 +
.../transaction/TestThreadingTransactions.java | 120 ++
.../transaction/TestTransactionCoordinator.java | 177 ++
.../TestTransactionCoordinatorControl.java | 141 ++
.../transaction/TestTransactionLifecycle.java | 261 +++
.../transaction/TestTransactionLifecycle2.java | 298 ++++
.../seaborne/dboe/transaction/TestTxnId.java | 52 +
.../seaborne/dboe/transaction/TestTxnLib.java | 197 +++
.../seaborne/dboe/transaction/TestTxnLib2.java | 65 +
.../dboe/transaction/TestTxnSwitching.java | 192 +++
.../dboe/transaction/TransactionalInteger.java | 59 +
.../src/test/resources/log4j.properties | 6 +
jena-db/fuseki-tdb2/pom.xml | 129 ++
.../org/seaborne/fuseki/cmd/FusekiTDB2Cmd.java | 33 +
jena-db/pom.xml | 421 +++++
jena-db/tdb2-cmds/.gitignore | 2 +
jena-db/tdb2-cmds/pom.xml | 122 ++
jena-db/tdb2-cmds/src/main/java/tdb2/Intro.java | 31 +
.../src/main/java/tdb2/cmdline/CmdSub.java | 71 +
.../src/main/java/tdb2/cmdline/CmdTDB.java | 84 +
.../src/main/java/tdb2/cmdline/CmdTDBGraph.java | 81 +
.../src/main/java/tdb2/cmdline/ModLocation.java | 55 +
.../src/main/java/tdb2/cmdline/ModModel.java | 66 +
.../main/java/tdb2/cmdline/ModTDBAssembler.java | 89 ++
.../main/java/tdb2/cmdline/ModTDBDataset.java | 138 ++
.../tdb2-cmds/src/main/java/tdb2/tdbbackup.java | 55 +
.../src/main/java/tdb2/tdbcompact.java | 48 +
.../tdb2-cmds/src/main/java/tdb2/tdbdump.java | 66 +
.../tdb2-cmds/src/main/java/tdb2/tdbloader.java | 175 ++
.../tdb2-cmds/src/main/java/tdb2/tdbquery.java | 51 +
.../tdb2-cmds/src/main/java/tdb2/tdbstats.java | 99 ++
.../tdb2-cmds/src/main/java/tdb2/tdbupdate.java | 56 +
.../src/main/resources/META-INF/LICENSE | 175 ++
.../src/main/resources/META-INF/NOTICE | 10 +
...rg.apache.jena.system.JenaSubsystemLifecycle | 1 +
.../org/apache/jena/tdb/tdb-properties.xml | 8 +
jena-db/tdb2-cmds/tdb2 | 99 ++
.../testing/Assembler/tdb-dataset-embed.ttl | 23 +
.../tdb2-cmds/testing/Assembler/tdb-dataset.ttl | 23 +
.../testing/Assembler/tdb-graph-embed.ttl | 27 +
.../testing/Assembler/tdb-graph-ref-dataset.ttl | 31 +
.../tdb2-cmds/testing/Assembler/tdb-graph.ttl | 27 +
.../testing/Assembler/tdb-named-graph-1.ttl | 29 +
.../testing/Assembler/tdb-named-graph-2.ttl | 28 +
jena-db/tdb2-cmds/testing/Basic/basic-00.rq | 4 +
jena-db/tdb2-cmds/testing/Basic/basic-1-O.rq | 4 +
jena-db/tdb2-cmds/testing/Basic/basic-1-P.rq | 4 +
jena-db/tdb2-cmds/testing/Basic/basic-1-PO.rq | 4 +
jena-db/tdb2-cmds/testing/Basic/basic-1-S.rq | 4 +
jena-db/tdb2-cmds/testing/Basic/basic-1-SO.rq | 4 +
jena-db/tdb2-cmds/testing/Basic/basic-1-SP.rq | 4 +
jena-db/tdb2-cmds/testing/Basic/basic-1-SPO.rq | 4 +
jena-db/tdb2-cmds/testing/Basic/basic-2-SO.rq | 4 +
jena-db/tdb2-cmds/testing/Basic/basic-3-O.rq | 4 +
jena-db/tdb2-cmds/testing/Basic/basic-3-P.rq | 4 +
jena-db/tdb2-cmds/testing/Basic/basic-3-PO.rq | 4 +
jena-db/tdb2-cmds/testing/Basic/basic-3-S.rq | 4 +
jena-db/tdb2-cmds/testing/Basic/basic-3-SO.rq | 4 +
jena-db/tdb2-cmds/testing/Basic/basic-3-SP.rq | 4 +
jena-db/tdb2-cmds/testing/Basic/data-1.ttl | 17 +
jena-db/tdb2-cmds/testing/Basic/manifest.ttl | 101 ++
jena-db/tdb2-cmds/testing/Data/solver-data.ttl | 7 +
jena-db/tdb2-cmds/testing/Loader/data-1.nq | 1 +
jena-db/tdb2-cmds/testing/Loader/data-2.nt | 1 +
jena-db/tdb2-cmds/testing/Loader/data-3.trig | 3 +
jena-db/tdb2-cmds/testing/Loader/data-4.ttl | 4 +
jena-db/tdb2-cmds/testing/Pattern/data-1.ttl | 17 +
jena-db/tdb2-cmds/testing/Pattern/manifest.ttl | 35 +
jena-db/tdb2-cmds/testing/Pattern/pattern-1.rq | 7 +
jena-db/tdb2-cmds/testing/Pattern/pattern-2.rq | 8 +
jena-db/tdb2-cmds/testing/Quads/data-1.ttl | 5 +
jena-db/tdb2-cmds/testing/Quads/data-2.ttl | 5 +
jena-db/tdb2-cmds/testing/Quads/data-dft.ttl | 10 +
jena-db/tdb2-cmds/testing/Quads/manifest.ttl | 51 +
jena-db/tdb2-cmds/testing/Quads/quad-01.rq | 9 +
jena-db/tdb2-cmds/testing/Quads/quad-02.rq | 8 +
jena-db/tdb2-cmds/testing/UnionGraph/data-1.ttl | 7 +
jena-db/tdb2-cmds/testing/UnionGraph/data-2.ttl | 5 +
.../tdb2-cmds/testing/UnionGraph/data-dft.ttl | 5 +
.../tdb2-cmds/testing/UnionGraph/manifest.ttl | 107 ++
.../testing/UnionGraph/merge-1-results.srx | 57 +
jena-db/tdb2-cmds/testing/UnionGraph/merge-1.rq | 8 +
.../testing/UnionGraph/merge-2-results.srx | 66 +
jena-db/tdb2-cmds/testing/UnionGraph/merge-2.rq | 8 +
.../testing/UnionGraph/merge-3-results.srx | 31 +
jena-db/tdb2-cmds/testing/UnionGraph/merge-3.rq | 8 +
.../testing/UnionGraph/merge-4-results.srx | 99 ++
jena-db/tdb2-cmds/testing/UnionGraph/merge-4.rq | 8 +
.../testing/UnionGraph/merge-5-results.srx | 33 +
jena-db/tdb2-cmds/testing/UnionGraph/merge-5.rq | 8 +
.../testing/UnionGraph/merge-6-results.srx | 43 +
jena-db/tdb2-cmds/testing/UnionGraph/merge-6.rq | 7 +
.../testing/UnionGraph/merge-A-results.srx | 99 ++
jena-db/tdb2-cmds/testing/UnionGraph/merge-A.rq | 8 +
.../testing/UnionGraph/merge-B-results.srx | 49 +
jena-db/tdb2-cmds/testing/UnionGraph/merge-B.rq | 8 +
jena-db/tdb2-cmds/testing/Update/create-1.ru | 1 +
jena-db/tdb2-cmds/testing/Update/drop-1.ru | 1 +
jena-db/tdb2-cmds/testing/Update/update-1.ru | 3 +
jena-db/tdb2-cmds/testing/Update/update-2.ru | 5 +
jena-db/tdb2-cmds/testing/Update/update-3.ru | 7 +
jena-db/tdb2-cmds/testing/Values/data-1.ttl | 23 +
jena-db/tdb2-cmds/testing/Values/manifest.ttl | 76 +
jena-db/tdb2-cmds/testing/Values/value-00.rq | 1 +
jena-db/tdb2-cmds/testing/Values/value-01.rq | 1 +
jena-db/tdb2-cmds/testing/Values/value-02.rq | 1 +
jena-db/tdb2-cmds/testing/Values/value-03.rq | 1 +
jena-db/tdb2-cmds/testing/Values/value-04.rq | 1 +
jena-db/tdb2-cmds/testing/Values/value-05.rq | 5 +
jena-db/tdb2-cmds/testing/Values/value-06.rq | 6 +
jena-db/tdb2-cmds/testing/Values/value-07.rq | 6 +
jena-db/tdb2-cmds/testing/Values/value-08.rq | 6 +
jena-db/tdb2-cmds/testing/Values/value-09.rq | 7 +
jena-db/tdb2-cmds/testing/manifest.ttl | 31 +
jena-db/tdb2/.gitignore | 2 +
jena-db/tdb2/pom.xml | 108 ++
.../java/org/seaborne/tdb2/DatabaseMgr.java | 114 ++
.../src/main/java/org/seaborne/tdb2/TDB2.java | 268 ++++
.../java/org/seaborne/tdb2/TDB2Factory.java | 124 ++
.../java/org/seaborne/tdb2/TDBException.java | 28 +
.../tdb2/assembler/DatasetAssemblerTDB.java | 79 +
.../tdb2/assembler/TDBGraphAssembler.java | 124 ++
.../java/org/seaborne/tdb2/assembler/Vocab.java | 36 +
.../org/seaborne/tdb2/assembler/VocabTDB2.java | 90 ++
.../tdb2/graph/TransactionHandlerTDB.java | 60 +
.../main/java/org/seaborne/tdb2/lib/Async.java | 84 +
.../java/org/seaborne/tdb2/lib/NodeLib.java | 141 ++
.../java/org/seaborne/tdb2/lib/TupleLib.java | 154 ++
.../java/org/seaborne/tdb2/loader/Loader.java | 78 +
.../tdb2/loader/StreamRDFBatchSplit.java | 224 +++
.../main/java/org/seaborne/tdb2/migrate/A2.java | 37 +
.../tdb2/migrate/TransformGraphRename.java | 53 +
.../seaborne/tdb2/modify/UpdateEngineTDB.java | 52 +
.../org/seaborne/tdb2/setup/ComponentIdMgr.java | 101 ++
.../org/seaborne/tdb2/setup/StoreParams.java | 441 +++++
.../seaborne/tdb2/setup/StoreParamsBuilder.java | 308 ++++
.../seaborne/tdb2/setup/StoreParamsCodec.java | 189 +++
.../seaborne/tdb2/setup/StoreParamsConst.java | 104 ++
.../seaborne/tdb2/setup/StoreParamsDynamic.java | 53 +
.../seaborne/tdb2/setup/StoreParamsFactory.java | 93 ++
.../org/seaborne/tdb2/setup/TDBBuilder.java | 290 ++++
.../seaborne/tdb2/setup/TDBDatasetDetails.java | 75 +
.../org/seaborne/tdb2/solver/Abortable.java | 20 +
.../org/seaborne/tdb2/solver/BindingNodeId.java | 112 ++
.../org/seaborne/tdb2/solver/BindingTDB.java | 154 ++
.../seaborne/tdb2/solver/OpExecutorTDB1.java | 427 +++++
.../main/java/org/seaborne/tdb2/solver/QC2.java | 48 +
.../seaborne/tdb2/solver/QueryEngineTDB.java | 206 +++
.../org/seaborne/tdb2/solver/QueryIterTDB.java | 58 +
.../org/seaborne/tdb2/solver/SolverLib.java | 340 ++++
.../tdb2/solver/StageGeneratorDirectTDB.java | 57 +
.../seaborne/tdb2/solver/StageMatchTuple.java | 195 +++
.../org/seaborne/tdb2/solver/stats/Stats.java | 137 ++
.../tdb2/solver/stats/StatsCollector.java | 35 +
.../tdb2/solver/stats/StatsCollectorBase.java | 53 +
.../tdb2/solver/stats/StatsCollectorNodeId.java | 55 +
.../tdb2/solver/stats/StatsResults.java | 52 +
.../tdb2/store/DatasetGraphSwitchable.java | 203 +++
.../seaborne/tdb2/store/DatasetGraphTDB.java | 480 ++++++
.../seaborne/tdb2/store/DatasetGraphTxn.java | 34 +
.../tdb2/store/DatasetGraphWrapperTxn.java | 34 +
.../seaborne/tdb2/store/DatasetPrefixesTDB.java | 173 ++
.../tdb2/store/GraphPrefixesProjectionTDB.java | 163 ++
.../java/org/seaborne/tdb2/store/GraphTDB.java | 180 +++
.../tdb2/store/GraphViewSwitchable.java | 139 ++
.../main/java/org/seaborne/tdb2/store/Hash.java | 56 +
.../tdb2/store/IteratorCheckNotConcurrent.java | 93 ++
.../seaborne/tdb2/store/IteratorTxnTracker.java | 55 +
.../java/org/seaborne/tdb2/store/NodeId.java | 219 +++
.../org/seaborne/tdb2/store/NodeIdFactory.java | 260 +++
.../org/seaborne/tdb2/store/NodeIdInline.java | 328 ++++
.../org/seaborne/tdb2/store/NodeIdType.java | 259 +++
.../seaborne/tdb2/store/PrefixMappingCache.java | 202 +++
.../java/org/seaborne/tdb2/store/QuadTable.java | 90 ++
.../org/seaborne/tdb2/store/StorageTDB.java | 41 +
.../java/org/seaborne/tdb2/store/TableBase.java | 48 +
.../org/seaborne/tdb2/store/TripleTable.java | 74 +
.../tdb2/store/nodetable/NodeTable.java | 81 +
.../tdb2/store/nodetable/NodeTableCache.java | 352 ++++
.../tdb2/store/nodetable/NodeTableInline.java | 70 +
.../tdb2/store/nodetable/NodeTableNative.java | 214 +++
.../tdb2/store/nodetable/NodeTableOps.java | 50 +
.../tdb2/store/nodetable/NodeTableTRDF.java | 108 ++
.../tdb2/store/nodetable/NodeTableWrapper.java | 93 ++
.../nodetable/TReadAppendFileTransport.java | 85 +
.../store/nodetupletable/NodeTupleTable.java | 71 +
.../nodetupletable/NodeTupleTableConcrete.java | 240 +++
.../nodetupletable/NodeTupleTableView.java | 112 ++
.../nodetupletable/NodeTupleTableWrapper.java | 97 ++
.../tdb2/store/tupletable/TupleIndex.java | 87 +
.../tdb2/store/tupletable/TupleIndexBase.java | 123 ++
.../tdb2/store/tupletable/TupleIndexRecord.java | 237 +++
.../TupleIndexRecordAsyncBulkAdd.java | 262 +++
.../store/tupletable/TupleIndexWrapper.java | 117 ++
.../tdb2/store/tupletable/TupleTable.java | 218 +++
.../seaborne/tdb2/store/value/DateTimeNode.java | 253 +++
.../seaborne/tdb2/store/value/DecimalNode.java | 22 +
.../tdb2/store/value/DecimalNode56.java | 140 ++
.../seaborne/tdb2/store/value/DoubleNode62.java | 241 +++
.../seaborne/tdb2/store/value/FloatNode.java | 31 +
.../seaborne/tdb2/store/value/IntegerNode.java | 63 +
.../seaborne/tdb2/sys/ConnectionTracker.java | 23 +
.../java/org/seaborne/tdb2/sys/CopyDSG.java | 53 +
.../seaborne/tdb2/sys/DatabaseConnection.java | 180 +++
.../java/org/seaborne/tdb2/sys/DatabaseOps.java | 264 +++
.../main/java/org/seaborne/tdb2/sys/EnvTDB.java | 61 +
.../org/seaborne/tdb2/sys/FilenameUtils.java | 102 ++
.../main/java/org/seaborne/tdb2/sys/IOX.java | 292 ++++
.../java/org/seaborne/tdb2/sys/InitTDB2.java | 40 +
.../org/seaborne/tdb2/sys/LockMRSWLite.java | 69 +
.../org/seaborne/tdb2/sys/StoreConnection.java | 194 +++
.../java/org/seaborne/tdb2/sys/SystemTDB.java | 416 +++++
.../java/org/seaborne/tdb2/sys/TDBInternal.java | 174 ++
.../main/java/org/seaborne/tdb2/sys/Util.java | 49 +
.../tdb2/src/main/resources/META-INF/LICENSE | 175 ++
jena-db/tdb2/src/main/resources/META-INF/NOTICE | 10 +
...rg.apache.jena.system.JenaSubsystemLifecycle | 1 +
.../org/apache/jena/tdb/tdb-properties.xml | 8 +
.../test/java/org/seaborne/tdb2/ConfigTest.java | 95 ++
.../src/test/java/org/seaborne/tdb2/TC_TDB.java | 80 +
.../test/java/org/seaborne/tdb2/TS_Factory.java | 32 +
.../java/org/seaborne/tdb2/TestDatabaseMgr.java | 89 ++
.../java/org/seaborne/tdb2/TestTDBFactory.java | 130 ++
.../tdb2/assembler/TS_TDBAssembler.java | 32 +
.../tdb2/assembler/TestTDBAssembler.java | 142 ++
.../tdb2/graph/AbstractTestGraphsTDB.java | 50 +
.../java/org/seaborne/tdb2/graph/TS_Graph.java | 35 +
.../tdb2/graph/TestDatasetGraphAccessorTDB.java | 47 +
.../tdb2/graph/TestDatasetGraphTDB.java | 52 +
.../tdb2/graph/TestGraphOverDatasetTDB.java | 63 +
.../org/seaborne/tdb2/graph/TestGraphsTDB1.java | 42 +
.../org/seaborne/tdb2/graph/TestGraphsTDB2.java | 51 +
.../tdb2/graph/TestPrefixMappingTDB.java | 106 ++
.../tdb2/junit/AbstractTestGraphTDB.java | 33 +
.../java/org/seaborne/tdb2/junit/Base_TS.java | 51 +
.../org/seaborne/tdb2/junit/BuildTestLib.java | 81 +
.../org/seaborne/tdb2/junit/QueryTestTDB.java | 192 +++
.../seaborne/tdb2/junit/TDBTestException.java | 28 +
.../test/java/org/seaborne/tdb2/junit/TL.java | 89 ++
.../org/seaborne/tdb2/junit/TestFactoryTDB.java | 87 +
.../java/org/seaborne/tdb2/lib/TS_LibTDB.java | 33 +
.../java/org/seaborne/tdb2/lib/TestNodeLib.java | 69 +
.../org/seaborne/tdb2/setup/TS_TDBSetup.java | 32 +
.../seaborne/tdb2/setup/TestStoreParams.java | 144 ++
.../tdb2/setup/TestStoreParamsChoose.java | 157 ++
.../tdb2/setup/TestStoreParamsCreate.java | 180 +++
.../org/seaborne/tdb2/solver/TS_SolverTDB.java | 30 +
.../org/seaborne/tdb2/solver/TestSolverTDB.java | 171 ++
.../org/seaborne/tdb2/solver/TestStats.java | 117 ++
.../AbstractTestStoreConnectionBasics.java | 185 +++
.../store/AbstractTestTransPromoteTDB2.java | 71 +
.../java/org/seaborne/tdb2/store/TS_Store.java | 71 +
.../org/seaborne/tdb2/store/TestDatasetTDB.java | 323 ++++
.../tdb2/store/TestDatasetTDBPersist.java | 111 ++
.../tdb2/store/TestDynamicDatasetTDB.java | 44 +
.../seaborne/tdb2/store/TestGraphNamedTDB.java | 60 +
.../org/seaborne/tdb2/store/TestGraphTDB.java | 57 +
.../org/seaborne/tdb2/store/TestNodeId.java | 127 ++
.../org/seaborne/tdb2/store/TestQuadFilter.java | 110 ++
.../tdb2/store/TestStoreConnectionDirect.java | 47 +
.../tdb2/store/TestStoreConnectionLock.java | 71 +
.../tdb2/store/TestStoreConnectionMapped.java | 50 +
.../tdb2/store/TestStoreConnectionMem.java | 28 +
.../seaborne/tdb2/store/TestSuiteGraphTDB.java | 40 +
.../tdb2/store/TestTransPromoteTDB.java | 72 +
.../tdb2/store/TestTransactionLifecycleTDB.java | 33 +
.../seaborne/tdb2/store/TestTransactions.java | 204 +++
.../seaborne/tdb2/store/TestTripleTable.java | 132 ++
.../seaborne/tdb2/store/Test_SPARQL_TDB.java | 221 +++
.../store/nodetable/AbstractTestNodeTable.java | 66 +
.../tdb2/store/nodetable/TS_NodeTable.java | 33 +
.../tdb2/store/nodetable/TestNodeTable.java | 37 +
.../tdb2/store/nodetable/TestNodeTableBase.java | 39 +
.../store/nodetable/TestNodeTableStored.java | 45 +
.../nodetable/TestNodeTableStoredBase.java | 46 +
.../tupletable/AbstractTestTupleIndex.java | 264 +++
.../seaborne/tdb2/store/tupletable/NData.java | 37 +
.../tdb2/store/tupletable/TS_TupleTable.java | 31 +
.../store/tupletable/TestTupleIndexRecord.java | 42 +
.../tupletable/TestTupleIndexRecordDirect.java | 314 ++++
.../tdb2/store/tupletable/TestTupleTable.java | 151 ++
.../tdb2/store/value/TestDoubleNode62.java | 123 ++
.../tdb2/store/value/TestNodeIdInline.java | 285 ++++
.../test/java/org/seaborne/tdb2/sys/TS_Sys.java | 33 +
.../tdb2/sys/TestDatabaseConnection.java | 69 +
.../org/seaborne/tdb2/sys/TestDatabaseOps.java | 172 ++
.../java/org/seaborne/tdb2/sys/TestOps.java | 31 +
.../java/org/seaborne/tdb2/sys/TestSys.java | 32 +
.../testing/Assembler/tdb-dataset-embed.ttl | 23 +
jena-db/tdb2/testing/Assembler/tdb-dataset.ttl | 23 +
.../tdb2/testing/Assembler/tdb-graph-embed.ttl | 27 +
.../testing/Assembler/tdb-graph-ref-dataset.ttl | 31 +
jena-db/tdb2/testing/Assembler/tdb-graph.ttl | 27 +
.../testing/Assembler/tdb-named-graph-1.ttl | 29 +
.../testing/Assembler/tdb-named-graph-2.ttl | 28 +
jena-db/tdb2/testing/Basic/basic-00.rq | 4 +
jena-db/tdb2/testing/Basic/basic-1-O.rq | 4 +
jena-db/tdb2/testing/Basic/basic-1-P.rq | 4 +
jena-db/tdb2/testing/Basic/basic-1-PO.rq | 4 +
jena-db/tdb2/testing/Basic/basic-1-S.rq | 4 +
jena-db/tdb2/testing/Basic/basic-1-SO.rq | 4 +
jena-db/tdb2/testing/Basic/basic-1-SP.rq | 4 +
jena-db/tdb2/testing/Basic/basic-1-SPO.rq | 4 +
jena-db/tdb2/testing/Basic/basic-2-SO.rq | 4 +
jena-db/tdb2/testing/Basic/basic-3-O.rq | 4 +
jena-db/tdb2/testing/Basic/basic-3-P.rq | 4 +
jena-db/tdb2/testing/Basic/basic-3-PO.rq | 4 +
jena-db/tdb2/testing/Basic/basic-3-S.rq | 4 +
jena-db/tdb2/testing/Basic/basic-3-SO.rq | 4 +
jena-db/tdb2/testing/Basic/basic-3-SP.rq | 4 +
jena-db/tdb2/testing/Basic/data-1.ttl | 17 +
jena-db/tdb2/testing/Basic/manifest.ttl | 101 ++
jena-db/tdb2/testing/Data/solver-data.ttl | 7 +
jena-db/tdb2/testing/Loader/data-1.nq | 1 +
jena-db/tdb2/testing/Loader/data-2.nt | 1 +
jena-db/tdb2/testing/Loader/data-3.trig | 3 +
jena-db/tdb2/testing/Loader/data-4.ttl | 4 +
jena-db/tdb2/testing/Pattern/data-1.ttl | 17 +
jena-db/tdb2/testing/Pattern/manifest.ttl | 35 +
jena-db/tdb2/testing/Pattern/pattern-1.rq | 7 +
jena-db/tdb2/testing/Pattern/pattern-2.rq | 8 +
jena-db/tdb2/testing/Quads/data-1.ttl | 5 +
jena-db/tdb2/testing/Quads/data-2.ttl | 5 +
jena-db/tdb2/testing/Quads/data-dft.ttl | 10 +
jena-db/tdb2/testing/Quads/manifest.ttl | 51 +
jena-db/tdb2/testing/Quads/quad-01.rq | 9 +
jena-db/tdb2/testing/Quads/quad-02.rq | 8 +
jena-db/tdb2/testing/UnionGraph/data-1.ttl | 7 +
jena-db/tdb2/testing/UnionGraph/data-2.ttl | 5 +
jena-db/tdb2/testing/UnionGraph/data-dft.ttl | 5 +
jena-db/tdb2/testing/UnionGraph/manifest.ttl | 107 ++
.../tdb2/testing/UnionGraph/merge-1-results.srx | 57 +
jena-db/tdb2/testing/UnionGraph/merge-1.rq | 8 +
.../tdb2/testing/UnionGraph/merge-2-results.srx | 66 +
jena-db/tdb2/testing/UnionGraph/merge-2.rq | 8 +
.../tdb2/testing/UnionGraph/merge-3-results.srx | 31 +
jena-db/tdb2/testing/UnionGraph/merge-3.rq | 8 +
.../tdb2/testing/UnionGraph/merge-4-results.srx | 99 ++
jena-db/tdb2/testing/UnionGraph/merge-4.rq | 8 +
.../tdb2/testing/UnionGraph/merge-5-results.srx | 33 +
jena-db/tdb2/testing/UnionGraph/merge-5.rq | 8 +
.../tdb2/testing/UnionGraph/merge-6-results.srx | 43 +
jena-db/tdb2/testing/UnionGraph/merge-6.rq | 7 +
.../tdb2/testing/UnionGraph/merge-A-results.srx | 99 ++
jena-db/tdb2/testing/UnionGraph/merge-A.rq | 8 +
.../tdb2/testing/UnionGraph/merge-B-results.srx | 49 +
jena-db/tdb2/testing/UnionGraph/merge-B.rq | 8 +
jena-db/tdb2/testing/Update/create-1.ru | 1 +
jena-db/tdb2/testing/Update/drop-1.ru | 1 +
jena-db/tdb2/testing/Update/update-1.ru | 3 +
jena-db/tdb2/testing/Update/update-2.ru | 5 +
jena-db/tdb2/testing/Update/update-3.ru | 7 +
jena-db/tdb2/testing/Values/data-1.ttl | 23 +
jena-db/tdb2/testing/Values/manifest.ttl | 76 +
jena-db/tdb2/testing/Values/value-00.rq | 1 +
jena-db/tdb2/testing/Values/value-01.rq | 1 +
jena-db/tdb2/testing/Values/value-02.rq | 1 +
jena-db/tdb2/testing/Values/value-03.rq | 1 +
jena-db/tdb2/testing/Values/value-04.rq | 1 +
jena-db/tdb2/testing/Values/value-05.rq | 5 +
jena-db/tdb2/testing/Values/value-06.rq | 6 +
jena-db/tdb2/testing/Values/value-07.rq | 6 +
jena-db/tdb2/testing/Values/value-08.rq | 6 +
jena-db/tdb2/testing/Values/value-09.rq | 7 +
jena-db/tdb2/testing/manifest.ttl | 31 +
jena-db/use-fuseki-tdb2.md | 60 +
jena-db/use-tdb2-cmds.md | 21 +
jena-db/use-tdb2.md | 27 +
598 files changed, 55053 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/.gitignore
----------------------------------------------------------------------
diff --cc jena-db/.gitignore
index 0000000,0000000..18ee681
new file mode 100644
--- /dev/null
+++ b/jena-db/.gitignore
@@@ -1,0 -1,0 +1,46 @@@
++*.class
++
++## Package Files
++*.jar
++*.war
++*.ear
++
++hs_err_pid*
++tmp/
++*.bak
++
++## From https://www.gitignore.io
++
++### Maven ###
++target/
++pom.xml.tag
++pom.xml.releaseBackup
++pom.xml.versionsBackup
++pom.xml.next
++release.properties
++dependency-reduced-pom.xml
++buildNumber.properties
++.mvn/timing.properties
++
++### Gradle ###
++**/.gradle/
++build/
++# Ignore Gradle GUI config
++gradle-app.setting
++# Don't ignore the Gradle wrapper jar file
++!gradle-wrapper.jar
++# Cache of project
++.gradletasknamecache
++
++
++## Eclipse
++.classpath
++.project
++.settings/
++.recommenders
++.metadata
++
++## Database files.
++DB*/
++## Fuseki area
++run/
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/.travis.yml
----------------------------------------------------------------------
diff --cc jena-db/.travis.yml
index 0000000,0000000..d7b228d
new file mode 100644
--- /dev/null
+++ b/jena-db/.travis.yml
@@@ -1,0 -1,0 +1,17 @@@
++---
++language: java
++jdk:
++ - oraclejdk8
++
++notifications:
++ email:
++ # [always|never|change]
++ on_success: change
++ on_failure: change
++
++## sudo: false
++## install: mvn dependency:go-offline
++## script: mvn verify
++## env:
++## global:
++## - JAVA_OPTS="-Xmx3072M -Xms512M -XX:+UseG1GC"
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/LICENSE
----------------------------------------------------------------------
diff --cc jena-db/LICENSE
index 0000000,0000000..e06d208
new file mode 100644
--- /dev/null
+++ b/jena-db/LICENSE
@@@ -1,0 -1,0 +1,202 @@@
++Apache License
++ Version 2.0, January 2004
++ http://www.apache.org/licenses/
++
++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
++
++ 1. Definitions.
++
++ "License" shall mean the terms and conditions for use, reproduction,
++ and distribution as defined by Sections 1 through 9 of this document.
++
++ "Licensor" shall mean the copyright owner or entity authorized by
++ the copyright owner that is granting the License.
++
++ "Legal Entity" shall mean the union of the acting entity and all
++ other entities that control, are controlled by, or are under common
++ control with that entity. For the purposes of this definition,
++ "control" means (i) the power, direct or indirect, to cause the
++ direction or management of such entity, whether by contract or
++ otherwise, or (ii) ownership of fifty percent (50%) or more of the
++ outstanding shares, or (iii) beneficial ownership of such entity.
++
++ "You" (or "Your") shall mean an individual or Legal Entity
++ exercising permissions granted by this License.
++
++ "Source" form shall mean the preferred form for making modifications,
++ including but not limited to software source code, documentation
++ source, and configuration files.
++
++ "Object" form shall mean any form resulting from mechanical
++ transformation or translation of a Source form, including but
++ not limited to compiled object code, generated documentation,
++ and conversions to other media types.
++
++ "Work" shall mean the work of authorship, whether in Source or
++ Object form, made available under the License, as indicated by a
++ copyright notice that is included in or attached to the work
++ (an example is provided in the Appendix below).
++
++ "Derivative Works" shall mean any work, whether in Source or Object
++ form, that is based on (or derived from) the Work and for which the
++ editorial revisions, annotations, elaborations, or other modifications
++ represent, as a whole, an original work of authorship. For the purposes
++ of this License, Derivative Works shall not include works that remain
++ separable from, or merely link (or bind by name) to the interfaces of,
++ the Work and Derivative Works thereof.
++
++ "Contribution" shall mean any work of authorship, including
++ the original version of the Work and any modifications or additions
++ to that Work or Derivative Works thereof, that is intentionally
++ submitted to Licensor for inclusion in the Work by the copyright owner
++ or by an individual or Legal Entity authorized to submit on behalf of
++ the copyright owner. For the purposes of this definition, "submitted"
++ means any form of electronic, verbal, or written communication sent
++ to the Licensor or its representatives, including but not limited to
++ communication on electronic mailing lists, source code control systems,
++ and issue tracking systems that are managed by, or on behalf of, the
++ Licensor for the purpose of discussing and improving the Work, but
++ excluding communication that is conspicuously marked or otherwise
++ designated in writing by the copyright owner as "Not a Contribution."
++
++ "Contributor" shall mean Licensor and any individual or Legal Entity
++ on behalf of whom a Contribution has been received by Licensor and
++ subsequently incorporated within the Work.
++
++ 2. Grant of Copyright License. Subject to the terms and conditions of
++ this License, each Contributor hereby grants to You a perpetual,
++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
++ copyright license to reproduce, prepare Derivative Works of,
++ publicly display, publicly perform, sublicense, and distribute the
++ Work and such Derivative Works in Source or Object form.
++
++ 3. Grant of Patent License. Subject to the terms and conditions of
++ this License, each Contributor hereby grants to You a perpetual,
++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
++ (except as stated in this section) patent license to make, have made,
++ use, offer to sell, sell, import, and otherwise transfer the Work,
++ where such license applies only to those patent claims licensable
++ by such Contributor that are necessarily infringed by their
++ Contribution(s) alone or by combination of their Contribution(s)
++ with the Work to which such Contribution(s) was submitted. If You
++ institute patent litigation against any entity (including a
++ cross-claim or counterclaim in a lawsuit) alleging that the Work
++ or a Contribution incorporated within the Work constitutes direct
++ or contributory patent infringement, then any patent licenses
++ granted to You under this License for that Work shall terminate
++ as of the date such litigation is filed.
++
++ 4. Redistribution. You may reproduce and distribute copies of the
++ Work or Derivative Works thereof in any medium, with or without
++ modifications, and in Source or Object form, provided that You
++ meet the following conditions:
++
++ (a) You must give any other recipients of the Work or
++ Derivative Works a copy of this License; and
++
++ (b) You must cause any modified files to carry prominent notices
++ stating that You changed the files; and
++
++ (c) You must retain, in the Source form of any Derivative Works
++ that You distribute, all copyright, patent, trademark, and
++ attribution notices from the Source form of the Work,
++ excluding those notices that do not pertain to any part of
++ the Derivative Works; and
++
++ (d) If the Work includes a "NOTICE" text file as part of its
++ distribution, then any Derivative Works that You distribute must
++ include a readable copy of the attribution notices contained
++ within such NOTICE file, excluding those notices that do not
++ pertain to any part of the Derivative Works, in at least one
++ of the following places: within a NOTICE text file distributed
++ as part of the Derivative Works; within the Source form or
++ documentation, if provided along with the Derivative Works; or,
++ within a display generated by the Derivative Works, if and
++ wherever such third-party notices normally appear. The contents
++ of the NOTICE file are for informational purposes only and
++ do not modify the License. You may add Your own attribution
++ notices within Derivative Works that You distribute, alongside
++ or as an addendum to the NOTICE text from the Work, provided
++ that such additional attribution notices cannot be construed
++ as modifying the License.
++
++ You may add Your own copyright statement to Your modifications and
++ may provide additional or different license terms and conditions
++ for use, reproduction, or distribution of Your modifications, or
++ for any such Derivative Works as a whole, provided Your use,
++ reproduction, and distribution of the Work otherwise complies with
++ the conditions stated in this License.
++
++ 5. Submission of Contributions. Unless You explicitly state otherwise,
++ any Contribution intentionally submitted for inclusion in the Work
++ by You to the Licensor shall be under the terms and conditions of
++ this License, without any additional terms or conditions.
++ Notwithstanding the above, nothing herein shall supersede or modify
++ the terms of any separate license agreement you may have executed
++ with Licensor regarding such Contributions.
++
++ 6. Trademarks. This License does not grant permission to use the trade
++ names, trademarks, service marks, or product names of the Licensor,
++ except as required for reasonable and customary use in describing the
++ origin of the Work and reproducing the content of the NOTICE file.
++
++ 7. Disclaimer of Warranty. Unless required by applicable law or
++ agreed to in writing, Licensor provides the Work (and each
++ Contributor provides its Contributions) on an "AS IS" BASIS,
++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
++ implied, including, without limitation, any warranties or conditions
++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
++ PARTICULAR PURPOSE. You are solely responsible for determining the
++ appropriateness of using or redistributing the Work and assume any
++ risks associated with Your exercise of permissions under this License.
++
++ 8. Limitation of Liability. In no event and under no legal theory,
++ whether in tort (including negligence), contract, or otherwise,
++ unless required by applicable law (such as deliberate and grossly
++ negligent acts) or agreed to in writing, shall any Contributor be
++ liable to You for damages, including any direct, indirect, special,
++ incidental, or consequential damages of any character arising as a
++ result of this License or out of the use or inability to use the
++ Work (including but not limited to damages for loss of goodwill,
++ work stoppage, computer failure or malfunction, or any and all
++ other commercial damages or losses), even if such Contributor
++ has been advised of the possibility of such damages.
++
++ 9. Accepting Warranty or Additional Liability. While redistributing
++ the Work or Derivative Works thereof, You may choose to offer,
++ and charge a fee for, acceptance of support, warranty, indemnity,
++ or other liability obligations and/or rights consistent with this
++ License. However, in accepting such obligations, You may act only
++ on Your own behalf and on Your sole responsibility, not on behalf
++ of any other Contributor, and only if You agree to indemnify,
++ defend, and hold each Contributor harmless for any liability
++ incurred by, or claims asserted against, such Contributor by reason
++ of your accepting any such warranty or additional liability.
++
++ END OF TERMS AND CONDITIONS
++
++ APPENDIX: How to apply the Apache License to your work.
++
++ To apply the Apache License to your work, attach the following
++ boilerplate notice, with the fields enclosed by brackets "{}"
++ replaced with your own identifying information. (Don't include
++ the brackets!) The text should be enclosed in the appropriate
++ comment syntax for the file format. We also recommend that a
++ file or class name and description of purpose be included on the
++ same "printed page" as the copyright notice for easier
++ identification within third-party archives.
++
++ Copyright {yyyy} {name of copyright owner}
++
++ 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.
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/NOTICE
----------------------------------------------------------------------
diff --cc jena-db/NOTICE
index 0000000,0000000..5ba7ec0
new file mode 100644
--- /dev/null
+++ b/jena-db/NOTICE
@@@ -1,0 -1,0 +1,10 @@@
++Mantis Database Operating Environment
++
++Copyright 2013-2017 Andy Seaborne
++Copyright 2014, 2015 Epimorphics Ltd.
++
++Portions of this software derive from software from Apache Jena:
++ - Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
++ - Copyright 2010, 2011 Epimorphics Ltd.
++ - Copyright 2010, 2011 Talis Systems Ltd.
++These have been licensed to the Apache Software Foundation under a software grant.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/README.md
----------------------------------------------------------------------
diff --cc jena-db/README.md
index 0000000,0000000..f9c3d43
new file mode 100644
--- /dev/null
+++ b/jena-db/README.md
@@@ -1,0 -1,0 +1,64 @@@
++[](https://travis-ci.org/afs/mantis)
++
++# Mantis - Database Operating Environment
++
++Mantis is a set of database-related components. It includes:
++
++* Transaction Coordination
++* Copy-on-write data structures
++* Query algebra evaluation library
++* Abstraction of basic file operations
++
++TDB2 is a reworking for TDB that provides scalable transactions as well
++as refining the machinary for reliability.
++
++License: Apache License
++
++See [LICENSE](LICENSE) and [NOTICE](NOTICE) for details.
++
++Continuous integration: [TravisCI](https://travis-ci.org/afs/mantis)
++
++Notes on using [TDB2 in a Java application](use-tdb2.md).
++
++Notes on using [TDB2 from the command line](use-tdb2-cmds.md).
++
++Notes on using [TDB2 with Apache Jena Fuseki](use-fuseki-tdb2.md).
++
++Status: currently snapshot builds only.
++
++It depends on [Apache Jena](https://jena.apache.org/) snapshots.
++
++Maven repositories setup:
++
++```
++ <repositories>
++ <!-- Apache Snapshot Repository -->
++ <repository>
++ <id>apache-repository-snapshots</id>
++ <url>https://repository.apache.org/snapshots</url>
++ <releases>
++ <enabled>false</enabled>
++ </releases>
++ <snapshots>
++ <enabled>true</enabled>
++ <updatePolicy>daily</updatePolicy>
++ <checksumPolicy>fail</checksumPolicy>
++ </snapshots>
++ </repository>
++
++ <!-- Sonatype snapshot repository -->
++ <repository>
++ <id>sonatype.public</id>
++ <name>Sonatype Snapshots Repository</name>
++ <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
++ <releases>
++ <enabled>false</enabled>
++ </releases>
++ <snapshots>
++ <enabled>true</enabled>
++ </snapshots>
++ </repository>
++
++ </repositories>
++```
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/.gitignore
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/.gitignore
index 0000000,0000000..b49c563
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/.gitignore
@@@ -1,0 -1,0 +1,4 @@@
++/target/
++/target/
++/target/
++/target/
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/README.md
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/README.md
index 0000000,0000000..5969da0
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/README.md
@@@ -1,0 -1,0 +1,1 @@@
++Basic file-level abstractions.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/pom.xml
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/pom.xml
index 0000000,0000000..986c95f
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/pom.xml
@@@ -1,0 -1,0 +1,64 @@@
++<?xml version="1.0" encoding="utf-8"?>
++<!--
++ 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.
++-->
++
++<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
++ <modelVersion>4.0.0</modelVersion>
++
++ <artifactId>dboe-base</artifactId>
++ <packaging>jar</packaging>
++ <name>Mantis (${project.artifactId})</name>
++
++ <parent>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>mantis</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </parent>
++
++ <dependencies>
++
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-arq</artifactId>
++ </dependency>
++
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-arq</artifactId>
++ <classifier>tests</classifier>
++ <scope>test</scope>
++ </dependency>
++
++ </dependencies>
++
++ <build>
++ <plugins>
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-jar-plugin</artifactId>
++ <executions>
++ <execution>
++ <goals>
++ <goal>test-jar</goal>
++ </goals>
++ </execution>
++ </executions>
++ </plugin>
++ </plugins>
++ </build>
++
++</project>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/DBOpEnvException.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/DBOpEnvException.java
index 0000000,0000000..77b489f
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/DBOpEnvException.java
@@@ -1,0 -1,0 +1,28 @@@
++/*
++ * 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.dboe;
++
++import org.apache.jena.shared.JenaException;
++
++public class DBOpEnvException extends JenaException
++{
++ public DBOpEnvException() { super() ; }
++ public DBOpEnvException(String msg) { super(msg) ; }
++ public DBOpEnvException(Throwable th) { super(th) ; }
++ public DBOpEnvException(String msg, Throwable th) { super(msg, th) ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/StorageException.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/StorageException.java
index 0000000,0000000..c67c618
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/StorageException.java
@@@ -1,0 -1,0 +1,26 @@@
++/*
++ * 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.dboe.base;
++
++public class StorageException extends RuntimeException
++{
++ public StorageException() { super() ; }
++ public StorageException(String msg) { super(msg) ; }
++ public StorageException(Throwable th) { super(th) ; }
++ public StorageException(String msg, Throwable th) { super(msg, th) ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/Block.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/Block.java
index 0000000,0000000..043b043
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/Block.java
@@@ -1,0 -1,0 +1,165 @@@
++/*
++ * 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.dboe.base.block;
++
++import java.io.ByteArrayOutputStream ;
++import java.io.PrintStream ;
++import java.nio.ByteBuffer ;
++import org.apache.jena.atlas.lib.ByteBufferLib ;
++
++public final class Block
++{
++ // XXX Note development code added to enforce read-only use. Marked [RO]
++
++ // While the general mechanisms support long block id,
++ // some uses make restrictions.
++ // BlockMgrs:
++ // Blocks for indexes (B+Trees) are addressed by int - one int is 2G of 8K units = 16T
++ // Blocks for objects are addressed by long - this is file offset so 2G is not enough.
++
++ private final Long id ; // Keep as object. It's the cache key.
++ //private BlockRef blockRef ;
++
++
++ // These are information carrying flags -- not enforced
++ // although .write checks the readOnly flags.
++ private boolean readOnly = false ;
++ private boolean modified = false ;
++
++ private /*[[Dev-RO]] final*/ ByteBuffer byteBuffer ;
++ // If the byteBuffer is, say, a slice of another one,
++ // this can be used to carry a ref to the real ByteBuffer.
++ private ByteBuffer underlyingByteBuffer ;
++
++ public Block(long id, ByteBuffer byteBuffer) {
++ this(Long.valueOf(id), byteBuffer) ;
++ }
++
++ public Block(Long id, ByteBuffer byteBuffer) {
++ // ByteBuffer is whole disk space from byte 0 for this disk unit.
++ this.id = id ;
++ this.byteBuffer = byteBuffer ;
++ // this.blockRef = null ;
++ // Default - writeable, unmodified block.
++ this.readOnly = false ;
++ this.modified = false ;
++ this.underlyingByteBuffer = null ;
++ }
++
++ public final Long getId() {
++ return id ;
++ }
++
++ public final ByteBuffer getByteBuffer() {
++ return byteBuffer ;
++ }
++
++ public boolean isReadOnly() {
++ return readOnly ;
++ }
++
++ public void setReadOnly(boolean readonly) {
++ if ( readonly && modified )
++ throw new BlockException("Attempt to mark a modified block as read-only") ;
++ // Hard to force a read-only byte buffer because higher levels
++ // may slice this and have their own byte buffers or even
++ // intBuffers etc.
++ this.readOnly = readonly ;
++ }
++
++ public boolean isModified() {
++ return modified ;
++ }
++
++ public void setModified(boolean modified) {
++ if ( readOnly && modified )
++ throw new BlockException("Attempt to mark a readonly block as modified") ;
++ this.modified = modified ;
++ }
++
++ public ByteBuffer getUnderlyingByteBuffer()
++ { return underlyingByteBuffer ; }
++
++ public void setUnderlyingByteBuffer(ByteBuffer underlyingByteBuffer)
++ { this.underlyingByteBuffer = underlyingByteBuffer ; }
++
++ @Override
++ public String toString() {
++ ByteBuffer bb = getByteBuffer() ;
++ if ( true )
++ // Short form.
++ return String.format("Block: %d (posn=%d, limit=%d, cap=%d)", id, bb.position(), bb.limit(), bb.capacity()) ;
++ // Long form - with some bytes from the ByteBuffer.
++ ByteArrayOutputStream out = new ByteArrayOutputStream() ;
++ PrintStream x = new PrintStream(out) ;
++ ByteBufferLib.print(x, bb) ;
++ x.flush() ;
++ String str = out.toString() ;
++ return String.format("Block: %d %s", id, str) ;
++ }
++
++ /** Deep copy, including ByteBuffer contents into a HeapByteBuffer. */
++ public Block replicate() {
++ ByteBuffer dstBuffer = ByteBuffer.allocate(getByteBuffer().capacity()) ;
++ return replicate(dstBuffer) ;
++ }
++
++ /**
++ * Deep copy, including ByteBuffer contents, using the supplied ByteBuffer
++ * to hold the contents and to be used when constructing the new Block. The
++ * capacity of the supplied ByteBuffer must be equal to or greater than this
++ * block's capacity.
++ */
++ private Block replicate(ByteBuffer dstBuffer) {
++ replicateByteBuffer(getByteBuffer(), dstBuffer) ;
++ Block b = new Block(getId(), dstBuffer) ;
++ b.setModified(modified) ;
++ b.setReadOnly(readOnly) ;
++ // b.blockRef = null ;
++ return b ;
++ }
++
++ public static void replicate(Block srcBlock, Block dstBlock) {
++ if ( !srcBlock.getId().equals(dstBlock.getId()) )
++ throw new BlockException("FileAccessMem: Attempt to copy across blocks: " + srcBlock.getId() + " => " + dstBlock.getId()) ;
++ replicate(srcBlock.getByteBuffer(), dstBlock.getByteBuffer()) ;
++ }
++
++ private static ByteBuffer replicateByteBuffer(ByteBuffer srcBlk, ByteBuffer dstBlk) {
++ int x = srcBlk.position() ;
++ int y = srcBlk.limit() ;
++ srcBlk.clear() ;
++
++ if ( srcBlk.hasArray() && dstBlk.hasArray() )
++ System.arraycopy(srcBlk.array(), 0, dstBlk.array(), 0, srcBlk.capacity()) ;
++ else
++ dstBlk.put(srcBlk) ;
++
++ srcBlk.position(x) ;
++ dstBlk.position(x) ;
++ srcBlk.limit(y) ;
++ dstBlk.limit(y) ;
++ return dstBlk ;
++ }
++
++ private static void replicate(ByteBuffer srcBlk, ByteBuffer dstBlk) {
++ srcBlk.position(0) ;
++ dstBlk.position(0) ;
++ dstBlk.put(srcBlk) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockException.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockException.java
index 0000000,0000000..5a7ab89
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockException.java
@@@ -1,0 -1,0 +1,28 @@@
++/*
++ * 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.dboe.base.block;
++
++import org.seaborne.dboe.base.file.FileException ;
++
++public class BlockException extends FileException
++{
++ public BlockException() { super() ; }
++ public BlockException(String msg) { super(msg) ; }
++ public BlockException(Throwable th) { super(th) ; }
++ public BlockException(String msg, Throwable th) { super(msg, th) ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgr.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgr.java
index 0000000,0000000..4fd8dc3
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgr.java
@@@ -1,0 -1,0 +1,99 @@@
++/*
++ * 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.dboe.base.block;
++
++import org.apache.jena.atlas.lib.Closeable ;
++import org.apache.jena.atlas.lib.Sync ;
++
++
++public interface BlockMgr extends Sync, Closeable /*UnitMgr<Block>*/
++{
++ /** Allocate an uninitialized block - writable - call only inside a update sequence.
++ * If blockSize is -1, means "default/fixed size" for this BlockMgr
++ */
++ public Block allocate(int blockSize) ;
++
++ /** Answer whether there are any blocks in the collection being managed */
++ public boolean isEmpty() ;
++
++ /** The fixed allocated blocks are in the range [0,allocLimit).
++ * Allocation units need not be +1 increments */
++ public long allocLimit() ;
++
++ /** Reset the allocation limit, should be a number previously obtained from allocLimit */
++ public void resetAlloc(long boundary) ;
++
++ /** Fetch a block, use for read only */
++ public Block getRead(long id);
++
++ /** Fetch a block, use for write and read - only inside "update" */
++ public Block getWrite(long id);
++
++ /** Release a block, unmodified or already written. */
++ public void release(Block block) ;
++
++ /** Promote to writeable : it's OK to promote an already writeable block */
++ public Block promote(Block block);
++
++ // Bad name? "endWrite", "put" -- for a mapped block, the changes are made directly, not on the write() */
++ /** Write a block back - it still needs releasing. */
++ public void write(Block block) ;
++
++ /** Replace the contents of a block slot with new contents. Block does not need releasing.
++ * The write() operation may not do real work if the block is mapped - this operation
++ * really does replace the contents with the new contents.
++ */
++ public void overwrite(Block blk) ;
++
++ /** Announce a block is no longer in use (i.e it's now freed) */
++ public void free(Block block);
++
++ /** Is this a valid block id? (may be a free block)*/
++ public boolean valid(int id) ;
++
++ /** Close the block manager */
++ @Override
++ public void close() ;
++
++ /** Is this block manager still usable? Closed block managers can not perform any operations except this one. */
++ public boolean isClosed() ;
++
++ /** Sync the block manager */
++ @Override
++ public void sync() ;
++
++ /** Sync the block manager : system operation to ensure sync() is passed down */
++ public void syncForce() ;
++
++ // begin/end markers.
++
++ /** Start of update */
++ public void beginUpdate() ;
++
++ /** Completion of update */
++ public void endUpdate() ;
++
++ /** Start of read */
++ public void beginRead() ;
++
++ /** Completion of read */
++ public void endRead() ;
++
++ /* Label for helping trace which BlockMgr is which */
++ public String getLabel() ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrBase.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrBase.java
index 0000000,0000000..6a7a71b
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrBase.java
@@@ -1,0 -1,0 +1,51 @@@
++/*
++ * 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.dboe.base.block;
++
++import org.slf4j.Logger ;
++
++public abstract class BlockMgrBase implements BlockMgr
++{
++ protected final int blockSize ;
++ private String label ;
++ protected abstract Logger log() ;
++
++ // Fixed size, fixed block type.
++ protected BlockMgrBase(String label, int blockSize)
++ {
++ this.label = label ;
++ this.blockSize = blockSize ;
++ }
++
++ @Override
++ public final Block allocate(int blkSize)
++ {
++ if ( blkSize > 0 && blkSize != this.blockSize )
++ throw new BlockException("Fixed blocksize BlockMgr: request= "+blkSize+" fixed size="+this.blockSize) ;
++ return allocate() ;
++ }
++
++ protected abstract Block allocate() ;
++
++ @Override final public String getLabel() { return label ; }
++
++ @Override public void endUpdate() {}
++ @Override public void beginUpdate() {}
++ @Override public void beginRead() {}
++ @Override public void endRead() {}
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrBuilder.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrBuilder.java
index 0000000,0000000..ebf55d0
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrBuilder.java
@@@ -1,0 -1,0 +1,24 @@@
++/*
++ * 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.dboe.base.block;
++
++import org.seaborne.dboe.base.file.FileSet ;
++
++public interface BlockMgrBuilder {
++ BlockMgr buildBlockMgr(FileSet fileSet, String ext, BlockParams indexParams) ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrBuilderStd.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrBuilderStd.java
index 0000000,0000000..26ef1f5
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrBuilderStd.java
@@@ -1,0 -1,0 +1,28 @@@
++/*
++ * 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.dboe.base.block;
++
++import org.seaborne.dboe.base.file.FileSet ;
++
++public class BlockMgrBuilderStd implements BlockMgrBuilder {
++ @Override
++ public BlockMgr buildBlockMgr(FileSet fileSet, String ext, BlockParams indexParams) {
++ return BlockMgrFactory.create(fileSet, ext, indexParams) ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrCache.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrCache.java
index 0000000,0000000..753f6a1
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrCache.java
@@@ -1,0 -1,0 +1,325 @@@
++/*
++ * 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.dboe.base.block ;
++
++import java.util.ArrayList ;
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.apache.jena.atlas.lib.Cache ;
++import org.apache.jena.atlas.lib.CacheFactory ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/** Caching block manager - this is an LRU cache */
++public class BlockMgrCache extends BlockMgrSync {
++ // Actually, this is two cache one on the read blocks and one on the write
++ // blocks.
++ // The overridden public operations are sync'ed.
++ // As sync is on "this", it also covers all the other operations via
++ // BlockMgrSync
++
++ private static Logger log = LoggerFactory.getLogger(BlockMgrCache.class) ;
++ // Read cache : always present.
++ private final Cache<Long, Block> readCache ;
++
++ // Delayed dirty writes. May be present, may not.
++ private final Cache<Long, Block> writeCache ;
++
++ // Also enable the logging level.
++ public static boolean globalLogging = false ;
++ private boolean logging = false ;
++ // ---- stats
++ long cacheReadHits = 0 ;
++ long cacheMisses = 0 ;
++ long cacheWriteHits = 0 ;
++
++ static BlockMgr create(int readSlots, int writeSlots, final BlockMgr blockMgr) {
++ if ( readSlots < 0 && writeSlots < 0 )
++ return blockMgr ;
++ return new BlockMgrCache(readSlots, writeSlots, blockMgr) ;
++ }
++
++ private BlockMgrCache(int readSlots, int writeSlots, final BlockMgr blockMgr) {
++ super(blockMgr) ;
++ // Caches are related so we can't use a Getter for cache management.
++ if ( readSlots < -1 )
++ readCache = CacheFactory.createNullCache() ;
++ else
++ readCache = CacheFactory.createCache(readSlots) ;
++ if ( writeSlots <= 0 )
++ writeCache = null ;
++ else {
++ writeCache = CacheFactory.createCache(writeSlots) ;
++ writeCache.setDropHandler((id, block) -> {
++ // We're inside a synchronized operation at this point.
++ log("Cache spill: write block: %d", id) ;
++ if ( block == null ) {
++ log.warn("Write cache: " + id + " dropping an entry that isn't there") ;
++ return ;
++ }
++ // Force the block to be writtern
++ // by sending it to the wrapped BlockMgr
++ BlockMgrCache.super.write(block) ;
++ }) ;
++ }
++ }
++
++ @Override
++ synchronized public void resetAlloc(long boundary) {
++ // On abort, need to clear the caches of inaccesible blocks.
++ // An abort is rare (?). We do very carefully.
++ // Could (probably) delete in the loop or use Iteator.remove on keys().
++ // (Check the Cache contract)
++ List<Long> removals = new ArrayList<>() ;
++ readCache.keys().forEachRemaining((x)->{
++ if ( x >= boundary )
++ removals.add(x) ;
++ }) ;
++ removals.forEach(readCache::remove) ;
++ removals.clear() ;
++ writeCache.keys().forEachRemaining((x)->{
++ if ( x >= boundary )
++ removals.add(x) ;
++ }) ;
++ removals.forEach(writeCache::remove) ;
++ super.resetAlloc(boundary);
++ }
++
++ @Override
++ synchronized public Block getRead(long id) {
++ // A Block may be in the read cache or the write cache.
++ // It can be just in the write cache because the read cache is finite.
++ Block blk = readCache.getIfPresent(id) ;
++ if ( blk != null ) {
++ cacheReadHits++ ;
++ log("Hit(r->r) : %d", id) ;
++ return blk ;
++ }
++
++ // A requested block may be in the other cache.
++ // Writable blocks are readable.
++ // readable blocks are not writeable (see below).
++ if ( writeCache != null )
++ // Might still be in the dirty blocks.
++ // Leave in write cache
++ blk = writeCache.getIfPresent(id) ;
++ if ( blk != null ) {
++ cacheWriteHits++ ;
++ log("Hit(r->w) : %d", id) ;
++ return blk ;
++ }
++
++ cacheMisses++ ;
++ log("Miss/r: %d", id) ;
++ blk = super.getRead(id) ;
++ readCache.put(id, blk) ;
++ return blk ;
++ }
++
++ @Override
++ synchronized public Block getWrite(long _id) {
++ Long id = _id ;
++ Block blk = null ;
++ if ( writeCache != null )
++ blk = writeCache.getIfPresent(id) ;
++ if ( blk != null ) {
++ cacheWriteHits++ ;
++ log("Hit(w->w) : %d", id) ;
++ return blk ;
++ }
++
++ // blk is null.
++ // A requested block may be in the other cache. Promote it.
++
++ if ( readCache.containsKey(id) ) {
++ blk = readCache.getIfPresent(id) ;
++ cacheReadHits++ ;
++ log("Hit(w->r) : %d", id) ;
++ blk = promote(blk) ;
++ return blk ;
++ }
++
++ // Did not find.
++ cacheMisses++ ;
++ log("Miss/w: %d", id) ;
++ // Pass operation to wrapper.
++ blk = super.getWrite(id) ;
++ if ( writeCache != null )
++ writeCache.put(id, blk) ;
++ return blk ;
++ }
++
++ @Override
++ synchronized public Block promote(Block block) {
++ Long id = block.getId() ;
++ readCache.remove(id) ;
++ Block block2 = super.promote(block) ;
++ if ( writeCache != null )
++ writeCache.put(id, block2) ;
++ return block ;
++ }
++
++ @Override
++ synchronized public void write(Block block) {
++ writeCache(block) ;
++ super.write(block) ;
++ }
++
++ @Override
++ synchronized public void overwrite(Block block) {
++ Long id = block.getId() ;
++ // It can be a read block (by the transaction), now being written for
++ // real (enacting a transaction).
++ super.overwrite(block) ;
++ // Keep read cache up-to-date.
++ // Must at least expel the read block (which is not the overwrite
++ // block).
++ readCache.put(id, block) ;
++ }
++
++ private void writeCache(Block block) {
++ Long id = block.getId() ;
++ log("WriteCache : %d", id) ;
++ // Should not be in the read cache due to a getWrite earlier.
++ if ( readCache.containsKey(id) )
++ log.warn("write: Block in the read cache") ;
++ if ( writeCache != null ) {
++ writeCache.put(id, block) ;
++ return ;
++ }
++ }
++
++ @Override
++ synchronized public void free(Block block) {
++ Long id = block.getId() ;
++ log("Free : %d", id) ;
++ if ( readCache.containsKey(id) ) {
++ log.warn("Freeing block from read cache") ;
++ readCache.remove(id) ;
++ }
++ if ( writeCache != null )
++ writeCache.remove(id) ;
++ super.free(block) ;
++ }
++
++ @Override
++ synchronized public void sync() {
++ _sync(false) ;
++ }
++
++ @Override
++ synchronized public void syncForce() {
++ _sync(true) ;
++ }
++
++ @Override
++ synchronized public void close() {
++ if ( writeCache != null )
++ log("close (" + writeCache.size() + " blocks)") ;
++ syncFlush() ;
++ super.close() ;
++ }
++
++ @Override
++ public String toString() {
++ return "Cache:" + super.blockMgr.toString() ;
++ }
++
++ private void log(String fmt, Object... args) {
++ if ( !logging && !globalLogging )
++ return ;
++ String msg = String.format(fmt, args) ;
++ if ( getLabel() != null )
++ msg = getLabel() + " : " + msg ;
++ log.debug(msg) ;
++ }
++
++ private void _sync(boolean force) {
++ if ( true ) {
++ String x = "" ;
++ if ( getLabel() != null )
++ x = getLabel() + " : " ;
++ log("%sH=%d, M=%d, W=%d", x, cacheReadHits, cacheMisses, cacheWriteHits) ;
++ }
++
++ if ( writeCache != null )
++ log("sync (%d blocks)", writeCache.size()) ;
++ else
++ log("sync") ;
++ boolean somethingWritten = syncFlush() ;
++
++ if ( force ) {
++ log("syncForce underlying BlockMgr") ;
++ super.syncForce() ;
++ } else if ( somethingWritten ) {
++ log("sync underlying BlockMgr") ;
++ super.sync() ;
++ } else
++ log("Empty sync") ;
++ }
++
++ private boolean syncFlush() {
++ if ( writeCache == null )
++ return false ;
++
++ boolean didSync = false ;
++
++ log("Flush (write cache)") ;
++
++ long N = writeCache.size() ;
++ Long[] ids = new Long[(int)N] ;
++
++ // Single writer (sync is a write operation MRSW)
++ // Iterating is safe.
++
++ Iterator<Long> iter = writeCache.keys() ;
++ if ( iter.hasNext() )
++ didSync = true ;
++
++ // Need to get all then delete else concurrent modification exception.
++ for ( int i = 0 ; iter.hasNext() ; i++ )
++ ids[i] = iter.next() ;
++
++ for ( int i = 0 ; i < N ; i++ ) {
++ Long id = ids[i] ;
++ expelEntry(id) ;
++ }
++ if ( didSync )
++ super.sync() ;
++ return didSync ;
++ }
++
++ // Write out when flushed.
++ // Do not call from drop handler.
++ private void expelEntry(Long id) {
++ Block block = writeCache.getIfPresent(id) ;
++ if ( block == null ) {
++ log.warn("Write cache: " + id + " expelling entry that isn't there") ;
++ return ;
++ }
++ log("Expel (write cache): %d", id) ;
++ // This pushes the block to the BlockMgr being cached.
++ super.write(block) ;
++ writeCache.remove(id) ;
++
++ // Move it into the readCache because it's often read after writing
++ // and the read cache is often larger.
++ readCache.put(id, block) ;
++ }
++}
[16/50] [abbrv] jena git commit: [maven-release-plugin] prepare for
next development iteration
Posted by an...@apache.org.
[maven-release-plugin] prepare for next development iteration
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/dcfa94e1
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/dcfa94e1
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/dcfa94e1
Branch: refs/heads/jena-tdb2
Commit: dcfa94e1e3854ebfbdd1e106c110c29215ec48cb
Parents: a23065e
Author: Andy Seaborne <an...@seaborne.org>
Authored: Mon Sep 4 12:56:37 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Mon Sep 4 12:56:37 2017 +0100
----------------------------------------------------------------------
dboe-base/pom.xml | 2 +-
dboe-index-test/pom.xml | 4 ++--
dboe-index/pom.xml | 4 ++--
dboe-trans-data/pom.xml | 10 +++++-----
dboe-transaction/pom.xml | 4 ++--
fuseki-tdb2/pom.xml | 4 ++--
pom.xml | 4 ++--
tdb2-cmds/pom.xml | 4 ++--
tdb2/pom.xml | 4 ++--
9 files changed, 20 insertions(+), 20 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/dcfa94e1/dboe-base/pom.xml
----------------------------------------------------------------------
diff --git a/dboe-base/pom.xml b/dboe-base/pom.xml
index 4179450..986c95f 100644
--- a/dboe-base/pom.xml
+++ b/dboe-base/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</parent>
<dependencies>
http://git-wip-us.apache.org/repos/asf/jena/blob/dcfa94e1/dboe-index-test/pom.xml
----------------------------------------------------------------------
diff --git a/dboe-index-test/pom.xml b/dboe-index-test/pom.xml
index 48c1b63..b06a773 100644
--- a/dboe-index-test/pom.xml
+++ b/dboe-index-test/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</parent>
<dependencies>
@@ -34,7 +34,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-index</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/jena/blob/dcfa94e1/dboe-index/pom.xml
----------------------------------------------------------------------
diff --git a/dboe-index/pom.xml b/dboe-index/pom.xml
index dcc92cb..28943de 100644
--- a/dboe-index/pom.xml
+++ b/dboe-index/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</parent>
<dependencies>
@@ -34,7 +34,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-base</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</dependency>
</dependencies>
http://git-wip-us.apache.org/repos/asf/jena/blob/dcfa94e1/dboe-trans-data/pom.xml
----------------------------------------------------------------------
diff --git a/dboe-trans-data/pom.xml b/dboe-trans-data/pom.xml
index a579aa4..50756aa 100644
--- a/dboe-trans-data/pom.xml
+++ b/dboe-trans-data/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</parent>
<dependencies>
@@ -33,26 +33,26 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-transaction</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-index</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-index-test</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-base</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
http://git-wip-us.apache.org/repos/asf/jena/blob/dcfa94e1/dboe-transaction/pom.xml
----------------------------------------------------------------------
diff --git a/dboe-transaction/pom.xml b/dboe-transaction/pom.xml
index f45beb7..8c4b21f 100644
--- a/dboe-transaction/pom.xml
+++ b/dboe-transaction/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</parent>
<dependencies>
@@ -33,7 +33,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-base</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</dependency>
</dependencies>
http://git-wip-us.apache.org/repos/asf/jena/blob/dcfa94e1/fuseki-tdb2/pom.xml
----------------------------------------------------------------------
diff --git a/fuseki-tdb2/pom.xml b/fuseki-tdb2/pom.xml
index 6c3383c..8205005 100644
--- a/fuseki-tdb2/pom.xml
+++ b/fuseki-tdb2/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</parent>
<packaging>jar</packaging>
@@ -36,7 +36,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>tdb2</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/jena/blob/dcfa94e1/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 72b8aba..9be78e4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
<artifactId>mantis</artifactId>
<packaging>pom</packaging>
<url>https://github.com/afs/mantis</url>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
<name>Mantis :: Database Operation Environment</name>
<description>Mantis :: Database Operation Environment</description>
@@ -56,7 +56,7 @@
<url>https://github.com/afs/mantis</url>
<connection>scm:git:https://github.com/afs/mantis</connection>
<developerConnection>scm:git:git@github.com:afs/mantis.git</developerConnection>
- <tag>mantis-0.3.0</tag>
+ <tag>HEAD</tag>
</scm>
<properties>
http://git-wip-us.apache.org/repos/asf/jena/blob/dcfa94e1/tdb2-cmds/pom.xml
----------------------------------------------------------------------
diff --git a/tdb2-cmds/pom.xml b/tdb2-cmds/pom.xml
index 9885c77..d55b4c8 100644
--- a/tdb2-cmds/pom.xml
+++ b/tdb2-cmds/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</parent>
<dependencies>
@@ -35,7 +35,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>tdb2</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/jena/blob/dcfa94e1/tdb2/pom.xml
----------------------------------------------------------------------
diff --git a/tdb2/pom.xml b/tdb2/pom.xml
index 886e2da..80cfc5a 100644
--- a/tdb2/pom.xml
+++ b/tdb2/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</parent>
<dependencies>
@@ -43,7 +43,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-trans-data</artifactId>
- <version>0.3.0</version>
+ <version>0.3.1-SNAPSHOT</version>
</dependency>
<dependency>
[03/50] [abbrv] jena git commit: Switchable conatiner datasets
Posted by an...@apache.org.
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 ;
+ }
+}
[39/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/ComponentIds.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/ComponentIds.java
index 0000000,0000000..b7f27dc
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/ComponentIds.java
@@@ -1,0 -1,0 +1,61 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++
++/** Some fixed, marker, {@link ComponentId}s */
++public class ComponentIds {
++
++ public static final ComponentId idNull = make("Monitor", -9999) ;
++ public static final ComponentId idSystem = make("System", -9988) ;
++
++ private static ComponentId make(String string, int v) {
++ return ComponentId.alloc(string, null, v) ;
++ }
++
++
++//
++// // Linux : "uuid -v 4"
++//
++// /* For single instance components and base ids for incremental registration */
++// public static final ComponentId idTxnMRSW = make("MRSW", "93a58341-ed53-4f0c-bac1-d9969ea38cf3") ;
++// // TODO tie to registration (this predates)
++// public static final ComponentId idTxnCounter = make("Counter", "6b901671-e6db-45c5-9217-7506d21a0000") ;
++// public static final ComponentId idMonitor = make("Monitor", "c4d8a1e6-052b-413a-8d80-c5a6b442e608") ;
++// public static final ComponentId idNull = make("Monitor", "e6e31271-b6dc-452c-b624-d4e099464365") ;
++// public static final ComponentId idSystem = make("System", "95e0f729-ad29-48b2-bd70-e3738663c578") ;
++// public static final ComponentId idBlobBase = make("Blob", "43436b91-87ce-4d6b-827c-c3b9ea6536ba") ;
++// public static final ComponentId idDev = make("Blob", "82a6833a-1475-495a-83ca-10370c7c40cd") ;
++//
++// public static ComponentId make(String label, String uuidStr) {
++// byte[] bytes = L.uuidAsBytes(uuidStr) ;
++// return ComponentId.create(label, bytes) ;
++// }
++
++ /* For later
++ 82a6833a-1475-495a-83ca-10370c7c40cd
++ 1d32231b-aa11-47ed-8893-6b36673fe04c
++ 27c4845e-c05a-410d-8c74-278a23b03bbd
++ f841ba46-a297-487d-b622-dd452c888dab
++ 09efba54-7428-4689-929d-b1719a56c345
++ a9fbdc3c-442d-4086-8f40-b6ef773871b9
++ */
++
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/PrepareState.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/PrepareState.java
index 0000000,0000000..9f4431e
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/PrepareState.java
@@@ -1,0 -1,0 +1,40 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import java.nio.ByteBuffer ;
++
++final
++public class PrepareState {
++ private final ComponentId component ;
++ private final ByteBuffer data ;
++
++ public /*For testing*/ PrepareState(ComponentId compoent, ByteBuffer data) {
++ this.component = compoent ;
++ this.data = data ;
++ }
++
++ public ComponentId getComponent() {
++ return component ;
++ }
++
++ public ByteBuffer getData() {
++ return data ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/QuorumGenerator.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/QuorumGenerator.java
index 0000000,0000000..3303c30
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/QuorumGenerator.java
@@@ -1,0 -1,0 +1,27 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import org.apache.jena.query.ReadWrite ;
++
++/** Generate a transaction quorum for a transaction as it begins */
++public interface QuorumGenerator {
++ public ComponentGroup genQuorum(ReadWrite mode) ;
++}
++
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/StateMgrBase.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/StateMgrBase.java
index 0000000,0000000..2a78548
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/StateMgrBase.java
@@@ -1,0 -1,0 +1,175 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import java.nio.ByteBuffer ;
++
++import org.apache.jena.atlas.lib.Closeable ;
++import org.apache.jena.atlas.lib.Sync ;
++import org.seaborne.dboe.base.file.BufferChannel ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/** Helper class for the manage the persistent state of a transactional.
++ * The persistent state is assumed to be a fixed size, or at least
++ * of known maximum size.
++ * May not be suitable for all transactional component implementations.
++ */
++
++public abstract class StateMgrBase implements Sync, Closeable {
++ /* Compare to TransBlob which is a similar idea but where it is a
++ * component in the transaction component group. That can lead to
++ * the wrong control, or at least unclear, of the writing during
++ * the transaction commit cycle.
++ */
++
++ private static Logger log = LoggerFactory.getLogger(StateMgrBase.class) ;
++
++ private final BufferChannel storage ;
++ // One ByteBuffer that is reused where possible.
++ // This is short-term usage
++ // * get disk state-> deserialize
++ // * serialize->set disk state
++ // on a single thread (the transaction writer).
++ private ByteBuffer bb ;
++ // Is the internal state out of sync with the disk state?
++ private boolean dirty = false ;
++
++ protected StateMgrBase(BufferChannel storage, int sizeBytes) {
++ bb = ByteBuffer.allocate(sizeBytes) ;
++ this.storage = storage ;
++ }
++
++ /**
++ * After the default initial state is known, call this, for example, at the
++ * end of the constructor. If no on-disk state is found, a clean copy is written.
++ */
++ protected void init() {
++ if ( ! storage.isEmpty() )
++ readState() ;
++ else
++ writeState() ;
++ }
++
++ /* Serialize the necessary state into a ByteBuffer.
++ * The argument ByteBuffer can be used or a new one returned
++ * if it is the wrong size (e.g. too small). The returned one will become the
++ * recycled ByteBuffer. The returned ByteBuffer should have posn/limit
++ * delimiting the necessary space to write.
++ */
++ protected abstract ByteBuffer serialize(ByteBuffer bytes) ;
++
++ /*
++ * Deserialize the persistent state from the ByteBuffer (delimited by posn/limit).
++ * The byte buffer will be the recycled one from last time.
++ * Most
++ */
++ protected abstract void deserialize(ByteBuffer bytes) ;
++
++ /** Note that the in-memory state is not known to be the same
++ * as the on-disk state.
++ */
++ protected void setDirtyFlag() {
++ dirty = true ;
++ }
++
++ /**
++ * Event call for state writing. Called after successful
++ * writing of the state.
++ */
++ protected abstract void writeStateEvent() ;
++
++ /**
++ * Event call for state reading. Called after successful
++ * deserializing of the state.
++ */
++ protected abstract void readStateEvent() ;
++
++ /** Note that the in-memory state is the same
++ * as the on-disk state, or at least the on-disk state is
++ * acceptable for restart at any time.
++ */
++ protected void clearDirtyFlag() {
++ dirty = false ;
++ }
++
++ /** Low level control - for example, used for cloning setup.
++ * Use with care.
++ */
++ public BufferChannel getBufferChannel() {
++ return storage ;
++ }
++
++ /** Return the serialized state using the internal ByteBuffer
++ * Typically called by "prepare" for the bytes to write to the journal.
++ * Calls {@link #serialize}.
++ * This method does not perform an external I/O.
++ */
++ public ByteBuffer getState() {
++ bb.rewind() ;
++ serialize(bb) ;
++ return bb ;
++ }
++
++ /** Set the in-memory state from a ByteBuffer, for example, from journal recovery.
++ * This method does not perform an external I/O.
++ * Call "writeState" to put the n-memory state as the disk state.
++ */
++ public void setState(ByteBuffer buff) {
++ buff.rewind() ;
++ deserialize(buff) ;
++ dirty = true ;
++ }
++
++ //public BufferChannel getChannel() { return storage ; }
++
++ /** The write process : serialize, write, sync,
++ * After this, the bytes definitely are on disk, not in some OS cache
++ */
++ public void writeState() {
++ bb.rewind() ;
++ ByteBuffer bb1 = serialize(bb) ;
++ if ( bb1 != null )
++ bb = bb1 ;
++ bb.rewind() ;
++ int len = storage.write(bb, 0) ;
++ storage.sync() ;
++ dirty = false ;
++ writeStateEvent() ;
++ }
++
++ /** The read process : get all bytes on disk, deserialize */
++ public void readState() {
++ bb.rewind() ;
++ int len = storage.read(bb, 0) ;
++ bb.rewind() ;
++ deserialize(bb) ;
++ readStateEvent() ;
++ }
++
++ @Override
++ public void sync() {
++ if ( dirty )
++ writeState() ;
++ }
++
++ @Override
++ public void close() {
++ storage.close() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/StateMgrData.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/StateMgrData.java
index 0000000,0000000..17db3be
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/StateMgrData.java
@@@ -1,0 -1,0 +1,87 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import java.nio.ByteBuffer ;
++import java.util.Arrays ;
++
++import org.seaborne.dboe.base.file.BufferChannel ;
++
++/** StateManagement for a number of long values, a common need
++ * (might as well store ints as long on disk
++ * for small numbers of integers)
++ */
++public class StateMgrData extends StateMgrBase {
++ private final long[] data ;
++
++ public StateMgrData(BufferChannel storage, long... initialData) {
++ super(storage, numBytes(initialData)) ;
++ data = copy(initialData) ;
++ super.init() ;
++ }
++
++ @Override
++ protected void init() { throw new TransactionException("Don't call init()") ; }
++
++ private static long[] copy(long[] data) { return Arrays.copyOf(data, data.length) ; }
++
++ private static int numBytes(long[] data) { return data.length * Long.BYTES ; }
++
++ // Protected - leave whether to expose these operations as "public"
++ // to the subclass. A subclass may choose instead to make these
++ // to more meaningful names, or ensure that daat consistentecny rules are applied.
++
++ protected long[] getData() {
++ return copy(data) ;
++ }
++
++ protected void setData(long... newData) {
++ if ( newData.length != data.length )
++ throw new IllegalArgumentException() ;
++ System.arraycopy(newData, 0, data, 0, data.length);
++ }
++
++ protected long get(int i) {
++ return data[i] ;
++ }
++
++ protected void set(int i, long v) {
++ data[i] = v ;
++ super.setDirtyFlag() ;
++ }
++
++ @Override
++ protected ByteBuffer serialize(ByteBuffer bytes) {
++ for ( int i = 0 ; i < data.length ; i++ )
++ bytes.putLong(data[i]) ;
++ return bytes ;
++ }
++
++ @Override
++ protected void deserialize(ByteBuffer bytes) {
++ for ( int i = 0 ; i < data.length ; i++ )
++ data[i] = bytes.getLong() ;
++ }
++
++ @Override
++ protected void writeStateEvent() {}
++
++ @Override
++ protected void readStateEvent() {}
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/StateMgrDataIdx.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/StateMgrDataIdx.java
index 0000000,0000000..8f1c818
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/StateMgrDataIdx.java
@@@ -1,0 -1,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.dboe.transaction.txn;
++
++import org.seaborne.dboe.base.file.BufferChannel ;
++
++/** StateManagement for a number of long values,
++ * state accessed by index.
++ */
++public final class StateMgrDataIdx extends StateMgrData {
++ public StateMgrDataIdx(BufferChannel storage, long... initialData) {
++ super(storage, initialData) ;
++ }
++
++ // Expose these operations as public
++
++ @Override
++ public long[] getData() { return super.getData() ; }
++
++ @Override
++ public void setData(long... newData) { super.setData(newData); }
++
++ @Override
++ public long get(int i) { return super.get(i) ; }
++
++ @Override
++ public void set(int i, long v) { super.set(i, v); }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/SysTrans.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/SysTrans.java
index 0000000,0000000..091b635
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/SysTrans.java
@@@ -1,0 -1,0 +1,52 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import java.nio.ByteBuffer ;
++
++/** Single component aspect of a transaction */
++final
++class SysTrans {
++ private final TransactionalComponent elt ;
++ private final Transaction transaction ;
++ private final TxnId txnId ;
++
++ public SysTrans(TransactionalComponent elt, Transaction transaction, TxnId txnId) {
++ this.elt = elt ;
++ this.transaction = transaction ;
++ this.txnId = txnId ;
++ }
++
++ public void begin() { }
++ public boolean promote() { return elt.promote(transaction) ; }
++
++ public ByteBuffer commitPrepare() { return elt.commitPrepare(transaction) ; }
++
++ public void commit() { elt.commit(transaction); }
++
++ public void commitEnd() { elt.commitEnd(transaction); }
++
++ public void abort() { elt.abort(transaction); }
++
++ public void complete() { elt.complete(transaction); }
++
++ public Transaction getTransaction() { return transaction ; }
++ public TxnId getTxnId() { return txnId ; }
++ public TransactionalComponent getComponent() { return elt ; }
++ public ComponentId getComponentId() { return elt.getComponentId() ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/SysTransState.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/SysTransState.java
index 0000000,0000000..8bf9e5c
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/SysTransState.java
@@@ -1,0 -1,0 +1,35 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++/** State for one detached components. */
++public class SysTransState {
++ private final TransactionalComponent elt ;
++ private final Transaction transaction ;
++ private final Object state ;
++
++ public SysTransState(TransactionalComponent elt, Transaction transaction, Object state) {
++ this.elt = elt ;
++ this.transaction = transaction ;
++ this.state = state ;
++ }
++
++ public TransactionalComponent getComponent() { return elt ; }
++ public Transaction getTransaction() { return transaction ; }
++ public Object getState() { return state ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/Transaction.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/Transaction.java
index 0000000,0000000..8f17352
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/Transaction.java
@@@ -1,0 -1,0 +1,294 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import static org.seaborne.dboe.transaction.txn.TxnState.ABORTED;
++import static org.seaborne.dboe.transaction.txn.TxnState.ACTIVE;
++import static org.seaborne.dboe.transaction.txn.TxnState.COMMIT;
++import static org.seaborne.dboe.transaction.txn.TxnState.COMMITTED;
++import static org.seaborne.dboe.transaction.txn.TxnState.DETACHED;
++import static org.seaborne.dboe.transaction.txn.TxnState.END_ABORTED;
++import static org.seaborne.dboe.transaction.txn.TxnState.END_COMMITTED;
++import static org.seaborne.dboe.transaction.txn.TxnState.INACTIVE;
++import static org.seaborne.dboe.transaction.txn.TxnState.PREPARE;
++
++import java.util.List ;
++import java.util.Objects ;
++import java.util.concurrent.atomic.AtomicReference ;
++
++import org.apache.jena.query.ReadWrite ;
++
++/**
++ * A transaction as the composition of actions on components.
++ * Works in conjunction with the TransactionCoordinator
++ * to provide the transaction lifecycle.
++ * @see TransactionCoordinator
++ * @see TransactionalComponent
++ */
++final
++public class Transaction implements TransactionInfo {
++ // Using an AtomicReference<TxnState> requires that
++ // TransactionalComponentLifecycle.internalComplete
++ // frees the thread local for the threadTxn, otherwise memory
++ // usage grows. If a plain member variable is used slow growth
++ // is still seen.
++ // Nulling txnMgr and clearing components stops that slow growth.
++
++ private TransactionCoordinator txnMgr ;
++ private final TxnId txnId ;
++ private final List<SysTrans> components ;
++
++ // Using an AtomicReference makes this observable from the outside.
++ // It also allow for multithreaded transactions (later).
++ private final AtomicReference<TxnState> state = new AtomicReference<>() ;
++ //private TxnState state ;
++ private long dataVersion ;
++ private ReadWrite mode ;
++
++ public Transaction(TransactionCoordinator txnMgr, TxnId txnId, ReadWrite readWrite, long dataVersion, List<SysTrans> components) {
++ Objects.requireNonNull(txnMgr) ;
++ Objects.requireNonNull(txnId) ;
++ Objects.requireNonNull(readWrite) ;
++ Objects.requireNonNull(components) ;
++ this.txnMgr = txnMgr ;
++ this.txnId = txnId ;
++ this.mode = readWrite ;
++ this.dataVersion = dataVersion ;
++ this.components = components ;
++ setState(INACTIVE) ;
++ }
++
++ /*package*/ void resetDataVersion(long dataVersion) {
++ this.dataVersion = dataVersion;
++ }
++
++ /*package*/ void setState(TxnState newState) {
++ state.set(newState) ;
++ }
++
++ @Override
++ public TxnState getState() {
++ return state.get() ;
++ }
++
++ /**
++ * Each transaction is allocated a serialization point by the transaction
++ * coordinator. Normally, this is related to this number and it increases
++ * over time as the data changes. Two readers can have the same
++ * serialization point - they are working with the same view of the data.
++ */
++ @Override
++ public long getDataVersion() {
++ return dataVersion ;
++ }
++
++ public void begin() {
++ checkState(INACTIVE);
++ components.forEach((c) -> c.begin()) ;
++ setState(ACTIVE) ;
++ }
++
++ public boolean promote() {
++ checkState(ACTIVE);
++ boolean b = txnMgr.promoteTxn(this) ;
++ if ( !b )
++ return false ;
++ mode = ReadWrite.WRITE;
++ return true ;
++ }
++
++ /*package*/ void promoteComponents() {
++ // Call back from the Transaction coordinator during promote.
++ components.forEach((c) -> {
++ if ( ! c.promote() )
++ throw new TransactionException("Failed to promote") ;
++ }) ;
++ mode = ReadWrite.WRITE ;
++ }
++
++ public void notifyUpdate() {
++ checkState(ACTIVE) ;
++ if ( mode == ReadWrite.READ ) {
++ System.err.println("notifyUpdate - promote needed") ;
++ promote() ;
++ mode = ReadWrite.WRITE ;
++ }
++ }
++
++ public void prepare() {
++ checkState(ACTIVE) ;
++ if ( mode == ReadWrite.WRITE )
++ txnMgr.executePrepare(this) ;
++ setState(PREPARE);
++ }
++
++ public void commit() {
++ // Split into READ and WRITE forms.
++ TxnState s = getState();
++ if ( s == ACTIVE )
++ // Auto exec prepare().
++ prepare() ;
++ checkState(PREPARE) ;
++ setState(COMMIT) ;
++ switch(mode) {
++ case WRITE:
++ txnMgr.executeCommit(this,
++ ()->{components.forEach((c) -> c.commit()) ; } ,
++ ()->{components.forEach((c) -> c.commitEnd()) ; } ) ;
++ break ;
++ case READ:
++ // Different lifecycle?
++ txnMgr.executeCommit(this,
++ ()->{components.forEach((c) -> c.commit()) ; } ,
++ ()->{components.forEach((c) -> c.commitEnd()) ; } ) ;
++ break ;
++ }
++ setState(COMMITTED) ;
++ }
++
++ public void abort() {
++ abort$();
++ endInternal() ;
++ }
++
++ private void abort$() {
++ // Split into READ and WRITE forms.
++ checkState(ACTIVE, ABORTED) ;
++ // Includes notification start/finish
++ txnMgr.executeAbort(this, ()-> { components.forEach((c) -> c.abort()) ; }) ;
++ setState(ABORTED) ;
++ }
++
++ public void end() {
++ txnMgr.notifyEndStart(this) ;
++ if ( isWriteTxn() && getState() == ACTIVE ) {
++ throw new TransactionException("Write transaction with no commit or abort") ;
++ //Log.warn(this, "Write transaction with no commit() or abort() before end()");
++ // Just the abort process.
++ //abort$() ;
++ }
++ endInternal() ;
++ txnMgr.notifyEndFinish(this) ;
++ txnMgr = null ;
++ //components.clear() ;
++ }
++
++ private void endInternal() {
++ if ( hasFinalised() )
++ return ;
++ // Called once, at the first abort/commit/end.
++ txnMgr.notifyCompleteStart(this);
++ components.forEach((c) -> c.complete()) ;
++ txnMgr.completed(this) ;
++ if ( getState() == COMMITTED )
++ setState(END_COMMITTED);
++ else
++ setState(END_ABORTED);
++ txnMgr.notifyCompleteFinish(this);
++ }
++
++ /*package*/ List<SysTrans> getComponents() {
++ return components ;
++ }
++
++ /*package*/ void detach() {
++ checkState(ACTIVE,PREPARE) ;
++ setState(DETACHED) ;
++ }
++
++ /*package*/ void attach() {
++ checkState(DETACHED) ;
++ setState(ACTIVE) ;
++ }
++
++ public void requireWriteTxn() {
++ checkState(ACTIVE) ;
++ if ( mode != ReadWrite.WRITE )
++ throw new TransactionException("Not a write transaction") ;
++ }
++
++ @Override
++ public boolean hasStarted() {
++ TxnState x = getState() ;
++ return x == INACTIVE ;
++ }
++
++ @Override
++ public boolean hasFinished() {
++ TxnState x = getState() ;
++ return x == COMMITTED || x == ABORTED || x == END_COMMITTED || x == END_ABORTED ;
++ }
++
++ @Override
++ public boolean hasFinalised() {
++ TxnState x = getState() ;
++ return x == END_COMMITTED || x == END_ABORTED ;
++ }
++
++ @Override
++ public TxnId getTxnId() { return txnId ; }
++
++ @Override
++ public ReadWrite getMode() { return mode ; }
++
++ /** Is this a READ transaction?
++ * Convenience operation equivalent to {@code (getMode() == READ)}
++ */
++ @Override
++ public boolean isReadTxn() { return mode == ReadWrite.READ ; }
++
++ /** Is this a WRITE transaction?
++ * Convenience operation equivalent to {@code (getMode() == WRITE)}
++ */
++ @Override
++ public boolean isWriteTxn() { return mode == ReadWrite.WRITE ; }
++
++ // hashCode/equality
++ // These must be object equality. No two transactions objects are .equals unless they are ==
++
++ private void checkWriteTxn() {
++ if ( ! isActiveTxn() || ! isWriteTxn() )
++ throw new TransactionException("Not in a write transaction") ;
++ }
++
++ // XXX Duplicate -- TransactionalComponentLifecycle
++ private void checkState(TxnState expected) {
++ TxnState s = getState();
++ if ( s != expected )
++ throw new TransactionException("Transaction is in state "+s+": expected state "+expected) ;
++ }
++
++ private void checkState(TxnState expected1, TxnState expected2) {
++ TxnState s = getState();
++ if ( s != expected1 && s != expected2 )
++ throw new TransactionException("Transaction is in state "+s+": expected state "+expected1+" or "+expected2) ;
++ }
++
++ // Avoid varargs ... undue worry?
++ private void checkState(TxnState expected1, TxnState expected2, TxnState expected3) {
++ TxnState s = getState();
++ if ( s != expected1 && s != expected2 && s != expected3 )
++ throw new TransactionException("Transaction is in state "+s+": expected state "+expected1+", "+expected2+" or "+expected3) ;
++ }
++
++ @Override
++ public boolean isActiveTxn() {
++ return getState() != INACTIVE ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionCoordinator.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionCoordinator.java
index 0000000,0000000..cede020
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionCoordinator.java
@@@ -1,0 -1,0 +1,804 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import static org.apache.jena.query.ReadWrite.WRITE ;
++import static org.seaborne.dboe.transaction.txn.journal.JournalEntryType.UNDO ;
++
++import java.nio.ByteBuffer ;
++import java.util.ArrayList ;
++import java.util.Iterator ;
++import java.util.List ;
++import java.util.Objects ;
++import java.util.concurrent.ConcurrentHashMap ;
++import java.util.concurrent.Semaphore ;
++import java.util.concurrent.atomic.AtomicLong ;
++import java.util.concurrent.locks.ReadWriteLock ;
++import java.util.concurrent.locks.ReentrantReadWriteLock ;
++
++import org.apache.jena.atlas.logging.Log ;
++import org.apache.jena.query.ReadWrite ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.sys.Sys ;
++import org.seaborne.dboe.transaction.txn.journal.Journal ;
++import org.seaborne.dboe.transaction.txn.journal.JournalEntry ;
++import org.slf4j.Logger ;
++
++/**
++ * One {@code TransactionCoordinator} per group of {@link TransactionalComponent}s.
++ * {@link TransactionalComponent}s can not be shared across TransactionCoordinators.
++ * <p>
++ * This is a general engine although tested and most used for multiple-reader
++ * and single-writer (MR+SW). {@link TransactionalComponentLifecycle} provides the
++ * per-threadstyle.
++ * <p>
++ * Contrast to MRSW: multiple-reader or single-writer.
++ * <h3>Block writers</h3>
++ * Block until no writers are active.
++ * When this returns, this guarantees that the database is not changing
++ * and the journal is flushed to disk.
++ * <p>
++ * See {@link #blockWriters()}, {@link #enableWriters()}, {@link #execAsWriter(Runnable)}
++ * <h3>Excluisve mode</h3>
++ * Exclusive mode is when the current thread is the only active code : no readers, no writers.
++ * <p>
++ * See {@link #startExclusiveMode()}/{@link #tryExclusiveMode()} {@link #finishExclusiveMode()}, {@link #execExclusive(Runnable)}
++ *
++ * @see Transaction
++ * @see TransactionalComponent
++ * @see TransactionalSystem
++ */
++final
++public class TransactionCoordinator {
++ private static Logger log = Sys.syslog ;
++
++ private final Journal journal ;
++ private boolean coordinatorStarted = false ;
++
++ private final ComponentGroup components = new ComponentGroup() ;
++ // Components
++ private ComponentGroup txnComponents = null ;
++ private List<ShutdownHook> shutdownHooks ;
++ private TxnIdGenerator txnIdGenerator = TxnIdFactory.txnIdGenSimple ;
++
++ private QuorumGenerator quorumGenerator = null ;
++ //private QuorumGenerator quorumGenerator = (m) -> components ;
++
++ // Semaphore to implement "Single Active Writer" - independent of readers
++ // This is not reentrant.
++ private Semaphore writersWaiting = new Semaphore(1, true) ;
++
++ // All transaction need a "read" lock through out their lifetime.
++ // Do not confuse with read/write transactions. We need a
++ // "one exclusive, or many other" lock which happens to be called ReadWriteLock
++ // See also {@code lock} which protects the datastructures during transaction management.
++ private ReadWriteLock exclusivitylock = new ReentrantReadWriteLock() ;
++
++ // Coordinator wide lock object.
++ private Object coordinatorLock = new Object() ;
++
++ @FunctionalInterface
++ public interface ShutdownHook { void shutdown() ; }
++
++ /** Create a TransactionCoordinator, initially with no associated {@link TransactionalComponent}s */
++ public TransactionCoordinator(Location location) {
++ this(Journal.create(location)) ;
++ }
++
++ /** Create a TransactionCoordinator, initially with no associated {@link TransactionalComponent}s */
++ public TransactionCoordinator(Journal journal) {
++ this(journal, null , new ArrayList<>()) ;
++ }
++
++ /** Create a TransactionCoordinator, initially with {@link TransactionalComponent} in the ComponentGroup */
++ public TransactionCoordinator(Journal journal, List<TransactionalComponent> components) {
++ this(journal, components , new ArrayList<>()) ;
++ }
++
++ // /** Create a TransactionCoordinator, initially with no associated {@link TransactionalComponent}s */
++// public TransactionCoordinator(Location journalLocation) {
++// this(Journal.create(journalLocation), new ArrayList<>() , new ArrayList<>()) ;
++// }
++
++ private TransactionCoordinator(Journal journal, List<TransactionalComponent> txnComp, List<ShutdownHook> shutdownHooks) {
++ this.journal = journal ;
++ this.shutdownHooks = new ArrayList<>(shutdownHooks) ;
++ if ( txnComp != null ) {
++ //txnComp.forEach(x-> System.out.println(x.getComponentId().label()+" :: "+Bytes.asHex(x.getComponentId().bytes()) ) ) ;
++ txnComp.forEach(components::add);
++ }
++ }
++
++ /** Add a {@link TransactionalComponent}.
++ * Safe to call at any time but it is good practice is to add all the
++ * compoents before any transactions start.
++ * Internally, the coordinator ensures the add will safely happen but it
++ * does not add the component to existing transactions.
++ * This must be setup before recovery is attempted.
++ */
++ public TransactionCoordinator add(TransactionalComponent elt) {
++ checkSetup() ;
++ synchronized(coordinatorLock) {
++ components.add(elt) ;
++ }
++ return this ;
++ }
++
++ /**
++ * Remove a {@link TransactionalComponent}.
++ * @see #add
++ */
++ public TransactionCoordinator remove(TransactionalComponent elt) {
++ checkSetup() ;
++ synchronized(coordinatorLock) {
++ components.remove(elt.getComponentId()) ;
++ }
++ return this ;
++ }
++
++ /**
++ * Add a shutdown hook. Shutdown is not guaranteed to be called
++ * and hence hooks may not get called.
++ */
++ public void add(TransactionCoordinator.ShutdownHook hook) {
++ checkSetup() ;
++ synchronized(coordinatorLock) {
++ shutdownHooks.add(hook) ;
++ }
++ }
++
++ /** Remove a shutdown hook */
++ public void remove(TransactionCoordinator.ShutdownHook hook) {
++ checkSetup() ;
++ synchronized(coordinatorLock) {
++ shutdownHooks.remove(hook) ;
++ }
++ }
++
++ public void setQuorumGenerator(QuorumGenerator qGen) {
++ checkSetup() ;
++ this.quorumGenerator = qGen ;
++ }
++
++ public void start() {
++ checkSetup() ;
++ recovery() ;
++ coordinatorStarted = true ;
++ }
++
++ private /*public*/ void recovery() {
++
++ Iterator<JournalEntry> iter = journal.entries() ;
++ if ( ! iter.hasNext() ) {
++ components.forEachComponent(c -> c.cleanStart()) ;
++ return ;
++ }
++
++ log.info("Journal recovery start") ;
++ components.forEachComponent(c -> c.startRecovery()) ;
++
++ // Group to commit
++
++ List<JournalEntry> entries = new ArrayList<>() ;
++
++ iter.forEachRemaining( entry -> {
++ switch(entry.getType()) {
++ case ABORT :
++ entries.clear() ;
++ break ;
++ case COMMIT :
++ recover(entries) ;
++ entries.clear() ;
++ break ;
++ case REDO : case UNDO :
++ entries.add(entry) ;
++ break ;
++ }
++ }) ;
++
++ components.forEachComponent(c -> c.finishRecovery()) ;
++ journal.reset() ;
++ log.info("Journal recovery end") ;
++ }
++
++ private void recover(List<JournalEntry> entries) {
++ entries.forEach(e -> {
++ if ( e.getType() == UNDO ) {
++ Log.warn(TransactionCoordinator.this, "UNDO entry : not handled") ;
++ return ;
++ }
++ ComponentId cid = e.getComponentId() ;
++ ByteBuffer bb = e.getByteBuffer() ;
++ // find component.
++ TransactionalComponent c = components.findComponent(cid) ;
++ if ( c == null ) {
++ Log.warn(TransactionCoordinator.this, "No component for "+cid) ;
++ return ;
++ }
++ c.recover(bb);
++ }) ;
++ }
++
++ public void setTxnIdGenerator(TxnIdGenerator generator) {
++ this.txnIdGenerator = generator ;
++ }
++
++ public Journal getJournal() {
++ return journal ;
++ }
++
++ public TransactionCoordinatorState detach(Transaction txn) {
++ txn.detach();
++ TransactionCoordinatorState coordinatorState = new TransactionCoordinatorState(txn) ;
++ components.forEach((id, c) -> {
++ SysTransState s = c.detach() ;
++ coordinatorState.componentStates.put(id, s) ;
++ } ) ;
++ // The txn still counts as "active" for tracking purposes below.
++ return coordinatorState ;
++ }
++
++ public void attach(TransactionCoordinatorState coordinatorState) {
++ Transaction txn = coordinatorState.transaction ;
++ txn.attach() ;
++ coordinatorState.componentStates.forEach((id, obj) -> {
++ components.findComponent(id).attach(obj);
++ });
++ }
++
++ public void shutdown() {
++ if ( coordinatorLock == null )
++ return ;
++ components.forEach((id, c) -> c.shutdown()) ;
++ shutdownHooks.forEach((h)-> h.shutdown()) ;
++ coordinatorLock = null ;
++ journal.close();
++ }
++
++ // Are we in the initialization phase?
++ private void checkSetup() {
++ if ( coordinatorStarted )
++ throw new TransactionException("TransactionCoordinator has already been started") ;
++ }
++
++ // Are we up and ruuning?
++ private void checkActive() {
++ if ( ! coordinatorStarted )
++ throw new TransactionException("TransactionCoordinator has not been started") ;
++ checkNotShutdown();
++ }
++
++ // Check not wrapped up
++ private void checkNotShutdown() {
++ if ( coordinatorLock == null )
++ throw new TransactionException("TransactionCoordinator has been shutdown") ;
++ }
++
++ private void releaseWriterLock() {
++ int x = writersWaiting.availablePermits() ;
++ if ( x != 0 )
++ throw new TransactionException("TransactionCoordinator: Probably mismatch of enable/disableWriter calls") ;
++ writersWaiting.release() ;
++ }
++
++ /** Acquire the writer lock - return true if succeeded */
++ private boolean acquireWriterLock(boolean canBlock) {
++ if ( ! canBlock )
++ return writersWaiting.tryAcquire() ;
++ try {
++ writersWaiting.acquire() ;
++ return true;
++ } catch (InterruptedException e) { throw new TransactionException(e) ; }
++ }
++
++ /** Enter exclusive mode; block if necessary.
++ * There are no active transactions on return; new transactions will be held up in 'begin'.
++ * Return to normal (release waiting transactions, allow new transactions)
++ * with {@link #finishExclusiveMode}.
++ * <p>
++ * Do not call inside an existing transaction.
++ */
++ public void startExclusiveMode() {
++ startExclusiveMode(true);
++ }
++
++ /** Try to enter exclusive mode.
++ * If return is true, then there are no active transactions on return and new transactions will be held up in 'begin'.
++ * If false, there were in-progress transactions.
++ * Return to normal (release waiting transactions, allow new transactions)
++ * with {@link #finishExclusiveMode}.
++ * <p>
++ * Do not call inside an existing transaction.
++ */
++ public boolean tryExclusiveMode() {
++ return tryExclusiveMode(false);
++ }
++
++ /** Try to enter exclusive mode.
++ * If return is true, then there are no active transactions on return and new transactions will be held up in 'begin'.
++ * If false, there were in-progress transactions.
++ * Return to normal (release waiting transactions, allow new transactions)
++ * with {@link #finishExclusiveMode}.
++ * <p>
++ * Do not call inside an existing transaction.
++ * @param canBlock Allow the operation block and wait for the exclusive mode lock.
++ */
++ public boolean tryExclusiveMode(boolean canBlock) {
++ return startExclusiveMode(canBlock);
++ }
++
++ private boolean startExclusiveMode(boolean canBlock) {
++ if ( canBlock ) {
++ exclusivitylock.writeLock().lock() ;
++ return true ;
++ }
++ return exclusivitylock.writeLock().tryLock() ;
++ }
++
++ /** Return to normal (release waiting transactions, allow new transactions).
++ * Must be paired with an earlier {@link #startExclusiveMode}.
++ */
++ public void finishExclusiveMode() {
++ exclusivitylock.writeLock().unlock() ;
++ }
++
++ /** Execute an action in exclusive mode. This method can block.
++ * Equivalent to:
++ * <pre>
++ * startExclusiveMode() ;
++ * try { action.run(); }
++ * finally { finishExclusiveMode(); }
++ * </pre>
++ *
++ * @param action
++ */
++ public void execExclusive(Runnable action) {
++ startExclusiveMode() ;
++ try { action.run(); }
++ finally { finishExclusiveMode(); }
++ }
++
++ /** Block until no writers are active.
++ * When this returns, this guarantees that the database is not changing
++ * and the journal is flushed to disk.
++ * <p>
++ * The application must call {@link #enableWriters} later.
++ * <p>
++ * This operation must not be nested (it will block).
++ *
++ * @see #tryBlockWriters()
++ * @see #enableWriters()
++ *
++ */
++ public void blockWriters() {
++ acquireWriterLock(true) ;
++ }
++
++ /** Try to block all writers, or return if can't at the moment.
++ * <p>
++ * Unlike a write transction, there is no associated transaction.
++ * <p>
++ * If it returns true, the application must call {@link #enableWriters} later.
++ *
++ * @see #blockWriters()
++ * @see #enableWriters()
++
++ * @return true if the operation succeeded and writers are blocked
++ */
++ public boolean tryBlockWriters() {
++ return tryBlockWriters(false) ;
++ }
++
++ /**
++ * Block until no writers are active, optionally blocking or returning if can't at the moment.
++ * <p>
++ * Unlike a write transction, there is no associated transaction.
++ * <p>
++ * If it returns true, the application must call {@link #enableWriters} later.
++ * @param canBlock
++ * @return true if the operation succeeded and writers are blocked
++ */
++ public boolean tryBlockWriters(boolean canBlock) {
++ return acquireWriterLock(canBlock) ;
++ }
++ /** Allow writers.
++ * This must be used in conjunction with {@link #blockWriters()} or {@link #tryBlockWriters()}
++ *
++ * @see #blockWriters()
++ * @see #tryBlockWriters()
++ */
++ public void enableWriters() {
++ releaseWriterLock();
++ }
++
++ /** Execute an action in as if a Write but no write transaction started.
++ * This method can block.
++ * <p>
++ * Equivalent to:
++ * <pre>
++ * blockWriters() ;
++ * try { action.run(); }
++ * finally { enableWriters(); }
++ * </pre>
++ *
++ * @param action
++ */
++ public void execAsWriter(Runnable action) {
++ blockWriters() ;
++ try { action.run(); }
++ finally { enableWriters(); }
++ }
++
++ /** Start a transaction. This may block. */
++ public Transaction begin(ReadWrite readWrite) {
++ return begin(readWrite, true) ;
++ }
++
++ /**
++ * Start a transaction. Returns null if this operation would block.
++ * Readers can start at any time.
++ * A single writer policy is currently imposed so a "begin(WRITE)"
++ * may block.
++ */
++ public Transaction begin(ReadWrite readWrite, boolean canBlock) {
++ 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 {
++ if ( ! exclusivitylock.readLock().tryLock() )
++ return null ;
++ }
++
++ // Readers never block.
++ if ( readWrite == WRITE ) {
++ // Writers take a WRITE permit from the semaphore to ensure there
++ // is at most one active writer, else the attempt to start the
++ // transaction blocks.
++ // Released by in notifyCommitFinish/notifyAbortFinish
++ boolean b = acquireWriterLock(canBlock) ;
++ if ( !b ) {
++ exclusivitylock.readLock().unlock() ;
++ return null ;
++ }
++ }
++ Transaction transaction = begin$(readWrite) ;
++ startActiveTransaction(transaction) ;
++ transaction.begin();
++ return transaction;
++ }
++
++ // The version is the serialization point for a transaction.
++ // All transactions on the same view of the data get the same serialization point.
++
++ // A read transaction can be promoted if writer does not start
++ // This TransactionCoordinator provides Serializable, Read-lock-free
++ // execution. With no item locking, a read can only be promoted
++ // if no writer started since the reader started.
++
++ /* The version of the data - incremented when transaction commits.
++ * This is the version with repest to the last commited transaction.
++ * Aborts do not cause the data version to advance.
++ * This counterr never goes backwards.
++ */
++ private final AtomicLong dataVersion = new AtomicLong(0) ;
++
++ private Transaction begin$(ReadWrite readWrite) {
++ synchronized(coordinatorLock) {
++ // Thread safe part of 'begin'
++ // Allocate the transaction serialization point.
++ TxnId txnId = txnIdGenerator.generate() ;
++ List<SysTrans> sysTransList = new ArrayList<>() ;
++ Transaction transaction = new Transaction(this, txnId, readWrite, dataVersion.get(), sysTransList) ;
++
++ ComponentGroup txnComponents = chooseComponents(this.components, readWrite) ;
++
++ try {
++ txnComponents.forEachComponent(elt -> {
++ SysTrans sysTrans = new SysTrans(elt, transaction, txnId) ;
++ sysTransList.add(sysTrans) ; }) ;
++ // Calling each component must be inside the lock
++ // so that a transaction does not commit overlapping with setup.
++ // If it did, different components might end up starting from
++ // different start states of the overall system.
++ txnComponents.forEachComponent(elt -> elt.begin(transaction)) ;
++ } catch(Throwable ex) {
++ // Careful about incomplete.
++ //abort() ;
++ //complete() ;
++ throw ex ;
++ }
++ return transaction ;
++ }
++ }
++
++ private ComponentGroup chooseComponents(ComponentGroup components, ReadWrite readWrite) {
++ if ( quorumGenerator == null )
++ return components ;
++ ComponentGroup cg = quorumGenerator.genQuorum(readWrite) ;
++ if ( cg == null )
++ return components ;
++ cg.forEach((id, c) -> {
++ TransactionalComponent tcx = components.findComponent(id) ;
++ if ( ! tcx.equals(c) )
++ log.warn("TransactionalComponent not in TransactionCoordinator's ComponentGroup") ;
++ }) ;
++ if ( log.isDebugEnabled() )
++ log.debug("Custom ComponentGroup for transaction "+readWrite+": size="+cg.size()+" of "+components.size()) ;
++ return cg ;
++ }
++
++ /** Is promotion of transactions enabled? */
++ /*private*/public/*for development*/ static boolean promotion = true ;
++
++ /** Control of whether a transaction promotion can see any commits that
++ * happened between this transaction starting and it promoting.
++ * A form of "ReadCommitted".
++ */
++ /*private*/public/*for development*/ static boolean readCommittedPromotion = false ;
++
++ /** Whether to wait for writers when trying to promote */
++ private static final boolean promotionWaitForWriters = true;
++
++ /** Attempt to promote a tranasaction from READ to WRITE.
++ * No-op for a transaction already a writer.
++ * Throws {@link TransactionException} if the promotion
++ * can not be done.
++ */
++ /*package*/ boolean promoteTxn(Transaction transaction) {
++ if ( ! promotion )
++ return false;
++
++ if ( transaction.getMode() == WRITE )
++ return true ;
++
++ // Has there been an writer active since the transaction started?
++ // Do a test outside the lock - only dataVaersion can change and that increases.
++ // If "read commited transactions" not allowed, the data has changed in a way we
++ // do no twish to expose.
++ // If this test fails outside the lock it will fail inside.
++ // If it passes, we have to test again in case there is an active writer.
++
++ if ( ! readCommittedPromotion ) {
++ long txnEpoch = transaction.getDataVersion() ; // The transaction-start point.
++ long currentEpoch = dataVersion.get() ; // The data serialization point.
++
++ if ( txnEpoch < currentEpoch )
++ // The data has changed and "read committed" not allowed.
++ // We can reject now.
++ return false ;
++ }
++
++ // Once we have acquireWriterLock, we are single writer.
++ // We may have to discard writer status because eocne we can make the defintite
++ // decision on promotion, we find we can't promote after all.
++ if ( readCommittedPromotion ) {
++ /*
++ * acquireWriterLock(true) ;
++ * synchronized(coordinatorLock) {
++ * begin$ ==>
++ * reset transaction.
++ * promote components
++ * reset dataVersion
++ */
++ acquireWriterLock(true) ;
++ synchronized(coordinatorLock) {
++ try {
++ transaction.promoteComponents() ;
++ // Because we want to see the new state of the data.s
++ //transaction.resetDataVersion(dataVersion.get());
++ } catch (TransactionException ex) {
++ try { transaction.abort(); } catch(RuntimeException ex2) {}
++ releaseWriterLock();
++ return false ;
++ }
++ }
++ return true;
++ }
++
++ if ( ! waitForWriters() )
++ // Failed to become a writer.
++ return false;
++ // Now a proto-writer.
++
++ synchronized(coordinatorLock) {
++ // Not read commited.
++ // Need to check the data version once we are the writer and all previous
++ // writers have commited or aborted.
++ // Has there been an writer active since the transaction started?
++ long txnEpoch = transaction.getDataVersion() ; // The transaction-start point.
++ long currentEpoch = dataVersion.get() ; // The data serialization point.
++
++ if ( txnEpoch != currentEpoch ) {
++ // Failed to promote.
++ releaseWriterLock();
++ return false ;
++ }
++
++ // ... we have now got the writer lock ...
++ try {
++ transaction.promoteComponents() ;
++ // No need to reset the data version because strict isolation.
++ } catch (TransactionException ex) {
++ try { transaction.abort(); } catch(RuntimeException ex2) {}
++ releaseWriterLock();
++ return false ;
++ }
++ }
++ return true ;
++ }
++
++ private boolean waitForWriters() {
++ if ( promotionWaitForWriters )
++ return acquireWriterLock(true) ;
++ else
++ return acquireWriterLock(false) ;
++ }
++
++ // Called once by Transaction after the action of commit()/abort() or end()
++ /** Signal that the transaction has finished. */
++ /*package*/ void completed(Transaction transaction) {
++ finishActiveTransaction(transaction);
++ journal.reset() ;
++ }
++
++ /*package*/ void executePrepare(Transaction transaction) {
++ // Do here because it needs access to the journal.
++ notifyPrepareStart(transaction);
++ transaction.getComponents().forEach(sysTrans -> {
++ TransactionalComponent c = sysTrans.getComponent() ;
++ ByteBuffer data = c.commitPrepare(transaction) ;
++ if ( data != null ) {
++ PrepareState s = new PrepareState(c.getComponentId(), data) ;
++ journal.write(s) ;
++ }
++ }) ;
++ notifyPrepareFinish(transaction);
++ }
++
++ /*package*/ void executeCommit(Transaction transaction, Runnable commit, Runnable finish) {
++ // This is the commit point.
++ synchronized(coordinatorLock) {
++ // *** COMMIT POINT
++ journal.sync() ;
++ // *** COMMIT POINT
++ // Now run the Transactions commit actions.
++ commit.run() ;
++ journal.truncate(0) ;
++ // and tell the Transaction it's finished.
++ finish.run() ;
++ // Bump global serialization point if necessary.
++ if ( transaction.getMode() == WRITE )
++ advanceDataVersion() ;
++ notifyCommitFinish(transaction) ;
++ }
++ }
++
++ // Inside the global transaction start/commit lock.
++ private void advanceDataVersion() {
++ dataVersion.incrementAndGet();
++ }
++
++ /*package*/ void executeAbort(Transaction transaction, Runnable abort) {
++ notifyAbortStart(transaction) ;
++ abort.run();
++ notifyAbortFinish(transaction) ;
++ }
++
++ // Active transactions: this is (the missing) ConcurrentHashSet
++ private final static Object dummy = new Object() ;
++ private ConcurrentHashMap<Transaction, Object> activeTransactions = new ConcurrentHashMap<>() ;
++ private AtomicLong activeTransactionCount = new AtomicLong(0) ;
++ private AtomicLong activeReadersCount = new AtomicLong(0) ;
++ private AtomicLong activeWritersCount = new AtomicLong(0) ;
++
++ private void startActiveTransaction(Transaction transaction) {
++ synchronized(coordinatorLock) {
++ // Use lock to ensure all the counters move together.
++ // Thread safe - we have not let the Transaction object out yet.
++ countBegin.incrementAndGet() ;
++ switch(transaction.getMode()) {
++ case READ: countBeginRead.incrementAndGet() ; activeReadersCount.incrementAndGet() ; break ;
++ case WRITE: countBeginWrite.incrementAndGet() ; activeWritersCount.incrementAndGet() ; break ;
++ }
++ activeTransactionCount.incrementAndGet() ;
++ activeTransactions.put(transaction, dummy) ;
++ }
++ }
++
++ private void finishActiveTransaction(Transaction transaction) {
++ synchronized(coordinatorLock) {
++ // Idempotent.
++ Object x = activeTransactions.remove(transaction) ;
++ if ( x == null )
++ return ;
++ countFinished.incrementAndGet() ;
++ activeTransactionCount.decrementAndGet() ;
++ switch(transaction.getMode()) {
++ case READ: activeReadersCount.decrementAndGet() ; break ;
++ case WRITE: activeWritersCount.decrementAndGet() ; break ;
++ }
++ }
++ exclusivitylock.readLock().unlock() ;
++ }
++
++ public long countActiveReaders() { return activeReadersCount.get() ; }
++ public long countActiveWriter() { return activeWritersCount.get() ; }
++ public long countActive() { return activeTransactionCount.get(); }
++
++ // notify*Start/Finish called round each transaction lifecycle step
++ // Called in cooperation between Transaction and TransactionCoordinator
++ // depending on who is actually do the work of each step.
++
++ /*package*/ void notifyPrepareStart(Transaction transaction) {}
++
++ /*package*/ void notifyPrepareFinish(Transaction transaction) {}
++
++ // Writers released here - can happen because of commit() or abort().
++
++ private void notifyCommitStart(Transaction transaction) {}
++
++ private void notifyCommitFinish(Transaction transaction) {
++ if ( transaction.getMode() == WRITE )
++ releaseWriterLock();
++ }
++
++ private void notifyAbortStart(Transaction transaction) { }
++
++ private void notifyAbortFinish(Transaction transaction) {
++ if ( transaction.getMode() == WRITE )
++ releaseWriterLock();
++ }
++
++ /*package*/ void notifyEndStart(Transaction transaction) { }
++
++ /*package*/ void notifyEndFinish(Transaction transaction) {}
++
++ // Called by Transaction once at the end of first commit()/abort() or end()
++
++ /*package*/ void notifyCompleteStart(Transaction transaction) { }
++
++ /*package*/ void notifyCompleteFinish(Transaction transaction) { }
++
++ // Coordinator state.
++ private final AtomicLong countBegin = new AtomicLong(0) ;
++
++ private final AtomicLong countBeginRead = new AtomicLong(0) ;
++
++ private final AtomicLong countBeginWrite = new AtomicLong(0) ;
++
++ private final AtomicLong countFinished = new AtomicLong(0) ;
++
++ // Access counters
++ public long countBegin() { return countBegin.get() ; }
++
++ public long countBeginRead() { return countBeginRead.get() ; }
++
++ public long countBeginWrite() { return countBeginWrite.get() ; }
++
++ public long countFinished() { return countFinished.get() ; }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionCoordinatorState.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionCoordinatorState.java
index 0000000,0000000..def1f6e
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionCoordinatorState.java
@@@ -1,0 -1,0 +1,33 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import java.util.HashMap ;
++import java.util.Map ;
++
++public class TransactionCoordinatorState {
++ /*package*/final Transaction transaction ;
++ /*package*/Map<ComponentId, SysTransState> componentStates = new HashMap<>();
++ /*package*/ TransactionCoordinatorState(Transaction transaction) {
++ this.transaction = transaction ;
++ }
++
++ public Transaction getTransaction() {
++ return transaction ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionException.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionException.java
index 0000000,0000000..8e45811
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionException.java
@@@ -1,0 -1,0 +1,29 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import org.apache.jena.sparql.JenaTransactionException ;
++
++public class TransactionException extends JenaTransactionException {
++ public TransactionException() { super(); }
++ public TransactionException(String message) { super(message); }
++ public TransactionException(Throwable cause) { super(cause) ; }
++ public TransactionException(String message, Throwable cause) { super(message, cause) ; }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionInfo.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionInfo.java
index 0000000,0000000..34a39f2
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionInfo.java
@@@ -1,0 -1,0 +1,75 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import static org.seaborne.dboe.transaction.txn.TxnState.INACTIVE ;
++import org.apache.jena.query.ReadWrite ;
++
++/**
++ * A view that provides information about a transaction
++ * @see Transaction
++ */
++public interface TransactionInfo {
++
++ /** The transaction lifecycle state */
++ public TxnState getState() ;
++
++ /**
++ * Each transaction is allocated a serialization point by the transaction
++ * coordinator. Normally, this is related to this number and it increases
++ * over time as the data changes. Two readers can have the same
++ * serialization point - they are working with the same view of the data.
++ */
++ public long getDataVersion() ;
++
++ /** Has the transaction started? */
++ public boolean hasStarted() ;
++
++ /** Has the transaction finished (has commit/abort/end been called)? */
++ public boolean hasFinished() ;
++
++ /** Has the transaction gone through all lifecycle states? */
++ public boolean hasFinalised() ;
++
++ /** Get the trasnaction id for this transaction. Unique within this OS process (JVM) at least . */
++ public TxnId getTxnId() ;
++
++ /** What mode is this transaction?
++ * This may change from {@code READ} to {@code WRITE} in a transactions lifetime.
++ */
++ public ReadWrite getMode() ;
++
++ /** Is this a view of a READ transaction?
++ * Convenience operation equivalent to {@code (getMode() == READ)}
++ */
++ public default boolean isReadTxn() { return getMode() == ReadWrite.READ ; }
++
++ /** Is this a view of a WRITE transaction?
++ * Convenience operation equivalent to {@code (getMode() == WRITE)}
++ */
++ public default boolean isWriteTxn() { return getMode() == ReadWrite.WRITE ; }
++
++ /** Is this a view of a transaction that is active?
++ * Equivalent to {@code getState() != INACTIVE}
++ */
++ public default boolean isActiveTxn() {
++ return getState() != INACTIVE ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalBase.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalBase.java
index 0000000,0000000..13b6683
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalBase.java
@@@ -1,0 -1,0 +1,249 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import java.util.Objects ;
++
++import org.apache.jena.atlas.logging.Log ;
++import org.apache.jena.query.ReadWrite ;
++
++/**
++ * Framework for implementing a Transactional.
++ */
++
++public class TransactionalBase implements TransactionalSystem {
++ // Help debugging by generating names for Transactionals.
++ private final String label ;
++ protected boolean isShutdown = false ;
++ protected final TransactionCoordinator txnMgr ;
++
++ // Per thread transaction.
++ private final ThreadLocal<Transaction> theTxn = new ThreadLocal<>() ;
++
++ public TransactionalBase(String label, TransactionCoordinator txnMgr) {
++ this.label = label ;
++ this.txnMgr = txnMgr ;
++ }
++
++ public TransactionalBase(TransactionCoordinator txnMgr) {
++ this(null, txnMgr) ;
++ }
++
++ @Override
++ public TransactionCoordinator getTxnMgr() {
++ return txnMgr ;
++ }
++
++ // Development
++ private static final boolean trackAttachDetach = false ;
++
++ @Override
++ public TransactionCoordinatorState detach() {
++ if ( trackAttachDetach )
++ Log.info(this, ">> detach");
++ checkRunning() ;
++ // Not if it just commited but before end.
++ //checkActive() ;
++ Transaction txn = theTxn.get() ;
++ TransactionCoordinatorState coordinatorState = null ;
++ if ( txn != null )
++ // We are not ending.
++ coordinatorState = txnMgr.detach(txn) ;
++ if ( trackAttachDetach )
++ Log.info(this, " theTxn = "+txn) ;
++ theTxn.remove() ; ///??????
++ if ( trackAttachDetach )
++ Log.info(this, "<< detach");
++ if ( coordinatorState == null )
++ throw new TransactionException("Not attached") ;
++ return coordinatorState ;
++ }
++
++ @Override
++ public void attach(TransactionCoordinatorState coordinatorState) {
++ if ( trackAttachDetach )
++ Log.info(this, ">> attach");
++ Objects.nonNull(coordinatorState) ;
++ checkRunning() ;
++ checkNotActive() ;
++ TxnState txnState = coordinatorState.transaction.getState() ;
++ if ( txnState != TxnState.DETACHED )
++ throw new TransactionException("Not a detached transaction") ;
++ txnMgr.attach(coordinatorState) ;
++ if ( trackAttachDetach )
++ Log.info(this, " theTxn = "+coordinatorState.transaction) ;
++ theTxn.set(coordinatorState.transaction);
++ if ( trackAttachDetach )
++ Log.info(this, "<< attach");
++ }
++
++ @Override
++ public final void begin(ReadWrite readWrite) {
++ Objects.nonNull(readWrite) ;
++ checkRunning() ;
++ checkNotActive() ;
++ Transaction transaction = txnMgr.begin(readWrite) ;
++ theTxn.set(transaction) ;
++ }
++
++ @Override
++ public boolean promote() {
++ checkActive() ;
++ Transaction txn = getValidTransaction() ;
++ return txn.promote() ;
++ }
++
++ @Override
++ public final void commit() {
++ checkRunning() ;
++ TransactionalSystem.super.commit() ;
++ }
++
++ @Override
++ public void commitPrepare() {
++ Transaction txn = getValidTransaction() ;
++ txn.prepare() ;
++ }
++
++ @Override
++ public void commitExec() {
++ Transaction txn = getValidTransaction() ;
++ txn.commit() ;
++ _end() ;
++ }
++
++// /** Signal end of commit phase */
++// @Override
++// public void commitEnd() {
++// _end() ;
++// }
++
++ @Override
++ public final void abort() {
++ checkRunning() ;
++ checkActive() ;
++ Transaction txn = getValidTransaction() ;
++ try { txn.abort() ; }
++ finally { _end() ; }
++ }
++
++ @Override
++ public final void end() {
++ checkRunning() ;
++ // Don't check if active or if any thread locals exist
++ // because this may have already been called.
++ // txn.get() ; -- may be null -- test repeat calls.
++ _end() ;
++ }
++
++ /**
++ * Return the Read/write state (or null when not in a transaction)
++ */
++ @Override
++ final
++ public ReadWrite getState() {
++ checkRunning() ;
++ // tricky - touching theTxn causes it to initialize.
++ Transaction txn = theTxn.get() ;
++ if ( txn != null )
++ return txn.getMode() ;
++ theTxn.remove() ;
++ return null ;
++ }
++
++ @Override
++ final
++ public TransactionInfo getTransactionInfo() {
++ return getThreadTransaction() ;
++ }
++
++ @Override
++ final
++ public Transaction getThreadTransaction() {
++ Transaction txn = theTxn.get() ;
++ // Touched the thread local so it is defined now.
++// if ( txn == null )
++// theTxn.remove() ;
++ return txn ;
++ }
++
++ /** Get the transaction, checking there is one */
++ private Transaction getValidTransaction() {
++ Transaction txn = theTxn.get() ;
++ if ( txn == null )
++ throw new TransactionException("Not in a transaction") ;
++ return txn ;
++ }
++
++ private void checkRunning() {
++// if ( ! hasStarted )
++// throw new TransactionException("Not started") ;
++
++ if ( isShutdown )
++ throw new TransactionException("Shutdown") ;
++ }
++
++ /**
++ * Shutdown component, aborting any in-progress transactions. This operation
++ * is not guaranteed to be called.
++ */
++ public void shutdown() {
++ txnMgr.shutdown() ;
++ isShutdown = true ;
++ }
++
++ protected String label(String msg) {
++ if ( label == null )
++ return msg ;
++ return label+": "+msg ;
++ }
++
++ final
++ protected void checkActive() {
++ checkNotShutdown() ;
++ if ( ! isInTransaction() )
++ throw new TransactionException(label("Not in an active transaction")) ;
++ }
++
++ final
++ protected void checkNotActive() {
++ checkNotShutdown() ;
++ if ( isInTransaction() )
++ throw new TransactionException(label("Currently in an active transaction")) ;
++ }
++
++ final
++ protected void checkNotShutdown() {
++ if ( isShutdown )
++ throw new TransactionException(label("Already shutdown")) ;
++ }
++
++ private final void _end() {
++ Transaction txn = theTxn.get() ;
++ if ( txn != null ) {
++ try {
++ // Can throw an exception on begin(W)...end().
++ txn.end() ;
++ } finally {
++ theTxn.set(null) ;
++ theTxn.remove() ;
++ }
++ }
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalComponent.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalComponent.java
index 0000000,0000000..dce526b
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalComponent.java
@@@ -1,0 -1,0 +1,175 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import java.nio.ByteBuffer ;
++
++/** Interface that for components of a transaction system.
++* <p><br/>
++* The {@link TransactionCoordinator} manages a number of components
++* which provide the {@link TransactionalComponent} interface.
++* <p><br/>
++* When a new coordinator starts, typically being when the in-process system starts,
++* there is a recovery phase when work from a previous coordinator is recovered.
++* Transactions were either were properly committed by the previous coordinator,
++* and hence redo actions (finalization) should be done,
++* or they were not, in which case undo actions may be needed.
++* Transctions to discard are not notified, only fully commited transaction are
++* notified during recovery. The component may need to keepit's own record of
++* undo actions needed across restarts.
++* <p><br/>
++* Lifecycle of startup:
++* <ul>
++* <li>{@link #startRecovery}
++* <li>{@link #recover} for each commited/durable transaction (redo actions)
++* <li>{@link #finishRecovery}, discarding any othe transactions (undo actions).
++* </ul>
++* <p><br/>
++* Lifecycle of a read transaction:
++* <ul>
++* <li>{@link #begin}
++* <li>{@link #complete}
++* </ul>
++* <br/>
++* A read transaction may also include {@code commit} or {@code abort} lifecycles.
++* {@link #commitPrepare} and {@link #commitEnd} are not called.
++*<p><br/>
++* Lifecycle of a write transaction:
++* <li>{@link #begin}
++* <li>{@link #commitPrepare}
++* <li>{@link #commit} or {@link #abort}
++* <li>{@link #commitEnd}
++* <li>{@link #complete} including abort
++* </ul>
++* <br/>
++* or if the application aborts the transaction:
++* <ul>
++* <li>{@link #begin}
++* <li>{@link #abort}
++* <li>{@link #complete}
++* </ul>
++* <p>
++* {@link #complete} may be called out of sequence and it forces an abort if before
++* {@link #commitPrepare}. Once {@link #commitPrepare} has been called, the component
++* can not decide whether to commit finally or to cause a system abort; it must wait
++* for the coordinator. After {@link #commitEnd}, the coordinator has definitely
++* commited the overall transaction and local prepared state can be released, and changes
++* made to the permanent state of the component.
++*
++* @see Transaction
++* @see TransactionCoordinator
++*/
++
++public interface TransactionalComponent
++{
++ /**
++ * Every component <i>instance</i> must supplied a unique number.
++ * It is used to route journal entries to subsystems, including across restarts/recovery.
++ * Uniqueness scope is within the same {@link TransactionCoordinator},
++ * and the same across restarts.
++ * <p>
++ * If a component imposes the rule of one-per-{@link TransactionCoordinator},
++ * the same number can be used (if different from all other component type instances).
++ * <p>
++ * If a component can have multiple instances per {@link TransactionCoordinator},
++ * for example indexes, each must have a unique instance id.
++ */
++ public ComponentId getComponentId() ;
++
++ // ---- Recovery phase
++ public void startRecovery() ;
++
++ /** Notification that {@code ref} was really committed and is being recovered.
++ *
++ * @param ref Same bytes as were written during prepare originally.
++ */
++ public void recover(ByteBuffer ref) ;
++
++ /** End of the receovery phase */
++ public void finishRecovery() ;
++
++ /** Indicate that no recovery is being done (the journal thinks everything was completed last time) */
++ public void cleanStart() ;
++
++ // ---- Normal operation
++
++ /** Start a transaction; return an identifier for this components use. */
++ public void begin(Transaction transaction) ;
++
++ /** Promote a component in a transaction.
++ * <p>
++ * May return "false" for "can't do that" if the transaction can not be promoted.
++ * <p>
++ * May throw {@link UnsupportedOperationException} if promotion is not supported.
++ */
++ public boolean promote(Transaction transaction) ;
++
++ /** Prepare for a commit.
++ * Returns some bytes that will be written to the journal.
++ * The journal remains valid until {@link #commitEnd} is called.
++ */
++ public ByteBuffer commitPrepare(Transaction transaction) ;
++
++ /** Commit a transaction (make durable).
++ * Other components not have been commited yet and recovery may occur still.
++ * Permanent state should not be finalised until {@link #commitEnd}.
++ */
++ public void commit(Transaction transaction) ;
++
++ /** Signal all commits on all components are done (the component can clearup now) */
++ public void commitEnd(Transaction transaction) ;
++
++ /** Abort a transaction (undo the effect of a transaction) */
++ public void abort(Transaction transaction) ;
++
++ /** Finalization - the coordinator will not mention the transaction again
++ * although recovery after a crash may do so.
++ */
++ public void complete(Transaction transaction) ;
++
++ // ---- End of operations
++
++ /** Detach this component from the transaction of the current thread
++ * and return some internal state that can be used in a future call of
++ * {@link #attach(SysTransState)}
++ * <p>
++ * After this call, the component is not in a transaction but the
++ * existing transaction still exists. The thread may start a new
++ * transaction; that transaction is completely independent of the
++ * detached transaction.
++ * <p>
++ * Returns {@code null} if the current thread not in a transaction.
++ * The component may return null to indicate it has no state.
++ * The return system state should be used in a call to {@link #attach(SysTransState)}
++ * and the transaction ended in the usual way.
++ *
++ */
++ public SysTransState detach() ;
++
++ /** Set the current thread to be in the transaction. The {@code systemState}
++ * must be obtained from a call of {@link #detach()}.
++ * This method can only be called once per {@code systemState}.
++ */
++ public void attach(SysTransState systemState) ;
++
++ /** Shutdown component, aborting any in-progress transactions.
++ * This operation is not guaranteed to be called.
++ */
++ public void shutdown() ;
++
++}
[20/50] [abbrv] jena git commit: Reformat
Posted by an...@apache.org.
Reformat
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/9b987b00
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/9b987b00
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/9b987b00
Branch: refs/heads/jena-tdb2
Commit: 9b987b002235c87f58e9a419025679e66bb83d25
Parents: 4d02f57
Author: Andy Seaborne <an...@seaborne.org>
Authored: Mon Sep 4 23:14:04 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Mon Sep 4 23:14:04 2017 +0100
----------------------------------------------------------------------
tdb2-cmds/src/main/java/tdb2/tdbcompact.java | 3 +++
tdb2-cmds/src/main/java/tdb2/tdbdump.java | 16 ++++++----------
2 files changed, 9 insertions(+), 10 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/9b987b00/tdb2-cmds/src/main/java/tdb2/tdbcompact.java
----------------------------------------------------------------------
diff --git a/tdb2-cmds/src/main/java/tdb2/tdbcompact.java b/tdb2-cmds/src/main/java/tdb2/tdbcompact.java
index 373e822..ea2e275 100644
--- a/tdb2-cmds/src/main/java/tdb2/tdbcompact.java
+++ b/tdb2-cmds/src/main/java/tdb2/tdbcompact.java
@@ -40,6 +40,9 @@ public class tdbcompact extends CmdTDB {
@Override
protected void exec() {
DatasetGraphSwitchable dsg = getDatabaseContainer() ;
+ long start = System.currentTimeMillis();
DatabaseOps.compact(dsg) ;
+ long finish = System.currentTimeMillis();
+ System.out.printf("Compacted in %.3fs", (finish-start)/1000.0);
}
}
http://git-wip-us.apache.org/repos/asf/jena/blob/9b987b00/tdb2-cmds/src/main/java/tdb2/tdbdump.java
----------------------------------------------------------------------
diff --git a/tdb2-cmds/src/main/java/tdb2/tdbdump.java b/tdb2-cmds/src/main/java/tdb2/tdbdump.java
index f54220c..9c50e87 100644
--- a/tdb2-cmds/src/main/java/tdb2/tdbdump.java
+++ b/tdb2-cmds/src/main/java/tdb2/tdbdump.java
@@ -31,27 +31,23 @@ public class tdbdump extends CmdTDB
{
static ModLangOutput modLangOutput = new ModLangOutput() ;
- static public void main(String... argv)
- {
+ static public void main(String... argv) {
CmdTDB.init() ;
new tdbdump(argv).mainRun() ;
}
- protected tdbdump(String[] argv)
- {
+ protected tdbdump(String[] argv) {
super(argv) ;
addModule(modLangOutput) ;
}
-
+
@Override
- protected String getSummary()
- {
- return getCommandName()+" : Write a dataset to stdout (defaults to N-Quads)" ;
+ protected String getSummary() {
+ return getCommandName() + " : Write a dataset to stdout (defaults to N-Quads)" ;
}
@Override
- protected void exec()
- {
+ protected void exec() {
DatasetGraph dsg = getDatasetGraph() ;
// Prefer stream over fully pretty output formats.
RDFFormat fmt = modLangOutput.getOutputStreamFormat() ;
[36/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/pom.xml
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/pom.xml
index 0000000,0000000..d55b4c8
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/pom.xml
@@@ -1,0 -1,0 +1,122 @@@
++<?xml version="1.0" encoding="utf-8"?>
++<!--
++ 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.
++-->
++
++<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
++
++ <modelVersion>4.0.0</modelVersion>
++
++ <artifactId>tdb2-cmds</artifactId>
++ <packaging>jar</packaging>
++ <name>Mantis (${project.artifactId})</name>
++
++ <parent>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>mantis</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </parent>
++
++ <dependencies>
++
++ <dependency>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>tdb2</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </dependency>
++
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-cmds</artifactId>
++ <exclusions>
++ <exclusion>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-tdb</artifactId>
++ </exclusion>
++ </exclusions>
++ </dependency>
++
++ <!-- Require a logging implementation -->
++ <dependency>
++ <groupId>org.slf4j</groupId>
++ <artifactId>slf4j-log4j12</artifactId>
++ </dependency>
++
++ <dependency>
++ <groupId>log4j</groupId>
++ <artifactId>log4j</artifactId>
++ </dependency>
++
++ </dependencies>
++
++ <build>
++ <plugins>
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-source-plugin</artifactId>
++ <executions>
++ <execution>
++ <id>attach-sources</id>
++ <!-- <phase>package</phase> package is the default -->
++ <goals>
++ <goal>jar-no-fork</goal>
++ </goals>
++ </execution>
++ </executions>
++ </plugin>
++
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-shade-plugin</artifactId>
++ <version>2.4.3</version>
++ <configuration>
++ <shadedArtifactAttached>false</shadedArtifactAttached>
++ <transformers>
++ <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
++ <mainClass>tdb2.Intro</mainClass>
++ </transformer>
++ <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
++ <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer" />
++ <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheNoticeResourceTransformer">
++ <addHeader>false</addHeader>
++ </transformer>
++ </transformers>
++ <filters>
++ <filter>
++ <artifact>*:*</artifact>
++ <excludes>
++ <exclude>META-INF/*.SF</exclude>
++ <exclude>META-INF/*.DSA</exclude>
++ <exclude>META-INF/*.RSA</exclude>
++ </excludes>
++ </filter>
++ </filters>
++ </configuration>
++ <executions>
++ <execution>
++ <phase>package</phase>
++ <!--<phase /><!- - Switch off -->
++ <goals>
++ <goal>shade</goal>
++ </goals>
++ </execution>
++ </executions>
++ </plugin>
++
++ </plugins>
++ </build>
++
++</project>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/java/tdb2/Intro.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/java/tdb2/Intro.java
index 0000000,0000000..f8fd6e0
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/java/tdb2/Intro.java
@@@ -1,0 -1,0 +1,31 @@@
++/*
++ * 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 tdb2;
++
++public class Intro {
++ public static void main(String...a) {
++ System.err.println("Commands available:");
++ System.err.println(" tdb2.tdbloader");
++ System.err.println(" tdb2.tdbquery");
++ System.err.println(" tdb2.tdbupdate");
++ System.err.println(" tdb2.tdbdump");
++ System.err.println(" tdb2.tdbstats");
++
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/CmdSub.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/CmdSub.java
index 0000000,0000000..bda20c5
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/CmdSub.java
@@@ -1,0 -1,0 +1,71 @@@
++/*
++ * 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 tdb2.cmdline;
++
++import java.util.Collection;
++import java.util.HashMap;
++import java.util.Map;
++
++import jena.cmd.CmdException;
++
++public class CmdSub {
++ public interface Exec {
++ public void exec(String[] argv) ;
++ }
++ private Map<String, Exec> dispatch = new HashMap<>() ;
++
++ private String subCmd ;
++ private String args[] ;
++
++ public CmdSub(String... argv) {
++ subCmd = subCommand(argv) ;
++ args = cmdline(argv) ;
++ }
++
++ protected void exec() {
++ Exec exec = dispatch.get(subCmd) ;
++ if ( exec == null )
++ throw new CmdException("No subcommand: " + subCmd) ;
++ exec.exec(args) ;
++ }
++
++ protected static String[] cmdline(String... argv) {
++ String[] a = new String[argv.length - 1] ;
++ System.arraycopy(argv, 1, a, 0, argv.length - 1) ;
++ return a ;
++ }
++
++ protected static String subCommand(String... argv) {
++ if ( argv.length == 0 )
++ throw new CmdException("Missing subcommand") ;
++
++ String subCmd = argv[0] ;
++ if ( subCmd.startsWith("-") )
++ throw new CmdException("Argument found where subcommand expected") ;
++ return subCmd ;
++ }
++
++ protected void addSubCommand(String subCmdName, Exec exec) {
++ dispatch.put(subCmdName, exec) ;
++ }
++
++ protected Collection<String> subCommandNames() {
++ return dispatch.keySet() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/CmdTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/CmdTDB.java
index 0000000,0000000..da799fd
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/CmdTDB.java
@@@ -1,0 -1,0 +1,84 @@@
++/*
++ * 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 tdb2.cmdline;
++
++import arq.cmdline.CmdARQ ;
++import org.apache.jena.Jena ;
++import org.apache.jena.atlas.lib.Lib ;
++import org.apache.jena.atlas.logging.LogCtl ;
++import org.apache.jena.query.ARQ ;
++import org.apache.jena.query.Dataset ;
++import org.apache.jena.sparql.core.DatasetGraph ;
++import org.apache.jena.system.JenaSystem ;
++import org.seaborne.dboe.base.file.Location;
++import org.seaborne.tdb2.TDB2;
++import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
++import org.seaborne.tdb2.sys.TDBInternal ;
++
++public abstract class CmdTDB extends CmdARQ
++{
++ protected final ModTDBDataset tdbDatasetAssembler = new ModTDBDataset() ;
++
++ private static boolean initialized = false ;
++
++ protected CmdTDB(String[] argv) {
++ super(argv) ;
++ init() ;
++ super.addModule(tdbDatasetAssembler) ;
++ super.modVersion.addClass(Jena.class) ;
++ super.modVersion.addClass(ARQ.class) ;
++ super.modVersion.addClass(TDB2.class) ;
++ }
++
++ public static synchronized void init() {
++ // In case called from elsewhere.
++ JenaSystem.init() ;
++ if (initialized)
++ return ;
++ // attempt once.
++ initialized = true ;
++ LogCtl.setCmdLogging() ;
++ }
++
++ @Override
++ protected void processModulesAndArgs() {
++ super.processModulesAndArgs() ;
++ }
++
++ protected Location getLocation() {
++ return tdbDatasetAssembler.getLocation() ;
++ }
++
++ protected DatasetGraph getDatasetGraph() {
++ return getDataset().asDatasetGraph() ;
++ }
++
++ protected DatasetGraphSwitchable getDatabaseContainer() {
++ return TDBInternal.getDatabaseContainer(getDatasetGraph());
++ }
++
++ protected Dataset getDataset() {
++ return tdbDatasetAssembler.getDataset() ;
++ }
++
++ @Override
++ protected String getCommandName() {
++ return Lib.className(this) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/CmdTDBGraph.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/CmdTDBGraph.java
index 0000000,0000000..60b7982
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/CmdTDBGraph.java
@@@ -1,0 -1,0 +1,81 @@@
++/*
++ * 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 tdb2.cmdline;
++
++import jena.cmd.ArgDecl;
++import jena.cmd.CmdException;
++import org.apache.jena.atlas.lib.Lib ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.graph.NodeFactory ;
++import org.apache.jena.query.Dataset ;
++import org.apache.jena.rdf.model.Model ;
++import org.seaborne.tdb2.store.GraphTDB;
++import tdb2.cmdline.CmdTDB;
++
++public abstract class CmdTDBGraph extends CmdTDB
++{
++ private static final ArgDecl argNamedGraph = new ArgDecl(ArgDecl.HasValue, "graph") ;
++ protected String graphName = null ;
++
++ protected CmdTDBGraph(String[] argv)
++ {
++ super(argv) ;
++ super.add(argNamedGraph, "--graph=IRI", "Act on a named graph") ;
++ }
++
++ @Override
++ protected void processModulesAndArgs()
++ {
++ super.processModulesAndArgs() ;
++ if ( contains(argNamedGraph) )
++ graphName = getValue(argNamedGraph) ;
++ }
++
++ protected Model getModel()
++ {
++ Dataset ds = tdbDatasetAssembler.getDataset() ;
++
++ if ( graphName != null )
++ {
++ Model m = ds.getNamedModel(graphName) ;
++ if ( m == null )
++ throw new CmdException("No such named graph (is this a TDB dataset?)") ;
++ return m ;
++ }
++ else
++ return ds.getDefaultModel() ;
++ }
++
++ public Node getGraphName() { return graphName == null ? null : NodeFactory.createURI(graphName) ; }
++
++ protected GraphTDB getGraph()
++ {
++ if ( graphName != null )
++ return (GraphTDB)tdbDatasetAssembler.getDataset().getNamedModel(graphName).getGraph() ;
++ else
++ return (GraphTDB)tdbDatasetAssembler.getDataset().getDefaultModel().getGraph() ;
++ }
++
++ @Override
++ protected String getCommandName()
++ {
++ return Lib.className(this) ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/ModLocation.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/ModLocation.java
index 0000000,0000000..1d6b37a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/ModLocation.java
@@@ -1,0 -1,0 +1,55 @@@
++/*
++ * 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 tdb2.cmdline;
++
++import jena.cmd.ArgDecl;
++import jena.cmd.CmdArgModule;
++import jena.cmd.CmdGeneral;
++import jena.cmd.ModBase;
++import org.seaborne.dboe.base.file.Location;
++
++public class ModLocation extends ModBase
++{
++ public ModLocation() {}
++
++ protected final ArgDecl locationDecl = new ArgDecl(ArgDecl.HasValue, "location", "loc") ;
++ protected Location location = null ;
++
++ @Override
++ public void registerWith(CmdGeneral cmdLine)
++ {
++ cmdLine.getUsage().startCategory("Location") ;
++ cmdLine.add(locationDecl, "--loc=DIR", "Location (a directory)") ;
++ }
++
++ public void checkCommandLine(CmdArgModule cmdLine)
++ {}
++
++ @Override
++ public void processArgs(CmdArgModule cmdLine)
++ {
++ if ( cmdLine.contains(locationDecl) )
++ {
++ String dir = cmdLine.getValue(locationDecl) ;
++ location = Location.create(dir) ;
++ }
++ }
++
++ public Location getLocation() { return location ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/ModModel.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/ModModel.java
index 0000000,0000000..eca9612
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/ModModel.java
@@@ -1,0 -1,0 +1,66 @@@
++/*
++ * 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 tdb2.cmdline;
++
++import jena.cmd.ArgDecl;
++import jena.cmd.CmdArgModule;
++import jena.cmd.CmdGeneral;
++import jena.cmd.ModBase;
++
++import org.apache.jena.rdf.model.Model ;
++import org.apache.jena.util.FileManager ;
++
++/** Name a model */
++public class ModModel extends ModBase
++{
++ protected ArgDecl modelArgDecl = null ;
++ private Model model = null ;
++
++ //public ModModel() { this("model") ; }
++ public ModModel(String argName, String ... altNames)
++ {
++ modelArgDecl = new ArgDecl(ArgDecl.HasValue, argName) ;
++ for ( String x : altNames )
++ modelArgDecl.addName(x) ;
++ }
++
++ public ArgDecl getArg()
++ {
++ return modelArgDecl ;
++ }
++
++ @Override
++ public void registerWith(CmdGeneral cmdLine)
++ {
++ cmdLine.add(modelArgDecl, "--"+modelArgDecl.getKeyName()+"=filename", "Filename for a model") ;
++ }
++
++ @Override
++ public void processArgs(CmdArgModule cmdLine)
++ {
++ if ( cmdLine.contains(modelArgDecl) )
++ {
++ String filename = cmdLine.getValue(modelArgDecl) ;
++ model = FileManager.get().loadModel(filename) ;
++ }
++ }
++
++ public Model getModel() { return model ; }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/ModTDBAssembler.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/ModTDBAssembler.java
index 0000000,0000000..6fbb345
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/ModTDBAssembler.java
@@@ -1,0 -1,0 +1,89 @@@
++/*
++ * 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 tdb2.cmdline;
++
++import java.io.File;
++
++import jena.cmd.CmdArgModule;
++import jena.cmd.CmdException;
++import jena.cmd.CmdGeneral;
++import org.seaborne.dboe.base.file.Location;
++import tdb2.cmdline.ModLocation;
++import arq.cmdline.ModAssembler;
++
++/** Extends ModAssembler to include --tdb.
++ * Defaulting to "tdb.ttl" is done in ModTDBDataset because it interacts
++ * with --location
++ */
++public class ModTDBAssembler extends ModAssembler
++{
++ private ModLocation modLocation = new ModLocation() ;
++
++ public static final String defaultAssemblerFile = "tdb.ttl" ;
++ protected boolean useDefaultAssemblerFile = false ;
++
++ public ModTDBAssembler()
++ {
++ super() ;
++ ModAssembler.assemblerDescDecl.addName("tdb") ;
++ }
++
++ @Override
++ public void processArgs(CmdArgModule cmdLine)
++ {
++ int count = 0 ;
++
++ modLocation.processArgs(cmdLine) ;
++ super.processArgs(cmdLine) ;
++ if ( super.getAssemblerFile() != null ) count++ ;
++ if ( modLocation.getLocation() != null ) count++ ;
++
++ if ( count == 0 )
++ {
++ useDefaultAssemblerFile = true ;
++ // throw new CmdException("No assembler file and no location") ;
++ }
++
++ if ( count > 1 )
++ throw new CmdException("Only one of an assembler file and a location") ;
++ }
++
++ @Override
++ public void registerWith(CmdGeneral cmdLine)
++ {
++ super.registerWith(cmdLine) ;
++ cmdLine.addModule(modLocation) ;
++ //cmdLine.getUsage().startCategory("Dataset") ;
++ cmdLine.getUsage().addUsage("--tdb=", "Assembler description file") ;
++ }
++
++ public Location getLocation() { return modLocation.getLocation() ; }
++
++ @Override
++ public String getAssemblerFile()
++ {
++ if ( useDefaultAssemblerFile )
++ {
++ File f = new File(defaultAssemblerFile) ;
++ if ( f.exists() )
++ return defaultAssemblerFile ;
++ }
++ return super.getAssemblerFile() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/ModTDBDataset.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/ModTDBDataset.java
index 0000000,0000000..199268a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/java/tdb2/cmdline/ModTDBDataset.java
@@@ -1,0 -1,0 +1,138 @@@
++/*
++ * 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 tdb2.cmdline;
++
++import java.util.ArrayList ;
++import java.util.List ;
++
++import arq.cmdline.ModDataset ;
++import jena.cmd.ArgDecl;
++import jena.cmd.CmdArgModule;
++import jena.cmd.CmdException;
++import jena.cmd.CmdGeneral;
++import org.apache.jena.atlas.logging.Log ;
++import org.apache.jena.query.* ;
++import org.apache.jena.rdf.model.Model ;
++import org.apache.jena.riot.RDFDataMgr ;
++import org.apache.jena.shared.JenaException ;
++import org.apache.jena.sparql.core.assembler.AssemblerUtils ;
++import org.apache.jena.sparql.core.assembler.DatasetAssemblerVocab ;
++import org.apache.jena.util.FileManager ;
++import org.seaborne.dboe.base.file.Location;
++import org.seaborne.tdb2.TDB2Factory;
++import org.seaborne.tdb2.assembler.VocabTDB2;
++import org.seaborne.tdb2.store.DatasetGraphTDB;
++
++public class ModTDBDataset extends ModDataset
++{
++ // Mixes assembler, location and "tdb"
++ // Can make a single model or a dataset
++
++ private ArgDecl argMem = new ArgDecl(ArgDecl.HasValue, "mem", "data") ;
++ private ModTDBAssembler modAssembler = new ModTDBAssembler() ;
++ private String inMemFile = null ;
++
++ public ModTDBDataset() {}
++
++ @Override
++ public void registerWith(CmdGeneral cmdLine)
++ {
++ cmdLine.add(argMem, "--mem=FILE", "Execute on an in-memory TDB database (for testing)") ;
++ cmdLine.addModule(modAssembler) ;
++ }
++
++ @Override
++ public void processArgs(CmdArgModule cmdLine)
++ {
++ inMemFile = cmdLine.getValue(argMem) ;
++ modAssembler.processArgs(cmdLine) ;
++ }
++
++ @Override
++ public Dataset createDataset() {
++ if ( inMemFile != null ) {
++ Dataset ds = TDB2Factory.createDataset();
++ RDFDataMgr.read(ds, inMemFile);
++ return ds;
++ }
++
++ if ( modAssembler.getAssemblerFile() != null ) {
++ Dataset thing = null;
++ // Two variants: plain dataset with TDB2 dataset or plain building
++ // (which may go wrong later if TDB2 directly is needed).
++ try {
++ thing = (Dataset)AssemblerUtils.build(modAssembler.getAssemblerFile(), VocabTDB2.tDatasetTDB);
++ if ( thing != null && !(thing.asDatasetGraph() instanceof DatasetGraphTDB) )
++ Log.warn(this, "Unexpected: Not a TDB2 dataset for type DatasetTDB2");
++
++ if ( thing == null )
++ // Should use assembler inheritance but how do we assert
++ // the subclass relationship in a program?
++ thing = (Dataset)AssemblerUtils.build(modAssembler.getAssemblerFile(), DatasetAssemblerVocab.tDataset);
++ }
++ catch (JenaException ex) {
++ throw ex;
++ }
++ catch (Exception ex) {
++ throw new CmdException("Error creating", ex);
++ }
++ return thing;
++ }
++
++ if ( modAssembler.getLocation() == null )
++ throw new CmdException("No assembler file nor location provided");
++
++ // No assembler - use location to find a database.
++ Dataset ds = TDB2Factory.connectDataset(modAssembler.getLocation());
++ return ds;
++ }
++
++ public Location getLocation()
++ {
++ List<String> x = locations() ;
++ if ( x.size() == 0 )
++ return null ;
++ return Location.create(x.get(0)) ;
++ }
++
++ public List<String> locations()
++ {
++ List<String> locations = new ArrayList<>() ;
++
++ if ( modAssembler.getLocation() != null )
++ locations.add(modAssembler.getLocation().getDirectoryPath()) ;
++
++ // Extract the location from the assember file.
++ if ( modAssembler.getAssemblerFile() != null )
++ {
++ // Find and clear all locations
++ Model m = FileManager.get().loadModel(modAssembler.getAssemblerFile()) ;
++ Query query = QueryFactory.create("PREFIX tdb: <http://jena.hpl.hp.com/2008/tdb#> SELECT ?dir { [] tdb:location ?dir FILTER (isURI(?dir)) }") ;
++ try(QueryExecution qExec = QueryExecutionFactory.create(query, m)) {
++ for (ResultSet rs = qExec.execSelect() ; rs.hasNext() ; )
++ {
++ String x = rs.nextSolution().getResource("dir").getURI() ;
++ locations.add(x) ;
++ }
++ }
++ }
++
++ return locations ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/java/tdb2/tdbbackup.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/java/tdb2/tdbbackup.java
index 0000000,0000000..8291514
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/java/tdb2/tdbbackup.java
@@@ -1,0 -1,0 +1,55 @@@
++/*
++ * 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 tdb2;
++
++import arq.cmdline.ModLangOutput ;
++import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
++import org.seaborne.tdb2.sys.DatabaseOps ;
++import tdb2.cmdline.CmdTDB;
++
++public class tdbbackup extends CmdTDB
++{
++ static ModLangOutput modLangOutput = new ModLangOutput() ;
++
++ static public void main(String... argv)
++ {
++ CmdTDB.init() ;
++ new tdbbackup(argv).mainRun() ;
++ }
++
++ protected tdbbackup(String[] argv)
++ {
++ super(argv) ;
++ addModule(modLangOutput) ;
++ }
++
++ @Override
++ protected String getSummary()
++ {
++ return getCommandName()+" : Backup a TDB dataset" ;
++ }
++
++ @Override
++ protected void exec()
++ {
++ DatasetGraphSwitchable dsg = getDatabaseContainer();
++ String fn = DatabaseOps.backup(dsg);
++ System.out.println("Backup written to "+fn);
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/java/tdb2/tdbcompact.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/java/tdb2/tdbcompact.java
index 0000000,0000000..ea2e275
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/java/tdb2/tdbcompact.java
@@@ -1,0 -1,0 +1,48 @@@
++/*
++ * 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 tdb2;
++
++import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
++import org.seaborne.tdb2.sys.DatabaseOps ;
++import tdb2.cmdline.CmdTDB;
++
++public class tdbcompact extends CmdTDB {
++ static public void main(String... argv) {
++ CmdTDB.init() ;
++ new tdbcompact(argv).mainRun() ;
++ }
++
++ protected tdbcompact(String[] argv) {
++ super(argv) ;
++ }
++
++ @Override
++ protected String getSummary() {
++ return getCommandName() + " : Compact a TDB2 dataset" ;
++ }
++
++ @Override
++ protected void exec() {
++ DatasetGraphSwitchable dsg = getDatabaseContainer() ;
++ long start = System.currentTimeMillis();
++ DatabaseOps.compact(dsg) ;
++ long finish = System.currentTimeMillis();
++ System.out.printf("Compacted in %.3fs", (finish-start)/1000.0);
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/java/tdb2/tdbdump.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/java/tdb2/tdbdump.java
index 0000000,0000000..9c50e87
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/java/tdb2/tdbdump.java
@@@ -1,0 -1,0 +1,66 @@@
++/*
++ * 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 tdb2;
++
++import arq.cmdline.ModLangOutput ;
++import jena.cmd.CmdException ;
++import org.apache.jena.riot.RDFDataMgr ;
++import org.apache.jena.riot.RDFFormat ;
++import org.apache.jena.riot.RDFLanguages ;
++import org.apache.jena.sparql.core.DatasetGraph ;
++import org.seaborne.dboe.jenax.Txn;
++import tdb2.cmdline.CmdTDB;
++
++public class tdbdump extends CmdTDB
++{
++ static ModLangOutput modLangOutput = new ModLangOutput() ;
++
++ static public void main(String... argv) {
++ CmdTDB.init() ;
++ new tdbdump(argv).mainRun() ;
++ }
++
++ protected tdbdump(String[] argv) {
++ super(argv) ;
++ addModule(modLangOutput) ;
++ }
++
++ @Override
++ protected String getSummary() {
++ return getCommandName() + " : Write a dataset to stdout (defaults to N-Quads)" ;
++ }
++
++ @Override
++ protected void exec() {
++ DatasetGraph dsg = getDatasetGraph() ;
++ // Prefer stream over fully pretty output formats.
++ RDFFormat fmt = modLangOutput.getOutputStreamFormat() ;
++ // Stream writing happens naturally - no need to call StreamRDFWriter.
++ //if ( fmt != null && StreamRDFWriter.registered(fmt) )
++ if ( fmt == null )
++ fmt = modLangOutput.getOutputFormatted() ;
++ if ( fmt == null )
++ // Default.
++ fmt = RDFFormat.NQUADS ;
++ if ( ! RDFLanguages.isQuads(fmt.getLang() ))
++ throw new CmdException("Databases can be dumped only in quad formats (e.g. Trig, N-Quads), not "+fmt.getLang()) ;
++ RDFFormat fmtFinal = fmt ;
++ Txn.executeRead(dsg, ()->RDFDataMgr.write(System.out, dsg, fmtFinal));
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/java/tdb2/tdbloader.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/java/tdb2/tdbloader.java
index 0000000,0000000..f31cb70
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/java/tdb2/tdbloader.java
@@@ -1,0 -1,0 +1,175 @@@
++/*
++ * 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 tdb2 ;
++
++import java.util.List ;
++
++import jena.cmd.ArgDecl;
++import jena.cmd.CmdException;
++import org.apache.jena.atlas.lib.FileOps;
++import org.apache.jena.atlas.lib.NotImplemented;
++import org.apache.jena.atlas.lib.ProgressMonitor;
++import org.apache.jena.graph.Graph;
++import org.apache.jena.query.ARQ ;
++import org.apache.jena.riot.Lang ;
++import org.apache.jena.riot.RDFDataMgr;
++import org.apache.jena.riot.RDFLanguages ;
++import org.apache.jena.riot.system.ProgressStreamRDF;
++import org.apache.jena.riot.system.StreamRDF;
++import org.apache.jena.riot.system.StreamRDFLib;
++import org.apache.jena.sparql.core.DatasetGraph;
++import org.apache.jena.system.Txn;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++import tdb2.cmdline.CmdTDB;
++import tdb2.cmdline.CmdTDBGraph;
++
++public class tdbloader extends CmdTDBGraph {
++ // private static final ArgDecl argParallel = new ArgDecl(ArgDecl.NoValue, "parallel") ;
++ // private static final ArgDecl argIncremental = new ArgDecl(ArgDecl.NoValue, "incr", "incremental") ;
++ private static final ArgDecl argNoStats = new ArgDecl(ArgDecl.NoValue, "nostats") ;
++ private static final ArgDecl argStats = new ArgDecl(ArgDecl.HasValue, "stats") ;
++
++ private boolean showProgress = true ;
++ private boolean generateStats = true ;
++
++ static public void main(String... argv) {
++ CmdTDB.init() ;
++ new tdbloader(argv).mainRun() ;
++ }
++
++ protected tdbloader(String[] argv) {
++ super(argv) ;
++ super.add(argNoStats, "--nostats", "Switch off statistics gathering") ;
++ super.add(argStats) ; // Hidden argument
++ }
++
++ @Override
++ protected void processModulesAndArgs() {
++ super.processModulesAndArgs() ;
++ }
++
++ @Override
++ protected String getSummary() {
++ return getCommandName() + " [--desc DATASET | -loc DIR] FILE ..." ;
++ }
++
++ @Override
++ protected void exec() {
++ if ( isVerbose() ) {
++ System.out.println("Java maximum memory: " + Runtime.getRuntime().maxMemory()) ;
++ System.out.println(ARQ.getContext()) ;
++ }
++ if ( isVerbose() )
++ showProgress = true ;
++ if ( isQuiet() )
++ showProgress = false ;
++ if ( super.contains(argStats) ) {
++ if ( ! hasValueOfTrue(argStats) && ! hasValueOfFalse(argStats) )
++ throw new CmdException("Not a boolean value: "+getValue(argStats)) ;
++ generateStats = super.hasValueOfTrue(argStats) ;
++ }
++
++ if ( super.contains(argNoStats))
++ generateStats = false ;
++
++ List<String> urls = getPositional() ;
++ if ( urls.size() == 0 )
++ urls.add("-") ;
++
++ if ( graphName == null ) {
++ loadQuads(urls) ;
++ return ;
++ }
++
++ // There's a --graph.
++ // Check/warn that there are no quads formats mentioned
++ // (RIOT will take the default graph from quads).
++
++ for ( String url : urls ) {
++ Lang lang = RDFLanguages.filenameToLang(url) ;
++ if ( lang != null && RDFLanguages.isQuads(lang) ) {
++ System.err.println("Warning: Quads format given - only the default graph is loaded into the graph for --graph") ;
++ break ;
++ }
++ }
++
++ loadNamedGraph(urls) ;
++ }
++
++// void loadDefaultGraph(List<String> urls) {
++// GraphTDB graph = getGraph() ;
++// TDBLoader.load(graph, urls, showProgress) ;
++// return ;
++// }
++
++ void loadNamedGraph(List<String> urls) {
++ Graph graph = getGraph() ;
++ TDBLoader.load(graph, urls, showProgress) ;
++ return ;
++ }
++
++ void loadQuads(List<String> urls) {
++ TDBLoader.load(getDatasetGraph(), urls, showProgress, generateStats) ;
++ return ;
++ }
++
++ /** Tick point for messages during loading of data */
++ public static int DataTickPoint = 50 * 1000 ;
++ /** Tick point for messages during secondary index creation */
++ public static long IndexTickPoint = 100 * 1000 ;
++
++ /** Number of ticks per super tick */
++ public static int superTick = 10 ;
++
++ private static Logger LOG = LoggerFactory.getLogger("TDB2");
++
++ static class TDBLoader {
++
++ public static void load(DatasetGraph dsg, List<String> urls, boolean showProgress, boolean generateStats) {
++ Txn.executeWrite(dsg, ()->{
++ urls.forEach((x)->loadOne(dsg, x, showProgress));
++ });
++ }
++
++ private static void loadOne(DatasetGraph dsg, String x, boolean showProgress) {
++ StreamRDF dest = StreamRDFLib.dataset(dsg);
++ StreamRDF sink = dest;
++ ProgressMonitor monitor = null;
++ if ( showProgress ) {
++ String basename = FileOps.splitDirFile(x).get(1);
++ monitor = ProgressMonitor.create(LOG, basename, DataTickPoint, superTick);
++ sink = new ProgressStreamRDF(sink, monitor);
++ }
++ if ( monitor!= null )
++ monitor.start();
++ sink.start();
++ RDFDataMgr.parse(sink, x);
++ sink.finish();
++ if ( monitor!= null ) {
++ monitor.finish();
++ monitor.finishMessage();
++ }
++ }
++
++ public static void load(Graph graph, List<String> urls, boolean showProgress) {
++ throw new NotImplemented();
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/java/tdb2/tdbquery.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/java/tdb2/tdbquery.java
index 0000000,0000000..fffe597
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/java/tdb2/tdbquery.java
@@@ -1,0 -1,0 +1,51 @@@
++/*
++ * 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 tdb2;
++
++import arq.query;
++import arq.cmdline.ModDataset;
++import tdb2.cmdline.CmdTDB;
++import tdb2.cmdline.ModTDBDataset;
++
++public class tdbquery extends query {
++ // Inherits from arq.query so is not a CmdTDB. Mixins for Java!
++ public static void main(String... argv) {
++ CmdTDB.init();
++ new tdbquery(argv).mainRun();
++ }
++
++ public tdbquery(String[] argv) {
++ super(argv);
++ }
++
++ @Override
++ protected String getSummary() {
++ return getCommandName() + " --loc=<path> --query=<query>";
++ }
++
++// @Override
++// protected void processModulesAndArgs() {
++// super.processModulesAndArgs();
++// }
++
++ @Override
++ protected ModDataset setModDataset() {
++ return new ModTDBDataset();
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/java/tdb2/tdbstats.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/java/tdb2/tdbstats.java
index 0000000,0000000..7f53199
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/java/tdb2/tdbstats.java
@@@ -1,0 -1,0 +1,99 @@@
++/*
++ * 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 tdb2;
++
++import java.util.Iterator ;
++
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.atlas.logging.Log ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.sparql.core.Quad ;
++import org.seaborne.dboe.jenax.Txn;
++import org.seaborne.tdb2.solver.SolverLib;
++import org.seaborne.tdb2.solver.stats.Stats;
++import org.seaborne.tdb2.solver.stats.StatsCollectorNodeId;
++import org.seaborne.tdb2.solver.stats.StatsResults;
++import org.seaborne.tdb2.store.DatasetGraphTDB;
++import org.seaborne.tdb2.store.NodeId;
++import org.seaborne.tdb2.store.nodetable.NodeTable;
++import org.seaborne.tdb2.store.nodetupletable.NodeTupleTable;
++import org.seaborne.tdb2.sys.TDBInternal ;
++import tdb2.cmdline.CmdTDB;
++import tdb2.cmdline.CmdTDBGraph;
++
++public class tdbstats extends CmdTDBGraph {
++ static public void main(String... argv) {
++ CmdTDB.init();
++ new tdbstats(argv).mainRun();
++ }
++
++ protected tdbstats(String[] argv) {
++ super(argv);
++ }
++
++ @Override
++ protected String getSummary() {
++ return null;
++ }
++
++ public static StatsResults stats(DatasetGraphTDB dsg, Node gn) {
++ return Txn.calculateRead(dsg, ()->stats$(dsg, gn));
++ }
++
++ private static StatsResults stats$(DatasetGraphTDB dsg, Node gn) {
++
++ NodeTable nt = dsg.getTripleTable().getNodeTupleTable().getNodeTable();
++ StatsCollectorNodeId stats = new StatsCollectorNodeId(nt);
++
++ if ( gn == null ) {
++ Iterator<Tuple<NodeId>> iter = dsg.getTripleTable().getNodeTupleTable().findAll();
++ for ( ; iter.hasNext() ; ) {
++ Tuple<NodeId> t = iter.next();
++ stats.record(null, t.get(0), t.get(1), t.get(2));
++ }
++ } else {
++ // If the union graph, then we need to scan all quads but with uniqueness.
++ boolean unionGraph = Quad.isUnionGraph(gn) ;
++ NodeId gnid = null ;
++ if ( !unionGraph ) {
++ gnid = nt.getNodeIdForNode(gn);
++ if ( NodeId.isDoesNotExist(gnid) )
++ Log.warn(tdbstats.class, "No such graph: " + gn);
++ }
++
++ NodeTupleTable ntt = dsg.getQuadTable().getNodeTupleTable();
++ Iterator<Tuple<NodeId>> iter = unionGraph
++ ? SolverLib.unionGraph(ntt)
++ : ntt.find(gnid, null, null, null) ;
++ for ( ; iter.hasNext() ; ) {
++ Tuple<NodeId> t = iter.next();
++ stats.record(t.get(0), t.get(1), t.get(2), t.get(3));
++ }
++ }
++ return stats.results();
++ }
++
++ @Override
++ protected void exec() {
++ DatasetGraphTDB dsg = TDBInternal.getDatasetGraphTDB(getDatasetGraph());
++ Node gn = getGraphName();
++ StatsResults results = stats(dsg, gn);
++ Stats.write(System.out, results);
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/java/tdb2/tdbupdate.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/java/tdb2/tdbupdate.java
index 0000000,0000000..cbe0245
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/java/tdb2/tdbupdate.java
@@@ -1,0 -1,0 +1,56 @@@
++/*
++ * 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 tdb2;
++
++import arq.cmdline.ModDataset;
++import jena.cmd.CmdException;
++import org.apache.jena.sparql.core.DatasetGraph;
++import org.seaborne.tdb2.TDB2;
++import tdb2.cmdline.CmdTDB;
++import tdb2.cmdline.ModTDBDataset;
++
++public class tdbupdate extends arq.update {
++ // Inherits from arq.update so is not a CmdTDB. Mixins for Java!
++ public static void main(String... argv) {
++ CmdTDB.init();
++ new tdbupdate(argv).mainRun();
++ }
++
++ public tdbupdate(String[] argv) {
++ super(argv);
++ // Because this inherits from an ARQ command
++ CmdTDB.init();
++ super.modVersion.addClass(TDB2.class);
++ }
++
++ @Override
++ protected void processModulesAndArgs() {
++ super.processModulesAndArgs();
++ }
++
++ @Override
++ protected ModDataset setModeDataset() {
++ return new ModTDBDataset();
++ }
++
++ @Override
++ protected DatasetGraph dealWithNoDataset() {
++ throw new CmdException("No dataset provided");
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/resources/META-INF/LICENSE
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/resources/META-INF/LICENSE
index 0000000,0000000..67db858
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/resources/META-INF/LICENSE
@@@ -1,0 -1,0 +1,175 @@@
++
++ Apache License
++ Version 2.0, January 2004
++ http://www.apache.org/licenses/
++
++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
++
++ 1. Definitions.
++
++ "License" shall mean the terms and conditions for use, reproduction,
++ and distribution as defined by Sections 1 through 9 of this document.
++
++ "Licensor" shall mean the copyright owner or entity authorized by
++ the copyright owner that is granting the License.
++
++ "Legal Entity" shall mean the union of the acting entity and all
++ other entities that control, are controlled by, or are under common
++ control with that entity. For the purposes of this definition,
++ "control" means (i) the power, direct or indirect, to cause the
++ direction or management of such entity, whether by contract or
++ otherwise, or (ii) ownership of fifty percent (50%) or more of the
++ outstanding shares, or (iii) beneficial ownership of such entity.
++
++ "You" (or "Your") shall mean an individual or Legal Entity
++ exercising permissions granted by this License.
++
++ "Source" form shall mean the preferred form for making modifications,
++ including but not limited to software source code, documentation
++ source, and configuration files.
++
++ "Object" form shall mean any form resulting from mechanical
++ transformation or translation of a Source form, including but
++ not limited to compiled object code, generated documentation,
++ and conversions to other media types.
++
++ "Work" shall mean the work of authorship, whether in Source or
++ Object form, made available under the License, as indicated by a
++ copyright notice that is included in or attached to the work
++ (an example is provided in the Appendix below).
++
++ "Derivative Works" shall mean any work, whether in Source or Object
++ form, that is based on (or derived from) the Work and for which the
++ editorial revisions, annotations, elaborations, or other modifications
++ represent, as a whole, an original work of authorship. For the purposes
++ of this License, Derivative Works shall not include works that remain
++ separable from, or merely link (or bind by name) to the interfaces of,
++ the Work and Derivative Works thereof.
++
++ "Contribution" shall mean any work of authorship, including
++ the original version of the Work and any modifications or additions
++ to that Work or Derivative Works thereof, that is intentionally
++ submitted to Licensor for inclusion in the Work by the copyright owner
++ or by an individual or Legal Entity authorized to submit on behalf of
++ the copyright owner. For the purposes of this definition, "submitted"
++ means any form of electronic, verbal, or written communication sent
++ to the Licensor or its representatives, including but not limited to
++ communication on electronic mailing lists, source code control systems,
++ and issue tracking systems that are managed by, or on behalf of, the
++ Licensor for the purpose of discussing and improving the Work, but
++ excluding communication that is conspicuously marked or otherwise
++ designated in writing by the copyright owner as "Not a Contribution."
++
++ "Contributor" shall mean Licensor and any individual or Legal Entity
++ on behalf of whom a Contribution has been received by Licensor and
++ subsequently incorporated within the Work.
++
++ 2. Grant of Copyright License. Subject to the terms and conditions of
++ this License, each Contributor hereby grants to You a perpetual,
++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
++ copyright license to reproduce, prepare Derivative Works of,
++ publicly display, publicly perform, sublicense, and distribute the
++ Work and such Derivative Works in Source or Object form.
++
++ 3. Grant of Patent License. Subject to the terms and conditions of
++ this License, each Contributor hereby grants to You a perpetual,
++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
++ (except as stated in this section) patent license to make, have made,
++ use, offer to sell, sell, import, and otherwise transfer the Work,
++ where such license applies only to those patent claims licensable
++ by such Contributor that are necessarily infringed by their
++ Contribution(s) alone or by combination of their Contribution(s)
++ with the Work to which such Contribution(s) was submitted. If You
++ institute patent litigation against any entity (including a
++ cross-claim or counterclaim in a lawsuit) alleging that the Work
++ or a Contribution incorporated within the Work constitutes direct
++ or contributory patent infringement, then any patent licenses
++ granted to You under this License for that Work shall terminate
++ as of the date such litigation is filed.
++
++ 4. Redistribution. You may reproduce and distribute copies of the
++ Work or Derivative Works thereof in any medium, with or without
++ modifications, and in Source or Object form, provided that You
++ meet the following conditions:
++
++ (a) You must give any other recipients of the Work or
++ Derivative Works a copy of this License; and
++
++ (b) You must cause any modified files to carry prominent notices
++ stating that You changed the files; and
++
++ (c) You must retain, in the Source form of any Derivative Works
++ that You distribute, all copyright, patent, trademark, and
++ attribution notices from the Source form of the Work,
++ excluding those notices that do not pertain to any part of
++ the Derivative Works; and
++
++ (d) If the Work includes a "NOTICE" text file as part of its
++ distribution, then any Derivative Works that You distribute must
++ include a readable copy of the attribution notices contained
++ within such NOTICE file, excluding those notices that do not
++ pertain to any part of the Derivative Works, in at least one
++ of the following places: within a NOTICE text file distributed
++ as part of the Derivative Works; within the Source form or
++ documentation, if provided along with the Derivative Works; or,
++ within a display generated by the Derivative Works, if and
++ wherever such third-party notices normally appear. The contents
++ of the NOTICE file are for informational purposes only and
++ do not modify the License. You may add Your own attribution
++ notices within Derivative Works that You distribute, alongside
++ or as an addendum to the NOTICE text from the Work, provided
++ that such additional attribution notices cannot be construed
++ as modifying the License.
++
++ You may add Your own copyright statement to Your modifications and
++ may provide additional or different license terms and conditions
++ for use, reproduction, or distribution of Your modifications, or
++ for any such Derivative Works as a whole, provided Your use,
++ reproduction, and distribution of the Work otherwise complies with
++ the conditions stated in this License.
++
++ 5. Submission of Contributions. Unless You explicitly state otherwise,
++ any Contribution intentionally submitted for inclusion in the Work
++ by You to the Licensor shall be under the terms and conditions of
++ this License, without any additional terms or conditions.
++ Notwithstanding the above, nothing herein shall supersede or modify
++ the terms of any separate license agreement you may have executed
++ with Licensor regarding such Contributions.
++
++ 6. Trademarks. This License does not grant permission to use the trade
++ names, trademarks, service marks, or product names of the Licensor,
++ except as required for reasonable and customary use in describing the
++ origin of the Work and reproducing the content of the NOTICE file.
++
++ 7. Disclaimer of Warranty. Unless required by applicable law or
++ agreed to in writing, Licensor provides the Work (and each
++ Contributor provides its Contributions) on an "AS IS" BASIS,
++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
++ implied, including, without limitation, any warranties or conditions
++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
++ PARTICULAR PURPOSE. You are solely responsible for determining the
++ appropriateness of using or redistributing the Work and assume any
++ risks associated with Your exercise of permissions under this License.
++
++ 8. Limitation of Liability. In no event and under no legal theory,
++ whether in tort (including negligence), contract, or otherwise,
++ unless required by applicable law (such as deliberate and grossly
++ negligent acts) or agreed to in writing, shall any Contributor be
++ liable to You for damages, including any direct, indirect, special,
++ incidental, or consequential damages of any character arising as a
++ result of this License or out of the use or inability to use the
++ Work (including but not limited to damages for loss of goodwill,
++ work stoppage, computer failure or malfunction, or any and all
++ other commercial damages or losses), even if such Contributor
++ has been advised of the possibility of such damages.
++
++ 9. Accepting Warranty or Additional Liability. While redistributing
++ the Work or Derivative Works thereof, You may choose to offer,
++ and charge a fee for, acceptance of support, warranty, indemnity,
++ or other liability obligations and/or rights consistent with this
++ License. However, in accepting such obligations, You may act only
++ on Your own behalf and on Your sole responsibility, not on behalf
++ of any other Contributor, and only if You agree to indemnify,
++ defend, and hold each Contributor harmless for any liability
++ incurred by, or claims asserted against, such Contributor by reason
++ of your accepting any such warranty or additional liability.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/resources/META-INF/NOTICE
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/resources/META-INF/NOTICE
index 0000000,0000000..5ba7ec0
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/resources/META-INF/NOTICE
@@@ -1,0 -1,0 +1,10 @@@
++Mantis Database Operating Environment
++
++Copyright 2013-2017 Andy Seaborne
++Copyright 2014, 2015 Epimorphics Ltd.
++
++Portions of this software derive from software from Apache Jena:
++ - Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
++ - Copyright 2010, 2011 Epimorphics Ltd.
++ - Copyright 2010, 2011 Talis Systems Ltd.
++These have been licensed to the Apache Software Foundation under a software grant.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/resources/META-INF/services/org.apache.jena.system.JenaSubsystemLifecycle
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/resources/META-INF/services/org.apache.jena.system.JenaSubsystemLifecycle
index 0000000,0000000..21f02ea
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/resources/META-INF/services/org.apache.jena.system.JenaSubsystemLifecycle
@@@ -1,0 -1,0 +1,1 @@@
++org.seaborne.tdb2.sys.InitTDB2
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/src/main/resources/org/apache/jena/tdb/tdb-properties.xml
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/src/main/resources/org/apache/jena/tdb/tdb-properties.xml
index 0000000,0000000..67d8255
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/src/main/resources/org/apache/jena/tdb/tdb-properties.xml
@@@ -1,0 -1,0 +1,8 @@@
++<?xml version="1.0" encoding="UTF-8"?>
++<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
++<!-- Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0 -->
++<properties version="1.0">
++ <comment>TDB System Properties</comment>
++ <entry key="org.apache.jena.tdb.version">${project.version}</entry>
++ <entry key="org.apache.jena.tdb.build.datetime">${build.time.xsd}</entry>
++</properties>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/tdb2
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/tdb2
index 0000000,0000000..d2772db
new file mode 100755
--- /dev/null
+++ b/jena-db/tdb2-cmds/tdb2
@@@ -1,0 -1,0 +1,99 @@@
++#!/usr/bin/env bash
++
++## Usage: tdb2
++## Sets up the java enviroment to run Jena-based commands.
++
++CP=
++
++#JENA_CP="$(jena)"
++## If Jena development, this needs to be different.
++JENA_CP="$HOME/jlib/apache-jena/lib/"'*'
++
++## Log4j
++LOG4J_CP="/home/afs/.m2/repo/org/slf4j/slf4j-log4j12/1.7.25/slf4j-log4j12-1.7.25.jar:/home/afs/.m2/repo/log4j/log4j/1.2.17/log4j-1.2.17.jar"
++## JUL
++JUL_CP="/home/afs/.m2/repo/org/slf4j/slf4j-jdk14/1.7.25/slf4j-jdk14-1.7.25.jar"
++
++H="$HOME/Mantis"
++D=
++
++# modules
++# Not dboe-index-test
++read -r -d '' MODULES << EOM
++dboe-base
++dboe-index
++dboe-transaction
++dboe-trans-data
++tdb2
++tdb2-cmds
++EOM
++
++if true # if in development area ./
++then
++ for X in $MODULES
++ do
++ [[ $D = "" ]] || D="$D:"
++ D="${D}$H/$X/target/classes"
++ done
++else
++ ## @@ By artifacts ...
++ echo "Not implemented: classpath by artifacts" 2>&1
++ exit 9
++fi
++
++
++TDB2_CP="$D"
++
++if [[ -e logging.properties ]]
++then
++ LOGGING_JUL=-Djava.util.logging.config.file=logging.properties
++fi
++if [[ -e log4j.properties ]]
++then
++ LOGGING_LOG4J=-Dlog4j.configuration=file:log4j.properties
++fi
++
++if [[ $# = 0 ]]
++then
++ echo "Class path: $TDB2_CP:${JENA_CP}"
++ exit
++ #echo "No class to run" 1>&2
++ #exit 1
++else
++ CMD="$1"
++ shift
++fi
++
++# Map CMD to class name
++TDB2_PKG="tdb2"
++
++# Alternative names.
++## case $CMD in
++## ???
++## CMD=tdb2.$CMD
++## ;;
++## *) ;;
++## esac
++
++# Map to class name.
++case $CMD in
++ "")
++ ;;
++ tdbbackup | tdbdump | tdbloader | tdbquery | tdbstats | tdbupdate | tdbcompact)
++ CMD_CLS="$TDB2_PKG"."$CMD"
++ ;;
++## tools.*)
++## CMD_CLS="${BASE_PKG}"."$CMD"
++## ;;
++ *)
++ echo "Unknown command $CMD" 2>&1
++ exit 1
++ ;;
++
++esac
++
++## echo "TDB2_CP=$TDB2_CP"
++## echo "JENA_CP=$JENA_CP"
++#echo java $JVM_ARGS $LOGGING_LOG4J $LOGGING_JUL -cp "$TDB2_CP:${JENA_CP}" "$CMD_CLS" "$@"
++
++java $JVM_ARGS $LOGGING_LOG4J $LOGGING_JUL -cp "$TDB2_CP:${JENA_CP}" "$CMD_CLS" "$@"
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Assembler/tdb-dataset-embed.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Assembler/tdb-dataset-embed.ttl
index 0000000,0000000..9edd5a3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Assembler/tdb-dataset-embed.ttl
@@@ -1,0 -1,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.
++
++@prefix tdb2: <http://jena.apache.org/2016/tdb#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
++
++<#dataset> rdf:type tdb2:DatasetTDB2 ;
++ tdb2:location "--mem--" ;
++ .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Assembler/tdb-dataset.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Assembler/tdb-dataset.ttl
index 0000000,0000000..c9d8d7b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Assembler/tdb-dataset.ttl
@@@ -1,0 -1,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.
++
++@prefix tdb2: <http://jena.apache.org/2016/tdb#> .
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
++
++<#dataset> rdf:type tdb2:DatasetTDB2 ;
++ # Do at least one the long way.
++ tdb2:location "target/tdb-testing/DB" ;
++ .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Assembler/tdb-graph-embed.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Assembler/tdb-graph-embed.ttl
index 0000000,0000000..af3daab
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Assembler/tdb-graph-embed.ttl
@@@ -1,0 -1,0 +1,27 @@@
++# 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.
++
++@prefix tdb2: <http://jena.apache.org/2016/tdb#> .
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
++
++<#dataset> rdf:type ja:RDFDataset ;
++ ja:defaultGraph <#graph> ;
++ .
++
++<#graph> rdf:type tdb2:GraphTDB2 ;
++ tdb2:location "--mem--" ;
++ .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Assembler/tdb-graph-ref-dataset.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Assembler/tdb-graph-ref-dataset.ttl
index 0000000,0000000..fe256bd
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Assembler/tdb-graph-ref-dataset.ttl
@@@ -1,0 -1,0 +1,31 @@@
++# 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.
++
++@prefix tdb2: <http://jena.apache.org/2016/tdb#> .
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
++
++<#dataset> rdf:type ja:RDFDataset ;
++ ja:defaultGraph <#graph> ;
++ .
++
++<#graph> rdf:type tdb2:GraphTDB2 ;
++ tdb2:dataset <#dataset> ;
++ .
++
++<#dataset> rdf:type tdb2:DatasetTDB2 ;
++ tdb2:location "--mem--" ;
++ .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Assembler/tdb-graph.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Assembler/tdb-graph.ttl
index 0000000,0000000..2ae8396
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Assembler/tdb-graph.ttl
@@@ -1,0 -1,0 +1,27 @@@
++# 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.
++
++@prefix tdb2: <http://jena.apache.org/2016/tdb#> .
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
++
++<#dataset> rdf:type ja:RDFDataset ;
++ ja:defaultGraph <#graph> ;
++ .
++
++<#graph> rdf:type tdb2:GraphTDB2 ;
++ tdb2:location "target/tdb-testing/DB" ;
++ .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Assembler/tdb-named-graph-1.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Assembler/tdb-named-graph-1.ttl
index 0000000,0000000..78e40cf
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Assembler/tdb-named-graph-1.ttl
@@@ -1,0 -1,0 +1,29 @@@
++
++# 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.
++
++@prefix tdb2: <http://jena.apache.org/2016/tdb#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
++
++<#dataset> rdf:type ja:RDFDataset ;
++ ja:defaultGraph <#graph> ;
++ .
++
++<#graph> rdf:type tdb2:GraphTDB2 ;
++ tdb2:location "--mem--" ;
++ tdb2:graphName "http://example.com/graph" ;
++ .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Assembler/tdb-named-graph-2.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Assembler/tdb-named-graph-2.ttl
index 0000000,0000000..ee2feab
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Assembler/tdb-named-graph-2.ttl
@@@ -1,0 -1,0 +1,28 @@@
++# 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.
++
++@prefix tdb2: <http://jena.apache.org/2016/tdb#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
++
++<#dataset> rdf:type ja:RDFDataset ;
++ ja:defaultGraph <#graph> ;
++ .
++
++<#graph> rdf:type tdb2:GraphTDB2 ;
++ tdb2:location "--mem--" ;
++ tdb2:graphName "http://example.com/graph" ;
++ .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/basic-00.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/basic-00.rq
index 0000000,0000000..f2341a0
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/basic-00.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example>
++
++SELECT *
++{ ?x ?p ?z }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/basic-1-O.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/basic-1-O.rq
index 0000000,0000000..e1d1da7
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/basic-1-O.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ ?x ?p :z1 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/basic-1-P.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/basic-1-P.rq
index 0000000,0000000..d64b9f9
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/basic-1-P.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ ?x :p1 ?z }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/basic-1-PO.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/basic-1-PO.rq
index 0000000,0000000..01fa14a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/basic-1-PO.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ ?x :p1 :z1 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/basic-1-S.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/basic-1-S.rq
index 0000000,0000000..180188e
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/basic-1-S.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ :x1 ?p ?z }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/basic-1-SO.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/basic-1-SO.rq
index 0000000,0000000..a4242fb
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/basic-1-SO.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ :x1 ?p :z1 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/basic-1-SP.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/basic-1-SP.rq
index 0000000,0000000..37ddfe6
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/basic-1-SP.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ :x1 :p1 ?z }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/basic-1-SPO.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/basic-1-SPO.rq
index 0000000,0000000..41aa20f
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/basic-1-SPO.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT ?v
++{ :x1 :p1 :z1 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/basic-2-SO.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/basic-2-SO.rq
index 0000000,0000000..49c5711
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/basic-2-SO.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ ?x ?p ?x }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/basic-3-O.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/basic-3-O.rq
index 0000000,0000000..f7f3f6b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/basic-3-O.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ ?x ?p :z1a }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/basic-3-P.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/basic-3-P.rq
index 0000000,0000000..8c79fa5
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/basic-3-P.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ ?x :p1a ?z }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/basic-3-PO.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/basic-3-PO.rq
index 0000000,0000000..a011a1c
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/basic-3-PO.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ ?x :p1 :z1a }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/basic-3-S.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/basic-3-S.rq
index 0000000,0000000..8b62930
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/basic-3-S.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ :x1a ?p ?z }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/basic-3-SO.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/basic-3-SO.rq
index 0000000,0000000..e71f0b3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/basic-3-SO.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ :x1 ?p :z1a }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/basic-3-SP.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/basic-3-SP.rq
index 0000000,0000000..3b7ff81
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/basic-3-SP.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ :x1a :p1 ?z }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/data-1.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/data-1.ttl
index 0000000,0000000..d3a3d80
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/data-1.ttl
@@@ -1,0 -1,0 +1,17 @@@
++@prefix : <http://example/> .
++
++:x1 :p1 :z1 .
++:x1 :p1 :z2 .
++
++:x1 :p2 :z1 .
++:x1 :p2 :z2 .
++
++:x2 :p1 :z1 .
++:x2 :p1 :z2 .
++
++:x2 :p2 :z1 .
++:x2 :p2 :z2 .
++
++:x :p :x .
++:x :x :x .
++
[13/50] [abbrv] jena git commit: Remove DatasetControl - no longer
applies
Posted by an...@apache.org.
Remove DatasetControl - no longer applies
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/982c0c7f
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/982c0c7f
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/982c0c7f
Branch: refs/heads/jena-tdb2
Commit: 982c0c7f6321bb280006624554e36669a9e98348
Parents: 4e8fc3b
Author: Andy Seaborne <an...@seaborne.org>
Authored: Mon Sep 4 10:36:48 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Mon Sep 4 10:36:48 2017 +0100
----------------------------------------------------------------------
.../org/seaborne/tdb2/setup/TDBBuilder.java | 8 +-
.../org/seaborne/tdb2/store/DatasetControl.java | 44 ------
.../seaborne/tdb2/store/DatasetControlMRSW.java | 144 -------------------
.../seaborne/tdb2/store/DatasetControlNone.java | 48 -------
.../tdb2/store/DatasetControlReadOnly.java | 59 --------
.../java/org/seaborne/tdb2/store/QuadTable.java | 4 +-
.../java/org/seaborne/tdb2/store/TableBase.java | 5 +-
.../org/seaborne/tdb2/store/TripleTable.java | 5 +-
.../store/nodetupletable/NodeTupleTable.java | 4 -
.../nodetupletable/NodeTupleTableConcrete.java | 66 ++++-----
.../nodetupletable/NodeTupleTableWrapper.java | 5 -
11 files changed, 33 insertions(+), 359 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/982c0c7f/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 67ee708..88e18fc 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/setup/TDBBuilder.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/setup/TDBBuilder.java
@@ -143,8 +143,6 @@ public class TDBBuilder {
return new TDBBuilder(txnCoord, location, params, new ComponentIdMgr(UUID.randomUUID())) ;
}
- private DatasetControl createPolicy() { return new DatasetControlNone() ; }
-
/** Look at a directory and see if it is a new area */
private static boolean isNewDatabaseArea(Location location) {
if ( location.isMem() )
@@ -188,7 +186,7 @@ public class TDBBuilder {
if ( tripleIndexes.length != indexes.length )
error(log, "Wrong number of triple table tuples indexes: "+tripleIndexes.length) ;
- TripleTable tripleTable = new TripleTable(tripleIndexes, nodeTable, createPolicy()) ;
+ TripleTable tripleTable = new TripleTable(tripleIndexes, nodeTable) ;
return tripleTable ;
}
@@ -205,7 +203,7 @@ public class TDBBuilder {
if ( tripleIndexes.length != indexes.length )
error(log, "Wrong number of triple table tuples indexes: "+tripleIndexes.length) ;
- QuadTable tripleTable = new QuadTable(tripleIndexes, nodeTable, createPolicy()) ;
+ QuadTable tripleTable = new QuadTable(tripleIndexes, nodeTable) ;
return tripleTable ;
}
@@ -221,7 +219,7 @@ public class TDBBuilder {
//NodeTable prefixNodes = makeNodeTable(location, pnNode2Id, pnId2Node, -1, -1, -1) ;
NodeTupleTable prefixTable = new NodeTupleTableConcrete(primary.length(),
prefixIndexes,
- prefixNodes, createPolicy()) ;
+ prefixNodes) ;
DatasetPrefixesTDB prefixes = new DatasetPrefixesTDB(prefixTable) ;
log.debug("Prefixes: "+primary+" :: "+String.join(",", indexes)) ;
return prefixes ;
http://git-wip-us.apache.org/repos/asf/jena/blob/982c0c7f/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
deleted file mode 100644
index b283ed4..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControl.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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/982c0c7f/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
deleted file mode 100644
index d4c9f57..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControlMRSW.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * 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/982c0c7f/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
deleted file mode 100644
index b1bf51b..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControlNone.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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/982c0c7f/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
deleted file mode 100644
index 85b31be..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetControlReadOnly.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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/982c0c7f/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 15a14ff..6d4b366 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/QuadTable.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/QuadTable.java
@@ -34,8 +34,8 @@ import org.seaborne.tdb2.store.tupletable.TupleIndex ;
*/
public class QuadTable extends TableBase {
- public QuadTable(TupleIndex[] indexes, NodeTable nodeTable, DatasetControl policy) {
- super(4, indexes, nodeTable, policy) ;
+ public QuadTable(TupleIndex[] indexes, NodeTable nodeTable) {
+ super(4, indexes, nodeTable) ;
}
/** Add a quad - return true if it was added, false if it already existed */
http://git-wip-us.apache.org/repos/asf/jena/blob/982c0c7f/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 05b80ab..1241a0b 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/TableBase.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/TableBase.java
@@ -28,12 +28,11 @@ public class TableBase implements Sync, Closeable
{
final protected NodeTupleTable table ;
- protected TableBase(int N, TupleIndex[] indexes, NodeTable nodeTable, DatasetControl policy) {
- table = new NodeTupleTableConcrete(N, indexes, nodeTable, policy) ;
+ protected TableBase(int N, TupleIndex[] indexes, NodeTable nodeTable) {
+ table = new NodeTupleTableConcrete(N, indexes, nodeTable) ;
}
public NodeTupleTable getNodeTupleTable() { return table ; }
- public DatasetControl getPolicy() { return table.getPolicy() ; }
@Override
public void sync() {
http://git-wip-us.apache.org/repos/asf/jena/blob/982c0c7f/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 8e5aeb9..a85494b 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/TripleTable.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/TripleTable.java
@@ -35,9 +35,8 @@ import org.seaborne.tdb2.store.tupletable.TupleIndex ;
*/
public class TripleTable extends TableBase {
- public TripleTable(TupleIndex[] indexes, NodeTable nodeTable, DatasetControl policy) {
- super(3, indexes, nodeTable, policy) ;
- // table = new NodeTupleTableConcrete(3, indexes, nodeTable, policy) ;
+ public TripleTable(TupleIndex[] indexes, NodeTable nodeTable) {
+ super(3, indexes, nodeTable) ;
}
/** Add triple */
http://git-wip-us.apache.org/repos/asf/jena/blob/982c0c7f/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 89139c9..4d48189 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,7 +23,6 @@ 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 ;
@@ -69,7 +68,4 @@ public interface NodeTupleTable extends Sync, Closeable
// and node tables separately.
public long size() ;
-
- /** Return the current policy, if any, for this NodeTupleTable */
- public DatasetControl getPolicy() ;
}
http://git-wip-us.apache.org/repos/asf/jena/blob/982c0c7f/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 0d967f0..e2fc5a9 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,7 +27,6 @@ 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 ;
@@ -38,14 +37,13 @@ public class NodeTupleTableConcrete implements NodeTupleTable
{
protected final NodeTable nodeTable ;
protected final TupleTable tupleTable ;
- private final DatasetControl dsPolicy ;
/*
* Concurrency checking: Everything goes through one of
* addRow, deleteRow or find*
*/
- public NodeTupleTableConcrete(int N, TupleIndex[] indexes, NodeTable nodeTable, DatasetControl dsControl)
+ public NodeTupleTableConcrete(int N, TupleIndex[] indexes, NodeTable nodeTable)
{
if (indexes.length == 0 || indexes[0] == null) throw new TDBException("A primary index is required") ;
for (TupleIndex index : indexes)
@@ -55,24 +53,19 @@ public class NodeTupleTableConcrete implements NodeTupleTable
N, index.getMappingStr(), index.getTupleLength())) ;
}
- this.dsPolicy = dsControl ;
this.tupleTable = new TupleTable(N, indexes) ;
this.nodeTable = nodeTable ;
}
- private void startWrite() { dsPolicy.startUpdate() ; }
+ private void startWrite() { }
- private void finishWrite() { dsPolicy.finishUpdate() ; }
+ private void finishWrite() { }
- private void startRead() { dsPolicy.startRead() ; }
+ private void startRead() { }
- private void finishRead() { dsPolicy.finishRead() ; }
+ private void finishRead() { }
@Override
- public DatasetControl getPolicy()
- { return dsPolicy ; }
-
- @Override
public void addRow(Node... nodes)
{
try {
@@ -180,73 +173,61 @@ public class NodeTupleTableConcrete implements NodeTupleTable
// ==== Node
- protected final NodeId idForNode(Node node)
- {
- if (node == null || node == Node.ANY) return NodeId.NodeIdAny ;
- if (node.isVariable()) throw new TDBException("Can't pass variables to NodeTupleTable.find*") ;
+ protected final NodeId idForNode(Node node) {
+ if ( node == null || node == Node.ANY )
+ return NodeId.NodeIdAny ;
+ if ( node.isVariable() )
+ throw new TDBException("Can't pass variables to NodeTupleTable.find*") ;
return nodeTable.getNodeIdForNode(node) ;
}
// ==== Accessors
/**
- * Return the undelying tuple table - used with great care by tools that
- * directly manipulate internal structures.
+ * Return the undelying tuple table - used with great care by tools that directly
+ * manipulate internal structures.
*/
@Override
- public final TupleTable getTupleTable()
- {
+ public final TupleTable getTupleTable() {
return tupleTable ;
}
/** Return the node table */
@Override
- public final NodeTable getNodeTable()
- {
+ public final NodeTable getNodeTable() {
return nodeTable ;
}
@Override
- public boolean isEmpty()
- {
+ public boolean isEmpty() {
return tupleTable.isEmpty() ;
}
/** Clear the tuple table - does not clear the node table */
@Override
- public void clear()
- {
+ public void clear() {
try {
startWrite() ;
tupleTable.clear() ;
- } finally {
- finishWrite() ;
- }
+ } finally { finishWrite() ; }
}
@Override
- public long size()
- {
+ public long size() {
return tupleTable.size() ;
}
- // @Override
@Override
- public final void close()
- {
- try
- {
+ public final void close() {
+ try {
startWrite() ;
tupleTable.close() ;
nodeTable.close() ;
- }
- finally { finishWrite() ; }
+ } finally { finishWrite() ; }
}
- // @Override
@Override
- public final void sync()
- {
+ public final void sync() {
try {
startWrite() ;
tupleTable.sync() ;
@@ -254,5 +235,6 @@ public class NodeTupleTableConcrete implements NodeTupleTable
} finally { finishWrite() ; }
}
- private <T> Iterator<T> iteratorControl(Iterator<T> iter) { return dsPolicy.iteratorControl(iter) ; }
+ // Add any iterator checking.
+ private <T> Iterator<T> iteratorControl(Iterator<T> iter) { return iter; }
}
http://git-wip-us.apache.org/repos/asf/jena/blob/982c0c7f/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 e54f964..952dda9 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,7 +21,6 @@ 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 ;
@@ -77,10 +76,6 @@ public class NodeTupleTableWrapper implements NodeTupleTable
{ return nodeTupleTable.getTupleTable() ; }
@Override
- public DatasetControl getPolicy()
- { return nodeTupleTable.getPolicy() ; }
-
- @Override
public boolean isEmpty()
{ return nodeTupleTable.isEmpty() ; }
[04/50] [abbrv] jena git commit: Switch to switchable
Posted by an...@apache.org.
Switch to switchable
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/780d6716
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/780d6716
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/780d6716
Branch: refs/heads/jena-tdb2
Commit: 780d67167bf4018f579ccbc56f8606962d3b665a
Parents: d72f696
Author: Andy Seaborne <an...@seaborne.org>
Authored: Thu Aug 31 12:55:23 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Thu Aug 31 12:55:46 2017 +0100
----------------------------------------------------------------------
.../java/org/seaborne/tdb2/DatabaseMgr.java | 15 +-
.../seaborne/tdb2/sys/DatabaseConnection.java | 34 ++--
.../java/org/seaborne/tdb2/sys/DatabaseOps.java | 26 +--
.../org/seaborne/tdb2/sys/StoreConnection.java | 6 +-
.../test/java/org/seaborne/tdb2/TS_Factory.java | 11 +-
.../seaborne/tdb2/TestDatabaseConnection.java | 68 ++++++++
.../java/org/seaborne/tdb2/TestDatabaseMgr.java | 89 +++++++++++
.../java/org/seaborne/tdb2/TestDatabaseOps.java | 114 +++++++++++++
.../java/org/seaborne/tdb2/TestTDBFactory.java | 159 ++++++++++---------
.../test/java/org/seaborne/tdb2/junit/TL.java | 10 +-
.../AbstractTestStoreConnectionBasics.java | 3 +-
11 files changed, 422 insertions(+), 113 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/780d6716/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
index 33a4a6b..7b3ff17 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/DatabaseMgr.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/DatabaseMgr.java
@@ -18,14 +18,13 @@
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.DatabaseConnection ;
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}.
@@ -36,10 +35,9 @@ 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() ;
+ return DatabaseConnection.connectCreate(location).getDatasetGraph();
+// // One level.
+// return StoreConnection.connectCreate(location).getDatasetGraph() ;
}
/** Create or connect to a TDB2-backed dataset */
@@ -73,10 +71,11 @@ public class DatabaseMgr {
* and does not lock out other use of the dataset.
*
* @param container
+ * @return File name of the backup.
*/
- public static void backup(DatasetGraph container) {
+ public static String backup(DatasetGraph container) {
DatasetGraphSwitchable dsg = requireSwitchable(container);
- throw new NotImplementedException("DatasetGraph backup not implemented yet");
+ return DatabaseOps.backup(dsg);
}
http://git-wip-us.apache.org/repos/asf/jena/blob/780d6716/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
index 3fa4983..62c5949 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseConnection.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseConnection.java
@@ -21,7 +21,9 @@ package org.seaborne.tdb2.sys;
import java.io.IOException ;
import java.nio.file.Path ;
import java.nio.file.Paths ;
+import java.util.HashSet ;
import java.util.Map ;
+import java.util.Set ;
import java.util.concurrent.ConcurrentHashMap ;
import org.apache.jena.atlas.io.IO ;
@@ -68,21 +70,20 @@ public class DatabaseConnection {
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));
+ DatabaseConnection dbConn = cache.computeIfAbsent(location, (loc)->buildForCache(loc, params));
return dbConn ;
}
- private static DatabaseConnection buildForCache(Location location, ProcessFileLock lock, StoreParams params) {
+ private static DatabaseConnection buildForCache(Location location, StoreParams params) {
if ( location.isMemUnique() ) {
throw new TDBException("Can't buildForCache a memory-unique location");
}
+ ProcessFileLock lock = null;
+ if (SystemTDB.DiskLocationMultiJvmUsagePrevention && ! location.isMem() ) {
+ lock = lockForLocation(location);
+ // Take the lock. This is atomic.
+ lock.lockEx();
+ }
DatasetGraph dsg = DatabaseOps.create(location);
return new DatabaseConnection(dsg, location, lock) ;
}
@@ -130,6 +131,21 @@ public class DatabaseConnection {
}
}
+ /**
+ * Stop managing all locations.
+ * Use with extreme care.
+ * This is intended to support internal testing.
+ */
+ public static synchronized void reset() {
+ // Copy to avoid potential CME.
+ Set<Location> x = new HashSet<>(cache.keySet()) ;
+ for (Location loc : x)
+ expel(loc, true) ;
+ cache.clear() ;
+ StoreConnection.reset();
+ }
+
+
// One of the other.
private final DatasetGraphSwitchable datasetGraphSwitchable;
private final DatasetGraph datasetGraph;
http://git-wip-us.apache.org/repos/asf/jena/blob/780d6716/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
index 8a375b9..82dc579 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
@@ -27,6 +27,7 @@ import java.util.zip.GZIPOutputStream ;
import org.apache.jena.atlas.RuntimeIOException ;
import org.apache.jena.atlas.lib.DateTimeUtils ;
+import org.apache.jena.atlas.lib.Pair ;
import org.apache.jena.atlas.logging.Log;
import org.apache.jena.riot.Lang ;
import org.apache.jena.riot.RDFDataMgr ;
@@ -42,6 +43,8 @@ import org.seaborne.tdb2.repack.sys.FilenameUtils;
import org.seaborne.tdb2.repack.sys.Util;
import org.seaborne.tdb2.setup.StoreParams;
import org.seaborne.tdb2.store.DatasetGraphTDB;
+import org.slf4j.Logger ;
+import org.slf4j.LoggerFactory ;
/** Operations on and about TDB2 databases.
* <p>
@@ -60,6 +63,7 @@ import org.seaborne.tdb2.store.DatasetGraphTDB;
* </ul>
*/
public class DatabaseOps {
+ private static Logger LOG = LoggerFactory.getLogger(DatabaseOps.class);
private static final String dbPrefix = "Data";
private static final String SEP = "-";
private static final String startCount = "0001";
@@ -68,15 +72,15 @@ public class DatabaseOps {
// Basename of the backup file. "backup_{DateTime}.nq.gz
private static final String BACKUPS_FN = "backup";
+ /** Create a fresh database - called by {@code DatabaseMgr}.
+ * It is important to go via {@code DatabaseConnection} to avoid
+ * duplicate {@code DatasetGraphSwitchable}s for the same location.
+ */
/*package*/ static DatasetGraph create(Location location) {
// Hide implementation class.
return createSwitchable(location);
}
- /** Create a fresh database - called by {@code DatabaseMgr}.
- * It is important to go via {@code DatabaseMgr} to avoid
- * duplicate {@code DatasetGraphSwitchable}s for the same location.
- */
private static DatasetGraphSwitchable createSwitchable(Location location) {
if ( location.isMem() ) {
DatasetGraph dsg = StoreConnection.connectCreate(location).getDatasetGraph();
@@ -100,7 +104,7 @@ public class DatabaseOps {
return appDSG;
}
- public static void backup(DatasetGraphSwitchable container) {
+ public static String backup(DatasetGraphSwitchable container) {
checkSupportsAdmin(container);
Path dbPath = container.getContainerPath();
Path backupDir = dbPath.resolve(BACKUPS_DIR);
@@ -117,14 +121,15 @@ public class DatabaseOps {
// activeBackups.add(dsg) ;
// }
- try (OutputStream out2 = openUniqueFileForWriting(backupDir, BACKUPS_FN, "nq.gz");
+ Pair<OutputStream, Path> x = openUniqueFileForWriting(backupDir, BACKUPS_FN, "nq.gz");
+ try (OutputStream out2 = x.getLeft();
OutputStream out1 = new GZIPOutputStream(out2, 8 * 1024) ;
OutputStream out = new BufferedOutputStream(out1)) {
Txn.executeRead(dsg, ()->RDFDataMgr.write(out, dsg, Lang.NQUADS));
} catch (IOException e) {
throw IOX.exception(e) ;
- } finally {
}
+ return x.getRight().toString();
}
private static void checkSupportsAdmin(DatasetGraphSwitchable container) {
@@ -136,7 +141,7 @@ public class DatabaseOps {
// --> IOX
- private static OutputStream openUniqueFileForWriting(Path dirPath, String basename, String ext) {
+ private static Pair<OutputStream, Path> openUniqueFileForWriting(Path dirPath, String basename, String ext) {
if ( ! Files.isDirectory(dirPath) )
throw new IllegalArgumentException("Not a directory: "+dirPath);
if ( basename.contains("/") || basename.contains("\\") )
@@ -148,7 +153,8 @@ public class DatabaseOps {
int x = 0 ;
for(;;) {
try {
- return Files.newOutputStream(p, StandardOpenOption.CREATE_NEW);
+ OutputStream out = Files.newOutputStream(p, StandardOpenOption.CREATE_NEW);
+ return Pair.create(out, p);
} catch (AccessDeniedException ex) {
throw IOX.exception("Access denied", ex);
} catch (FileAlreadyExistsException ex) {
@@ -193,7 +199,7 @@ public class DatabaseOps {
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());
+ LOG.debug(String.format("Compact %s -> %s\n", db1.getFileName(), db2.getFileName()));
compact(container, loc1, loc2);
}
http://git-wip-us.apache.org/repos/asf/jena/blob/780d6716/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java
index f73032d..3ef596f 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java
@@ -96,7 +96,11 @@ public class StoreConnection
return sConn ;
}
- /** Stop managing all locations. Use with great care. */
+ /**
+ * Stop managing all locations.
+ * Use with extreme care.
+ * This is intended to support internal testing.
+ */
public static synchronized void reset() {
// Copy to avoid potential CME.
Set<Location> x = new HashSet<>(cache.keySet()) ;
http://git-wip-us.apache.org/repos/asf/jena/blob/780d6716/tdb2/src/test/java/org/seaborne/tdb2/TS_Factory.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/TS_Factory.java b/tdb2/src/test/java/org/seaborne/tdb2/TS_Factory.java
index eb8fb1d..d963ad3 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/TS_Factory.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/TS_Factory.java
@@ -23,10 +23,13 @@ import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses( {
- TestTDBFactory.class
+ TestDatabaseMgr.class
+ , TestTDBFactory.class
+
+ // Move to TS_Sys
+ , TestDatabaseOps.class
+ , TestDatabaseConnection.class
})
public class TS_Factory
-{
-
-}
+{}
http://git-wip-us.apache.org/repos/asf/jena/blob/780d6716/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseConnection.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseConnection.java b/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseConnection.java
new file mode 100644
index 0000000..a720b11
--- /dev/null
+++ b/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseConnection.java
@@ -0,0 +1,68 @@
+/*
+ * 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 static org.junit.Assert.assertNotSame ;
+import static org.junit.Assert.assertSame ;
+
+import org.apache.jena.atlas.lib.FileOps ;
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.junit.Test ;
+import org.seaborne.dboe.base.file.Location ;
+import org.seaborne.tdb2.sys.DatabaseConnection ;
+
+public class TestDatabaseConnection {
+
+ @Test
+ public void testStoreConnectionTxn1() {
+ DatabaseConnection.reset() ;
+ // Only do disk things for test that need them (disk takes time!).
+ String DIRx = ConfigTest.getCleanDir() ;
+ Location DIR = Location.create(DIRx);
+ FileOps.clearDirectory(DIRx) ;
+ try {
+ DatasetGraph dg1 = DatabaseConnection.connectCreate(DIR).getDatasetGraph() ;
+ DatasetGraph dg2 = DatabaseConnection.connectCreate(DIR).getDatasetGraph() ;
+ assertSame(dg1, dg2) ;
+ }
+ finally {
+ FileOps.clearDirectory(DIRx) ;
+ }
+ }
+
+ @Test
+ public void testStoreConnectionTxn2() {
+ // Named memory locations
+ DatabaseConnection.reset() ;
+ DatasetGraph dg1 = DatabaseConnection.connectCreate(Location.mem("FOO")).getDatasetGraph() ;
+ DatasetGraph dg2 = DatabaseConnection.connectCreate(Location.mem("FOO")).getDatasetGraph() ;
+ assertSame(dg1, dg2) ;
+ }
+
+ @Test
+ public void testStoreConnectionTxn3() {
+ // Un-named memory locations
+ DatabaseConnection.reset() ;
+ DatasetGraph dg1 = DatabaseConnection.connectCreate(Location.mem()).getDatasetGraph() ;
+ DatasetGraph dg2 = DatabaseConnection.connectCreate(Location.mem()).getDatasetGraph() ;
+ assertNotSame(dg1, dg2) ;
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/780d6716/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java b/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java
new file mode 100644
index 0000000..5251b8b
--- /dev/null
+++ b/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java
@@ -0,0 +1,89 @@
+/*
+ * 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;
+
+import org.apache.jena.atlas.junit.BaseTest ;
+import org.apache.jena.atlas.lib.FileOps ;
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.apache.jena.sparql.core.Quad ;
+import org.apache.jena.sparql.sse.SSE ;
+import org.junit.Test ;
+import org.seaborne.dboe.base.file.Location ;
+import org.seaborne.dboe.jenax.Txn ;
+import org.seaborne.tdb2.sys.DatabaseConnection ;
+
+/** Test of DatabaseMgr - the DatasetGraph level API to TDB2 **/
+public class TestDatabaseMgr extends BaseTest
+{
+// String DIRx = ConfigTest.getCleanDir() ;
+// Location DIR = Location.create(DIRx);
+
+ static Quad quad1 = SSE.parseQuad("(_ _:a <p> 1)") ;
+ static Quad quad2 = SSE.parseQuad("(_ <s> <p> 1)") ;
+
+ @Test
+ public void testDatabaseMgr1() {
+ DatabaseConnection.reset() ;
+ DatasetGraph dg1 = DatabaseMgr.connectDatasetGraph(Location.mem("FOO")) ;
+ DatasetGraph dg2 = DatabaseMgr.connectDatasetGraph(Location.mem("FOO")) ;
+ Txn.executeWrite(dg1, ()->{
+ dg1.add(quad1) ;
+ }) ;
+ Txn.executeRead(dg2, ()->{
+ assertTrue(dg2.contains(quad1)) ;
+ }) ;
+ }
+
+ @Test
+ public void testDatabaseMgr2() {
+ DatabaseConnection.reset() ;
+ // The unnamed location is unique each time.
+ DatasetGraph dg1 = DatabaseMgr.connectDatasetGraph(Location.mem()) ;
+ DatasetGraph dg2 = DatabaseMgr.connectDatasetGraph(Location.mem()) ;
+ Txn.executeWrite(dg1, ()->{
+ dg1.add(quad1) ;
+ }) ;
+ Txn.executeRead(dg2, ()->{
+ assertFalse(dg2.contains(quad1)) ;
+ }) ;
+ }
+
+ @Test
+ public void testDatabaseMgrDisk() {
+ DatabaseConnection.reset() ;
+ // The named disk location
+ String DIRx = ConfigTest.getCleanDir() ;
+ Location LOC = Location.create(DIRx) ;
+ FileOps.clearDirectory(DIRx) ;
+ try {
+ DatasetGraph dg1 = DatabaseMgr.connectDatasetGraph(LOC) ;
+ DatasetGraph dg2 = DatabaseMgr.connectDatasetGraph(Location.create(LOC.getDirectoryPath())) ;
+ assertSame(dg1, dg2) ;
+ Txn.executeWrite(dg1, ()-> {
+ dg1.add(quad1) ;
+ }) ;
+ Txn.executeRead(dg2, ()-> {
+ assertTrue(dg2.contains(quad1)) ;
+ }) ;
+ }
+ finally {
+ FileOps.clearDirectory(DIRx) ;
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/780d6716/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseOps.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseOps.java b/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseOps.java
new file mode 100644
index 0000000..406758b
--- /dev/null
+++ b/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseOps.java
@@ -0,0 +1,114 @@
+/*
+ * 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;
+
+import static org.junit.Assert.* ;
+
+import org.apache.commons.io.FileUtils ;
+import org.apache.jena.atlas.lib.FileOps ;
+import org.apache.jena.riot.RDFDataMgr ;
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.apache.jena.sparql.core.Quad ;
+import org.apache.jena.sparql.sse.SSE ;
+import org.junit.After ;
+import org.junit.Before ;
+import org.junit.Test ;
+import org.seaborne.dboe.base.file.Location ;
+import org.seaborne.dboe.jenax.Txn ;
+import org.seaborne.tdb2.repack.DatasetGraphSwitchable ;
+import org.seaborne.tdb2.store.DatasetGraphTDB ;
+import org.seaborne.tdb2.sys.DatabaseConnection ;
+import org.seaborne.tdb2.sys.IOX ;
+import org.seaborne.tdb2.sys.StoreConnection ;
+
+public class TestDatabaseOps
+{
+ static String DIRx = ConfigTest.getCleanDir() ;
+ static Location DIR = Location.create(DIRx);
+
+ static Quad quad1 = SSE.parseQuad("(_ _:a <p> 1)") ;
+ static Quad quad2 = SSE.parseQuad("(_ <s> <p> 1)") ;
+
+ @Before
+ public void before() {
+ FileUtils.deleteQuietly(IOX.asFile(DIR));
+ FileOps.ensureDir(DIR.getDirectoryPath());
+ }
+
+ @After
+ public void after() {
+ DatabaseConnection.reset();
+ FileUtils.deleteQuietly(IOX.asFile(DIR));
+ }
+
+ @Test public void compact_1() {
+ DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(DIR);
+ DatasetGraphSwitchable dsgs = (DatasetGraphSwitchable)dsg;
+ DatasetGraph dsg1 = dsgs.get();
+ Location loc1 = ((DatasetGraphTDB)dsg1).getLocation();
+
+ Txn.executeWrite(dsg, ()-> {
+ dsg.add(quad1) ;
+ dsg.add(quad2) ;
+ }) ;
+ DatabaseMgr.compact(dsg);
+ DatasetGraph dsg2 = dsgs.get();
+ Location loc2 = ((DatasetGraphTDB)dsg2).getLocation();
+
+ assertNotEquals(dsg1, dsg2);
+ assertNotEquals(loc1, loc2);
+
+ Txn.executeRead(dsg, ()-> {
+ assertTrue(dsg.contains(quad1)) ;
+ assertTrue(dsg.contains(quad2)) ;
+ }) ;
+
+ // Naughty!
+ // dsg1 was closed and expelled. We must reopen its storage only.
+ DatasetGraph dsgOld = StoreConnection.connectCreate(loc1).getDatasetGraph();
+
+ Txn.executeWrite(dsgOld, ()->dsgOld.delete(quad1));
+
+ Txn.executeWrite(dsg, ()->assertTrue(dsg.contains(quad1)) );
+
+ Txn.executeWrite(dsg2, ()->assertTrue(dsg2.contains(quad1)) ) ;
+
+ StoreConnection.expel(loc1, true);
+ }
+
+// @Test public void compact_2() {
+// }
+
+ @Test public void backup_1() {
+ DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(DIR);
+ Txn.executeWrite(dsg, ()-> {
+ dsg.add(quad1) ;
+ dsg.add(quad2) ;
+ }) ;
+ String file1 = DatabaseMgr.backup(dsg);
+ DatasetGraph dsg2 = RDFDataMgr.loadDatasetGraph(file1);
+ Txn.executeRead(dsg, ()-> {
+ assertTrue(dsg.contains(quad2)) ;
+ assertEquals(2, dsg.getDefaultGraph().size());
+ assertTrue(dsg2.getDefaultGraph().isIsomorphicWith(dsg.getDefaultGraph()));
+ }) ;
+ String file2 = DatabaseMgr.backup(dsg);
+ assertNotEquals(file1, file2);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/780d6716/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java b/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
index fd6ba1c..7d1c780 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
@@ -19,103 +19,112 @@ package org.seaborne.tdb2;
import org.apache.jena.atlas.junit.BaseTest ;
import org.apache.jena.atlas.lib.FileOps ;
-import org.apache.jena.sparql.core.DatasetGraph ;
-import org.apache.jena.sparql.core.Quad ;
-import org.apache.jena.sparql.sse.SSE ;
-import org.junit.After ;
-import org.junit.Before ;
+import org.apache.jena.datatypes.xsd.XSDDatatype ;
+import org.apache.jena.query.Dataset ;
+import org.apache.jena.rdf.model.Literal ;
+import org.apache.jena.rdf.model.Property ;
+import org.apache.jena.rdf.model.Resource ;
+import org.apache.jena.rdf.model.ResourceFactory ;
import org.junit.Test ;
import org.seaborne.dboe.base.file.Location ;
import org.seaborne.dboe.jenax.Txn ;
-import org.seaborne.tdb2.sys.StoreConnection ;
+import org.seaborne.tdb2.sys.DatabaseConnection ;
+/** Test of TDB2Factory - the Dataset level API to TDB2 **/
public class TestTDBFactory extends BaseTest
{
- String DIRx = ConfigTest.getCleanDir() ;
- Location DIR = Location.create(DIRx);
+ static Resource s1 = ResourceFactory.createResource("http://example/s2");
+ static Resource s2 = ResourceFactory.createResource();
+ static Property p = ResourceFactory.createProperty("http://example/ns#", "p");
+ static Literal o1 = ResourceFactory.createPlainLiteral("object");
+ static Literal o2 = ResourceFactory.createTypedLiteral("1", XSDDatatype.XSDinteger);
- static Quad quad1 = SSE.parseQuad("(_ <s> <p> 1)") ;
- static Quad quad2 = SSE.parseQuad("(_ <s> <p> 1)") ;
-
- @Before
- public void before() {
- FileOps.clearDirectory(DIRx) ;
- }
-
- @After
- public void after() {
- FileOps.clearDirectory(DIRx) ;
- }
-
@Test
public void testTDBFactory1() {
- StoreConnection.reset() ;
- DatasetGraph dg1 = DatabaseMgr.connectDatasetGraph(Location.mem("FOO")) ;
- DatasetGraph dg2 = DatabaseMgr.connectDatasetGraph(Location.mem("FOO")) ;
- Txn.executeWrite(dg1, ()->{
- dg1.add(quad1) ;
- }) ;
- Txn.executeRead(dg2, ()->{
- assertTrue(dg2.contains(quad1)) ;
- }) ;
+ DatabaseConnection.reset() ;
+ Dataset ds = TDB2Factory.connectDataset(Location.mem()) ;
+ test(ds);
}
@Test
public void testTDBFactory2() {
- StoreConnection.reset() ;
- // The unnamed location is unique each time.
- DatasetGraph dg1 = DatabaseMgr.connectDatasetGraph(Location.mem()) ;
- DatasetGraph dg2 = DatabaseMgr.connectDatasetGraph(Location.mem()) ;
- Txn.executeWrite(dg1, ()->{
- dg1.add(quad1) ;
- }) ;
- Txn.executeRead(dg2, ()->{
- assertFalse(dg2.contains(quad1)) ;
- }) ;
+ DatabaseConnection.reset() ;
+ Dataset ds = TDB2Factory.connectDataset(Location.mem("MEMORY")) ;
+ test(ds);
}
-
-
+
@Test
- public void testStoreConnectionTxn1() {
- StoreConnection.reset() ;
- DatasetGraph dg1 = StoreConnection.connectCreate(DIR).getDatasetGraph() ;
- DatasetGraph dg2 = StoreConnection.connectCreate(DIR).getDatasetGraph() ;
- assertSame(dg1, dg2) ;
+ public void testTDBFactory3() {
+ DatabaseConnection.reset() ;
+ // Only do disk things for tests that need them (disk takes time!).
+ String DIRx = ConfigTest.getCleanDir() ;
+ Location DIR = Location.create(DIRx);
+ try {
+ FileOps.clearDirectory(DIRx) ;
+ Dataset ds = TDB2Factory.connectDataset(DIR) ;
+ test(ds);
+ } finally { FileOps.clearDirectory(DIRx) ; }
}
@Test
- public void testStoreConnectionTxn2() {
- // Named memory locations
- StoreConnection.reset() ;
- DatasetGraph dg1 = StoreConnection.connectCreate(Location.mem("FOO")).getDatasetGraph() ;
- DatasetGraph dg2 = StoreConnection.connectCreate(Location.mem("FOO")).getDatasetGraph() ;
-
- assertSame(dg1, dg2) ;
+ public void testTDBFactory2DS_1() {
+ DatabaseConnection.reset() ;
+ Dataset ds1 = TDB2Factory.connectDataset(Location.mem("FOO")) ;
+ Dataset ds2 = TDB2Factory.connectDataset(Location.mem("FOO")) ;
+ Txn.executeWrite(ds1, ()->{
+ ds1.getDefaultModel().add(s1, p, o1);
+ });
+ Txn.executeRead(ds2, ()->{
+ assertTrue(ds2.getDefaultModel().contains(s1, p, o1));
+ });
}
@Test
- public void testStoreConnectionTxn3() {
- // Un-named memory locations
- StoreConnection.reset() ;
- DatasetGraph dg1 = StoreConnection.connectCreate(Location.mem()).getDatasetGraph() ;
- DatasetGraph dg2 = StoreConnection.connectCreate(Location.mem()).getDatasetGraph() ;
-
- assertNotSame(dg1, dg2) ;
+ public void testTDBFactory2DS_2() {
+ DatabaseConnection.reset() ;
+ // The unnamed location is unique each time.
+ Dataset ds1 = TDB2Factory.connectDataset(Location.mem()) ;
+ Dataset ds2 = TDB2Factory.connectDataset(Location.mem()) ;
+ Txn.executeWrite(ds1, ()->{
+ ds1.getDefaultModel().add(s1, p, o1);
+ });
+ Txn.executeRead(ds2, ()->{
+ assertFalse(ds2.getDefaultModel().contains(s1, p, o1));
+ });
}
-
+
@Test
- public void testTDBFactoryDisk() {
- StoreConnection.reset() ;
- // The named disk location
- Location loc = DIR;
- DatasetGraph dg1 = DatabaseMgr.connectDatasetGraph(loc) ;
- DatasetGraph dg2 = DatabaseMgr.connectDatasetGraph(Location.create(loc.getDirectoryPath()));
- assertSame(dg1, dg2) ;
- Txn.executeWrite(dg1, ()->{
- dg1.add(quad1) ;
- }) ;
- Txn.executeRead(dg2, ()->{
- assertTrue(dg2.contains(quad1)) ;
- }) ;
+ public void testTDBFactory2DS_3() {
+ DatabaseConnection.reset() ;
+ DatabaseConnection.reset() ;
+ String DIRx = ConfigTest.getCleanDir() ;
+ Location DIR = Location.create(DIRx);
+ try {
+ Dataset ds1 = TDB2Factory.connectDataset(DIR) ;
+ Dataset ds2 = TDB2Factory.connectDataset(DIR) ;
+ Txn.executeWrite(ds1, ()->{
+ ds1.getDefaultModel().add(s1, p, o1);
+ });
+ Txn.executeRead(ds2, ()->{
+ assertTrue(ds2.getDefaultModel().contains(s1, p, o1));
+ });
+ } finally { FileOps.clearDirectory(DIRx) ; }
+ }
+
+ private static void test(Dataset ds) {
+ Txn.executeWrite(ds, ()->{
+ ds.getDefaultModel().add(s1, p, o1);
+ });
+ Txn.executeRead(ds, ()->{
+ assertTrue(ds.getDefaultModel().contains(s1, p, o1));
+ });
+ Txn.executeWrite(ds, ()->{
+ ds.getDefaultModel().remove(s1, p, o1);
+ ds.getDefaultModel().add(s2, p, o2);
+ });
+ Txn.executeRead(ds, ()->{
+ assertFalse(ds.getDefaultModel().contains(s1, p, o1));
+ assertTrue(ds.getDefaultModel().contains(s2, p, o2));
+ });
}
}
http://git-wip-us.apache.org/repos/asf/jena/blob/780d6716/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java b/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
index 47ee5d0..cd58c36 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
@@ -25,7 +25,7 @@ import org.seaborne.dboe.base.file.Location ;
import org.seaborne.tdb2.ConfigTest ;
import org.seaborne.tdb2.DatabaseMgr ;
import org.seaborne.tdb2.TDB2Factory ;
-import org.seaborne.tdb2.sys.StoreConnection ;
+import org.seaborne.tdb2.sys.DatabaseConnection ;
import org.seaborne.tdb2.sys.SystemTDB ;
/** Execute a test with a fresh dataset in a write transaction */
@@ -35,14 +35,14 @@ public class TL {
Dataset dataset = createTestDataset() ;
action.accept(dataset);
releaseDataset(dataset) ;
- StoreConnection.reset() ;
+ DatabaseConnection.reset() ;
}
public static void execMem(Consumer<Dataset> action) {
Dataset dataset = createTestDatasetMem() ;
action.accept(dataset);
- releaseDataset(dataset) ;
- StoreConnection.reset() ;
+ releaseDataset(dataset);
+ DatabaseConnection.reset();
}
// Or use these for @Before, @After style.
@@ -58,7 +58,7 @@ public class TL {
public static void releaseDataset(Dataset dataset) {
dataset.abort() ;
- StoreConnection.reset() ;
+ DatabaseConnection.reset() ;
}
public static Dataset createTestDataset() {
http://git-wip-us.apache.org/repos/asf/jena/blob/780d6716/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java b/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java
index a78ab67..854402b 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java
@@ -26,6 +26,7 @@ import org.junit.Before ;
import org.junit.Test ;
import org.seaborne.dboe.base.file.Location ;
import org.seaborne.dboe.jenax.Txn ;
+import org.seaborne.tdb2.sys.DatabaseConnection ;
import org.seaborne.tdb2.sys.StoreConnection ;
/** StoreConnection and transactions - basic wiring.
@@ -52,7 +53,7 @@ public abstract class AbstractTestStoreConnectionBasics extends BaseTest
@Before public void before()
{
- StoreConnection.reset() ;
+ DatabaseConnection.reset() ;
location = getLocation() ;
}
[41/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/rewriter/BPlusTreeRewriter.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/rewriter/BPlusTreeRewriter.java
index 0000000,0000000..16a535b
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/rewriter/BPlusTreeRewriter.java
@@@ -1,0 -1,0 +1,361 @@@
++/*
++ * 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.dboe.trans.bplustree.rewriter ;
++
++import static org.seaborne.dboe.trans.bplustree.rewriter.BPlusTreeRewriterUtils.divider ;
++import static org.seaborne.dboe.trans.bplustree.rewriter.BPlusTreeRewriterUtils.printIndexBlocks ;
++import static org.seaborne.dboe.trans.bplustree.rewriter.BPlusTreeRewriterUtils.summarizeDataBlocks ;
++
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import org.apache.jena.atlas.iterator.IteratorWithBuffer ;
++import org.apache.jena.atlas.lib.Pair ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.buffer.PtrBuffer ;
++import org.seaborne.dboe.base.buffer.RecordBuffer ;
++import org.seaborne.dboe.base.file.BufferChannel ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPage ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPageMgr ;
++import org.seaborne.dboe.trans.bplustree.* ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++public class BPlusTreeRewriter {
++ static private Logger log = LoggerFactory.getLogger(BPlusTreeRewriter.class) ;
++
++ static boolean rebalance = true ;
++ static boolean debug = false ;
++ static boolean materialize = debug ;
++
++ // Process:
++ // 1/ Take a stream of records and create leaves.
++ // Emit the RecordBufferPage (B+Tree leaves).
++ // 2/ Take a stream of RecordBufferPage and create the first level of
++ // branches.
++ // 3/ Take each branch level and create upper branches until root hit.
++ // 4/ Copy root block to root real location.
++
++ // --------------------------------
++
++ /**
++ * Given a stream of records and details of the B+Tree to build, go and
++ * build it.
++ *
++ * @return A newly built BPlusTree
++ */
++ public static BPlusTree packIntoBPlusTree(Iterator<Record> iterRecords, BPlusTreeParams bptParams, RecordFactory recordFactory,
++ BufferChannel bptState, BlockMgr blkMgrNodes, BlockMgr blkMgrRecords) {
++ // **** Attach to storage.
++ // Small caches as we mostly work on a block then move on.
++ // Only read behind and look ahead actually do any work on an existing
++ // block.
++ // (check this by rerunning with different cache sizes).
++
++ if ( !iterRecords.hasNext() )
++ // No records. Just return a B+Tree.
++ return BPlusTreeFactory.createNonTxn(bptParams, bptState, blkMgrNodes, blkMgrRecords) ;
++
++
++ // Initial B+tree needed to carry parameters around - not legal at this point.
++ BPlusTree bpt2 = BPT.createRootOnlyBPTree(bptParams, bptState, blkMgrNodes, blkMgrRecords) ;
++ // Get the root node.
++ // We will use this slot later and write in the correct root.
++ // The root has to be block zero currently.
++ BPTreeNode root = bpt2.getNodeManager().getWrite(BPlusTreeParams.RootId, BPlusTreeParams.RootParent) ;
++ // ******** Pack data blocks.
++ Iterator<Pair<Integer, Record>> iter = writePackedDataBlocks(iterRecords, bpt2) ;
++
++ // ******** Index layer
++ // Loop until one block only.
++ // Never zero blocks.
++ // Output is a single pair pointing to the root - but the root is in the
++ // wrong place.
++
++ boolean leafLayer = true ;
++ while (true) {
++ iter = genTreeLevel(iter, bpt2, leafLayer) ;
++ // Advances iter.
++ IteratorWithBuffer<Pair<Integer, Record>> iter2 = new IteratorWithBuffer<>(iter, 2) ;
++ boolean singleBlock = (iter2.peek(1) == null) ;
++ // Having peeked ahead, use the real stream.
++ iter = iter2 ;
++ if ( singleBlock )
++ break ;
++ leafLayer = false ;
++ }
++
++ // ******** Put root in right place.
++ Pair<Integer, Record> pair = iter.next() ;
++ if ( iter.hasNext() ) {
++ log.error("**** Building index layers didn't result in a single block") ;
++ return null ;
++ }
++ fixupRoot(root, pair, bpt2) ;
++ // ****** Finish the tree.
++ //bpt2.getStateManager().
++ blkMgrNodes.sync() ;
++ blkMgrRecords.sync() ;
++ return bpt2 ;
++ }
++
++ // **** data block phase
++
++ /** Pack record blocks into linked RecordBufferPages */
++ private static Iterator<Pair<Integer, Record>> writePackedDataBlocks(Iterator<Record> records, final BPlusTree bpt) {
++ if ( debug ) {
++ divider() ;
++ System.out.println("---- Data level") ;
++ }
++
++ final RecordBufferPageMgr mgr = bpt.getRecordsMgr().getRecordBufferPageMgr() ;
++ Iterator<RecordBufferPage> iter = new RecordBufferPageLinker(new RecordBufferPagePacker(records, mgr)) ;
++
++ // Write and convert to split pairs.
++ Iterator<Pair<Integer, Record>> iter2 = Iter.map(iter, rbp-> {
++ mgr.put(rbp) ;
++ Record r = rbp.getRecordBuffer().getHigh() ;
++ r = bpt.getRecordFactory().createKeyOnly(r) ;
++ return new Pair<>(rbp.getId(), r) ;
++ }) ;
++
++ if ( debug ) {
++ if ( rebalance )
++ System.out.println("Before rebalance (data)") ;
++ iter2 = summarizeDataBlocks(iter2, bpt.getRecordsMgr().getRecordBufferPageMgr()) ;
++ // iter2 = printDataBlocks(iter2,
++ // bpt.getRecordsMgr().getRecordBufferPageMgr()) ;
++ }
++
++ if ( rebalance )
++ iter2 = new RebalenceDataEnd(iter2, bpt) ;
++
++ // Testing - materialize - debug wil have done this
++ if ( materialize && !debug )
++ iter2 = Iter.toList(iter2).iterator() ;
++
++ if ( debug && rebalance ) {
++ System.out.println("After rebalance (data)") ;
++ iter2 = summarizeDataBlocks(iter2, bpt.getRecordsMgr().getRecordBufferPageMgr()) ;
++ // iter2 = printDataBlocks(iter2,
++ // bpt.getRecordsMgr().getRecordBufferPageMgr()) ;
++ }
++ return iter2 ;
++ }
++
++ private static class RebalenceDataEnd extends RebalenceBase {
++ private RecordBufferPageMgr mgr ;
++ private BPlusTree bpt ;
++
++ public RebalenceDataEnd(Iterator<Pair<Integer, Record>> iter, BPlusTree bpt) {
++ super(iter) ;
++ this.bpt = bpt ;
++ }
++
++ @Override
++ protected Record rebalance(int id1, Record r1, int id2, Record r2) {
++ RecordBufferPageMgr mgr = bpt.getRecordsMgr().getRecordBufferPageMgr() ;
++ RecordBufferPage page1 = mgr.getWrite(id1) ;
++ RecordBufferPage page2 = mgr.getWrite(id2) ;
++
++ // Wrong calculatation.
++ for ( int i = page2.getCount() ; i < page1.getMaxSize() / 2 ; i++ ) {
++ // shiftOneup(node1, node2) ;
++ Record r = page1.getRecordBuffer().getHigh() ;
++ page1.getRecordBuffer().removeTop() ;
++
++ page2.getRecordBuffer().add(0, r) ;
++ }
++
++ mgr.put(page1) ;
++ mgr.put(page2) ;
++
++ Record splitPoint = page1.getRecordBuffer().getHigh() ;
++ splitPoint = bpt.getRecordFactory().createKeyOnly(splitPoint) ;
++ // Record splitPoint = node1.maxRecord() ;
++ return splitPoint ;
++ }
++ }
++
++ // ---------------------------------------------------------------------------------------------
++
++ // **** tree block phase
++
++ /*
++ * Status: need to address the parent issue - how to set the parent as we
++ * work up the BPT. One way is to work in memory and assume that there is
++ * enough room for the B+Tree nodes (not the record nodes).
++ *
++ * Another way is to rely on the caching and two-pass each new layer to fix
++ * up parents.
++ *
++ * 3rd way - parents aren't actually used in B+Trees. Set the BPT code to
++ * ignore parent of -2. Always set the new nodes to -2 for a rebuild.
++ */
++
++ // Idea a layer processor for BPT nodes has a sink that is the parent.
++ // Need to rebal the last two blocks of a level.
++ // Same for data blocks.
++
++ // ---- Block stream to BTreeNodeStream.
++
++ private static Iterator<Pair<Integer, Record>> genTreeLevel(Iterator<Pair<Integer, Record>> iter, BPlusTree bpt, boolean leafLayer) {
++ if ( debug ) {
++ divider() ;
++ System.out.println("---- Index level") ;
++ List<Pair<Integer, Record>> x = Iter.toList(iter) ;
++ System.out.println(x) ;
++ iter = x.iterator() ;
++ }
++
++ Iterator<Pair<Integer, Record>> iter2 = new BPTreeNodeBuilder(iter, bpt.getNodeManager(), leafLayer, bpt.getRecordFactory()) ;
++
++ if ( debug ) {
++ if ( rebalance )
++ System.out.println("Before rebalance (index)") ;
++ // iter2 = summarizeIndexBlocks(iter2, bpt.getNodeManager()) ;
++ iter2 = printIndexBlocks(iter2, bpt.getNodeManager()) ;
++ }
++
++ if ( rebalance )
++ iter2 = new RebalenceIndexEnd(iter2, bpt, leafLayer) ;
++
++ if ( materialize && !debug )
++ iter2 = Iter.toList(iter2).iterator() ;
++
++ if ( debug && rebalance ) {
++ System.out.println("After rebalance (index)") ;
++ // iter2 = summarizeIndexBlocks(iter2, bpt.getNodeManager()) ;
++ iter2 = printIndexBlocks(iter2, bpt.getNodeManager()) ;
++ }
++ return iter2 ;
++ }
++
++ private abstract static class RebalenceBase extends IteratorWithBuffer<Pair<Integer, Record>> {
++ protected RebalenceBase(Iterator<Pair<Integer, Record>> iter) {
++ super(iter, 2) ;
++ }
++
++ @Override
++ protected final void endReachedInner() {
++ Pair<Integer, Record> pair1 = peek(0) ;
++ Pair<Integer, Record> pair2 = peek(1) ;
++ if ( pair1 == null || pair2 == null )
++ // Insufficient blocks to repack.
++ return ;
++
++ if ( debug )
++ System.out.printf("Rebalance: %s %s\n", pair1, pair2) ;
++ Record newSplitPoint = rebalance(pair1.car(), pair1.cdr(), pair2.car(), pair2.cdr()) ;
++ // Needed??
++ if ( newSplitPoint != null ) {
++ if ( debug )
++ System.out.println("Reset split point: " + pair1.cdr() + " => " + newSplitPoint) ;
++ pair1 = new Pair<>(pair1.car(), newSplitPoint) ;
++ if ( debug )
++ System.out.printf(" %s %s\n", pair1, pair2) ;
++ set(0, pair1) ;
++ }
++ }
++
++ protected abstract Record rebalance(int id1, Record r1, int id2, Record r2) ;
++ }
++
++ private static class RebalenceIndexEnd extends RebalenceBase {
++ private BPlusTree bpt ;
++
++ public RebalenceIndexEnd(Iterator<Pair<Integer, Record>> iter, BPlusTree bpt, boolean leafLayer) {
++ super(iter) ;
++ this.bpt = bpt ;
++ }
++
++ @Override
++ protected Record rebalance(int id1, Record r1, int id2, Record r2) {
++ BPTreeNodeMgr mgr = bpt.getNodeManager() ;
++ BPTreeNode node1 = mgr.getWrite(id1) ;
++ BPTreeNode node2 = mgr.getWrite(id2) ;
++
++ // rebalence
++ // ** Need rebalance of data leaf layer.
++ int count = node2.getCount() ;
++ if ( count >= bpt.getParams().getMinRec() )
++ return null ;
++
++ Record splitPoint = r1 ;
++
++ // Shift up all in one go and use .set.
++ // Convert to block move ; should be code in BPTreeNode to do this
++ // (insert).
++ for ( int i = count ; i < bpt.getParams().getMinRec() ; i++ ) {
++
++ Record r = splitPoint ;
++
++ // shiftOneup(node1, node2) ;
++ int ptr = node1.getPtrBuffer().getHigh() ;
++ splitPoint = node1.getRecordBuffer().getHigh() ;
++
++ node1.getPtrBuffer().removeTop() ;
++ node1.getRecordBuffer().removeTop() ;
++ node1.setCount(node1.getCount() - 1) ;
++
++ node2.getPtrBuffer().add(0, ptr) ;
++ node2.getRecordBuffer().add(0, r) ;
++ node2.setCount(node2.getCount() + 1) ;
++
++ // Need high of moved substree.
++
++ if ( debug )
++ System.out.printf("-- Shift up: %d %s\n", ptr, r) ;
++ }
++ mgr.put(node1) ;
++ mgr.put(node2) ;
++
++ return splitPoint ;
++ }
++ }
++
++ private static void fixupRoot(BPTreeNode root, Pair<Integer, Record> pair, BPlusTree bpt2) {
++ root.getPtrBuffer().clear() ;
++ root.getRecordBuffer().clear() ;
++
++ if ( BPlusTreeRewriter.debug ) {
++ divider() ;
++ System.out.printf("** Process root: %s\n", pair) ;
++ }
++
++ // Node or records?
++ // BPTreeNode => BPTree copy.
++ BPTreeNode node = bpt2.getNodeManager().getRead(pair.car(), BPlusTreeParams.RootParent) ;
++ copyBPTreeNode(node, root, bpt2) ;
++ bpt2.getNodeManager().release(node) ;
++ bpt2.getNodeManager().write(root);
++ }
++
++ private static void copyBPTreeNode(BPTreeNode nodeSrc, BPTreeNode nodeDst, BPlusTree bpt2) {
++ PtrBuffer pBuff = nodeSrc.getPtrBuffer() ;
++ pBuff.copy(0, nodeDst.getPtrBuffer(), 0, pBuff.getSize()) ;
++ RecordBuffer rBuff = nodeSrc.getRecordBuffer() ;
++ rBuff.copy(0, nodeDst.getRecordBuffer(), 0, rBuff.getSize()) ;
++ nodeDst.setCount(nodeSrc.getCount()) ;
++ nodeDst.setIsLeaf(nodeSrc.isLeaf()) ;
++ bpt2.getNodeManager().put(nodeDst) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/rewriter/BPlusTreeRewriterUtils.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/rewriter/BPlusTreeRewriterUtils.java
index 0000000,0000000..77cfdb2
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/rewriter/BPlusTreeRewriterUtils.java
@@@ -1,0 -1,0 +1,104 @@@
++/*
++ * 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.dboe.trans.bplustree.rewriter ;
++
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import org.apache.jena.atlas.lib.Pair ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPage ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPageMgr ;
++import org.seaborne.dboe.trans.bplustree.BPTreeNode ;
++import org.seaborne.dboe.trans.bplustree.BPTreeNodeMgr ;
++import org.seaborne.dboe.trans.bplustree.BPlusTreeParams ;
++
++class BPlusTreeRewriterUtils {
++ static String divider = "----------------------------------------" ;
++ static String nextDivider = null ;
++
++ static Iterator<Pair<Integer, Record>> summarizeDataBlocks(Iterator<Pair<Integer, Record>> iter, RecordBufferPageMgr recordPageMgr) {
++ divider() ;
++ List<Pair<Integer, Record>> pairs = Iter.toList(iter) ;
++ System.out.println("summarizeDataBlocks: " + pairs) ;
++ for ( Pair<Integer, Record> pair : pairs ) {
++ RecordBufferPage rbp = recordPageMgr.getRead(pair.car()) ;
++ System.out.printf("%s -- RecordBufferPage[id=%d,link=%d] (%d) -> [%s]\n", pair, rbp.getId(), rbp.getLink(), rbp.getCount(),
++ rbp.getRecordBuffer().getHigh()) ;
++ recordPageMgr.release(rbp) ;
++ }
++ return pairs.iterator() ;
++ }
++
++ static Iterator<Pair<Integer, Record>> summarizeIndexBlocks(Iterator<Pair<Integer, Record>> iter2, BPTreeNodeMgr bptNodeMgr) {
++ divider() ;
++ List<Pair<Integer, Record>> pairs = Iter.toList(iter2) ;
++ for ( Pair<Integer, Record> pair : pairs ) {
++ BPTreeNode bpNode = bptNodeMgr.getRead(pair.car(), BPlusTreeParams.RootParent) ;
++
++ String hr = "null" ;
++ if ( !bpNode.getRecordBuffer().isEmpty() )
++ hr = bpNode.getRecordBuffer().getHigh().toString() ;
++
++ System.out.printf("%s -- BPTreeNode: %d (%d) -> [%s]\n", pair, bpNode.getId(), bpNode.getCount(), hr) ;
++ bptNodeMgr.release(bpNode) ;
++ }
++ return pairs.iterator() ;
++ }
++
++ private static Iterator<Pair<Integer, Record>> printDataBlocks(Iterator<Pair<Integer, Record>> iter, RecordBufferPageMgr recordPageMgr) {
++ divider() ;
++ List<Pair<Integer, Record>> pairs = Iter.toList(iter) ;
++ System.out.printf(">>Packed data blocks\n") ;
++ for ( Pair<Integer, Record> pair : pairs ) {
++ System.out.printf(" %s\n", pair) ;
++ RecordBufferPage rbp = recordPageMgr.getRead(pair.car()) ;
++ // System.out.printf("RecordBufferPage[id=%d,link=%d] %d\n",
++ // rbp.getId(), rbp.getLink(), rbp.getCount() ) ;
++ System.out.println(rbp) ;
++ recordPageMgr.release(rbp) ;
++ }
++ System.out.printf("<<Packed data blocks\n") ;
++ System.out.printf("Blocks: %d\n", pairs.size()) ;
++ return pairs.iterator() ;
++ }
++
++ static Iterator<Pair<Integer, Record>> printIndexBlocks(Iterator<Pair<Integer, Record>> iter2, BPTreeNodeMgr bptNodeMgr) {
++ divider() ;
++ List<Pair<Integer, Record>> pairs = Iter.toList(iter2) ;
++ System.out.printf(">>Packed index blocks\n") ;
++ for ( Pair<Integer, Record> pair : pairs ) {
++ System.out.printf(" %s\n", pair) ;
++ BPTreeNode bpNode = bptNodeMgr.getRead(pair.car(), BPlusTreeParams.RootParent) ;
++ bpNode.setIsLeaf(true) ;
++ System.out.printf("BPTreeNode: %d\n", bpNode.getId()) ;
++ System.out.println(bpNode) ;
++ bptNodeMgr.release(bpNode) ;
++ }
++ System.out.printf("<<Packed index blocks\n") ;
++ return pairs.iterator() ;
++ }
++
++ static void divider() {
++ if ( nextDivider != null )
++ System.out.println(nextDivider) ;
++ nextDivider = divider ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/rewriter/RecordBufferPageLinker.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/rewriter/RecordBufferPageLinker.java
index 0000000,0000000..42c2b9c
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/rewriter/RecordBufferPageLinker.java
@@@ -1,0 -1,0 +1,81 @@@
++/*
++ * 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.dboe.trans.bplustree.rewriter ;
++
++import java.util.Iterator ;
++import java.util.NoSuchElementException ;
++
++import org.apache.jena.atlas.iterator.PeekIterator ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPage ;
++
++/**
++ * From a stream of RecordBufferPage, manage the link fields. That is, be a one
++ * slot delay so that the "link" field can point to the next page. Be careful
++ * about the last block.
++ *
++ */
++class RecordBufferPageLinker implements Iterator<RecordBufferPage> {
++ PeekIterator<RecordBufferPage> peekIter ;
++
++ RecordBufferPage slot = null ;
++
++ RecordBufferPageLinker(Iterator<RecordBufferPage> iter) {
++ if ( !iter.hasNext() ) {
++ peekIter = null ;
++ return ;
++ }
++
++ peekIter = new PeekIterator<>(iter) ;
++ }
++
++ @Override
++ public boolean hasNext() {
++ if ( slot != null )
++ return true ;
++
++ if ( peekIter == null )
++ return false ;
++
++ if ( !peekIter.hasNext() ) {
++ peekIter = null ;
++ return false ;
++ }
++
++ slot = peekIter.next() ;
++ RecordBufferPage nextSlot = peekIter.peek() ;
++ // If null, no slot ahead so no linkage field to set.
++ if ( nextSlot != null )
++ // Set the slot to the id of the next one
++ slot.setLink(nextSlot.getId()) ;
++ return true ;
++ }
++
++ @Override
++ public RecordBufferPage next() {
++ if ( !hasNext() )
++ throw new NoSuchElementException() ;
++ RecordBufferPage rbp = slot ;
++ slot = null ;
++ return rbp ;
++ }
++
++ @Override
++ public void remove() {
++ throw new UnsupportedOperationException() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/rewriter/RecordBufferPagePacker.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/rewriter/RecordBufferPagePacker.java
index 0000000,0000000..bb0485a
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/rewriter/RecordBufferPagePacker.java
@@@ -1,0 -1,0 +1,90 @@@
++/*
++ * 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.dboe.trans.bplustree.rewriter ;
++
++import java.util.Iterator ;
++import java.util.NoSuchElementException ;
++
++import org.seaborne.dboe.base.buffer.RecordBuffer ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPage ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPageMgr ;
++
++/**
++ * Iterate over a stream of records, packing them into RecordBufferPage -- the
++ * leaf of a B+Tree This class does not write the blocks back to the block
++ * manager. This class does allocate block ids and blocks.
++ *
++ * @see RecordBufferPageLinker
++ */
++
++class RecordBufferPagePacker implements Iterator<RecordBufferPage> {
++ Iterator<Record> records = null ;
++ RecordBufferPage recordBufferPage = null ;
++ RecordBufferPageMgr rbMgr = null ;
++
++ RecordBufferPagePacker(Iterator<Record> records, RecordBufferPageMgr rbMgr) {
++ this.records = records ;
++ this.rbMgr = rbMgr ;
++ }
++
++ @Override
++ public boolean hasNext() {
++ if ( recordBufferPage == null ) {
++ if ( records == null )
++ return false ;
++
++ if ( !records.hasNext() ) {
++ records = null ;
++ return false ;
++ }
++ // At least one record to be processed.
++ // No pending RecordBufferPage
++ // ==> There will be a RecordBufferPage to yield.
++
++ // int id = rbMgr.allocateId() ;
++ // //System.out.println("Allocate : "+id) ;
++ recordBufferPage = rbMgr.create() ;
++
++ RecordBuffer rb = recordBufferPage.getRecordBuffer() ;
++ while (!rb.isFull() && records.hasNext()) {
++ Record r = records.next() ;
++ rb.add(r) ;
++ }
++ if ( !records.hasNext() )
++ records = null ;
++ return true ;
++ }
++ return true ;
++
++ }
++
++ @Override
++ public RecordBufferPage next() {
++ if ( !hasNext() )
++ throw new NoSuchElementException() ;
++ RecordBufferPage rbp = recordBufferPage ;
++ recordBufferPage = null ;
++ return rbp ;
++ }
++
++ @Override
++ public void remove() {
++ throw new UnsupportedOperationException() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransBinaryDataFile.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransBinaryDataFile.java
index 0000000,0000000..569db33
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransBinaryDataFile.java
@@@ -1,0 -1,0 +1,237 @@@
++/*
++ * 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.dboe.trans.data;
++
++import java.nio.ByteBuffer ;
++import java.util.concurrent.atomic.AtomicLong ;
++
++import org.apache.jena.atlas.RuntimeIOException ;
++import org.apache.jena.atlas.io.IO ;
++import org.apache.jena.query.ReadWrite ;
++import org.seaborne.dboe.base.file.BinaryDataFile ;
++import org.seaborne.dboe.base.file.BufferChannel ;
++import org.seaborne.dboe.transaction.txn.* ;
++
++/** Transactional {@link BinaryDataFile}.
++ * An binary file that is append-only and allows only one writer at a time.
++ * All readers see the file up to the last commit point at the time
++ * they started. The sole writer sees more of the file.
++ */
++
++public class TransBinaryDataFile extends TransactionalComponentLifecycle<TransBinaryDataFile.TxnBinFile>
++ implements BinaryDataFile {
++
++ /*
++ * The file is written to as we go along so abort requires some action. We
++ * can't recover from just the file, without any redo or undo recovery
++ * action.
++ */
++
++ private final FileState stateMgr ;
++
++ // The current committed position and the limit as seen by readers.
++ // This is also the abort point.
++ private final AtomicLong committedLength ;
++
++ // The per thread runtime state
++ static class TxnBinFile {
++ final long length ;
++
++ TxnBinFile(long length) {
++ this.length = length ;
++ }
++ }
++
++ // Prepare record
++ static class FileState extends StateMgrData {
++ FileState(BufferChannel bufferChannel, long length, long position) {
++ super(bufferChannel, length, position) ;
++ }
++ private static int idxLength = 0 ;
++ long length() { return get(idxLength) ; }
++ void length(long len) { set(idxLength, len) ; }
++ }
++
++ private final BinaryDataFile binFile ;
++
++ /** Create a transactional BinaryDataFile over a base implementation.
++ * The base file must provide thread-safe operation.
++ */
++ public TransBinaryDataFile(BinaryDataFile binFile, ComponentId cid, BufferChannel bufferChannel) {
++ super(cid) ;
++ stateMgr = new FileState(bufferChannel, 0L, 0L) ;
++ this.binFile = binFile ;
++ if ( ! binFile.isOpen() )
++ binFile.open();
++ // Internal state may be updated by recovery. Start by
++ // setting to the "clean start" settings.
++ committedLength = new AtomicLong(binFile.length()) ;
++ }
++
++ private boolean recoveryAction = false ;
++
++ @Override
++ public void startRecovery() {
++ recoveryAction = false ;
++ }
++
++ @Override
++ public void recover(ByteBuffer ref) {
++ stateMgr.setState(ref);
++ committedLength.set(stateMgr.length()) ;
++ recoveryAction = true ;
++ }
++
++ @Override
++ public void finishRecovery() {
++ if ( recoveryAction ) {
++ long length = committedLength.get() ;
++ binFile.truncate(length) ;
++ binFile.sync();
++ committedLength.set(length) ;
++ }
++ }
++
++ @Override
++ public void cleanStart() { }
++
++ @Override
++ protected TxnBinFile _begin(ReadWrite readWrite, TxnId txnId) {
++ // Atomic read across the two because it's called from within
++ // TransactionCoordinator.begin$ where there is a lock.
++ return createState() ;
++ }
++
++ private TxnBinFile createState() {
++ long xLength = committedLength.get() ;
++ return new TxnBinFile(xLength) ;
++ }
++
++ @Override
++ protected TxnBinFile _promote(TxnId txnId, TxnBinFile state) {
++ return createState() ;
++ }
++
++ @Override
++ protected ByteBuffer _commitPrepare(TxnId txnId, TxnBinFile state) {
++ // Force to disk but do not set the on disk state to record that.
++ binFile.sync();
++ stateMgr.length(binFile.length()) ;
++ return stateMgr.getState() ;
++ }
++
++ @Override
++ protected void _commit(TxnId txnId, TxnBinFile state) {
++ if ( isWriteTxn() ) {
++ // Force to disk happens in _commitPrepare
++ stateMgr.writeState();
++ // Move visible commit point forward (not strictly necessary - transaction is ending.
++ committedLength.set(binFile.length()) ;
++ }
++ }
++
++ @Override
++ protected void _commitEnd(TxnId txnId, TxnBinFile state) {
++ }
++
++ @Override
++ protected void _abort(TxnId txnId, TxnBinFile state) {
++ if ( isWriteTxn() ) {
++ binFile.truncate(committedLength.get()) ;
++ binFile.sync() ;
++ }
++ }
++
++ @Override
++ protected void _complete(TxnId txnId, TxnBinFile state) {}
++
++ @Override
++ protected void _shutdown() {}
++
++ private void checkBoundsReader(long requestedPoint, TxnBinFile state) { }
++
++ @Override
++ public void open() {
++ if ( ! binFile.isOpen() )
++ binFile.open();
++ }
++
++ @Override
++ public boolean isOpen() {
++ return binFile.isOpen() ;
++ }
++
++ @Override
++ public int read(long posn, byte[] b, int start, int length) {
++ checkTxn();
++ if ( isReadTxn() )
++ checkRead(posn) ;
++ return binFile.read(posn, b, start, length) ;
++ }
++
++ private void checkRead(long posn) {
++ if ( posn > getDataState().length )
++ IO.exception("Out of bounds: (limit "+getDataState().length+")"+posn) ;
++ }
++
++ @Override
++ public long write(byte[] b, int start, int length) {
++ checkWriteTxn() ;
++ return binFile.write(b, start, length);
++ }
++
++ /**
++ * Truncate only supported for an abort - this transactional version of
++ * BinaryDataFile will not truncate to earlier than the commited length.
++ */
++ @Override
++ public void truncate(long size) {
++ checkWriteTxn();
++ TxnBinFile state = getDataState() ;
++ if ( size < state.length )
++ throw new RuntimeIOException("truncate("+size+") to smaller than commited length "+state.length) ;
++ binFile.truncate(size) ;
++ }
++
++ @Override
++ public void sync() {
++ // No-op in transactional mode.
++ checkWriteTxn();
++ }
++
++ @Override
++ public void close() {
++ binFile.close() ;
++ }
++
++ @Override
++ public long length() {
++ super.checkTxn();
++ if ( isReadTxn() )
++ // Reader view.
++ return getDataState().length ;
++ return binFile.length() ;
++ }
++
++ @Override
++ public boolean isEmpty() {
++ super.checkTxn();
++ return binFile.isEmpty() ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransBlob.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransBlob.java
index 0000000,0000000..a2dfbf3
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransBlob.java
@@@ -1,0 -1,0 +1,209 @@@
++/*
++ * 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.dboe.trans.data;
++
++import java.nio.ByteBuffer ;
++import java.util.concurrent.atomic.AtomicReference ;
++
++import org.apache.jena.atlas.RuntimeIOException ;
++import org.apache.jena.atlas.lib.Bytes ;
++import org.apache.jena.query.ReadWrite ;
++import org.seaborne.dboe.base.file.BufferChannel ;
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++import org.seaborne.dboe.transaction.txn.TransactionalComponentLifecycle ;
++import org.seaborne.dboe.transaction.txn.TxnId ;
++
++/** Manage a single binary (not too large) object.
++ * It is written and read from a file in one action,
++ * so changes completely replace the original contents.
++ * The whole object is written to the journal during prepare.
++ */
++public class TransBlob extends TransactionalComponentLifecycle<TransBlob.BlobState> {
++
++ // The last commited state.
++ // Immutable ByteBuffer.
++ private final AtomicReference<ByteBuffer> blobRef = new AtomicReference<>() ;
++ private final BufferChannel file ;
++
++ static class BlobState {
++ boolean hasChanged = false;
++ ByteBuffer $txnBlob ;
++
++ BlobState(ByteBuffer bb) {
++ setByteBuffer(bb) ;
++ }
++ void setByteBuffer(ByteBuffer bb) {
++ $txnBlob = bb ;
++ // Could compare - seems like added complexity.
++ hasChanged = true;
++ }
++
++ ByteBuffer getByteBuffer() { return $txnBlob ; }
++ }
++
++ public TransBlob(ComponentId cid, BufferChannel file) {
++ super(cid) ;
++ this.file = file ;
++ read() ;
++ }
++
++ private void read() {
++ long x = file.size() ;
++ ByteBuffer blob = ByteBuffer.allocate((int)x) ;
++ int len = file.read(blob) ;
++ if ( len != x )
++ throw new RuntimeIOException("Short read: "+len+" of "+x) ;
++ blob.rewind() ;
++ blobRef.set(blob) ;
++ }
++
++ private void write() {
++ ByteBuffer blob = blobRef.get();
++ blob.rewind() ;
++ int x = blob.remaining() ;
++ file.truncate(0);
++ int len = file.write(blob) ;
++ if ( len != x )
++ throw new RuntimeIOException("Short write: "+len+" of "+x) ;
++ file.sync();
++ blob.rewind() ;
++ }
++
++ /** Set the byte buffer.
++ * The byte buffer should not be accessed except by {@link #getBlob}.
++ * We avoid a copy in and copy out - we trust the caller.
++ * The byte buffer should be configured for read if used with {@link #getString}.
++ */
++ public void setBlob(ByteBuffer bb) {
++ checkWriteTxn();
++ getDataState().setByteBuffer(bb);
++ }
++
++ public ByteBuffer getBlob() {
++ if ( isActiveTxn() )
++ return getDataState().getByteBuffer() ;
++ return blobRef.get() ;
++ }
++
++ /** Set data from string - convenience operation */
++ public void setString(String dataStr) {
++ checkWriteTxn();
++ if ( dataStr == null ) {
++ setBlob(null);
++ return ;
++ }
++
++ // Attempt to reuse the write-transaction byte buffer
++ // We can't reuse if it's the blobRef (shared by other transactions)
++ // but if it's a new to this write transaction buffer we can reuse.
++
++ int maxNeeded = dataStr.length()*4 ;
++ ByteBuffer bb = getDataState().getByteBuffer() ;
++ if ( bb == blobRef.get() )
++ bb = ByteBuffer.allocate(maxNeeded) ;
++ else if ( bb.capacity() >= maxNeeded )
++ bb.clear() ;
++ else
++ bb = ByteBuffer.allocate(maxNeeded) ;
++ Bytes.toByteBuffer(dataStr, bb) ;
++ bb.flip() ;
++ setBlob(bb);
++ }
++
++ /** Get data as string - convenience operation */
++ public String getString() {
++ ByteBuffer bb = getBlob() ;
++ if (bb == null )
++ return null ;
++ int x = bb.position() ;
++ String s = Bytes.fromByteBuffer(bb) ;
++ bb.position(x) ;
++ return s ;
++ }
++
++ private boolean recoveryChange = false ;
++ @Override
++ public void startRecovery() {
++ recoveryChange = false ;
++ }
++
++ @Override
++ public void recover(ByteBuffer ref) {
++ blobRef.set(ref) ;
++ recoveryChange = true ;
++ }
++
++ @Override
++ public void finishRecovery() {
++ if ( recoveryChange )
++ write() ;
++ }
++
++ @Override
++ public void cleanStart() { }
++
++ @Override
++ protected BlobState _begin(ReadWrite readWrite, TxnId txnId) {
++ return createState();
++ }
++
++ private BlobState createState() {
++ ByteBuffer blob = blobRef.get() ;
++ // Save reference to ByteBuffer into the transaction state.
++ return new BlobState(blob) ;
++ }
++
++ @Override
++ protected BlobState _promote(TxnId txnId, BlobState state) {
++ // Our write state is the read state.
++ return createState();
++ }
++
++ @Override
++ protected ByteBuffer _commitPrepare(TxnId txnId, BlobState state) {
++ if ( ! state.hasChanged )
++ return null;
++ return state.getByteBuffer() ;
++ }
++
++ @Override
++ protected void _commit(TxnId txnId, BlobState state) {
++ if ( ! state.hasChanged )
++ return;
++ // NB Change reference.
++ blobRef.set(state.getByteBuffer()) ;
++ write() ;
++ }
++
++ @Override
++ protected void _commitEnd(TxnId txnId, BlobState state) {}
++
++ @Override
++ protected void _abort(TxnId txnId, BlobState state) {}
++
++ @Override
++ protected void _complete(TxnId txnId, BlobState state) {}
++
++ @Override
++ protected void _shutdown() {}
++
++ @Override
++ public String toString() { return getComponentId().label() ; }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/TC_TransData.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/TC_TransData.java
index 0000000,0000000..9681f2c
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/TC_TransData.java
@@@ -1,0 -1,0 +1,33 @@@
++/*
++ * 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.dboe.trans;
++
++import org.junit.runner.RunWith ;
++import org.junit.runners.Suite ;
++import org.seaborne.dboe.trans.bplustree.TS_TxnBPTree ;
++import org.seaborne.dboe.trans.data.TS_TransData ;
++import org.seaborne.dboe.trans.recovery.TestRecovery ;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TS_TransData.class
++ , TS_TxnBPTree.class
++ , TestRecovery.class
++})
++public class TC_TransData {}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/BPlusTreeMaker.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/BPlusTreeMaker.java
index 0000000,0000000..5487178
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/BPlusTreeMaker.java
@@@ -1,0 -1,0 +1,55 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import org.seaborne.dboe.index.Index ;
++import org.seaborne.dboe.index.RangeIndex ;
++import org.seaborne.dboe.trans.bplustree.BPlusTree ;
++import org.seaborne.dboe.index.test.RangeIndexMaker ;
++import org.seaborne.dboe.test.RecordLib ;
++
++public class BPlusTreeMaker implements RangeIndexMaker
++{
++ private int order ;
++ private int recordOrder ;
++ private boolean trackers ;
++
++
++ public BPlusTreeMaker(int order, int recordOrder, boolean trackers)
++ {
++ this.order = order ;
++ this.recordOrder = recordOrder ;
++ this.trackers = trackers ;
++ }
++
++ @Override
++ public Index makeIndex() { return makeRangeIndex() ; }
++
++ @Override
++ public RangeIndex makeRangeIndex()
++ {
++ BPlusTree bpTree = BPlusTreeFactory.makeMem(order, recordOrder, RecordLib.TestRecordLength, 0) ;
++ if ( trackers )
++ bpTree = BPlusTreeFactory.addTracking(bpTree) ;
++ return bpTree ;
++ }
++
++ @Override
++ public String getLabel() { return "B+Tree order = "+order ; }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TS_TxnBPTree.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TS_TxnBPTree.java
index 0000000,0000000..e8016c8
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TS_TxnBPTree.java
@@@ -1,0 -1,0 +1,41 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import org.junit.runner.RunWith ;
++import org.junit.runners.Suite ;
++import org.seaborne.dboe.trans.bplustree.rewriter.TestBPlusTreeRewriterNonTxn ;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++
++ // Non-transactional tests -- that is, algorithms and machinary.
++ TestBPTreeRecordsNonTxn.class,
++ TestBPlusTreeIndexNonTxn.class,
++ TestBPlusTreeNonTxn.class,
++ TestBPTreeModes.class,
++
++ // Transactional tests
++ TestBPlusTreeTxn.class,
++
++ // Rewriter
++ TestBPlusTreeRewriterNonTxn.class
++} )
++
++public class TS_TxnBPTree
++{ }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TestBPTreeModes.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TestBPTreeModes.java
index 0000000,0000000..71168cb
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TestBPTreeModes.java
@@@ -1,0 -1,0 +1,77 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import java.util.Arrays ;
++import java.util.Collection ;
++
++import org.junit.After ;
++import org.junit.AfterClass ;
++import org.junit.Before ;
++import org.junit.BeforeClass ;
++import org.junit.runner.RunWith ;
++import org.junit.runners.Parameterized ;
++import org.junit.runners.Parameterized.Parameters ;
++
++/** Run the B+Tree algorithm tests but for each combination of explicit
++ * write-in-place / always copy modes.
++ */
++@RunWith(Parameterized.class)
++public class TestBPTreeModes extends TestBPlusTreeNonTxn
++{
++ @Parameters(name="Node dup={0}, Record dup={1}")
++ public static Collection<Object[]> data()
++ {
++ return Arrays.asList(new Object[][]{
++ {true, true},
++ {true, false},
++ {false, true},
++ {false, false}
++ }) ;
++ }
++
++ public TestBPTreeModes(boolean nodeMode, boolean recordsMode) {
++
++ BPT.promoteDuplicateNodes = nodeMode ;
++ BPT.promoteDuplicateRecords = recordsMode ;
++ }
++
++ boolean modeAtStartNodes ;
++ boolean modeAtStartRecords ;
++
++ @BeforeClass public static void setupSuite() {
++ BPT.forcePromoteModes = true ;
++ }
++
++ @AfterClass public static void resetSuite() {
++ BPT.forcePromoteModes = false ;
++ }
++
++ @Before public void setModes() {
++ BPT.forcePromoteModes = true ;
++ modeAtStartNodes = BPT.promoteDuplicateNodes ;
++ modeAtStartRecords = BPT.promoteDuplicateRecords ;
++ }
++
++
++ @After public void resetModes() {
++ BPT.promoteDuplicateNodes = modeAtStartNodes ;
++ BPT.promoteDuplicateRecords = modeAtStartRecords ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TestBPTreeRecordsNonTxn.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TestBPTreeRecordsNonTxn.java
index 0000000,0000000..fad84f4
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TestBPTreeRecordsNonTxn.java
@@@ -1,0 -1,0 +1,326 @@@
++/*
++ * 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.dboe.trans.bplustree ;
++
++import org.junit.* ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.block.BlockMgrFactory ;
++import org.seaborne.dboe.base.buffer.RecordBuffer ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPage ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPageMgr ;
++import org.seaborne.dboe.sys.SystemIndex ;
++import org.seaborne.dboe.test.RecordLib ;
++
++public class TestBPTreeRecordsNonTxn extends Assert {
++ static private boolean oldNullOut ;
++
++ static private int blockSize ;
++ static private RecordFactory recordFactory ;
++
++ static private int bufSizeRecord ;
++ static private BlockMgr blkMgrRecords ;
++ static private RecordBufferPageMgr recordBufferPageMgr ;
++
++ @BeforeClass
++ public static void beforeClass() {
++ oldNullOut = SystemIndex.getNullOut() ;
++ SystemIndex.setNullOut(true) ;
++
++ blockSize = 4 * 8 ; // Which is 6 int records
++ recordFactory = new RecordFactory(4, 0) ;
++
++ bufSizeRecord = RecordBufferPage.calcRecordSize(recordFactory, blockSize) ;
++ blkMgrRecords = BlockMgrFactory.createMem("BPTreeRecords", blockSize) ;
++ recordBufferPageMgr = new RecordBufferPageMgr(recordFactory, blkMgrRecords) ;
++
++ BlockMgr blkMgrNodes = BlockMgrFactory.createMem("BPTreeNs", blockSize) ;
++
++ // Copy on write.
++ BPT.forcePromoteModes = true ;
++ BPT.promoteDuplicateRecords = true ;
++ }
++
++ @AfterClass
++ public static void afterClass() {
++ SystemIndex.setNullOut(oldNullOut) ;
++ BPT.forcePromoteModes = false ;
++ }
++
++ @Before
++ public void before() {
++ blkMgrRecords.beginUpdate() ;
++ }
++
++ @After
++ public void after() {
++ blkMgrRecords.endUpdate() ;
++ }
++
++ @Test
++ public void bpt_records_1() {
++ BPTreeRecords bpr = make() ;
++ fill(bpr) ;
++ check(bpr) ;
++ bpr.release() ;
++ }
++
++ @Test
++ public void bpt_records_2() {
++ BPTreeRecords bpr = make() ;
++ fill(bpr) ;
++ int s = bpr.getCount() ;
++ assertTrue(bpr.isFull()) ;
++ BPTreePage z = bpr.split() ;
++ assertTrue(z instanceof BPTreeRecords) ;
++ assertEquals(s, z.getCount() + bpr.getCount()) ;
++ check(bpr) ;
++ check((BPTreeRecords)z) ;
++ bpr.release() ;
++ z.release() ;
++ }
++
++ @Test
++ public void bpt_records_3() {
++ BPTreeRecords bpr = make() ;
++ for ( int i = 0 ; bpr.getCount() < bpr.getMaxSize() ; i++ )
++ insert(bpr, (i + 0x20)) ;
++ check(bpr) ;
++ bpr.release() ;
++ }
++
++ @Test
++ public void bpt_records_4() {
++ BPTreeRecords bpr = make() ;
++ for ( int i = bpr.getMaxSize() - 1 ; i >= 0 ; i-- )
++ insert(bpr, i + 0x20) ;
++ check(bpr) ;
++ bpr.release() ;
++ }
++
++ @Test
++ public void bpt_records_5() {
++ BPTreeRecords bpr = make() ;
++ int N = bpr.getMaxSize() ;
++
++ for ( int i = bpr.getMaxSize() - 1 ; i >= 0 ; i-- )
++ insert(bpr, (i + 0x20)) ;
++
++ delete(bpr, (1 + 0x20)) ;
++ assertEquals(N - 1, bpr.getCount()) ;
++ check(bpr) ;
++
++ delete(bpr, (2 + 0x20)) ;
++ assertEquals(N - 2, bpr.getCount()) ;
++ check(bpr) ;
++
++ delete(bpr, bpr.getLowRecord()) ;
++ assertEquals(N - 3, bpr.getCount()) ;
++ check(bpr) ;
++
++ delete(bpr, bpr.getHighRecord()) ;
++ assertEquals(N - 4, bpr.getCount()) ;
++ check(bpr) ;
++
++ bpr.release() ;
++ }
++
++ @Test
++ public void bpt_records_6() {
++ BPTreeRecords bpr = make() ;
++ fill(bpr) ;
++
++ // No match.
++ assertNull(search(bpr, RecordLib.intToRecord(0x20))) ;
++
++ Record r = RecordLib.intToRecord(0x32) ;
++ Record r2 = search(bpr, r) ;
++ assertTrue(Record.keyEQ(r, r2)) ;
++
++ r = bpr.getLowRecord() ;
++ r2 = search(bpr, r) ;
++ assertTrue(Record.keyEQ(r, r2)) ;
++
++ r = bpr.getHighRecord() ;
++ r2 = search(bpr, r) ;
++ assertTrue(Record.keyEQ(r, r2)) ;
++
++ bpr.release() ;
++ }
++
++ @Test
++ public void bpt_shift_1() {
++ BPTreeRecords bpr1 = make() ;
++ BPTreeRecords bpr2 = make() ;
++
++ insert(bpr1, 10) ;
++ Record r = bpr1.shiftRight(bpr2, null) ;
++ assertNull(r) ;
++ // assertTrue(Record.keyEQ(r, RecordTestLib.intToRecord(10))) ;
++ contains(bpr1) ;
++ contains(bpr2, 10) ;
++
++ bpr1.release() ;
++ bpr2.release() ;
++
++ }
++
++ @Test
++ public void bpt_shift_2() {
++ BPTreeRecords bpr1 = make() ;
++ BPTreeRecords bpr2 = make() ;
++
++ insert(bpr1, 10) ;
++ Record r = bpr2.shiftLeft(bpr1, null) ;
++
++ assertTrue(Record.keyEQ(r, RecordLib.intToRecord(10))) ;
++ contains(bpr1) ;
++ contains(bpr2, 10) ;
++ bpr1.release() ;
++ bpr2.release() ;
++ }
++
++ @Test
++ public void bpt_shift_3() {
++ BPTreeRecords bpr1 = make() ;
++ BPTreeRecords bpr2 = make() ;
++
++ insert(bpr1, 10, 20) ;
++ insert(bpr2, 99) ;
++
++ Record r = bpr1.shiftRight(bpr2, null) ;
++
++ assertTrue(r + " != " + RecordLib.intToRecord(10), Record.keyEQ(r, RecordLib.intToRecord(10))) ;
++ contains(bpr1, 10) ;
++ contains(bpr2, 20, 99) ;
++ bpr1.release() ;
++ bpr2.release() ;
++ }
++
++ @Test
++ public void bpt_shift_4() {
++ BPTreeRecords bpr1 = make() ;
++ BPTreeRecords bpr2 = make() ;
++
++ insert(bpr1, 10, 20) ;
++ insert(bpr2, 5) ;
++
++ Record r = bpr2.shiftLeft(bpr1, null) ;
++ assertTrue(Record.keyEQ(r, RecordLib.intToRecord(10))) ;
++
++ contains(bpr1, 20) ;
++ contains(bpr2, 5, 10) ;
++ bpr1.release() ;
++ bpr2.release() ;
++ }
++
++ @Test
++ public void bpt_merge_1() {
++ BPTreeRecords bpr1 = make() ;
++ BPTreeRecords bpr2 = make() ;
++
++ insert(bpr1, 10, 20) ;
++ insert(bpr2, 99) ;
++
++ BPTreeRecords bpr3 = (BPTreeRecords)bpr1.merge(bpr2, null) ;
++ contains(bpr1, 10, 20, 99) ;
++ contains(bpr2) ;
++ assertSame(bpr1, bpr3) ;
++ bpr1.release() ;
++ bpr2.release() ;
++ }
++
++ @Test
++ public void bpt_merge_2() {
++ BPTreeRecords bpr1 = make() ;
++ BPTreeRecords bpr2 = make() ;
++
++ insert(bpr1, 10, 20) ;
++ insert(bpr2, 5) ;
++
++ BPTreeRecords bpr3 = (BPTreeRecords)bpr2.merge(bpr1, null) ;
++ contains(bpr1) ;
++ contains(bpr2, 5, 10, 20) ;
++ assertSame(bpr2, bpr3) ;
++ bpr1.release() ;
++ bpr2.release() ;
++ }
++
++ protected static void check(BPTreeRecords bpr) {
++ assertTrue(bpr.getCount() >= 0) ;
++ assertTrue(bpr.getCount() <= bpr.getMaxSize()) ;
++
++ assertEquals(bpr.getRecordBuffer().getLow(), bpr.getLowRecord()) ;
++ assertEquals(bpr.getRecordBuffer().getHigh(), bpr.getHighRecord()) ;
++
++ for ( int i = 1 ; i < bpr.getCount() ; i++ ) {
++ Record r1 = bpr.getRecordBuffer().get(i - 1) ;
++ Record r2 = bpr.getRecordBuffer().get(i) ;
++ assertTrue(Record.keyLE(r1, r2)) ;
++ }
++ }
++
++ private static Record search(BPTreeRecords bpr, int x) {
++ return search(bpr, RecordLib.intToRecord(x)) ;
++ }
++
++ private static Record search(BPTreeRecords bpr, Record r) {
++ return bpr.internalSearch(null, r) ;
++ }
++
++ private static void insert(BPTreeRecords bpr, int... values) {
++ for ( int value : values ) {
++ bpr.internalInsert(null, RecordLib.intToRecord(value)) ;
++ }
++ }
++
++ private static void insert(BPTreeRecords bpr, Record r) {
++ bpr.internalInsert(null, r) ;
++ }
++
++ private static void delete(BPTreeRecords bpr, int... values) {
++ for ( int value : values ) {
++ delete(bpr, RecordLib.intToRecord(value)) ;
++ }
++ }
++
++ private static void delete(BPTreeRecords bpr, Record r) {
++ bpr.internalDelete(null, r) ;
++ }
++
++ private static void contains(BPTreeRecords bpr, int... values) {
++ assertEquals(values.length, bpr.getCount()) ;
++ for ( int i = 1 ; i < values.length ; i++ )
++ assertTrue(Record.compareByKeyValue(RecordLib.intToRecord(values[i]), bpr.getRecordBuffer().get(i)) == 0) ;
++ }
++
++ protected static BPTreeRecords make() {
++ RecordBufferPage page = recordBufferPageMgr.create() ;
++ BPTreeRecordsMgr mgr = new BPTreeRecordsMgr(null, recordFactory, recordBufferPageMgr) ;
++ return new BPTreeRecords(mgr, page) ;
++ }
++
++ protected static void fill(BPTreeRecords bpr) {
++ int N = bpr.getRecordBuffer().maxSize() ;
++ for ( int i = 0 ; i < N ; i++ ) {
++ RecordBuffer rb = bpr.getRecordBuffer() ;
++ insert(bpr, (i + 0x30)) ;
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TestBPlusTreeIndexNonTxn.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TestBPlusTreeIndexNonTxn.java
index 0000000,0000000..1834f77
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TestBPlusTreeIndexNonTxn.java
@@@ -1,0 -1,0 +1,60 @@@
++/*
++ * 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.dboe.trans.bplustree ;
++
++import org.apache.jena.atlas.logging.LogCtl ;
++import org.junit.AfterClass ;
++import org.junit.BeforeClass ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.index.test.AbstractTestIndex ;
++import org.seaborne.dboe.sys.SystemIndex ;
++import org.seaborne.dboe.test.RecordLib ;
++
++/** Run the tests in default settings for a tree in "non-transactional" mode */
++public class TestBPlusTreeIndexNonTxn extends AbstractTestIndex {
++ static boolean addTracker = true ;
++ // Panic.
++ static boolean addLogger = false ;
++
++ static boolean originalNullOut ;
++ @BeforeClass
++ static public void beforeClass() {
++ BPT.CheckingNode = true ;
++ originalNullOut = SystemIndex.getNullOut() ;
++ SystemIndex.setNullOut(true) ;
++ }
++
++ @AfterClass
++ static public void afterClass() {
++ SystemIndex.setNullOut(originalNullOut) ;
++ }
++ @Override
++ protected BPlusTree makeIndex(int order, int minRecords) {
++ BPlusTree bpt = BPlusTreeFactory.makeMem(order, minRecords, RecordLib.TestRecordLength, 0) ;
++ if ( addLogger ) {
++ // Put it in but disable it so that it can be enabled
++ // in the middle of a complex operation.
++ LogCtl.disable(BlockMgr.class) ;
++ bpt = BPlusTreeFactory.addLogging(bpt) ;
++ }
++ if ( addTracker )
++ bpt = BPlusTreeFactory.addTracking(bpt) ;
++ bpt.nonTransactional() ;
++ return bpt ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TestBPlusTreeNonTxn.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TestBPlusTreeNonTxn.java
index 0000000,0000000..266326a
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TestBPlusTreeNonTxn.java
@@@ -1,0 -1,0 +1,90 @@@
++/*
++ * 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.dboe.trans.bplustree ;
++
++import static org.seaborne.dboe.index.test.IndexTestLib.add ;
++import static org.seaborne.dboe.test.RecordLib.intToRecord ;
++
++import java.util.List ;
++
++import org.apache.jena.atlas.logging.LogCtl ;
++import org.junit.AfterClass ;
++import org.junit.BeforeClass ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.index.test.AbstractTestRangeIndex ;
++import org.seaborne.dboe.sys.SystemIndex ;
++import org.seaborne.dboe.test.RecordLib ;
++
++/** Run the tests in default settings for a tree in "non-transactional" mode */
++public class TestBPlusTreeNonTxn extends AbstractTestRangeIndex {
++ // See TestBPTreeModes for parameterised tests for the duplication modes.
++
++ // Add tracker or not (usually not)
++ // The tracker checking can impose more constraints than are needed
++ // giving false negatives. Iterator aren't tracked (they may not
++ // be consumed; don't release pages properly)
++ static boolean addTracker = false ;
++ // Panic.
++ static boolean addLogger = false ;
++
++ static boolean originalNullOut ;
++ @BeforeClass
++ static public void beforeClass() {
++ BPT.CheckingNode = true ;
++ originalNullOut = SystemIndex.getNullOut() ;
++ SystemIndex.setNullOut(true) ;
++ }
++
++ @AfterClass
++ static public void afterClass() {
++ SystemIndex.setNullOut(originalNullOut) ;
++ }
++
++ protected void testClearX(int N) {
++ int[] keys = new int[N] ; // Slice is 1000.
++ for ( int i = 0 ; i < keys.length ; i++ )
++ keys[i] = i ;
++ BPlusTree rIndex = makeRangeIndex(2, 2) ;
++ add(rIndex, keys) ;
++ rIndex.dump() ;
++ if ( N > 0 )
++ assertFalse(rIndex.isEmpty()) ;
++ List<Record> x = intToRecord(keys, RecordLib.TestRecordLength) ;
++ for ( int i = 0 ; i < keys.length ; i++ ) {
++ System.out.println(i+": "+x.get(i)) ;
++ rIndex.delete(x.get(i)) ;
++ }
++ assertTrue(rIndex.isEmpty()) ;
++ }
++
++ @Override
++ protected BPlusTree makeRangeIndex(int order, int minRecords) {
++ BPlusTree bpt = BPlusTreeFactory.makeMem(order, minRecords, RecordLib.TestRecordLength, 0) ;
++ if ( addLogger ) {
++ // Put it in but disable it so that it can be enabled
++ // in the middle of a complex operation.
++ LogCtl.disable(BlockMgr.class) ;
++ bpt = BPlusTreeFactory.addLogging(bpt) ;
++ }
++ if ( addTracker )
++ bpt = BPlusTreeFactory.addTracking(bpt) ;
++ bpt.nonTransactional() ;
++ return bpt ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TestBPlusTreeTxn.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TestBPlusTreeTxn.java
index 0000000,0000000..70000f6
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/TestBPlusTreeTxn.java
@@@ -1,0 -1,0 +1,205 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import org.apache.jena.query.ReadWrite ;
++import org.junit.Assert ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.index.test.IndexTestLib ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.dboe.test.RecordLib ;
++import org.seaborne.dboe.transaction.Transactional ;
++import org.seaborne.dboe.transaction.TransactionalFactory ;
++import org.seaborne.dboe.transaction.txn.TransactionalComponent ;
++
++/** Tests of B+Tree and transactions */
++public class TestBPlusTreeTxn extends Assert {
++
++ static BPlusTree createBPTree() {
++ return BPlusTreeFactory.makeMem(2, 2, RecordLib.TestRecordLength, 0) ;
++ }
++
++ static Transactional transactional(TransactionalComponent ... components) {
++ return transactional(Location.mem(), components) ;
++ }
++
++ static Transactional transactional(Location location, TransactionalComponent ... components) {
++ return TransactionalFactory.createTransactional(location, components) ;
++ }
++
++ // Commit
++ @Test public void bptree_txn_01() {
++ BPlusTree bpt = createBPTree() ;
++ assertNotNull(bpt.getComponentId()) ;
++ int outerRootIdx1 = bpt.getRootId() ;
++ Transactional thing = transactional(bpt) ;
++ Txn.executeWrite(thing, () -> {
++ IndexTestLib.add(bpt, 1, 2, 3, 4) ;
++ } );
++ int outerRootIdx2 = bpt.getRootId() ;
++ assertNotEquals("After txn", outerRootIdx1, outerRootIdx2);
++ }
++
++ // Commit - only the first changes the root.
++ @Test public void bptree_txn_02() {
++ BPlusTree bpt = createBPTree() ;
++ int outerRootIdx1 = bpt.getRootId() ;
++ Transactional thing = transactional(bpt) ;
++ Txn.executeWrite(thing, () -> {
++ int rootIdx1 = bpt.getRootId() ;
++ assertEquals("Inside txn (1)", outerRootIdx1, rootIdx1);
++ IndexTestLib.add(bpt, 1) ;
++ int rootIdx2 = bpt.getRootId() ;
++ assertNotEquals("Inside txn (2)", rootIdx1, rootIdx2);
++ IndexTestLib.add(bpt, 2, 3, 4) ;
++ int rootIdx3 = bpt.getRootId() ;
++ assertEquals("Inside txn (3)", rootIdx2, rootIdx3);
++ } ) ;
++ int outerRootIdx2 = bpt.getRootId() ;
++ assertNotEquals("After txn", outerRootIdx1, outerRootIdx2);
++ }
++
++ // Abort
++ @Test public void bptree_txn_03() {
++ BPlusTree bpt = createBPTree() ;
++ int outerRootIdx1 = bpt.getRootId() ;
++ Transactional thing = transactional(bpt) ;
++ thing.begin(ReadWrite.WRITE);
++ IndexTestLib.add(bpt, 1, 2, 3, 4) ;
++ thing.abort() ;
++ thing.end() ;
++ int outerRootIdx2 = bpt.getRootId() ;
++ assertEquals("After txn", outerRootIdx1, outerRootIdx2);
++ }
++
++ // Two transactions
++ @Test public void bptree_txn_04() {
++ BPlusTree bpt = createBPTree() ;
++ int outerRootIdx1 = bpt.getRootId() ;
++ Transactional thing = transactional(bpt) ;
++ Txn.executeWrite(thing, () -> {
++ IndexTestLib.add(bpt, 1, 2, 3, 4) ;
++ } );
++ int outerRootIdx2 = bpt.getRootId() ;
++ assertNotEquals("After txn(1)", outerRootIdx1, outerRootIdx2);
++ Txn.executeWrite(thing, () -> {
++ IndexTestLib.add(bpt, 5, 6) ;
++ } );
++ int outerRootIdx3 = bpt.getRootId() ;
++ assertNotEquals("After txn (2)", outerRootIdx1, outerRootIdx3);
++ assertNotEquals("After txn (3)", outerRootIdx2, outerRootIdx3);
++ }
++
++ // Two transactions, second an insert no-op.
++ // Relies on all blocks not being full and so not being
++ // split on the way down due to the early split algorithm.
++ @Test public void bptree_txn_05() {
++ BPlusTree bpt = createBPTree() ;
++ int outerRootIdx1 = bpt.getRootId() ;
++ Transactional thing = transactional(bpt) ;
++ Txn.executeWrite(thing, () -> {
++ IndexTestLib.add(bpt, 1, 2, 3) ;
++ } );
++ int outerRootIdx2 = bpt.getRootId() ;
++ assertNotEquals("After txn(1)", outerRootIdx1, outerRootIdx2);
++ Txn.executeWrite(thing, () -> {
++ IndexTestLib.add(bpt, 1, 2) ;
++ } );
++ int outerRootIdx3 = bpt.getRootId() ;
++ assertNotEquals("After txn (2)", outerRootIdx1, outerRootIdx3);
++ assertEquals("After txn (3)", outerRootIdx2, outerRootIdx3);
++ }
++
++ // Two transactions, second a delete no-op.
++ // Relies on all blocks not being min0size so not rebalanced.
++ @Test public void bptree_txn_06() {
++ BPlusTree bpt = createBPTree() ;
++ int outerRootIdx1 = bpt.getRootId() ;
++ Transactional thing = transactional(bpt) ;
++ Txn.executeWrite(thing, () -> {
++ IndexTestLib.add(bpt, 1, 2, 3) ;
++ } );
++ int outerRootIdx2 = bpt.getRootId() ;
++ assertNotEquals("After txn(1)", outerRootIdx1, outerRootIdx2);
++ Txn.executeWrite(thing, () -> {
++ IndexTestLib.delete(bpt, 5, 6) ;
++ } );
++ int outerRootIdx3 = bpt.getRootId() ;
++ assertNotEquals("After txn (2)", outerRootIdx1, outerRootIdx3);
++ assertEquals("After txn (3)", outerRootIdx2, outerRootIdx3);
++ }
++
++ // Two trees
++ @Test public void bptree_txn_10() {
++ BPlusTree bpt1 = createBPTree() ;
++ BPlusTree bpt2 = createBPTree() ;
++ assertNotEquals(bpt1.getComponentId(), bpt2.getComponentId()) ;
++
++ Transactional thing = transactional(bpt1, bpt2) ;
++ Txn.executeWrite(thing, () -> {
++ IndexTestLib.add(bpt1, 1, 2, 3) ;
++ IndexTestLib.add(bpt2, 4, 5) ;
++ } );
++ Txn.executeRead(thing, ()->{
++ IndexTestLib.testIndexContents(bpt2, 4, 5);
++ IndexTestLib.testIndexContents(bpt1, 1, 2, 3);
++ } );
++ }
++
++ @Test public void bptree_txn_11() {
++ BPlusTree bpt1 = createBPTree() ;
++ BPlusTree bpt2 = createBPTree() ;
++ assertNotEquals(bpt1.getComponentId(), bpt2.getComponentId()) ;
++
++ Transactional thing = transactional(bpt1, bpt2) ;
++
++ // Commit 1
++ Txn.executeWrite(thing, () -> {
++ IndexTestLib.add(bpt1, 2, 1) ;
++ IndexTestLib.add(bpt2, 3, 4, 5) ;
++ }) ;
++ Txn.executeRead(thing, ()->{
++ IndexTestLib.testIndexContents(bpt2, 3, 4, 5);
++ IndexTestLib.testIndexContents(bpt1, 1, 2);
++ } );
++
++ // Abort
++ thing.begin(ReadWrite.WRITE);
++ IndexTestLib.add(bpt1, 9, 10) ;
++ IndexTestLib.delete(bpt2, 3, 11) ;
++ thing.abort() ;
++ Txn.executeRead(thing, ()->{
++ IndexTestLib.testIndexContents(bpt2, 3, 4, 5);
++ IndexTestLib.testIndexContents(bpt1, 1, 2);
++ } );
++
++ // Commit 2
++ Txn.executeWrite(thing, () -> {
++ IndexTestLib.delete(bpt1, 1,3) ;
++ IndexTestLib.add(bpt1, 4) ;
++ IndexTestLib.add(bpt2, 11, 12, 13) ;
++ }) ;
++ Txn.executeRead(thing, ()->{
++ IndexTestLib.testIndexContents(bpt2, 3, 4, 5, 11, 12, 13);
++ IndexTestLib.testIndexContents(bpt1, 2, 4);
++ } );
++ }
++
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/rewriter/TestBPlusTreeRewriterNonTxn.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/rewriter/TestBPlusTreeRewriterNonTxn.java
index 0000000,0000000..d9c2b6a
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/rewriter/TestBPlusTreeRewriterNonTxn.java
@@@ -1,0 -1,0 +1,179 @@@
++/*
++ * 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.dboe.trans.bplustree.rewriter;
++
++import java.util.ArrayList ;
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.apache.jena.atlas.lib.Bytes ;
++import org.junit.AfterClass ;
++import org.junit.Assert ;
++import org.junit.BeforeClass ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.block.BlockMgrFactory ;
++import org.seaborne.dboe.base.file.BufferChannel ;
++import org.seaborne.dboe.base.file.FileFactory ;
++import org.seaborne.dboe.base.file.FileSet ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.sys.Names ;
++import org.seaborne.dboe.trans.bplustree.BPTreeException ;
++import org.seaborne.dboe.trans.bplustree.BPlusTree ;
++import org.seaborne.dboe.trans.bplustree.BPlusTreeParams ;
++//import org.seaborne.dboe.trans.bplustree.rewriter.BPlusTreeRewriter ;
++
++public class TestBPlusTreeRewriterNonTxn extends Assert
++{
++ // See also CmdTestBlusTreeRewriter for randomized soak testing.
++
++ static int KeySize = 4 ;
++ static int ValueSize = 8 ;
++ static RecordFactory recordFactory = new RecordFactory(KeySize,ValueSize) ;
++
++ // The BPlusTreeRewriter works directly on storage.
++ static boolean b ;
++ @BeforeClass public static void beforeClass() { b = BlockMgrFactory.AddTracker ; BlockMgrFactory.AddTracker = false ; }
++ @AfterClass public static void afterClass() { BlockMgrFactory.AddTracker = b ;}
++
++ @Test public void bpt_rewrite_01() { runTest(2, 0) ; }
++ @Test public void bpt_rewrite_02() { runTest(3, 0) ; }
++
++ @Test public void bpt_rewrite_03() { runTest(2, 1) ; }
++ @Test public void bpt_rewrite_04() { runTest(3, 1) ; }
++
++ @Test public void bpt_rewrite_05() { runTest(2, 2) ; }
++ @Test public void bpt_rewrite_06() { runTest(3, 2) ; }
++
++ @Test public void bpt_rewrite_07() { runTest(2, 100) ; }
++ @Test public void bpt_rewrite_08() { runTest(3, 100) ; }
++
++ @Test public void bpt_rewrite_99() { runTest(5, 1000) ; }
++
++ static void runTest(int order, int N)
++ { runOneTest(order, N , recordFactory, false) ; }
++
++ public static void runOneTest(int order, int N, RecordFactory recordFactory, boolean debug)
++ {
++ BPlusTreeParams bptParams = new BPlusTreeParams(order, recordFactory) ;
++ BPlusTreeRewriter.debug = debug ;
++
++ // ---- Test data
++ List<Record> originaldata = TestBPlusTreeRewriterNonTxn.createData(N, recordFactory) ;
++ if ( debug )
++ System.out.println("Test data: "+originaldata) ;
++
++ FileSet destination = FileSet.mem() ;
++ // ---- Rewrite
++ BufferChannel rootState = FileFactory.createBufferChannel(destination, Names.extBptState) ;
++ // Write leaves to ...
++ BlockMgr blkMgr1 = BlockMgrFactory.create(destination, Names.extBptTree, bptParams.getCalcBlockSize(), 10, 10) ;
++ // Write nodes to ...
++ BlockMgr blkMgr2 = BlockMgrFactory.create(destination, Names.extBptTree, bptParams.getCalcBlockSize(), 10, 10) ;
++
++ BPlusTree bpt2 = BPlusTreeRewriter.packIntoBPlusTree(originaldata.iterator(), bptParams, recordFactory,
++ rootState, blkMgr1, blkMgr2) ;
++ if ( debug )
++ {
++ BPlusTreeRewriterUtils.divider() ;
++ bpt2.dump();
++ }
++
++ // ---- Checking
++ bpt2.check() ;
++
++ scanComparision(originaldata, bpt2) ;
++ findComparison(originaldata, bpt2) ;
++ sizeComparison(originaldata, bpt2) ;
++ }
++
++ public static void scanComparision(List<Record> originaldata, BPlusTree bpt2)
++ {
++ // ** Scan comparisonSetupIndex
++ Iterator<Record> iter1 = originaldata.iterator() ;
++ Iterator<Record> iter2 = bpt2.iterator() ;
++ long count = 0 ;
++ for ( ; iter1.hasNext() ; )
++ {
++ count++ ;
++ Record r1 = iter1.next();
++ if ( ! iter2.hasNext() )
++ error("Deviation: new B+Tree is smaller") ;
++ Record r2 = iter2.next();
++
++ if ( ! Record.equals(r1, r2) )
++ error("Deviation in iteration record %d: %s : %s", count, r1, r2) ;
++ }
++ if ( iter2.hasNext() )
++ error("New B+Tree larger than original") ;
++ }
++
++ public static void findComparison(List<Record> originaldata, BPlusTree bpt2)
++ {
++ Iterator<Record> iter1 = originaldata.iterator() ;
++
++ long count = 0 ;
++ for ( ; iter1.hasNext() ; )
++ {
++ count++ ;
++ Record r1 = iter1.next();
++
++ Record r3 = bpt2.find(r1) ;
++ if ( r3 == null )
++ {
++ r3 = bpt2.find(r1) ;
++ error("Deviation in find at record %d: %s : null", count, r1) ;
++ }
++ if ( ! Record.equals(r1, r3) )
++ error("Deviation in find at record %d: %s : %s", count, r1, r3) ;
++ }
++
++ }
++
++ public static void sizeComparison(List<Record> originaldata, BPlusTree bpt2)
++ {
++ long count1 = originaldata.size() ;
++ long count2 = bpt2.size() ;
++ //System.out.printf("Sizes = %d / %d\n", count1, count2) ;
++ if ( count1 != count2 )
++ // Not error - this test does not identify why there was a problem so continue.
++ System.err.println("**** DIFFERENT") ;
++ }
++
++ static List<Record> createData(int N, RecordFactory recordFactory)
++ {
++ List<Record> originaldata = new ArrayList<>(N) ;
++ for ( int i = 0; i < N ; i++ )
++ {
++ Record record = recordFactory.create() ;
++ Bytes.setInt(i+1, record.getKey()) ;
++ if ( recordFactory.hasValue() )
++ Bytes.setInt(10*i+1, record.getValue()) ;
++ originaldata.add(record) ;
++ }
++ return originaldata ;
++ }
++
++ private static void error(String string, Object ...args)
++ {
++ String msg = String.format(string, args) ;
++ System.err.println(msg) ;
++ throw new BPTreeException(msg) ;
++ }
++}
[49/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrFactory.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrFactory.java
index 0000000,0000000..583c490
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrFactory.java
@@@ -1,0 -1,0 +1,150 @@@
++/*
++ * 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.dboe.base.block ;
++
++import org.apache.jena.atlas.logging.Log ;
++import org.seaborne.dboe.DBOpEnvException ;
++import org.seaborne.dboe.base.file.* ;
++import org.seaborne.dboe.sys.SystemIndex ;
++
++public class BlockMgrFactory {
++ // This isn't always helpful so be careful if setting the default to "true".
++ // Sometimes the tracking is too strict
++ // e.g. transactions keep blocks and not release them down the layers.
++ public/* final */static boolean AddTracker = false ;
++
++ public static BlockMgr tracker(BlockMgr blockMgr) {
++ if ( blockMgr instanceof BlockMgrTracker )
++ return blockMgr ;
++ return BlockMgrTracker.track(blockMgr) ;
++ }
++
++ /** Add a tracker if the system default is to do so */
++ private static BlockMgr track(BlockMgr blockMgr) {
++ if ( !AddTracker )
++ return blockMgr ;
++ return tracker(blockMgr) ;
++ }
++
++ public static BlockMgr create(FileSet fileSet, String ext, BlockParams params) {
++ return create(fileSet, ext,
++ params.getFileMode(),
++ params.getBlockSize(),
++ params.getBlockReadCacheSize(),
++ params.getBlockWriteCacheSize()) ;
++ }
++
++ public static BlockMgr create(FileSet fileSet, String ext, int blockSize, int readBlockCacheSize, int writeBlockCacheSize) {
++ return create(fileSet, ext, null, blockSize, readBlockCacheSize, writeBlockCacheSize) ;
++ }
++
++ // XXX Deprecate?
++ public static BlockMgr create(FileSet fileSet, String ext, FileMode fileMode, int blockSize, int readBlockCacheSize, int writeBlockCacheSize) {
++ if ( fileSet.isMem() )
++ return createMem(fileSet.filename(ext), blockSize) ;
++ else
++ return createFile(fileSet.filename(ext), fileMode, blockSize, readBlockCacheSize, writeBlockCacheSize) ;
++ }
++
++ /** Create an in-memory block manager */
++ public static BlockMgr createMem(String indexName, int blockSize) {
++ BlockAccess file = new BlockAccessMem(indexName, blockSize) ;
++ BlockMgr blockMgr = new BlockMgrFileAccess(file, blockSize) ;
++ blockMgr = new BlockMgrFreeChain(blockMgr) ;
++ // Small cache - testing.
++ blockMgr = BlockMgrCache.create(3, 3, blockMgr) ;
++ return track(blockMgr) ;
++ }
++
++ /** Create a BlockMgr backed by a real file */
++ public static BlockMgr createFile(String filename, BlockParams params) {
++ return createFile(filename,
++ params.getFileMode(), params.getBlockSize(),
++ params.getBlockReadCacheSize(), params.getBlockWriteCacheSize()) ;
++ }
++
++ /** Create a BlockMgr backed by a real file */
++ public static BlockMgr createFile(String filename, FileMode fileMode, int blockSize, int readBlockCacheSize, int writeBlockCacheSize) {
++ if ( fileMode == null )
++ fileMode = SystemIndex.fileMode() ;
++ switch (fileMode) {
++ case mapped :
++ return createMMapFile(filename, blockSize) ;
++ case direct :
++ return createStdFile(filename, blockSize, readBlockCacheSize, writeBlockCacheSize) ;
++ }
++ throw new DBOpEnvException("Unknown file mode: " + fileMode) ;
++ }
++
++ /** Create a NIO Block Manager */
++ public static BlockMgr createMMapFile(String filename, int blockSize) {
++ BlockAccess file = new BlockAccessMapped(filename, blockSize) ;
++ BlockMgr blockMgr = wrapFileAccess(file, blockSize) ;
++ return track(blockMgr) ;
++ }
++
++ /** Create a Block Manager using direct access (and a cache) */
++ public static BlockMgr createStdFile(String filename, int blockSize, int readBlockCacheSize, int writeBlockCacheSize) {
++ BlockAccess file = new BlockAccessDirect(filename, blockSize) ;
++ BlockMgr blockMgr = wrapFileAccess(file, blockSize) ;
++ blockMgr = addCache(blockMgr, readBlockCacheSize, writeBlockCacheSize) ;
++ return track(blockMgr) ;
++ }
++
++ /** Create a Block Manager using direct access, no caching, no nothing. */
++ public static BlockMgr createStdFileNoCache(String filename, int blockSize) {
++ BlockAccess blockAccess = new BlockAccessDirect(filename, blockSize) ;
++ BlockMgr blockMgr = new BlockMgrFileAccess(blockAccess, blockSize) ;
++ return blockMgr ;
++ }
++
++ /**
++ * Add a caching layer to a BlockMgr.
++ * <p>
++ * This does not make sense for memory BlockMgr or for memory mapper files.
++ * This function always add the cache.
++ *
++ * @see #addCache(BlockMgr, FileSet, FileMode, int, int)
++ */
++ public static BlockMgr addCache(BlockMgr blockMgr, int readBlockCacheSize, int writeBlockCacheSize) {
++ if ( blockMgr instanceof BlockMgrCache )
++ Log.warn(BlockMgrFactory.class, "BlockMgr already has a cache: " + blockMgr.getLabel()) ;
++ return BlockMgrCache.create(readBlockCacheSize, writeBlockCacheSize, blockMgr) ;
++ }
++
++ /**
++ * Add a caching layer to a BlockMgr if appropriate. This does not make
++ * sense for memory BlockMgr or for memory mapper files. These are skipped.
++ */
++ public static BlockMgr addCache(BlockMgr blockMgr, FileSet fileSet, FileMode fileMode, int readBlockCacheSize, int writeBlockCacheSize) {
++ if ( fileSet.isMem() )
++ return blockMgr ;
++ if ( fileMode == null )
++ fileMode = SystemIndex.fileMode() ;
++ if ( fileMode == FileMode.mapped )
++ return blockMgr ;
++ return addCache(blockMgr, readBlockCacheSize, writeBlockCacheSize) ;
++ }
++
++ private static BlockMgr wrapFileAccess(BlockAccess blockAccess, int blockSize) {
++ BlockMgr blockMgr = new BlockMgrFileAccess(blockAccess, blockSize) ;
++ // This is a temporary fix to the problem
++ blockMgr = new BlockMgrFreeChain(blockMgr) ;
++ return blockMgr ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrFileAccess.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrFileAccess.java
index 0000000,0000000..c13ac2c
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrFileAccess.java
@@@ -1,0 -1,0 +1,168 @@@
++/*
++ * 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.dboe.base.block ;
++
++import static java.lang.String.format ;
++
++import org.apache.jena.atlas.lib.InternalErrorException ;
++import org.apache.jena.atlas.lib.Lib ;
++import org.seaborne.dboe.base.file.BlockAccess ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/**
++ * Block manager that maps from the FileAccess layer to a BlockMgr. Add free
++ * block management (but we should layer with BlockMgrFreeChain)
++ */
++
++final public class BlockMgrFileAccess extends BlockMgrBase {
++ private static Logger log = LoggerFactory.getLogger(BlockMgrFileAccess.class) ;
++
++ private final BlockAccess file ;
++ private boolean closed = false ;
++ // Set on any write operations.
++ private boolean syncNeeded = false ;
++
++ // Create via the BlockMgrFactory.
++ /* package */BlockMgrFileAccess(BlockAccess blockAccess, int blockSize) {
++ super(blockAccess.getLabel(), blockSize) ;
++ file = blockAccess ;
++ }
++
++ @Override
++ protected Block allocate() {
++ syncNeeded = true ;
++ return file.allocate(blockSize) ;
++ }
++
++ @Override
++ public Block promote(Block block) {
++ return block ;
++ }
++
++ @Override
++ public Block getRead(long id) {
++ return getBlock(id, true) ;
++ }
++
++ @Override
++ public Block getWrite(long id) {
++ return getBlock(id, false) ;
++ }
++
++ private Block getBlock(long id, boolean readOnly) {
++ checkNotClosed() ;
++ Block block = file.read(id) ;
++ block.setReadOnly(readOnly) ;
++ return block ;
++ }
++
++ private void checkNotClosed() {
++ if ( closed )
++ throw new InternalErrorException(Lib.className(this)+" : already closed") ;
++ }
++
++ @Override
++ public void release(Block block) {
++ checkNotClosed() ;
++ }
++
++ @Override
++ public void write(Block block) {
++ checkNotClosed() ;
++ if ( block.isReadOnly() )
++ throw new BlockException("Attempt to write a read-only block ("+block.getId()+")" ) ;
++ syncNeeded = true ;
++ file.write(block) ;
++ }
++
++ @Override
++ public void overwrite(Block block) {
++ checkNotClosed() ;
++ syncNeeded = true ;
++ file.overwrite(block) ;
++ }
++
++ @Override
++ public void free(Block block) {
++ checkNotClosed() ;
++ // syncNeeded = true ;
++ // We do nothing about free blocks currently.
++ }
++
++ @Override
++ public boolean valid(int id) {
++ checkNotClosed() ;
++ return file.valid(id) ;
++ }
++
++ @Override
++ public void sync() {
++ checkNotClosed() ;
++ if ( syncNeeded )
++ file.sync() ;
++ else
++ syncNeeded = true ;
++ syncNeeded = false ;
++ }
++
++ @Override
++ public void syncForce() {
++ checkNotClosed() ;
++ file.sync() ;
++ }
++
++ @Override
++ public boolean isClosed() {
++ return closed ;
++ }
++
++ @Override
++ public void close() {
++ closed = true ;
++ file.close() ;
++ }
++
++ @Override
++ public boolean isEmpty() {
++ checkNotClosed() ;
++ return file.isEmpty() ;
++ }
++
++ @Override
++ public long allocLimit() {
++ checkNotClosed() ;
++ return file.allocBoundary() ;
++ }
++
++ @Override
++ public void resetAlloc(long boundary) {
++ checkNotClosed() ;
++ file.resetAllocBoundary(boundary);
++ }
++
++ @Override
++ public String toString() {
++ return format("BlockMgrFileAccess[%d bytes]:%s", blockSize, file) ;
++ }
++
++ @Override
++ protected Logger log() {
++ return log ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrFreeChain.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrFreeChain.java
index 0000000,0000000..b131507
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrFreeChain.java
@@@ -1,0 -1,0 +1,83 @@@
++/*
++ * 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.dboe.base.block ;
++
++import java.util.ArrayDeque ;
++import java.util.Deque ;
++
++/**
++ * Recycle blocks - but only in-session. At the end of JVM run, the blocks are
++ * made "permanent" as no one finds them again on restart.
++ */
++final public class BlockMgrFreeChain extends BlockMgrWrapper {
++ // Could keep Pair<Integer, ByteBuffer>
++ // List<Block> freeBlocks = new ArrayList<Block>() ;
++ private final Deque<Block> freeBlocks = new ArrayDeque<>() ; // Keep as heap?
++
++ public BlockMgrFreeChain(BlockMgr blockMgr) {
++ super(blockMgr) ;
++ }
++
++ @Override
++ public Block allocate(int blockSize) {
++ if ( !freeBlocks.isEmpty() ) {
++ Block block = freeBlocks.removeFirst() ;
++ block.getByteBuffer().position(0) ;
++ return block ;
++ }
++ return super.allocate(blockSize) ;
++ }
++
++ @Override
++ public void free(Block block) {
++ if ( block.getId() >= blockMgr.allocLimit() )
++ freeBlocks.add(block) ;
++ }
++
++ @Override
++ public void resetAlloc(long boundary) {
++ super.resetAlloc(boundary);
++ // Just clear - assumes this is effectively a transaction boundary.
++ freeBlocks.clear();
++// Iterator<Block> iter = freeBlocks.iterator() ;
++// while(iter.hasNext()) {
++// Block blk = iter.next() ;
++// if ( blk.getId() < boundary )
++// iter.remove();
++// }
++ }
++ @Override
++ public boolean valid(int id) {
++ for ( Block blk : freeBlocks ) {
++ if ( blk.getId() == id )
++ return true ;
++ }
++ return super.valid(id) ;
++ }
++
++ @Override
++ public void sync() {
++ // Flush free blocks?
++ super.sync() ;
++ }
++
++ @Override
++ public String toString() {
++ return "Free:" + super.toString() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrLogger.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrLogger.java
index 0000000,0000000..bd218b8
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrLogger.java
@@@ -1,0 -1,0 +1,180 @@@
++/*
++ * 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.dboe.base.block ;
++
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++public class BlockMgrLogger implements BlockMgr // extends BlockMgrWrapper
++{
++ private final BlockMgr blockMgr ;
++ protected final Logger log ;
++ protected final boolean logAllOperations ;
++ private final String label ;
++
++ public BlockMgrLogger(BlockMgr blockMgr, boolean logAllOperations) {
++ this(null, blockMgr.getLabel(), blockMgr, logAllOperations) ;
++ }
++
++ public BlockMgrLogger(String label, BlockMgr blockMgr, boolean logAllOperations) {
++ this(null, label, blockMgr, logAllOperations) ;
++ }
++
++ public BlockMgrLogger(Logger log, String label, BlockMgr blockMgr, boolean logAllOperations) {
++ this.blockMgr = blockMgr ;
++ if ( log == null )
++ log = LoggerFactory.getLogger(BlockMgr.class) ;
++ this.log = log ;
++ this.logAllOperations = logAllOperations ;
++ if ( label == null )
++ label = blockMgr.getLabel() ;
++ this.label = label ;
++ }
++
++ @Override
++ public String getLabel() {
++ return label ;
++ }
++
++ @Override
++ public Block allocate(int blockSize) {
++ Block x = blockMgr.allocate(blockSize) ;
++ info("Allocate(" + x.getId() + ")") ;
++ return x ;
++ }
++
++ @Override
++ public boolean isEmpty() {
++ info("isEmpty()") ;
++ return blockMgr.isEmpty() ;
++ }
++
++ @Override
++ public long allocLimit() {
++ info("limit()") ;
++ return blockMgr.allocLimit() ;
++ }
++
++ @Override
++ public void resetAlloc(long boundary) {
++ info("resetAlloc("+boundary+")") ;
++ blockMgr.resetAlloc(boundary) ;
++ }
++
++ @Override
++ public Block getRead(long id) {
++ info("getRead(" + id + ")") ;
++ return blockMgr.getRead(id) ;
++ }
++
++ @Override
++ public Block getWrite(long id) {
++ info("getWrite(" + id + ")") ;
++ return blockMgr.getWrite(id) ;
++ }
++
++ @Override
++ public Block promote(Block block) {
++ info("promote(" + block.getId() + ")") ;
++ return blockMgr.promote(block) ;
++ }
++
++ @Override
++ public void release(Block block) {
++ info("release(" + block.getId() + ")") ;
++ blockMgr.release(block) ;
++ }
++
++ @Override
++ public void write(Block block) {
++ info("write(" + block.getId() + ")") ;
++ blockMgr.write(block) ;
++ }
++
++ @Override
++ public void overwrite(Block block) {
++ info("overwrite(" + block.getId() + ")") ;
++ blockMgr.overwrite(block) ;
++ }
++
++ @Override
++ public void free(Block block) {
++ info("freeBlock(" + block.getId() + ")") ;
++ blockMgr.free(block) ;
++ }
++
++ @Override
++ public boolean valid(int id) {
++ info("valid(" + id + ")") ;
++ return blockMgr.valid(id) ;
++ }
++
++ @Override
++ public void close() {
++ info("close") ;
++ blockMgr.close() ;
++ }
++
++ @Override
++ public boolean isClosed() {
++ info("isClosed") ;
++ return blockMgr.isClosed() ;
++ }
++
++ @Override
++ public void sync() {
++ info("sync") ;
++ blockMgr.sync() ;
++ }
++
++ @Override
++ public void syncForce() {
++ info("syncForce") ;
++ blockMgr.syncForce() ;
++ }
++
++ @Override
++ public void beginRead() {
++ info("> start read") ;
++ blockMgr.beginRead() ;
++ }
++
++ @Override
++ public void endRead() {
++ info("< finish read") ;
++ blockMgr.endRead() ;
++ }
++
++ @Override
++ public void beginUpdate() {
++ info("> start update") ;
++ blockMgr.beginUpdate() ;
++ }
++
++ @Override
++ public void endUpdate() {
++ info("< finish update") ;
++ blockMgr.endUpdate() ;
++ }
++
++ private void info(String string) {
++ if ( label != null )
++ string = label + ": " + string ;
++ log.info(string) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrReadonly.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrReadonly.java
index 0000000,0000000..eca86af
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrReadonly.java
@@@ -1,0 -1,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.dboe.base.block;
++
++import org.seaborne.dboe.DBOpEnvException ;
++
++public class BlockMgrReadonly extends BlockMgrWrapper
++{
++ public BlockMgrReadonly(BlockMgr blockMgr) {
++ super(blockMgr) ;
++ }
++
++ @Override public void beginUpdate() { throw new DBOpEnvException("Read-only block manager") ; }
++ @Override public void endUpdate() { throw new DBOpEnvException("Read-only block manager") ; }
++ @Override public Block allocate(int blockSize) { throw new DBOpEnvException("Read-only block manager") ; }
++ @Override public Block getWrite(long id) { throw new DBOpEnvException("Read-only block manager") ; }
++ @Override public Block promote(Block block) { throw new DBOpEnvException("Read-only block manager") ; }
++ @Override public void write(Block block) { throw new DBOpEnvException("Read-only block manager") ; }
++ @Override public void overwrite(Block block) { throw new DBOpEnvException("Read-only block manager") ; }
++ @Override public void free(Block block) { throw new DBOpEnvException("Read-only block manager") ; }
++
++// @Override
++// public void sync()
++// {
++// blockMgr.sync() ;
++// }
++
++ @Override public String toString() { return "RO:"+super.toString() ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrSwitcher.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrSwitcher.java
index 0000000,0000000..1a05120
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrSwitcher.java
@@@ -1,0 -1,0 +1,39 @@@
++/*
++ * 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.dboe.base.block;
++
++public class BlockMgrSwitcher extends BlockMgrWrapper
++{
++ protected final BlockMgr blockMgr1 ;
++ protected final BlockMgr blockMgr2 ;
++
++ public BlockMgrSwitcher(BlockMgr blockMgr1, BlockMgr blockMgr2)
++ {
++ super(blockMgr1) ;
++ this.blockMgr1 = blockMgr1 ;
++ this.blockMgr2 = blockMgr2 ;
++ }
++
++ public void switchover()
++ {
++ if ( super.blockMgr == blockMgr1 )
++ setBlockMgr(blockMgr2) ;
++ else
++ setBlockMgr(blockMgr1) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrSync.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrSync.java
index 0000000,0000000..492f543
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrSync.java
@@@ -1,0 -1,0 +1,148 @@@
++/*
++ * 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.dboe.base.block ;
++
++
++/**
++ * Add synchronized to a BlockMgr. This is the same as BlockMgrWrapper but with
++ * 'synchronized' added
++ */
++
++public class BlockMgrSync implements BlockMgr {
++ protected final BlockMgr blockMgr ;
++
++ public BlockMgrSync(BlockMgr blockMgr) {
++ this.blockMgr = blockMgr ;
++ }
++
++ public BlockMgr getWrapped() {
++ return blockMgr ;
++ }
++
++ @Override
++ synchronized public Block allocate(int blockSize) {
++ return blockMgr.allocate(blockSize) ;
++ }
++
++ @Override
++ synchronized public Block getRead(long id) {
++ return blockMgr.getRead(id) ;
++ }
++
++ @Override
++ synchronized public Block getWrite(long id) {
++ return blockMgr.getWrite(id) ;
++ }
++
++ @Override
++ synchronized public Block promote(Block block) {
++ return blockMgr.promote(block) ;
++ }
++
++ @Override
++ synchronized public void release(Block block) {
++ blockMgr.release(block) ;
++ }
++
++ @Override
++ synchronized public void write(Block block) {
++ blockMgr.write(block) ;
++ }
++
++ @Override
++ synchronized public void overwrite(Block block) {
++ blockMgr.overwrite(block) ;
++ }
++
++ @Override
++ synchronized public void free(Block block) {
++ blockMgr.free(block) ;
++ }
++
++ @Override
++ synchronized public void sync() {
++ blockMgr.sync() ;
++ }
++
++ @Override
++ synchronized public void syncForce() {
++ blockMgr.syncForce() ;
++ }
++
++ @Override
++ synchronized public void close() {
++ blockMgr.close() ;
++ }
++
++ @Override
++ synchronized public boolean isEmpty() {
++ return blockMgr.isEmpty() ;
++ }
++
++ @Override
++ synchronized public long allocLimit() {
++ return blockMgr.allocLimit() ;
++ }
++
++
++ @Override
++ synchronized public void resetAlloc(long boundary) {
++ blockMgr.resetAlloc(boundary) ;
++ }
++
++ @Override
++ synchronized public void beginRead() {
++ blockMgr.beginRead() ;
++ }
++
++ @Override
++ synchronized public void endRead() {
++ blockMgr.endRead() ;
++ }
++
++ @Override
++ synchronized public void beginUpdate() {
++ blockMgr.beginUpdate() ;
++ }
++
++ @Override
++ synchronized public void endUpdate() {
++ blockMgr.endUpdate() ;
++ }
++
++ @Override
++ synchronized public boolean valid(int id) {
++ return blockMgr.valid(id) ;
++ }
++
++ @Override
++ synchronized public boolean isClosed() {
++ return blockMgr.isClosed() ;
++ }
++
++ @Override
++ synchronized public String getLabel() {
++ return blockMgr.getLabel() ;
++ }
++
++ @Override
++ public String toString() {
++ return "Sync:" + blockMgr.toString() ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrTracker.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrTracker.java
index 0000000,0000000..588a455
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrTracker.java
@@@ -1,0 -1,0 +1,413 @@@
++/*
++ * 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.dboe.base.block ;
++
++import static org.seaborne.dboe.base.block.BlockMgrTracker.Action.Alloc ;
++import static org.seaborne.dboe.base.block.BlockMgrTracker.Action.BeginRead ;
++import static org.seaborne.dboe.base.block.BlockMgrTracker.Action.BeginUpdate ;
++import static org.seaborne.dboe.base.block.BlockMgrTracker.Action.EndRead ;
++import static org.seaborne.dboe.base.block.BlockMgrTracker.Action.EndUpdate ;
++import static org.seaborne.dboe.base.block.BlockMgrTracker.Action.Free ;
++import static org.seaborne.dboe.base.block.BlockMgrTracker.Action.GetRead ;
++import static org.seaborne.dboe.base.block.BlockMgrTracker.Action.GetWrite ;
++import static org.seaborne.dboe.base.block.BlockMgrTracker.Action.Promote ;
++import static org.seaborne.dboe.base.block.BlockMgrTracker.Action.Release ;
++import static org.seaborne.dboe.base.block.BlockMgrTracker.Action.Write ;
++
++import java.util.ArrayList ;
++import java.util.List ;
++
++import org.apache.jena.atlas.lib.Pair ;
++import org.apache.jena.ext.com.google.common.collect.HashMultiset ;
++import org.apache.jena.ext.com.google.common.collect.Multiset ;
++import org.seaborne.dboe.DBOpEnvException ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++public class BlockMgrTracker /* extends BlockMgrWrapper */ implements BlockMgr {
++ private static Logger loggerDefault = LoggerFactory.getLogger(BlockMgrTracker.class) ;
++ public static boolean verbose = false ;
++
++ static enum Action {
++ Alloc, Promote, GetRead, GetWrite, Write, Release, Free,
++ BeginRead, EndRead,
++ BeginUpdate, EndUpdate
++ }
++ static final Long NoId = (long)-9 ;
++
++ // ---- State for tracking
++ // Track and count block references and releases
++ // No - the page is dirty.
++
++
++ protected final Multiset<Long> activeReadBlocks = HashMultiset.create() ;
++ protected final Multiset<Long> activeWriteBlocks = HashMultiset.create() ;
++ // Track the operations
++ protected final List<Pair<Action, Long>> actions = new ArrayList<>() ;
++ // ---- State for tracking
++
++ protected final BlockMgr blockMgr ;
++
++ private void clearInternalRW() {
++ activeReadBlocks.clear() ;
++ activeWriteBlocks.clear() ;
++ actions.clear() ;
++ }
++
++ private void clearInternalIter() {
++ clearInternalRW() ;
++ }
++
++ private int inRead = 0 ;
++ private boolean inUpdate = false ;
++ private boolean inBatch = false ;
++ private final Logger log ;
++ private final String label ;
++
++ public static BlockMgr track(BlockMgr blkMgr) {
++ return track(blkMgr.getLabel(), blkMgr) ;
++ }
++
++ private static BlockMgr track(String label, BlockMgr blkMgr) {
++ return new BlockMgrTracker(label, blkMgr) ;
++ }
++
++ private BlockMgrTracker(BlockMgr blockMgr) {
++ this(LoggerFactory.getLogger(BlockMgrTracker.class), blockMgr.getLabel(), blockMgr) ;
++ }
++
++ private BlockMgrTracker(String label, BlockMgr blockMgr) {
++ this(loggerDefault, label, blockMgr) ;
++ }
++
++ //
++ // public BlockMgrTracker(Class<?> cls, String label, BlockMgr blockMgr)
++ // {
++ // this(LoggerFactory.getLogger(cls), label, blockMgr) ;
++ // }
++
++ private BlockMgrTracker(Logger logger, String label, BlockMgr blockMgr) {
++ this.blockMgr = blockMgr ;
++ this.log = logger ;
++ this.label = blockMgr.getLabel() ;
++ }
++
++ private void add(Action action, Long id) {
++ actions.add(new Pair<>(action, id)) ;
++ }
++
++ @Override
++ public Block allocate(int blockSize) {
++ Block block ;
++ synchronized (this) {
++ checkUpdate(Alloc) ;
++ block = blockMgr.allocate(blockSize) ;
++ Long id = block.getId() ;
++ activeWriteBlocks.add(id) ;
++ add(Alloc, id) ;
++ }
++ return block ;
++ }
++
++ @Override
++ public Block getRead(long id) {
++ // What if this is a write block already?
++ synchronized (this) {
++ checkRead(GetRead) ;
++ Long x = id ;
++ add(GetRead, x) ;
++
++ if ( activeWriteBlocks.contains(x) )
++ activeWriteBlocks.add(x) ;
++ else
++ activeReadBlocks.add(x) ;
++ }
++ return blockMgr.getRead(id) ;
++ }
++
++ @Override
++ public Block getWrite(long id) {
++ synchronized (this) {
++ checkUpdate(GetWrite) ;
++ Long x = id ;
++ add(GetWrite, x) ;
++ activeWriteBlocks.add(x) ;
++ }
++ return blockMgr.getWrite(id) ;
++ }
++
++ @Override
++ public Block promote(Block block) {
++ synchronized (this) {
++ checkUpdate(Promote) ;
++ Long id = block.getId() ;
++ add(Promote, id) ;
++
++ if ( !activeWriteBlocks.contains(id) && !activeReadBlocks.contains(id) )
++ error(Promote, id + " is not an active block") ;
++
++ if ( activeReadBlocks.contains(id) )
++ // Remove one read count
++ // Really, do this if obtained via "getRead" and not "getWrite"
++ activeReadBlocks.remove(id) ;
++
++ // Double promotion results in only one entry.
++ if ( !activeWriteBlocks.contains(id) )
++ activeWriteBlocks.add(id) ;
++ }
++ return blockMgr.promote(block) ;
++ }
++
++ @Override
++ public void release(Block block) {
++ synchronized (this) {
++ checkRead(Release) ;
++ Long id = block.getId() ;
++ add(Release, id) ;
++
++ if ( !activeReadBlocks.contains(id) && !activeWriteBlocks.contains(id) )
++ error(Release, id + " is not an active block") ;
++
++ // May have been promoted.
++ if ( activeWriteBlocks.contains(id) )
++ activeWriteBlocks.remove(id) ;
++ else
++ activeReadBlocks.remove(block.getId()) ;
++ }
++ blockMgr.release(block) ;
++ }
++
++ @Override
++ public void write(Block block) {
++ writeTracker(block) ;
++ blockMgr.write(block) ;
++ }
++
++ @Override
++ synchronized public void overwrite(Block block) {
++ writeTracker(block) ;
++ blockMgr.overwrite(block) ;
++ }
++
++ private void writeTracker(Block block) {
++ synchronized (this) {
++ checkUpdate(Write) ;
++ Long id = block.getId() ;
++ add(Write, id) ;
++ if ( !activeWriteBlocks.contains(id) )
++ error(Write, id + " is not an active write block") ;
++ }
++ }
++
++ @Override
++ public void free(Block block) {
++ synchronized (this) {
++ checkUpdate(Free) ;
++ Long id = block.getId() ;
++ add(Free, id) ;
++ if ( activeReadBlocks.contains(id) )
++ error(Free, id + " is a read block") ;
++ else if ( !activeWriteBlocks.contains(id) )
++ error(Free, id + " is not a write block") ;
++ activeWriteBlocks.remove(id) ;
++ }
++ blockMgr.free(block) ;
++ }
++
++ @Override
++ public void sync() {
++ blockMgr.sync() ;
++ }
++
++ @Override
++ public void syncForce() {
++ blockMgr.syncForce() ;
++ }
++
++ @Override
++ public void close() {
++ blockMgr.close() ;
++ }
++
++ @Override
++ public boolean isEmpty() {
++ return blockMgr.isEmpty() ;
++ }
++
++ @Override
++ public long allocLimit() {
++ return blockMgr.allocLimit() ;
++ }
++
++ @Override
++ public void resetAlloc(long boundary) {
++ blockMgr.resetAlloc(boundary) ;
++ }
++
++ @Override
++ public boolean valid(int id) {
++ return blockMgr.valid(id) ;
++ }
++
++ @Override
++ public boolean isClosed() {
++ return blockMgr.isClosed() ;
++ }
++
++ @Override
++ synchronized public void beginRead() {
++ synchronized (this) {
++ if ( inUpdate )
++ error(BeginRead, "beginRead when already in update") ;
++ inRead++ ;
++ inUpdate = false ;
++ }
++ blockMgr.beginRead() ;
++ }
++
++ @Override
++ synchronized public void endRead() {
++ synchronized (this) {
++ if ( inRead == 0 )
++ error(EndRead, "endRead but not in read") ;
++ if ( inUpdate )
++ error(EndRead, "endRead when in update") ;
++
++ checkEmpty("Outstanding write blocks at end of read operations!", activeWriteBlocks) ;
++
++ if ( inRead == 0 ) {
++ // Check at end of multiple reads or a write
++ checkEmpty("Outstanding read blocks at end of read operations", activeReadBlocks) ;
++ clearInternalRW() ;
++ }
++
++ inUpdate = false ;
++ inRead-- ;
++ }
++ blockMgr.endRead() ;
++ }
++
++ @Override
++ public void beginUpdate() {
++ synchronized (this) {
++ if ( inRead > 0 )
++ error(BeginUpdate, "beginUpdate when already in read") ;
++ if ( inUpdate )
++ error(BeginUpdate, "beginUpdate when already in update") ;
++ inUpdate = true ;
++ }
++ blockMgr.beginUpdate() ;
++ }
++
++ @Override
++ public void endUpdate() {
++ synchronized (this) {
++ if ( !inUpdate )
++ error(EndUpdate, "endUpdate but not in update") ;
++ if ( inRead > 0 )
++ error(EndUpdate, "endUpdate when in read") ;
++
++ checkEmpty("Outstanding read blocks at end of update operations", activeReadBlocks) ;
++
++ checkEmpty("Outstanding write blocks at end of update operations", activeWriteBlocks) ;
++
++ inUpdate = false ;
++ inRead = 0 ;
++ clearInternalRW() ;
++ }
++ blockMgr.endUpdate() ;
++ }
++
++ private void checkUpdate(Action action) {
++// if ( ! inBatch )
++// warn(action, "update called outside a batch") ;
++ if ( ! inUpdate )
++ error(action, "called outside update") ;
++ }
++
++ private void checkRead(Action action) {
++ if ( !inUpdate && inRead == 0 )
++ error(action, "Called outside update and read") ;
++ }
++
++ private void checkEmpty(String string, Multiset<Long> blocks) {
++ if ( !blocks.isEmpty() ) {
++ error(string) ;
++ for ( Long id : blocks )
++ info(" Block: " + id) ;
++ history() ;
++ throw new DBOpEnvException() ;
++ // debugPoint() ;
++ }
++ }
++
++ private String msg(String string) {
++ if ( label == null )
++ return string ;
++ return label + ": " + string ;
++ }
++
++ private void info(String string) {
++ log.info(msg(string)) ;
++ }
++
++ private void warn(String string) {
++ log.warn(msg(string)) ;
++ }
++
++ private void warn(Action action, String string) {
++ warn(action + ": " + string) ;
++ }
++
++ private void error(String string) {
++ log.error(msg(string)) ;
++ }
++
++ private void error(Action action, String string) {
++ if ( verbose ) {
++ error(action + ": " + string) ;
++ history() ;
++ }
++ throw new BlockException(msg(action + ": " + string)) ;
++ // debugPoint() ;
++ }
++
++ // Do nothing - but use a a breakpoint point.
++ private void debugPoint() {}
++
++ private void history() {
++ info("History") ;
++ for ( Pair<Action, Long> p : actions ) {
++ if ( p.getRight() != NoId )
++ log.info(String.format("%s: %-12s %d", label, p.getLeft(), p.getRight())) ;
++ else
++ log.info(String.format("%s: %-12s", label, p.getLeft())) ;
++
++ }
++ }
++
++ @Override
++ public String toString() {
++ return "BlockMgrTracker" + ((label == null) ? "" : (": " + label)) ;
++ }
++
++ @Override
++ public String getLabel() {
++ return label ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrWrapper.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrWrapper.java
index 0000000,0000000..029d309
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockMgrWrapper.java
@@@ -1,0 -1,0 +1,148 @@@
++/*
++ * 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.dboe.base.block ;
++
++
++public class BlockMgrWrapper implements BlockMgr {
++ protected BlockMgr blockMgr ;
++
++ public BlockMgrWrapper(BlockMgr blockMgr) {
++ setBlockMgr(blockMgr) ;
++ }
++
++ /** Set another BlockMgr as the target of the wrapper - return the old one */
++ protected final BlockMgr setBlockMgr(BlockMgr blockMgr) {
++ BlockMgr old = this.blockMgr ;
++ this.blockMgr = blockMgr ;
++ return old ;
++ }
++
++ public BlockMgr getWrapped() {
++ return blockMgr ;
++ }
++
++ @Override
++ public Block allocate(int blockSize) {
++ return blockMgr.allocate(blockSize) ;
++ }
++
++ @Override
++ public Block getRead(long id) {
++ return blockMgr.getRead(id) ;
++ }
++
++ @Override
++ public Block getWrite(long id) {
++ return blockMgr.getWrite(id) ;
++ }
++
++ @Override
++ public Block promote(Block block) {
++ return blockMgr.promote(block) ;
++ }
++
++ @Override
++ public void release(Block block) {
++ blockMgr.release(block) ;
++ }
++
++ @Override
++ public void write(Block block) {
++ blockMgr.write(block) ;
++ }
++
++ @Override
++ public void overwrite(Block block) {
++ blockMgr.overwrite(block) ;
++ }
++
++ @Override
++ public void free(Block block) {
++ blockMgr.free(block) ;
++ }
++
++ @Override
++ public boolean isEmpty() {
++ return blockMgr.isEmpty() ;
++ }
++
++ @Override
++ public long allocLimit() {
++ return blockMgr.allocLimit() ;
++ }
++
++ @Override
++ public void resetAlloc(long boundary) {
++ blockMgr.resetAlloc(boundary) ;
++ }
++
++ @Override
++ public void sync() {
++ blockMgr.sync() ;
++ }
++
++ @Override
++ public void syncForce() {
++ blockMgr.syncForce() ;
++ }
++
++ @Override
++ public boolean valid(int id) {
++ return blockMgr.valid(id) ;
++ }
++
++ @Override
++ public boolean isClosed() {
++ return blockMgr.isClosed() ;
++ }
++
++ @Override
++ public void close() {
++ blockMgr.close() ;
++ }
++
++ @Override
++ public void beginRead() {
++ blockMgr.beginRead() ;
++ }
++
++ @Override
++ public void endRead() {
++ blockMgr.endRead() ;
++ }
++
++ @Override
++ public void beginUpdate() {
++ blockMgr.beginUpdate() ;
++ }
++
++ @Override
++ public void endUpdate() {
++ blockMgr.endUpdate() ;
++ }
++
++ @Override
++ public String getLabel() {
++ return blockMgr.getLabel() ;
++ }
++
++ @Override
++ public String toString() {
++ return blockMgr.toString() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockParams.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockParams.java
index 0000000,0000000..28afbfa
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockParams.java
@@@ -1,0 -1,0 +1,26 @@@
++/*
++ * 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.dboe.base.block;
++
++public interface BlockParams {
++ public FileMode getFileMode() ;
++ public Integer getBlockSize() ;
++ public Integer getBlockReadCacheSize() ;
++ public Integer getBlockWriteCacheSize() ;
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockType.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockType.java
index 0000000,0000000..0acc6b1
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/BlockType.java
@@@ -1,0 -1,0 +1,68 @@@
++/*
++ * 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.dboe.base.block;
++
++import org.apache.jena.atlas.io.IndentedWriter ;
++import org.apache.jena.atlas.io.Printable ;
++import org.seaborne.dboe.DBOpEnvException ;
++
++import org.apache.jena.sparql.util.Named ;
++
++public enum BlockType implements Printable, Named
++{
++ // The id should fit into an unsigned byte.
++ FREE(-1, "Free"),
++ BTREE_NODE(5, "BTreeNode") ,
++ BPTREE_BRANCH(6, "BPlusTreeBranch") ,
++ BPTREE_LEAF(7, "BPlusTreeLeaf") ,
++ DICTIONARY(10, "Dictionary") ,
++ RECORD_BLOCK(99, "RecordBlock"),
++ UNDEF(255, "UndefinedBlockType")
++ ;
++
++ private final int id ;
++ private final String name ;
++
++ BlockType(int id, String name)
++ {
++ this.id = id ;
++ this.name = name ;
++
++ }
++
++ @Override
++ public void output(IndentedWriter out)
++ { out.print(getName()) ; }
++
++ final public int id() { return id ; }
++
++ @Override
++ final public String getName() { return name ; }
++
++ @Override public String toString() { return getName() ; }
++
++ public static BlockType extract(int x)
++ {
++ if ( x == BTREE_NODE.id() ) return BTREE_NODE ;
++ if ( x == BPTREE_BRANCH.id() ) return BPTREE_BRANCH ;
++ if ( x == BPTREE_LEAF.id() ) return BPTREE_LEAF ;
++ if ( x == RECORD_BLOCK.id() ) return RECORD_BLOCK ;
++ if ( x == DICTIONARY.id() ) return DICTIONARY ;
++ throw new DBOpEnvException("No known block type for "+x) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/FileMode.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/FileMode.java
index 0000000,0000000..c6531a6
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/block/FileMode.java
@@@ -1,0 -1,0 +1,26 @@@
++/*
++ * 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.dboe.base.block;
++
++public enum FileMode
++{
++ /** Use memory mapped files */
++ mapped,
++ /** Use in-JVM caching */
++ direct ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/buffer/BufferBase.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/buffer/BufferBase.java
index 0000000,0000000..ca170a4
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/buffer/BufferBase.java
@@@ -1,0 -1,0 +1,262 @@@
++/*
++ * 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.dboe.base.buffer;
++
++import static java.lang.String.format ;
++import static org.seaborne.dboe.sys.SystemIndex.FillByte ;
++import static org.seaborne.dboe.sys.Sys.NetworkOrder ;
++import static org.seaborne.dboe.sys.SystemIndex.NullOut ;
++
++import java.nio.ByteBuffer ;
++
++import org.apache.jena.atlas.lib.ByteBufferLib ;
++import org.seaborne.dboe.base.record.RecordException ;
++
++
++/** ByteBuffer specialization - Common operations for RecordBuffer and PtrBuffer */
++abstract class BufferBase
++{
++ public static final boolean CheckBuffer = false ;
++
++ protected ByteBuffer bb ;
++ protected int slotLen ;
++ protected int numSlot ; // Number of records in use
++ protected final int maxSlot ; // Maximum number of records
++
++ protected BufferBase(ByteBuffer bb, int slotLen, int num)
++ {
++ if ( CheckBuffer )
++ {
++ if ( ! bb.order().equals(NetworkOrder) || !bb.hasArray() )
++ throw new RecordException("Duff buffer (byte order is not network order)") ;
++ if ( bb.limit() == 0 )
++ throw new RecordException("Duff buffer (zero length byte buffer)") ;
++ int size = bb.limit() ;
++ int slots = size/slotLen ;
++ if ( size%slotLen != 0 )
++ throw new RecordException(format("Misaligned buffer: size=%d, keyLen=%d",size, slotLen)) ;
++ if ( slots < num )
++ throw new RecordException(format("Wrong size: slots=%d, len=%d", slots, num)) ;
++ }
++ this.bb = bb ;
++ this.slotLen = slotLen ;
++ this.numSlot = num ;
++ this.maxSlot = bb.limit()/slotLen ;
++ if ( ! bb.isReadOnly() && NullOut )
++ clear(numSlot, maxSlot-numSlot) ;
++ }
++
++ // Why so many final methods? This code is performace critical and "final" methods
++ // can be inlined by the JIT - or just not have object dispatch done each time
++ // because the destination is fixed.
++ // (and here - there are quite a few assumed relationships of the ints).
++
++ final
++ public void copy(int srcIdx, BufferBase dst, int dstIdx, int len)
++ {
++ if ( len == 0 )
++ return ;
++
++ // Check end index is inside the buffer.
++ checkBounds(srcIdx+len-1, maxSlot) ;
++
++ BufferBase src = this ; // Clarity
++
++ if ( dst.numSlot < dstIdx-1 )
++ // Allow copy to be just off the end of dst.
++ throw new IllegalArgumentException(format("copy: Out of bounds: dstIdx=%d, dst size=%d", dstIdx, dst.numSlot)) ;
++ if ( src.slotLen != dst.slotLen )
++ throw new RecordException(format("copy: records of differnt sizes: %d, %d",src.slotLen, dst.slotLen)) ;
++
++ // How do we set the numRec in dst? max(dstIdx+len, old count)
++ ByteBufferLib.bbcopy(src.bb, srcIdx, dst.bb, dstIdx, len, slotLen) ;
++ dst.numSlot = Math.max(dstIdx+len, dst.numSlot) ;
++ }
++
++ final
++ public void copyToTop(BufferBase dst)
++ {
++ copy(0, dst, dst.numSlot, numSlot) ; }
++
++ /** Remove top element */
++ final public void removeTop()
++ {
++ if ( numSlot == 0 )
++ throw new IndexOutOfBoundsException("removeTop: empty buffer") ;
++ clear(numSlot-1) ;
++ numSlot-- ;
++ }
++
++ final public void remove(int idx) { shiftDown(idx) ; }
++
++ /** Does not reset the size */
++ final
++ public void clear(int idx, int len)
++ {
++ if ( NullOut )
++ ByteBufferLib.bbfill(bb, idx, (idx+len), FillByte, slotLen) ;
++ }
++
++ /** Does not reset the size */
++ final public void clear() { clear(0, maxSlot) ; numSlot = 0 ; }
++
++ /** Does not reset the size */
++ final public void clear(int idx) { clear(idx, 1) ; }
++
++ /** Is the record at idx set clear or not?
++ This is done without regard to buffer size.
++ Requires NullOut to be accurate.
++ Testing.
++ */
++ final public boolean isClear(int idx)
++ {
++ checkBounds(idx, maxSlot) ;
++ int x = idx*slotLen ;
++ int y = (idx+1)*slotLen ;
++ for ( int i = x ; i < y ; i++ )
++ if ( bb.get(i) != FillByte )
++ {
++// byte b = bb.get(i) ;
++// lib.ByteBufferLib.print(bb) ;
++ return false ;
++ }
++ return true ;
++ }
++
++ final public boolean isFull()
++ {
++ return numSlot >= maxSlot ;
++ }
++
++ final public boolean isEmpty()
++ {
++ return numSlot == 0 ;
++ }
++
++ final public void incSize() { incSize(1) ; }
++ final public void incSize(int n)
++ {
++ if ( numSlot+n > maxSlot )
++ throw new IllegalArgumentException(format("inc(%d): out of range: max=%d", n, maxSlot)) ;
++ numSlot += n ;
++ }
++
++ final public void decSize() { decSize(1) ; }
++ final public void decSize(int n)
++ {
++ if ( numSlot-n < 0 )
++ throw new IllegalArgumentException(format("dec(%d): out of range: max=%d", n, maxSlot)) ;
++ numSlot -= n ;
++ }
++
++ final public int slotLen() { return slotLen ; }
++
++ final public int getSize() { return numSlot ; }
++
++ final public void setSize(int n)
++ {
++ if ( n < 0 || n > maxSlot )
++ throw new IllegalArgumentException(format("size(%d): out of range: max=%d", n, maxSlot)) ;
++ numSlot = n ;
++ }
++
++ final public int size() { return numSlot ; }
++ final public int maxSize() { return maxSlot ; }
++
++ final public void shiftUp(int idx) { shiftUpN(idx, 1) ; }
++ final public void shiftUpN(int idx, int num)
++ {
++ checkBounds(idx, numSlot) ;
++ if ( numSlot + num > maxSlot )
++ throw new IllegalArgumentException(format("Shift up(%d): out of range: len=%d max=%d", num, num, maxSlot)) ;
++
++ ByteBufferLib.bbcopy(bb, idx, idx+num, (numSlot-idx), slotLen) ; // src, dst
++ if ( NullOut )
++ clear(idx, num) ;
++
++ numSlot += num ;
++ }
++
++ final public void shiftDown(int idx) { shiftDownN(idx, 1) ; }
++ final public void shiftDownN(int idx, int num)
++ {
++ checkBounds(idx, numSlot) ;
++ if ( idx+num > numSlot )
++ throw new IllegalArgumentException(format("Shift down(%d,%d): out of range: len=%d", idx, num, num)) ;
++
++ ByteBufferLib.bbcopy(bb, idx+num, idx, (numSlot-num-idx), slotLen) ; // src, dst
++
++ if ( NullOut )
++ clear(numSlot-num, num) ;
++ numSlot -= num ;
++ }
++
++// @Override
++// final public String toString()
++// {
++// StringBuilder str = new StringBuilder() ;
++// str.append(format("Len=%d Count=%d ", bb.limit()/recLen, num)) ;
++//
++// for ( int i = 0 ; i < max*recLen ; i++ )
++// {
++// if ( i != 0 && i%recLen == 0 )
++// str.append(" ") ;
++// byte b = bb.get(i) ;
++// str.append(format("%02x", b)) ;
++// }
++// return str.toString() ;
++// }
++
++ /** Move the element from the high end of this to the low end of other */
++ public void shiftRight(BufferBase other)
++ {
++ if ( other.numSlot >= other.maxSlot )
++ throw new BufferException("No space in destination buffer") ;
++ if ( numSlot <= 0 )
++ throw new BufferException("Empty buffer") ;
++
++ if ( other.numSlot > 0 )
++ other.shiftUp(0) ;
++ else
++ other.numSlot++ ;
++ // Copy high to low slot.
++ ByteBufferLib.bbcopy(bb, (numSlot-1), other.bb, 0, 1, slotLen) ;
++ removeTop() ;
++ }
++
++ /** Move the element from the low end of other to the high end of this */
++ public void shiftLeft(BufferBase other)
++ {
++ if ( numSlot >= maxSlot )
++ throw new BufferException("No space in destination buffer") ;
++ if ( other.numSlot <= 0 )
++ throw new BufferException("Empty buffer") ;
++
++ // Copy low to above high slot.
++ ByteBufferLib.bbcopy(other.bb, 0, bb, numSlot, 1, slotLen) ;
++ // Correct length.
++ numSlot ++ ;
++ other.shiftDown(0) ;
++ }
++
++ final private static void checkBounds(int idx, int len)
++ {
++ if ( idx < 0 || idx >= len )
++ throw new BufferException(format("Out of bounds: idx=%d, size=%d", idx, len)) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/buffer/BufferException.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/buffer/BufferException.java
index 0000000,0000000..ee90872
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/buffer/BufferException.java
@@@ -1,0 -1,0 +1,26 @@@
++/*
++ * 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.dboe.base.buffer;
++
++public class BufferException extends RuntimeException
++{
++ public BufferException() { super() ; }
++ public BufferException(String msg) { super(msg) ; }
++ public BufferException(Throwable th) { super(th) ; }
++ public BufferException(String msg, Throwable th) { super(msg, th) ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/buffer/PtrBuffer.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/buffer/PtrBuffer.java
index 0000000,0000000..0c084fa
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/buffer/PtrBuffer.java
@@@ -1,0 -1,0 +1,124 @@@
++/*
++ * 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.dboe.base.buffer ;
++
++import static java.lang.String.format ;
++
++import java.nio.ByteBuffer ;
++import java.nio.IntBuffer ;
++
++import org.seaborne.dboe.base.record.RecordException ;
++import org.seaborne.dboe.sys.Sys;
++import org.seaborne.dboe.sys.SystemIndex ;
++
++/** An IntBuffer with extra operations */
++
++final public class PtrBuffer extends BufferBase {
++ private IntBuffer iBuff ;
++
++ private PtrBuffer(int maxRec) {
++ this(ByteBuffer.allocate(SystemIndex.SizeOfPointer * maxRec), 0) ;
++ }
++
++ public PtrBuffer(ByteBuffer bb, int num) {
++ super(bb, SystemIndex.SizeOfPointer, num) ;
++ iBuff = bb.asIntBuffer() ;
++
++ if ( CheckBuffer ) {
++ // It is a IntBuffer with associated ByteBuffer
++ if ( iBuff.position() != 0 || bb.order() != Sys.NetworkOrder )
++ throw new RecordException("Duff pointer buffer") ;
++ }
++ }
++
++ public int get(int idx) {
++ checkBounds(idx, numSlot) ;
++ return _get(idx) ;
++ }
++
++ public int getHigh() {
++ if ( numSlot == 0 )
++ throw new IllegalArgumentException("Empty PtrBuffer") ;
++ return _get(numSlot - 1) ;
++ }
++
++ public int getLow() {
++ if ( numSlot == 0 )
++ throw new IllegalArgumentException("Empty PtrBuffer") ;
++ return _get(0) ;
++ }
++
++ public void add(int val) {
++ add(numSlot, val) ;
++ }
++
++ public void add(int idx, int val) {
++ if ( idx != numSlot ) {
++ checkBounds(idx, numSlot) ;
++ shiftUp(idx) ;
++ } else {
++ if ( numSlot >= maxSlot )
++ throw new BufferException(format("Out of bounds: idx=%d, ptrs=%d", idx, maxSlot)) ;
++ numSlot++ ;
++ }
++ // Add right at the top.
++ _set(idx, val) ;
++ }
++
++ public void set(int idx, int val) {
++ checkBounds(idx, numSlot) ;
++ _set(idx, val) ;
++ }
++
++ private final int _get(int idx) {
++ return iBuff.get(idx) ;
++ }
++
++ private final void _set(int idx, int val) {
++ iBuff.put(idx, val) ;
++ }
++
++ @Override
++ public String toString() {
++ StringBuilder str = new StringBuilder() ;
++ str.append(format("Len=%d Max=%d ", numSlot, maxSlot)) ;
++
++ for ( int i = 0 ; i < numSlot ; i++ ) {
++ if ( i != 0 )
++ str.append(" ") ;
++ int x = _get(i) ;
++ str.append(format("%04d", x)) ;
++ }
++ return str.toString() ;
++ }
++
++ private static void checkBounds(int idx, int len) {
++ if ( idx < 0 || idx >= len )
++ throw new BufferException(format("Out of bounds: idx=%d, ptrs=%d", idx, len)) ;
++ }
++
++ /**
++ * A duplicate which does not share anything with the original - for testing
++ */
++ public PtrBuffer duplicate() {
++ PtrBuffer n = new PtrBuffer(maxSlot) ;
++ copy(0, n, 0, maxSlot) ; // numSlot
++ n.numSlot = numSlot ; // Reset
++ return n ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/buffer/RecordBuffer.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/buffer/RecordBuffer.java
index 0000000,0000000..2a715bf
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/buffer/RecordBuffer.java
@@@ -1,0 -1,0 +1,235 @@@
++/*
++ * 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.dboe.base.buffer ;
++
++import static java.lang.String.format ;
++import static org.apache.jena.atlas.lib.Alg.encodeIndex ;
++
++import java.nio.ByteBuffer ;
++import java.util.Iterator ;
++
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.base.record.RecordMapper ;
++
++final public class RecordBuffer extends BufferBase {
++ private RecordFactory factory ;
++
++ // Need own specialized binary search :-(
++
++ public RecordBuffer(RecordFactory recFactory, int maxRec) {
++ this(ByteBuffer.allocate(recFactory.recordLength() * maxRec), recFactory, 0) ;
++ }
++
++ public RecordBuffer(ByteBuffer bb, RecordFactory recFactory, int num) {
++ super(bb, recFactory.recordLength(), num) ;
++ this.factory = recFactory ;
++ }
++
++ public <X> X access(int idx, byte[] key, RecordMapper<X> mapper) {
++ checkBounds(idx, numSlot) ;
++ return _access(idx, key, mapper) ;
++ }
++
++ public Record get(int idx) {
++ checkBounds(idx, numSlot) ;
++ return _get(idx) ;
++ }
++
++ public Record getLow() {
++ if ( numSlot == 0 )
++ throw new IllegalArgumentException("getLow: Empty RecordBuffer") ;
++ return _get(0) ;
++ }
++
++ public Record getHigh() {
++ if ( numSlot == 0 )
++ throw new IllegalArgumentException("getHigh: Empty RecordBuffer") ;
++ return _get(numSlot - 1) ;
++ }
++
++ // Inserts at top.
++ public void add(Record record) {
++ add(numSlot, record) ;
++ }
++
++ // Inserts at slot idx
++ public void add(int idx, Record record) {
++ if ( idx != numSlot ) {
++ checkBounds(idx, numSlot) ;
++ shiftUp(idx) ; // Changes count.
++ } else {
++ if ( numSlot >= maxSlot )
++ throw new BufferException(format("Out of bounds: idx=%d, ptrs=%d", idx, maxSlot)) ;
++ numSlot++ ;
++ }
++ _set(idx, record) ;
++ }
++
++ // Overwrites the contents of slot idx
++ public void set(int idx, Record record) {
++ if ( idx == numSlot ) {
++ add(idx, record) ;
++ return ;
++ } else
++ checkBounds(idx, numSlot) ;
++ _set(idx, record) ;
++ }
++
++ // No checking bound : careful use only!
++
++ public <X> X _access(int idx, byte[] key, RecordMapper<X> mapper) {
++ return factory.access(bb, idx, key, mapper) ;
++ }
++
++ public Record _get(int idx) {
++ return factory.buildFrom(bb, idx) ;
++ }
++
++ // No bounds checking : careful use only!
++ void _set(int idx, Record rec) {
++ factory.insertInto(rec, bb, idx) ;
++ }
++
++ // Linear search for testing.
++ int find1(byte[] data) {
++ for ( int i = 0 ; i < numSlot ; i++ ) {
++ int x = compare(i, data) ;
++ if ( x == 0 )
++ return i ;
++ if ( x > 0 )
++ return encodeIndex(i) ;
++ }
++ return encodeIndex(numSlot) ;
++ }
++
++ // Binary search
++ public int find(Record k) {
++ return find(k, 0, numSlot) ;
++ }
++
++ public Iterator<Record> iterator() {
++ return new RecordBufferIterator(this) ;
++ }
++
++ /** Iterator over a range from min (inclusive) to max(exclusive) */
++ public Iterator<Record> iterator(Record min, Record max) {
++ return new RecordBufferIterator(this, min, max) ;
++ }
++
++ public Record findGet(Record k) {
++ int x = find(k) ;
++ if ( x >= 0 )
++ return get(x) ;
++ return null ;
++ }
++
++ /** return true is removed anything */
++ public boolean removeByKey(Record k) {
++ int x = find(k) ;
++ if ( x < 0 )
++ return false ;
++ super.remove(x) ;
++ return true ;
++ }
++
++ /** Search for key in range fromIndex (inclusive) to toIndex (exclusive) */
++ public int find(Record rec, int fromIndex, int toIndex) {
++ int low = fromIndex ;
++ int high = toIndex - 1 ;
++
++ byte[] key = rec.getKey() ;
++ // http://en.wikipedia.org/wiki/Binary_search
++
++ while (low <= high) {
++ int mid = (low + high) >>> 1 ; // int divide by 2
++
++ int x = compare(mid, key) ;
++ // System.out.printf("Compare: %d(%s) %s ==> %d\n", mid,
++ // Record.str(get(mid)), Record.str(data), x) ;
++
++ if ( x < 0 )
++ low = mid + 1 ;
++ else if ( x > 0 )
++ high = mid - 1 ;
++ else
++ return mid ;
++ }
++ // On exit, when not finding, low is the least value
++ // above, including off the end of the array.
++ return encodeIndex(low) ;
++ }
++
++ // Record compareByKey except we avoid touching bytes by exiting as soon as
++ // possible.
++ // No record created as would be by using
++ // compareByKey(RecordBuffer.get(idx), record)
++ // Compare the slot at idx with value.
++ private int compare(int idx, byte[] value) {
++ idx = idx * slotLen ;
++
++ for ( int i = 0 ; i < value.length ; i++ ) {
++ byte b1 = bb.get(idx + i) ;
++ byte b2 = value[i] ;
++ if ( b1 == b2 )
++ continue ;
++ return (b1 & 0xFF) - (b2 & 0xFF) ;
++ }
++ return 0 ;
++ }
++
++ @Override
++ public String toString() {
++ StringBuilder str = new StringBuilder(40000) ;
++ str.append(format("Len=%d Max=%d: ", numSlot, bb.limit() / slotLen)) ;
++
++ // Print active slots as records.
++ for ( int i = 0 ; i < numSlot ; i++ ) {
++ if ( i != 0 )
++ str.append(" ") ;
++ Record r = _get(i) ;
++ str.append(r.toString()) ;
++ }
++
++ // // Print empty slots
++ // for ( int i = numSlot*slotLen ; i < maxSlot*slotLen ; i++ )
++ // {
++ // if ( i != 0 && i%slotLen == 0 )
++ // str.append(" ") ;
++ // byte b = bb.get(i) ;
++ // str.append(format("%02x", b)) ;
++ // }
++ String s = str.toString() ;
++ return s ;
++ }
++
++ private static void checkBounds(int idx, int len) {
++ if ( idx < 0 || idx >= len )
++ throw new IllegalArgumentException(format("Out of bounds: idx=%d, size=%d", idx, len)) ;
++ }
++
++ /**
++ * A duplicate which does not share anything with the original - for testing
++ */
++ public RecordBuffer duplicate() {
++ RecordBuffer n = new RecordBuffer(factory, maxSlot) ;
++ copy(0, n, 0, maxSlot) ; // numSlot
++ n.numSlot = numSlot ; // reset the allocated length
++ return n ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/buffer/RecordBufferIterator.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/buffer/RecordBufferIterator.java
index 0000000,0000000..bef7a7a
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/buffer/RecordBufferIterator.java
@@@ -1,0 -1,0 +1,97 @@@
++/*
++ * 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.dboe.base.buffer;
++
++import static org.apache.jena.atlas.lib.Alg.decodeIndex ;
++
++import java.util.Iterator;
++import java.util.NoSuchElementException;
++
++import org.seaborne.dboe.base.record.Record ;
++
++public class RecordBufferIterator implements Iterator<Record>
++{
++ private RecordBuffer rBuff ;
++ private int nextIdx ;
++ private Record slot = null ;
++ private final Record maxRec ;
++ private final Record minRec ;
++
++ RecordBufferIterator(RecordBuffer rBuff)
++ { this(rBuff, null, null); }
++
++ RecordBufferIterator(RecordBuffer rBuff, Record minRecord, Record maxRecord)
++ {
++ this.rBuff = rBuff ;
++ nextIdx = 0 ;
++ minRec = minRecord ;
++ if ( minRec != null )
++ {
++ nextIdx = rBuff.find(minRec) ;
++ if ( nextIdx < 0 )
++ nextIdx = decodeIndex(nextIdx) ;
++ }
++
++ maxRec = maxRecord ;
++ }
++
++ private void finish()
++ {
++ rBuff = null ;
++ nextIdx = -99 ;
++ slot = null ;
++ }
++
++ @Override
++ public boolean hasNext()
++ {
++ if ( slot != null )
++ return true ;
++ if ( nextIdx < 0 )
++ return false ;
++ if ( nextIdx >= rBuff.size() )
++ {
++ finish() ;
++ return false ;
++ }
++
++ slot = rBuff.get(nextIdx) ;
++ if ( maxRec != null && Record.keyGE(slot, maxRec) )
++ {
++ // Finished - now to large
++ finish() ;
++ return false ;
++ }
++ nextIdx ++ ;
++ return true ;
++ }
++
++ @Override
++ public Record next()
++ {
++ if ( ! hasNext() )
++ throw new NoSuchElementException("RecordBufferIterator") ;
++ Record r = slot ;
++ slot = null ;
++ return r ;
++ }
++
++ @Override
++ public void remove()
++ { throw new UnsupportedOperationException("RecordBufferIterator.remove") ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/AlreadyLocked.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/AlreadyLocked.java
index 0000000,0000000..dfe4125
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/AlreadyLocked.java
@@@ -1,0 -1,0 +1,29 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.seaborne.dboe.DBOpEnvException;
++
++/** Exception throws when an attempt to take a {@link ProcessFileLock}
++ * with a call of {@link ProcessFileLock#lockEx}
++ * is made and the lock is already held.
++ */
++public class AlreadyLocked extends DBOpEnvException {
++ public AlreadyLocked(String msg) { super(msg); }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFile.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFile.java
index 0000000,0000000..3d9772c
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFile.java
@@@ -1,0 -1,0 +1,99 @@@
++/*
++ * 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.dboe.base.file;
++
++import java.io.RandomAccessFile ;
++
++import org.apache.jena.atlas.lib.Closeable ;
++import org.apache.jena.atlas.lib.Sync ;
++
++/** An append-only, read-anywhere, binary file.
++ * A {@code BinaryDataFile} does not record the length and assumes the
++ * entries are self-defining.
++ *
++ * @see RandomAccessFile
++ */
++public interface BinaryDataFile extends Closeable, Sync {
++ // What about java.nio.channels.FileChannel?
++ // On OpenJDK, RandomAccessFile and FileChannelImpl both dive into native code.
++ //
++ // The choice seems to come down to ByteBuffers vs byte[]
++ // which in turn is a small/large data (scattered data)
++ // issue. We are currently expecting small(er) I/O so byte[]
++ // and being like Thrift is better.
++
++ // byte[] vs ByteBuffer
++
++ /** Open the file */
++ public void open() ;
++
++ /** Is it open? */
++ public boolean isOpen() ;
++
++ /** Read into a byte array, returning the number of bytes read.
++ * Reads are at an absolute position and a read is atomic/thread-safe.
++ *
++ * @param posn Location of the read operation.
++ * @param b byte array
++ *
++ * @return The number of bytes read
++ */
++ public default int read(long posn, byte b[]) {
++ return read(posn, b, 0, b.length);
++ }
++
++ /** Read into a byte array, returning the number of bytes read.
++ * Reads are at an absolute position and a read is atomic/thread-safe.
++ *
++ * @param posn Location of the read operation.
++ * @param b
++ * @param start of bytesarray to read into
++ * @param length Maximum number of bytes to read.
++ * @return The number of bytes read
++ */
++
++ public int read(long posn, byte b[], int start, int length) ;
++
++ /** Write bytes - bytes are always written to the end of the file.
++ * Return the location where the write started.
++ */
++ public default long write(byte b[]) {
++ return write(b, 0, b.length) ;
++ }
++
++ /** Write bytes - bytes are always written to the end of the file.
++ * Return the location where the write started.
++ */
++ public long write(byte b[], int start, int length) ;
++
++ /** Return the length of the file (including any buffered writes) */
++ public long length() ;
++
++ /** Truncate the file */
++ public void truncate(long length) ;
++
++ /** Return whether this is an empty file or not */
++ public default boolean isEmpty() { return length() == 0 ; }
++
++ @Override
++ public void sync() ;
++
++ @Override
++ public void close() ;
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFileMem.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFileMem.java
index 0000000,0000000..17513a8
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFileMem.java
@@@ -1,0 -1,0 +1,114 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.apache.jena.atlas.RuntimeIOException ;
++import org.apache.jena.atlas.io.IO ;
++
++/** Implementation of {@link BinaryDataFile} in memory for testing
++ * and development use. Raw performance is not an objective.
++ *
++ * <li>This implementation is thread-safe.
++ */
++public class BinaryDataFileMem implements BinaryDataFile {
++
++ private boolean readMode ;
++ private SegmentedMemBuffer storage ;
++
++ public BinaryDataFileMem() {
++ }
++
++ @Override
++ synchronized
++ public void open() {
++ if ( storage != null )
++ throw new RuntimeIOException("Already open") ;
++ storage = new SegmentedMemBuffer() ;
++ readMode = true ;
++ }
++
++ @Override
++ synchronized
++ public boolean isOpen() {
++ return storage != null ;
++ }
++
++ @Override
++ synchronized
++ public int read(long posn, byte[] b, int start, int length) {
++ checkOpen() ;
++ switchToReadMode() ;
++ return storage.read(posn, b, start, length) ;
++ }
++
++ @Override
++ synchronized
++ public long write(byte[] b, int start, int length) {
++ checkOpen() ;
++ switchToWriteMode() ;
++ long x = storage.length() ;
++ storage.write(x, b, start, length) ;
++ return x ;
++ }
++
++ @Override
++ synchronized
++ public void truncate(long length) {
++ if ( length < 0 )
++ IO.exception(String.format("truncate: bad length : %d", length)) ;
++ checkOpen() ;
++ switchToWriteMode() ;
++ storage.truncate(length);
++ }
++
++ @Override
++ synchronized
++ public void sync() {
++ checkOpen() ;
++ storage.sync();
++ }
++
++ @Override
++ synchronized
++ public void close() {
++ if ( ! isOpen() )
++ return ;
++ storage.close();
++ storage = null ;
++ }
++
++ @Override
++ synchronized
++ public long length() {
++ return storage.length() ;
++ }
++
++ private void switchToReadMode() {
++ readMode = true ;
++ }
++
++ private void switchToWriteMode() {
++ readMode = false ;
++ }
++
++ private void checkOpen() {
++ if ( ! isOpen() )
++ throw new RuntimeIOException("Not open") ;
++ }
++}
++
[14/50] [abbrv] jena git commit: IteratorCheckNotConcurrent
Posted by an...@apache.org.
IteratorCheckNotConcurrent
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/ef68a8d6
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/ef68a8d6
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/ef68a8d6
Branch: refs/heads/jena-tdb2
Commit: ef68a8d694269931935b32efc058060286e689b3
Parents: 982c0c7
Author: Andy Seaborne <an...@seaborne.org>
Authored: Mon Sep 4 10:41:23 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Mon Sep 4 10:41:23 2017 +0100
----------------------------------------------------------------------
.../tdb2/store/IteratorCheckNotConcurrent.java | 93 ++++++++++++++++++++
.../org/seaborne/tdb2/store/TripleTable.java | 3 +-
2 files changed, 94 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/ef68a8d6/tdb2/src/main/java/org/seaborne/tdb2/store/IteratorCheckNotConcurrent.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/IteratorCheckNotConcurrent.java b/tdb2/src/main/java/org/seaborne/tdb2/store/IteratorCheckNotConcurrent.java
new file mode 100644
index 0000000..0aa4182
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/IteratorCheckNotConcurrent.java
@@ -0,0 +1,93 @@
+/*
+ * 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.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 ;
+
+/** Wrapper to check an iterator has not been used across some write operation. */
+class IteratorCheckNotConcurrent<T> implements Iterator<T>, Closeable
+{
+ private Iterator<T> iter ;
+ private AtomicLong eCount ; // Needs fixing to be per thera in some way - either from the caller or here.
+ 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)) ;
+ }
+ }
+
+ private static void policyError(String message) {
+ throw new ConcurrentModificationException(message) ;
+ }
+
+ @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() ;
+ // Reset the epoch.
+ startEpoch = eCount.get() ;
+ }
+
+ @Override
+ public void close() {
+ finished = true ;
+ Iter.close(iter) ;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/jena/blob/ef68a8d6/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 a85494b..54dcac3 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/TripleTable.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/TripleTable.java
@@ -30,8 +30,7 @@ import org.seaborne.tdb2.store.tupletable.TupleIndex ;
/**
* TripleTable - a collection of TupleIndexes for 3-tuples together with a node
* table. Normally, based on 3 indexes (SPO, POS, OSP) but other indexing
- * structures can be configured. The node table form can map to and from NodeIds
- * (longs)
+ * structures can be configured.
*/
public class TripleTable extends TableBase {
[07/50] [abbrv] jena git commit: Note about gpg and SHA512
Posted by an...@apache.org.
Note about gpg and SHA512
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/0d5a4688
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/0d5a4688
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/0d5a4688
Branch: refs/heads/jena-tdb2
Commit: 0d5a46884e21f807f2433947da5890191d07bbd8
Parents: 218d10c
Author: Andy Seaborne <an...@seaborne.org>
Authored: Sat Sep 2 18:40:46 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Sat Sep 2 18:40:46 2017 +0100
----------------------------------------------------------------------
pom.xml | 8 ++++++++
1 file changed, 8 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/0d5a4688/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 77a2033..af22a7d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -350,6 +350,14 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
+ <!-- Does this interfer with external -Darguments=-Dgpg.keyname=
+ i.e. is it additive?
+ <configuration>
+ <gpgArguments>
+ <arg>- -digest-algo=SHA512</arg> <comment fix
+ </gpgArguments>
+ </configuration>
+ -->
<executions>
<execution>
<id>sign-artifacts</id>
[02/50] [abbrv] jena git commit: Switchable conatiner datasets
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
new file mode 100644
index 0000000..8a375b9
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
@@ -0,0 +1,261 @@
+/*
+ * 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.BufferedOutputStream ;
+import java.io.IOException ;
+import java.io.OutputStream ;
+import java.nio.file.* ;
+import java.util.List;
+import java.util.zip.GZIPOutputStream ;
+
+import org.apache.jena.atlas.RuntimeIOException ;
+import org.apache.jena.atlas.lib.DateTimeUtils ;
+import org.apache.jena.atlas.logging.Log;
+import org.apache.jena.riot.Lang ;
+import org.apache.jena.riot.RDFDataMgr ;
+import org.apache.jena.sparql.core.DatasetGraph;
+import org.seaborne.dboe.base.file.Location;
+import org.seaborne.dboe.jenax.Txn ;
+import org.seaborne.dboe.transaction.txn.TransactionCoordinator;
+import org.seaborne.dboe.transaction.txn.TransactionalSystem;
+import org.seaborne.tdb2.TDBException;
+import org.seaborne.tdb2.repack.DatasetGraphSwitchable ;
+import org.seaborne.tdb2.repack.sys.CopyDSG;
+import org.seaborne.tdb2.repack.sys.FilenameUtils;
+import org.seaborne.tdb2.repack.sys.Util;
+import org.seaborne.tdb2.setup.StoreParams;
+import org.seaborne.tdb2.store.DatasetGraphTDB;
+
+/** Operations on and about TDB2 databases.
+ * <p>
+ * TDB2 uses a hierarchical structure to manage on disk.
+ * <p>
+ * If in-memory (non-scalable, not-performant, perfect simulation for functionality using a RAM disk, for testing mainly),
+ * then the switchable layer is just a covenience. DatasetGrapOps such as {@link #compact}
+ * and {@link #backup} do not apply.
+ * <p>
+ * Directory and files on disk:
+ * <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 Backups/} -- backups.
+ * <li> External indexes like {@code TextIndex/} -- the text index only applies to the current, latest database.
+ * </ul>
+ */
+public class DatabaseOps {
+ private static final String dbPrefix = "Data";
+ private static final String SEP = "-";
+ private static final String startCount = "0001";
+
+ private static final String BACKUPS_DIR = "Backups";
+ // Basename of the backup file. "backup_{DateTime}.nq.gz
+ private static final String BACKUPS_FN = "backup";
+
+ /*package*/ static DatasetGraph create(Location location) {
+ // Hide implementation class.
+ return createSwitchable(location);
+ }
+
+ /** Create a fresh database - called by {@code DatabaseMgr}.
+ * It is important to go via {@code DatabaseMgr} to avoid
+ * duplicate {@code DatasetGraphSwitchable}s for the same location.
+ */
+ private static DatasetGraphSwitchable createSwitchable(Location location) {
+ if ( location.isMem() ) {
+ DatasetGraph dsg = StoreConnection.connectCreate(location).getDatasetGraph();
+ return new DatasetGraphSwitchable(null, dsg);
+ }
+ // 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();
+ DatasetGraphSwitchable appDSG = new DatasetGraphSwitchable(path, dsg);
+ return appDSG;
+ }
+
+ public static void backup(DatasetGraphSwitchable container) {
+ checkSupportsAdmin(container);
+ Path dbPath = container.getContainerPath();
+ Path backupDir = dbPath.resolve(BACKUPS_DIR);
+ if ( ! Files.exists(backupDir) )
+ IOX.createDirectory(backupDir);
+
+ DatasetGraph dsg = container;
+
+// // Per backup source lock.
+// synchronized(activeBackups) {
+// // Atomically check-and-set
+// if ( activeBackups.contains(dsg) )
+// Log.warn(Fuseki.serverLog, "Backup already in progress") ;
+// activeBackups.add(dsg) ;
+// }
+
+ try (OutputStream out2 = openUniqueFileForWriting(backupDir, BACKUPS_FN, "nq.gz");
+ OutputStream out1 = new GZIPOutputStream(out2, 8 * 1024) ;
+ OutputStream out = new BufferedOutputStream(out1)) {
+ Txn.executeRead(dsg, ()->RDFDataMgr.write(out, dsg, Lang.NQUADS));
+ } catch (IOException e) {
+ throw IOX.exception(e) ;
+ } finally {
+ }
+ }
+
+ private static void checkSupportsAdmin(DatasetGraphSwitchable container) {
+ if ( ! container.hasContainerPath() )
+ throw new TDBException("Dataset does not support admin operations");
+ }
+
+ //private static void logWarn(String msg) {}
+
+
+ // --> IOX
+ private static OutputStream openUniqueFileForWriting(Path dirPath, String basename, String ext) {
+ if ( ! Files.isDirectory(dirPath) )
+ throw new IllegalArgumentException("Not a directory: "+dirPath);
+ if ( basename.contains("/") || basename.contains("\\") )
+ throw new IllegalArgumentException("Basename must not contain a file path separator (\"/\" or \"\\\")");
+
+ String timestamp = DateTimeUtils.nowAsString("yyyy-MM-dd_HH:mm:ss") ;
+ String filename = basename + "_" + timestamp ;
+ Path p = dirPath.resolve(filename+"."+ext);
+ int x = 0 ;
+ for(;;) {
+ try {
+ return Files.newOutputStream(p, StandardOpenOption.CREATE_NEW);
+ } catch (AccessDeniedException ex) {
+ throw IOX.exception("Access denied", ex);
+ } catch (FileAlreadyExistsException ex) {
+ // Drop through and try again.
+ } catch (IOException ex) {
+ throw IOX.exception(ex) ;
+ }
+ // Try again.
+ x++;
+ if ( x >= 5 )
+ throw new RuntimeIOException("Can't create the unique name: number of attempts exceeded");
+ p = dirPath.resolve(filename+"_"+x+"."+ext);
+ }
+ }
+
+
+ // JVM-wide :-(
+ private static Object compactionLock = new Object();
+
+ public static void compact(DatasetGraphSwitchable container) {
+ checkSupportsAdmin(container);
+ synchronized(compactionLock) {
+ Path base = container.getContainerPath();
+ Path db1 = findLocation(base, dbPrefix);
+ Location loc1 = IOX.asLocation(db1);
+
+ // -- Checks
+ Location loc1a = ((DatasetGraphTDB)container.get()).getLocation();
+ if ( loc1a.isMem() ) {}
+ if ( ! loc1a.exists() )
+ throw new TDBException("No such location: "+loc1a);
+
+ // Is this the same database location?
+ if ( ! loc1.equals(loc1a) )
+ throw new TDBException("Inconsistent (not latested?) : "+loc1a+" : "+loc1);
+ // -- Checks
+
+ // 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 dsgCurrent = (DatasetGraphTDB)container.get();
+ if ( ! dsgCurrent.getLocation().equals(loc1) )
+ throw new TDBException("Inconsistent locations for base : "+dsgCurrent.getLocation()+" , "+dsgCurrent.getLocation());
+
+ DatasetGraphTDB dsgBase = srcConn.getDatasetGraphTDB();
+ if ( dsgBase != dsgCurrent )
+ throw new TDBException("Inconsistent datasets : "+dsgCurrent.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.tryBlockWriters();
+ // txnMgr.begin(WRITE, false) will now bounce.
+
+ // 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.
+ if ( ! container.change(dsgCurrent, dsgCompact) ) {
+ Log.warn(DatabaseOps.class, "Inconistent: old datasetgraph not as expected");
+ 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/sys/DatasetControl.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControl.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControl.java
deleted file mode 100644
index e389e52..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControl.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.sys;
-
-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();
-
- /** Notify 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/sys/DatasetControlMRSW.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControlMRSW.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControlMRSW.java
deleted file mode 100644
index 518bb6e..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControlMRSW.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * 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.sys;
-
-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 checkCourrentModification() {
- if ( finished )
- return ;
-
- long now = eCount.get() ;
- if ( now != startEpoch ) {
- policyError(format("Iterator: started at %d, now %d", startEpoch, now)) ;
-
- }
- }
-
- @Override
- public boolean hasNext() {
- checkCourrentModification() ;
- boolean b = iter.hasNext() ;
- if ( !b )
- close() ;
- return b ;
- }
-
- @Override
- public T next() {
- checkCourrentModification() ;
- try { return iter.next() ; }
- catch (NoSuchElementException ex) {
- close() ;
- throw ex ;
- }
- }
-
- @Override
- public void remove() {
- checkCourrentModification() ;
- 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/sys/DatasetControlMutable.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControlMutable.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControlMutable.java
deleted file mode 100644
index cfce6e7..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControlMutable.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.sys ;
-
-import java.util.Iterator ;
-
-/** A DatasetControl tat is an indirection to another and can be changed */
-public class DatasetControlMutable implements DatasetControl {
- private DatasetControl other ;
-
- public DatasetControlMutable(DatasetControl control) { set(control) ; }
-
- public void set(DatasetControl newOther) { other = newOther ; }
-
- @Override
- public void startUpdate() {
- other.startUpdate() ;
- }
-
- @Override
- public void finishUpdate() {
- other.finishUpdate() ;
- }
-
- @Override
- public void startRead() {
- other.startRead() ;
- }
-
- @Override
- public void finishRead() {
- other.finishUpdate() ;
- }
-
- @Override
- public <T> Iterator<T> iteratorControl(Iterator<T> iter) {
- return other.iteratorControl(iter) ;
- }
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControlNone.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControlNone.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControlNone.java
deleted file mode 100644
index 8206574..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControlNone.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.sys;
-
-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/sys/DatasetControlReadOnly.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControlReadOnly.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControlReadOnly.java
deleted file mode 100644
index 0bde32e..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatasetControlReadOnly.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.sys;
-
-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/sys/IOX.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/IOX.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/IOX.java
new file mode 100644
index 0000000..049fbb3
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/IOX.java
@@ -0,0 +1,293 @@
+/*
+ * 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.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.seaborne.tdb2.repack.sys.Util ;
+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);
+ }
+
+ /** Convert an {@link IOException} into a {@link RuntimeIOException}.
+ * <p>
+ * Idiom:
+ * <pre>
+ * catch(IOException ex) { throw new exception("Oh dear", ex); }
+ * </pre>
+ * @param message
+ * @param ioException
+ * @return RuntimeIOException
+ */
+ public static RuntimeIOException exception(String message, IOException ioException) {
+ return new RuntimeIOException(message, 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/test/java/org/seaborne/tdb2/TestTDBFactory.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java b/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
index 8805bbc..fd6ba1c 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
@@ -37,35 +37,35 @@ public class TestTDBFactory extends BaseTest
static Quad quad1 = SSE.parseQuad("(_ <s> <p> 1)") ;
static Quad quad2 = SSE.parseQuad("(_ <s> <p> 1)") ;
- @Before public void before()
- {
- FileOps.clearDirectory(DIRx) ;
+ @Before
+ public void before() {
+ FileOps.clearDirectory(DIRx) ;
}
-
- @After public void after()
- {
- FileOps.clearDirectory(DIRx) ;
+
+ @After
+ public void after() {
+ FileOps.clearDirectory(DIRx) ;
}
-
- @Test public void testTDBFactory1()
- {
+
+ @Test
+ public void testTDBFactory1() {
StoreConnection.reset() ;
- DatasetGraph dg1 = TDB2Factory.connectDatasetGraph(Location.mem("FOO")) ;
- DatasetGraph dg2 = TDB2Factory.connectDatasetGraph(Location.mem("FOO")) ;
+ DatasetGraph dg1 = DatabaseMgr.connectDatasetGraph(Location.mem("FOO")) ;
+ DatasetGraph dg2 = DatabaseMgr.connectDatasetGraph(Location.mem("FOO")) ;
Txn.executeWrite(dg1, ()->{
- dg1.add(quad1) ;
+ dg1.add(quad1) ;
}) ;
Txn.executeRead(dg2, ()->{
assertTrue(dg2.contains(quad1)) ;
}) ;
}
- @Test public void testTDBFactory2()
- {
+ @Test
+ public void testTDBFactory2() {
StoreConnection.reset() ;
// The unnamed location is unique each time.
- DatasetGraph dg1 = TDB2Factory.connectDatasetGraph(Location.mem()) ;
- DatasetGraph dg2 = TDB2Factory.connectDatasetGraph(Location.mem()) ;
+ DatasetGraph dg1 = DatabaseMgr.connectDatasetGraph(Location.mem()) ;
+ DatasetGraph dg2 = DatabaseMgr.connectDatasetGraph(Location.mem()) ;
Txn.executeWrite(dg1, ()->{
dg1.add(quad1) ;
}) ;
@@ -74,16 +74,17 @@ public class TestTDBFactory extends BaseTest
}) ;
}
- @Test public void testStoreConnectionTxn1()
- {
+
+ @Test
+ public void testStoreConnectionTxn1() {
StoreConnection.reset() ;
DatasetGraph dg1 = StoreConnection.connectCreate(DIR).getDatasetGraph() ;
DatasetGraph dg2 = StoreConnection.connectCreate(DIR).getDatasetGraph() ;
assertSame(dg1, dg2) ;
}
- @Test public void testStoreConnectionTxn2()
- {
+ @Test
+ public void testStoreConnectionTxn2() {
// Named memory locations
StoreConnection.reset() ;
DatasetGraph dg1 = StoreConnection.connectCreate(Location.mem("FOO")).getDatasetGraph() ;
@@ -92,8 +93,8 @@ public class TestTDBFactory extends BaseTest
assertSame(dg1, dg2) ;
}
- @Test public void testStoreConnectionTxn3()
- {
+ @Test
+ public void testStoreConnectionTxn3() {
// Un-named memory locations
StoreConnection.reset() ;
DatasetGraph dg1 = StoreConnection.connectCreate(Location.mem()).getDatasetGraph() ;
@@ -102,4 +103,19 @@ public class TestTDBFactory extends BaseTest
assertNotSame(dg1, dg2) ;
}
+ @Test
+ public void testTDBFactoryDisk() {
+ StoreConnection.reset() ;
+ // The named disk location
+ Location loc = DIR;
+ DatasetGraph dg1 = DatabaseMgr.connectDatasetGraph(loc) ;
+ DatasetGraph dg2 = DatabaseMgr.connectDatasetGraph(Location.create(loc.getDirectoryPath()));
+ assertSame(dg1, dg2) ;
+ Txn.executeWrite(dg1, ()->{
+ dg1.add(quad1) ;
+ }) ;
+ Txn.executeRead(dg2, ()->{
+ assertTrue(dg2.contains(quad1)) ;
+ }) ;
+ }
}
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java b/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
index ad1f452..47ee5d0 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
@@ -23,6 +23,7 @@ import org.apache.jena.query.Dataset ;
import org.apache.jena.sparql.core.DatasetGraph ;
import org.seaborne.dboe.base.file.Location ;
import org.seaborne.tdb2.ConfigTest ;
+import org.seaborne.tdb2.DatabaseMgr ;
import org.seaborne.tdb2.TDB2Factory ;
import org.seaborne.tdb2.sys.StoreConnection ;
import org.seaborne.tdb2.sys.SystemTDB ;
@@ -76,7 +77,7 @@ public class TL {
}
public static DatasetGraph createTestDatasetGraphMem() {
- DatasetGraph dataset = TDB2Factory.createDatasetGraph() ;
+ DatasetGraph dataset = DatabaseMgr.createDatasetGraph() ;
// Non-transactional tests
dataset = SystemTDB.setNonTransactional(dataset) ;
return dataset ;
http://git-wip-us.apache.org/repos/asf/jena/blob/d72f6961/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransPromoteTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransPromoteTDB.java b/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransPromoteTDB.java
index 9976f78..2814f32 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransPromoteTDB.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransPromoteTDB.java
@@ -23,7 +23,7 @@ import org.apache.log4j.Logger;
import org.seaborne.dboe.transaction.txn.Transaction;
import org.seaborne.dboe.transaction.txn.TransactionCoordinator;
import org.seaborne.dboe.transaction.txn.TransactionException;
-import org.seaborne.tdb2.TDB2Factory;
+import org.seaborne.tdb2.DatabaseMgr ;
public class TestTransPromoteTDB extends AbstractTestTransPromoteTDB2 {
@@ -62,7 +62,7 @@ public class TestTransPromoteTDB extends AbstractTestTransPromoteTDB2 {
@Override
protected DatasetGraph create() {
- return TDB2Factory.createDatasetGraph();
+ return DatabaseMgr.createDatasetGraph();
}
@Override
[06/50] [abbrv] jena git commit: Migrate tests to
DatasetGraphSwitchable
Posted by an...@apache.org.
Migrate tests to DatasetGraphSwitchable
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/218d10c5
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/218d10c5
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/218d10c5
Branch: refs/heads/jena-tdb2
Commit: 218d10c5010f670566bd33cb49503370834388bd
Parents: 780d671
Author: Andy Seaborne <an...@seaborne.org>
Authored: Sat Sep 2 18:21:59 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Sat Sep 2 18:40:31 2017 +0100
----------------------------------------------------------------------
.../java/org/seaborne/tdb2/DatabaseMgr.java | 18 +-
tdb2/src/main/java/org/seaborne/tdb2/TDB2.java | 8 +-
.../tdb2/repack/DatasetGraphRecorder.java | 53 -----
.../tdb2/repack/DatasetGraphSwitchable.java | 214 -------------------
.../org/seaborne/tdb2/repack/sys/CopyDSG.java | 53 -----
.../seaborne/tdb2/repack/sys/FilenameUtils.java | 102 ---------
.../java/org/seaborne/tdb2/repack/sys/Util.java | 49 -----
.../seaborne/tdb2/solver/QueryEngineTDB.java | 24 +--
.../tdb2/store/DatasetGraphSwitchable.java | 197 +++++++++++++++++
.../seaborne/tdb2/store/DatasetGraphTxn.java | 2 +-
.../tdb2/store/DatasetGraphWrapperTxn.java | 34 +++
.../tdb2/store/GraphViewSwitchable.java | 139 ++++++++++++
.../java/org/seaborne/tdb2/sys/CopyDSG.java | 53 +++++
.../seaborne/tdb2/sys/DatabaseConnection.java | 16 +-
.../java/org/seaborne/tdb2/sys/DatabaseOps.java | 5 +-
.../org/seaborne/tdb2/sys/FilenameUtils.java | 102 +++++++++
.../main/java/org/seaborne/tdb2/sys/IOX.java | 1 -
.../org/seaborne/tdb2/sys/StoreConnection.java | 14 +-
.../java/org/seaborne/tdb2/sys/TDBInternal.java | 56 ++++-
.../main/java/org/seaborne/tdb2/sys/Util.java | 49 +++++
.../src/test/java/org/seaborne/tdb2/TC_TDB.java | 2 +-
.../test/java/org/seaborne/tdb2/TS_Factory.java | 3 -
.../seaborne/tdb2/TestDatabaseConnection.java | 68 ------
.../java/org/seaborne/tdb2/TestDatabaseMgr.java | 8 +-
.../java/org/seaborne/tdb2/TestDatabaseOps.java | 114 ----------
.../java/org/seaborne/tdb2/TestTDBFactory.java | 16 +-
.../tdb2/assembler/TestTDBAssembler.java | 31 ++-
.../tdb2/graph/TestPrefixMappingTDB.java | 8 +-
.../test/java/org/seaborne/tdb2/junit/TL.java | 8 +-
.../tdb2/setup/TestStoreParamsCreate.java | 12 +-
.../org/seaborne/tdb2/solver/TestStats.java | 3 +-
.../AbstractTestStoreConnectionBasics.java | 6 +-
.../tdb2/store/TestDatasetTDBPersist.java | 11 +-
.../seaborne/tdb2/store/TestTransactions.java | 7 +-
.../test/java/org/seaborne/tdb2/sys/TS_Sys.java | 10 +-
.../tdb2/sys/TestDatabaseConnection.java | 69 ++++++
.../org/seaborne/tdb2/sys/TestDatabaseOps.java | 117 ++++++++++
37 files changed, 913 insertions(+), 769 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/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
index 7b3ff17..b4dfd23 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/DatabaseMgr.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/DatabaseMgr.java
@@ -21,10 +21,11 @@ package org.seaborne.tdb2;
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.DatasetGraphSwitchable ;
import org.seaborne.tdb2.store.DatasetGraphTDB ;
import org.seaborne.tdb2.sys.DatabaseConnection ;
import org.seaborne.tdb2.sys.DatabaseOps ;
+import org.seaborne.tdb2.sys.TDBInternal ;
/** Operations for TDBS DatasetGraph, including admin operations
* See {@link TDB2Factory} for creating API-level {@link Dataset Datasets}.
@@ -86,10 +87,7 @@ public class DatabaseMgr {
/** 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 TDBInternal.isBackedByTDB(datasetGraph);
}
/** Return the location of a DatasetGraph if it is backed by TDB, else null */
@@ -107,12 +105,10 @@ public class DatabaseMgr {
}
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)");
+ DatasetGraphTDB dsg = TDBInternal.getDatasetGraphTDB(datasetGraph);
+ if ( dsg == null )
+ throw new TDBException("Not a TDB database (argument is neither a switchable nor direct TDB DatasetGraph)");
+ return dsg;
}
}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/TDB2.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/TDB2.java b/tdb2/src/main/java/org/seaborne/tdb2/TDB2.java
index 3d2ea09..6a18faa 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/TDB2.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/TDB2.java
@@ -40,8 +40,8 @@ import org.seaborne.tdb2.modify.UpdateEngineTDB ;
import org.seaborne.tdb2.solver.QueryEngineTDB ;
import org.seaborne.tdb2.solver.StageGeneratorDirectTDB ;
import org.seaborne.tdb2.sys.EnvTDB ;
-import org.seaborne.tdb2.sys.StoreConnection ;
import org.seaborne.tdb2.sys.SystemTDB ;
+import org.seaborne.tdb2.sys.TDBInternal ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
@@ -94,11 +94,11 @@ public class TDB2 {
}
/**
- * Release any and all system resources held by TDB. This does NOT close or
- * release datasets or graphs held by client code.
+ * Release any and all system resources held by TDB.
+ * All release datasets or graphs held by client code are no longer valid.
*/
public static void closedown() {
- StoreConnection.reset() ;
+ TDBInternal.reset() ;
}
/** Sync a TDB-backed Model. Do nothing if not TDB-backed. */
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/repack/DatasetGraphRecorder.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/repack/DatasetGraphRecorder.java b/tdb2/src/main/java/org/seaborne/tdb2/repack/DatasetGraphRecorder.java
deleted file mode 100644
index 2cca0ae..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/repack/DatasetGraphRecorder.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.repack;
-
-import java.io.File ;
-
-import org.apache.jena.sparql.core.DatasetChanges ;
-import org.apache.jena.sparql.core.DatasetGraph ;
-import org.apache.jena.sparql.core.DatasetGraphMonitor ;
-
-public class DatasetGraphRecorder extends DatasetGraphMonitor {
-
- DatasetChanges monitor ;
-
- public DatasetGraphRecorder(DatasetGraph dsg, String directory) {
- super(dsg, createMonitor(directory));
- }
-
- public void startLogging() { System.err.println("Not implemented"); }
- public void stopLogging() { System.err.println("Not implemented"); }
-
-
- private static DatasetChanges createMonitor(String directory) {
- File place = new File(directory) ;
- if ( ! place.exists() ) {
-
- }
- if ( ! place.isDirectory() ) {
-
- }
- if ( ! place.canWrite() ) {
-
- }
- return null ;
- }
-
-}
-
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/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
deleted file mode 100644
index 642fb61..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/repack/DatasetGraphSwitchable.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * 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.repack;
-
-import java.nio.file.Path;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
-
-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
-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;
-
- public DatasetGraphSwitchable(Path base, DatasetGraph dsg) {
- // Don't use the slot in datasetGraphWrapper - use the AtomicReference
- super(null) ;
- dsgx.set(dsg);
- 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.
- * It is also guaranteed that this is called only once per
- * delegated call. Changes to the wrapped object can be
- * made based on that contract.
- */
- @Override
- public DatasetGraph get() { return dsgx.get(); }
-
- /** Set the base {@link DatasetGraph}.
- * Returns the old value.
- */
- 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/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/CopyDSG.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/CopyDSG.java b/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/CopyDSG.java
deleted file mode 100644
index 6701f88..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/CopyDSG.java
+++ /dev/null
@@ -1,53 +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.util.Iterator;
-import java.util.List;
-
-import org.apache.jena.atlas.iterator.Iter;
-import org.apache.jena.graph.Graph;
-import org.apache.jena.graph.Node;
-import org.apache.jena.sparql.core.DatasetGraph;
-import org.apache.jena.sparql.core.Quad;
-import org.seaborne.dboe.jenax.Txn;
-
-/** Copy operations of any {@link DatasetGraph} */
-public class CopyDSG {
-
- public static void copy(DatasetGraph dsgSrc, DatasetGraph dsgDst) {
- Txn.executeRead(dsgSrc, ()->{
- Txn.executeWrite(dsgDst, () -> {
- Iterator<Quad> iter = dsgSrc.find();
- iter.forEachRemaining(dsgDst::add);
- copyPrefixes(dsgSrc, dsgDst);
- });
- });
- }
-
- public static void copyPrefixes(DatasetGraph dsgSrc, DatasetGraph dsgDst) {
- List<Node> graphNames = Iter.toList(dsgSrc.listGraphNodes());
- copyPrefixes(dsgSrc.getDefaultGraph(), dsgDst.getDefaultGraph());
- graphNames.forEach((gn)->copyPrefixes(dsgSrc.getGraph(gn), dsgDst.getGraph(gn)));
- }
-
- public static void copyPrefixes(Graph srcGraph, Graph dstGraph) {
- dstGraph.getPrefixMapping().setNsPrefixes(srcGraph.getPrefixMapping());
- }
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/FilenameUtils.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/FilenameUtils.java b/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/FilenameUtils.java
deleted file mode 100644
index f0330ac..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/FilenameUtils.java
+++ /dev/null
@@ -1,102 +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.IOException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.regex.Pattern;
-
-import org.apache.jena.atlas.logging.FmtLog;
-import org.seaborne.dboe.DBOpEnvException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class FilenameUtils {
-
- static Logger LOG = LoggerFactory.getLogger(FilenameUtils.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 + nameSep + "*")) {
- 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;
- }
-
- /**
- * Extract the inde from a version-ed filename. (Base-NNNN format).
- * @param name
- * @param namebase
- * @param nameSep
- */
- 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;
- }
-
- /** Construct a filename */
- public static String filename(String prefix, String sep, int N) {
- return String.format("%s%s%04d", prefix, sep, N);
- }
-
- /** Construct a filename */
- public static String filename(String prefix, String sep, String index) {
- return String.format("%s%s%s", prefix, sep, index);
- }
-
-
-
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/Util.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/Util.java b/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/Util.java
deleted file mode 100644
index 7b69090..0000000
--- a/tdb2/src/main/java/org/seaborne/tdb2/repack/sys/Util.java
+++ /dev/null
@@ -1,49 +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.util.List;
-import java.util.NoSuchElementException;
-
-/** Utility code that should go somewhere */
-public class Util {
-
- /** Get the last element of a list, or throw NoSuchElementException
- * @param list
- * @return T
- * @throws NoSuchElementException
- */
- public static <T> T getLast(List<T> list) {
- T elt = getLastOrNull(list);
- if ( elt == null )
- throw new NoSuchElementException();
- return elt;
- }
-
- /**
- * Get the last element of a list, or return null.
- * @param list
- * @return T
- */
- public static <T> T getLastOrNull(List<T> list) {
- if ( list.isEmpty() )
- return null;
- return list.get(list.size()-1);
- }
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/solver/QueryEngineTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/solver/QueryEngineTDB.java b/tdb2/src/main/java/org/seaborne/tdb2/solver/QueryEngineTDB.java
index b6f4a65..dfece29 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/solver/QueryEngineTDB.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/solver/QueryEngineTDB.java
@@ -39,7 +39,7 @@ import org.seaborne.tdb2.TDB2 ;
import org.seaborne.tdb2.TDBException ;
import org.seaborne.tdb2.migrate.A2 ;
import org.seaborne.tdb2.store.DatasetGraphTDB ;
-import org.seaborne.tdb2.store.DatasetGraphTxn ;
+import org.seaborne.tdb2.sys.TDBInternal ;
// This exists to intercept the query execution setup.
// e.g choose the transformation optimizations
@@ -140,21 +140,17 @@ public class QueryEngineTDB extends QueryEngineMain
protected static class QueryEngineFactoryTDB implements QueryEngineFactory
{
- // If a DatasetGraphTransaction is passed in, we are outside a transaction.
-
- private static boolean isHandledByTDB(DatasetGraph dataset)
- {
- if (dataset instanceof DatasetGraphTxn) return true ;
- if (dataset instanceof DatasetGraphTDB) return true ;
- //if (dataset instanceof DatasetGraphTransaction ) return true ;
- return false ;
+ private static boolean isHandledByTDB(DatasetGraph dataset) {
+ return TDBInternal.isBackedByTDB(dataset);
}
- protected DatasetGraphTDB dsgToQuery(DatasetGraph dataset)
- {
- if (dataset instanceof DatasetGraphTDB)
- return (DatasetGraphTDB)dataset ;
- throw new TDBException("Internal inconsistency: trying to execute query on unrecognized kind of DatasetGraph: "+Lib.className(dataset)) ;
+ protected DatasetGraphTDB dsgToQuery(DatasetGraph dataset) {
+ try {
+ return TDBInternal.requireStorage(dataset);
+ } catch (TDBException ex) {
+ // Check to a more specific message.
+ throw new TDBException("Internal inconsistency: trying to execute query on unrecognized kind of DatasetGraph: "+Lib.className(dataset)) ;
+ }
}
@Override
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphSwitchable.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphSwitchable.java b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphSwitchable.java
new file mode 100644
index 0000000..115b304
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphSwitchable.java
@@ -0,0 +1,197 @@
+/*
+ * 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.nio.file.Path;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.jena.atlas.lib.Cache ;
+import org.apache.jena.atlas.lib.CacheFactory ;
+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.*;
+
+final
+public class DatasetGraphSwitchable extends DatasetGraphWrapperTxn /* Until ARQ catches up with promote */
+{
+ // 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;
+
+ public DatasetGraphSwitchable(Path base, DatasetGraph dsg) {
+ // Don't use the slot in datasetGraphWrapper - use the AtomicReference
+ super(null) ;
+ dsgx.set(dsg);
+ 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.
+ * It is also guaranteed that this is called only once per
+ * delegated call. Changes to the wrapped object can be
+ * made based on that contract.
+ */
+ @Override
+ public DatasetGraph get() { return dsgx.get(); }
+
+ /** Set the base {@link DatasetGraph}.
+ * Returns the old value.
+ */
+ 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) {
+ // No need to clear. ngCache.clear();
+ return dsgx.compareAndSet(oldDSG, newDSG);
+ }
+
+ private Graph dftGraph = GraphViewSwitchable.createDefaultGraph(this);
+
+ @Override
+ public Graph getDefaultGraph() {
+ return dftGraph;
+ }
+
+// private Cache<Node, Graph> ngCache = CacheFactory.createCache(10);
+ private Cache<Node, Graph> ngCache = CacheFactory.createOneSlotCache();
+
+ @Override
+ public Graph getGraph(Node gn) {
+ return ngCache.getOrFill(gn, ()->GraphViewSwitchable.createNamedGraph(this, 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/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphTxn.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphTxn.java b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphTxn.java
index 47bc8e0..0915ff0 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphTxn.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphTxn.java
@@ -23,7 +23,7 @@ import org.seaborne.dboe.transaction.Transactional ;
/** Transaction representation of a DatasetGraph */
public interface DatasetGraphTxn extends DatasetGraph, Transactional {
// Combines org.seaborne.dboe.transaction.Transactional and org.apache.jena.sparql.core.Transactional.
- // o.s.dboe.Transactional add promote() ... and
+ // o.s.dboe.Transactional add promote()
@Override
public default boolean supportsTransactions() { return true ; }
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphWrapperTxn.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphWrapperTxn.java b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphWrapperTxn.java
new file mode 100644
index 0000000..e172c90
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphWrapperTxn.java
@@ -0,0 +1,34 @@
+/*
+ * 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.store;
+
+import org.apache.jena.sparql.core.DatasetGraphWrapper ;
+
+public class DatasetGraphWrapperTxn extends DatasetGraphWrapper implements DatasetGraphTxn {
+
+ public DatasetGraphWrapperTxn(DatasetGraphTxn dsg) {
+ super(dsg) ;
+ }
+
+ @Override
+ public boolean promote() {
+ return ((DatasetGraphTxn)get()).promote() ;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/store/GraphViewSwitchable.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/GraphViewSwitchable.java b/tdb2/src/main/java/org/seaborne/tdb2/store/GraphViewSwitchable.java
new file mode 100644
index 0000000..d52f7a0
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/GraphViewSwitchable.java
@@ -0,0 +1,139 @@
+/*
+ * 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.store;
+
+import java.util.Map ;
+
+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.DatasetPrefixStorage ;
+import org.apache.jena.sparql.core.GraphView ;
+import org.apache.jena.sparql.core.Quad ;
+
+/** A GraphView that is sensitive to {@link DatasetGraphSwitchable} switching.
+ */
+public class GraphViewSwitchable extends GraphView {
+ // Fixups for GraphView
+ // Prefixes.
+ // Transaction handler.
+ // Long term - ensure that GraphView uses get() always, inc prefixes, transaction handlers
+
+ // Factory style.
+ public static GraphViewSwitchable createDefaultGraph(DatasetGraphSwitchable dsg)
+ { return new GraphViewSwitchable(dsg, Quad.defaultGraphNodeGenerated) ; }
+
+ public static GraphView createNamedGraph(DatasetGraphSwitchable dsg, Node graphIRI)
+ { return new GraphViewSwitchable(dsg, graphIRI) ; }
+
+ public static GraphViewSwitchable createUnionGraph(DatasetGraphSwitchable dsg)
+ { return new GraphViewSwitchable(dsg, Quad.unionGraph) ; }
+
+ private final DatasetGraphSwitchable dsgx;
+ protected DatasetGraphSwitchable getx() { return dsgx; }
+
+ protected GraphViewSwitchable(DatasetGraphSwitchable dsg, Node gn) {
+ super(dsg, gn) ;
+ this.dsgx = dsg;
+ }
+
+// @Override
+// public TransactionHandler getTransactionHandler() {
+// // XXX Awiting for promote to be enabled.
+// return super.getTransactionHandler();
+// }
+
+ @Override
+ protected PrefixMapping createPrefixMapping() {
+ Node gn = super.getGraphName();
+ if ( gn == Quad.defaultGraphNodeGenerated )
+ gn = null;
+ if ( Quad.isUnionGraph(gn) ) {
+ // Read-only wrapper would be better that a copy.
+ PrefixMapping pmap = new PrefixMappingImpl();
+ pmap.setNsPrefixes(prefixMapping(null));
+ return pmap;
+ }
+ return prefixMapping(gn);
+ }
+
+ /** Return the {@code DatasetGraphSwitchable} we are viewing. */
+ @Override
+ public DatasetGraphSwitchable getDataset() {
+ return getx() ;
+ }
+
+ // TDB2 specific.
+ // Does not cope with blank nodes.
+ // A PrefixMapping sending operations via the switchable.
+ // Long term, rework as PrefixMapping over PrefixMap over DatasetPrefixStorage
+ private PrefixMapping prefixMapping(Node graphName) {
+
+ String gn = (graphName == null) ? "" : graphName.getURI();
+
+ return new PrefixMappingImpl() {
+
+ DatasetPrefixStorage dps() {
+ return ((DatasetGraphTDB)(getx().get())).getPrefixes();
+ }
+
+ Graph graph() {
+ DatasetGraphTDB dsg = (DatasetGraphTDB)getx().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) {
+ //Ignore. String x = super.get(prefix);
+ // (Ignore more?)
+ 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();
+ }
+ };
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/sys/CopyDSG.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/CopyDSG.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/CopyDSG.java
new file mode 100644
index 0000000..4e53ea3
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/CopyDSG.java
@@ -0,0 +1,53 @@
+/*
+ * 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.util.Iterator;
+import java.util.List;
+
+import org.apache.jena.atlas.iterator.Iter;
+import org.apache.jena.graph.Graph;
+import org.apache.jena.graph.Node;
+import org.apache.jena.sparql.core.DatasetGraph;
+import org.apache.jena.sparql.core.Quad;
+import org.seaborne.dboe.jenax.Txn;
+
+/** Copy operations of any {@link DatasetGraph} */
+public class CopyDSG {
+
+ public static void copy(DatasetGraph dsgSrc, DatasetGraph dsgDst) {
+ Txn.executeRead(dsgSrc, ()->{
+ Txn.executeWrite(dsgDst, () -> {
+ Iterator<Quad> iter = dsgSrc.find();
+ iter.forEachRemaining(dsgDst::add);
+ copyPrefixes(dsgSrc, dsgDst);
+ });
+ });
+ }
+
+ public static void copyPrefixes(DatasetGraph dsgSrc, DatasetGraph dsgDst) {
+ List<Node> graphNames = Iter.toList(dsgSrc.listGraphNodes());
+ copyPrefixes(dsgSrc.getDefaultGraph(), dsgDst.getDefaultGraph());
+ graphNames.forEach((gn)->copyPrefixes(dsgSrc.getGraph(gn), dsgDst.getGraph(gn)));
+ }
+
+ public static void copyPrefixes(Graph srcGraph, Graph dstGraph) {
+ dstGraph.getPrefixMapping().setNsPrefixes(srcGraph.getPrefixMapping());
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/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
index 62c5949..0e22f8f 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseConnection.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseConnection.java
@@ -33,8 +33,8 @@ 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 ;
+import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
// StoreConnection, DatabaseConnection < Connection<X>
@@ -108,15 +108,18 @@ public class DatabaseConnection {
return ProcessFileLock.create(lockFilename);
}
- /** Stop managing a location. Use with great care (testing only). */
- public static synchronized void expel(Location location, boolean force) {
+ /** Use via {@link TDBInternal#expel} wherever possible.
+ * <p>
+ * Stop managing a location. Use with great care (testing only).<br/>
+ * Does not expel from {@link StoreConnection}.
+ */
+ public static synchronized void internalExpel(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) ;
@@ -136,13 +139,12 @@ public class DatabaseConnection {
* Use with extreme care.
* This is intended to support internal testing.
*/
- public static synchronized void reset() {
+ public static synchronized void internalReset() {
// Copy to avoid potential CME.
Set<Location> x = new HashSet<>(cache.keySet()) ;
for (Location loc : x)
- expel(loc, true) ;
+ internalExpel(loc, true) ;
cache.clear() ;
- StoreConnection.reset();
}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
index 82dc579..b985798 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
@@ -37,11 +37,8 @@ import org.seaborne.dboe.jenax.Txn ;
import org.seaborne.dboe.transaction.txn.TransactionCoordinator;
import org.seaborne.dboe.transaction.txn.TransactionalSystem;
import org.seaborne.tdb2.TDBException;
-import org.seaborne.tdb2.repack.DatasetGraphSwitchable ;
-import org.seaborne.tdb2.repack.sys.CopyDSG;
-import org.seaborne.tdb2.repack.sys.FilenameUtils;
-import org.seaborne.tdb2.repack.sys.Util;
import org.seaborne.tdb2.setup.StoreParams;
+import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
import org.seaborne.tdb2.store.DatasetGraphTDB;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/sys/FilenameUtils.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/FilenameUtils.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/FilenameUtils.java
new file mode 100644
index 0000000..623ac99
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/FilenameUtils.java
@@ -0,0 +1,102 @@
+/*
+ * 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.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.apache.jena.atlas.logging.FmtLog;
+import org.seaborne.dboe.DBOpEnvException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FilenameUtils {
+
+ static Logger LOG = LoggerFactory.getLogger(FilenameUtils.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 + nameSep + "*")) {
+ 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;
+ }
+
+ /**
+ * Extract the inde from a version-ed filename. (Base-NNNN format).
+ * @param name
+ * @param namebase
+ * @param nameSep
+ */
+ 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;
+ }
+
+ /** Construct a filename */
+ public static String filename(String prefix, String sep, int N) {
+ return String.format("%s%s%04d", prefix, sep, N);
+ }
+
+ /** Construct a filename */
+ public static String filename(String prefix, String sep, String index) {
+ return String.format("%s%s%s", prefix, sep, index);
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/sys/IOX.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/IOX.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/IOX.java
index 049fbb3..ed78f88 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/IOX.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/IOX.java
@@ -34,7 +34,6 @@ 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.seaborne.tdb2.repack.sys.Util ;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java
index 3ef596f..54d863b 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java
@@ -101,22 +101,26 @@ public class StoreConnection
* Use with extreme care.
* This is intended to support internal testing.
*/
- public static synchronized void reset() {
+ public static synchronized void internalReset() {
// Copy to avoid potential CME.
Set<Location> x = new HashSet<>(cache.keySet()) ;
for (Location loc : x)
- expel(loc, true) ;
+ internalExpel(loc, true) ;
cache.clear() ;
ChannelManager.reset();
}
/** Stop managing a location. There should be no transactions running. */
public static synchronized void release(Location location) {
- expel(location, false) ;
+ internalExpel(location, false) ;
}
- /** Stop managing a location. Use with great care (testing only). */
- public static synchronized void expel(Location location, boolean force) {
+ /** Use via {@link TDBInternal#expel} wherever possible.
+ * <p>
+ * Stop managing a location.<br/>
+ * Use with great care (testing only).
+ */
+ public static synchronized void internalExpel(Location location, boolean force) {
StoreConnection sConn = cache.get(location) ;
if (sConn == null) return ;
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java
index 466e1d2..25c1688 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java
@@ -20,12 +20,20 @@ package org.seaborne.tdb2.sys;
import org.apache.jena.graph.Node;
import org.apache.jena.query.Dataset;
import org.apache.jena.sparql.core.DatasetGraph;
+import org.seaborne.dboe.base.file.Location ;
+import org.seaborne.tdb2.TDBException ;
+import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
import org.seaborne.tdb2.store.DatasetGraphTDB;
import org.seaborne.tdb2.store.NodeId;
import org.seaborne.tdb2.store.nodetable.NodeTable;
/**
- * A collection of helpers to abstract away from internal details of TDB. Use with care.
+ * A collection of helpers to abstract away from calling code knowing the
+ * internal details of TDB.
+ * <p>
+ * Use with care.
+ * <p>{@link DatabaseOps#compact Compaction} invalidates any previous objects.
+ *
*/
public class TDBInternal {
/**
@@ -88,17 +96,59 @@ public class TDBInternal {
/**
* Return the DatasetGraphTDB for a Dataset, or null.
+ * Use the {@link DatasetGraphTDB} with care.
*/
public static DatasetGraphTDB getDatasetGraphTDB(Dataset ds) {
return getDatasetGraphTDB(ds.asDatasetGraph());
}
/**
- * Return the DatasetGraphTDB for a DatasetGraph, or null. May not be up-to-date.
+ * Return the DatasetGraphTDB for a DatasetGraph, or null.
+ * Use the {@link DatasetGraphTDB} with care.
*/
public static DatasetGraphTDB getDatasetGraphTDB(DatasetGraph dsg) {
+ return unwrap(dsg);
+ }
+
+ /**
+ * Return the DatasetGraphTDB for a DatasetGraph, or throw an exception.
+ */
+ public static DatasetGraphTDB requireStorage(DatasetGraph dsg) {
+ DatasetGraphTDB dsgtdb = unwrap(dsg);
+ if ( dsgtdb == null )
+ throw new TDBException("Not a TDB database (argument is neither a switchable nor direct TDB DatasetGraph)");
+ return dsgtdb;
+ }
+
+ private static DatasetGraphTDB unwrap(DatasetGraph datasetGraph) {
+ DatasetGraph dsg = datasetGraph;
+ if ( dsg instanceof DatasetGraphSwitchable )
+ dsg = ((DatasetGraphSwitchable)datasetGraph).get();
if ( dsg instanceof DatasetGraphTDB )
- return (DatasetGraphTDB)dsg;
+ return ((DatasetGraphTDB)dsg);
return null;
}
+
+ /** Stop managing a location. Use with great care (testing only). */
+ public static synchronized void expel(Location location, boolean force) {
+ DatabaseConnection.internalExpel(location, force);
+ StoreConnection.internalExpel(location, force);
+ }
+
+ /**
+ * Reset the whole TDB system.
+ * Use with great care.
+ */
+ public static void reset() {
+ DatabaseConnection.internalReset();
+ StoreConnection.internalReset();
+ }
+
+ public static boolean isBackedByTDB(DatasetGraph datasetGraph) {
+ if ( datasetGraph instanceof DatasetGraphSwitchable )
+ return true;
+ if ( datasetGraph instanceof DatasetGraphTDB )
+ return true;
+ return false;
+ }
}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/main/java/org/seaborne/tdb2/sys/Util.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/Util.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/Util.java
new file mode 100644
index 0000000..3ac6336
--- /dev/null
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/Util.java
@@ -0,0 +1,49 @@
+/*
+ * 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.util.List;
+import java.util.NoSuchElementException;
+
+/** Utility code that should go somewhere */
+public class Util {
+
+ /** Get the last element of a list, or throw NoSuchElementException
+ * @param list
+ * @return T
+ * @throws NoSuchElementException
+ */
+ public static <T> T xgetLast(List<T> list) {
+ T elt = getLastOrNull(list);
+ if ( elt == null )
+ throw new NoSuchElementException();
+ return elt;
+ }
+
+ /**
+ * Get the last element of a list, or return null.
+ * @param list
+ * @return T
+ */
+ public static <T> T getLastOrNull(List<T> list) {
+ if ( list.isEmpty() )
+ return null;
+ return list.get(list.size()-1);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/TC_TDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/TC_TDB.java b/tdb2/src/test/java/org/seaborne/tdb2/TC_TDB.java
index 5c97542..8d1a695 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/TC_TDB.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/TC_TDB.java
@@ -50,10 +50,10 @@ import org.seaborne.tdb2.sys.TS_Sys ;
, TS_TDBSetup.class
, TS_Store.class
, TS_SolverTDB.class
- , TS_Sys.class
, TS_Graph.class
, TS_Factory.class
, TS_TDBAssembler.class
+ , TS_Sys.class
} )
public class TC_TDB
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/TS_Factory.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/TS_Factory.java b/tdb2/src/test/java/org/seaborne/tdb2/TS_Factory.java
index d963ad3..b6dc979 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/TS_Factory.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/TS_Factory.java
@@ -26,9 +26,6 @@ import org.junit.runners.Suite;
TestDatabaseMgr.class
, TestTDBFactory.class
- // Move to TS_Sys
- , TestDatabaseOps.class
- , TestDatabaseConnection.class
})
public class TS_Factory
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseConnection.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseConnection.java b/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseConnection.java
deleted file mode 100644
index a720b11..0000000
--- a/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseConnection.java
+++ /dev/null
@@ -1,68 +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;
-
-import static org.junit.Assert.assertNotSame ;
-import static org.junit.Assert.assertSame ;
-
-import org.apache.jena.atlas.lib.FileOps ;
-import org.apache.jena.sparql.core.DatasetGraph ;
-import org.junit.Test ;
-import org.seaborne.dboe.base.file.Location ;
-import org.seaborne.tdb2.sys.DatabaseConnection ;
-
-public class TestDatabaseConnection {
-
- @Test
- public void testStoreConnectionTxn1() {
- DatabaseConnection.reset() ;
- // Only do disk things for test that need them (disk takes time!).
- String DIRx = ConfigTest.getCleanDir() ;
- Location DIR = Location.create(DIRx);
- FileOps.clearDirectory(DIRx) ;
- try {
- DatasetGraph dg1 = DatabaseConnection.connectCreate(DIR).getDatasetGraph() ;
- DatasetGraph dg2 = DatabaseConnection.connectCreate(DIR).getDatasetGraph() ;
- assertSame(dg1, dg2) ;
- }
- finally {
- FileOps.clearDirectory(DIRx) ;
- }
- }
-
- @Test
- public void testStoreConnectionTxn2() {
- // Named memory locations
- DatabaseConnection.reset() ;
- DatasetGraph dg1 = DatabaseConnection.connectCreate(Location.mem("FOO")).getDatasetGraph() ;
- DatasetGraph dg2 = DatabaseConnection.connectCreate(Location.mem("FOO")).getDatasetGraph() ;
- assertSame(dg1, dg2) ;
- }
-
- @Test
- public void testStoreConnectionTxn3() {
- // Un-named memory locations
- DatabaseConnection.reset() ;
- DatasetGraph dg1 = DatabaseConnection.connectCreate(Location.mem()).getDatasetGraph() ;
- DatasetGraph dg2 = DatabaseConnection.connectCreate(Location.mem()).getDatasetGraph() ;
- assertNotSame(dg1, dg2) ;
- }
-
-
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java b/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java
index 5251b8b..552aa56 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java
@@ -25,7 +25,7 @@ import org.apache.jena.sparql.sse.SSE ;
import org.junit.Test ;
import org.seaborne.dboe.base.file.Location ;
import org.seaborne.dboe.jenax.Txn ;
-import org.seaborne.tdb2.sys.DatabaseConnection ;
+import org.seaborne.tdb2.sys.TDBInternal ;
/** Test of DatabaseMgr - the DatasetGraph level API to TDB2 **/
public class TestDatabaseMgr extends BaseTest
@@ -38,7 +38,7 @@ public class TestDatabaseMgr extends BaseTest
@Test
public void testDatabaseMgr1() {
- DatabaseConnection.reset() ;
+ TDBInternal.reset() ;
DatasetGraph dg1 = DatabaseMgr.connectDatasetGraph(Location.mem("FOO")) ;
DatasetGraph dg2 = DatabaseMgr.connectDatasetGraph(Location.mem("FOO")) ;
Txn.executeWrite(dg1, ()->{
@@ -51,7 +51,7 @@ public class TestDatabaseMgr extends BaseTest
@Test
public void testDatabaseMgr2() {
- DatabaseConnection.reset() ;
+ TDBInternal.reset() ;
// The unnamed location is unique each time.
DatasetGraph dg1 = DatabaseMgr.connectDatasetGraph(Location.mem()) ;
DatasetGraph dg2 = DatabaseMgr.connectDatasetGraph(Location.mem()) ;
@@ -65,7 +65,7 @@ public class TestDatabaseMgr extends BaseTest
@Test
public void testDatabaseMgrDisk() {
- DatabaseConnection.reset() ;
+ TDBInternal.reset() ;
// The named disk location
String DIRx = ConfigTest.getCleanDir() ;
Location LOC = Location.create(DIRx) ;
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseOps.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseOps.java b/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseOps.java
deleted file mode 100644
index 406758b..0000000
--- a/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseOps.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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;
-
-import static org.junit.Assert.* ;
-
-import org.apache.commons.io.FileUtils ;
-import org.apache.jena.atlas.lib.FileOps ;
-import org.apache.jena.riot.RDFDataMgr ;
-import org.apache.jena.sparql.core.DatasetGraph ;
-import org.apache.jena.sparql.core.Quad ;
-import org.apache.jena.sparql.sse.SSE ;
-import org.junit.After ;
-import org.junit.Before ;
-import org.junit.Test ;
-import org.seaborne.dboe.base.file.Location ;
-import org.seaborne.dboe.jenax.Txn ;
-import org.seaborne.tdb2.repack.DatasetGraphSwitchable ;
-import org.seaborne.tdb2.store.DatasetGraphTDB ;
-import org.seaborne.tdb2.sys.DatabaseConnection ;
-import org.seaborne.tdb2.sys.IOX ;
-import org.seaborne.tdb2.sys.StoreConnection ;
-
-public class TestDatabaseOps
-{
- static String DIRx = ConfigTest.getCleanDir() ;
- static Location DIR = Location.create(DIRx);
-
- static Quad quad1 = SSE.parseQuad("(_ _:a <p> 1)") ;
- static Quad quad2 = SSE.parseQuad("(_ <s> <p> 1)") ;
-
- @Before
- public void before() {
- FileUtils.deleteQuietly(IOX.asFile(DIR));
- FileOps.ensureDir(DIR.getDirectoryPath());
- }
-
- @After
- public void after() {
- DatabaseConnection.reset();
- FileUtils.deleteQuietly(IOX.asFile(DIR));
- }
-
- @Test public void compact_1() {
- DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(DIR);
- DatasetGraphSwitchable dsgs = (DatasetGraphSwitchable)dsg;
- DatasetGraph dsg1 = dsgs.get();
- Location loc1 = ((DatasetGraphTDB)dsg1).getLocation();
-
- Txn.executeWrite(dsg, ()-> {
- dsg.add(quad1) ;
- dsg.add(quad2) ;
- }) ;
- DatabaseMgr.compact(dsg);
- DatasetGraph dsg2 = dsgs.get();
- Location loc2 = ((DatasetGraphTDB)dsg2).getLocation();
-
- assertNotEquals(dsg1, dsg2);
- assertNotEquals(loc1, loc2);
-
- Txn.executeRead(dsg, ()-> {
- assertTrue(dsg.contains(quad1)) ;
- assertTrue(dsg.contains(quad2)) ;
- }) ;
-
- // Naughty!
- // dsg1 was closed and expelled. We must reopen its storage only.
- DatasetGraph dsgOld = StoreConnection.connectCreate(loc1).getDatasetGraph();
-
- Txn.executeWrite(dsgOld, ()->dsgOld.delete(quad1));
-
- Txn.executeWrite(dsg, ()->assertTrue(dsg.contains(quad1)) );
-
- Txn.executeWrite(dsg2, ()->assertTrue(dsg2.contains(quad1)) ) ;
-
- StoreConnection.expel(loc1, true);
- }
-
-// @Test public void compact_2() {
-// }
-
- @Test public void backup_1() {
- DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(DIR);
- Txn.executeWrite(dsg, ()-> {
- dsg.add(quad1) ;
- dsg.add(quad2) ;
- }) ;
- String file1 = DatabaseMgr.backup(dsg);
- DatasetGraph dsg2 = RDFDataMgr.loadDatasetGraph(file1);
- Txn.executeRead(dsg, ()-> {
- assertTrue(dsg.contains(quad2)) ;
- assertEquals(2, dsg.getDefaultGraph().size());
- assertTrue(dsg2.getDefaultGraph().isIsomorphicWith(dsg.getDefaultGraph()));
- }) ;
- String file2 = DatabaseMgr.backup(dsg);
- assertNotEquals(file1, file2);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java b/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
index 7d1c780..795c871 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
@@ -28,7 +28,7 @@ import org.apache.jena.rdf.model.ResourceFactory ;
import org.junit.Test ;
import org.seaborne.dboe.base.file.Location ;
import org.seaborne.dboe.jenax.Txn ;
-import org.seaborne.tdb2.sys.DatabaseConnection ;
+import org.seaborne.tdb2.sys.TDBInternal ;
/** Test of TDB2Factory - the Dataset level API to TDB2 **/
public class TestTDBFactory extends BaseTest
@@ -41,21 +41,21 @@ public class TestTDBFactory extends BaseTest
@Test
public void testTDBFactory1() {
- DatabaseConnection.reset() ;
+ TDBInternal.reset() ;
Dataset ds = TDB2Factory.connectDataset(Location.mem()) ;
test(ds);
}
@Test
public void testTDBFactory2() {
- DatabaseConnection.reset() ;
+ TDBInternal.reset() ;
Dataset ds = TDB2Factory.connectDataset(Location.mem("MEMORY")) ;
test(ds);
}
@Test
public void testTDBFactory3() {
- DatabaseConnection.reset() ;
+ TDBInternal.reset() ;
// Only do disk things for tests that need them (disk takes time!).
String DIRx = ConfigTest.getCleanDir() ;
Location DIR = Location.create(DIRx);
@@ -68,7 +68,7 @@ public class TestTDBFactory extends BaseTest
@Test
public void testTDBFactory2DS_1() {
- DatabaseConnection.reset() ;
+ TDBInternal.reset() ;
Dataset ds1 = TDB2Factory.connectDataset(Location.mem("FOO")) ;
Dataset ds2 = TDB2Factory.connectDataset(Location.mem("FOO")) ;
Txn.executeWrite(ds1, ()->{
@@ -81,7 +81,7 @@ public class TestTDBFactory extends BaseTest
@Test
public void testTDBFactory2DS_2() {
- DatabaseConnection.reset() ;
+ TDBInternal.reset() ;
// The unnamed location is unique each time.
Dataset ds1 = TDB2Factory.connectDataset(Location.mem()) ;
Dataset ds2 = TDB2Factory.connectDataset(Location.mem()) ;
@@ -95,8 +95,8 @@ public class TestTDBFactory extends BaseTest
@Test
public void testTDBFactory2DS_3() {
- DatabaseConnection.reset() ;
- DatabaseConnection.reset() ;
+ TDBInternal.reset() ;
+ TDBInternal.reset() ;
String DIRx = ConfigTest.getCleanDir() ;
Location DIR = Location.create(DIRx);
try {
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/assembler/TestTDBAssembler.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/assembler/TestTDBAssembler.java b/tdb2/src/test/java/org/seaborne/tdb2/assembler/TestTDBAssembler.java
index cf22821..581af56 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/assembler/TestTDBAssembler.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/assembler/TestTDBAssembler.java
@@ -32,11 +32,9 @@ import org.junit.Before ;
import org.junit.BeforeClass ;
import org.junit.Test ;
import org.seaborne.tdb2.ConfigTest ;
-import org.seaborne.tdb2.assembler.VocabTDB2 ;
-import org.seaborne.tdb2.store.DatasetGraphTDB ;
-import org.seaborne.tdb2.store.DatasetGraphTxn ;
-import org.seaborne.tdb2.store.GraphTDB ;
-import org.seaborne.tdb2.sys.StoreConnection ;
+import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
+import org.seaborne.tdb2.store.GraphViewSwitchable ;
+import org.seaborne.tdb2.sys.TDBInternal ;
public class TestTDBAssembler extends BaseTest
{
@@ -52,13 +50,13 @@ public class TestTDBAssembler extends BaseTest
@Before
public void before() {
- StoreConnection.reset() ;
+ TDBInternal.reset() ;
FileOps.clearDirectory(dirDB) ;
}
@AfterClass
static public void afterClass() {
- StoreConnection.reset() ;
+ TDBInternal.reset() ;
FileOps.clearDirectory(dirDB) ;
}
@@ -76,7 +74,7 @@ public class TestTDBAssembler extends BaseTest
Object thing = AssemblerUtils.build(filename, type) ;
assertTrue(thing instanceof Dataset) ;
Dataset ds = (Dataset)thing ;
- assertTrue(ds.asDatasetGraph() instanceof DatasetGraphTxn) ;
+ assertTrue(ds.asDatasetGraph() instanceof DatasetGraphSwitchable) ;
assertTrue(ds.supportsTransactions()) ;
ds.close() ;
}
@@ -88,11 +86,6 @@ public class TestTDBAssembler extends BaseTest
@Test
public void createGraphEmbed() {
- // Jena 3.1.0 needs ... remove for Jena 3.1.1 or later.
-// if ( true ) {
-// System.err.println("TestTDBAssembler.createGraphEmbed disabled for Jena 3.1.0") ;
-// return ;
-// }
String f = dirAssem + "/tdb-graph-embed.ttl" ;
Object thing = null ;
try {
@@ -105,9 +98,9 @@ public class TestTDBAssembler extends BaseTest
assertTrue(thing instanceof Model) ;
Graph graph = ((Model)thing).getGraph() ;
- assertTrue(graph instanceof GraphTDB) ;
+ assertTrue(graph instanceof GraphViewSwitchable) ;
- DatasetGraphTDB ds = ((GraphTDB)graph).getDSG() ;
+ DatasetGraphSwitchable ds = ((GraphViewSwitchable)graph).getDataset() ;
if ( ds != null )
ds.close() ;
}
@@ -140,10 +133,10 @@ public class TestTDBAssembler extends BaseTest
assertTrue(thing instanceof Model) ;
Graph graph = ((Model)thing).getGraph() ;
- assertTrue(graph instanceof GraphTDB) ;
+ assertTrue(graph instanceof GraphViewSwitchable) ;
- DatasetGraphTDB ds = ((GraphTDB)graph).getDSG() ;
- if ( ds != null )
- ds.close() ;
+ DatasetGraphSwitchable dsg = ((GraphViewSwitchable)graph).getDataset();
+ if ( dsg != null )
+ dsg.close() ;
}
}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/graph/TestPrefixMappingTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/graph/TestPrefixMappingTDB.java b/tdb2/src/test/java/org/seaborne/tdb2/graph/TestPrefixMappingTDB.java
index 27fbbb1..7deaea4 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/graph/TestPrefixMappingTDB.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/graph/TestPrefixMappingTDB.java
@@ -25,16 +25,16 @@ import org.junit.* ;
import org.seaborne.dboe.base.file.Location ;
import org.seaborne.tdb2.ConfigTest ;
import org.seaborne.tdb2.junit.BuildTestLib ;
-import org.seaborne.tdb2.sys.StoreConnection ;
+import org.seaborne.tdb2.sys.TDBInternal ;
public class TestPrefixMappingTDB extends AbstractTestPrefixMapping2
{
static DatasetPrefixStorage last = null ;
@BeforeClass public static void beforeClass() {}
- @AfterClass public static void afterClass() { StoreConnection.reset() ; ConfigTest.deleteTestingDir() ; }
+ @AfterClass public static void afterClass() { TDBInternal.reset() ; ConfigTest.deleteTestingDir() ; }
- @Before public void before() { StoreConnection.reset() ; }
+ @Before public void before() { TDBInternal.reset() ; }
@After public void after() { }
@@ -78,7 +78,6 @@ public class TestPrefixMappingTDB extends AbstractTestPrefixMapping2
// Persistent.
@Test
public void persistent1() {
- StoreConnection.reset();
String dir = ConfigTest.getTestingDir() ;
FileOps.clearDirectory(dir) ;
@@ -93,7 +92,6 @@ public class TestPrefixMappingTDB extends AbstractTestPrefixMapping2
// Persistent.
@Test
public void persistent2() {
- StoreConnection.reset();
String dir = ConfigTest.getTestingDir() ;
FileOps.clearDirectory(dir) ;
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java b/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
index cd58c36..7385354 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
@@ -25,8 +25,8 @@ import org.seaborne.dboe.base.file.Location ;
import org.seaborne.tdb2.ConfigTest ;
import org.seaborne.tdb2.DatabaseMgr ;
import org.seaborne.tdb2.TDB2Factory ;
-import org.seaborne.tdb2.sys.DatabaseConnection ;
import org.seaborne.tdb2.sys.SystemTDB ;
+import org.seaborne.tdb2.sys.TDBInternal ;
/** Execute a test with a fresh dataset in a write transaction */
public class TL {
@@ -35,14 +35,14 @@ public class TL {
Dataset dataset = createTestDataset() ;
action.accept(dataset);
releaseDataset(dataset) ;
- DatabaseConnection.reset() ;
+ TDBInternal.reset() ;
}
public static void execMem(Consumer<Dataset> action) {
Dataset dataset = createTestDatasetMem() ;
action.accept(dataset);
releaseDataset(dataset);
- DatabaseConnection.reset();
+ TDBInternal.reset();
}
// Or use these for @Before, @After style.
@@ -58,7 +58,7 @@ public class TL {
public static void releaseDataset(Dataset dataset) {
dataset.abort() ;
- DatabaseConnection.reset() ;
+ TDBInternal.reset() ;
}
public static Dataset createTestDataset() {
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java b/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java
index ce811a9..fbac48e 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java
@@ -31,7 +31,9 @@ import org.junit.Test ;
import org.seaborne.dboe.base.file.Location ;
import org.seaborne.dboe.sys.Names;
import org.seaborne.tdb2.ConfigTest ;
+import org.seaborne.tdb2.sys.DatabaseConnection ;
import org.seaborne.tdb2.sys.StoreConnection ;
+import org.seaborne.tdb2.sys.TDBInternal ;
/**
* This test suite uses on-disk structures, does a lot of clean/create/sync
@@ -52,12 +54,12 @@ public class TestStoreParamsCreate extends BaseTest {
@Before public void clearupTest() {
// Flush and clean.
- StoreConnection.expel(loc, true) ;
+ DatabaseConnection.internalExpel(loc, true);
FileOps.clearAll(DB_DIR);
}
@After public void expelDatabase() {
- StoreConnection.expel(loc, true) ;
+ TDBInternal.expel(loc, true) ;
}
@Test public void params_create_01() {
@@ -81,7 +83,7 @@ public class TestStoreParamsCreate extends BaseTest {
// Create.
StoreConnection.connectCreate(loc) ;
// Drop.
- StoreConnection.expel(loc, true) ;
+ TDBInternal.expel(loc, true) ;
// Reconnect
StoreConnection.connectCreate(loc, null) ;
StoreParams pLoc = StoreParamsCodec.read(loc) ;
@@ -98,7 +100,7 @@ public class TestStoreParamsCreate extends BaseTest {
// Create.
StoreConnection.connectCreate(loc, null) ;
// Drop.
- StoreConnection.expel(loc, true) ;
+ TDBInternal.expel(loc, true) ;
// Reconnect
StoreConnection.connectCreate(loc, pSpecial) ;
//StoreParams pLoc = StoreParamsCodec.read(loc) ;
@@ -123,7 +125,7 @@ public class TestStoreParamsCreate extends BaseTest {
// Create.
StoreConnection.connectCreate(loc, pApp) ;
// Drop.
- StoreConnection.expel(loc, true) ;
+ TDBInternal.expel(loc, true) ;
// Reconnect
StoreConnection.connectCreate(loc, pSpecial) ;
//StoreParams pLoc = StoreParamsCodec.read(loc) ;
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java b/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java
index db63eeb..e31263b 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java
@@ -32,10 +32,11 @@ import org.seaborne.tdb2.store.DatasetGraphTDB ;
import org.seaborne.tdb2.store.NodeId ;
import org.seaborne.tdb2.store.nodetable.NodeTable ;
import org.seaborne.tdb2.store.nodetupletable.NodeTupleTable ;
+import org.seaborne.tdb2.sys.TDBInternal ;
public class TestStats extends BaseTest
{
- static DatasetGraphTDB dsg = ((DatasetGraphTDB)TL.createTestDatasetGraphMem()) ;
+ static DatasetGraphTDB dsg = TDBInternal.getDatasetGraphTDB(TL.createTestDatasetGraphMem()) ;
static NodeTupleTable quads = dsg.getQuadTable().getNodeTupleTable() ;
static NodeTupleTable triples = dsg.getTripleTable().getNodeTupleTable() ;
static NodeTable nt = quads.getNodeTable() ;
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java b/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java
index 854402b..c23dc0e 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java
@@ -26,8 +26,8 @@ import org.junit.Before ;
import org.junit.Test ;
import org.seaborne.dboe.base.file.Location ;
import org.seaborne.dboe.jenax.Txn ;
-import org.seaborne.tdb2.sys.DatabaseConnection ;
import org.seaborne.tdb2.sys.StoreConnection ;
+import org.seaborne.tdb2.sys.TDBInternal ;
/** StoreConnection and transactions - basic wiring.
* These tests are slow on rotational disk.
@@ -53,11 +53,11 @@ public abstract class AbstractTestStoreConnectionBasics extends BaseTest
@Before public void before()
{
- DatabaseConnection.reset() ;
+ TDBInternal.reset() ;
location = getLocation() ;
}
- @After public void after() {}
+ @After public void after() { TDBInternal.reset() ; }
@Test
public void store_01()
[05/50] [abbrv] jena git commit: Migrate tests to
DatasetGraphSwitchable
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDBPersist.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDBPersist.java b/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDBPersist.java
index 45e73a6..fe928a0 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDBPersist.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDBPersist.java
@@ -17,11 +17,14 @@
package org.seaborne.tdb2.store;
+import static org.junit.Assert.assertEquals ;
+import static org.junit.Assert.assertFalse ;
+import static org.junit.Assert.assertTrue ;
+
import java.util.Arrays ;
import java.util.List ;
import org.apache.jena.atlas.iterator.Iter ;
-import org.apache.jena.atlas.junit.BaseTest ;
import org.apache.jena.graph.Graph ;
import org.apache.jena.graph.Node ;
import org.apache.jena.graph.Triple ;
@@ -31,7 +34,7 @@ import org.junit.Test ;
import org.seaborne.tdb2.junit.TL ;
/** Testing persistence */
-public class TestDatasetTDBPersist extends BaseTest
+public class TestDatasetTDBPersist
{
static Node n0 = NodeFactoryExtra.parseNode("<http://example/n0>") ;
static Node n1 = NodeFactoryExtra.parseNode("<http://example/n1>") ;
@@ -40,8 +43,8 @@ public class TestDatasetTDBPersist extends BaseTest
@Test
public void dataset1() {
TL.exec((ds) -> {
- assertTrue(ds.getDefaultModel().getGraph() instanceof GraphTDB) ;
- assertTrue(ds.getNamedModel("http://example/").getGraph() instanceof GraphTDB) ;
+ assertTrue(ds.getDefaultModel().getGraph() instanceof GraphViewSwitchable) ;
+ assertTrue(ds.getNamedModel("http://example/").getGraph() instanceof GraphViewSwitchable) ;
}) ;
}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java b/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
index bfae615..5442c79 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
@@ -37,7 +37,6 @@ import org.seaborne.dboe.base.file.Location ;
import org.seaborne.dboe.jenax.Txn ;
import org.seaborne.dboe.transaction.txn.TransactionException;
import org.seaborne.tdb2.TDB2Factory ;
-import org.seaborne.tdb2.sys.StoreConnection ;
import org.seaborne.tdb2.sys.TDBInternal;
/** Transactions and store connections - extended tests assuming the
@@ -84,7 +83,7 @@ public class TestTransactions extends BaseTest
@After public void after() {
dataset.close() ;
- StoreConnection.expel(location, true);
+ TDBInternal.expel(location, true);
}
// Models across transactions
@@ -135,7 +134,7 @@ public class TestTransactions extends BaseTest
load(data2);
dataset.begin(ReadWrite.READ);
- Iterator<Quad> iter = TDBInternal.getDatasetGraphTDB(dataset).find();
+ Iterator<Quad> iter = dataset.asDatasetGraph().find();
dataset.end();
iter.next();
}
@@ -169,7 +168,7 @@ public class TestTransactions extends BaseTest
load(data2);
dataset.begin(ReadWrite.READ);
- Iterator<Quad> iter = TDBInternal.getDatasetGraphTDB(dataset).find();
+ Iterator<Quad> iter = dataset.asDatasetGraph().find();
dataset.end();
dataset.begin(ReadWrite.READ);
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/sys/TS_Sys.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/sys/TS_Sys.java b/tdb2/src/test/java/org/seaborne/tdb2/sys/TS_Sys.java
index 2c93a96..7a37acc 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/sys/TS_Sys.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/sys/TS_Sys.java
@@ -20,14 +20,14 @@ package org.seaborne.tdb2.sys;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
-import org.seaborne.tdb2.sys.TestSys ;
@RunWith(Suite.class)
@Suite.SuiteClasses( {
- TestSys.class
+ TestDatabaseOps.class
+ , TestDatabaseConnection.class
+ , TestSys.class
+ //, TestOps.class
})
public class TS_Sys
-{
-
-}
+{}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseConnection.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseConnection.java b/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseConnection.java
new file mode 100644
index 0000000..8e6bdcc
--- /dev/null
+++ b/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseConnection.java
@@ -0,0 +1,69 @@
+/*
+ * 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 static org.junit.Assert.assertNotSame ;
+import static org.junit.Assert.assertSame ;
+
+import org.apache.jena.atlas.lib.FileOps ;
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.junit.Test ;
+import org.seaborne.dboe.base.file.Location ;
+import org.seaborne.tdb2.ConfigTest ;
+import org.seaborne.tdb2.sys.DatabaseConnection ;
+
+public class TestDatabaseConnection {
+
+ @Test
+ public void testStoreConnectionTxn1() {
+ TDBInternal.reset() ;
+ // Only do disk things for test that need them (disk takes time!).
+ String DIRx = ConfigTest.getCleanDir() ;
+ Location DIR = Location.create(DIRx);
+ FileOps.clearDirectory(DIRx) ;
+ try {
+ DatasetGraph dg1 = DatabaseConnection.connectCreate(DIR).getDatasetGraph() ;
+ DatasetGraph dg2 = DatabaseConnection.connectCreate(DIR).getDatasetGraph() ;
+ assertSame(dg1, dg2) ;
+ }
+ finally {
+ FileOps.clearDirectory(DIRx) ;
+ }
+ }
+
+ @Test
+ public void testStoreConnectionTxn2() {
+ // Named memory locations
+ TDBInternal.reset() ;
+ DatasetGraph dg1 = DatabaseConnection.connectCreate(Location.mem("FOO")).getDatasetGraph() ;
+ DatasetGraph dg2 = DatabaseConnection.connectCreate(Location.mem("FOO")).getDatasetGraph() ;
+ assertSame(dg1, dg2) ;
+ }
+
+ @Test
+ public void testStoreConnectionTxn3() {
+ // Un-named memory locations
+ TDBInternal.reset() ;
+ DatasetGraph dg1 = DatabaseConnection.connectCreate(Location.mem()).getDatasetGraph() ;
+ DatasetGraph dg2 = DatabaseConnection.connectCreate(Location.mem()).getDatasetGraph() ;
+ assertNotSame(dg1, dg2) ;
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/218d10c5/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java b/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java
new file mode 100644
index 0000000..67883a4
--- /dev/null
+++ b/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java
@@ -0,0 +1,117 @@
+/*
+ * 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.sys;
+
+import static org.junit.Assert.assertEquals ;
+import static org.junit.Assert.assertFalse ;
+import static org.junit.Assert.assertNotEquals ;
+import static org.junit.Assert.assertTrue ;
+
+import org.apache.commons.io.FileUtils ;
+import org.apache.jena.atlas.lib.FileOps ;
+import org.apache.jena.riot.RDFDataMgr ;
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.apache.jena.sparql.core.Quad ;
+import org.apache.jena.sparql.sse.SSE ;
+import org.junit.After ;
+import org.junit.Before ;
+import org.junit.Test ;
+import org.seaborne.dboe.base.file.Location ;
+import org.seaborne.dboe.jenax.Txn ;
+import org.seaborne.tdb2.ConfigTest ;
+import org.seaborne.tdb2.DatabaseMgr ;
+import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
+import org.seaborne.tdb2.store.DatasetGraphTDB ;
+
+public class TestDatabaseOps
+{
+ static String DIRx = ConfigTest.getCleanDir() ;
+ static Location DIR = Location.create(DIRx);
+
+ static Quad quad1 = SSE.parseQuad("(_ _:a <p> 1)") ;
+ static Quad quad2 = SSE.parseQuad("(_ <s> <p> 1)") ;
+
+ @Before
+ public void before() {
+ FileUtils.deleteQuietly(IOX.asFile(DIR));
+ FileOps.ensureDir(DIR.getDirectoryPath());
+ }
+
+ @After
+ public void after() {
+ TDBInternal.reset();
+ FileUtils.deleteQuietly(IOX.asFile(DIR));
+ }
+
+ @Test public void compact_1() {
+ DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(DIR);
+ DatasetGraphSwitchable dsgs = (DatasetGraphSwitchable)dsg;
+ DatasetGraph dsg1 = dsgs.get();
+ Location loc1 = ((DatasetGraphTDB)dsg1).getLocation();
+
+ Txn.executeWrite(dsg, ()-> {
+ dsg.add(quad1) ;
+ dsg.add(quad2) ;
+ }) ;
+ DatabaseMgr.compact(dsg);
+
+ assertFalse(StoreConnection.isSetup(loc1));
+
+ DatasetGraph dsg2 = dsgs.get();
+ Location loc2 = ((DatasetGraphTDB)dsg2).getLocation();
+
+ assertNotEquals(dsg1, dsg2);
+ assertNotEquals(loc1, loc2);
+
+ Txn.executeRead(dsg, ()-> {
+ assertTrue(dsg.contains(quad1)) ;
+ assertTrue(dsg.contains(quad2)) ;
+ }) ;
+
+ // dsg1 was closed and expelled. We must carefully reopen its storage only.
+
+ DatasetGraph dsgOld = StoreConnection.connectCreate(loc1).getDatasetGraph();
+
+ Txn.executeWrite(dsgOld, ()->dsgOld.delete(quad1));
+ Txn.executeRead(dsg, ()->assertTrue(dsg.contains(quad1)) );
+ Txn.executeRead(dsg2, ()->assertTrue(dsg2.contains(quad1)) ) ;
+
+ TDBInternal.expel(loc1, true);
+ }
+
+// @Test public void compact_2() {
+// }
+
+ @Test public void backup_1() {
+ DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(DIR);
+ Txn.executeWrite(dsg, ()-> {
+ dsg.add(quad1) ;
+ dsg.add(quad2) ;
+ }) ;
+ String file1 = DatabaseMgr.backup(dsg);
+ DatasetGraph dsg2 = RDFDataMgr.loadDatasetGraph(file1);
+ Txn.executeRead(dsg, ()-> {
+ assertTrue(dsg.contains(quad2)) ;
+ assertEquals(2, dsg.getDefaultGraph().size());
+ assertTrue(dsg2.getDefaultGraph().isIsomorphicWith(dsg.getDefaultGraph()));
+ }) ;
+ String file2 = DatabaseMgr.backup(dsg);
+ assertNotEquals(file1, file2);
+ }
+
+}
[26/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionLock.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionLock.java
index 0000000,0000000..ad87de7
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionLock.java
@@@ -1,0 -1,0 +1,71 @@@
++/*
++ * 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.store;
++
++import static org.junit.Assert.*;
++import org.junit.Rule;
++import org.junit.Test;
++import org.junit.rules.TemporaryFolder;
++import org.seaborne.dboe.base.file.AlreadyLocked;
++import org.seaborne.dboe.base.file.Location;
++import org.seaborne.dboe.base.file.ProcessFileLock;
++import org.seaborne.tdb2.sys.StoreConnection;
++
++/**
++ * Tests for {@link ProcessFileLock} in conjunction with {@link StoreConnection}s
++ */
++public class TestStoreConnectionLock {
++ @Rule
++ public TemporaryFolder tempDir = new TemporaryFolder();
++
++ @Test
++ public void lock_store_connection_01() {
++ Location dir = Location.create(tempDir.getRoot().getAbsolutePath());
++ ProcessFileLock lock = StoreConnection.lockForLocation(dir);
++ assertFalse(lock.isLockedHere());
++
++ StoreConnection sConn = StoreConnection.connectCreate(dir);
++ assertEquals(dir, sConn.getLocation());
++ assertEquals(lock, sConn.getLock());
++ assertTrue(lock.isLockedHere());
++
++ StoreConnection.release(dir);
++ assertFalse(lock.isLockedHere());
++ }
++
++ @Test(expected=AlreadyLocked.class)
++ public void lock_store_connection_02() {
++ Location dir = Location.create(tempDir.getRoot().getAbsolutePath());
++ ProcessFileLock lock = StoreConnection.lockForLocation(dir);
++ lock.lockEx();
++ StoreConnection sConn = StoreConnection.connectCreate(dir);
++ }
++// Location dir = Location.create(tempDir.getRoot().getAbsolutePath());
++// // Creating a StoreConnection on the location will obtain the lock
++// StoreConnection.make(dir);
++// // Releasing the connection releases the lock
++// StoreConnection.release(dir);
++// }
++//
++// @Test(expected = TDBException.class)
++// public void location_lock_store_connection_02() throws IOException {
++// Location dir = Location.create(tempDir.getRoot().getAbsolutePath());
++// StoreConnection.make(dir);
++// }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionMapped.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionMapped.java
index 0000000,0000000..ac3127a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionMapped.java
@@@ -1,0 -1,0 +1,50 @@@
++/*
++ * 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 org.junit.AfterClass ;
++import org.junit.BeforeClass ;
++import org.seaborne.dboe.base.block.FileMode ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++import org.seaborne.tdb2.sys.TestOps ;
++
++/** Slow tests - complete cleaning of disk areas each time */
++public class TestStoreConnectionMapped extends AbstractTestStoreConnectionBasics
++{
++ static FileMode mode ;
++
++ @BeforeClass
++ public static void beforeClassFileMode()
++ {
++ mode = SystemTDB.fileMode() ;
++ TestOps.setFileMode(FileMode.mapped) ;
++ }
++
++ @AfterClass
++ public static void afterClassFileMode()
++ {
++ TestOps.setFileMode(mode) ;
++ }
++
++ @Override
++ protected Location getLocation() {
++ return Location.create(ConfigTest.getCleanDir()) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionMem.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionMem.java
index 0000000,0000000..6da2c57
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionMem.java
@@@ -1,0 -1,0 +1,28 @@@
++/*
++ * 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 org.seaborne.dboe.base.file.Location ;
++
++public class TestStoreConnectionMem extends AbstractTestStoreConnectionBasics
++{
++ @Override
++ protected Location getLocation() {
++ return Location.mem("TestStoreConnection") ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestSuiteGraphTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestSuiteGraphTDB.java
index 0000000,0000000..cacbb35
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestSuiteGraphTDB.java
@@@ -1,0 -1,0 +1,40 @@@
++/*
++ * 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 junit.framework.TestSuite ;
++
++import org.junit.runner.RunWith ;
++import org.junit.runners.AllTests ;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.junit.TestFactoryTDB ;
++
++/** Scripted test generation */
++
++@RunWith(AllTests.class)
++public class TestSuiteGraphTDB extends TestSuite
++{
++ static public TestSuite suite() { return new TestSuiteGraphTDB() ; }
++
++ private TestSuiteGraphTDB()
++ {
++ super("TDB-Scripts") ;
++ String manifestMain = ConfigTest.getTestingDataRoot()+"/manifest.ttl" ;
++ TestFactoryTDB.make(this, manifestMain, "TDB-") ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransPromoteTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransPromoteTDB.java
index 0000000,0000000..2814f32
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransPromoteTDB.java
@@@ -1,0 -1,0 +1,72 @@@
++/*
++ * 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.store;
++
++import org.apache.jena.sparql.core.DatasetGraph;
++import org.apache.log4j.Logger;
++import org.seaborne.dboe.transaction.txn.Transaction;
++import org.seaborne.dboe.transaction.txn.TransactionCoordinator;
++import org.seaborne.dboe.transaction.txn.TransactionException;
++import org.seaborne.tdb2.DatabaseMgr ;
++
++public class TestTransPromoteTDB extends AbstractTestTransPromoteTDB2 {
++
++ public TestTransPromoteTDB() {
++ super(getLoggers());
++ }
++
++ private static Logger[] getLoggers() {
++ return new Logger[]{ Logger.getLogger(Transaction.class) } ;
++ }
++
++ @Override
++ protected void setPromotion(boolean b) {
++ TransactionCoordinator.promotion = b ;
++ }
++
++ @Override
++ protected boolean getPromotion() {
++ return TransactionCoordinator.promotion ;
++ }
++
++ @Override
++ protected void setReadCommitted(boolean b) {
++ TransactionCoordinator.readCommittedPromotion = b ;
++ }
++
++ @Override
++ protected boolean getReadCommitted() {
++ return TransactionCoordinator.readCommittedPromotion ;
++ }
++
++ @Override
++ protected Class<? extends Exception> getTransactionExceptionClass() {
++ return TransactionException.class;
++ }
++
++ @Override
++ protected DatasetGraph create() {
++ return DatabaseMgr.createDatasetGraph();
++ }
++
++ @Override
++ protected boolean supportsReadCommitted() {
++ return true;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactionLifecycleTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactionLifecycleTDB.java
index 0000000,0000000..7f1add3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactionLifecycleTDB.java
@@@ -1,0 -1,0 +1,33 @@@
++/*
++ * 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 org.apache.jena.query.Dataset ;
++import org.apache.jena.sparql.transaction.AbstractTestTransactionLifecycle;
++import org.seaborne.tdb2.TDB2Factory ;
++
++/** Transaction tests - from ARQ */
++public class TestTransactionLifecycleTDB extends AbstractTestTransactionLifecycle
++{
++ @Override
++ protected Dataset create() {
++ return TDB2Factory.createDataset() ;
++ }
++}
++
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
index 0000000,0000000..1aed0a6
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
@@@ -1,0 -1,0 +1,204 @@@
++/*
++ * 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.io.StringReader ;
++import java.util.Iterator;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import static org.junit.Assert.*;
++import org.apache.jena.atlas.lib.StrUtils ;
++import org.apache.jena.query.Dataset ;
++import org.apache.jena.query.ReadWrite;
++import org.apache.jena.rdf.model.Model ;
++import org.apache.jena.rdf.model.Statement;
++import org.apache.jena.riot.Lang ;
++import org.apache.jena.riot.RDFDataMgr ;
++import org.apache.jena.sparql.core.Quad;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.dboe.transaction.txn.TransactionException;
++import org.seaborne.tdb2.TDB2Factory ;
++import org.seaborne.tdb2.sys.TDBInternal;
++
++/** Transactions and store connections - extended tests assuming the
++ * basics work. Hence these tests use memory databases.
++ *
++ * For tests of StoreConnection basics:
++ * @see AbstractTestStoreConnectionBasics
++ * @see TestStoreConnectionDirect
++ * @see TestStoreConnectionMapped
++ * @see TestStoreConnectionMem
++ */
++public class TestTransactions
++{
++ // Per-test unique-ish.
++ static int count = 0 ;
++ long x = System.currentTimeMillis()+(count++) ;
++
++ String ns = "http://example/TestTransactions#" ;
++ String data1 = StrUtils.strjoinNL
++ ("prefix : <"+ns+">"
++ ,":s :p '000-"+x+"' ."
++ ,":s :p '111-"+x+"' ."
++ ," :g {"
++ ," :s :p '222-"+x+"' ."
++ ," :s :p '333-"+x+"' ."
++ ," :s :p '444-"+x+"' ."
++ ,"}"
++ ) ;
++ String data2 = StrUtils.strjoinNL
++ ("prefix : <"+ns+">"
++ ,":s :p 'AAA-"+x+"' ."
++ ,":s :p 'BBB-"+x+"' ."
++ ,":s :p 'CCC-"+x+"' ."
++ ,":s :p 'DDD-"+x+"' ."
++ ) ;
++
++ Dataset dataset ;
++ Location location ;
++
++ @Before public void before() {
++ location = Location.mem() ;
++ dataset = TDB2Factory.connectDataset(location) ;
++ }
++
++ @After public void after() {
++ dataset.close() ;
++ TDBInternal.expel(dataset.asDatasetGraph());
++ }
++
++ // Models across transactions
++ @Test public void trans_01() {
++ Model named = dataset.getNamedModel(ns+"g") ;
++ Txn.executeWrite(dataset, ()->{
++ RDFDataMgr.read(dataset, new StringReader(data1), null, Lang.TRIG) ;
++ }) ;
++
++ Txn.executeRead(dataset, ()->{
++ long x1 = Iter.count(dataset.getDefaultModel().listStatements()) ;
++ assertEquals(2, x1) ;
++ long x2 = Iter.count(named.listStatements()) ;
++ assertEquals(3, x2) ;
++ }) ;
++
++ }
++
++ @Test public void trans_02() {
++ Model model = dataset.getDefaultModel() ;
++ Txn.executeWrite(dataset, ()->{
++ RDFDataMgr.read(model, new StringReader(data2), null, Lang.TURTLE) ;
++ }) ;
++ Txn.executeRead(dataset, ()->{
++ assertEquals(4, model.size()) ;
++ }) ;
++ }
++
++ // Iterators and trasnaxction scope.
++
++ private void load(String data) {
++ Txn.executeWrite(dataset, ()->{
++ RDFDataMgr.read(dataset, new StringReader(data), null, Lang.TURTLE) ;
++ }) ;
++ }
++
++ public void iterator_01() {
++ load(data2);
++
++ dataset.begin(ReadWrite.READ);
++ Iterator<Quad> iter = TDBInternal.getDatasetGraphTDB(dataset).find();
++ Iter.consume(iter);
++ dataset.end();
++ }
++
++ @Test(expected=TransactionException.class)
++ public void iterator_02() {
++ load(data2);
++
++ dataset.begin(ReadWrite.READ);
++ Iterator<Quad> iter = dataset.asDatasetGraph().find();
++ dataset.end();
++ iter.next();
++ }
++
++ @Test(expected=TransactionException.class)
++ public void iterator_03() {
++ load(data2);
++
++ dataset.begin(ReadWrite.READ);
++ Iterator<Quad> iter = TDBInternal.getDatasetGraphTDB(dataset).find();
++ dataset.end();
++ iter.next();
++ }
++
++ @Test(expected=TransactionException.class)
++ public void iterator_04() {
++ load(data2);
++ Iterator<Statement> iter = Txn.calculateRead(dataset, ()->dataset.getDefaultModel().listStatements());
++ iter.next();
++ }
++
++ @Test(expected=TransactionException.class)
++ public void iterator_05() {
++ load(data2);
++ Iterator<Statement> iter = Txn.calculateWrite(dataset, ()->dataset.getDefaultModel().listStatements());
++ iter.next();
++ }
++
++ @Test(expected=TransactionException.class)
++ public void iterator_06() {
++ load(data2);
++
++ dataset.begin(ReadWrite.READ);
++ Iterator<Quad> iter = dataset.asDatasetGraph().find();
++ dataset.end();
++
++ dataset.begin(ReadWrite.READ);
++ iter.next();
++ dataset.end();
++ }
++
++// @Test
++// public void iterator_07() {
++// load(data2);
++//
++// // Isolated by copy.
++// Iterator<Quad> iter = TDBInternal.getDatasetGraphTDB(dataset).find();
++//
++// dataset.begin(ReadWrite.READ);
++// iter.next();
++// dataset.end();
++// }
++//
++// @Test
++// public void iterator_08() {
++// load(data2);
++//
++// // Isolated by copy.
++// Iterator<Quad> iter = TDBInternal.getDatasetGraphTDB(dataset).find();
++//
++// dataset.begin(ReadWrite.READ);
++// dataset.end();
++// iter.next();
++// }
++}
++
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTripleTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTripleTable.java
index 0000000,0000000..98e48d1
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTripleTable.java
@@@ -1,0 -1,0 +1,132 @@@
++/*
++ * 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 static org.junit.Assert.*;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.graph.Triple ;
++import org.apache.jena.query.ReadWrite ;
++import org.apache.jena.sparql.util.NodeFactoryExtra ;
++import org.apache.log4j.Level ;
++import org.apache.log4j.Logger ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.setup.TDBBuilder ;
++
++public class TestTripleTable
++{
++ static {
++ Logger.getLogger("org.apache.jena.tdb.info").setLevel(Level.WARN) ;
++ Logger.getLogger("org.apache.jena.tdb.exec").setLevel(Level.WARN) ;
++ }
++
++ private static void add(TripleTable table, Node s, Node p, Node o)
++ {
++ table.add(new Triple(s,p,o)) ;
++ }
++
++ private static void notMatch(TripleTable table, Node s, Node p, Node o)
++ {
++ Iterator<Triple> iter = table.find(s, p, o) ;
++ assertNotNull(iter) ;
++ assertFalse(iter.hasNext()) ;
++ }
++
++ private static void match(TripleTable table, Node s, Node p, Node o)
++ {
++ Iterator<Triple> iter = table.find(s, p, o) ;
++ assertNotNull(iter) ;
++ assertTrue(iter.hasNext()) ;
++ }
++
++
++ private static void contains(TripleTable table, Node s, Node p, Node o)
++ {
++ Iterator<Triple> iter = table.find(s, p, o) ;
++ assertNotNull(iter) ;
++ assertTrue(iter.hasNext()) ;
++ assertEquals(new Triple(s, p, o), iter.next()) ;
++ assertFalse(iter.hasNext()) ;
++ }
++
++ static Node n1 = NodeFactoryExtra.parseNode("<http://example/n1>") ;
++ static Node n2 = NodeFactoryExtra.parseNode("<http://example/n2>") ;
++ static Node n3 = NodeFactoryExtra.parseNode("<http://example/n3>") ;
++ static Node n4 = NodeFactoryExtra.parseNode("<http://example/n4>") ;
++ static Node n5 = NodeFactoryExtra.parseNode("<http://example/n5>") ;
++ static Node n6 = NodeFactoryExtra.parseNode("<http://example/n6>") ;
++
++ @Test public void createTripleTable1()
++ {
++ TripleTable table = createTripleTableMem() ;
++ notMatch(table, n1, n2, n3) ;
++ }
++
++ @Test public void add1()
++ {
++ TripleTable table = createTripleTableMem() ;
++ table.add(new Triple(n1,n2,n3)) ;
++ }
++
++ @Test public void find1()
++ {
++ TripleTable table = createTripleTableMem() ;
++ add(table, n1, n2, n3) ;
++ contains(table, n1, n2, n3) ;
++ notMatch(table, n1, n2, n4) ;
++ }
++
++ @Test public void find2()
++ {
++ TripleTable table = createTripleTableMem() ;
++ add(table, n1, n2, n3) ;
++ add(table, n1, n2, n4) ;
++ contains(table, n1, n2, n3) ;
++ contains(table, n1, n2, n4) ;
++ }
++
++ @Test public void find3()
++ {
++ TripleTable table = createTripleTableMem() ;
++ add(table, n1, n2, n3) ;
++ add(table, n4, n5, n6) ;
++ contains(table, n1, n2, n3) ;
++ contains(table, n4, n5, n6) ;
++ notMatch(table, n1, n2, n4) ;
++ }
++
++ @Test public void find4()
++ {
++ TripleTable table = createTripleTableMem() ;
++ add(table, n1, n2, n3) ;
++ add(table, n4, n5, n6) ;
++ match(table, Node.ANY, n2, n3) ;
++ match(table, null, n2, n3) ;
++ match(table, null, null, null) ;
++ }
++
++ private TripleTable createTripleTableMem()
++ {
++ DatasetGraphTxn dsx = TDBBuilder.build(Location.mem()) ;
++ dsx.begin(ReadWrite.WRITE);
++ DatasetGraphTDB ds = (DatasetGraphTDB)dsx ;
++ return ds.getTripleTable() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/Test_SPARQL_TDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/Test_SPARQL_TDB.java
index 0000000,0000000..0ab4cb4
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/Test_SPARQL_TDB.java
@@@ -1,0 -1,0 +1,221 @@@
++/*
++ * 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 org.junit.Assert.*;
++import org.apache.jena.atlas.lib.StrUtils ;
++import org.apache.jena.graph.Graph ;
++import org.apache.jena.graph.NodeFactory ;
++import org.apache.jena.graph.Triple ;
++import org.apache.jena.query.* ;
++import org.apache.jena.rdf.model.Model ;
++import org.apache.jena.sparql.sse.SSE ;
++import org.apache.jena.update.* ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.tdb2.TDB2 ;
++import org.seaborne.tdb2.TDB2Factory ;
++
++/**
++ * Test SPARQL
++ */
++public class Test_SPARQL_TDB
++{
++ private static Dataset create() {
++ return TDB2Factory.createDataset() ;
++ }
++
++ private static Dataset create(Location location) {
++ return TDB2Factory.connectDataset(location) ;
++ }
++
++ private static String graphName = "http://example/" ;
++ private static Triple triple = SSE.parseTriple("(<x> <y> 123)") ;
++
++ // Standalone graph.
++ @Test public void sparql1()
++ {
++ // Test OpExecutor.execute(OpBGP) for a named graph used as a standalone model
++ Dataset ds = create() ;
++ add(ds, graphName, triple) ;
++ Txn.executeRead(ds, ()->{
++ Model m = ds.getNamedModel(graphName) ;
++ String qs = "SELECT * { ?s ?p ?o . }" ;
++ Query query = QueryFactory.create(qs) ;
++ QueryExecution qexec = QueryExecutionFactory.create(query, m) ;
++ ResultSet rs = qexec.execSelect() ;
++ ResultSetFormatter.consume(rs) ;
++ }) ;
++ }
++
++ // Standalone graph.
++ @Test public void sparql2()
++ {
++ // Test OpExecutor.execute(OpFilter)for a named graph used as a standalone model
++ Dataset ds = create() ;
++ add(ds, graphName, triple) ;
++
++ Txn.executeRead(ds, ()->{
++ Model m = ds.getNamedModel(graphName) ;
++ String qs = "SELECT * { ?s ?p ?o . FILTER ( ?o < 456 ) }" ;
++ Query query = QueryFactory.create(qs) ;
++ try(QueryExecution qexec = QueryExecutionFactory.create(query, m)) {
++ ResultSet rs = qexec.execSelect() ;
++ ResultSetFormatter.consume(rs) ;
++ }
++ }) ;
++ }
++
++ // Requires OpDatasetNames
++ @Test public void sparql3()
++ {
++ Dataset dataset = create() ;
++ // No triple added
++ Txn.executeRead(dataset, ()->{
++ Query query = QueryFactory.create("SELECT ?g { GRAPH ?g {} }") ;
++ QueryExecution qExec = QueryExecutionFactory.create(query, dataset) ;
++ ResultSet rs = qExec.execSelect() ;
++ int n = ResultSetFormatter.consume(rs) ;
++ assertEquals(0, n) ;
++ }) ;
++ }
++
++ @Test public void sparql4()
++ {
++ Dataset dataset = create() ;
++ add(dataset, graphName, triple) ;
++ Txn.executeRead(dataset, ()->{
++ Query query = QueryFactory.create("SELECT ?g { GRAPH ?g {} }") ;
++ QueryExecution qExec = QueryExecutionFactory.create(query, dataset) ;
++ ResultSet rs = qExec.execSelect() ;
++ int n = ResultSetFormatter.consume(rs) ;
++ assertEquals(1, n) ;
++ }) ;
++ }
++
++ @Test public void sparql5()
++ {
++ Dataset dataset = create() ;
++ add(dataset, graphName, triple);
++ Txn.executeRead(dataset, ()->{
++ Query query = QueryFactory.create("ASK { GRAPH <"+graphName+"> {} }") ;
++ boolean b = QueryExecutionFactory.create(query, dataset).execAsk() ;
++ assertEquals(true, b) ;
++ }) ;
++ }
++
++ @Test public void sparql6()
++ {
++ Dataset dataset = create() ;
++ add(dataset, graphName, triple);
++ Txn.executeRead(dataset, ()->{
++ Query query = QueryFactory.create("ASK { GRAPH <http://example/x> {} }") ;
++ boolean b = QueryExecutionFactory.create(query, dataset).execAsk() ;
++ assertEquals(false, b) ;
++ }) ;
++ }
++
++ private static void add(Dataset dataset, String graphName, Triple triple) {
++ Txn.executeWrite(dataset, ()->{
++ Graph g2 = dataset.asDatasetGraph().getGraph(NodeFactory.createURI(graphName)) ;
++ g2.add(triple) ;
++ });
++ }
++
++ // Test transactions effective.
++
++ @Test public void sparql_txn_1()
++ {
++ Dataset dataset = create() ;
++ Txn.executeWrite(dataset, ()->{
++ update(dataset, "INSERT DATA { <x:s> <x:p> <x:o> }") ;
++ }) ;
++ // Explicit trasnaction steps.
++ dataset.begin(ReadWrite.READ) ;
++ try {
++ int n = count(dataset) ;
++ assertEquals(1, n) ;
++ n = count(dataset, "SELECT * { <x:s> <x:p> <x:o>}") ;
++ assertEquals(1, n) ;
++ } finally { dataset.end() ; }
++ }
++
++ @Test public void sparql_txn_2()
++ {
++ Dataset dataset1 = create(Location.mem("foo")) ;
++ Dataset dataset2 = create(Location.mem("foo")) ;
++
++ Txn.executeWrite(dataset1, ()->{
++ update(dataset1, "INSERT DATA { <x:s> <x:p> <x:o> }") ;
++ }) ;
++
++ Txn.executeRead(dataset1, ()->{
++ assertEquals(1, count(dataset1)) ;
++ }) ;
++
++ // Same location.
++ Txn.executeRead(dataset2, ()->{
++ assertEquals(1, count(dataset2)) ;
++ }) ;
++ }
++
++ @Test public void sparql_update_unionGraph()
++ {
++ Dataset ds = TDB2Factory.createDataset() ;
++ // Update concrete default graph
++ Txn.executeWrite(ds, ()->{
++ ds.asDatasetGraph().add(SSE.parseQuad("(<g> <s> <p> 123)")) ;
++ }) ;
++ ds.getContext().setTrue(TDB2.symUnionDefaultGraph) ;
++
++ Txn.executeWrite(ds, ()->{
++ // Update by looking in union graph
++ String us = StrUtils.strjoinNL(
++ "INSERT { GRAPH <http://example/g2> { ?s ?p 'NEW' } }",
++ "WHERE { ",
++ "?s ?p 123",
++ " }" ) ;
++ UpdateRequest req = UpdateFactory.create(us) ;
++ UpdateAction.execute(req, ds) ;
++ }) ;
++
++ Txn.executeRead(ds, ()->{
++ Model m = ds.getNamedModel("http://example/g2") ;
++ assertEquals("Did not find 1 statement in named graph", 1, m.size()) ;
++ }) ;
++ }
++
++ private int count(Dataset dataset)
++ { return count(dataset, "SELECT * { ?s ?p ?o }") ; }
++
++ private int count(Dataset dataset, String queryString)
++
++ {
++ Query query = QueryFactory.create(queryString) ;
++ QueryExecution qExec = QueryExecutionFactory.create(query, dataset) ;
++ ResultSet rs = qExec.execSelect() ;
++ return ResultSetFormatter.consume(rs) ;
++ }
++ private void update(Dataset dataset, String string)
++ {
++ UpdateRequest req = UpdateFactory.create(string) ;
++ UpdateProcessor proc = UpdateExecutionFactory.create(req, dataset) ;
++ proc.execute() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/AbstractTestNodeTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/AbstractTestNodeTable.java
index 0000000,0000000..158e2ff
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/AbstractTestNodeTable.java
@@@ -1,0 -1,0 +1,66 @@@
++/*
++ * 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.nodetable;
++
++import static org.junit.Assert.assertEquals ;
++import static org.junit.Assert.assertNotEquals ;
++import static org.junit.Assert.assertNotNull ;
++
++import org.apache.jena.graph.Node ;
++import org.apache.jena.sparql.util.NodeFactoryExtra ;
++import org.junit.Test ;
++import org.seaborne.tdb2.store.NodeId ;
++
++public abstract class AbstractTestNodeTable
++{
++ protected abstract NodeTable createEmptyNodeTable() ;
++
++ protected void testNode(String str) {
++ testNode(NodeFactoryExtra.parseNode(str)) ;
++ }
++
++ protected void testNode(Node n) {
++ NodeTable nt = createEmptyNodeTable() ;
++ writeNode(nt, n) ;
++ }
++
++ protected static void writeNode(NodeTable nt, String str) {
++ writeNode(nt, NodeFactoryExtra.parseNode(str)) ;
++ }
++
++ protected static void writeNode(NodeTable nt, Node n) {
++ NodeId nodeId = nt.getAllocateNodeId(n) ;
++ assertNotNull(nodeId) ;
++ assertNotEquals(NodeId.NodeDoesNotExist, nodeId) ;
++ assertNotEquals(NodeId.NodeIdAny, nodeId) ;
++
++ Node n2 = nt.getNodeForNodeId(nodeId) ;
++ assertEquals(n, n2) ;
++
++ NodeId nodeId2 = nt.getNodeIdForNode(n) ;
++ assertEquals(nodeId, nodeId2) ;
++ }
++
++ @Test public void nodetable_01() { testNode("<http://example/x>") ; }
++ @Test public void nodetable_02() { testNode("1") ; }
++ @Test public void nodetable_03() { testNode("_:x") ; }
++ @Test public void nodetable_04() { testNode("'x'") ; }
++ @Test public void nodetable_05() { testNode("'x'@en") ; }
++ @Test public void nodetable_06() { testNode("'x'^^<http://example/dt>") ; }
++ @Test public void nodetable_07() { testNode("'نواف'") ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TS_NodeTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TS_NodeTable.java
index 0000000,0000000..62f9388
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TS_NodeTable.java
@@@ -1,0 -1,0 +1,33 @@@
++/*
++ * 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.nodetable;
++
++import org.junit.runner.RunWith ;
++import org.junit.runners.Suite ;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestNodeTableBase.class
++ , TestNodeTableStoredBase.class
++ , TestNodeTableStored.class
++ , TestNodeTable.class
++})
++public class TS_NodeTable
++{
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTable.java
index 0000000,0000000..9b7eda2
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTable.java
@@@ -1,0 -1,0 +1,37 @@@
++/*
++ * 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.nodetable;
++
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.junit.BuildTestLib ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.setup.StoreParamsBuilder ;
++
++public class TestNodeTable extends AbstractTestNodeTable
++{
++ @Override
++ protected NodeTable createEmptyNodeTable()
++ {
++ StoreParams params =
++ StoreParamsBuilder.create()
++ .nodeId2NodeCacheSize(10)
++ .node2NodeIdCacheSize(10)
++ .nodeMissCacheSize(10).build() ;
++ return BuildTestLib.makeNodeTable(Location.mem(), "test", params) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableBase.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableBase.java
index 0000000,0000000..d4bf131
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableBase.java
@@@ -1,0 -1,0 +1,39 @@@
++/*
++ * 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.nodetable;
++
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.junit.BuildTestLib ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.setup.StoreParamsBuilder ;
++
++public class TestNodeTableBase extends AbstractTestNodeTable
++{
++ @Override
++ protected NodeTable createEmptyNodeTable()
++ {
++ StoreParams params =
++ StoreParamsBuilder.create()
++ .nodeId2NodeCacheSize(-1)
++ .node2NodeIdCacheSize(-1)
++ .nodeMissCacheSize(-1).build() ;
++
++ // No cache, no inlining.
++ return BuildTestLib.makeNodeTableBase(Location.mem(), "test", params) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableStored.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableStored.java
index 0000000,0000000..12063e0
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableStored.java
@@@ -1,0 -1,0 +1,45 @@@
++/*
++ * 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.nodetable;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.junit.BuildTestLib ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.setup.StoreParamsBuilder ;
++
++
++public class TestNodeTableStored extends AbstractTestNodeTable
++{
++ static String base = ConfigTest.getTestingDir() ;
++ static Location location = Location.create(base+"/nodetable-test") ;
++
++ @Override
++ protected NodeTable createEmptyNodeTable()
++ {
++ FileOps.ensureDir(location.getDirectoryPath());
++ FileOps.clearDirectory(location.getDirectoryPath());
++ StoreParams params =
++ StoreParamsBuilder.create()
++ .nodeId2NodeCacheSize(10)
++ .node2NodeIdCacheSize(10)
++ .nodeMissCacheSize(10).build() ;
++ return BuildTestLib.makeNodeTable(location, "test", params) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableStoredBase.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableStoredBase.java
index 0000000,0000000..edbc2d8
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableStoredBase.java
@@@ -1,0 -1,0 +1,46 @@@
++/*
++ * 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.nodetable;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.junit.BuildTestLib ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.setup.StoreParamsBuilder ;
++
++
++public class TestNodeTableStoredBase extends AbstractTestNodeTable
++{
++
++ static String base = ConfigTest.getTestingDir() ;
++ static Location location = Location.create(base+"/nodetable-test") ;
++
++ @Override
++ protected NodeTable createEmptyNodeTable()
++ {
++ FileOps.ensureDir(location.getDirectoryPath());
++ FileOps.clearDirectory(location.getDirectoryPath());
++ StoreParams params =
++ StoreParamsBuilder.create()
++ .nodeId2NodeCacheSize(-1)
++ .node2NodeIdCacheSize(-1)
++ .nodeMissCacheSize(-1).build() ;
++ return BuildTestLib.makeNodeTableBase(location, "test", params) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/AbstractTestTupleIndex.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/AbstractTestTupleIndex.java
index 0000000,0000000..6a2e138
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/AbstractTestTupleIndex.java
@@@ -1,0 -1,0 +1,264 @@@
++/*
++ * 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.tupletable;
++
++import static org.apache.jena.atlas.lib.tuple.TupleFactory.tuple ;
++
++import java.util.Iterator ;
++import java.util.Set ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import static org.junit.Assert.*;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.junit.Test ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.store.tupletable.TupleIndex ;
++import static org.seaborne.tdb2.store.tupletable.NData.*;
++
++/** Test TupleIndexes (general) */
++public abstract class AbstractTestTupleIndex
++{
++ protected abstract TupleIndex create(String description) ;
++
++ protected static void add(TupleIndex index, NodeId x1, NodeId x2, NodeId x3)
++ {
++ Tuple<NodeId> tuple = tuple(x1, x2, x3) ;
++ index.add(tuple) ;
++ }
++
++ @Test public void TupleIndex_1()
++ {
++ TupleIndex index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_1()
++ {
++ TupleIndex index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, n2, n3) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ assertTrue(iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_2()
++ {
++ TupleIndex index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, n2, null) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ assertTrue(iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_3()
++ {
++ TupleIndex index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, null, n3) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ assertTrue(iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_4()
++ {
++ TupleIndex index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ assertTrue(iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_5()
++ {
++ TupleIndex index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ add(index, n1, n2, n4) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, n2, n3) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++ assertEquals(1, x.size()) ;
++ assertTrue(x.contains(tuple(n1, n2, n3))) ;
++ assertFalse(x.contains(tuple(n1, n2, n4))) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_6()
++ {
++ TupleIndex index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ add(index, n1, n2, n4) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, n2, NodeId.NodeIdAny) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++ assertEquals(2, x.size()) ;
++ assertTrue(x.contains(tuple(n1, n2, n3))) ;
++ assertTrue(x.contains(tuple(n1, n2, n4))) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_7()
++ {
++ TupleIndex index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ add(index, n1, n2, n4) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++ assertEquals(2, x.size()) ;
++ assertTrue(x.contains(tuple(n1, n2, n3))) ;
++ assertTrue(x.contains(tuple(n1, n2, n4))) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_8()
++ {
++ TupleIndex index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ add(index, n2, n3, n4) ;
++
++ {
++ Tuple<NodeId> tuple2 = tuple(n1, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++ assertEquals(1, x.size()) ;
++ assertTrue(x.contains(tuple(n1, n2, n3))) ;
++ }
++
++ {
++ Tuple<NodeId> tuple2 = tuple(n2, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++ assertEquals(1, x.size()) ;
++ assertTrue(x.contains(tuple(n2, n3, n4))) ;
++ }
++ }
++
++ @Test public void TupleIndexRecordPOS_1()
++ {
++ TupleIndex index = create("POS") ;
++ add(index, n1, n2, n3) ;
++ Tuple<NodeId> tuple2 = tuple(n1, n2, n3) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ assertTrue("Can't find tuple", iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordPOS_2()
++ {
++ TupleIndex index = create("POS") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(null, n2, null) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ assertTrue("Can't find tuple",iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++
++ @Test public void TupleIndexRecordPOS_3()
++ {
++ TupleIndex index = create("POS") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(null, n2, n3) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ assertTrue("Can't find tuple", iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordFindNot_1()
++ {
++ TupleIndex index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(n4, n5, n6) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ assertNotNull(iter) ;
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordFindNot_2()
++ {
++ TupleIndex index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, n5, n6) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordFindNot_3()
++ {
++ TupleIndex index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, null, n6) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordFindNot_4()
++ {
++ TupleIndex index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ add(index, n1, n5, n6) ;
++
++ Tuple<NodeId> tuple2 = tuple(n4, n5, n6) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordFindNot_5()
++ {
++ TupleIndex index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ add(index, n1, n5, n6) ;
++
++ Tuple<NodeId> tuple2 = tuple(n2, n5, n6) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordFindNot_6()
++ {
++ TupleIndex index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ add(index, n4, n5, n6) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, null, n6) ;
++ Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++ assertFalse(iter.hasNext()) ;
++ }
++
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/NData.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/NData.java
index 0000000,0000000..c22451f
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/NData.java
@@@ -1,0 -1,0 +1,37 @@@
++/*
++ * 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.tupletable;
++
++import org.apache.jena.atlas.lib.BitsLong;
++import org.seaborne.tdb2.store.NodeId;
++import org.seaborne.tdb2.store.NodeIdFactory;
++import org.seaborne.tdb2.store.NodeIdType;
++
++public class NData {
++ public static NodeId n1 = create(1) ;
++ public static NodeId n2 = create(2) ;
++ public static NodeId n3 = create(3) ;
++ public static NodeId n4 = NodeIdFactory.createValue(NodeIdType.XSD_INTEGER, 1);
++ public static NodeId n5 = NodeIdFactory.createValue(NodeIdType.XSD_INTEGER, 2);
++ // -2 as inlined.
++ public static NodeId n6 = NodeIdFactory.createValue(NodeIdType.XSD_INTEGER, BitsLong.clear(-2L, 56, 64));
++
++ private static NodeId create(long v) {
++ return NodeIdFactory.createPtr(v);
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TS_TupleTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TS_TupleTable.java
index 0000000,0000000..607ffe8
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TS_TupleTable.java
@@@ -1,0 -1,0 +1,31 @@@
++/*
++ * 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.tupletable;
++
++import org.junit.runner.RunWith;
++import org.junit.runners.Suite;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestTupleIndexRecord.class,
++ TestTupleIndexRecordDirect.class,
++ TestTupleTable.class
++} )
++
++public class TS_TupleTable
++{ }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecord.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecord.java
index 0000000,0000000..ce62f16
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecord.java
@@@ -1,0 -1,0 +1,42 @@@
++/*
++ * 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.tupletable;
++
++import org.apache.jena.atlas.lib.tuple.TupleMap ;
++import org.seaborne.dboe.base.file.FileSet ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.index.IndexParams ;
++import org.seaborne.dboe.index.RangeIndex ;
++import org.seaborne.tdb2.junit.BuildTestLib ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++
++public class TestTupleIndexRecord extends AbstractTestTupleIndex
++{
++ static RecordFactory factory = new RecordFactory(3*SystemTDB.SizeOfNodeId, 0) ;
++
++ @Override
++ protected TupleIndexRecord create(String description)
++ {
++ IndexParams indexParams = StoreParams.getDftStoreParams() ;
++ RangeIndex rIdx = BuildTestLib.buildRangeIndex(FileSet.mem(), factory, indexParams) ;
++ TupleMap tmap = TupleMap.create("SPO", description) ;
++ TupleIndexRecord index = new TupleIndexRecord(3, tmap, description, factory, rIdx) ;
++ return index ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecordDirect.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecordDirect.java
index 0000000,0000000..a48c87b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecordDirect.java
@@@ -1,0 -1,0 +1,314 @@@
++/*
++ * 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.tupletable;
++
++import static org.seaborne.tdb2.store.tupletable.NData.*;
++import static org.apache.jena.atlas.lib.tuple.TupleFactory.tuple ;
++
++import java.util.Iterator ;
++import java.util.Set ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import static org.junit.Assert.*;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.atlas.lib.tuple.TupleMap ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.FileSet ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.index.IndexParams ;
++import org.seaborne.dboe.index.RangeIndex ;
++import org.seaborne.tdb2.junit.BuildTestLib ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++
++public class TestTupleIndexRecordDirect
++{
++ static RecordFactory factory = new RecordFactory(3*SystemTDB.SizeOfNodeId, 0) ;
++
++ static TupleIndexRecord create(String description)
++ {
++ IndexParams indexParams = StoreParams.getDftStoreParams() ;
++ RangeIndex rIdx = BuildTestLib.buildRangeIndex(FileSet.mem(), factory, indexParams) ;
++ TupleMap tmap = TupleMap.create("SPO", description) ;
++ TupleIndexRecord index = new TupleIndexRecord(3, tmap, description, factory, rIdx) ;
++ return index ;
++ }
++
++ static void add(TupleIndexRecord index, NodeId x1, NodeId x2, NodeId x3)
++ {
++ Tuple<NodeId> tuple = tuple(x1, x2, x3) ;
++ index.add(tuple) ;
++ }
++
++ @Test public void TupleIndexRecord_1()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_1()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, n2, n3) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ assertTrue(iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_2()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, n2, null) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ assertTrue(iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_3()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, null, n3) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ assertNull(iter) ;
++ iter = index.findOrPartialScan(tuple2) ;
++ assertTrue(iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_4()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ assertTrue(iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_5()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ add(index, n1, n2, n4) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, n2, n3) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++ assertEquals(1, x.size()) ;
++ assertTrue(x.contains(tuple(n1, n2, n3))) ;
++ assertFalse(x.contains(tuple(n1, n2, n4))) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_6()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ add(index, n1, n2, n4) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, n2, NodeId.NodeIdAny) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++ assertEquals(2, x.size()) ;
++ assertTrue(x.contains(tuple(n1, n2, n3))) ;
++ assertTrue(x.contains(tuple(n1, n2, n4))) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_7()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ add(index, n1, n2, n4) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++ assertEquals(2, x.size()) ;
++ assertTrue(x.contains(tuple(n1, n2, n3))) ;
++ assertTrue(x.contains(tuple(n1, n2, n4))) ;
++ }
++
++ @Test public void TupleIndexRecordSPO_8()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ add(index, n2, n3, n4) ;
++
++ {
++ Tuple<NodeId> tuple2 = tuple(n1, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++ assertEquals(1, x.size()) ;
++ assertTrue(x.contains(tuple(n1, n2, n3))) ;
++ }
++
++ {
++ Tuple<NodeId> tuple2 = tuple(n2, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++ assertEquals(1, x.size()) ;
++ assertTrue(x.contains(tuple(n2, n3, n4))) ;
++ }
++ }
++
++ @Test public void TupleIndexRecordPOS_1()
++ {
++ TupleIndexRecord index = create("POS") ;
++ add(index, n1, n2, n3) ;
++ Tuple<NodeId> tuple2 = tuple(n1, n2, n3) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ assertTrue("Can't find tuple", iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordPOS_2()
++ {
++ TupleIndexRecord index = create("POS") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(null, n2, null) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ assertTrue("Can't find tuple",iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++
++ @Test public void TupleIndexRecordPOS_3()
++ {
++ TupleIndexRecord index = create("POS") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(null, n2, n3) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ assertTrue("Can't find tuple", iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordFindScan_1()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ Tuple<NodeId> tuple2 = tuple(n1, null, n3) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ assertNull(iter) ;
++ iter = index.findOrPartialScan(tuple2) ;
++ assertTrue(iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordFindScan_2()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ add(index, n1, n2, n4) ;
++
++
++ Tuple<NodeId> tuple2 = tuple(null, null, n3) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ assertNull(iter) ;
++
++ iter = index.findOrPartialScan(tuple2) ;
++ assertNull(iter) ;
++
++ iter = index.findOrScan(tuple2) ;
++ assertTrue(iter.hasNext()) ;
++ iter.next();
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordFindNot_1()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(n4, n5, n6) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ assertNotNull(iter) ;
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordFindNot_2()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, n5, n6) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordFindNot_3()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, null, n6) ;
++ Iterator<Tuple<NodeId>> iter = index.findOrPartialScan(tuple2) ;
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordFindNot_4()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ add(index, n1, n5, n6) ;
++
++ Tuple<NodeId> tuple2 = tuple(n4, n5, n6) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordFindNot_5()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ add(index, n1, n5, n6) ;
++
++ Tuple<NodeId> tuple2 = tuple(n2, n5, n6) ;
++ Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++ assertFalse(iter.hasNext()) ;
++ }
++
++ @Test public void TupleIndexRecordFindNot_6()
++ {
++ TupleIndexRecord index = create("SPO") ;
++ add(index, n1, n2, n3) ;
++ add(index, n4, n5, n6) ;
++
++ Tuple<NodeId> tuple2 = tuple(n1, null, n6) ;
++ Iterator<Tuple<NodeId>> iter = index.findOrPartialScan(tuple2) ;
++ assertFalse(iter.hasNext()) ;
++ }
++
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleTable.java
index 0000000,0000000..4d27266
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleTable.java
@@@ -1,0 -1,0 +1,151 @@@
++/*
++ * 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.tupletable;
++
++import static org.apache.jena.atlas.lib.tuple.TupleFactory.tuple ;
++
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import static org.junit.Assert.*;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++import static org.seaborne.tdb2.store.tupletable.NData.*;
++
++public class TestTupleTable
++{
++ static RecordFactory factory = new RecordFactory(3*SystemTDB.SizeOfNodeId, 0) ;
++
++ static private TupleTable create()
++ {
++ TupleIndex idxSPO = TestTupleIndexRecordDirect.create("SPO") ;
++ TupleIndex idxPOS = TestTupleIndexRecordDirect.create("POS") ;
++ TupleIndex idxOSP = TestTupleIndexRecordDirect.create("OSP") ;
++ TupleIndex x[] = { idxSPO, idxPOS, idxOSP } ;
++ TupleTable table = new TupleTable(3, x) ;
++ return table ;
++ }
++
++ static private TupleTable create2()
++ {
++ TupleIndex idxSPO = TestTupleIndexRecordDirect.create("SPO") ;
++ TupleIndex x[] = { idxSPO } ;
++ TupleTable table = new TupleTable(3, x) ;
++ return table ;
++ }
++
++ static void add(TupleTable table, NodeId x1, NodeId x2, NodeId x3)
++ {
++ Tuple<NodeId> tuple = tuple(x1, x2, x3) ;
++ table.add(tuple) ;
++ }
++
++ @Test public void create1() { create() ; }
++
++ @Test public void createFind1()
++ {
++ TupleTable table = create() ;
++ add(table, n1, n2, n3) ;
++ // Cast removes compile lint warning.
++ Tuple<NodeId> pat = tuple((NodeId)null, null, null) ;
++ Iterator<Tuple<NodeId>> iter = table.find(pat) ;
++ List<Tuple<NodeId>> x = Iter.toList(iter) ;
++ int z = x.size() ;
++ assertEquals(1, z) ;
++ Tuple<NodeId> e1 = x.get(0) ;
++ assertEquals(tuple(n1, n2, n3) , e1) ;
++ }
++
++ @Test public void createFind2()
++ {
++ TupleTable table = create() ;
++ add(table, n1, n2, n3) ;
++ add(table, n1, n2, n4) ;
++
++ Tuple<NodeId> pat = tuple(null, n2, null) ;
++ Iterator<Tuple<NodeId>> iter = table.find(pat) ;
++ assertNotNull(iter) ;
++ List<Tuple<NodeId>> x = Iter.toList(iter) ;
++ int z = x.size() ;
++ assertEquals(2, z) ;
++
++ Tuple<NodeId> e1 = x.get(0) ;
++ Tuple<NodeId> e2 = x.get(1) ;
++ assertEquals(tuple(n1, n2, n3) , e1) ;
++ assertEquals(tuple(n1, n2, n4) , e2) ;
++ }
++
++ @Test public void createFind3()
++ {
++ // test scan
++ TupleTable table = create2() ;
++ add(table, n1, n2, n3) ;
++ add(table, n1, n2, n4) ;
++
++ Tuple<NodeId> pat = tuple(n1, null, n3) ;
++ Iterator<Tuple<NodeId>> iter = table.find(pat) ;
++ assertNotNull(iter) ;
++ List<Tuple<NodeId>> x = Iter.toList(iter) ;
++ int z = x.size() ;
++ assertEquals(1, z) ;
++
++ Tuple<NodeId> e1 = x.get(0) ;
++ assertEquals(tuple(n1, n2, n3) , e1) ;
++ }
++
++ @Test public void createFind4()
++ {
++ // test scan
++ TupleTable table = create2() ;
++ add(table, n1, n2, n3) ;
++ add(table, n1, n2, n4) ;
++
++ Tuple<NodeId> pat = tuple(null, null, n3) ;
++ Iterator<Tuple<NodeId>> iter = table.find(pat) ;
++ assertNotNull(iter) ;
++ List<Tuple<NodeId>> x = Iter.toList(iter) ;
++ int z = x.size() ;
++ assertEquals(1, z) ;
++
++ Tuple<NodeId> e1 = x.get(0) ;
++ assertEquals(tuple(n1, n2, n3) , e1) ;
++ }
++
++ @Test public void createFind5()
++ {
++ // test scan
++ TupleTable table = create2() ;
++ add(table, n1, n2, n3) ;
++ add(table, n1, n2, n4) ;
++
++ Tuple<NodeId> pat = tuple(null, NodeId.NodeIdAny, n3) ;
++ Iterator<Tuple<NodeId>> iter = table.find(pat) ;
++ assertNotNull(iter) ;
++ List<Tuple<NodeId>> x = Iter.toList(iter) ;
++ int z = x.size() ;
++ assertEquals(1, z) ;
++
++ Tuple<NodeId> e1 = x.get(0) ;
++ assertEquals(tuple(n1, n2, n3) , e1) ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/value/TestDoubleNode62.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/value/TestDoubleNode62.java
index 0000000,0000000..112bd52
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/value/TestDoubleNode62.java
@@@ -1,0 -1,0 +1,123 @@@
++/*
++ * 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.store.value;
++
++import org.apache.jena.atlas.lib.BitsLong;
++import org.junit.Test;
++import org.seaborne.tdb2.store.value.DoubleNode62;
++
++import static org.junit.Assert.*;
++
++public class TestDoubleNode62 {
++ @Test public void double_01() { testRoundTripDouble(1d); }
++ @Test public void double_02() { testRoundTripDouble(-1d); }
++ @Test public void double_03() { testRoundTripDouble(-1111111111e50d); }
++ @Test public void double_04() { testRoundTripDouble(1111111111e50d); }
++
++ @Test public void double_05() { testNoEncoding(1e300); }
++ @Test public void double_06() { testNoEncoding(1e100); }
++ @Test public void double_07() { testNoEncoding(1e78); }
++ @Test public void double_08() { testNoEncoding(2e77); }
++ @Test public void double_09() { testRoundTripDouble(1e77); }
++
++ @Test public void double_10() { testNoEncoding(3e-300); }
++ @Test public void double_11() { testNoEncoding(3e-100); }
++ @Test public void double_12() { testNoEncoding(3e-77); }
++ @Test public void double_13() { testRoundTripDouble(3.5e-77); }
++ @Test public void double_14() { testRoundTripDouble(4e-77); }
++ @Test public void double_15() { testRoundTripDouble(1e-76); }
++ @Test public void double_16() { testRoundTripDouble(1e-75); }
++
++ @Test public void double_20() { testRoundTripDouble(Double.POSITIVE_INFINITY); }
++ @Test public void double_21() { testRoundTripDouble(Double.NEGATIVE_INFINITY); }
++ @Test public void double_22() { testRoundTripDouble(Double.NaN); }
++ @Test public void double_23() { testNoEncoding(Double.MAX_VALUE); }
++ @Test public void double_24() { testNoEncoding(Double.MIN_NORMAL); }
++ @Test public void double_25() { testNoEncoding(Double.MIN_VALUE); }
++
++ @Test public void double_30() { testRoundTripDouble(DoubleNode62.POSITIVE_INFINITY); }
++ @Test public void double_31() { testRoundTripDouble(DoubleNode62.NEGATIVE_INFINITY); }
++ @Test public void double_32() { testRoundTripDouble(DoubleNode62.NaN); }
++ @Test public void double_33() { testNoEncoding(DoubleNode62.MAX_VALUE); }
++ @Test public void double_34() { testNoEncoding(DoubleNode62.MIN_NORMAL); }
++ @Test public void double_35() { testNoEncoding(DoubleNode62.MIN_VALUE); }
++
++ @Test public void double_40() { sameValue(DoubleNode62.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); }
++ @Test public void double_41() { sameValue(DoubleNode62.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY); }
++ @Test public void double_42() { sameValue(DoubleNode62.NaN, Double.NaN); }
++
++ @Test public void double_50() { testConst(DoubleNode62.POSITIVE_INFINITY_BITS, 0x1ff0000000000000L); }
++ @Test public void double_51() { testConst(DoubleNode62.NEGATIVE_INFINITY_BITS, 0x3ff0000000000000L); }
++ @Test public void double_52() { testConst(DoubleNode62.NaN_BITS, 0x1ff8000000000000L); }
++ @Test public void double_53() { testConst(DoubleNode62.MAX_VALUE_BITS, 0x3fefffffffffffffL); }
++ @Test public void double_54() { testConst(DoubleNode62.MIN_NORMAL_BITS, 0x0010000000000000L); }
++ @Test public void double_55() { testConst(DoubleNode62.MIN_VALUE_BITS, 0x01L); }
++
++ private void sameValue(double d1, double d2) {
++ // Not d1 == d2 - NaN != NaN
++ assertEquals(Double.valueOf(d1), Double.valueOf(d2));
++ }
++
++ private static void testConst(long x, long expected) {
++ //print(expected);
++ //print(x);
++ assertEquals(expected, x);
++ double d = DoubleNode62.unpack(x);
++ long z = DoubleNode62.pack(d);
++ assertEquals(expected, z);
++ }
++
++ private void testNoEncoding(double d) {
++ testRoundTripDouble(d, false);
++ }
++
++ private static void testRoundTripDouble(double d) {
++ testRoundTripDouble(d, true);
++ }
++
++ private static void testRoundTripDouble(double d, boolean valid) {
++ //System.out.printf("Double: %.2e\n", d);
++ long x0 = Double.doubleToRawLongBits(d);
++ //print(x0);
++ long x = DoubleNode62.pack(d);
++ //print(x);
++ if ( x == DoubleNode62.NO_ENCODING ) {
++ if ( valid )
++ fail("Expect no encoding");
++
++ //System.out.println("No encoding");
++ //System.out.println();
++ return;
++ }
++
++ double d2 = DoubleNode62.unpack(x);
++
++ Double double1 = d ;
++ Double double2 = d2 ;
++ assertEquals(double1, double2);
++ }
++
++ private static void print(long x) {
++ long z[] = new long[4];
++ for ( int i = 0 ; i < 4 ; i++ ) {
++ z[3-i] = BitsLong.unpack(x, i*16, (i+1)*16) ;
++ }
++ System.out.printf("0x%04X %04X %04X %04X\n", z[0], z[1], z[2], z[3]);
++ }
++}
[10/50] [abbrv] jena git commit: Expel datasets based on
container/storage location.
Posted by an...@apache.org.
Expel datasets based on container/storage location.
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/d8fd29aa
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/d8fd29aa
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/d8fd29aa
Branch: refs/heads/jena-tdb2
Commit: d8fd29aa36e5d4e5da71c7f06f149ea2aa349e7b
Parents: 10f2bb1
Author: Andy Seaborne <an...@seaborne.org>
Authored: Sun Sep 3 17:14:56 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Sun Sep 3 17:14:56 2017 +0100
----------------------------------------------------------------------
.../java/org/seaborne/tdb2/DatabaseMgr.java | 4 +-
.../tdb2/store/DatasetGraphSwitchable.java | 12 +-
.../seaborne/tdb2/sys/DatabaseConnection.java | 12 +-
.../java/org/seaborne/tdb2/sys/DatabaseOps.java | 4 +-
.../org/seaborne/tdb2/sys/StoreConnection.java | 10 +-
.../java/org/seaborne/tdb2/sys/SystemTDB.java | 33 +++---
.../java/org/seaborne/tdb2/sys/TDBInternal.java | 20 +++-
.../tdb2/graph/TestDatasetGraphAccessorTDB.java | 15 ++-
.../tdb2/graph/TestDatasetGraphTDB.java | 18 ++-
.../tdb2/graph/TestGraphOverDatasetTDB.java | 20 +++-
.../org/seaborne/tdb2/graph/TestGraphsTDB1.java | 15 ++-
.../test/java/org/seaborne/tdb2/junit/TL.java | 39 ++++---
.../tdb2/setup/TestStoreParamsCreate.java | 26 +++--
.../org/seaborne/tdb2/solver/TestSolverTDB.java | 4 +-
.../org/seaborne/tdb2/solver/TestStats.java | 69 +++++------
.../org/seaborne/tdb2/store/TestDatasetTDB.java | 6 +-
.../tdb2/store/TestDatasetTDBPersist.java | 114 +++++++++----------
.../tdb2/store/TestDynamicDatasetTDB.java | 7 +-
.../seaborne/tdb2/store/TestGraphNamedTDB.java | 8 +-
.../org/seaborne/tdb2/store/TestGraphTDB.java | 6 +-
.../seaborne/tdb2/store/TestTransactions.java | 2 +-
.../org/seaborne/tdb2/sys/TestDatabaseOps.java | 2 -
22 files changed, 273 insertions(+), 173 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/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
index b4dfd23..098a646 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/DatabaseMgr.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/DatabaseMgr.java
@@ -90,9 +90,9 @@ public class DatabaseMgr {
return TDBInternal.isBackedByTDB(datasetGraph);
}
- /** Return the location of a DatasetGraph if it is backed by TDB, else null */
+ /** Return the location of a DatasetGraph if it is backed by TDB, else null. */
public static Location location(DatasetGraph datasetGraph) {
- DatasetGraphTDB dsg = requireDirect(datasetGraph);
+ DatasetGraphSwitchable dsg = requireSwitchable(datasetGraph);
if ( dsg == null )
return null ;
return dsg.getLocation();
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphSwitchable.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphSwitchable.java b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphSwitchable.java
index 115b304..9469a1d 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphSwitchable.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/DatasetGraphSwitchable.java
@@ -27,7 +27,9 @@ 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.apache.jena.sparql.core.DatasetGraph ;
+import org.apache.jena.sparql.core.DatasetPrefixStorage ;
+import org.seaborne.dboe.base.file.Location ;
final
public class DatasetGraphSwitchable extends DatasetGraphWrapperTxn /* Until ARQ catches up with promote */
@@ -43,12 +45,14 @@ public class DatasetGraphSwitchable extends DatasetGraphWrapperTxn /* Until ARQ
private final AtomicReference<DatasetGraph> dsgx = new AtomicReference<>();
// Null for in-memory datasets.
private final Path basePath;
+ private final Location location ;
- public DatasetGraphSwitchable(Path base, DatasetGraph dsg) {
+ public DatasetGraphSwitchable(Path base, Location location, DatasetGraph dsg) {
// Don't use the slot in datasetGraphWrapper - use the AtomicReference
super(null) ;
dsgx.set(dsg);
- this.basePath = base;
+ this.basePath = base;
+ this.location = location;
}
/** Is this {@code DatasetGraphSwitchable} just a holder for a {@code DatasetGraph}?
@@ -58,6 +62,8 @@ public class DatasetGraphSwitchable extends DatasetGraphWrapperTxn /* Until ARQ
public Path getContainerPath() { return basePath; }
+ public Location getLocation() { return location; }
+
/** The dataset to use for redirection - can be overridden.
* It is also guaranteed that this is called only once per
* delegated call. Changes to the wrapped object can be
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/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
index 0e22f8f..e9e6c27 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseConnection.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseConnection.java
@@ -114,16 +114,13 @@ public class DatabaseConnection {
* Does not expel from {@link StoreConnection}.
*/
public static synchronized void internalExpel(Location location, boolean force) {
+ // ** Check it is a container location
DatabaseConnection dbConn = cache.get(location) ;
- if (dbConn == null) return ;
- cache.remove(location) ;
+ if ( dbConn == null )
+ return ;
dbConn.isValid = false;
//dbConn.datasetGraph = null;
//dbConn.datasetGraphSwitchable = null;
-
- // 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() ) {
@@ -144,10 +141,11 @@ public class DatabaseConnection {
Set<Location> x = new HashSet<>(cache.keySet()) ;
for (Location loc : x)
internalExpel(loc, true) ;
+ if ( ! cache.isEmpty() )
+ System.err.println("DatabaseConnection: Cache not empty!");
cache.clear() ;
}
-
// One of the other.
private final DatasetGraphSwitchable datasetGraphSwitchable;
private final DatasetGraph datasetGraph;
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
index b985798..bb34ed3 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/DatabaseOps.java
@@ -81,7 +81,7 @@ public class DatabaseOps {
private static DatasetGraphSwitchable createSwitchable(Location location) {
if ( location.isMem() ) {
DatasetGraph dsg = StoreConnection.connectCreate(location).getDatasetGraph();
- return new DatasetGraphSwitchable(null, dsg);
+ return new DatasetGraphSwitchable(null, location, dsg);
}
// Exists?
if ( ! location.exists() )
@@ -97,7 +97,7 @@ public class DatabaseOps {
}
Location loc2 = IOX.asLocation(db);
DatasetGraphTDB dsg = StoreConnection.connectCreate(loc2).getDatasetGraphTDB();
- DatasetGraphSwitchable appDSG = new DatasetGraphSwitchable(path, dsg);
+ DatasetGraphSwitchable appDSG = new DatasetGraphSwitchable(path, location, dsg);
return appDSG;
}
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java
index 54d863b..21d5377 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/StoreConnection.java
@@ -32,6 +32,8 @@ import org.seaborne.dboe.base.file.ChannelManager ;
import org.seaborne.dboe.base.file.Location ;
import org.seaborne.dboe.base.file.ProcessFileLock;
import org.seaborne.dboe.sys.Names;
+import org.seaborne.dboe.transaction.txn.TransactionCoordinator ;
+import org.seaborne.dboe.transaction.txn.TransactionException ;
import org.seaborne.tdb2.setup.StoreParams ;
import org.seaborne.tdb2.setup.TDBBuilder ;
import org.seaborne.tdb2.store.DatasetGraphTDB ;
@@ -124,14 +126,16 @@ public class StoreConnection
StoreConnection sConn = cache.get(location) ;
if (sConn == null) return ;
- // if (!force && sConn.transactionManager.activeTransactions())
- // throw new TDBTransactionException("Can't expel: Active transactions for location: " + location) ;
+ TransactionCoordinator txnCoord = sConn.getDatasetGraphTDB().getTxnSystem().getTxnMgr();
+ if (!force && txnCoord.countActive() > 0 )
+ throw new TransactionException("Can't expel: Active transactions for location: " + location) ;
// No transactions at this point
// (or we don't care and are clearing up forcefully.)
- sConn.getDatasetGraphTDB().getTxnSystem().getTxnMgr().shutdown();
sConn.getDatasetGraphTDB().shutdown() ;
+ // Done by DatasetGraphTDB()
+ //txnCoord.shutdown();
sConn.isValid = false ;
cache.remove(location) ;
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/main/java/org/seaborne/tdb2/sys/SystemTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/SystemTDB.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/SystemTDB.java
index 6531310..51ef995 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/SystemTDB.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/SystemTDB.java
@@ -25,9 +25,6 @@ import org.apache.jena.atlas.io.IO ;
import org.apache.jena.atlas.lib.PropertyUtils ;
import org.apache.jena.atlas.logging.Log ;
import org.apache.jena.query.ARQ ;
-import org.apache.jena.query.Dataset ;
-import org.apache.jena.query.ReadWrite ;
-import org.apache.jena.sparql.core.DatasetGraph ;
import org.apache.jena.sparql.engine.optimizer.reorder.ReorderLib ;
import org.apache.jena.sparql.engine.optimizer.reorder.ReorderTransformation ;
import org.apache.jena.sparql.util.Symbol ;
@@ -38,7 +35,6 @@ import org.seaborne.dboe.base.record.RecordFactory ;
import org.seaborne.dboe.sys.Sys;
import org.seaborne.tdb2.TDB2 ;
import org.seaborne.tdb2.TDBException ;
-import org.seaborne.tdb2.store.DatasetGraphTxn ;
import org.seaborne.tdb2.store.NodeId ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
@@ -402,20 +398,19 @@ public class SystemTDB
throw new TDBException("Unrecognized file mode (not one of 'default', 'direct' or 'mapped': "+x) ;
}
- public static Dataset setNonTransactional(Dataset dataset) {
- if ( dataset.isInTransaction() )
- return dataset ; // And hope it's a write transaction.
- dataset.begin(ReadWrite.WRITE);
- //Or wrap DatasetGraphTDB?
- return dataset ;
- }
-
- public static DatasetGraph setNonTransactional(DatasetGraph dataset) {
- DatasetGraphTxn dsgx = (DatasetGraphTxn)dataset ;
- if ( dsgx.isInTransaction() )
- return dataset ;
- dsgx.begin(ReadWrite.WRITE);
- return dataset ;
- }
+// public static Dataset setNonTransactional(Dataset dataset) {
+// if ( dataset.isInTransaction() )
+// return dataset ; // And hope it's a write transaction.
+// dataset.begin(ReadWrite.WRITE);
+// //Or wrap DatasetGraphTDB?
+// return dataset ;
+// }
+//
+// public static DatasetGraph setNonTransactional(DatasetGraph dataset) {
+// if ( dataset.isInTransaction() )
+// return dataset ;
+// dataset.begin(ReadWrite.WRITE);
+// return dataset ;
+// }
}
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java
index 25c1688..3bd7427 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java
@@ -129,12 +129,22 @@ public class TDBInternal {
return null;
}
- /** Stop managing a location. Use with great care (testing only). */
- public static synchronized void expel(Location location, boolean force) {
- DatabaseConnection.internalExpel(location, force);
- StoreConnection.internalExpel(location, force);
+ /** Stop managing a DatasetGraph. Use with great care (testing only). */
+ public static synchronized void expel(DatasetGraph dsg) {
+ Location locContainer = null;
+ Location locStorage = null;
+
+ if ( dsg instanceof DatasetGraphSwitchable ) {
+ locContainer = ((DatasetGraphSwitchable)dsg).getLocation();
+ dsg = ((DatasetGraphSwitchable)dsg).getWrapped();
+ }
+ if ( dsg instanceof DatasetGraphTDB )
+ locStorage = ((DatasetGraphTDB)dsg).getLocation();
+
+ DatabaseConnection.internalExpel(locContainer, false);
+ StoreConnection.internalExpel(locStorage, false);
}
-
+
/**
* Reset the whole TDB system.
* Use with great care.
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphAccessorTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphAccessorTDB.java b/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphAccessorTDB.java
index 327ca47..8184154 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphAccessorTDB.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphAccessorTDB.java
@@ -18,17 +18,30 @@
package org.seaborne.tdb2.graph;
import org.apache.jena.query.DatasetAccessorFactory ;
+import org.apache.jena.query.ReadWrite ;
import org.apache.jena.sparql.core.DatasetGraph ;
import org.apache.jena.web.AbstractTestDatasetGraphAccessor ;
import org.apache.jena.web.DatasetGraphAccessor ;
+import org.junit.After ;
+import org.junit.Before ;
import org.seaborne.tdb2.junit.TL ;
public class TestDatasetGraphAccessorTDB extends AbstractTestDatasetGraphAccessor
{
+ DatasetGraph dsg = TL.createTestDatasetGraphMem() ;
+ @Before public void before() {
+ dsg.begin(ReadWrite.WRITE);
+ }
+
+ @After public void after() {
+ dsg.abort();
+ dsg.end();
+ TL.expel(dsg);
+ }
+
@Override
protected DatasetGraphAccessor getDatasetUpdater()
{
- DatasetGraph dsg = TL.createTestDatasetGraphMem() ;
return DatasetAccessorFactory.make(dsg) ;
}
}
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphTDB.java b/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphTDB.java
index 12092fb..0cd2bca 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphTDB.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphTDB.java
@@ -17,16 +17,32 @@
package org.seaborne.tdb2.graph;
+import org.apache.jena.query.ReadWrite ;
import org.apache.jena.sparql.core.AbstractDatasetGraphTests ;
import org.apache.jena.sparql.core.DatasetGraph ;
+import org.junit.After ;
+import org.junit.Before ;
import org.junit.Test ;
import org.seaborne.tdb2.junit.TL ;
// Quad tests
public class TestDatasetGraphTDB extends AbstractDatasetGraphTests
{
+ DatasetGraph dsg = TL.createTestDatasetGraphMem() ;
+ @Before public void before() {
+ dsg.begin(ReadWrite.WRITE);
+ }
+
+ @After public void after() {
+ dsg.abort();
+ dsg.end();
+ TL.expel(dsg);
+ }
+
@Override
- protected DatasetGraph emptyDataset() { return TL.createTestDatasetGraphMem() ; }
+ protected DatasetGraph emptyDataset() {
+ return dsg ;
+ }
@Override
// Empty graph tests: N/A
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphOverDatasetTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphOverDatasetTDB.java b/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphOverDatasetTDB.java
index 20a0577..de01a86 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphOverDatasetTDB.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphOverDatasetTDB.java
@@ -19,15 +19,33 @@ package org.seaborne.tdb2.graph;
import org.apache.jena.graph.Graph ;
import org.apache.jena.graph.Node ;
+import org.apache.jena.query.ReadWrite ;
import org.apache.jena.sparql.core.AbstractTestGraphOverDataset ;
import org.apache.jena.sparql.core.DatasetGraph ;
+import org.junit.After ;
import org.seaborne.tdb2.junit.TL ;
/** This is the view-graph test suite run over a TDB DatasetGraph to check compatibility */
public class TestGraphOverDatasetTDB extends AbstractTestGraphOverDataset
{
+ DatasetGraph dsg = null;
+ @After public void after2() {
+ if ( dsg == null )
+ return;
+ dsg.abort();
+ dsg.end();
+ TL.expel(dsg);
+ }
+
@Override
- protected DatasetGraph createBaseDSG() { return TL.createTestDatasetGraphMem() ; }
+ protected DatasetGraph createBaseDSG() {
+ // Called in initialization.
+ if ( dsg == null ) {
+ dsg = TL.createTestDatasetGraphMem() ;
+ dsg.begin(ReadWrite.WRITE);
+ }
+ return dsg ;
+ }
@Override
protected Graph makeNamedGraph(DatasetGraph dsg, Node gn)
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphsTDB1.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphsTDB1.java b/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphsTDB1.java
index e6638a3..3f703e5 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphsTDB1.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphsTDB1.java
@@ -18,12 +18,25 @@
package org.seaborne.tdb2.graph;
import org.apache.jena.query.Dataset ;
+import org.apache.jena.query.ReadWrite ;
+import org.junit.After ;
+import org.junit.Before ;
import org.seaborne.tdb2.junit.TL ;
public class TestGraphsTDB1 extends AbstractTestGraphsTDB
{
+ Dataset ds = TL.createTestDatasetMem();
+ @Before public void before() {
+ ds.begin(ReadWrite.WRITE);
+ }
+
+ @After public void after() {
+ ds.abort();
+ ds.end();
+ TL.expel(ds);
+ }
@Override
protected Dataset createDataset() {
- return TL.createTestDatasetMem() ;
+ return ds ;
}
}
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java b/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
index 7385354..4ff4ae6 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
@@ -21,28 +21,37 @@ import java.util.function.Consumer ;
import org.apache.jena.query.Dataset ;
import org.apache.jena.sparql.core.DatasetGraph ;
+import org.apache.jena.system.Txn ;
import org.seaborne.dboe.base.file.Location ;
import org.seaborne.tdb2.ConfigTest ;
import org.seaborne.tdb2.DatabaseMgr ;
import org.seaborne.tdb2.TDB2Factory ;
-import org.seaborne.tdb2.sys.SystemTDB ;
import org.seaborne.tdb2.sys.TDBInternal ;
-/** Execute a test with a fresh dataset in a write transaction */
+/** Support for tests to be less "transaction-y" */
public class TL {
public static void exec(Consumer<Dataset> action) {
- Dataset dataset = createTestDataset() ;
- action.accept(dataset);
- releaseDataset(dataset) ;
- TDBInternal.reset() ;
+ Dataset dataset = createTestDataset();
+ try {
+ Txn.executeWrite(dataset, ()->action.accept(dataset));
+ //TDBInternal.reset();
+
+ } finally { expel(dataset); }
}
public static void execMem(Consumer<Dataset> action) {
Dataset dataset = createTestDatasetMem() ;
- action.accept(dataset);
- releaseDataset(dataset);
- TDBInternal.reset();
+ Txn.executeWrite(dataset, ()->action.accept(dataset));
+ expel(dataset);
+ }
+
+ public static void expel(Dataset dataset) {
+ expel(dataset.asDatasetGraph());
+ }
+
+ public static void expel(DatasetGraph dataset) {
+ TDBInternal.expel(dataset);
}
// Or use these for @Before, @After style.
@@ -56,30 +65,24 @@ public class TL {
return location ;
}
- public static void releaseDataset(Dataset dataset) {
+ private static void releaseDataset(Dataset dataset) {
dataset.abort() ;
- TDBInternal.reset() ;
+ expel(dataset);
}
- public static Dataset createTestDataset() {
+ private static Dataset createTestDataset() {
Location location = cleanLocation() ;
Dataset dataset = TDB2Factory.connectDataset(location) ;
- // Non-transactional tests
- dataset = SystemTDB.setNonTransactional(dataset) ;
return dataset ;
}
public static Dataset createTestDatasetMem() {
Dataset dataset = TDB2Factory.createDataset() ;
- // Non-transactional tests
- dataset = SystemTDB.setNonTransactional(dataset) ;
return dataset ;
}
public static DatasetGraph createTestDatasetGraphMem() {
DatasetGraph dataset = DatabaseMgr.createDatasetGraph() ;
- // Non-transactional tests
- dataset = SystemTDB.setNonTransactional(dataset) ;
return dataset ;
}
}
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java b/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java
index 44aacfb..071b135 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java
@@ -17,13 +17,19 @@
package org.seaborne.tdb2.setup;
+import static org.junit.Assert.assertEquals ;
+import static org.junit.Assert.assertFalse ;
+import static org.junit.Assert.assertNotEquals ;
+import static org.junit.Assert.assertNotNull ;
+import static org.junit.Assert.assertNull ;
+import static org.junit.Assert.assertTrue ;
+
import java.nio.file.Files ;
import java.nio.file.Path ;
import java.nio.file.Paths ;
import org.apache.jena.atlas.json.JSON ;
import org.apache.jena.atlas.json.JsonObject ;
-import static org.junit.Assert.*;
import org.apache.jena.atlas.lib.FileOps ;
import org.junit.After ;
import org.junit.Before ;
@@ -31,7 +37,6 @@ import org.junit.Test ;
import org.seaborne.dboe.base.file.Location ;
import org.seaborne.dboe.sys.Names;
import org.seaborne.tdb2.ConfigTest ;
-import org.seaborne.tdb2.sys.DatabaseConnection ;
import org.seaborne.tdb2.sys.StoreConnection ;
import org.seaborne.tdb2.sys.TDBInternal ;
@@ -40,6 +45,7 @@ import org.seaborne.tdb2.sys.TDBInternal ;
* calls and can be noticably slow.
*/
public class TestStoreParamsCreate {
+ // Thse tests work on storage locations.
private final String DB_DIR = ConfigTest.getCleanDir() ;
private final Path db = Paths.get(DB_DIR) ;
private final Path cfg = Paths.get(DB_DIR, Names.TDB_CONFIG_FILE) ;
@@ -52,14 +58,18 @@ public class TestStoreParamsCreate {
.blockReadCacheSize(4)
.build();
+ private void expel() {
+ StoreConnection.internalExpel(loc, true);
+ }
+
@Before public void clearupTest() {
// Flush and clean.
- DatabaseConnection.internalExpel(loc, true);
- FileOps.clearAll(DB_DIR);
+ TDBInternal.reset();
+ FileOps.clearAll(loc.getDirectoryPath());
}
@After public void expelDatabase() {
- TDBInternal.expel(loc, true) ;
+ expel();
}
@Test public void params_create_01() {
@@ -83,7 +93,7 @@ public class TestStoreParamsCreate {
// Create.
StoreConnection.connectCreate(loc) ;
// Drop.
- TDBInternal.expel(loc, true) ;
+ expel();
// Reconnect
StoreConnection.connectCreate(loc, null) ;
StoreParams pLoc = StoreParamsCodec.read(loc) ;
@@ -100,7 +110,7 @@ public class TestStoreParamsCreate {
// Create.
StoreConnection.connectCreate(loc, null) ;
// Drop.
- TDBInternal.expel(loc, true) ;
+ expel();
// Reconnect
StoreConnection.connectCreate(loc, pSpecial) ;
//StoreParams pLoc = StoreParamsCodec.read(loc) ;
@@ -125,7 +135,7 @@ public class TestStoreParamsCreate {
// Create.
StoreConnection.connectCreate(loc, pApp) ;
// Drop.
- TDBInternal.expel(loc, true) ;
+ expel();
// Reconnect
StoreConnection.connectCreate(loc, pSpecial) ;
//StoreParams pLoc = StoreParamsCodec.read(loc) ;
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/test/java/org/seaborne/tdb2/solver/TestSolverTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/solver/TestSolverTDB.java b/tdb2/src/test/java/org/seaborne/tdb2/solver/TestSolverTDB.java
index d94252e..43ef56d 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/solver/TestSolverTDB.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/solver/TestSolverTDB.java
@@ -54,6 +54,7 @@ public class TestSolverTDB
@BeforeClass static public void beforeClass()
{
dataset = TL.createTestDatasetMem() ;
+ dataset.begin(ReadWrite.WRITE);
graphData = ConfigTest.getTestingDataRoot()+"/Data/solver-data.ttl" ;
RDFDataMgr.read(dataset, graphData) ;
graph = dataset.asDatasetGraph().getDefaultGraph() ;
@@ -63,7 +64,8 @@ public class TestSolverTDB
@AfterClass static public void afterClass() {
- TL.releaseDataset(dataset);
+ dataset.abort();
+ TL.expel(dataset);
}
static private void addAll(Graph srcGraph, Graph dstGraph)
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java b/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java
index 8bb3ae7..a9dfe92 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java
@@ -17,14 +17,16 @@
package org.seaborne.tdb2.solver;
+import static org.junit.Assert.assertEquals ;
+
import java.util.Iterator ;
-import static org.junit.Assert.*;
import org.apache.jena.atlas.lib.tuple.Tuple ;
import org.apache.jena.graph.NodeFactory ;
import org.apache.jena.sparql.core.Quad ;
import org.apache.jena.sparql.sse.SSE ;
import org.junit.Test ;
+import org.seaborne.dboe.jenax.Txn ;
import org.seaborne.tdb2.junit.TL ;
import org.seaborne.tdb2.solver.stats.StatsCollectorNodeId ;
import org.seaborne.tdb2.solver.stats.StatsResults ;
@@ -46,42 +48,45 @@ public class TestStats
static Quad q3 = SSE.parseQuad("(<g2> <s> <p> 9)") ;
static Quad q4 = SSE.parseQuad("(_ <s> <p> 1)") ;
static {
- dsg.add(q1) ;
- dsg.add(q2) ;
- dsg.add(q3) ;
- dsg.add(q4) ;
+ Txn.executeWrite(dsg, ()->{
+ dsg.add(q1) ;
+ dsg.add(q2) ;
+ dsg.add(q3) ;
+ dsg.add(q4) ;
+ });
}
-
- private StatsResults statsForGraph(NodeId gid)
- {
- Iterator<Tuple<NodeId>> iter = quads.find(gid, null, null, null) ;
-
- StatsCollectorNodeId stats = new StatsCollectorNodeId(nt) ;
- for ( ; iter.hasNext(); )
- {
- Tuple<NodeId> t = iter.next() ;
- stats.record(t.get(0), t.get(1), t.get(2), t.get(3)) ;
- }
-
- return stats.results() ;
+ private StatsResults statsForGraph(NodeId gid) {
+ // StatsCollectorNodeId writes nodes for rdf:type (this is not good).
+ return Txn.calculateWrite(dsg, ()-> {
+ Iterator<Tuple<NodeId>> iter = quads.find(gid, null, null, null) ;
+
+ StatsCollectorNodeId stats = new StatsCollectorNodeId(nt) ;
+ for ( ; iter.hasNext() ; ) {
+ Tuple<NodeId> t = iter.next() ;
+ stats.record(t.get(0), t.get(1), t.get(2), t.get(3)) ;
+ }
+
+ return stats.results() ;
+ }) ;
}
-
- private StatsResults statsForDftGraph()
- {
- Iterator<Tuple<NodeId>> iter = triples.findAll() ;
-
- StatsCollectorNodeId stats = new StatsCollectorNodeId(nt) ;
- for ( ; iter.hasNext(); )
- {
- Tuple<NodeId> t = iter.next() ;
- stats.record(null, t.get(0), t.get(1), t.get(2)) ;
- }
-
- return stats.results() ;
+
+ private StatsResults statsForDftGraph() {
+ // StatsCollectorNodeId writes nodes for rdf:type (this is not good).
+ return Txn.calculateWrite(dsg, ()-> {
+ Iterator<Tuple<NodeId>> iter = triples.findAll() ;
+
+ StatsCollectorNodeId stats = new StatsCollectorNodeId(nt) ;
+ for ( ; iter.hasNext() ; ) {
+ Tuple<NodeId> t = iter.next() ;
+ stats.record(null, t.get(0), t.get(1), t.get(2)) ;
+ }
+
+ return stats.results() ;
+ }) ;
}
- @Test public void stats_01() {
+ @Test public void stats_01() {
StatsResults r = statsForDftGraph() ;
assertEquals(1, r.getCount()) ;
assertEquals(1, r.getPredicates().keySet().size()) ;
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDB.java b/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDB.java
index 48fd7fb..1ff5387 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDB.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDB.java
@@ -40,10 +40,14 @@ public class TestDatasetTDB
@Before public void before() {
dataset = TL.createTestDatasetMem() ;
+ dataset.begin(ReadWrite.WRITE);
}
@After public void after() {
- TL.releaseDataset(dataset);
+ dataset.abort();
+ dataset.end();
+ TL.expel(dataset);
+
}
private Dataset dataset() {
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDBPersist.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDBPersist.java b/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDBPersist.java
index fe928a0..81a5dd5 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDBPersist.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDBPersist.java
@@ -17,18 +17,12 @@
package org.seaborne.tdb2.store;
-import static org.junit.Assert.assertEquals ;
import static org.junit.Assert.assertFalse ;
import static org.junit.Assert.assertTrue ;
-import java.util.Arrays ;
-import java.util.List ;
-
-import org.apache.jena.atlas.iterator.Iter ;
import org.apache.jena.graph.Graph ;
import org.apache.jena.graph.Node ;
import org.apache.jena.graph.Triple ;
-import org.apache.jena.sparql.sse.SSE ;
import org.apache.jena.sparql.util.NodeFactoryExtra ;
import org.junit.Test ;
import org.seaborne.tdb2.junit.TL ;
@@ -60,58 +54,58 @@ public class TestDatasetTDBPersist
}) ;
}
- @Test
- public void dataset3() {
- TL.exec((ds) -> {
- Graph g1 = ds.getDefaultModel().getGraph() ;
- // Sometimes, under windows, deleting the files by
- // clearDirectory does not work.
- // Needed for safe tests on windows.
- g1.clear() ;
-
- Graph g2 = ds.getNamedModel("http://example/").getGraph() ;
- g2.add(new Triple(n0, n1, n2)) ;
- assertTrue(g2.contains(n0, n1, n2)) ;
- assertFalse(g1.contains(n0, n1, n2)) ;
- }) ;
- }
-
- @Test
- public void dataset4() {
- String graphName = "http://example/" ;
- Triple triple = SSE.parseTriple("(<x> <y> <z>)") ;
- Node gn = org.apache.jena.graph.NodeFactory.createURI(graphName) ;
-
- TL.exec((ds) -> {
- // ?? See TupleLib.
- ds.asDatasetGraph().deleteAny(gn, null, null, null) ;
-
- Graph g2 = ds.asDatasetGraph().getGraph(gn) ;
-
- // Graphs only exists if they have a triple in them
- assertFalse(ds.containsNamedModel(graphName)) ;
-
- List<String> names = Iter.toList(ds.listNames()) ;
- assertEquals(0, names.size()) ;
- assertEquals(0, ds.asDatasetGraph().size()) ;
- }) ;
- }
-
- @Test
- public void dataset5() {
- String graphName = "http://example/" ;
- Triple triple = SSE.parseTriple("(<x> <y> <z>)") ;
- TL.exec((ds) -> {
- Graph g2 = ds.asDatasetGraph().getGraph(org.apache.jena.graph.NodeFactory.createURI(graphName)) ;
- // Graphs only exists if they have a triple in them
- g2.add(triple) ;
-
- assertTrue(ds.containsNamedModel(graphName)) ;
- List<String> x = Iter.toList(ds.listNames()) ;
- List<String> y = Arrays.asList(graphName) ;
- assertEquals(x, y) ;
-
- assertEquals(1, ds.asDatasetGraph().size()) ;
- }) ;
- }
+// @Test
+// public void dataset3() {
+// TL.exec((ds) -> {
+// Graph g1 = ds.getDefaultModel().getGraph() ;
+// // Sometimes, under windows, deleting the files by
+// // clearDirectory does not work.
+// // Needed for safe tests on windows.
+// g1.clear() ;
+//
+// Graph g2 = ds.getNamedModel("http://example/").getGraph() ;
+// g2.add(new Triple(n0, n1, n2)) ;
+// assertTrue(g2.contains(n0, n1, n2)) ;
+// assertFalse(g1.contains(n0, n1, n2)) ;
+// }) ;
+// }
+//
+// @Test
+// public void dataset4() {
+// String graphName = "http://example/" ;
+// Triple triple = SSE.parseTriple("(<x> <y> <z>)") ;
+// Node gn = org.apache.jena.graph.NodeFactory.createURI(graphName) ;
+//
+// TL.exec((ds) -> {
+// // ?? See TupleLib.
+// ds.asDatasetGraph().deleteAny(gn, null, null, null) ;
+//
+// Graph g2 = ds.asDatasetGraph().getGraph(gn) ;
+//
+// // Graphs only exists if they have a triple in them
+// assertFalse(ds.containsNamedModel(graphName)) ;
+//
+// List<String> names = Iter.toList(ds.listNames()) ;
+// assertEquals(0, names.size()) ;
+// assertEquals(0, ds.asDatasetGraph().size()) ;
+// }) ;
+// }
+//
+// @Test
+// public void dataset5() {
+// String graphName = "http://example/" ;
+// Triple triple = SSE.parseTriple("(<x> <y> <z>)") ;
+// TL.exec((ds) -> {
+// Graph g2 = ds.asDatasetGraph().getGraph(org.apache.jena.graph.NodeFactory.createURI(graphName)) ;
+// // Graphs only exists if they have a triple in them
+// g2.add(triple) ;
+//
+// assertTrue(ds.containsNamedModel(graphName)) ;
+// List<String> x = Iter.toList(ds.listNames()) ;
+// List<String> y = Arrays.asList(graphName) ;
+// assertEquals(x, y) ;
+//
+// assertEquals(1, ds.asDatasetGraph().size()) ;
+// }) ;
+// }
}
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/test/java/org/seaborne/tdb2/store/TestDynamicDatasetTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/TestDynamicDatasetTDB.java b/tdb2/src/test/java/org/seaborne/tdb2/store/TestDynamicDatasetTDB.java
index fbcfc48..d0376e9 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/TestDynamicDatasetTDB.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/TestDynamicDatasetTDB.java
@@ -18,6 +18,7 @@
package org.seaborne.tdb2.store;
import org.apache.jena.query.Dataset ;
+import org.apache.jena.query.ReadWrite ;
import org.apache.jena.sparql.core.AbstractTestDynamicDataset ;
import org.seaborne.tdb2.TDB2 ;
import org.seaborne.tdb2.junit.TL ;
@@ -27,11 +28,13 @@ public class TestDynamicDatasetTDB extends AbstractTestDynamicDataset
@Override
protected Dataset createDataset()
{
- return TL.createTestDatasetMem() ;
+ Dataset ds = TL.createTestDatasetMem() ;
+ ds.begin(ReadWrite.WRITE);
+ return ds;
}
@Override
- protected void releaseDataset(Dataset ds) { TL.releaseDataset(ds); }
+ protected void releaseDataset(Dataset ds) { ds.abort(); TL.expel(ds); }
protected void startDynamicAndUnionTest() { TDB2.getContext().setTrue(TDB2.symUnionDefaultGraph) ; }
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphNamedTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphNamedTDB.java b/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphNamedTDB.java
index 99c933e..d844c5a 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphNamedTDB.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphNamedTDB.java
@@ -20,6 +20,7 @@ package org.seaborne.tdb2.store;
import org.apache.jena.graph.Graph ;
import org.apache.jena.graph.Node ;
import org.apache.jena.query.Dataset ;
+import org.apache.jena.query.ReadWrite ;
import org.apache.jena.sparql.graph.AbstractTestGraph2 ;
import org.apache.jena.sparql.util.NodeFactoryExtra ;
import org.junit.After ;
@@ -36,14 +37,17 @@ public class TestGraphNamedTDB extends AbstractTestGraph2
@Before
public void before() {
dataset = TL.createTestDatasetMem() ;
+ dataset.begin(ReadWrite.WRITE);
graph = dataset.asDatasetGraph().getGraph(graphNode) ;
}
@After
public void after() {
- TL.releaseDataset(dataset) ;
+ dataset.abort();
+ dataset.end();
+ TL.expel(dataset) ;
}
-
+
@Override
protected Graph emptyGraph() {
graph.clear() ;
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphTDB.java b/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphTDB.java
index 0317cc5..7f941eb 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphTDB.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphTDB.java
@@ -19,6 +19,7 @@ package org.seaborne.tdb2.store;
import org.apache.jena.graph.Graph ;
import org.apache.jena.query.Dataset ;
+import org.apache.jena.query.ReadWrite ;
import org.apache.jena.sparql.graph.AbstractTestGraph2 ;
import org.junit.After ;
import org.junit.Before ;
@@ -33,12 +34,15 @@ public class TestGraphTDB extends AbstractTestGraph2
@Before
public void before() {
dataset = TL.createTestDatasetMem() ;
+ dataset.begin(ReadWrite.WRITE);
graph = dataset.getDefaultModel().getGraph() ;
}
@After
public void after() {
- TL.releaseDataset(dataset) ;
+ dataset.abort();
+ dataset.end();
+ TL.expel(dataset) ;
}
@Override
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java b/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
index 47bc3e5..1aed0a6 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
@@ -83,7 +83,7 @@ public class TestTransactions
@After public void after() {
dataset.close() ;
- TDBInternal.expel(location, true);
+ TDBInternal.expel(dataset.asDatasetGraph());
}
// Models across transactions
http://git-wip-us.apache.org/repos/asf/jena/blob/d8fd29aa/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java b/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java
index 67883a4..09b9804 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java
@@ -90,8 +90,6 @@ public class TestDatabaseOps
Txn.executeWrite(dsgOld, ()->dsgOld.delete(quad1));
Txn.executeRead(dsg, ()->assertTrue(dsg.contains(quad1)) );
Txn.executeRead(dsg2, ()->assertTrue(dsg2.contains(quad1)) ) ;
-
- TDBInternal.expel(loc1, true);
}
// @Test public void compact_2() {
[28/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java
index 0000000,0000000..0b57de8
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java
@@@ -1,0 -1,0 +1,174 @@@
++/*
++ * 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.sys;
++
++import org.apache.jena.graph.Node;
++import org.apache.jena.query.Dataset;
++import org.apache.jena.sparql.core.DatasetGraph;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
++import org.seaborne.tdb2.store.DatasetGraphTDB;
++import org.seaborne.tdb2.store.NodeId;
++import org.seaborne.tdb2.store.nodetable.NodeTable;
++
++/**
++ * A collection of helpers to abstract away from calling code knowing the
++ * internal details of TDB.
++ * <p>
++ * Use with care.
++ * <p>{@link DatabaseOps#compact Compaction} invalidates any previous objects.
++ *
++ */
++public class TDBInternal {
++ /**
++ * Return the NodeId for a node. Returns NodeId.NodeDoesNotExist when the node is not
++ * found. Returns null when not a TDB-backed dataset.
++ */
++ public static NodeId getNodeId(Dataset ds, Node node) {
++ return getNodeId(ds.asDatasetGraph(), node);
++ }
++
++ /**
++ * Return the NodeId for a node. Returns NodeId.NodeDoesNotExist when the node is not
++ * found. Returns null when not a TDB-backed dataset.
++ */
++ public static NodeId getNodeId(DatasetGraph ds, Node node) {
++ DatasetGraphTDB dsg = getDatasetGraphTDB(ds);
++ return getNodeId(dsg, node);
++ }
++
++ /**
++ * Return the NodeId for a node. Returns NodeId.NodeDoesNotExist when the node is not
++ * found. Returns null when not a TDB-backed dataset.
++ */
++ public static NodeId getNodeId(DatasetGraphTDB dsg, Node node) {
++ if ( dsg == null )
++ return null;
++ NodeTable nodeTable = dsg.getQuadTable().getNodeTupleTable().getNodeTable();
++ NodeId nodeId = nodeTable.getNodeIdForNode(node);
++ return nodeId;
++ }
++
++ /**
++ * Return the node for a NodeId (if any). Returns null if the NodeId does not exist in
++ * the dataset.
++ */
++ public static Node getNode(Dataset ds, NodeId nodeId) {
++ return getNode(ds.asDatasetGraph(), nodeId);
++ }
++
++ /**
++ * Return the node for a NodeId (if any). Returns null if the NodeId does not exist in
++ * the dataset.
++ */
++ public static Node getNode(DatasetGraph ds, NodeId nodeId) {
++ DatasetGraphTDB dsg = getDatasetGraphTDB(ds);
++ return getNode(dsg, nodeId);
++ }
++
++ /**
++ * Return the node for a NodeId (if any). Returns null if the NodeId does not exist in
++ * the dataset.
++ */
++ public static Node getNode(DatasetGraphTDB dsg, NodeId nodeId) {
++ if ( dsg == null )
++ return null;
++ NodeTable nodeTable = dsg.getQuadTable().getNodeTupleTable().getNodeTable();
++ Node node = nodeTable.getNodeForNodeId(nodeId);
++ return node;
++ }
++
++ /**
++ * Return the DatasetGraphTDB for a Dataset, or null.
++ * Use the {@link DatasetGraphTDB} with care.
++ */
++ public static DatasetGraphTDB getDatasetGraphTDB(Dataset ds) {
++ return getDatasetGraphTDB(ds.asDatasetGraph());
++ }
++
++ /**
++ * Return the DatasetGraphTDB for a DatasetGraph, or null.
++ * Use the {@link DatasetGraphTDB} with care.
++ */
++ public static DatasetGraphSwitchable getDatabaseContainer(DatasetGraph dsg) {
++ if ( dsg instanceof DatasetGraphSwitchable )
++ return (DatasetGraphSwitchable)dsg;
++ throw new TDBException("Not a TDB database container");
++ }
++
++ /**
++ * Return the DatasetGraphTDB for a DatasetGraph, or null.
++ * Use the {@link DatasetGraphTDB} with care.
++ */
++ public static DatasetGraphTDB getDatasetGraphTDB(DatasetGraph dsg) {
++ return unwrap(dsg);
++ }
++
++ /**
++ * Return the DatasetGraphTDB for a DatasetGraph, or throw an exception.
++ */
++ public static DatasetGraphTDB requireStorage(DatasetGraph dsg) {
++ DatasetGraphTDB dsgtdb = unwrap(dsg);
++ if ( dsgtdb == null )
++ throw new TDBException("Not a TDB database (argument is neither a switchable nor direct TDB DatasetGraph)");
++ return dsgtdb;
++ }
++
++ private static DatasetGraphTDB unwrap(DatasetGraph datasetGraph) {
++ DatasetGraph dsg = datasetGraph;
++ if ( dsg instanceof DatasetGraphSwitchable )
++ dsg = ((DatasetGraphSwitchable)datasetGraph).get();
++ if ( dsg instanceof DatasetGraphTDB )
++ return ((DatasetGraphTDB)dsg);
++ return null;
++ }
++
++ /** Stop managing a DatasetGraph. Use with great care (testing only). */
++ public static synchronized void expel(DatasetGraph dsg) {
++ Location locContainer = null;
++ Location locStorage = null;
++
++ if ( dsg instanceof DatasetGraphSwitchable ) {
++ locContainer = ((DatasetGraphSwitchable)dsg).getLocation();
++ dsg = ((DatasetGraphSwitchable)dsg).getWrapped();
++ }
++ if ( dsg instanceof DatasetGraphTDB )
++ locStorage = ((DatasetGraphTDB)dsg).getLocation();
++
++ DatabaseConnection.internalExpel(locContainer, false);
++ StoreConnection.internalExpel(locStorage, false);
++ }
++
++ /**
++ * Reset the whole TDB system.
++ * Use with great care.
++ */
++ public static void reset() {
++ DatabaseConnection.internalReset();
++ StoreConnection.internalReset();
++ }
++
++ public static boolean isBackedByTDB(DatasetGraph datasetGraph) {
++ if ( datasetGraph instanceof DatasetGraphSwitchable )
++ return true;
++ if ( datasetGraph instanceof DatasetGraphTDB )
++ return true;
++ return false;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/Util.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/Util.java
index 0000000,0000000..3ac6336
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/sys/Util.java
@@@ -1,0 -1,0 +1,49 @@@
++/*
++ * 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.util.List;
++import java.util.NoSuchElementException;
++
++/** Utility code that should go somewhere */
++public class Util {
++
++ /** Get the last element of a list, or throw NoSuchElementException
++ * @param list
++ * @return T
++ * @throws NoSuchElementException
++ */
++ public static <T> T xgetLast(List<T> list) {
++ T elt = getLastOrNull(list);
++ if ( elt == null )
++ throw new NoSuchElementException();
++ return elt;
++ }
++
++ /**
++ * Get the last element of a list, or return null.
++ * @param list
++ * @return T
++ */
++ public static <T> T getLastOrNull(List<T> list) {
++ if ( list.isEmpty() )
++ return null;
++ return list.get(list.size()-1);
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/resources/META-INF/LICENSE
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/resources/META-INF/LICENSE
index 0000000,0000000..67db858
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/resources/META-INF/LICENSE
@@@ -1,0 -1,0 +1,175 @@@
++
++ Apache License
++ Version 2.0, January 2004
++ http://www.apache.org/licenses/
++
++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
++
++ 1. Definitions.
++
++ "License" shall mean the terms and conditions for use, reproduction,
++ and distribution as defined by Sections 1 through 9 of this document.
++
++ "Licensor" shall mean the copyright owner or entity authorized by
++ the copyright owner that is granting the License.
++
++ "Legal Entity" shall mean the union of the acting entity and all
++ other entities that control, are controlled by, or are under common
++ control with that entity. For the purposes of this definition,
++ "control" means (i) the power, direct or indirect, to cause the
++ direction or management of such entity, whether by contract or
++ otherwise, or (ii) ownership of fifty percent (50%) or more of the
++ outstanding shares, or (iii) beneficial ownership of such entity.
++
++ "You" (or "Your") shall mean an individual or Legal Entity
++ exercising permissions granted by this License.
++
++ "Source" form shall mean the preferred form for making modifications,
++ including but not limited to software source code, documentation
++ source, and configuration files.
++
++ "Object" form shall mean any form resulting from mechanical
++ transformation or translation of a Source form, including but
++ not limited to compiled object code, generated documentation,
++ and conversions to other media types.
++
++ "Work" shall mean the work of authorship, whether in Source or
++ Object form, made available under the License, as indicated by a
++ copyright notice that is included in or attached to the work
++ (an example is provided in the Appendix below).
++
++ "Derivative Works" shall mean any work, whether in Source or Object
++ form, that is based on (or derived from) the Work and for which the
++ editorial revisions, annotations, elaborations, or other modifications
++ represent, as a whole, an original work of authorship. For the purposes
++ of this License, Derivative Works shall not include works that remain
++ separable from, or merely link (or bind by name) to the interfaces of,
++ the Work and Derivative Works thereof.
++
++ "Contribution" shall mean any work of authorship, including
++ the original version of the Work and any modifications or additions
++ to that Work or Derivative Works thereof, that is intentionally
++ submitted to Licensor for inclusion in the Work by the copyright owner
++ or by an individual or Legal Entity authorized to submit on behalf of
++ the copyright owner. For the purposes of this definition, "submitted"
++ means any form of electronic, verbal, or written communication sent
++ to the Licensor or its representatives, including but not limited to
++ communication on electronic mailing lists, source code control systems,
++ and issue tracking systems that are managed by, or on behalf of, the
++ Licensor for the purpose of discussing and improving the Work, but
++ excluding communication that is conspicuously marked or otherwise
++ designated in writing by the copyright owner as "Not a Contribution."
++
++ "Contributor" shall mean Licensor and any individual or Legal Entity
++ on behalf of whom a Contribution has been received by Licensor and
++ subsequently incorporated within the Work.
++
++ 2. Grant of Copyright License. Subject to the terms and conditions of
++ this License, each Contributor hereby grants to You a perpetual,
++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
++ copyright license to reproduce, prepare Derivative Works of,
++ publicly display, publicly perform, sublicense, and distribute the
++ Work and such Derivative Works in Source or Object form.
++
++ 3. Grant of Patent License. Subject to the terms and conditions of
++ this License, each Contributor hereby grants to You a perpetual,
++ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
++ (except as stated in this section) patent license to make, have made,
++ use, offer to sell, sell, import, and otherwise transfer the Work,
++ where such license applies only to those patent claims licensable
++ by such Contributor that are necessarily infringed by their
++ Contribution(s) alone or by combination of their Contribution(s)
++ with the Work to which such Contribution(s) was submitted. If You
++ institute patent litigation against any entity (including a
++ cross-claim or counterclaim in a lawsuit) alleging that the Work
++ or a Contribution incorporated within the Work constitutes direct
++ or contributory patent infringement, then any patent licenses
++ granted to You under this License for that Work shall terminate
++ as of the date such litigation is filed.
++
++ 4. Redistribution. You may reproduce and distribute copies of the
++ Work or Derivative Works thereof in any medium, with or without
++ modifications, and in Source or Object form, provided that You
++ meet the following conditions:
++
++ (a) You must give any other recipients of the Work or
++ Derivative Works a copy of this License; and
++
++ (b) You must cause any modified files to carry prominent notices
++ stating that You changed the files; and
++
++ (c) You must retain, in the Source form of any Derivative Works
++ that You distribute, all copyright, patent, trademark, and
++ attribution notices from the Source form of the Work,
++ excluding those notices that do not pertain to any part of
++ the Derivative Works; and
++
++ (d) If the Work includes a "NOTICE" text file as part of its
++ distribution, then any Derivative Works that You distribute must
++ include a readable copy of the attribution notices contained
++ within such NOTICE file, excluding those notices that do not
++ pertain to any part of the Derivative Works, in at least one
++ of the following places: within a NOTICE text file distributed
++ as part of the Derivative Works; within the Source form or
++ documentation, if provided along with the Derivative Works; or,
++ within a display generated by the Derivative Works, if and
++ wherever such third-party notices normally appear. The contents
++ of the NOTICE file are for informational purposes only and
++ do not modify the License. You may add Your own attribution
++ notices within Derivative Works that You distribute, alongside
++ or as an addendum to the NOTICE text from the Work, provided
++ that such additional attribution notices cannot be construed
++ as modifying the License.
++
++ You may add Your own copyright statement to Your modifications and
++ may provide additional or different license terms and conditions
++ for use, reproduction, or distribution of Your modifications, or
++ for any such Derivative Works as a whole, provided Your use,
++ reproduction, and distribution of the Work otherwise complies with
++ the conditions stated in this License.
++
++ 5. Submission of Contributions. Unless You explicitly state otherwise,
++ any Contribution intentionally submitted for inclusion in the Work
++ by You to the Licensor shall be under the terms and conditions of
++ this License, without any additional terms or conditions.
++ Notwithstanding the above, nothing herein shall supersede or modify
++ the terms of any separate license agreement you may have executed
++ with Licensor regarding such Contributions.
++
++ 6. Trademarks. This License does not grant permission to use the trade
++ names, trademarks, service marks, or product names of the Licensor,
++ except as required for reasonable and customary use in describing the
++ origin of the Work and reproducing the content of the NOTICE file.
++
++ 7. Disclaimer of Warranty. Unless required by applicable law or
++ agreed to in writing, Licensor provides the Work (and each
++ Contributor provides its Contributions) on an "AS IS" BASIS,
++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
++ implied, including, without limitation, any warranties or conditions
++ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
++ PARTICULAR PURPOSE. You are solely responsible for determining the
++ appropriateness of using or redistributing the Work and assume any
++ risks associated with Your exercise of permissions under this License.
++
++ 8. Limitation of Liability. In no event and under no legal theory,
++ whether in tort (including negligence), contract, or otherwise,
++ unless required by applicable law (such as deliberate and grossly
++ negligent acts) or agreed to in writing, shall any Contributor be
++ liable to You for damages, including any direct, indirect, special,
++ incidental, or consequential damages of any character arising as a
++ result of this License or out of the use or inability to use the
++ Work (including but not limited to damages for loss of goodwill,
++ work stoppage, computer failure or malfunction, or any and all
++ other commercial damages or losses), even if such Contributor
++ has been advised of the possibility of such damages.
++
++ 9. Accepting Warranty or Additional Liability. While redistributing
++ the Work or Derivative Works thereof, You may choose to offer,
++ and charge a fee for, acceptance of support, warranty, indemnity,
++ or other liability obligations and/or rights consistent with this
++ License. However, in accepting such obligations, You may act only
++ on Your own behalf and on Your sole responsibility, not on behalf
++ of any other Contributor, and only if You agree to indemnify,
++ defend, and hold each Contributor harmless for any liability
++ incurred by, or claims asserted against, such Contributor by reason
++ of your accepting any such warranty or additional liability.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/resources/META-INF/NOTICE
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/resources/META-INF/NOTICE
index 0000000,0000000..5ba7ec0
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/resources/META-INF/NOTICE
@@@ -1,0 -1,0 +1,10 @@@
++Mantis Database Operating Environment
++
++Copyright 2013-2017 Andy Seaborne
++Copyright 2014, 2015 Epimorphics Ltd.
++
++Portions of this software derive from software from Apache Jena:
++ - Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
++ - Copyright 2010, 2011 Epimorphics Ltd.
++ - Copyright 2010, 2011 Talis Systems Ltd.
++These have been licensed to the Apache Software Foundation under a software grant.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/resources/META-INF/services/org.apache.jena.system.JenaSubsystemLifecycle
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/resources/META-INF/services/org.apache.jena.system.JenaSubsystemLifecycle
index 0000000,0000000..21f02ea
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/resources/META-INF/services/org.apache.jena.system.JenaSubsystemLifecycle
@@@ -1,0 -1,0 +1,1 @@@
++org.seaborne.tdb2.sys.InitTDB2
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/resources/org/apache/jena/tdb/tdb-properties.xml
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/resources/org/apache/jena/tdb/tdb-properties.xml
index 0000000,0000000..67d8255
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/resources/org/apache/jena/tdb/tdb-properties.xml
@@@ -1,0 -1,0 +1,8 @@@
++<?xml version="1.0" encoding="UTF-8"?>
++<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
++<!-- Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0 -->
++<properties version="1.0">
++ <comment>TDB System Properties</comment>
++ <entry key="org.apache.jena.tdb.version">${project.version}</entry>
++ <entry key="org.apache.jena.tdb.build.datetime">${build.time.xsd}</entry>
++</properties>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/ConfigTest.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/ConfigTest.java
index 0000000,0000000..fc161fd
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/ConfigTest.java
@@@ -1,0 -1,0 +1,95 @@@
++/*
++ * 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;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++
++public class ConfigTest
++{
++ private static String testingDataRoot = "testing" ;
++ // Place under target
++ private static final String testingDir = "target/tdb-testing" ;
++ private static final String testingDirDB = "target/tdb-testing/DB" ;
++ static boolean nonDeleteableMMapFiles = SystemTDB.isWindows ;
++
++ static boolean initialized = false ;
++
++ private static void init()
++ {
++ FileOps.ensureDir("target") ;
++ FileOps.ensureDir(testingDir) ;
++ FileOps.ensureDir(testingDirDB) ;
++ initialized = true ;
++ }
++
++ private static int count = 0 ;
++
++ public static void setTestingDataRoot(String dir) { testingDataRoot = dir ; }
++ public static String getTestingDataRoot() { return testingDataRoot ; }
++
++ /** return a directory */
++ public static final String getCleanDir() {
++ init() ;
++ String dir = nonDeleteableMMapFiles ? getTestingDirUnique() : getTestingDirDB() ;
++ FileOps.ensureDir(dir);
++ FileOps.clearDirectory(dir) ;
++ return dir ;
++ }
++ /** Get a empty directory name that has not been used before in this JVM */
++
++ private static final String getTestingDirUnique()
++ {
++ init() ;
++ String dn = testingDir+"/D-"+(++count) ;
++ FileOps.ensureDir(dn) ;
++ FileOps.clearDirectory(dn) ;
++ return dn ;
++ }
++
++ public static final String getTestingDir()
++ {
++ init() ;
++ return testingDir ;
++ }
++
++ public static final void deleteTestingDir()
++ {
++ if ( ! FileOps.exists(testingDir) )
++ return ;
++ deleteTestingDirDB() ;
++ FileOps.clearDirectory(testingDir) ;
++ FileOps.deleteSilent(testingDir) ;
++ }
++
++ public static final String getTestingDirDB()
++ {
++ init() ;
++ FileOps.ensureDir(testingDirDB) ;
++ return testingDirDB ;
++ }
++
++ public static final void deleteTestingDirDB()
++ {
++ if ( ! FileOps.exists(testingDirDB) )
++ return ;
++ FileOps.clearDirectory(testingDirDB) ;
++ FileOps.deleteSilent(testingDirDB) ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/TC_TDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/TC_TDB.java
index 0000000,0000000..8d1a695
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/TC_TDB.java
@@@ -1,0 -1,0 +1,80 @@@
++/*
++ * 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;
++
++import org.apache.jena.sparql.engine.optimizer.reorder.ReorderLib ;
++import org.apache.jena.sparql.engine.optimizer.reorder.ReorderTransformation ;
++import org.apache.log4j.Level ;
++import org.apache.log4j.Logger ;
++import org.junit.AfterClass ;
++import org.junit.BeforeClass ;
++import org.junit.runner.RunWith ;
++import org.junit.runners.Suite ;
++import org.seaborne.dboe.base.block.FileMode ;
++import org.seaborne.tdb2.assembler.TS_TDBAssembler ;
++import org.seaborne.tdb2.graph.TS_Graph ;
++import org.seaborne.tdb2.lib.TS_LibTDB ;
++import org.seaborne.tdb2.setup.TS_TDBSetup ;
++import org.seaborne.tdb2.solver.TS_SolverTDB ;
++import org.seaborne.tdb2.store.TS_Store ;
++import org.seaborne.tdb2.store.nodetable.TS_NodeTable ;
++import org.seaborne.tdb2.store.tupletable.TS_TupleTable ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++import org.seaborne.tdb2.sys.TS_Sys ;
++
++// Naming conventions.
++// TS_* - Test sets: collections of testing files (Often Test*)
++// TC_* - Test collection: sets of TS's and TC's.
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ // TDB
++ TS_LibTDB.class
++ , TS_NodeTable.class
++ , TS_TupleTable.class
++ , TS_TDBSetup.class
++ , TS_Store.class
++ , TS_SolverTDB.class
++ , TS_Graph.class
++ , TS_Factory.class
++ , TS_TDBAssembler.class
++ , TS_Sys.class
++} )
++
++public class TC_TDB
++{
++ static {
++ if ( false )
++ SystemTDB.setFileMode(FileMode.direct) ;
++ }
++ static ReorderTransformation dftReorder = null ;
++
++ @BeforeClass static public void beforeClass()
++ {
++ //org.apache.log4j.LogManager.resetConfiguration() ;
++ //org.apache.log4j.PropertyConfigurator.configure("log4j.properties") ;
++ Logger.getLogger("org.apache.jena.tdb.info").setLevel(Level.WARN) ;
++ //Logger.getLogger("org.apache.jena.tdb.exec").setLevel(Level.WARN) ;
++ dftReorder = SystemTDB.defaultReorderTransform ;
++ SystemTDB.defaultReorderTransform = ReorderLib.identity() ;
++ }
++
++ @AfterClass static public void afterClass() {
++ SystemTDB.defaultReorderTransform = dftReorder ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/TS_Factory.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/TS_Factory.java
index 0000000,0000000..b6dc979
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/TS_Factory.java
@@@ -1,0 -1,0 +1,32 @@@
++/*
++ * 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;
++
++
++import org.junit.runner.RunWith;
++import org.junit.runners.Suite;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestDatabaseMgr.class
++ , TestTDBFactory.class
++
++})
++
++public class TS_Factory
++{}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java
index 0000000,0000000..da75494
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java
@@@ -1,0 -1,0 +1,89 @@@
++/*
++ * 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;
++
++import static org.junit.Assert.*;
++import org.apache.jena.atlas.lib.FileOps ;
++import org.apache.jena.sparql.core.DatasetGraph ;
++import org.apache.jena.sparql.core.Quad ;
++import org.apache.jena.sparql.sse.SSE ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.tdb2.sys.TDBInternal ;
++
++/** Test of DatabaseMgr - the DatasetGraph level API to TDB2 **/
++public class TestDatabaseMgr
++{
++// String DIRx = ConfigTest.getCleanDir() ;
++// Location DIR = Location.create(DIRx);
++
++ static Quad quad1 = SSE.parseQuad("(_ _:a <p> 1)") ;
++ static Quad quad2 = SSE.parseQuad("(_ <s> <p> 1)") ;
++
++ @Test
++ public void testDatabaseMgr1() {
++ TDBInternal.reset() ;
++ DatasetGraph dg1 = DatabaseMgr.connectDatasetGraph(Location.mem("FOO")) ;
++ DatasetGraph dg2 = DatabaseMgr.connectDatasetGraph(Location.mem("FOO")) ;
++ Txn.executeWrite(dg1, ()->{
++ dg1.add(quad1) ;
++ }) ;
++ Txn.executeRead(dg2, ()->{
++ assertTrue(dg2.contains(quad1)) ;
++ }) ;
++ }
++
++ @Test
++ public void testDatabaseMgr2() {
++ TDBInternal.reset() ;
++ // The unnamed location is unique each time.
++ DatasetGraph dg1 = DatabaseMgr.connectDatasetGraph(Location.mem()) ;
++ DatasetGraph dg2 = DatabaseMgr.connectDatasetGraph(Location.mem()) ;
++ Txn.executeWrite(dg1, ()->{
++ dg1.add(quad1) ;
++ }) ;
++ Txn.executeRead(dg2, ()->{
++ assertFalse(dg2.contains(quad1)) ;
++ }) ;
++ }
++
++ @Test
++ public void testDatabaseMgrDisk() {
++ TDBInternal.reset() ;
++ // The named disk location
++ String DIRx = ConfigTest.getCleanDir() ;
++ Location LOC = Location.create(DIRx) ;
++ FileOps.clearDirectory(DIRx) ;
++ try {
++ DatasetGraph dg1 = DatabaseMgr.connectDatasetGraph(LOC) ;
++ DatasetGraph dg2 = DatabaseMgr.connectDatasetGraph(Location.create(LOC.getDirectoryPath())) ;
++ assertSame(dg1, dg2) ;
++ Txn.executeWrite(dg1, ()-> {
++ dg1.add(quad1) ;
++ }) ;
++ Txn.executeRead(dg2, ()-> {
++ assertTrue(dg2.contains(quad1)) ;
++ }) ;
++ }
++ finally {
++ FileOps.clearDirectory(DIRx) ;
++ }
++
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
index 0000000,0000000..752a95c
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
@@@ -1,0 -1,0 +1,130 @@@
++/*
++ * 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;
++
++import static org.junit.Assert.*;
++import org.apache.jena.atlas.lib.FileOps ;
++import org.apache.jena.datatypes.xsd.XSDDatatype ;
++import org.apache.jena.query.Dataset ;
++import org.apache.jena.rdf.model.Literal ;
++import org.apache.jena.rdf.model.Property ;
++import org.apache.jena.rdf.model.Resource ;
++import org.apache.jena.rdf.model.ResourceFactory ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.tdb2.sys.TDBInternal ;
++
++/** Test of TDB2Factory - the Dataset level API to TDB2 **/
++public class TestTDBFactory
++{
++ static Resource s1 = ResourceFactory.createResource("http://example/s2");
++ static Resource s2 = ResourceFactory.createResource();
++ static Property p = ResourceFactory.createProperty("http://example/ns#", "p");
++ static Literal o1 = ResourceFactory.createPlainLiteral("object");
++ static Literal o2 = ResourceFactory.createTypedLiteral("1", XSDDatatype.XSDinteger);
++
++ @Test
++ public void testTDBFactory1() {
++ TDBInternal.reset() ;
++ Dataset ds = TDB2Factory.connectDataset(Location.mem()) ;
++ test(ds);
++ }
++
++ @Test
++ public void testTDBFactory2() {
++ TDBInternal.reset() ;
++ Dataset ds = TDB2Factory.connectDataset(Location.mem("MEMORY")) ;
++ test(ds);
++ }
++
++ @Test
++ public void testTDBFactory3() {
++ TDBInternal.reset() ;
++ // Only do disk things for tests that need them (disk takes time!).
++ String DIRx = ConfigTest.getCleanDir() ;
++ Location DIR = Location.create(DIRx);
++ try {
++ FileOps.clearDirectory(DIRx) ;
++ Dataset ds = TDB2Factory.connectDataset(DIR) ;
++ test(ds);
++ } finally { FileOps.clearDirectory(DIRx) ; }
++ }
++
++ @Test
++ public void testTDBFactory2DS_1() {
++ TDBInternal.reset() ;
++ Dataset ds1 = TDB2Factory.connectDataset(Location.mem("FOO")) ;
++ Dataset ds2 = TDB2Factory.connectDataset(Location.mem("FOO")) ;
++ Txn.executeWrite(ds1, ()->{
++ ds1.getDefaultModel().add(s1, p, o1);
++ });
++ Txn.executeRead(ds2, ()->{
++ assertTrue(ds2.getDefaultModel().contains(s1, p, o1));
++ });
++ }
++
++ @Test
++ public void testTDBFactory2DS_2() {
++ TDBInternal.reset() ;
++ // The unnamed location is unique each time.
++ Dataset ds1 = TDB2Factory.connectDataset(Location.mem()) ;
++ Dataset ds2 = TDB2Factory.connectDataset(Location.mem()) ;
++ Txn.executeWrite(ds1, ()->{
++ ds1.getDefaultModel().add(s1, p, o1);
++ });
++ Txn.executeRead(ds2, ()->{
++ assertFalse(ds2.getDefaultModel().contains(s1, p, o1));
++ });
++ }
++
++ @Test
++ public void testTDBFactory2DS_3() {
++ TDBInternal.reset() ;
++ TDBInternal.reset() ;
++ String DIRx = ConfigTest.getCleanDir() ;
++ Location DIR = Location.create(DIRx);
++ try {
++ Dataset ds1 = TDB2Factory.connectDataset(DIR) ;
++ Dataset ds2 = TDB2Factory.connectDataset(DIR) ;
++ Txn.executeWrite(ds1, ()->{
++ ds1.getDefaultModel().add(s1, p, o1);
++ });
++ Txn.executeRead(ds2, ()->{
++ assertTrue(ds2.getDefaultModel().contains(s1, p, o1));
++ });
++ } finally { FileOps.clearDirectory(DIRx) ; }
++ }
++
++ private static void test(Dataset ds) {
++ Txn.executeWrite(ds, ()->{
++ ds.getDefaultModel().add(s1, p, o1);
++ });
++ Txn.executeRead(ds, ()->{
++ assertTrue(ds.getDefaultModel().contains(s1, p, o1));
++ });
++ Txn.executeWrite(ds, ()->{
++ ds.getDefaultModel().remove(s1, p, o1);
++ ds.getDefaultModel().add(s2, p, o2);
++ });
++ Txn.executeRead(ds, ()->{
++ assertFalse(ds.getDefaultModel().contains(s1, p, o1));
++ assertTrue(ds.getDefaultModel().contains(s2, p, o2));
++ });
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/assembler/TS_TDBAssembler.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/assembler/TS_TDBAssembler.java
index 0000000,0000000..d6f622a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/assembler/TS_TDBAssembler.java
@@@ -1,0 -1,0 +1,32 @@@
++/*
++ * 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.assembler;
++
++import org.junit.runner.RunWith ;
++import org.junit.runners.Suite ;
++import org.seaborne.tdb2.junit.Base_TS ;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestTDBAssembler.class
++})
++
++public class TS_TDBAssembler extends Base_TS
++{
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/assembler/TestTDBAssembler.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/assembler/TestTDBAssembler.java
index 0000000,0000000..f1e13e2
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/assembler/TestTDBAssembler.java
@@@ -1,0 -1,0 +1,142 @@@
++/*
++ * 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.assembler;
++
++import org.apache.jena.assembler.JA ;
++import org.apache.jena.assembler.exceptions.AssemblerException ;
++import static org.junit.Assert.*;
++import org.apache.jena.atlas.lib.FileOps ;
++import org.apache.jena.graph.Graph ;
++import org.apache.jena.query.Dataset ;
++import org.apache.jena.rdf.model.Model ;
++import org.apache.jena.rdf.model.Resource ;
++import org.apache.jena.sparql.core.assembler.AssemblerUtils ;
++import org.apache.jena.sparql.core.assembler.DatasetAssemblerVocab ;
++import org.junit.AfterClass ;
++import org.junit.Before ;
++import org.junit.BeforeClass ;
++import org.junit.Test ;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
++import org.seaborne.tdb2.store.GraphViewSwitchable ;
++import org.seaborne.tdb2.sys.TDBInternal ;
++
++public class TestTDBAssembler
++{
++ // Can be slow - explicitly closes the dataset.
++ static String dirAssem = null ;
++ static final String dirDB = ConfigTest.getTestingDir()+"/DB" ;
++
++ @BeforeClass
++ static public void beforeClass() {
++ dirAssem = ConfigTest.getTestingDataRoot() + "/Assembler" ;
++ FileOps.ensureDir(dirDB) ;
++ }
++
++ @Before
++ public void before() {
++ TDBInternal.reset() ;
++ FileOps.clearDirectory(dirDB) ;
++ }
++
++ @AfterClass
++ static public void afterClass() {
++ TDBInternal.reset() ;
++ FileOps.clearDirectory(dirDB) ;
++ }
++
++ @Test
++ public void createDatasetDirect() {
++ createTest(dirAssem + "/tdb-dataset.ttl", VocabTDB2.tDatasetTDB) ;
++ }
++
++ @Test
++ public void createDatasetEmbed() {
++ createTest(dirAssem + "/tdb-dataset-embed.ttl", DatasetAssemblerVocab.tDataset) ;
++ }
++
++ private void createTest(String filename, Resource type) {
++ Object thing = AssemblerUtils.build(filename, type) ;
++ assertTrue(thing instanceof Dataset) ;
++ Dataset ds = (Dataset)thing ;
++ assertTrue(ds.asDatasetGraph() instanceof DatasetGraphSwitchable) ;
++ assertTrue(ds.supportsTransactions()) ;
++ ds.close() ;
++ }
++
++ @Test
++ public void createGraphDirect() {
++ testGraph(dirAssem + "/tdb-graph.ttl", false) ;
++ }
++
++ @Test
++ public void createGraphEmbed() {
++ String f = dirAssem + "/tdb-graph-embed.ttl" ;
++ Object thing = null ;
++ try {
++ thing = AssemblerUtils.build(f, JA.Model) ;
++ }
++ catch (AssemblerException e) {
++ e.getCause().printStackTrace(System.err) ;
++ throw e ;
++ }
++
++ assertTrue(thing instanceof Model) ;
++ Graph graph = ((Model)thing).getGraph() ;
++ assertTrue(graph instanceof GraphViewSwitchable) ;
++
++ DatasetGraphSwitchable ds = ((GraphViewSwitchable)graph).getDataset() ;
++ if ( ds != null )
++ ds.close() ;
++ }
++
++ @Test
++ public void createNamedGraph1() {
++ testGraph(dirAssem + "/tdb-named-graph-1.ttl", true) ;
++ }
++
++ @Test
++ public void createNamedGraph2() {
++ testGraph(dirAssem + "/tdb-named-graph-2.ttl", true) ;
++ }
++
++ @Test
++ public void createNamedGraphViaDataset() {
++ testGraph(dirAssem + "/tdb-graph-ref-dataset.ttl", false) ;
++ }
++
++ private static void testGraph(String assemblerFile, boolean named) {
++ Object thing = null ;
++ try {
++ thing = AssemblerUtils.build(assemblerFile, VocabTDB2.tGraphTDB) ;
++ }
++ catch (AssemblerException e) {
++ e.getCause().printStackTrace(System.err) ;
++ throw e ;
++ }
++
++ assertTrue(thing instanceof Model) ;
++ Graph graph = ((Model)thing).getGraph() ;
++
++ assertTrue(graph instanceof GraphViewSwitchable) ;
++
++ DatasetGraphSwitchable dsg = ((GraphViewSwitchable)graph).getDataset();
++ if ( dsg != null )
++ dsg.close() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/AbstractTestGraphsTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/AbstractTestGraphsTDB.java
index 0000000,0000000..762e8ee
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/AbstractTestGraphsTDB.java
@@@ -1,0 -1,0 +1,50 @@@
++/*
++ * 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.graph;
++
++import org.apache.jena.sparql.engine.optimizer.reorder.ReorderLib ;
++import org.apache.jena.sparql.engine.optimizer.reorder.ReorderTransformation ;
++import org.apache.jena.sparql.graph.GraphsTests ;
++import org.junit.AfterClass ;
++import org.junit.BeforeClass ;
++import org.junit.Ignore ;
++import org.junit.Test ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++
++public abstract class AbstractTestGraphsTDB extends GraphsTests
++{
++ private static ReorderTransformation reorder ;
++
++ @BeforeClass public static void setupClass()
++ {
++ reorder = SystemTDB.defaultReorderTransform ;
++ SystemTDB.defaultReorderTransform = ReorderLib.identity() ;
++ }
++
++ @AfterClass public static void afterClass() { SystemTDB.defaultReorderTransform = reorder ; }
++
++ // These don't pass ... not quite clear if the test is right. Investigate.
++
++ @Override
++ @Ignore @Test public void graph_count5() {}
++
++ @Override
++ @Ignore @Test public void graph_count6() {}
++
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TS_Graph.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TS_Graph.java
index 0000000,0000000..b6dbdea
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TS_Graph.java
@@@ -1,0 -1,0 +1,35 @@@
++/*
++ * 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.graph;
++
++import org.junit.runner.RunWith ;
++import org.junit.runners.Suite ;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestPrefixMappingTDB.class
++ , TestDatasetGraphTDB.class
++ , TestGraphsTDB1.class
++ , TestGraphsTDB2.class
++ , TestDatasetGraphAccessorTDB.class
++ , TestGraphOverDatasetTDB.class
++})
++public class TS_Graph
++{
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphAccessorTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphAccessorTDB.java
index 0000000,0000000..8184154
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphAccessorTDB.java
@@@ -1,0 -1,0 +1,47 @@@
++/*
++ * 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.graph;
++
++import org.apache.jena.query.DatasetAccessorFactory ;
++import org.apache.jena.query.ReadWrite ;
++import org.apache.jena.sparql.core.DatasetGraph ;
++import org.apache.jena.web.AbstractTestDatasetGraphAccessor ;
++import org.apache.jena.web.DatasetGraphAccessor ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.seaborne.tdb2.junit.TL ;
++
++public class TestDatasetGraphAccessorTDB extends AbstractTestDatasetGraphAccessor
++{
++ DatasetGraph dsg = TL.createTestDatasetGraphMem() ;
++ @Before public void before() {
++ dsg.begin(ReadWrite.WRITE);
++ }
++
++ @After public void after() {
++ dsg.abort();
++ dsg.end();
++ TL.expel(dsg);
++ }
++
++ @Override
++ protected DatasetGraphAccessor getDatasetUpdater()
++ {
++ return DatasetAccessorFactory.make(dsg) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphTDB.java
index 0000000,0000000..0cd2bca
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestDatasetGraphTDB.java
@@@ -1,0 -1,0 +1,52 @@@
++/*
++ * 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.graph;
++
++import org.apache.jena.query.ReadWrite ;
++import org.apache.jena.sparql.core.AbstractDatasetGraphTests ;
++import org.apache.jena.sparql.core.DatasetGraph ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.tdb2.junit.TL ;
++
++// Quad tests
++public class TestDatasetGraphTDB extends AbstractDatasetGraphTests
++{
++ DatasetGraph dsg = TL.createTestDatasetGraphMem() ;
++ @Before public void before() {
++ dsg.begin(ReadWrite.WRITE);
++ }
++
++ @After public void after() {
++ dsg.abort();
++ dsg.end();
++ TL.expel(dsg);
++ }
++
++ @Override
++ protected DatasetGraph emptyDataset() {
++ return dsg ;
++ }
++
++ @Override
++ // Empty graph tests: N/A
++ @Test public void graph_01()
++ {}
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphOverDatasetTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphOverDatasetTDB.java
index 0000000,0000000..de01a86
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphOverDatasetTDB.java
@@@ -1,0 -1,0 +1,63 @@@
++/*
++ * 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.graph;
++
++import org.apache.jena.graph.Graph ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.query.ReadWrite ;
++import org.apache.jena.sparql.core.AbstractTestGraphOverDataset ;
++import org.apache.jena.sparql.core.DatasetGraph ;
++import org.junit.After ;
++import org.seaborne.tdb2.junit.TL ;
++
++/** This is the view-graph test suite run over a TDB DatasetGraph to check compatibility */
++public class TestGraphOverDatasetTDB extends AbstractTestGraphOverDataset
++{
++ DatasetGraph dsg = null;
++ @After public void after2() {
++ if ( dsg == null )
++ return;
++ dsg.abort();
++ dsg.end();
++ TL.expel(dsg);
++ }
++
++ @Override
++ protected DatasetGraph createBaseDSG() {
++ // Called in initialization.
++ if ( dsg == null ) {
++ dsg = TL.createTestDatasetGraphMem() ;
++ dsg.begin(ReadWrite.WRITE);
++ }
++ return dsg ;
++ }
++
++ @Override
++ protected Graph makeNamedGraph(DatasetGraph dsg, Node gn)
++ {
++ return dsg.getGraph(gn) ;
++ }
++
++ @Override
++ protected Graph makeDefaultGraph(DatasetGraph dsg)
++ {
++ return dsg.getDefaultGraph() ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphsTDB1.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphsTDB1.java
index 0000000,0000000..3f703e5
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphsTDB1.java
@@@ -1,0 -1,0 +1,42 @@@
++/*
++ * 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.graph;
++
++import org.apache.jena.query.Dataset ;
++import org.apache.jena.query.ReadWrite ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.seaborne.tdb2.junit.TL ;
++
++public class TestGraphsTDB1 extends AbstractTestGraphsTDB
++{
++ Dataset ds = TL.createTestDatasetMem();
++ @Before public void before() {
++ ds.begin(ReadWrite.WRITE);
++ }
++
++ @After public void after() {
++ ds.abort();
++ ds.end();
++ TL.expel(ds);
++ }
++ @Override
++ protected Dataset createDataset() {
++ return ds ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphsTDB2.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphsTDB2.java
index 0000000,0000000..ba665f8
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestGraphsTDB2.java
@@@ -1,0 -1,0 +1,51 @@@
++/*
++ * 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.graph;
++
++import org.apache.jena.query.Dataset ;
++import org.apache.jena.query.ReadWrite ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.tdb2.TDB2Factory ;
++
++public class TestGraphsTDB2 extends AbstractTestGraphsTDB
++{
++ // Transactional.
++ @Before
++ public void before() {
++ getDataset().begin(ReadWrite.READ) ;
++ }
++
++ @After
++ public void after() {
++ getDataset().end() ;
++ }
++
++ @Override
++ protected void fillDataset(Dataset dataset) {
++ Txn.executeWrite(dataset, ()->{
++ super.fillDataset(dataset) ;
++ });
++ }
++
++ @Override
++ protected Dataset createDataset() {
++ return TDB2Factory.createDataset() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestPrefixMappingTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestPrefixMappingTDB.java
index 0000000,0000000..7deaea4
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/graph/TestPrefixMappingTDB.java
@@@ -1,0 -1,0 +1,106 @@@
++/*
++ * 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.graph;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.apache.jena.shared.PrefixMapping ;
++import org.apache.jena.sparql.core.DatasetPrefixStorage ;
++import org.apache.jena.sparql.graph.AbstractTestPrefixMapping2 ;
++import org.junit.* ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.junit.BuildTestLib ;
++import org.seaborne.tdb2.sys.TDBInternal ;
++
++public class TestPrefixMappingTDB extends AbstractTestPrefixMapping2
++{
++ static DatasetPrefixStorage last = null ;
++
++ @BeforeClass public static void beforeClass() {}
++ @AfterClass public static void afterClass() { TDBInternal.reset() ; ConfigTest.deleteTestingDir() ; }
++
++ @Before public void before() { TDBInternal.reset() ; }
++ @After public void after() { }
++
++
++ @Override
++ protected PrefixMapping create() {
++ last = createTestingMem() ;
++ return view() ;
++ }
++
++ static DatasetPrefixStorage createTestingMem() {
++ return createTesting(Location.mem()) ;
++ }
++
++ static DatasetPrefixStorage createTesting(Location location) {
++ return BuildTestLib.makePrefixes(location) ;
++ }
++
++ @Override
++ protected PrefixMapping view() {
++ return last.getPrefixMapping() ;
++ }
++
++ @Test public void multiple1() {
++ DatasetPrefixStorage prefixes = createTestingMem() ;
++ PrefixMapping pmap1 = prefixes.getPrefixMapping() ;
++ PrefixMapping pmap2 = prefixes.getPrefixMapping("http://graph/") ;
++ pmap1.setNsPrefix("x", "http://foo/") ;
++ assertNull(pmap2.getNsPrefixURI("x")) ;
++ assertNotNull(pmap1.getNsPrefixURI("x")) ;
++ }
++
++ @Test public void multiple2() {
++ DatasetPrefixStorage prefixes = createTestingMem() ;
++ PrefixMapping pmap1 = prefixes.getPrefixMapping("http://graph/") ; // Same
++ PrefixMapping pmap2 = prefixes.getPrefixMapping("http://graph/") ;
++ pmap1.setNsPrefix("x", "http://foo/") ;
++ assertNotNull(pmap2.getNsPrefixURI("x")) ;
++ assertNotNull(pmap1.getNsPrefixURI("x")) ;
++ }
++
++ // Persistent.
++ @Test
++ public void persistent1() {
++ String dir = ConfigTest.getTestingDir() ;
++ FileOps.clearDirectory(dir) ;
++
++ DatasetPrefixStorage prefixes = createTesting(Location.create(dir)) ;
++ PrefixMapping pmap1 = prefixes.getPrefixMapping() ;
++
++ String x = pmap1.getNsPrefixURI("x") ;
++ assertNull(x) ;
++ prefixes.close() ;
++ }
++
++ // Persistent.
++ @Test
++ public void persistent2() {
++ String dir = ConfigTest.getTestingDir() ;
++ FileOps.clearDirectory(dir) ;
++
++ DatasetPrefixStorage prefixes = createTesting(Location.create(dir)) ;
++ PrefixMapping pmap1 = prefixes.getPrefixMapping() ;
++
++ pmap1.setNsPrefix("x", "http://foo/") ;
++ assertEquals("http://foo/", pmap1.getNsPrefixURI("x")) ;
++ prefixes.close() ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/AbstractTestGraphTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/AbstractTestGraphTDB.java
index 0000000,0000000..bac78a5
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/AbstractTestGraphTDB.java
@@@ -1,0 -1,0 +1,33 @@@
++/*
++ * 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.junit;
++
++import org.apache.jena.graph.test.AbstractTestGraph ;
++
++public abstract class AbstractTestGraphTDB extends AbstractTestGraph
++{
++ public AbstractTestGraphTDB(String name)
++ {
++ super(name) ;
++ }
++
++ @Override public void testIsomorphismFile() {}
++
++ // Meaning less - graphs (and hence models) are not indpenedent of their datasets.
++ @Override public void testCloseSetsIsClosed() {}
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/Base_TS.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/Base_TS.java
index 0000000,0000000..ce2eda1
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/Base_TS.java
@@@ -1,0 -1,0 +1,51 @@@
++/*
++ * 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.junit;
++
++import org.apache.jena.sparql.engine.optimizer.reorder.ReorderLib ;
++import org.apache.jena.sparql.engine.optimizer.reorder.ReorderTransformation ;
++import org.apache.log4j.Level ;
++import org.apache.log4j.Logger ;
++import org.junit.AfterClass ;
++import org.junit.BeforeClass ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++
++public class Base_TS
++{
++ static Level level = null ;
++ static ReorderTransformation rt = null ;
++
++ @BeforeClass static public void beforeClass()
++ {
++ rt = SystemTDB.defaultReorderTransform ;
++ level = Logger.getLogger("org.apache.jena.tdb.info").getLevel() ;
++ Logger.getLogger("org.apache.jena.tdb.info").setLevel(Level.FATAL) ;
++ Logger.getLogger("org.seaborne.tdb2.info").setLevel(Level.FATAL) ;
++ SystemTDB.defaultReorderTransform = ReorderLib.identity() ;
++ rt = SystemTDB.defaultReorderTransform ;
++ }
++
++ @AfterClass static public void afterClass()
++ {
++ if ( level != null ) {
++ Logger.getLogger("org.apache.jena.tdb.info").setLevel(level) ;
++ Logger.getLogger("org.seaborne.tdb2.info").setLevel(level) ;
++ }
++ SystemTDB.defaultReorderTransform = rt ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/BuildTestLib.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/BuildTestLib.java
index 0000000,0000000..171232e
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/BuildTestLib.java
@@@ -1,0 -1,0 +1,81 @@@
++/*
++ * 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.junit;
++
++import org.apache.jena.query.ReadWrite ;
++import org.apache.jena.sparql.core.DatasetPrefixStorage ;
++import org.seaborne.dboe.base.file.* ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.index.Index ;
++import org.seaborne.dboe.index.IndexParams ;
++import org.seaborne.dboe.index.RangeIndex ;
++import org.seaborne.dboe.trans.bplustree.BPlusTree ;
++import org.seaborne.dboe.trans.bplustree.BPlusTreeFactory ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.setup.TDBBuilder ;
++import org.seaborne.tdb2.store.DatasetGraphTDB ;
++import org.seaborne.tdb2.store.nodetable.NodeTable ;
++import org.seaborne.tdb2.store.nodetable.NodeTableCache ;
++import org.seaborne.tdb2.store.nodetable.NodeTableInline ;
++import org.seaborne.tdb2.store.nodetable.NodeTableTRDF ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++
++/** Build things for non-transactional tests.
++ * Sometimes, create a daatset and find the relevant part.
++ */
++public class BuildTestLib {
++
++ public static RangeIndex buildRangeIndex(FileSet mem, RecordFactory factory, IndexParams indexParams) {
++ BPlusTree bpt = BPlusTreeFactory.makeMem(5, factory.keyLength(), factory.valueLength()) ;
++ bpt.nonTransactional() ;
++ return bpt ;
++ }
++
++ public static NodeTable makeNodeTable(Location location, String basename, StoreParams params) {
++ NodeTable nt = makeNodeTableBase(location, basename, params) ;
++ nt = NodeTableCache.create(nt, params) ;
++ nt = NodeTableInline.create(nt) ;
++ return nt ;
++ }
++
++ public static NodeTable makeNodeTableBase(Location location, String basename, StoreParams params) {
++ RecordFactory recordFactory = new RecordFactory(SystemTDB.LenNodeHash, SystemTDB.SizeOfNodeId) ;
++ FileSet fs = new FileSet(location, basename) ;
++
++ Index index = buildRangeIndex(fs, recordFactory, params) ;
++ BinaryDataFile bdf = createBinaryDataFile(location, basename+"-data") ;
++ NodeTable nt = new NodeTableTRDF(index, bdf) ;
++ return nt ;
++ }
++
++ public static DatasetPrefixStorage makePrefixes(Location location) {
++ DatasetGraphTDB ds = (DatasetGraphTDB)TDBBuilder.build(location) ;
++ ds.begin(ReadWrite.WRITE);
++ return ds.getPrefixes() ;
++ }
++
++ /** Create a non-thread-safe BinaryDataFile*/
++ public static BinaryDataFile createBinaryDataFile(Location loc, String name) {
++ if ( loc.isMem() )
++ return new BinaryDataFileMem() ;
++ String filename = loc.getPath(name) ;
++ return new BinaryDataFileRandomAccess(filename) ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/QueryTestTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/QueryTestTDB.java
index 0000000,0000000..ef16ed9
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/QueryTestTDB.java
@@@ -1,0 -1,0 +1,192 @@@
++/*
++ * 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.junit;
++
++import java.util.List ;
++
++import org.apache.jena.query.* ;
++import org.apache.jena.rdf.model.Model ;
++import org.apache.jena.sparql.SystemARQ ;
++import org.apache.jena.sparql.engine.QueryEngineFactory ;
++import org.apache.jena.sparql.engine.QueryExecutionBase ;
++import org.apache.jena.sparql.engine.ref.QueryEngineRef ;
++import org.apache.jena.sparql.junit.EarlReport ;
++import org.apache.jena.sparql.junit.EarlTestCase ;
++import org.apache.jena.sparql.junit.TestItem ;
++import org.apache.jena.sparql.resultset.ResultSetCompare ;
++import org.apache.jena.sparql.resultset.SPARQLResult ;
++import org.apache.jena.util.FileManager ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.tdb2.TDB2Factory ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++public class QueryTestTDB extends EarlTestCase
++{
++ // Changed to using in-memory graphs/datasets because this is testing the query
++ // processing. Physical graph/datsets is in package "store".
++
++ private static Logger log = LoggerFactory.getLogger(QueryTestTDB.class) ;
++ private Dataset dataset = null ;
++
++ boolean skipThisTest = false ;
++
++ final List<String> defaultGraphURIs ;
++ final List<String> namedGraphURIs ;
++ final String queryFile ;
++ final SPARQLResult results ;
++
++ // Track what's currently loaded in the GraphLocation
++ private static List<String> currentDefaultGraphs = null ;
++ private static List<String> currentNamedGraphs = null ;
++
++ // Old style (Junit3)
++ public QueryTestTDB(String testName, EarlReport report, TestItem item)
++ {
++ this(testName, report, item.getURI(),
++ item.getDefaultGraphURIs(), item.getNamedGraphURIs(),
++ item.getResults(), item.getQueryFile()
++ ) ;
++ }
++
++ public QueryTestTDB(String testName, EarlReport report,
++ String uri,
++ List<String> dftGraphs,
++ List<String> namedGraphs,
++ SPARQLResult rs,
++ String queryFile
++ )
++ {
++ super(testName, uri, report) ;
++ this.defaultGraphURIs = dftGraphs ;
++ this.namedGraphURIs = namedGraphs ;
++ this.queryFile = queryFile ;
++ this.results = rs ;
++ }
++
++ boolean oldValueUsePlainGraph = SystemARQ.UsePlainGraph ;
++
++ @Override public void setUpTest() {
++ dataset = TDB2Factory.createDataset() ;
++ Txn.executeWrite(dataset, ()->{
++ setupData() ;
++ }) ;
++ // Make sure a plain, no sameValueAs graph is used.
++ oldValueUsePlainGraph = SystemARQ.UsePlainGraph ;
++ SystemARQ.UsePlainGraph = true ;
++ }
++
++ @Override public void tearDownTest()
++ {
++ if ( dataset != null )
++ {
++ dataset.close() ;
++ dataset = null ;
++ }
++ SystemARQ.UsePlainGraph = oldValueUsePlainGraph ;
++ }
++
++ public void setupData()
++ {
++ if ( compareLists(defaultGraphURIs, currentDefaultGraphs) &&
++ compareLists(namedGraphURIs, currentNamedGraphs) )
++ return ;
++
++ if ( defaultGraphURIs == null )
++ throw new TDBTestException("No default graphs given") ;
++
++ //graphLocation.clear() ;
++
++ for ( String fn : defaultGraphURIs )
++ load(dataset.getDefaultModel(), fn) ;
++
++ for ( String fn : namedGraphURIs )
++ load(dataset.getNamedModel(fn), fn) ;
++ }
++
++
++ @Override
++ protected void runTestForReal() throws Throwable
++ {
++ if ( skipThisTest )
++ {
++ log.info(this.getName()+" : Skipped") ;
++ return ;
++ }
++
++ Query query = QueryFactory.read(queryFile) ;
++ Dataset ds = DatasetFactory.create(defaultGraphURIs, namedGraphURIs) ;
++
++ // ---- First, get the expected results by executing in-memory or from a results file.
++
++ ResultSetRewindable rs1$ = null ;
++ String expectedLabel$ = "" ;
++ if ( results != null )
++ {
++ rs1$ = ResultSetFactory.makeRewindable(results.getResultSet()) ;
++ expectedLabel$ = "Results file" ;
++ }
++ else
++ {
++ QueryEngineFactory f = QueryEngineRef.getFactory() ;
++ try(QueryExecution qExec1 = new QueryExecutionBase(query, ds, null, f)) {
++ rs1$ = ResultSetFactory.makeRewindable(qExec1.execSelect()) ;
++ }
++ expectedLabel$ = "Standard engine" ;
++ }
++ // Effectively final.
++ ResultSetRewindable rs1 = rs1$ ;
++ String expectedLabel = expectedLabel$ ;
++ // ---- Second, execute in persistent graph
++
++ Dataset ds2 = dataset ; //DatasetFactory.create(model) ;
++ Txn.executeRead(ds2, ()->{
++ try(QueryExecution qExec2 = QueryExecutionFactory.create(query, ds2)) {
++ ResultSet rs = qExec2.execSelect() ;
++ ResultSetRewindable rs2 = ResultSetFactory.makeRewindable(rs) ;
++
++ // See if the same.
++ boolean b = ResultSetCompare.equalsByValue(rs1, rs2) ;
++ if ( !b )
++ {
++ rs1.reset() ;
++ rs2.reset() ;
++ System.out.println("------------------- "+this.getName());
++ System.out.printf("**** Expected (%s)", expectedLabel) ;
++ ResultSetFormatter.out(System.out, rs1) ;
++ System.out.println("**** Got (TDB)") ;
++ ResultSetFormatter.out(System.out, rs2) ;
++ }
++
++ assertTrue("Results sets not the same", b) ;
++ }
++ }) ;
++ }
++
++ private static void load(Model model, String fn)
++ {
++ FileManager.get().readModel(model, fn) ;
++ }
++
++ private static boolean compareLists(List<String> list1, List<String> list2)
++ {
++ if ( list1 == null )
++ return ( list2 == null ) ;
++ return list1.equals(list2) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/TDBTestException.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/TDBTestException.java
index 0000000,0000000..e2e2bcb
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/TDBTestException.java
@@@ -1,0 -1,0 +1,28 @@@
++/*
++ * 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.junit;
++
++import org.seaborne.tdb2.TDBException ;
++
++public class TDBTestException extends TDBException
++{
++ public TDBTestException() {}
++ public TDBTestException(String msg) { super(msg) ; }
++ public TDBTestException(Throwable th) { super(th) ;}
++ public TDBTestException(String msg, Throwable th) { super(msg, th) ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
index 0000000,0000000..4ff4ae6
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/TL.java
@@@ -1,0 -1,0 +1,89 @@@
++/*
++ * 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.junit;
++
++import java.util.function.Consumer ;
++
++import org.apache.jena.query.Dataset ;
++import org.apache.jena.sparql.core.DatasetGraph ;
++import org.apache.jena.system.Txn ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.DatabaseMgr ;
++import org.seaborne.tdb2.TDB2Factory ;
++import org.seaborne.tdb2.sys.TDBInternal ;
++
++/** Support for tests to be less "transaction-y" */
++public class TL {
++
++ public static void exec(Consumer<Dataset> action) {
++ Dataset dataset = createTestDataset();
++ try {
++ Txn.executeWrite(dataset, ()->action.accept(dataset));
++ //TDBInternal.reset();
++
++ } finally { expel(dataset); }
++ }
++
++ public static void execMem(Consumer<Dataset> action) {
++ Dataset dataset = createTestDatasetMem() ;
++ Txn.executeWrite(dataset, ()->action.accept(dataset));
++ expel(dataset);
++ }
++
++ public static void expel(Dataset dataset) {
++ expel(dataset.asDatasetGraph());
++ }
++
++ public static void expel(DatasetGraph dataset) {
++ TDBInternal.expel(dataset);
++ }
++
++ // Or use these for @Before, @After style.
++
++ public static Location cleanLocation() {
++ // To avoid the problems on MS Windows where memory mapped files
++ // can't be deleted from a running JVM, we use a different, cleaned
++ // directory each time.
++ String dirname = ConfigTest.getCleanDir() ;
++ Location location = Location.create(dirname) ;
++ return location ;
++ }
++
++ private static void releaseDataset(Dataset dataset) {
++ dataset.abort() ;
++ expel(dataset);
++ }
++
++ private static Dataset createTestDataset() {
++ Location location = cleanLocation() ;
++ Dataset dataset = TDB2Factory.connectDataset(location) ;
++ return dataset ;
++ }
++
++ public static Dataset createTestDatasetMem() {
++ Dataset dataset = TDB2Factory.createDataset() ;
++ return dataset ;
++ }
++
++ public static DatasetGraph createTestDatasetGraphMem() {
++ DatasetGraph dataset = DatabaseMgr.createDatasetGraph() ;
++ return dataset ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/TestFactoryTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/TestFactoryTDB.java
index 0000000,0000000..516de02
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/junit/TestFactoryTDB.java
@@@ -1,0 -1,0 +1,87 @@@
++/*
++ * 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.junit;
++
++import junit.framework.Test ;
++import junit.framework.TestCase ;
++import junit.framework.TestSuite ;
++import org.apache.jena.rdf.model.Resource ;
++import org.apache.jena.sparql.junit.EarlReport ;
++import org.apache.jena.sparql.junit.SurpressedTest ;
++import org.apache.jena.sparql.junit.TestItem ;
++import org.apache.jena.sparql.vocabulary.TestManifestX ;
++import org.apache.jena.util.junit.TestFactoryManifest ;
++
++public class TestFactoryTDB extends TestFactoryManifest
++{
++ public static EarlReport report = null ;
++
++ public static void make(TestSuite ts, String manifestFile, String testRootName)
++ {
++ // for each graph type do
++ TestSuite ts2 = makeSuite(manifestFile, testRootName) ;
++ ts.addTest(ts2) ;
++ }
++
++ public static TestSuite makeSuite(String manifestFile, String testRootName)
++ {
++ TestFactoryTDB f = new TestFactoryTDB(testRootName) ;
++ TestSuite ts = f.process(manifestFile) ;
++ if ( testRootName != null )
++ ts.setName(testRootName+ts.getName()) ;
++ return ts ;
++ }
++
++ // Factory
++
++ public String testRootName ;
++
++ public TestFactoryTDB(String testRootName)
++ {
++ this.testRootName = testRootName ;
++ }
++
++ @Override
++ protected Test makeTest(Resource manifest, Resource entry, String testName, Resource action, Resource result)
++ {
++ if ( testRootName != null )
++ testName = testRootName+testName ;
++
++ TestItem testItem = TestItem.create(entry, null) ;
++
++ TestCase test = null ;
++
++ if ( testItem.getTestType() != null )
++ {
++ if ( testItem.getTestType().equals(TestManifestX.TestQuery) )
++ test = new QueryTestTDB(testName, report, testItem) ;
++
++ if ( testItem.getTestType().equals(TestManifestX.TestSurpressed) )
++ test = new SurpressedTest(testName, report, testItem) ;
++
++ if ( test == null )
++ System.err.println("Unrecognized test type: "+testItem.getTestType()) ;
++ }
++ // Default
++ if ( test == null )
++ test = new QueryTestTDB(testName, report, testItem) ;
++
++ return test ;
++ }
++
++}
[35/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Basic/manifest.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Basic/manifest.ttl
index 0000000,0000000..aacbb56
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Basic/manifest.ttl
@@@ -1,0 -1,0 +1,101 @@@
++# 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.
++
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
++@prefix qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
++
++<> rdf:type mf:Manifest ;
++ rdfs:label "Basic test cases" ;
++ mf:entries
++ (
++ [ mf:name "Basic 00" ;
++ mf:action
++ [ qt:query <basic-00.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic S" ;
++ mf:action
++ [ qt:query <basic-1-S.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic P" ;
++ mf:action
++ [ qt:query <basic-1-P.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic O" ;
++ mf:action
++ [ qt:query <basic-1-O.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 1 SP" ;
++ mf:action
++ [ qt:query <basic-1-SP.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 1 SO" ;
++ mf:action
++ [ qt:query <basic-1-SO.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 1 PO" ;
++ mf:action
++ [ qt:query <basic-1-PO.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 1 SPO" ;
++ mf:action
++ [ qt:query <basic-1-SPO.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 2 SO" ;
++ mf:action
++ [ qt:query <basic-2-SO.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++
++ [ mf:name "Basic 3 S" ;
++ mf:action
++ [ qt:query <basic-3-S.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 3 P" ;
++ mf:action
++ [ qt:query <basic-3-P.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 3 O" ;
++ mf:action
++ [ qt:query <basic-3-O.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 3 SP" ;
++ mf:action
++ [ qt:query <basic-3-SP.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 3 SO" ;
++ mf:action
++ [ qt:query <basic-3-SO.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 3 PO" ;
++ mf:action
++ [ qt:query <basic-3-SO.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ ) .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Data/solver-data.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Data/solver-data.ttl
index 0000000,0000000..cdbfb19
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Data/solver-data.ttl
@@@ -1,0 -1,0 +1,7 @@@
++@prefix : <http://example/> .
++
++:s :p :o .
++:s :p 10 .
++:s :p :x .
++:x :q :y .
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Loader/data-1.nq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Loader/data-1.nq
index 0000000,0000000..e9812a6
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Loader/data-1.nq
@@@ -1,0 -1,0 +1,1 @@@
++<s> <p> <o> <g> .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Loader/data-2.nt
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Loader/data-2.nt
index 0000000,0000000..81fc25f
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Loader/data-2.nt
@@@ -1,0 -1,0 +1,1 @@@
++<s> <p> <o> .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Loader/data-3.trig
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Loader/data-3.trig
index 0000000,0000000..8000cc1
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Loader/data-3.trig
@@@ -1,0 -1,0 +1,3 @@@
++prefix : <http://example/>
++
++:g { :s :p :o }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Loader/data-4.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Loader/data-4.ttl
index 0000000,0000000..49678f1
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Loader/data-4.ttl
@@@ -1,0 -1,0 +1,4 @@@
++prefix : <http://example/>
++
++:s :p :o .
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Pattern/data-1.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Pattern/data-1.ttl
index 0000000,0000000..d3a3d80
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Pattern/data-1.ttl
@@@ -1,0 -1,0 +1,17 @@@
++@prefix : <http://example/> .
++
++:x1 :p1 :z1 .
++:x1 :p1 :z2 .
++
++:x1 :p2 :z1 .
++:x1 :p2 :z2 .
++
++:x2 :p1 :z1 .
++:x2 :p1 :z2 .
++
++:x2 :p2 :z1 .
++:x2 :p2 :z2 .
++
++:x :p :x .
++:x :x :x .
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Pattern/manifest.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Pattern/manifest.ttl
index 0000000,0000000..094244b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Pattern/manifest.ttl
@@@ -1,0 -1,0 +1,35 @@@
++# 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.
++
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
++@prefix qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
++
++<> rdf:type mf:Manifest ;
++ rdfs:label "Patterns" ;
++ mf:entries
++ (
++ [ mf:name "Pattern 1" ;
++ mf:action
++ [ qt:query <pattern-1.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Pattern 2" ;
++ mf:action
++ [ qt:query <pattern-2.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ ) .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Pattern/pattern-1.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Pattern/pattern-1.rq
index 0000000,0000000..ca7c8fc
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Pattern/pattern-1.rq
@@@ -1,0 -1,0 +1,7 @@@
++PREFIX : <http://example/OTHER>
++
++SELECT *
++{
++ :NoSuchNode ?p ?z .
++ ?x ?p ?z
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Pattern/pattern-2.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Pattern/pattern-2.rq
index 0000000,0000000..9b90038
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Pattern/pattern-2.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example/OTHER>
++
++SELECT *
++{
++ # Test shared variables
++ ?x1 :p1 ?z .
++ ?x2 :p1 ?z .
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Quads/data-1.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Quads/data-1.ttl
index 0000000,0000000..adc4239
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Quads/data-1.ttl
@@@ -1,0 -1,0 +1,5 @@@
++@prefix : <http://example/> .
++
++:x :p 1 .
++
++:x1 :p :x .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Quads/data-2.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Quads/data-2.ttl
index 0000000,0000000..100a7c7
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Quads/data-2.ttl
@@@ -1,0 -1,0 +1,5 @@@
++@prefix : <http://example/> .
++
++:x :p 1 .
++
++:x2 :p :x .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Quads/data-dft.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Quads/data-dft.ttl
index 0000000,0000000..a2ef718
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Quads/data-dft.ttl
@@@ -1,0 -1,0 +1,10 @@@
++@prefix : <http://example/> .
++
++:x :p 1 .
++:x :p 2 .
++
++:y :p 1 .
++:y :p :x .
++:y :p :z .
++
++:z :q "abc" .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Quads/manifest.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Quads/manifest.ttl
index 0000000,0000000..15a46a7
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Quads/manifest.ttl
@@@ -1,0 -1,0 +1,51 @@@
++# 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.
++
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
++@prefix qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
++
++<> rdf:type mf:Manifest ;
++ rdfs:label "Quads and quad patterns" ;
++ mf:entries
++ (
++ [ mf:name "Quad-1" ;
++ mf:action
++ [ qt:query <quad-01.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ]
++ ]
++ [ mf:name "Quad-2" ;
++ mf:action
++ [ qt:query <quad-02.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ]
++ ]
++
++ ## Union of named graphs, explicitly named default graph
++ ## Complex patterns.
++
++## [ mf:name "Basic 00" ;
++## mf:action
++## [ qt:query <basic-00.rq> ;
++## qt:data <data-1.ttl> ;
++## qt:graphData ; ]
++## ]
++ ) .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Quads/quad-01.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Quads/quad-01.rq
index 0000000,0000000..b705fc8
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Quads/quad-01.rq
@@@ -1,0 -1,0 +1,9 @@@
++PREFIX : <http://example/>
++PREFIX sys: <urn:x-arq:>
++
++SELECT *
++{
++ {?s ?p ?o } UNION { GRAPH ?g {?s ?p ?o}}
++}
++
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Quads/quad-02.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Quads/quad-02.rq
index 0000000,0000000..ef3bf2f
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Quads/quad-02.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example/>
++PREFIX sys: <urn:x-arq:>
++
++SELECT *
++{
++ ?s ?p ?x
++ GRAPH ?g {?s1 ?p1 ?x }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/data-1.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/data-1.ttl
index 0000000,0000000..77be09c
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/data-1.ttl
@@@ -1,0 -1,0 +1,7 @@@
++@prefix : <http://example/> .
++
++:x :p 1 .
++:x :p 2 .
++
++
++:y :q :x .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/data-2.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/data-2.ttl
index 0000000,0000000..59ac719
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/data-2.ttl
@@@ -1,0 -1,0 +1,5 @@@
++@prefix : <http://example/> .
++
++:x :p 1 .
++:x :p 99 .
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/data-dft.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/data-dft.ttl
index 0000000,0000000..d64ddd9
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/data-dft.ttl
@@@ -1,0 -1,0 +1,5 @@@
++@prefix : <http://example/> .
++
++:x :p 11 .
++:x :p 999 .
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/manifest.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/manifest.ttl
index 0000000,0000000..217d229
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/manifest.ttl
@@@ -1,0 -1,0 +1,107 @@@
++# 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.
++
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
++@prefix mfx: <http://jena.hpl.hp.com/2005/05/test-manifest-extra#> .
++@prefix qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
++
++<> rdf:type mf:Manifest ;
++ rdfs:label "Union of named graphs" ;
++ mf:entries
++ (
++ [ mf:name "Merge-1" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-1.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-1-results.srx>
++ ]
++ [ mf:name "Merge-2" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-2.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-2-results.srx>
++ ]
++ [ mf:name "Merge-3" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-3.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-3-results.srx>
++ ]
++ [ mf:name "Merge-4" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-4.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-4-results.srx>
++ ]
++ [ mf:name "Merge-5" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-5.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-5-results.srx>
++ ]
++ [ mf:name "Merge-6" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-6.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-6-results.srx>
++ ]
++ # Queries that need more than one SQL query (currently)
++ [ mf:name "Merge-A" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-A.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-A-results.srx>
++ ]
++ [ mf:name "Merge-B" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-B.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-B-results.srx>
++ ]
++ ).
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-1-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-1-results.srx
index 0000000,0000000..f850ec3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-1-results.srx
@@@ -1,0 -1,0 +1,57 @@@
++<?xml version="1.0"?>
++<sparql
++ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++ xmlns:xs="http://www.w3.org/2001/XMLSchema#"
++ xmlns="http://www.w3.org/2005/sparql-results#" >
++ <head>
++ <variable name="s"/>
++ <variable name="p"/>
++ <variable name="o"/>
++ </head>
++ <results>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-1.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-1.rq
index 0000000,0000000..c403064
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-1.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example/>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph { ?s ?p ?o }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-2-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-2-results.srx
index 0000000,0000000..18f9252
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-2-results.srx
@@@ -1,0 -1,0 +1,66 @@@
++<?xml version="1.0"?>
++<sparql
++ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++ xmlns:xs="http://www.w3.org/2001/XMLSchema#"
++ xmlns="http://www.w3.org/2005/sparql-results#" >
++ <head>
++ <variable name="s"/>
++ <variable name="p"/>
++ <variable name="o"/>
++ <variable name="q"/>
++ <variable name="z"/>
++ </head>
++ <results>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-2.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-2.rq
index 0000000,0000000..27953a6
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-2.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example/>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph { ?s ?p ?o . ?o ?q ?z }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-3-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-3-results.srx
index 0000000,0000000..4a65413
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-3-results.srx
@@@ -1,0 -1,0 +1,31 @@@
++<?xml version="1.0"?>
++<sparql
++ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++ xmlns:xs="http://www.w3.org/2001/XMLSchema#"
++ xmlns="http://www.w3.org/2005/sparql-results#" >
++ <head>
++ <variable name="p"/>
++ </head>
++ <results>
++ <result>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ </result>
++ <result>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ </result>
++ <result>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ </result>
++ <result>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-3.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-3.rq
index 0000000,0000000..1212926
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-3.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example/>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph { [] ?p [] }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-4-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-4-results.srx
index 0000000,0000000..0b44cb2
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-4-results.srx
@@@ -1,0 -1,0 +1,99 @@@
++<?xml version="1.0"?>
++<sparql
++ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++ xmlns:xs="http://www.w3.org/2001/XMLSchema#"
++ xmlns="http://www.w3.org/2005/sparql-results#" >
++ <head>
++ <variable name="s"/>
++ <variable name="p"/>
++ <variable name="o"/>
++ <variable name="q"/>
++ <variable name="z"/>
++ </head>
++ <results>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-4.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-4.rq
index 0000000,0000000..004f4bc
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-4.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example/>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph
++ { ?s ?p ?o . OPTIONAL { ?o ?q ?z } }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-5-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-5-results.srx
index 0000000,0000000..c7d777f
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-5-results.srx
@@@ -1,0 -1,0 +1,33 @@@
++<?xml version="1.0"?>
++<sparql xmlns="http://www.w3.org/2005/sparql-results#">
++ <head>
++ <variable name="p"/>
++ <variable name="o"/>
++ </head>
++ <results>
++ <result>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-5.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-5.rq
index 0000000,0000000..fa9bfe3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-5.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example/>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph { :x ?p ?o }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-6-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-6-results.srx
index 0000000,0000000..b4d31dc
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-6-results.srx
@@@ -1,0 -1,0 +1,43 @@@
++<?xml version="1.0"?>
++<sparql xmlns="http://www.w3.org/2005/sparql-results#">
++ <head>
++ <variable name="x"/>
++ <variable name="p"/>
++ <variable name="v"/>
++ </head>
++ <results>
++ <result>
++ <binding name="x">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="v">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="x">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="v">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="x">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="v">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-6.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-6.rq
index 0000000,0000000..7819cbb
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-6.rq
@@@ -1,0 -1,0 +1,7 @@@
++PREFIX : <http://example/>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph { ?x ?p 99 . ?x :p ?v }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-A-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-A-results.srx
index 0000000,0000000..1438c25
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-A-results.srx
@@@ -1,0 -1,0 +1,99 @@@
++<?xml version="1.0"?>
++<sparql
++ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++ xmlns:xs="http://www.w3.org/2001/XMLSchema#"
++ xmlns="http://www.w3.org/2005/sparql-results#" >
++ <head>
++ <variable name="s"/>
++ <variable name="p"/>
++ <variable name="o"/>
++ <variable name="q"/>
++ <variable name="z"/>
++ </head>
++ <results>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-A.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-A.rq
index 0000000,0000000..7bab242
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-A.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph
++ { ?s ?p ?o . OPTIONAL { ?o ?q ?z FILTER(?o != 123) } }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-B-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-B-results.srx
index 0000000,0000000..60d7766
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-B-results.srx
@@@ -1,0 -1,0 +1,49 @@@
++<?xml version="1.0"?>
++<sparql
++ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++ xmlns:xs="http://www.w3.org/2001/XMLSchema#"
++ xmlns="http://www.w3.org/2005/sparql-results#" >
++ <head>
++ <variable name="s"/>
++ <variable name="p"/>
++ <variable name="o"/>
++ <variable name="q"/>
++ <variable name="v"/>
++ </head>
++ <results>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="v">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">11</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="v">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">999</literal>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/UnionGraph/merge-B.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/UnionGraph/merge-B.rq
index 0000000,0000000..d4aceda
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/UnionGraph/merge-B.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph { ?s ?p ?o . }
++ { ?o ?q ?v }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Update/create-1.ru
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Update/create-1.ru
index 0000000,0000000..3276ec1
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Update/create-1.ru
@@@ -1,0 -1,0 +1,1 @@@
++CREATE GRAPH <http://example/graph>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Update/drop-1.ru
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Update/drop-1.ru
index 0000000,0000000..2512eb3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Update/drop-1.ru
@@@ -1,0 -1,0 +1,1 @@@
++DROP GRAPH <http://example/graph>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Update/update-1.ru
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Update/update-1.ru
index 0000000,0000000..7a6b737
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Update/update-1.ru
@@@ -1,0 -1,0 +1,3 @@@
++PREFIX : <http://example/>
++
++INSERT { :r :p 123 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Update/update-2.ru
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Update/update-2.ru
index 0000000,0000000..41e4ec0
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Update/update-2.ru
@@@ -1,0 -1,0 +1,5 @@@
++PREFIX : <http://example/>
++
++CREATE GRAPH <http://example/g1>
++INSERT INTO GRAPH <http://example/g1>
++{ :r :p 123 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Update/update-3.ru
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Update/update-3.ru
index 0000000,0000000..17f8410
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Update/update-3.ru
@@@ -1,0 -1,0 +1,7 @@@
++PREFIX : <http://example/>
++
++CREATE GRAPH <http://example/g1>
++INSERT INTO GRAPH <http://example/g1>
++{ :r :p 123 }
++DELETE FROM GRAPH <http://example/g1>
++{ :r :p 123 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Values/data-1.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Values/data-1.ttl
index 0000000,0000000..27c37dd
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Values/data-1.ttl
@@@ -1,0 -1,0 +1,23 @@@
++@prefix : <http://example/> .
++@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
++
++:x1 :p 1 .
++:x2 :p "1" .
++:x3 :p "1"@en .
++
++:x4 :p 1.5 .
++
++:x5 :p "2008-04-29T09:13:15+01:00"^^xsd:dateTime .
++
++:x6 :p "0008-04-29T09:13:15-01:00"^^xsd:dateTime .
++
++:x7 :p "-3000-04-29T09:13:15Z"^^xsd:dateTime .
++
++# Not encoded inline
++:x8 :p "-3000-04-29T09:13:15Z"^^xsd:dateTime .
++
++:x9 :p "2008-04-29"^^xsd:date .
++
++:x10 :p "2008-04-29Z"^^xsd:date .
++
++:x11 :p "2008-04-29+01:00"^^xsd:date .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Values/manifest.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Values/manifest.ttl
index 0000000,0000000..3396af5
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Values/manifest.ttl
@@@ -1,0 -1,0 +1,76 @@@
++# 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.
++
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
++@prefix qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
++
++<> rdf:type mf:Manifest ;
++ rdfs:label "Value tests" ;
++ mf:entries
++ (
++ [ mf:name "Value-00" ;
++ mf:action
++ [ qt:query <value-00.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-01" ;
++ mf:action
++ [ qt:query <value-01.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-02" ;
++ mf:action
++ [ qt:query <value-02.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-03" ;
++ mf:action
++ [ qt:query <value-03.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++
++ [ mf:name "Value-04" ;
++ mf:action
++ [ qt:query <value-04.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-05" ;
++ mf:action
++ [ qt:query <value-05.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-06" ;
++ mf:action
++ [ qt:query <value-06.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-07" ;
++ mf:action
++ [ qt:query <value-07.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-08" ;
++ mf:action
++ [ qt:query <value-08.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-09" ;
++ mf:action
++ [ qt:query <value-09.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ ) .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Values/value-00.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Values/value-00.rq
index 0000000,0000000..d1fe80b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Values/value-00.rq
@@@ -1,0 -1,0 +1,1 @@@
++SELECT * { ?s ?p ?o }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Values/value-01.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Values/value-01.rq
index 0000000,0000000..664f67a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Values/value-01.rq
@@@ -1,0 -1,0 +1,1 @@@
++SELECT * { ?s ?p 1 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Values/value-02.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Values/value-02.rq
index 0000000,0000000..5dfe5ec
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Values/value-02.rq
@@@ -1,0 -1,0 +1,1 @@@
++SELECT * { ?s ?p 1.5 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Values/value-03.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Values/value-03.rq
index 0000000,0000000..7134be8
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Values/value-03.rq
@@@ -1,0 -1,0 +1,1 @@@
++SELECT * { ?s ?p "1" }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Values/value-04.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Values/value-04.rq
index 0000000,0000000..030116d
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Values/value-04.rq
@@@ -1,0 -1,0 +1,1 @@@
++SELECT * { ?s ?p "1"@en }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Values/value-05.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Values/value-05.rq
index 0000000,0000000..fbd8d9b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Values/value-05.rq
@@@ -1,0 -1,0 +1,5 @@@
++SELECT *
++{
++ ?s ?p ?o .
++ FILTER(?o = 1)
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Values/value-06.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Values/value-06.rq
index 0000000,0000000..8f34124
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Values/value-06.rq
@@@ -1,0 -1,0 +1,6 @@@
++PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
++
++SELECT *
++{
++ ?s ?p "2008-04-29+01:00"^^xsd:date .
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Values/value-07.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Values/value-07.rq
index 0000000,0000000..cafd777
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Values/value-07.rq
@@@ -1,0 -1,0 +1,6 @@@
++PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
++
++SELECT *
++{
++ ?s ?p ?x . FILTER (?x = "2008-04-29+01:00"^^xsd:date) .
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Values/value-08.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Values/value-08.rq
index 0000000,0000000..e6fc284
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Values/value-08.rq
@@@ -1,0 -1,0 +1,6 @@@
++PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
++
++SELECT *
++{
++ ?s ?p "2008-04-29T09:13:15+01:00"^^xsd:dateTime .
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/Values/value-09.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/Values/value-09.rq
index 0000000,0000000..02dcc20
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/Values/value-09.rq
@@@ -1,0 -1,0 +1,7 @@@
++PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
++
++SELECT *
++{
++ # Out of range - not an immediate literal
++ ?s ?p "-3000-04-29T09:13:15Z"^^xsd:dateTime
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/testing/manifest.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/testing/manifest.ttl
index 0000000,0000000..aeaf80e
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/testing/manifest.ttl
@@@ -1,0 -1,0 +1,31 @@@
++# 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.
++
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
++@prefix qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
++
++<> rdf:type mf:Manifest ;
++ rdfs:label "TDB - Scripts" ;
++ mf:include (
++ <Basic/manifest.ttl>
++ <Pattern/manifest.ttl>
++ <Quads/manifest.ttl>
++ <Values/manifest.ttl>
++ <UnionGraph/manifest.ttl>
++ ) .
++
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/.gitignore
----------------------------------------------------------------------
diff --cc jena-db/tdb2/.gitignore
index 0000000,0000000..731afb6
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/.gitignore
@@@ -1,0 -1,0 +1,2 @@@
++DB*
++D.*
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/pom.xml
----------------------------------------------------------------------
diff --cc jena-db/tdb2/pom.xml
index 0000000,0000000..80cfc5a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/pom.xml
@@@ -1,0 -1,0 +1,108 @@@
++<?xml version="1.0" encoding="utf-8"?>
++<!--
++ 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.
++-->
++
++<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
++
++ <modelVersion>4.0.0</modelVersion>
++
++ <artifactId>tdb2</artifactId>
++ <packaging>jar</packaging>
++ <name>Mantis (${project.artifactId})</name>
++
++ <parent>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>mantis</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </parent>
++
++ <dependencies>
++
++ <!--
++ <dependency>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>dboe-quack</artifactId>
++ <version>0.2.0-SNAPSHOT</version>
++ </dependency>
++ -->
++
++ <dependency>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>dboe-trans-data</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </dependency>
++
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-core</artifactId>
++ <classifier>tests</classifier>
++ <scope>test</scope>
++ </dependency>
++
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-arq</artifactId>
++ <classifier>tests</classifier>
++ <scope>test</scope>
++ </dependency>
++
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-base</artifactId>
++ <classifier>tests</classifier>
++ <scope>test</scope>
++ </dependency>
++
++ </dependencies>
++
++ <build>
++ <plugins>
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-jar-plugin</artifactId>
++ <executions>
++ <execution>
++ <goals>
++ <goal>test-jar</goal>
++ </goals>
++ </execution>
++ </executions>
++ </plugin>
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-source-plugin</artifactId>
++ <executions>
++ <execution>
++ <id>attach-sources</id>
++ <!-- <phase>package</phase> package is the default -->
++ <goals>
++ <goal>jar-no-fork</goal>
++ </goals>
++ </execution>
++ <execution>
++ <id>attach-sources-test</id>
++ <goals>
++ <goal>test-jar-no-fork</goal>
++ </goals>
++ </execution>
++ </executions>
++ </plugin>
++
++ </plugins>
++ </build>
++
++</project>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/DatabaseMgr.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/DatabaseMgr.java
index 0000000,0000000..098a646
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/DatabaseMgr.java
@@@ -1,0 -1,0 +1,114 @@@
++/*
++ * 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.jena.query.Dataset ;
++import org.apache.jena.sparql.core.DatasetGraph ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
++import org.seaborne.tdb2.store.DatasetGraphTDB ;
++import org.seaborne.tdb2.sys.DatabaseConnection ;
++import org.seaborne.tdb2.sys.DatabaseOps ;
++import org.seaborne.tdb2.sys.TDBInternal ;
++
++/** 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 DatabaseConnection.connectCreate(location).getDatasetGraph();
++// // One level.
++// return StoreConnection.connectCreate(location).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
++ * @return File name of the backup.
++ */
++ public static String backup(DatasetGraph container) {
++ DatasetGraphSwitchable dsg = requireSwitchable(container);
++ return DatabaseOps.backup(dsg);
++ }
++
++
++ /** 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) {
++ return TDBInternal.isBackedByTDB(datasetGraph);
++ }
++
++ /** Return the location of a DatasetGraph if it is backed by TDB, else null. */
++ public static Location location(DatasetGraph datasetGraph) {
++ DatasetGraphSwitchable dsg = requireSwitchable(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) {
++ DatasetGraphTDB dsg = TDBInternal.getDatasetGraphTDB(datasetGraph);
++ if ( dsg == null )
++ throw new TDBException("Not a TDB database (argument is neither a switchable nor direct TDB DatasetGraph)");
++ return dsg;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/TDB2.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/TDB2.java
index 0000000,0000000..6a18faa
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/TDB2.java
@@@ -1,0 -1,0 +1,268 @@@
++/*
++ * 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 ;
++
++import org.apache.jena.atlas.lib.Sync ;
++import org.apache.jena.graph.Graph ;
++import org.apache.jena.ontology.OntModel ;
++import org.apache.jena.ontology.impl.OntModelImpl ;
++import org.apache.jena.query.ARQ ;
++import org.apache.jena.rdf.model.Model ;
++import org.apache.jena.reasoner.InfGraph ;
++import org.apache.jena.riot.lang.ReaderRIOTRDFXML;
++import org.apache.jena.sparql.SystemARQ ;
++import org.apache.jena.sparql.core.assembler.AssemblerUtils ;
++import org.apache.jena.sparql.engine.main.StageBuilder ;
++import org.apache.jena.sparql.engine.main.StageGenerator ;
++import org.apache.jena.sparql.lib.Metadata ;
++import org.apache.jena.sparql.mgt.SystemInfo ;
++import org.apache.jena.sparql.util.Context ;
++import org.apache.jena.sparql.util.MappingRegistry ;
++import org.apache.jena.sparql.util.Symbol ;
++import org.apache.jena.system.JenaSystem ;
++import org.seaborne.tdb2.assembler.VocabTDB2 ;
++import org.seaborne.tdb2.modify.UpdateEngineTDB ;
++import org.seaborne.tdb2.solver.QueryEngineTDB ;
++import org.seaborne.tdb2.solver.StageGeneratorDirectTDB ;
++import org.seaborne.tdb2.sys.EnvTDB ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++import org.seaborne.tdb2.sys.TDBInternal ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++public class TDB2 {
++ /** IRI for TDB */
++ public static final String tdbIRI = "http://seaborne.org/#tdb" ;
++
++ /** Root of TDB-defined parameter names */
++ public static final String tdbParamNS = "http://seaborne.org/TDB#" ;
++
++ /** Prefix for TDB-defined parameter names */
++ public static final String tdbSymbolPrefix = "tdb" ;
++
++ // Internal logging
++ private static final Logger log = LoggerFactory.getLogger(TDB2.class) ;
++
++ /** Logger for loading information */
++ public static final String logLoaderName = "org.apache.jena.tdb.loader" ;
++ /** Logger for loading information */
++ public static final Logger logLoader = LoggerFactory.getLogger(logLoaderName) ;
++
++ /** Logger for general information */
++ public static final String logInfoName = "org.apache.jena.info" ;
++ /** Logger for general information */
++ public static final Logger logInfo = LoggerFactory.getLogger(logInfoName) ;
++
++ // /** Logger for execution information */
++ // public static final String logExecName = "org.apache.jena.tdb.exec" ;
++ // /** Logger for execution information */
++ // public static final Logger logExec = LoggerFactory.getLogger(logExecName)
++ // ;
++
++ public final static String namespace = "http://jena.apache.org/2016/tdb#" ;
++
++ /** Symbol to use the union of named graphs as the default graph of a query */
++ public static final Symbol symUnionDefaultGraph = SystemTDB.allocSymbol("unionDefaultGraph") ;
++
++ /**
++ * A String enum Symbol that specifies the type of temporary storage for
++ * transaction journal write blocks.
++ * <p/>
++ * "mem" = Java heap memory (default) <br>
++ * "direct" = Process heap memory <br>
++ * "mapped" = Memory mapped temporary file <br>
++ */
++ public static final Symbol transactionJournalWriteBlockMode = SystemTDB.allocSymbol("transactionJournalWriteBlockMode") ;
++
++ public static Context getContext() {
++ return ARQ.getContext() ;
++ }
++
++ /**
++ * Release any and all system resources held by TDB.
++ * All release datasets or graphs held by client code are no longer valid.
++ */
++ public static void closedown() {
++ TDBInternal.reset() ;
++ }
++
++ /** Sync a TDB-backed Model. Do nothing if not TDB-backed. */
++ public static void sync(Model model) {
++ if ( model instanceof OntModelImpl ) {
++ OntModelImpl ontModel = (OntModelImpl)model ;
++ sync(ontModel.getBaseGraph()) ;
++ return ;
++ }
++ // This never happens (there is only one OntModel implementation)
++ if ( model instanceof OntModel ) {
++ OntModel ontModel = (OntModel)model ;
++ sync(ontModel.getBaseModel()) ;
++ return ;
++ }
++
++ sync(model.getGraph()) ;
++ }
++
++ /** Sync a TDB-backed Graph. Do nothing if not TDB-backed. */
++ public static void sync(Graph graph) {
++ if ( graph == null )
++ return ;
++
++ if ( graph instanceof InfGraph ) {
++ InfGraph infGraph = (InfGraph)graph ;
++ sync(infGraph.getRawGraph()) ;
++ return ;
++ }
++ syncObject(graph) ;
++ }
++
++// /** Sync a TDB-backed Dataset. Do nothing if not TDB-backed. */
++// public static void sync(Dataset dataset) {
++// if ( dataset == null )
++// return ;
++// DatasetGraph ds = dataset.asDatasetGraph() ;
++// sync(ds) ;
++// }
++//
++// /** Sync a TDB-backed DatasetGraph. Do nothing if not TDB-backed. */
++// public static void sync(DatasetGraph dataset) {
++// if ( dataset == null )
++// return ;
++//
++// // Should be: SystemARQ.sync(dataset) ;
++// if ( dataset instanceof DatasetGraphTDB ) {
++// syncObject(dataset) ;
++// return ;
++// }
++//
++// if ( dataset instanceof DatasetGraphTransaction ) {
++// DatasetGraphTransaction dsgt = (DatasetGraphTransaction)dataset ;
++// // This only sync if the dataset has not been used transactionally.
++// // Can't sync transactional datasets (it's meaningless)
++// dsgt.syncIfNotTransactional() ;
++// return ;
++// }
++//
++// // May be a general purpose dataset with TDB objects in it.
++// sync(dataset.getDefaultGraph()) ;
++// Iterator<Node> iter = dataset.listGraphNodes() ;
++// iter = Iter.toList(iter).iterator() ; // Avoid iterator concurrency.
++// for (; iter.hasNext();) {
++// Node n = iter.next() ;
++// Graph g = dataset.getGraph(n) ;
++// sync(g) ;
++// }
++// }
++
++ /**
++ * Sync a TDB synchronizable object (model, graph, dataset). If force is
++ * true, synchronize as much as possible (e.g. file metadata) else make a
++ * reasonable attenpt at synchronization but does not gauarantee disk state.
++ * Do nothing otherwise
++ */
++ private static void syncObject(Object object) {
++ if ( object == null )
++ return ;
++ if ( object instanceof Sync )
++ ((Sync)object).sync() ;
++ }
++
++ private static final Object initLock = new Object() ;
++ private static volatile boolean initialized = false ;
++ static { JenaSystem.init(); }
++
++ /**
++ * TDB System initialization - normally, this is not explicitly called
++ * because all routes to use TDB will cause initialization to occur.
++ * However, calling it repeatedly is safe and low cost.
++ */
++ public static void init() {
++ if ( initialized )
++ return ;
++ synchronized(initLock) {
++ if ( initialized ) {
++ if ( JenaSystem.DEBUG_INIT )
++ System.err.println("TDB2.init - return") ;
++ return ;
++ }
++ initialized = true ;
++ if ( JenaSystem.DEBUG_INIT )
++ System.err.println("TDB2.init - start") ;
++
++ SystemTDB.init() ;
++ ARQ.init() ;
++ ReaderRIOTRDFXML.RiotUniformCompatibility = true ;
++ EnvTDB.processGlobalSystemProperties() ;
++
++ MappingRegistry.addPrefixMapping(SystemTDB.tdbSymbolPrefix, SystemTDB.symbolNamespace) ;
++ AssemblerUtils.init() ;
++ VocabTDB2.init() ;
++ QueryEngineTDB.register() ;
++ UpdateEngineTDB.register() ;
++ MappingRegistry.addPrefixMapping(TDB2.tdbSymbolPrefix, TDB2.tdbParamNS) ;
++
++ wireIntoExecution() ;
++ if ( JenaSystem.DEBUG_INIT )
++ System.err.println("TDB.init - finish") ;
++ }
++ }
++
++ private static void wireIntoExecution() {
++ // Globally change the stage generator to intercept BGP on TDB
++ // Globally change the stage generator to intercept BGP on TDB
++ Context cxt = ARQ.getContext() ;
++ StageGenerator orig = StageBuilder.chooseStageGenerator(cxt) ;
++
++ // Wire in the TDB stage generator which will make TDB work whether
++ // or not the TDB executor is used. This means that datasets of mixed
++ // graph types inside a general purpose dataset work.
++ StageGenerator stageGenerator = new StageGeneratorDirectTDB(orig) ;
++ StageBuilder.setGenerator(ARQ.getContext(), stageGenerator) ;
++ }
++
++ // ---- Static constants read by modVersion
++ // ---- Must be after initialization.
++
++ static private String metadataLocation = "org/apache/jena/tdb/tdb-properties.xml" ;
++ static private Metadata metadata = new Metadata(metadataLocation) ;
++
++ /** The root package name for TDB */
++ public static final String PATH = "org.apache.jena.tdb" ;
++
++ // The names known to ModVersion : "NAME", "VERSION", "BUILD_DATE"
++
++ public static final String NAME = "TDB" ;
++
++ /** The full name of the current TDB version */
++ public static final String VERSION = metadata.get(PATH + ".version", "DEV") ;
++
++ /** The date and time at which this release was built */
++ public static final String BUILD_DATE = metadata.get(PATH + ".build.datetime", "unset") ;
++
++ // Final initialization (in case any statics in this file are important).
++ static {
++ initialization2() ;
++ }
++
++ private static void initialization2() {
++ // Set management information.
++ SystemInfo systemInfo = new SystemInfo(TDB2.tdbIRI, TDB2.PATH, TDB2.VERSION, TDB2.BUILD_DATE) ;
++ SystemARQ.registerSubSystem(systemInfo) ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/TDB2Factory.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/TDB2Factory.java
index 0000000,0000000..93cc3d2
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/TDB2Factory.java
@@@ -1,0 -1,0 +1,124 @@@
++/*
++ * 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;
++
++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 ;
++
++/**
++ * Public factory for connecting to and creating datasets backed by TDB2 storage.
++ */
++public class TDB2Factory
++{
++ private TDB2Factory() {}
++
++ /** @deprecated Use {@link DatabaseMgr#connectDatasetGraph(Location)} */
++ @Deprecated
++ public static DatasetGraph createDatasetGraph(Location location) {
++ return DatabaseMgr.connectDatasetGraph(location);
++ }
++
++ /** @deprecated Use {@link #connectDataset(Location)} */
++ @Deprecated
++ public static Dataset createDataset(Location location) {
++ return connectDataset(location);
++ }
++
++ /** Create or connect to a TDB2-backed dataset */
++ public static Dataset connectDataset(Location location) {
++ DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(location) ;
++ return DatasetFactory.wrap(dsg) ;
++ }
++
++ /** @deprecated Use {@link DatabaseMgr#connectDatasetGraph(String)} */
++ @Deprecated
++ public static DatasetGraph createDatasetGraph(String location) {
++ return DatabaseMgr.connectDatasetGraph(location);
++ }
++
++ /** @deprecated Use {@link #connectDataset(String)} */
++ @Deprecated
++ public static Dataset createDataset(String location) {
++ return connectDataset(location);
++ }
++
++ /** Create or connect to a TDB2-backed dataset */
++ public static Dataset connectDataset(String location) {
++ return connectDataset(Location.create(location)) ; }
++
++ /**
++ * 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()) ; }
++
++// /**
++// * Read the file and assembler a dataset
++// */
++// public static Dataset assembleDataset(String assemblerFile) {
++// return (Dataset)AssemblerUtils.build(assemblerFile, VocabTDB.tDatasetTDB) ;
++// }
++//
++// /** Release from the JVM. All caching is lost. */
++// public static void release(Dataset dataset) {
++// _release(location(dataset)) ;
++// }
++//
++// /** Release from the JVM. All caching is lost. */
++// public static void release(DatasetGraph dataset) {
++// _release(location(dataset)) ;
++// }
++
++ /** Tes whether a dataset is backed by TDB or not. */
++ public static boolean isBackedByTDB(Dataset dataset) {
++ DatasetGraph dsg = dataset.asDatasetGraph() ;
++ return DatabaseMgr.isBackedByTDB(dsg) ;
++ }
++
++ /** 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 DatabaseMgr.location(dsg) ;
++ }
++
++// /** Set the {@link StoreParams} for specific Location.
++// * This call must only be called before a dataset from Location
++// * is created. This operation should be used with care; bad choices
++// * of {@link StoreParams} can reduce performance.
++// *
++// * <a href="http://jena.apache.org/documentation/tdb/store-paramters.html"
++// * >See documentation</a>.
++// *
++// * @param location The persistent storage location
++// * @param params StoreParams to use
++// * @throws IllegalStateException If the dataset has already been setup.
++// */
++// public static void setup(Location location, StoreParams params) {
++// StoreConnection sConn = StoreConnection.getExisting(location) ;
++// if ( sConn != null )
++// throw new IllegalStateException("Location is already active") ;
++// StoreConnection.make(location, params) ;
++// }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/TDBException.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/TDBException.java
index 0000000,0000000..2e0ea26
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/TDBException.java
@@@ -1,0 -1,0 +1,28 @@@
++/*
++ * 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;
++
++import org.apache.jena.shared.JenaException ;
++
++public class TDBException extends JenaException
++{
++ public TDBException() { super() ; }
++ public TDBException(String msg) { super(msg) ; }
++ public TDBException(Throwable th) { super(th) ; }
++ public TDBException(String msg, Throwable th) { super(msg, th) ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/assembler/DatasetAssemblerTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/assembler/DatasetAssemblerTDB.java
index 0000000,0000000..dc2d67a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/assembler/DatasetAssemblerTDB.java
@@@ -1,0 -1,0 +1,79 @@@
++/*
++ * 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.assembler;
++
++import static org.apache.jena.sparql.util.graph.GraphUtils.exactlyOneProperty ;
++import static org.apache.jena.sparql.util.graph.GraphUtils.getStringValue ;
++import static org.seaborne.tdb2.assembler.VocabTDB2.pLocation ;
++import static org.seaborne.tdb2.assembler.VocabTDB2.pUnionDefaultGraph ;
++
++import org.apache.jena.assembler.Assembler ;
++import org.apache.jena.assembler.Mode ;
++import org.apache.jena.assembler.exceptions.AssemblerException ;
++import org.apache.jena.atlas.logging.Log ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.query.Dataset ;
++import org.apache.jena.query.DatasetFactory ;
++import org.apache.jena.rdf.model.Resource ;
++import org.apache.jena.sparql.core.DatasetGraph ;
++import org.apache.jena.sparql.core.assembler.AssemblerUtils ;
++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 ;
++
++public class DatasetAssemblerTDB extends DatasetAssembler
++{
++ static { JenaSystem.init(); }
++
++ @Override
++ public Dataset createDataset(Assembler a, Resource root, Mode mode) {
++ TDB2.init() ;
++ return make(root) ;
++ }
++
++ static Dataset make(Resource root) {
++ if ( !exactlyOneProperty(root, pLocation) )
++ throw new AssemblerException(root, "No location given") ;
++
++ String dir = getStringValue(root, pLocation) ;
++ Location loc = Location.create(dir) ;
++ DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(loc) ;
++
++ if ( root.hasProperty(pUnionDefaultGraph) ) {
++ Node b = root.getProperty(pUnionDefaultGraph).getObject().asNode() ;
++ NodeValue nv = NodeValue.makeNode(b) ;
++ if ( nv.isBoolean() )
++ dsg.getContext().set(TDB2.symUnionDefaultGraph, nv.getBoolean()) ;
++ else
++ Log.warn(DatasetAssemblerTDB.class, "Failed to recognize value for union graph setting (ignored): " + b) ;
++ }
++
++ /*
++ <r> rdf:type tdb:DatasetTDB2 ;
++ tdb:location "dir" ;
++ //ja:context [ ja:cxtName "arq:queryTimeout" ; ja:cxtValue "10000" ] ;
++ tdb:unionGraph true ; # or "true"
++ */
++ AssemblerUtils.setContext(root, dsg.getContext());
++ return DatasetFactory.wrap(dsg) ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/assembler/TDBGraphAssembler.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/assembler/TDBGraphAssembler.java
index 0000000,0000000..eebe51b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/assembler/TDBGraphAssembler.java
@@@ -1,0 -1,0 +1,124 @@@
++/*
++ * 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.assembler;
++
++import static org.apache.jena.sparql.util.graph.GraphUtils.getAsStringValue ;
++import static org.apache.jena.sparql.util.graph.GraphUtils.getResourceValue ;
++import static org.apache.jena.sparql.util.graph.GraphUtils.getStringValue ;
++import static org.seaborne.tdb2.assembler.VocabTDB2.* ;
++
++import org.apache.jena.assembler.Assembler ;
++import org.apache.jena.assembler.Mode ;
++import org.apache.jena.assembler.assemblers.AssemblerBase ;
++import org.apache.jena.assembler.exceptions.AssemblerException ;
++import org.apache.jena.atlas.logging.Log ;
++import org.apache.jena.query.Dataset ;
++import org.apache.jena.rdf.model.* ;
++import org.apache.jena.riot.out.NodeFmtLib ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.TDB2 ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.TDB2Factory ;
++
++public class TDBGraphAssembler extends AssemblerBase implements Assembler
++{
++ @Override
++ public Model open(Assembler a, Resource root, Mode mode)
++ {
++ // In case we go via explicit index construction,
++ // although given we got here, the assembler is wired in
++ // and that probably means TDB.init
++ TDB2.init() ;
++
++ // Make a model - the default model of the TDB dataset
++ // [] rdf:type tdb:GraphTDB ;
++ // tdb:location "dir" ;
++
++ // Make a named model.
++ // [] rdf:type tdb:GraphTDB ;
++ // tdb:location "dir" ;
++ // tdb:graphName <http://example/name> ;
++
++ // Location or dataset reference.
++ String locationDir = getStringValue(root, pLocation) ;
++ Resource dataset = getResourceValue(root, pDataset) ;
++
++ if ( locationDir != null && dataset != null )
++ throw new AssemblerException(root, "Both location and dataset given: exactly one required") ;
++
++ if ( locationDir == null && dataset == null )
++ throw new AssemblerException(root, "Must give location or refer to a dataset description") ;
++
++ String graphName = null ;
++ if ( root.hasProperty(pGraphName1) )
++ graphName = getAsStringValue(root, pGraphName1) ;
++ if ( root.hasProperty(pGraphName2) )
++ graphName = getAsStringValue(root, pGraphName2) ;
++
++ if ( root.hasProperty(pIndex) )
++ Log.warn(this, "Custom indexes not implemented yet - ignored") ;
++
++ final Dataset ds ;
++
++ if ( locationDir != null )
++ {
++ Location location = Location.create(locationDir) ;
++ ds = TDB2Factory.connectDataset(location) ;
++ }
++ else
++ ds = DatasetAssemblerTDB.make(dataset) ;
++
++ try {
++ if ( graphName != null )
++ return ds.getNamedModel(graphName) ;
++ else
++ return ds.getDefaultModel() ;
++ } catch (RuntimeException ex)
++ {
++ ex.printStackTrace(System.err) ;
++ throw ex ;
++ }
++ }
++
++ //@Unused
++ private void indexes(Resource root)
++ {
++ // ---- API ways
++
++ StmtIterator sIter = root.listProperties(pIndex) ;
++ while(sIter.hasNext())
++ {
++ RDFNode obj = sIter.nextStatement().getObject() ;
++ if ( obj.isLiteral() )
++ {
++ String desc = ((Literal)obj).getString() ;
++ System.out.printf("Index: %s\n", desc) ; System.out.flush();
++ continue ;
++ }
++ throw new TDBException("Wrong format for tdb:index: should be a string: found: "+NodeFmtLib.displayStr(obj)) ;
++ // Resource x = (Resource)obj ;
++ // String desc = x.getProperty(pDescription).getString() ;
++ // String file = x.getProperty(pFile).getString() ;
++ // System.out.printf("Index: %s in file %s\n", desc, file) ; System.out.flush();
++ }
++
++ System.out.flush();
++ throw new TDBException("Custom indexes turned off") ;
++ }
++
++}
[25/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/value/TestNodeIdInline.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/value/TestNodeIdInline.java
index 0000000,0000000..5aeafe5
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/value/TestNodeIdInline.java
@@@ -1,0 -1,0 +1,285 @@@
++/*
++ * 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.value;
++
++import static org.junit.Assert.*;
++import org.apache.jena.datatypes.xsd.XSDDatatype;
++import org.apache.jena.graph.Node;
++import org.apache.jena.graph.NodeFactory;
++import org.apache.jena.sparql.expr.NodeValue;
++import org.apache.jena.sparql.util.NodeFactoryExtra;
++import org.junit.Test;
++import org.seaborne.tdb2.store.NodeId;
++
++public class TestNodeIdInline
++{
++ @Test public void nodeId_int_01()
++ { test("'1'^^xsd:integer") ; }
++
++ @Test public void nodeId_int_02()
++ { test("2") ; }
++
++ @Test public void nodeId_int_03()
++ { test("'3'^^xsd:int") ; }
++
++ @Test public void nodeId_int_04()
++ { testNoInline("'3'") ; }
++
++ @Test public void nodeId_int_05()
++ { test("-1") ; }
++
++ @Test public void nodeId_int_06()
++ { test("-180") ; }
++
++ @Test public void nodeId_int_07()
++ { test("01", "1") ; }
++
++ @Test public void nodeId_int_08()
++ { test("+01", "1") ; }
++
++ @Test public void nodeId_int_09()
++ // More than Long.MAX_VALUE
++ { testNoInline("92233720368547758070") ; }
++
++ // On the edge.
++
++ static final long X = 1L<<55 ; // Just too large
++ static final long Y = -((1L<<55) +1) ; // Just too small
++
++ @Test public void nodeId_int_10()
++ { testNoInline("\""+Long.toString(X)+"\"^^xsd:integer") ; }
++
++ @Test public void nodeId_int_11()
++ {
++ Node n = NodeValue.makeInteger(X-1).asNode() ;
++ test("\""+Long.toString(X-1)+"\"^^xsd:integer", n) ;
++ }
++
++ @Test public void nodeId_int_12()
++ { testNoInline("\""+Long.toString(Y)+"\"^^xsd:integer") ; }
++
++ @Test public void nodeId_int_13()
++ {
++ Node n = NodeValue.makeInteger(Y+1).asNode() ;
++ test("\""+Long.toString(Y+1)+"\"^^xsd:integer", n) ;
++ }
++
++ @Test public void nodeId_int_20()
++ { test("'30'^^xsd:positiveInteger") ; }
++
++ @Test public void nodeId_int_21()
++ { testNoInline("'300'^^xsd:byte") ; }
++
++ @Test public void nodeId_decimal_1()
++ { test("3.14", "3.14") ; }
++
++ @Test public void nodeId_decimal_2()
++ { testNoInline("123456789.123456789") ; }
++
++ // Just this once, directly create the Node.
++ @Test public void nodeId_decimal_3()
++ { test("12.89", NodeFactory.createLiteral("12.89", XSDDatatype.XSDdecimal)) ; }
++
++ @Test public void nodeId_decimal_4()
++ { test("-1.0", "-1.0") ; }
++
++ // This number has > 47 bits of value : 2412.80478192688
++ @Test public void nodeId_decimal_5()
++ { testNoInline("2412.80478192688") ; }
++
++ // This number has > 47 bits of value : -2412.80478192688
++ @Test public void nodeId_decimal_6()
++ { testNoInline("-2412.80478192688") ; }
++
++ @Test public void nodeId_decimal_7()
++ { test("'0.00000001'^^xsd:decimal",
++ NodeFactory.createLiteral("0.00000001", XSDDatatype.XSDdecimal)) ;
++ }
++
++ @Test public void nodeId_decimal_8()
++ { test("0.00000001", NodeFactory.createLiteral("0.00000001", XSDDatatype.XSDdecimal)) ; }
++
++ @Test public void nodeId_dateTime_01()
++ { test("'2008-04-28T15:36:15+01:00'^^xsd:dateTime") ; }
++
++ @Test public void nodeId_dateTime_02()
++ { test("'2008-04-28T15:36:15Z'^^xsd:dateTime") ; }
++
++ @Test public void nodeId_dateTime_03()
++ { test("'2008-04-28T15:36:15+00:00'^^xsd:dateTime") ; }
++
++ @Test public void nodeId_dateTime_04()
++ { test("'2008-04-28T15:36:15-05:00'^^xsd:dateTime") ; }
++
++ // No timezone.
++ @Test public void nodeId_dateTime_05()
++ { test("'2008-04-28T15:36:15'^^xsd:dateTime") ; }
++
++ // Note the trailing zero - system does not preserve perfect lexical forms.
++ @Test public void nodeId_dateTime_06()
++ { test("'2008-04-28T15:36:05.450'^^xsd:dateTime", "'2008-04-28T15:36:05.45'^^xsd:dateTime") ; }
++
++ // Old Java bug, now fixed: T24:00:00 not accepted by DatatypeFactory.newXMLGregorianCalendar(lex)
++ // Note the Jena value is an XSDDateTime so it retains the "24"/"00" next day distinction.
++ @Test public void nodeId_dateTime_07()
++ { test("'2008-04-28T24:00:00'^^xsd:dateTime") ; }
++
++ // Out of range.
++ @Test public void nodeId_dateTime_08()
++ { testNoInline("'8008-04-28T15:36:05.45'^^xsd:dateTime") ; }
++
++ @Test public void nodeId_dateTime_09()
++ { test("'2008-04-28T15:36:05.001'^^xsd:dateTime") ; }
++
++ @Test public void nodeId_dateTime_10()
++ { test("'2008-04-28T15:36:05.01'^^xsd:dateTime") ; }
++
++ @Test public void nodeId_dateTime_11()
++ { test("'2008-04-28T15:36:05.1'^^xsd:dateTime") ; }
++
++ // Canonicalization test - fractional seconds.
++ @Test public void nodeId_dateTime_12()
++ { test("'2008-04-28T15:36:05.010'^^xsd:dateTime", "'2008-04-28T15:36:05.01'^^xsd:dateTime") ; }
++
++ @Test public void nodeId_dateTime_13()
++ { test("'2008-04-28T15:36:05.100'^^xsd:dateTime", "'2008-04-28T15:36:05.1'^^xsd:dateTime") ; }
++
++ @Test public void nodeId_dateTime_14()
++ { test("'2012-07-29T20:39:11.100+01:15'^^xsd:dateTime", "'2012-07-29T20:39:11.1+01:15'^^xsd:dateTime") ; }
++
++ @Test public void nodeId_dateTime_15()
++ { test("'2012-07-29T20:39:11.100-01:15'^^xsd:dateTime", "'2012-07-29T20:39:11.1-01:15'^^xsd:dateTime") ; }
++
++ @Test public void nodeId_dateTime_16()
++ { test("'2012-07-29T20:39:11.100+01:30'^^xsd:dateTime", "'2012-07-29T20:39:11.1+01:30'^^xsd:dateTime") ; }
++
++ @Test public void nodeId_dateTime_17()
++ { test("'2012-07-29T20:39:11.100-01:45'^^xsd:dateTime", "'2012-07-29T20:39:11.1-01:45'^^xsd:dateTime") ; }
++
++ @Test public void nodeId_dateTime_18()
++ { test("'2012-07-29T20:39:11.100Z'^^xsd:dateTime", "'2012-07-29T20:39:11.1Z'^^xsd:dateTime") ; }
++
++ @Test public void nodeId_dateTimeStamp_01()
++ { test("'2012-07-29T20:39:11.100Z'^^xsd:dateTimeStamp", "'2012-07-29T20:39:11.1Z'^^xsd:dateTimeStamp") ; }
++
++
++ @Test public void nodeId_date_1()
++ { test("'2008-04-28Z'^^xsd:date", "'2008-04-28Z'^^xsd:date") ; }
++
++ @Test public void nodeId_date_2()
++ { test("'2008-04-28+00:00'^^xsd:date", "'2008-04-28+00:00'^^xsd:date") ; }
++
++ @Test public void nodeId_date_3()
++ { test("'2008-04-28-05:00'^^xsd:date", "'2008-04-28-05:00'^^xsd:date") ; }
++
++ @Test public void nodeId_date_4()
++ { test("'2008-04-28+02:00'^^xsd:date", "'2008-04-28+02:00'^^xsd:date") ; }
++
++ @Test public void nodeId_date_5()
++ { testNoInline("'8008-04-28'^^xsd:date") ; }
++
++ @Test public void nodeId_date_6()
++ { test("'2012-07-29+06:15'^^xsd:date", "'2012-07-29+06:15'^^xsd:date") ; }
++
++ @Test public void nodeId_date_7()
++ { test("'2012-07-29-06:30'^^xsd:date", "'2012-07-29-06:30'^^xsd:date") ; }
++
++ @Test public void nodeId_boolean_1()
++ { test("'true'^^xsd:boolean", "'true'^^xsd:boolean") ; }
++
++ @Test public void nodeId_boolean_2()
++ { test("'false'^^xsd:boolean", "'false'^^xsd:boolean") ; }
++
++ @Test public void nodeId_boolean_3()
++ { test("'1'^^xsd:boolean", "'true'^^xsd:boolean") ; }
++
++ @Test public void nodeId_boolean_4()
++ { test("'0'^^xsd:boolean", "'false'^^xsd:boolean") ; }
++
++ // Many tests in TestDoubleNode62
++
++ @Test public void nodeId_double_1()
++ { test("1.0e0", NodeFactory.createLiteral("1.0e0", XSDDatatype.XSDdouble)) ; }
++
++ // Becomes the RDF/SPARQL preferred form - with expooent - for pretty printing.
++ @Test public void nodeId_double_2()
++ { test("'-0001.0'^^xsd:double", NodeFactory.createLiteral("-1.0e0", XSDDatatype.XSDdouble)) ; }
++
++ @Test public void nodeId_double_3()
++ { test("'NaN'^^xsd:double", NodeFactory.createLiteral("NaN", XSDDatatype.XSDdouble)) ; }
++
++ @Test public void nodeId_double_4()
++ { test("'INF'^^xsd:double", NodeFactory.createLiteral("INF", XSDDatatype.XSDdouble)) ; }
++
++ @Test public void nodeId_double_5()
++ { test("'-INF'^^xsd:double", NodeFactory.createLiteral("-INF", XSDDatatype.XSDdouble)) ; }
++
++ @Test public void nodeId_double_6()
++ { test("'1.1E9'^^xsd:double") ; }
++
++ @Test public void nodeId_double_7()
++ { test("1.1E9") ; }
++
++ @Test public void nodeId_double_8()
++ { testNoInline("1.1E80") ; }
++
++ @Test public void nodeId_double_9()
++ { testNoInline("1.1E-80") ; }
++
++ @Test public void nodeId_float_1()
++ { test("'0.0'^^xsd:float") ; }
++
++ @Test public void nodeId_float_2()
++ { test("'0'^^xsd:float", "'0.0'^^xsd:float") ; }
++
++ @Test public void nodeId_float_3()
++ { testNoInline("'x'^^xsd:float") ; }
++
++ @Test public void nodeId_float_4()
++ { test("'1.1e1'^^xsd:float", "'11.0'^^xsd:float") ; }
++
++ @Test public void nodeId_float_5()
++ { test("'1.1E9'^^xsd:float") ; }
++
++ private void test(String x) { test(x, x) ; }
++
++ private void test(String x, String expected) {
++ test(x, NodeFactoryExtra.parseNode(expected)) ;
++ }
++
++ private void testNoInline(String x) {
++ Node n = NodeFactoryExtra.parseNode(x) ;
++ NodeId nodeId = NodeId.inline(n) ;
++ assertNull("Converted NodeId but expected no inline form: "+x, nodeId) ;
++ }
++
++ private void test(String x, Node correct) {
++ Node n = NodeFactoryExtra.parseNode(x) ;
++ NodeId nodeId = NodeId.inline(n) ;
++ assertNotNull("Expected inlining: "+x, nodeId);
++
++ boolean b = NodeId.hasInlineDatatype(n) ;
++ assertTrue("Converted NodeId but datatype test was false", b) ;
++ Node n2 = NodeId.extract(nodeId) ;
++ assertNotNull("Expected recovery", n2) ;
++ String s = "("+correct.getLiteralLexicalForm()+","+n2.getLiteralLexicalForm()+")" ;
++ assertTrue("Not same value: "+s, correct.sameValueAs(n2)) ;
++ // Term equality.
++ assertEquals("Not same term", correct, n2) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/sys/TS_Sys.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/sys/TS_Sys.java
index 0000000,0000000..7a37acc
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/sys/TS_Sys.java
@@@ -1,0 -1,0 +1,33 @@@
++/*
++ * 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.sys;
++
++
++import org.junit.runner.RunWith;
++import org.junit.runners.Suite;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestDatabaseOps.class
++ , TestDatabaseConnection.class
++ , TestSys.class
++ //, TestOps.class
++})
++
++public class TS_Sys
++{}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseConnection.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseConnection.java
index 0000000,0000000..8e6bdcc
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseConnection.java
@@@ -1,0 -1,0 +1,69 @@@
++/*
++ * 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 static org.junit.Assert.assertNotSame ;
++import static org.junit.Assert.assertSame ;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.apache.jena.sparql.core.DatasetGraph ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.sys.DatabaseConnection ;
++
++public class TestDatabaseConnection {
++
++ @Test
++ public void testStoreConnectionTxn1() {
++ TDBInternal.reset() ;
++ // Only do disk things for test that need them (disk takes time!).
++ String DIRx = ConfigTest.getCleanDir() ;
++ Location DIR = Location.create(DIRx);
++ FileOps.clearDirectory(DIRx) ;
++ try {
++ DatasetGraph dg1 = DatabaseConnection.connectCreate(DIR).getDatasetGraph() ;
++ DatasetGraph dg2 = DatabaseConnection.connectCreate(DIR).getDatasetGraph() ;
++ assertSame(dg1, dg2) ;
++ }
++ finally {
++ FileOps.clearDirectory(DIRx) ;
++ }
++ }
++
++ @Test
++ public void testStoreConnectionTxn2() {
++ // Named memory locations
++ TDBInternal.reset() ;
++ DatasetGraph dg1 = DatabaseConnection.connectCreate(Location.mem("FOO")).getDatasetGraph() ;
++ DatasetGraph dg2 = DatabaseConnection.connectCreate(Location.mem("FOO")).getDatasetGraph() ;
++ assertSame(dg1, dg2) ;
++ }
++
++ @Test
++ public void testStoreConnectionTxn3() {
++ // Un-named memory locations
++ TDBInternal.reset() ;
++ DatasetGraph dg1 = DatabaseConnection.connectCreate(Location.mem()).getDatasetGraph() ;
++ DatasetGraph dg2 = DatabaseConnection.connectCreate(Location.mem()).getDatasetGraph() ;
++ assertNotSame(dg1, dg2) ;
++ }
++
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java
index 0000000,0000000..fa90400
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java
@@@ -1,0 -1,0 +1,172 @@@
++/*
++ * 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.sys;
++
++import static org.junit.Assert.* ;
++import static org.junit.Assert.assertFalse ;
++import static org.junit.Assert.assertNotEquals ;
++import static org.junit.Assert.assertTrue ;
++
++import org.apache.commons.io.FileUtils ;
++import org.apache.jena.atlas.lib.FileOps ;
++import org.apache.jena.graph.Graph ;
++import org.apache.jena.graph.Triple ;
++import org.apache.jena.riot.RDFDataMgr ;
++import org.apache.jena.sparql.core.DatasetGraph ;
++import org.apache.jena.sparql.core.Quad ;
++import org.apache.jena.sparql.sse.SSE ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.DatabaseMgr ;
++import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
++import org.seaborne.tdb2.store.DatasetGraphTDB ;
++
++public class TestDatabaseOps
++{
++ static String DIRx = ConfigTest.getCleanDir() ;
++ static Location DIR = Location.create(DIRx);
++
++ static Quad quad1 = SSE.parseQuad("(_ <s> <p> 1)") ;
++ static Quad quad2 = SSE.parseQuad("(_ _:a <p> 2)") ;
++ static Triple triple1 = quad1.asTriple();
++ static Triple triple2 = quad2.asTriple();
++ static Triple triple3 = SSE.parseTriple("(<s> <q> 3)") ;
++
++ @Before
++ public void before() {
++ FileUtils.deleteQuietly(IOX.asFile(DIR));
++ FileOps.ensureDir(DIR.getDirectoryPath());
++ }
++
++ @After
++ public void after() {
++ TDBInternal.reset();
++ FileUtils.deleteQuietly(IOX.asFile(DIR));
++ }
++
++ @Test public void compact_dsg_1() {
++ DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(DIR);
++ DatasetGraphSwitchable dsgs = (DatasetGraphSwitchable)dsg;
++ DatasetGraph dsg1 = dsgs.get();
++ Location loc1 = ((DatasetGraphTDB)dsg1).getLocation();
++
++ Txn.executeWrite(dsg, ()-> {
++ dsg.add(quad2) ;
++ dsg.add(quad1) ;
++ }) ;
++ DatabaseMgr.compact(dsg);
++
++ assertFalse(StoreConnection.isSetup(loc1));
++
++ DatasetGraph dsg2 = dsgs.get();
++ Location loc2 = ((DatasetGraphTDB)dsg2).getLocation();
++
++ assertNotEquals(dsg1, dsg2);
++ assertNotEquals(loc1, loc2);
++
++ Txn.executeRead(dsg, ()-> {
++ assertTrue(dsg.contains(quad2)) ;
++ assertTrue(dsg.contains(quad1)) ;
++ }) ;
++
++ // dsg1 was closed and expelled. We must carefully reopen its storage only.
++ DatasetGraph dsgOld = StoreConnection.connectCreate(loc1).getDatasetGraph();
++
++ Txn.executeWrite(dsgOld, ()->dsgOld.delete(quad2));
++ Txn.executeRead(dsg, ()->assertTrue(dsg.contains(quad2)) );
++ Txn.executeRead(dsg2, ()->assertTrue(dsg2.contains(quad2)) ) ;
++ }
++
++ @Test public void compact_graph_2() {
++ // graphs across compaction.
++ DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(DIR);
++ Graph g = dsg.getDefaultGraph();
++
++ DatasetGraphSwitchable dsgs = (DatasetGraphSwitchable)dsg;
++ DatasetGraph dsg1 = dsgs.get();
++ Location loc1 = ((DatasetGraphTDB)dsg1).getLocation();
++
++ Txn.executeWrite(dsg, ()-> {
++ dsg.add(quad2) ;
++ dsg.add(quad1) ;
++ }) ;
++ DatabaseMgr.compact(dsg);
++ Txn.executeRead(dsg, ()-> {
++ assertEquals(2, g.size());
++ assertTrue(g.contains(triple2));
++ }) ;
++
++ // Check is not attached to the old graph.
++ DatasetGraph dsgOld = StoreConnection.connectCreate(loc1).getDatasetGraph();
++
++ Txn.executeWrite(dsgOld, ()->dsgOld.getDefaultGraph().delete(triple2));
++ Txn.executeRead(dsg, ()->assertTrue(g.contains(triple2)) );
++
++ Txn.executeWrite(dsg, ()->g.add(triple3));
++ Txn.executeRead(dsgOld, ()->assertFalse(dsgOld.getDefaultGraph().contains(triple3)) );
++ }
++
++ @Test public void compact_prefixes_3() {
++ // prefixes axcross compaction.
++ DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(DIR);
++ Graph g = dsg.getDefaultGraph();
++ Txn.executeWrite(dsg, ()-> g.getPrefixMapping().setNsPrefix("ex", "http://example/") );
++
++ DatasetGraphSwitchable dsgs = (DatasetGraphSwitchable)dsg;
++ DatasetGraph dsg1 = dsgs.get();
++ Location loc1 = ((DatasetGraphTDB)dsg1).getLocation();
++
++ DatabaseMgr.compact(dsg);
++
++ Txn.executeRead(dsg, ()-> {
++ assertEquals("ex", g.getPrefixMapping().getNsURIPrefix("http://example/"));
++ assertEquals("http://example/", g.getPrefixMapping().getNsPrefixURI("ex"));
++ }) ;
++
++ // Check is not attached to the old graph.
++ DatasetGraph dsgOld = StoreConnection.connectCreate(loc1).getDatasetGraph();
++
++ Txn.executeWrite(dsgOld, ()->dsgOld.getDefaultGraph().getPrefixMapping().removeNsPrefix("ex"));
++ Txn.executeRead(dsg, ()->assertEquals("http://example/", g.getPrefixMapping().getNsPrefixURI("ex")));
++
++ Txn.executeWrite(dsg, ()->g.getPrefixMapping().setNsPrefix("ex2", "http://exampl2/") );
++ Txn.executeRead(dsgOld, ()->assertNull(dsgOld.getDefaultGraph().getPrefixMapping().getNsPrefixURI("ex")));
++ }
++
++ @Test public void backup_1() {
++ DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(DIR);
++ Txn.executeWrite(dsg, ()-> {
++ dsg.add(quad2) ;
++ dsg.add(quad1) ;
++ }) ;
++ String file1 = DatabaseMgr.backup(dsg);
++ DatasetGraph dsg2 = RDFDataMgr.loadDatasetGraph(file1);
++ Txn.executeRead(dsg, ()-> {
++ assertTrue(dsg.contains(quad1)) ;
++ assertEquals(2, dsg.getDefaultGraph().size());
++ assertTrue(dsg2.getDefaultGraph().isIsomorphicWith(dsg.getDefaultGraph()));
++ }) ;
++ String file2 = DatabaseMgr.backup(dsg);
++ assertNotEquals(file1, file2);
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/sys/TestOps.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/sys/TestOps.java
index 0000000,0000000..0c997fe
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/sys/TestOps.java
@@@ -1,0 -1,0 +1,31 @@@
++/*
++ * 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.sys;
++
++import org.seaborne.dboe.base.block.FileMode ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++
++public class TestOps
++{
++ public static void setFileMode(FileMode mode)
++ {
++ SystemTDB.internalSetFileMode(mode) ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/sys/TestSys.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/sys/TestSys.java
index 0000000,0000000..b537655
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/sys/TestSys.java
@@@ -1,0 -1,0 +1,32 @@@
++/*
++ * 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.sys;
++
++
++import static org.junit.Assert.*;
++import org.junit.Test ;
++import org.seaborne.tdb2.TDB2 ;
++
++public class TestSys
++{
++ @Test public void sys1()
++ {
++ assertNotNull(TDB2.VERSION) ;
++ assertNotNull(TDB2.BUILD_DATE) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Assembler/tdb-dataset-embed.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Assembler/tdb-dataset-embed.ttl
index 0000000,0000000..9edd5a3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Assembler/tdb-dataset-embed.ttl
@@@ -1,0 -1,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.
++
++@prefix tdb2: <http://jena.apache.org/2016/tdb#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
++
++<#dataset> rdf:type tdb2:DatasetTDB2 ;
++ tdb2:location "--mem--" ;
++ .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Assembler/tdb-dataset.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Assembler/tdb-dataset.ttl
index 0000000,0000000..c9d8d7b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Assembler/tdb-dataset.ttl
@@@ -1,0 -1,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.
++
++@prefix tdb2: <http://jena.apache.org/2016/tdb#> .
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
++
++<#dataset> rdf:type tdb2:DatasetTDB2 ;
++ # Do at least one the long way.
++ tdb2:location "target/tdb-testing/DB" ;
++ .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Assembler/tdb-graph-embed.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Assembler/tdb-graph-embed.ttl
index 0000000,0000000..af3daab
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Assembler/tdb-graph-embed.ttl
@@@ -1,0 -1,0 +1,27 @@@
++# 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.
++
++@prefix tdb2: <http://jena.apache.org/2016/tdb#> .
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
++
++<#dataset> rdf:type ja:RDFDataset ;
++ ja:defaultGraph <#graph> ;
++ .
++
++<#graph> rdf:type tdb2:GraphTDB2 ;
++ tdb2:location "--mem--" ;
++ .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Assembler/tdb-graph-ref-dataset.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Assembler/tdb-graph-ref-dataset.ttl
index 0000000,0000000..fe256bd
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Assembler/tdb-graph-ref-dataset.ttl
@@@ -1,0 -1,0 +1,31 @@@
++# 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.
++
++@prefix tdb2: <http://jena.apache.org/2016/tdb#> .
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
++
++<#dataset> rdf:type ja:RDFDataset ;
++ ja:defaultGraph <#graph> ;
++ .
++
++<#graph> rdf:type tdb2:GraphTDB2 ;
++ tdb2:dataset <#dataset> ;
++ .
++
++<#dataset> rdf:type tdb2:DatasetTDB2 ;
++ tdb2:location "--mem--" ;
++ .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Assembler/tdb-graph.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Assembler/tdb-graph.ttl
index 0000000,0000000..2ae8396
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Assembler/tdb-graph.ttl
@@@ -1,0 -1,0 +1,27 @@@
++# 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.
++
++@prefix tdb2: <http://jena.apache.org/2016/tdb#> .
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
++
++<#dataset> rdf:type ja:RDFDataset ;
++ ja:defaultGraph <#graph> ;
++ .
++
++<#graph> rdf:type tdb2:GraphTDB2 ;
++ tdb2:location "target/tdb-testing/DB" ;
++ .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Assembler/tdb-named-graph-1.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Assembler/tdb-named-graph-1.ttl
index 0000000,0000000..78e40cf
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Assembler/tdb-named-graph-1.ttl
@@@ -1,0 -1,0 +1,29 @@@
++
++# 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.
++
++@prefix tdb2: <http://jena.apache.org/2016/tdb#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
++
++<#dataset> rdf:type ja:RDFDataset ;
++ ja:defaultGraph <#graph> ;
++ .
++
++<#graph> rdf:type tdb2:GraphTDB2 ;
++ tdb2:location "--mem--" ;
++ tdb2:graphName "http://example.com/graph" ;
++ .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Assembler/tdb-named-graph-2.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Assembler/tdb-named-graph-2.ttl
index 0000000,0000000..ee2feab
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Assembler/tdb-named-graph-2.ttl
@@@ -1,0 -1,0 +1,28 @@@
++# 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.
++
++@prefix tdb2: <http://jena.apache.org/2016/tdb#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
++
++<#dataset> rdf:type ja:RDFDataset ;
++ ja:defaultGraph <#graph> ;
++ .
++
++<#graph> rdf:type tdb2:GraphTDB2 ;
++ tdb2:location "--mem--" ;
++ tdb2:graphName "http://example.com/graph" ;
++ .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/basic-00.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/basic-00.rq
index 0000000,0000000..f2341a0
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/basic-00.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example>
++
++SELECT *
++{ ?x ?p ?z }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/basic-1-O.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/basic-1-O.rq
index 0000000,0000000..e1d1da7
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/basic-1-O.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ ?x ?p :z1 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/basic-1-P.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/basic-1-P.rq
index 0000000,0000000..d64b9f9
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/basic-1-P.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ ?x :p1 ?z }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/basic-1-PO.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/basic-1-PO.rq
index 0000000,0000000..01fa14a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/basic-1-PO.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ ?x :p1 :z1 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/basic-1-S.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/basic-1-S.rq
index 0000000,0000000..180188e
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/basic-1-S.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ :x1 ?p ?z }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/basic-1-SO.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/basic-1-SO.rq
index 0000000,0000000..a4242fb
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/basic-1-SO.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ :x1 ?p :z1 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/basic-1-SP.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/basic-1-SP.rq
index 0000000,0000000..37ddfe6
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/basic-1-SP.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ :x1 :p1 ?z }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/basic-1-SPO.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/basic-1-SPO.rq
index 0000000,0000000..41aa20f
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/basic-1-SPO.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT ?v
++{ :x1 :p1 :z1 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/basic-2-SO.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/basic-2-SO.rq
index 0000000,0000000..49c5711
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/basic-2-SO.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ ?x ?p ?x }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/basic-3-O.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/basic-3-O.rq
index 0000000,0000000..f7f3f6b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/basic-3-O.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ ?x ?p :z1a }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/basic-3-P.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/basic-3-P.rq
index 0000000,0000000..8c79fa5
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/basic-3-P.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ ?x :p1a ?z }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/basic-3-PO.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/basic-3-PO.rq
index 0000000,0000000..a011a1c
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/basic-3-PO.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ ?x :p1 :z1a }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/basic-3-S.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/basic-3-S.rq
index 0000000,0000000..8b62930
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/basic-3-S.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ :x1a ?p ?z }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/basic-3-SO.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/basic-3-SO.rq
index 0000000,0000000..e71f0b3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/basic-3-SO.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ :x1 ?p :z1a }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/basic-3-SP.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/basic-3-SP.rq
index 0000000,0000000..3b7ff81
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/basic-3-SP.rq
@@@ -1,0 -1,0 +1,4 @@@
++PREFIX : <http://example/>
++
++SELECT *
++{ :x1a :p1 ?z }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/data-1.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/data-1.ttl
index 0000000,0000000..d3a3d80
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/data-1.ttl
@@@ -1,0 -1,0 +1,17 @@@
++@prefix : <http://example/> .
++
++:x1 :p1 :z1 .
++:x1 :p1 :z2 .
++
++:x1 :p2 :z1 .
++:x1 :p2 :z2 .
++
++:x2 :p1 :z1 .
++:x2 :p1 :z2 .
++
++:x2 :p2 :z1 .
++:x2 :p2 :z2 .
++
++:x :p :x .
++:x :x :x .
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Basic/manifest.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Basic/manifest.ttl
index 0000000,0000000..aacbb56
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Basic/manifest.ttl
@@@ -1,0 -1,0 +1,101 @@@
++# 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.
++
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
++@prefix qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
++
++<> rdf:type mf:Manifest ;
++ rdfs:label "Basic test cases" ;
++ mf:entries
++ (
++ [ mf:name "Basic 00" ;
++ mf:action
++ [ qt:query <basic-00.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic S" ;
++ mf:action
++ [ qt:query <basic-1-S.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic P" ;
++ mf:action
++ [ qt:query <basic-1-P.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic O" ;
++ mf:action
++ [ qt:query <basic-1-O.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 1 SP" ;
++ mf:action
++ [ qt:query <basic-1-SP.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 1 SO" ;
++ mf:action
++ [ qt:query <basic-1-SO.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 1 PO" ;
++ mf:action
++ [ qt:query <basic-1-PO.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 1 SPO" ;
++ mf:action
++ [ qt:query <basic-1-SPO.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 2 SO" ;
++ mf:action
++ [ qt:query <basic-2-SO.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++
++ [ mf:name "Basic 3 S" ;
++ mf:action
++ [ qt:query <basic-3-S.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 3 P" ;
++ mf:action
++ [ qt:query <basic-3-P.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 3 O" ;
++ mf:action
++ [ qt:query <basic-3-O.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 3 SP" ;
++ mf:action
++ [ qt:query <basic-3-SP.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 3 SO" ;
++ mf:action
++ [ qt:query <basic-3-SO.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Basic 3 PO" ;
++ mf:action
++ [ qt:query <basic-3-SO.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ ) .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Data/solver-data.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Data/solver-data.ttl
index 0000000,0000000..cdbfb19
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Data/solver-data.ttl
@@@ -1,0 -1,0 +1,7 @@@
++@prefix : <http://example/> .
++
++:s :p :o .
++:s :p 10 .
++:s :p :x .
++:x :q :y .
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Loader/data-1.nq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Loader/data-1.nq
index 0000000,0000000..e9812a6
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Loader/data-1.nq
@@@ -1,0 -1,0 +1,1 @@@
++<s> <p> <o> <g> .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Loader/data-2.nt
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Loader/data-2.nt
index 0000000,0000000..81fc25f
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Loader/data-2.nt
@@@ -1,0 -1,0 +1,1 @@@
++<s> <p> <o> .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Loader/data-3.trig
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Loader/data-3.trig
index 0000000,0000000..8000cc1
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Loader/data-3.trig
@@@ -1,0 -1,0 +1,3 @@@
++prefix : <http://example/>
++
++:g { :s :p :o }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Loader/data-4.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Loader/data-4.ttl
index 0000000,0000000..49678f1
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Loader/data-4.ttl
@@@ -1,0 -1,0 +1,4 @@@
++prefix : <http://example/>
++
++:s :p :o .
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Pattern/data-1.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Pattern/data-1.ttl
index 0000000,0000000..d3a3d80
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Pattern/data-1.ttl
@@@ -1,0 -1,0 +1,17 @@@
++@prefix : <http://example/> .
++
++:x1 :p1 :z1 .
++:x1 :p1 :z2 .
++
++:x1 :p2 :z1 .
++:x1 :p2 :z2 .
++
++:x2 :p1 :z1 .
++:x2 :p1 :z2 .
++
++:x2 :p2 :z1 .
++:x2 :p2 :z2 .
++
++:x :p :x .
++:x :x :x .
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Pattern/manifest.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Pattern/manifest.ttl
index 0000000,0000000..094244b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Pattern/manifest.ttl
@@@ -1,0 -1,0 +1,35 @@@
++# 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.
++
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
++@prefix qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
++
++<> rdf:type mf:Manifest ;
++ rdfs:label "Patterns" ;
++ mf:entries
++ (
++ [ mf:name "Pattern 1" ;
++ mf:action
++ [ qt:query <pattern-1.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Pattern 2" ;
++ mf:action
++ [ qt:query <pattern-2.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ ) .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Pattern/pattern-1.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Pattern/pattern-1.rq
index 0000000,0000000..ca7c8fc
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Pattern/pattern-1.rq
@@@ -1,0 -1,0 +1,7 @@@
++PREFIX : <http://example/OTHER>
++
++SELECT *
++{
++ :NoSuchNode ?p ?z .
++ ?x ?p ?z
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Pattern/pattern-2.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Pattern/pattern-2.rq
index 0000000,0000000..9b90038
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Pattern/pattern-2.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example/OTHER>
++
++SELECT *
++{
++ # Test shared variables
++ ?x1 :p1 ?z .
++ ?x2 :p1 ?z .
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Quads/data-1.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Quads/data-1.ttl
index 0000000,0000000..adc4239
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Quads/data-1.ttl
@@@ -1,0 -1,0 +1,5 @@@
++@prefix : <http://example/> .
++
++:x :p 1 .
++
++:x1 :p :x .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Quads/data-2.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Quads/data-2.ttl
index 0000000,0000000..100a7c7
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Quads/data-2.ttl
@@@ -1,0 -1,0 +1,5 @@@
++@prefix : <http://example/> .
++
++:x :p 1 .
++
++:x2 :p :x .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Quads/data-dft.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Quads/data-dft.ttl
index 0000000,0000000..a2ef718
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Quads/data-dft.ttl
@@@ -1,0 -1,0 +1,10 @@@
++@prefix : <http://example/> .
++
++:x :p 1 .
++:x :p 2 .
++
++:y :p 1 .
++:y :p :x .
++:y :p :z .
++
++:z :q "abc" .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Quads/manifest.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Quads/manifest.ttl
index 0000000,0000000..15a46a7
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Quads/manifest.ttl
@@@ -1,0 -1,0 +1,51 @@@
++# 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.
++
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
++@prefix qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
++
++<> rdf:type mf:Manifest ;
++ rdfs:label "Quads and quad patterns" ;
++ mf:entries
++ (
++ [ mf:name "Quad-1" ;
++ mf:action
++ [ qt:query <quad-01.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ]
++ ]
++ [ mf:name "Quad-2" ;
++ mf:action
++ [ qt:query <quad-02.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ]
++ ]
++
++ ## Union of named graphs, explicitly named default graph
++ ## Complex patterns.
++
++## [ mf:name "Basic 00" ;
++## mf:action
++## [ qt:query <basic-00.rq> ;
++## qt:data <data-1.ttl> ;
++## qt:graphData ; ]
++## ]
++ ) .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Quads/quad-01.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Quads/quad-01.rq
index 0000000,0000000..b705fc8
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Quads/quad-01.rq
@@@ -1,0 -1,0 +1,9 @@@
++PREFIX : <http://example/>
++PREFIX sys: <urn:x-arq:>
++
++SELECT *
++{
++ {?s ?p ?o } UNION { GRAPH ?g {?s ?p ?o}}
++}
++
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Quads/quad-02.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Quads/quad-02.rq
index 0000000,0000000..ef3bf2f
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Quads/quad-02.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example/>
++PREFIX sys: <urn:x-arq:>
++
++SELECT *
++{
++ ?s ?p ?x
++ GRAPH ?g {?s1 ?p1 ?x }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/data-1.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/data-1.ttl
index 0000000,0000000..77be09c
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/data-1.ttl
@@@ -1,0 -1,0 +1,7 @@@
++@prefix : <http://example/> .
++
++:x :p 1 .
++:x :p 2 .
++
++
++:y :q :x .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/data-2.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/data-2.ttl
index 0000000,0000000..59ac719
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/data-2.ttl
@@@ -1,0 -1,0 +1,5 @@@
++@prefix : <http://example/> .
++
++:x :p 1 .
++:x :p 99 .
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/data-dft.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/data-dft.ttl
index 0000000,0000000..d64ddd9
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/data-dft.ttl
@@@ -1,0 -1,0 +1,5 @@@
++@prefix : <http://example/> .
++
++:x :p 11 .
++:x :p 999 .
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/manifest.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/manifest.ttl
index 0000000,0000000..217d229
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/manifest.ttl
@@@ -1,0 -1,0 +1,107 @@@
++# 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.
++
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
++@prefix mfx: <http://jena.hpl.hp.com/2005/05/test-manifest-extra#> .
++@prefix qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
++
++<> rdf:type mf:Manifest ;
++ rdfs:label "Union of named graphs" ;
++ mf:entries
++ (
++ [ mf:name "Merge-1" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-1.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-1-results.srx>
++ ]
++ [ mf:name "Merge-2" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-2.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-2-results.srx>
++ ]
++ [ mf:name "Merge-3" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-3.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-3-results.srx>
++ ]
++ [ mf:name "Merge-4" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-4.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-4-results.srx>
++ ]
++ [ mf:name "Merge-5" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-5.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-5-results.srx>
++ ]
++ [ mf:name "Merge-6" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-6.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-6-results.srx>
++ ]
++ # Queries that need more than one SQL query (currently)
++ [ mf:name "Merge-A" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-A.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-A-results.srx>
++ ]
++ [ mf:name "Merge-B" ;
++ rdf:type mfx:TestQuery ;
++ mf:action
++ [ qt:query <merge-B.rq> ;
++ qt:data <data-dft.ttl> ;
++ qt:graphData <data-1.ttl> ;
++ qt:graphData <data-2.ttl> ;
++ ] ;
++ mf:result <merge-B-results.srx>
++ ]
++ ).
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-1-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-1-results.srx
index 0000000,0000000..f850ec3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-1-results.srx
@@@ -1,0 -1,0 +1,57 @@@
++<?xml version="1.0"?>
++<sparql
++ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++ xmlns:xs="http://www.w3.org/2001/XMLSchema#"
++ xmlns="http://www.w3.org/2005/sparql-results#" >
++ <head>
++ <variable name="s"/>
++ <variable name="p"/>
++ <variable name="o"/>
++ </head>
++ <results>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-1.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-1.rq
index 0000000,0000000..c403064
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-1.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example/>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph { ?s ?p ?o }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-2-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-2-results.srx
index 0000000,0000000..18f9252
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-2-results.srx
@@@ -1,0 -1,0 +1,66 @@@
++<?xml version="1.0"?>
++<sparql
++ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++ xmlns:xs="http://www.w3.org/2001/XMLSchema#"
++ xmlns="http://www.w3.org/2005/sparql-results#" >
++ <head>
++ <variable name="s"/>
++ <variable name="p"/>
++ <variable name="o"/>
++ <variable name="q"/>
++ <variable name="z"/>
++ </head>
++ <results>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-2.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-2.rq
index 0000000,0000000..27953a6
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-2.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example/>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph { ?s ?p ?o . ?o ?q ?z }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-3-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-3-results.srx
index 0000000,0000000..4a65413
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-3-results.srx
@@@ -1,0 -1,0 +1,31 @@@
++<?xml version="1.0"?>
++<sparql
++ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++ xmlns:xs="http://www.w3.org/2001/XMLSchema#"
++ xmlns="http://www.w3.org/2005/sparql-results#" >
++ <head>
++ <variable name="p"/>
++ </head>
++ <results>
++ <result>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ </result>
++ <result>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ </result>
++ <result>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ </result>
++ <result>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-3.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-3.rq
index 0000000,0000000..1212926
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-3.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example/>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph { [] ?p [] }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-4-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-4-results.srx
index 0000000,0000000..0b44cb2
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-4-results.srx
@@@ -1,0 -1,0 +1,99 @@@
++<?xml version="1.0"?>
++<sparql
++ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++ xmlns:xs="http://www.w3.org/2001/XMLSchema#"
++ xmlns="http://www.w3.org/2005/sparql-results#" >
++ <head>
++ <variable name="s"/>
++ <variable name="p"/>
++ <variable name="o"/>
++ <variable name="q"/>
++ <variable name="z"/>
++ </head>
++ <results>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-4.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-4.rq
index 0000000,0000000..004f4bc
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-4.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example/>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph
++ { ?s ?p ?o . OPTIONAL { ?o ?q ?z } }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-5-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-5-results.srx
index 0000000,0000000..c7d777f
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-5-results.srx
@@@ -1,0 -1,0 +1,33 @@@
++<?xml version="1.0"?>
++<sparql xmlns="http://www.w3.org/2005/sparql-results#">
++ <head>
++ <variable name="p"/>
++ <variable name="o"/>
++ </head>
++ <results>
++ <result>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-5.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-5.rq
index 0000000,0000000..fa9bfe3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-5.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example/>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph { :x ?p ?o }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-6-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-6-results.srx
index 0000000,0000000..b4d31dc
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-6-results.srx
@@@ -1,0 -1,0 +1,43 @@@
++<?xml version="1.0"?>
++<sparql xmlns="http://www.w3.org/2005/sparql-results#">
++ <head>
++ <variable name="x"/>
++ <variable name="p"/>
++ <variable name="v"/>
++ </head>
++ <results>
++ <result>
++ <binding name="x">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="v">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="x">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="v">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="x">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="v">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-6.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-6.rq
index 0000000,0000000..7819cbb
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-6.rq
@@@ -1,0 -1,0 +1,7 @@@
++PREFIX : <http://example/>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph { ?x ?p 99 . ?x :p ?v }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-A-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-A-results.srx
index 0000000,0000000..1438c25
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-A-results.srx
@@@ -1,0 -1,0 +1,99 @@@
++<?xml version="1.0"?>
++<sparql
++ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++ xmlns:xs="http://www.w3.org/2001/XMLSchema#"
++ xmlns="http://www.w3.org/2005/sparql-results#" >
++ <head>
++ <variable name="s"/>
++ <variable name="p"/>
++ <variable name="o"/>
++ <variable name="q"/>
++ <variable name="z"/>
++ </head>
++ <results>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">99</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">1</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="z">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="o">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">2</literal>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-A.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-A.rq
index 0000000,0000000..7bab242
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-A.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph
++ { ?s ?p ?o . OPTIONAL { ?o ?q ?z FILTER(?o != 123) } }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-B-results.srx
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-B-results.srx
index 0000000,0000000..60d7766
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-B-results.srx
@@@ -1,0 -1,0 +1,49 @@@
++<?xml version="1.0"?>
++<sparql
++ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++ xmlns:xs="http://www.w3.org/2001/XMLSchema#"
++ xmlns="http://www.w3.org/2005/sparql-results#" >
++ <head>
++ <variable name="s"/>
++ <variable name="p"/>
++ <variable name="o"/>
++ <variable name="q"/>
++ <variable name="v"/>
++ </head>
++ <results>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="v">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">11</literal>
++ </binding>
++ </result>
++ <result>
++ <binding name="s">
++ <uri>http://example/y</uri>
++ </binding>
++ <binding name="p">
++ <uri>http://example/q</uri>
++ </binding>
++ <binding name="o">
++ <uri>http://example/x</uri>
++ </binding>
++ <binding name="q">
++ <uri>http://example/p</uri>
++ </binding>
++ <binding name="v">
++ <literal datatype="http://www.w3.org/2001/XMLSchema#integer">999</literal>
++ </binding>
++ </result>
++ </results>
++</sparql>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/UnionGraph/merge-B.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/UnionGraph/merge-B.rq
index 0000000,0000000..d4aceda
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/UnionGraph/merge-B.rq
@@@ -1,0 -1,0 +1,8 @@@
++PREFIX : <http://example>
++PREFIX arq: <urn:x-arq:>
++
++SELECT *
++{
++ GRAPH arq:UnionGraph { ?s ?p ?o . }
++ { ?o ?q ?v }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Update/create-1.ru
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Update/create-1.ru
index 0000000,0000000..3276ec1
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Update/create-1.ru
@@@ -1,0 -1,0 +1,1 @@@
++CREATE GRAPH <http://example/graph>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Update/drop-1.ru
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Update/drop-1.ru
index 0000000,0000000..2512eb3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Update/drop-1.ru
@@@ -1,0 -1,0 +1,1 @@@
++DROP GRAPH <http://example/graph>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Update/update-1.ru
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Update/update-1.ru
index 0000000,0000000..7a6b737
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Update/update-1.ru
@@@ -1,0 -1,0 +1,3 @@@
++PREFIX : <http://example/>
++
++INSERT { :r :p 123 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Update/update-2.ru
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Update/update-2.ru
index 0000000,0000000..41e4ec0
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Update/update-2.ru
@@@ -1,0 -1,0 +1,5 @@@
++PREFIX : <http://example/>
++
++CREATE GRAPH <http://example/g1>
++INSERT INTO GRAPH <http://example/g1>
++{ :r :p 123 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Update/update-3.ru
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Update/update-3.ru
index 0000000,0000000..17f8410
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Update/update-3.ru
@@@ -1,0 -1,0 +1,7 @@@
++PREFIX : <http://example/>
++
++CREATE GRAPH <http://example/g1>
++INSERT INTO GRAPH <http://example/g1>
++{ :r :p 123 }
++DELETE FROM GRAPH <http://example/g1>
++{ :r :p 123 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Values/data-1.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Values/data-1.ttl
index 0000000,0000000..27c37dd
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Values/data-1.ttl
@@@ -1,0 -1,0 +1,23 @@@
++@prefix : <http://example/> .
++@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
++
++:x1 :p 1 .
++:x2 :p "1" .
++:x3 :p "1"@en .
++
++:x4 :p 1.5 .
++
++:x5 :p "2008-04-29T09:13:15+01:00"^^xsd:dateTime .
++
++:x6 :p "0008-04-29T09:13:15-01:00"^^xsd:dateTime .
++
++:x7 :p "-3000-04-29T09:13:15Z"^^xsd:dateTime .
++
++# Not encoded inline
++:x8 :p "-3000-04-29T09:13:15Z"^^xsd:dateTime .
++
++:x9 :p "2008-04-29"^^xsd:date .
++
++:x10 :p "2008-04-29Z"^^xsd:date .
++
++:x11 :p "2008-04-29+01:00"^^xsd:date .
[48/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFileRandomAccess.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFileRandomAccess.java
index 0000000,0000000..c3738ad
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFileRandomAccess.java
@@@ -1,0 -1,0 +1,148 @@@
++/*
++ * 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.dboe.base.file;
++
++import java.io.IOException ;
++import java.io.RandomAccessFile ;
++
++import org.apache.jena.atlas.RuntimeIOException ;
++import org.apache.jena.atlas.io.IO ;
++
++/** Implementation of {@link BinaryDataFile} using {@link RandomAccessFile}.
++ *
++ * <li>No buffering of reads or writes provided.
++ * <li>Not thread-safe.
++ *
++ * @see BinaryDataFileWriteBuffered
++ */
++public class BinaryDataFileRandomAccess implements BinaryDataFile {
++ // On OpenJDK, RandomAccessFile and FileChannelImpl both
++ // dive into native code.
++ protected RandomAccessFile file ;
++ protected boolean readMode ;
++ protected long readPosition ;
++ protected long writePosition ;
++ private final String filename ;
++
++ public BinaryDataFileRandomAccess(String filename) {
++ this.filename = filename ;
++ }
++
++ @Override
++ public void open() {
++ if ( file != null )
++ throw new RuntimeIOException("Already open") ;
++ try {
++ file = new RandomAccessFile(filename, "rw") ;
++ writePosition = file.length() ;
++ readPosition = 0 ;
++ readMode = true ;
++ }
++ catch (IOException e) { IO.exception(e); }
++ }
++
++ @Override
++ public boolean isOpen() {
++ return file != null ;
++ }
++
++ @Override
++ public int read(long posn, byte[] b, int start, int length) {
++ checkOpen() ;
++ switchToReadMode() ;
++ seek(posn) ;
++ try {
++ int x = file.read(b, start, length) ;
++ readPosition += x ;
++ return x ;
++ }
++ catch (IOException ex) { IO.exception(ex); return -1 ; }
++ }
++
++ @Override
++ public long write(byte[] b, int start, int length) {
++ checkOpen() ;
++ switchToWriteMode() ;
++ long x = writePosition ;
++ try {
++ file.write(b, start, length) ;
++ writePosition += length ;
++ }
++ catch (IOException ex) { IO.exception(ex) ; }
++ return x ;
++ }
++
++
++ // Move the RandomAccess file pointer.
++ private void seek(long posn) {
++ try { file.seek(posn) ; }
++ catch (IOException ex) { IO.exception(ex) ; }
++ }
++
++ @Override
++ public void truncate(long length) {
++ checkOpen() ;
++ switchToWriteMode() ;
++ try { file.setLength(length); }
++ catch (IOException ex) { IO.exception(ex) ; }
++ }
++
++ @Override
++ public void sync() {
++ checkOpen() ;
++ flush$() ;
++ }
++
++ protected void flush$() {
++ try { file.getFD().sync() ; }
++ catch (IOException ex) { IO.exception(ex) ; }
++ }
++
++ @Override
++ public void close() {
++ if ( ! isOpen() )
++ return ;
++ try { file.close(); }
++ catch (IOException ex) { IO.exception(ex) ; }
++ file = null ;
++ }
++
++ @Override
++ public long length() {
++ try { return file.length() ;}
++ catch (IOException ex) { IO.exception(ex) ; return -1 ;}
++ }
++
++ protected void switchToReadMode() {
++ if ( ! readMode )
++ readMode = true ;
++ }
++
++ protected void switchToWriteMode() {
++ if ( readMode ) {
++ readMode = false ;
++ seek(writePosition);
++ }
++ }
++
++ protected void checkOpen() {
++ if ( ! isOpen() )
++ throw new RuntimeIOException("Not open") ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFileSync.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFileSync.java
index 0000000,0000000..bb5c1b1
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFileSync.java
@@@ -1,0 -1,0 +1,82 @@@
++/*
++ * 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.dboe.base.file;
++
++
++/** Add synchronization to all BinaryDataFile operations.
++ * This gives the correct thread-safe operation
++ * but isn'tnecessarily the best way to do it.
++ */
++public class BinaryDataFileSync implements BinaryDataFile {
++ private final BinaryDataFile other ;
++
++ public BinaryDataFileSync(BinaryDataFile other) {
++ this.other = other ;
++ }
++
++ @Override
++ synchronized
++ public void open() { other.open() ; }
++
++ @Override
++ synchronized
++ public boolean isOpen() { return other.isOpen() ; }
++
++ @Override
++ synchronized
++ public int read(long posn, byte[] b) {
++ return other.read(posn, b) ;
++ }
++
++ @Override
++ synchronized
++ public int read(long posn, byte[] b, int start, int length) {
++ return other.read(posn, b, start, length) ;
++ }
++
++ @Override
++ synchronized
++ public long write(byte[] b) {
++ return other.write(b) ;
++ }
++
++ @Override
++ synchronized
++ public long write(byte[] b, int start, int length) {
++ return other.write(b, start, length) ;
++ }
++
++ @Override
++ synchronized
++ public long length() {
++ return other.length() ;
++ }
++
++ @Override
++ synchronized
++ public void truncate(long length) { other.truncate(length); }
++
++ @Override
++ synchronized
++ public void sync() { other.sync(); }
++
++ @Override
++ synchronized
++ public void close() { other.close(); }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFileWrapper.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFileWrapper.java
index 0000000,0000000..b970284
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFileWrapper.java
@@@ -1,0 -1,0 +1,67 @@@
++/*
++ * 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.dboe.base.file;
++
++public class BinaryDataFileWrapper implements BinaryDataFile {
++ private final BinaryDataFile other ;
++
++ public BinaryDataFileWrapper(BinaryDataFile other) {
++ this.other = other ;
++ }
++
++ @Override
++ public void open() { other.open() ; }
++
++ @Override
++ public boolean isOpen() { return other.isOpen() ; }
++
++ @Override
++ public int read(long posn, byte[] b) {
++ return other.read(posn, b) ;
++ }
++
++ @Override
++ public int read(long posn, byte[] b, int start, int length) {
++ return other.read(posn, b, start, length) ;
++ }
++
++ @Override
++ public long write(byte[] b) {
++ return other.write(b) ;
++ }
++
++ @Override
++ public long write(byte[] b, int start, int length) {
++ return other.write(b, start, length) ;
++ }
++
++ @Override
++ public long length() {
++ return other.length() ;
++ }
++
++ @Override
++ public void truncate(long length) { other.truncate(length); }
++
++ @Override
++ public void sync() { other.sync(); }
++
++ @Override
++ public void close() { other.close(); }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFileWriteBuffered.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFileWriteBuffered.java
index 0000000,0000000..da25ce1
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFileWriteBuffered.java
@@@ -1,0 -1,0 +1,162 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.apache.jena.atlas.RuntimeIOException ;
++
++/** Implementation of {@link BinaryDataFile} adding write buffering to another
++ * {@link BinaryDataFile} file such as a {@link BinaryDataFileRandomAccess}.
++ * <li>Thread-safe.
++ * <li>No read buffering provided.
++ * <li>The write buffer is flushed when switching to read.
++ */
++
++public class BinaryDataFileWriteBuffered implements BinaryDataFile {
++ private static final int SIZE = 128*1024 ;
++ private final Object sync = new Object() ;
++ private byte[] buffer ;
++ private int bufferLength ;
++ private boolean pendingOutput ;
++ private final BinaryDataFile other ;
++
++ public BinaryDataFileWriteBuffered(BinaryDataFile other) {
++ this(other, SIZE) ;
++ }
++
++ public BinaryDataFileWriteBuffered(BinaryDataFile other, int bufferSize) {
++ this.other = other ;
++ buffer = new byte[bufferSize] ;
++ }
++
++ @Override
++ public void open() {
++ synchronized(sync) {
++ other.open() ;
++ bufferLength = 0 ;
++ pendingOutput = false ;
++ }
++ }
++
++ @Override
++ public void close() {
++ synchronized(sync) {
++ if ( ! isOpen() )
++ return ;
++ writeBuffer();
++ other.close() ;
++ }
++ }
++
++ @Override
++ public boolean isOpen() {
++ synchronized(sync) {
++ return other.isOpen() ;
++ }
++ }
++
++ @Override
++ public long length() {
++ synchronized(sync) {
++ return other.length()+bufferLength ;
++ }
++ }
++
++ @Override
++ public void truncate(long posn) {
++ synchronized(sync) {
++ checkOpen() ;
++ if ( pendingOutput && posn >= other.length() )
++ writeBuffer() ;
++ other.truncate(posn) ;
++ }
++ }
++
++ private void checkOpen() {
++ if ( ! other.isOpen() )
++ throw new RuntimeIOException("Not open") ;
++ }
++
++ @Override
++ public int read(long posn, byte[] b, int start, int length) {
++ synchronized(sync) {
++ // Overlap with buffered area
++ // We flush the write buffer for a read so no need to check.
++ checkOpen() ;
++ switchToReadMode() ;
++ return other.read(posn, b, start, length) ;
++ }
++ }
++
++ @Override
++ public long write(byte[] buf, int off, int len) {
++ synchronized(sync) {
++ checkOpen() ;
++ switchToWriteMode() ;
++ long x = length() ;
++
++// if ( false ) {
++// // No buffering
++// try { file.write(buf, off, len) ; }
++// catch (IOException e) { IO.exception(e); }
++// bufferLength = 0 ;
++// return ;
++// }
++
++ // No room.
++ if ( bufferLength + len >= SIZE )
++ writeBuffer() ;
++
++ if ( bufferLength + len < SIZE ) {
++ // Room to buffer
++ System.arraycopy(buf, off, buffer, bufferLength, len);
++ bufferLength += len ;
++ pendingOutput = true ;
++ return x ;
++ }
++ // Larger than the buffer space. Write directly.
++ other.write(buf, off, len) ;
++ return x ;
++ }
++ }
++
++ @Override
++ public void sync() {
++ synchronized(sync) {
++ writeBuffer() ;
++ other.sync();
++ }
++ }
++
++ private void writeBuffer() {
++ if ( pendingOutput ) {
++ pendingOutput = false ;
++ other.write(buffer, 0, bufferLength) ;
++ bufferLength = 0 ;
++ }
++ }
++
++ // Inside synchronization
++ protected void switchToWriteMode() {
++ }
++
++ // Inside synchronization
++ protected void switchToReadMode() {
++ writeBuffer() ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccess.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccess.java
index 0000000,0000000..ba8d491
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccess.java
@@@ -1,0 -1,0 +1,64 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.apache.jena.atlas.lib.Closeable ;
++import org.apache.jena.atlas.lib.Sync ;
++import org.seaborne.dboe.base.block.Block ;
++
++/**
++ * Interface to concrete storage - read and write Blocks, addressed by id.
++ * Suitable for memory mapped I/O (returns
++ * internally allocated space for read, not provided from outside; write() can
++ * insist the block written comes from allocate()).
++ * This interfce can also be backed by an in-memory implemntation
++ * ({@link BlockAccessMem}, {@link BlockAccessByteArray}).
++ *
++ * This is wrapped in a BlockMgr to provide a higher level abstraction.
++ *
++ * @see BufferChannel
++ */
++public interface BlockAccess extends Sync, Closeable
++{
++ public Block allocate(int size) ;
++
++ public Block read(long id) ;
++
++ public void write(Block block) ;
++
++ public void overwrite(Block block) ;
++
++ public boolean isEmpty() ;
++
++ /* The limit of the current allocation space.
++ * Allocated blocks have ids in [0, allocBoundary).
++ * Allocation units need not be in +1 increments.
++ */
++ public long allocBoundary() ;
++
++ /** Reset the allocation space (i.e. truncate).
++ * The boundary should be a number obtained from a previous
++ * call of allocLimit. It can not be greater than the current
++ * allocation boundary.
++ */
++ public void resetAllocBoundary(long boundary) ;
++
++ public boolean valid(long id) ;
++
++ public String getLabel() ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccessBase.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccessBase.java
index 0000000,0000000..1244cd8
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccessBase.java
@@@ -1,0 -1,0 +1,175 @@@
++/*
++ * 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.dboe.base.file;
++
++import static java.lang.String.format ;
++
++import java.nio.ByteBuffer ;
++import java.nio.channels.FileChannel ;
++import java.util.concurrent.atomic.AtomicLong ;
++
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.base.block.BlockException ;
++import org.seaborne.dboe.sys.FileLib ;
++import org.seaborne.dboe.sys.Sys;
++import org.slf4j.Logger ;
++
++/** Support for a disk file backed FileAccess */
++public abstract class BlockAccessBase implements BlockAccess {
++ protected final int blockSize ;
++ protected FileChannel file ;
++ protected final String filename ;
++
++ protected final String label ;
++ // Does this need to be tread safe?
++ // Only changes in a write transaction
++
++ // Don't overload use of this!
++ protected final AtomicLong seq ;
++ protected long numFileBlocks = -1 ;
++
++ public BlockAccessBase(String filename, int blockSize) {
++ this.filename = filename ;
++ this.file = FileLib.openManaged(filename) ;
++ this.blockSize = blockSize ;
++ this.label = label(filename) ;
++ // This is not related to used file length in mapped mode.
++ long filesize = FileLib.size(file) ;
++ long longBlockSize = blockSize ;
++
++ numFileBlocks = filesize / longBlockSize ; // This is not related to
++ // used file length in mapped
++ // mode.
++ seq = new AtomicLong(numFileBlocks) ;
++
++ if ( numFileBlocks > Integer.MAX_VALUE )
++ getLog().warn(format("File size (%d) exceeds tested block number limits (%d)", filesize, blockSize)) ;
++
++ if ( filesize % longBlockSize != 0 )
++ throw new BlockException(format("File size (%d) not a multiple of blocksize (%d)", filesize, blockSize)) ;
++ }
++
++ /** Find path compoent, with extension */
++ private static String label(String filename) {
++ int j = filename.lastIndexOf('/') ;
++ if ( j < 0 )
++ j = filename.lastIndexOf('\\') ;
++ String fn = (j >= 0) ? filename.substring(j + 1) : filename ;
++ return fn ;
++ }
++
++ protected abstract Logger getLog() ;
++
++ @Override
++ final public boolean isEmpty() {
++ return numFileBlocks <= 0 ;
++ }
++
++ final protected void writeNotification(Block block) {}
++
++ final protected void overwriteNotification(Block block) {
++ // Write at end => extend
++ if ( block.getId() >= numFileBlocks ) {
++ numFileBlocks = block.getId() + 1 ;
++ seq.set(numFileBlocks) ;
++ }
++ }
++
++ final protected int allocateId() {
++ checkIfClosed() ;
++ int id = (int)seq.getAndIncrement() ;
++ numFileBlocks++ ; // TODO Fix this when proper freeblock management is
++ // introduced.
++ return id ;
++ }
++
++ @Override
++ final public long allocBoundary() {
++ checkIfClosed() ;
++ return seq.get() ;
++ // Underlying area is untouched.
++ }
++
++ @Override
++ final public void resetAllocBoundary(long boundary) {
++ checkIfClosed() ;
++ seq.set(boundary) ;
++ _resetAllocBoundary(boundary) ;
++ }
++
++ protected abstract void _resetAllocBoundary(long boundary) ;
++
++ @Override
++ final synchronized public boolean valid(long id) {
++ if ( id >= numFileBlocks )
++ return false ;
++ if ( id < 0 )
++ return false ;
++ return true ;
++ }
++
++ final protected void check(long id) {
++ if ( id > Integer.MAX_VALUE )
++ throw new BlockException(format("BlockAccessBase: Id (%d) too large", id)) ;
++
++ // Access to numFileBlocks not synchronized - it's only a check
++ if ( id < 0 || id >= numFileBlocks ) {
++ // Do it properly!
++ synchronized (this) {
++ if ( id < 0 || id >= numFileBlocks )
++ throw new BlockException(format("BlockAccessBase: Bounds exception: %s: (%d,%d)", filename, id, numFileBlocks)) ;
++ }
++ }
++ }
++
++ final protected void check(Block block) {
++ check(block.getId()) ;
++ ByteBuffer bb = block.getByteBuffer() ;
++ if ( bb.capacity() != blockSize )
++ throw new BlockException(format("BlockMgrFile: Wrong size block. Expected=%d : actual=%d", blockSize, bb.capacity())) ;
++ if ( bb.order() != Sys.NetworkOrder )
++ throw new BlockException("BlockMgrFile: Wrong byte order") ;
++ }
++
++ protected void force() {
++ FileLib.sync(file) ;
++ }
++
++ // @Override
++ final public boolean isClosed() {
++ return file == null ;
++ }
++
++ protected final void checkIfClosed() {
++ if ( isClosed() )
++ getLog().error("File has been closed") ;
++ }
++
++ protected abstract void _close() ;
++
++ @Override
++ final public void close() {
++ _close() ;
++ file = null ;
++ }
++
++ @Override
++ public String getLabel() {
++ return label ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccessByteArray.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccessByteArray.java
index 0000000,0000000..45d932c
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccessByteArray.java
@@@ -1,0 -1,0 +1,129 @@@
++/*
++ * 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.dboe.base.file ;
++
++import java.nio.ByteBuffer ;
++
++import org.apache.jena.atlas.lib.ByteBufferLib ;
++import org.seaborne.dboe.base.block.Block ;
++import static org.seaborne.dboe.sys.Sys.SizeOfInt ;
++
++/**
++ * FileAccess interface backed by a byte array.
++ */
++public class BlockAccessByteArray implements BlockAccess {
++ private ByteBuffer bytes ;
++ private long length ; // Bytes in use: 0 to length-1
++ private long alloc ; // Bytes allocated - next allocation number.
++ private final String label ;
++
++ public BlockAccessByteArray(String label) {
++ bytes = ByteBuffer.allocate(1024) ;
++ length = 0 ;
++ alloc = 0 ;
++ this.label = label ;
++ }
++
++ @Override
++ public String getLabel() {
++ return label ;
++ }
++
++ @Override
++ public Block allocate(int size) {
++ long addr = alloc ;
++ ByteBuffer bb = ByteBuffer.allocate(size) ;
++ alloc += (size + SizeOfInt) ;
++ return new Block((int)addr, bb) ;
++ }
++
++ @Override
++ public long allocBoundary() {
++ return alloc ;
++ }
++
++ @Override
++ public void resetAllocBoundary(long boundary) {
++ ByteBufferLib.fill(bytes, (int)boundary, (int)length, (byte)0);
++ length = boundary ;
++ alloc = boundary ;
++ bytes.limit((int)alloc) ;
++
++ }
++
++ @Override
++ public Block read(long id) {
++ // Variable length blocks.
++ if ( id < 0 || id >= length || id >= bytes.capacity() )
++ throw new FileException("Bad id (read): " + id) ;
++ bytes.position((int)id) ;
++ int len = bytes.getInt() ;
++ ByteBuffer bb = ByteBuffer.allocate(len) ;
++ // Copy out the bytes - copy for safety.
++ bytes.get(bb.array(), 0, len) ;
++ return new Block(id, bb) ;
++ }
++
++ @Override
++ public void write(Block block) {
++ // Variable length blocks.
++ long loc = block.getId() ;
++ if ( loc < 0 || loc > length ) // Can be equal => append.
++ throw new FileException("Bad id (write): " + loc + " (" + alloc + "," + length + ")") ;
++ ByteBuffer bb = block.getByteBuffer() ;
++ int len = bb.capacity() ;
++
++ if ( loc == length ) {
++ if ( bytes.capacity() - length < len ) {
++ int cap2 = bytes.capacity() + 1024 ;
++ while (bytes.capacity() - length < len)
++ cap2 += 1024 ;
++
++ ByteBuffer bytes2 = ByteBuffer.allocate(cap2) ;
++ bytes2.position(0) ;
++ bytes2.put(bytes) ;
++ bytes = bytes2 ;
++ }
++ length += len + SizeOfInt ;
++ }
++ bytes.position((int)loc) ;
++ bytes.putInt(len) ;
++ bytes.put(bb.array(), 0, bb.capacity()) ;
++ }
++
++ @Override
++ public void overwrite(Block block) {
++ write(block) ;
++ }
++
++ @Override
++ public boolean isEmpty() {
++ return length == 0 ;
++ }
++
++ @Override
++ public boolean valid(long id) {
++ return (id >= 0 && id < length) ;
++ }
++
++ @Override
++ public void sync() {}
++
++ @Override
++ public void close() {}
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccessDirect.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccessDirect.java
index 0000000,0000000..62b4f43
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccessDirect.java
@@@ -1,0 -1,0 +1,130 @@@
++/*
++ * 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.dboe.base.file;
++
++import static java.lang.String.format ;
++
++import java.io.IOException ;
++import java.nio.ByteBuffer ;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.sys.FileLib ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++public class BlockAccessDirect extends BlockAccessBase
++{
++ // Maybe layer BlockAccess on BufferChannel - retrofitting.
++ // but need separate for memory mapped files anyway.
++
++ private static Logger log = LoggerFactory.getLogger(BlockAccessDirect.class) ;
++
++ public BlockAccessDirect(String filename, int blockSize)
++ {
++ super(filename, blockSize) ;
++ }
++
++ @Override
++ public Block allocate(int blkSize)
++ {
++ if ( blkSize > 0 && blkSize != this.blockSize )
++ throw new FileException("Fixed blocksize only: request= "+blkSize+"fixed size="+this.blockSize) ;
++ int x = allocateId() ;
++ ByteBuffer bb = ByteBuffer.allocate(blkSize) ;
++ Block block = new Block(x, bb) ;
++ return block;
++ }
++
++ @Override
++ public Block read(long id)
++ {
++ check(id) ;
++ checkIfClosed() ;
++ ByteBuffer bb = ByteBuffer.allocate(blockSize) ;
++ readByteBuffer(id, bb) ;
++ bb.rewind() ;
++ Block block = new Block(id, bb) ;
++ return block ;
++ }
++
++ private void readByteBuffer(long id, ByteBuffer dst)
++ {
++ try {
++ int len = file.read(dst, filePosition(id)) ;
++ if ( len != blockSize )
++ throw new FileException(format("get: short read (%d, not %d)", len, blockSize)) ;
++ } catch (IOException ex)
++ { throw new FileException("FileAccessDirect", ex) ; }
++ }
++
++ private final long filePosition(long id)
++ {
++ return id*blockSize ;
++ }
++
++ @Override
++ public void write(Block block)
++ {
++ check(block) ;
++ checkIfClosed() ;
++ ByteBuffer bb = block.getByteBuffer() ;
++ // This .clear() except the javadoc suggests this is not the correct use of .clear()
++ // and the name does
++ bb.limit(bb.capacity()) ; // It shouldn't have been changed.
++ bb.rewind() ;
++ try {
++ int len = file.write(bb, filePosition(block.getId())) ;
++ if ( len != blockSize )
++ throw new FileException(format("write: short write (%d, not %d)", len, blockSize)) ;
++ } catch (IOException ex)
++ { throw new FileException("FileAccessDirect", ex) ; }
++ writeNotification(block) ;
++ }
++
++ @Override
++ public void overwrite(Block block)
++ {
++ overwriteNotification(block) ;
++ write(block) ;
++ }
++
++ @Override
++ protected void _resetAllocBoundary(long boundary) {
++ FileLib.truncate(file, filePosition(boundary)) ;
++ }
++
++ @Override
++ public void sync()
++ {
++ force() ;
++ }
++
++ @Override
++ protected void _close()
++ { super.force() ; }
++
++ @Override
++ protected Logger getLog()
++ {
++ return log ;
++ }
++
++ @Override
++ public String toString() { return "Direct:"+FileOps.basename(filename) ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccessMapped.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccessMapped.java
index 0000000,0000000..636d8f6
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccessMapped.java
@@@ -1,0 -1,0 +1,267 @@@
++/*
++ * 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.dboe.base.file;
++
++import static java.lang.String.format ;
++
++import java.io.IOException ;
++import java.nio.ByteBuffer ;
++import java.nio.MappedByteBuffer ;
++import java.nio.channels.FileChannel.MapMode ;
++import java.util.Arrays ;
++
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.sys.SystemIndex ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/** FileAccess for a file, using memory mapped I/O */
++final
++public class BlockAccessMapped extends BlockAccessBase
++{
++ /* Blocks are addressed by positive ints -
++ * Is that a limit?
++ * One billion is 2^30
++ * If a block is 8K, the 2^31*2^13 = 2^44 bits or 2^14 billion = 16K Billion. = 16 trillion bytes.
++ * No limit at the moment - later performance tuning will see what the cost of 48 or 63 bit addresses would be.
++ */
++
++ private static Logger log = LoggerFactory.getLogger(BlockAccessMapped.class) ;
++ private enum CopyContents { Overwrite, NoCopy }
++
++ // Segmentation avoids over-mapping; allows file to grow (in chunks)
++ private final int GrowthFactor = 2 ;
++ private final int SegmentSize = SystemIndex.SegmentSize ;
++ private final int blocksPerSegment ;
++
++ private int initialNumSegements = 1 ;
++ private MappedByteBuffer[] segments = new MappedByteBuffer[initialNumSegements] ;
++
++ // Unflushed segments.
++ private int segmentDirtyCount = 0 ;
++ private boolean[] segmentDirty = new boolean[initialNumSegements] ;
++
++ public BlockAccessMapped(String filename, int blockSize) {
++ super(filename, blockSize) ;
++ blocksPerSegment = SegmentSize/blockSize ;
++ if ( SegmentSize%blockSize != 0 )
++ getLog().warn(format("%s: Segment size(%d) not a multiple of blocksize (%d)", filename, SegmentSize, blockSize)) ;
++
++ for ( int i = 0 ; i < initialNumSegements ; i++ )
++ // Not strictly necessary - default value is false.
++ segmentDirty[i] = false ;
++ segmentDirtyCount = 0 ;
++
++ if ( getLog().isDebugEnabled() )
++ getLog().debug(format("Segment:%d BlockSize=%d blocksPerSegment=%d", SegmentSize, blockSize, blocksPerSegment)) ;
++ }
++
++
++ @Override
++ public Block allocate(int blkSize) {
++ if ( blkSize > 0 && blkSize != this.blockSize )
++ throw new FileException("Fixed blocksize only: request= "+blkSize+"fixed size="+this.blockSize) ;
++ int id = allocateId() ;
++ ByteBuffer bb = getByteBuffer(id) ;
++ bb.position(0) ;
++ Block block = new Block(id, bb) ;
++ return block ;
++ }
++
++ @Override
++ public Block read(long id) {
++ check(id) ;
++ checkIfClosed() ;
++ ByteBuffer bb = getByteBuffer(id) ;
++ bb.position(0) ;
++ Block block = new Block(id, bb) ;
++ return block ;
++ }
++
++ @Override
++ public void write(Block block) {
++ write(block, CopyContents.NoCopy) ;
++ }
++
++ @Override
++ public void overwrite(Block block) {
++ overwriteNotification(block) ;
++ write(block, CopyContents.Overwrite) ;
++ }
++
++ private void write(Block block, CopyContents copyContents) {
++ check(block) ;
++ checkIfClosed() ;
++ int id = block.getId().intValue() ;
++
++ if ( copyContents == CopyContents.Overwrite ) {
++ ByteBuffer bbDst = getByteBuffer(id) ;
++ bbDst.position(0) ;
++ ByteBuffer bbSrc = block.getByteBuffer() ;
++ bbSrc.rewind() ;
++ bbDst.put(bbSrc) ;
++ }
++
++ // Assumed MRSW - no need to sync as we are the only Writer
++ segmentDirty[segment(id)] = true ;
++ writeNotification(block) ;
++ }
++
++ @Override
++ public void sync() {
++ checkIfClosed() ;
++ force() ;
++ }
++
++ private ByteBuffer getByteBuffer(long _id) {
++ // Limitation: ids must be integers.
++ // ids are used to index into []-arrays.
++ int id = (int)_id ;
++
++ int seg = segment(id) ; // Segment.
++ int segOff = byteOffset(id) ; // Byte offset in segment
++
++ if ( getLog().isTraceEnabled() )
++ getLog().trace(format("%d => [%d, %d]", id, seg, segOff)) ;
++
++ synchronized (this) {
++ try {
++ // Need to put the alloc AND the slice/reset inside a sync.
++ ByteBuffer segBuffer = allocSegment(seg) ;
++ // Now slice the buffer to get the ByteBuffer to return
++ segBuffer.position(segOff) ;
++ segBuffer.limit(segOff+blockSize) ;
++ ByteBuffer dst = segBuffer.slice() ;
++
++ // And then reset limit to max for segment.
++ segBuffer.limit(segBuffer.capacity()) ;
++ // Extend block count when we allocate above end.
++ numFileBlocks = Math.max(numFileBlocks, id+1) ;
++ return dst ;
++ } catch (IllegalArgumentException ex) {
++ // Shouldn't (ha!) happen because the second "limit" resets
++ log.error("Id: "+id) ;
++ log.error("Seg="+seg) ;
++ log.error("Segoff="+segOff) ;
++ log.error(ex.getMessage(), ex) ;
++ throw ex ;
++ }
++ }
++ }
++
++ private final int segment(int id) { return id/blocksPerSegment ; }
++ private final int byteOffset(int id) { return (id%blocksPerSegment)*blockSize ; }
++ private final long fileLocationForSegment(long segmentNumber) { return segmentNumber*SegmentSize ; }
++
++ // Even for MultipleReader this needs to be sync'ed.??
++ private MappedByteBuffer allocSegment(int seg)
++ {
++ // Auxiliary function for get - which holds the lock needed here.
++ // The MappedByteBuffer must be sliced and reset once found/allocated
++ // so as not to mess up the underlying MappedByteBuffer in segments[].
++
++ // Only allocSegment(seg) and flushDirtySegements() and close()
++ // directly access segments[]
++
++ if ( seg < 0 ) {
++ getLog().error("Segment negative: "+seg) ;
++ throw new FileException("Negative segment: "+seg) ;
++ }
++
++ while ( seg >= segments.length ) {
++ // More space needed.
++ MappedByteBuffer[] segments2 = new MappedByteBuffer[GrowthFactor*segments.length] ;
++ System.arraycopy(segments, 0, segments2, 0, segments.length) ;
++ boolean[] segmentDirty2 = new boolean[GrowthFactor*segmentDirty.length] ;
++ System.arraycopy(segmentDirty, 0, segmentDirty2, 0, segmentDirty.length) ;
++
++ segmentDirty = segmentDirty2 ;
++ segments = segments2 ;
++ }
++
++ long offset = fileLocationForSegment(seg) ;
++
++ if ( offset < 0 ) {
++ getLog().error("Segment offset gone negative: "+seg) ;
++ throw new FileException("Negative segment offset: "+seg) ;
++ }
++
++ MappedByteBuffer segBuffer = segments[seg] ;
++ if ( segBuffer == null ) {
++ try {
++ segBuffer = file.map(MapMode.READ_WRITE, offset, SegmentSize) ;
++ if ( getLog().isDebugEnabled() )
++ getLog().debug(format("Segment: %d", seg)) ;
++ segments[seg] = segBuffer ;
++ }
++ catch (IOException ex) {
++ if ( ex.getCause() instanceof java.lang.OutOfMemoryError )
++ throw new FileException("BlockMgrMapped.segmentAllocate: Segment = " + seg + " : Offset = " + offset) ;
++ throw new FileException("BlockMgrMapped.segmentAllocate: Segment = " + seg, ex) ;
++ }
++ }
++ return segBuffer ;
++ }
++
++ private synchronized void flushDirtySegments() {
++
++ // A linked list (with uniqueness) of dirty segments may be better.
++ for ( int i = 0 ; i < segments.length ; i++ ) {
++ if ( segments[i] != null && segmentDirty[i] ) {
++ // Can we "flush" them all at once?
++ segments[i].force() ;
++ segmentDirty[i] = false ;
++ segmentDirtyCount-- ;
++ }
++ }
++ // This on its own does not force dirty segments to disk.
++ super.force() ;
++ }
++
++ @Override
++ protected void _resetAllocBoundary(long boundary) {
++
++ }
++
++
++ @Override
++ protected void _close() {
++ force() ;
++ // There is no unmap operation for MappedByteBuffers.
++ // Sun Bug id bug_id=4724038
++ // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4724038
++ Arrays.fill(segments, null) ;
++ Arrays.fill(segmentDirty, false) ;
++ segmentDirtyCount = 0 ;
++ }
++
++ @Override
++ protected void force() {
++ flushDirtySegments() ;
++ }
++
++ @Override
++ protected Logger getLog() {
++ return log ;
++ }
++
++ @Override
++ public String toString() {
++ return super.getLabel() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccessMem.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccessMem.java
index 0000000,0000000..c2159f2
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BlockAccessMem.java
@@@ -1,0 -1,0 +1,188 @@@
++/*
++ * 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.dboe.base.file;
++
++import static java.lang.String.format ;
++
++import java.nio.ByteBuffer ;
++import java.util.ArrayList ;
++import java.util.List ;
++
++import org.apache.jena.atlas.RuntimeIOException ;
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.sys.Sys;
++
++/**
++ * File access layer that simulates a disk in-memory - for testing, not written for efficiency.
++ * There is a safe mode, whereby blocks are copied in and out to guarantee no writing to an unallocated block.
++ * This is very inefficient but a better simulation of a disk.
++ *
++ * @see BlockAccessByteArray
++ */
++
++public class BlockAccessMem implements BlockAccess
++{
++ // "SafeMode" - duplicate the block data much like a disk.
++ // Mildly expensive for large block sizes.
++
++ public static boolean SafeMode = true ;
++ static final boolean Checking = true ;
++ boolean fileClosed = false ;
++ private List<Block> blocks = new ArrayList<>() ;
++ private final boolean safeModeThisMgr ;
++ protected final int blockSize ;
++ private final String label ;
++
++ public BlockAccessMem(String label, int blockSize) {
++ this(label, blockSize, SafeMode) ;
++ }
++
++ private BlockAccessMem(String label, int blockSize, boolean b) {
++ this.blockSize = blockSize ;
++ this.label = label ;
++ safeModeThisMgr = b ;
++ }
++
++ @Override
++ public Block allocate(int blkSize) {
++ checkNotClosed() ;
++ if ( blkSize > 0 && blkSize != this.blockSize )
++ throw new FileException("Fixed blocksize only: request= " + blkSize + " / fixed size=" + this.blockSize) ;
++
++ int x = blocks.size() ;
++ ByteBuffer bb = ByteBuffer.allocate(blkSize) ;
++ Block block = new Block(x, bb) ;
++ blocks.add(block) ;
++ return block ;
++ }
++
++ @Override
++ public Block read(long id) {
++ checkNotClosed() ;
++ check(id) ;
++ Block blk = blocks.get((int)id) ;
++ blk = replicateBlock(blk) ;
++ blk.setModified(false) ;
++ return blk ;
++ }
++
++ @Override
++ public void write(Block block) {
++ checkNotClosed() ;
++ check(block) ;
++ _write(block) ;
++ }
++
++ @Override
++ public void overwrite(Block block) {
++ checkNotClosed() ;
++ write(block) ;
++ }
++
++ private void _write(Block block) {
++ block = replicateBlock(block) ;
++ block.setModified(false) ;
++ // Memory isn't scaling to multi gigabytes.
++ blocks.set(block.getId().intValue(), block) ;
++ }
++
++ private Block replicateBlock(Block blk) {
++ if ( safeModeThisMgr )
++ // Deep replicate.
++ return blk.replicate() ;
++ // Just the block wrapper.
++ return new Block(blk.getId(), blk.getByteBuffer()) ;
++ }
++
++ @Override
++ public boolean isEmpty() {
++ checkNotClosed() ;
++ return blocks.isEmpty() ;
++ }
++
++ @Override
++ public long allocBoundary() {
++ checkNotClosed() ;
++ return blocks.size() ;
++ }
++
++ @Override
++ public void resetAllocBoundary(long boundary) {
++ checkNotClosed() ;
++ // Clear the list from boundary onwards.
++ blocks.subList((int)boundary, blocks.size()).clear() ;
++ }
++
++ @Override
++ public boolean valid(long id) {
++ checkNotClosed() ;
++ return id >= 0 && id < blocks.size() ;
++ }
++
++ private void checkNotClosed() {
++ if ( fileClosed )
++ throw new RuntimeIOException("Already closed") ;
++ }
++
++ @Override
++ public void close() {
++ if ( fileClosed )
++ return ;
++ fileClosed = true ;
++ blocks = null ;
++ }
++
++ @Override
++ public void sync() {
++ checkNotClosed() ;
++ }
++
++
++ private void check(Block block) {
++ check(block.getId()) ;
++ check(block.getByteBuffer()) ;
++ }
++
++ private void check(long id) {
++ if ( id > Integer.MAX_VALUE )
++ throw new FileException("BlockAccessMem: Bounds exception (id large than an int): " + id) ;
++ if ( !Checking )
++ return ;
++ if ( id < 0 || id >= blocks.size() )
++ throw new FileException("BlockAccessMem: "+label+": Bounds exception: " + id + " in [0, "+blocks.size()+")") ;
++ }
++
++ private void check(ByteBuffer bb) {
++ if ( !Checking )
++ return ;
++ if ( bb.capacity() != blockSize )
++ throw new FileException(format("FileAccessMem: Wrong size block. Expected=%d : actual=%d", blockSize, bb.capacity())) ;
++ if ( bb.order() != Sys.NetworkOrder )
++ throw new FileException("BlockMgrMem: Wrong byte order") ;
++ }
++
++ @Override
++ public String getLabel() {
++ return label ;
++ }
++
++ @Override
++ public String toString() {
++ return "Mem:" + label ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BufferChannel.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BufferChannel.java
index 0000000,0000000..9858181
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BufferChannel.java
@@@ -1,0 -1,0 +1,95 @@@
++/*
++ * 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.dboe.base.file;
++
++import java.nio.ByteBuffer ;
++import java.nio.channels.FileChannel ;
++
++import org.apache.jena.atlas.lib.Closeable ;
++import org.apache.jena.atlas.lib.Sync ;
++
++
++/**
++ * Interface to storage : a simplified version of FileChannel. Read and write
++ * bytes, passed via ByteBuffers, addressed by file location. This interface is
++ * not suitable for memory mapped I/O - there is no ability to use slices of a
++ * memort mapped file. This interface does not insert size of ByteBuffer - size
++ * of ByteBuffer passed to read controls the number of bytes read. Having our
++ * own abstraction enables us to implement memory-backed versions.
++ *
++ * @see BlockAccess
++ * @see java.nio.channels.FileChannel
++ */
++public interface BufferChannel extends Sync, Closeable
++{
++ // Like java.nio.channels.FileChannel except
++ // Allows implementation by non-files e.g. a memory backed storage.
++ // Runtime exceptions.
++ // This is a simple, low level "file = array of bytes" interface"
++ // This interface does not support slicing - so it's not suitable for memory mapped I/O
++ //
++ // TODO Consider use of allocateDirect
++
++ /** Return another channel to the same storage but with independent position.
++ * Chaos may result due to concurrent use.
++ */
++ public BufferChannel duplicate() ;
++
++ /** return the position */
++ public long position() ;
++
++ /** set the position */
++ public void position(long pos) ;
++
++ /** Read into a ByteBuffer. Returns the number of bytes read. -1 for end of file.
++ */
++ public int read(ByteBuffer buffer) ;
++
++ /** Read into a ByteBuffer, starting at position loc. Return the number of bytes read.
++ * loc must be within the file.
++ */
++ public int read(ByteBuffer buffer, long loc) ;
++
++ /** Write from ByteBuffer, starting at the current position.
++ * Return the number of bytes written
++ */
++ public int write(ByteBuffer buffer) ;
++
++ /** Write from ByteBuffer, starting at position loc.
++ * Return the number of bytes written.
++ * loc must be within 0 to length - writing at length is append */
++ public int write(ByteBuffer buffer, long loc) ;
++
++ /** Truncate the file.
++ * @see FileChannel#truncate(long)
++ */
++ public void truncate(long size) ;
++
++ /** Length of storage, in bytes.*/
++ public long size() ;
++
++ /** Is it empty? */
++ public boolean isEmpty() ;
++
++ /** useful display string */
++ public String getLabel() ;
++
++ /** Filename for this BufferChannel (maybe null) */
++ public String getFilename() ;
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BufferChannelFile.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BufferChannelFile.java
index 0000000,0000000..216bff2
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BufferChannelFile.java
@@@ -1,0 -1,0 +1,171 @@@
++/*
++ * 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.dboe.base.file ;
++
++import java.io.IOException ;
++import java.nio.ByteBuffer ;
++import java.nio.channels.FileChannel ;
++
++import org.apache.jena.atlas.io.IO ;
++import org.seaborne.dboe.sys.FileLib ;
++
++public class BufferChannelFile implements BufferChannel {
++ private String filename ;
++ private FileChannel file ;
++
++ /** Create a BufferChannelFile */
++ public static BufferChannelFile create(String filename) {
++ return create(filename, "rw") ;
++ }
++
++ /** Create a BufferChannelFile */
++ public static BufferChannelFile create(String filename, String mode) {
++ FileChannel base = ChannelManager.acquire(filename, mode) ;
++ return new BufferChannelFile(filename, base) ;
++ }
++
++ /** Create a BufferChannelFile with unmangaged file resources - use with care */
++ public static BufferChannelFile createUnmanaged(String filename, String mode) {
++ FileChannel channel = FileLib.openUnmanaged(filename, mode) ;
++ return new BufferChannelFile(filename, channel) ;
++ }
++
++ private BufferChannelFile(String filename, FileChannel channel) {
++ this.filename = filename ;
++ this.file = channel ;
++ }
++
++ @Override
++ public BufferChannel duplicate() {
++ return new BufferChannelFile(filename, file) ;
++ }
++
++ @Override
++ public long position() {
++ try {
++ return file.position() ;
++ }
++ catch (IOException e) {
++ IO.exception(e) ;
++ return -1 ;
++ }
++ }
++
++ @Override
++ public void position(long pos) {
++ try {
++ file.position(pos) ;
++ }
++ catch (IOException e) {
++ IO.exception(e) ;
++ }
++ }
++
++ @Override
++ public void truncate(long length) {
++ try {
++ // http://bugs.sun.com/view_bug.do?bug_id=6191269
++ if ( length < file.position() )
++ file.position(length) ;
++ file.truncate(length) ;
++ }
++ catch (IOException e) {
++ IO.exception(e) ;
++ }
++ }
++
++ @Override
++ public int read(ByteBuffer buffer) {
++ try {
++ return file.read(buffer) ;
++ }
++ catch (IOException e) {
++ IO.exception(e) ;
++ return -1 ;
++ }
++ }
++
++ @Override
++ public int read(ByteBuffer buffer, long loc) {
++ try {
++ return file.read(buffer, loc) ;
++ }
++ catch (IOException e) {
++ IO.exception(e) ;
++ return -1 ;
++ }
++ }
++
++ @Override
++ public int write(ByteBuffer buffer) {
++ try {
++ return file.write(buffer) ;
++ }
++ catch (IOException e) {
++ IO.exception(e) ;
++ return -1 ;
++ }
++ }
++
++ @Override
++ public int write(ByteBuffer buffer, long loc) {
++ try {
++ return file.write(buffer, loc) ;
++ }
++ catch (IOException e) {
++ IO.exception(e) ;
++ return -1 ;
++ }
++ }
++
++ @Override
++ public long size() {
++ return FileLib.size(file) ;
++ }
++
++ @Override
++ public boolean isEmpty() {
++ return size() == 0 ;
++ }
++
++ @Override
++ public void sync() {
++ FileLib.sync(file) ;
++ }
++
++ @Override
++ public void close() {
++ FileLib.close(file) ;
++ }
++
++ @Override
++ public String getLabel() {
++ return filename ;
++ }
++
++ @Override
++ public String toString() {
++ return filename ;
++ }
++
++ @Override
++ public String getFilename() {
++ return filename ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BufferChannelMem.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BufferChannelMem.java
index 0000000,0000000..ea3c6ba
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/BufferChannelMem.java
@@@ -1,0 -1,0 +1,240 @@@
++/*
++ * 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.dboe.base.file ;
++
++import java.nio.ByteBuffer ;
++
++import org.apache.jena.atlas.lib.ByteBufferLib ;
++import org.apache.jena.atlas.logging.FmtLog ;
++import org.seaborne.dboe.base.StorageException ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++// XXX Merge/replace with SegmentedByteBuffer which has more predicable performance.
++public class BufferChannelMem implements BufferChannel {
++ private static Logger log = LoggerFactory.getLogger(BufferChannelMem.class) ;
++ // The "file pointer" is the position of this buffer.
++ // The "size" is the limit of this buffer.
++ private ByteBuffer bytes ;
++ private String name ;
++ private static int INC_SIZE = 1024 ;
++
++ private final boolean TRACKING ;
++
++ static public BufferChannel create() {
++ return new BufferChannelMem("unnamed") ;
++ }
++
++ static public BufferChannel create(String name) {
++ return new BufferChannelMem(name) ;
++ }
++
++ private BufferChannelMem() {
++ // Unitialized blank.
++ TRACKING = false ;
++ }
++
++ private BufferChannelMem(String name) {
++ bytes = ByteBuffer.allocate(1024) ;
++ bytes.limit(0) ;
++ this.name = name ;
++ TRACKING = false ;
++ // Debugging : pick a filename.
++ // TRACKING = name.endsWith("prefixes.dat") ;
++ }
++
++ @Override
++ synchronized public BufferChannel duplicate() {
++ BufferChannelMem chan = new BufferChannelMem() ;
++ int x = bytes.position() ;
++ bytes.rewind() ;
++ chan.bytes = bytes.slice() ;
++ chan.bytes.position(0) ;
++ bytes.position(x) ;
++ return chan ;
++ }
++
++ @Override
++ synchronized public long position() {
++ checkIfClosed() ;
++ return bytes.position() ;
++ }
++
++ @Override
++ synchronized public void position(long pos) {
++ checkIfClosed() ;
++ if ( pos < 0 || pos > bytes.capacity() )
++ throw new StorageException("Out of range: " + pos) ;
++ bytes.position((int)pos) ;
++ }
++
++ @Override
++ synchronized public int read(ByteBuffer buffer) {
++ checkIfClosed() ;
++ if ( TRACKING )
++ log("read<<%s", ByteBufferLib.details(buffer));
++
++ int x = bytes.position() ;
++
++ int len = buffer.limit() - buffer.position() ;
++ if ( len > bytes.remaining() )
++ len = bytes.remaining() ;
++ // Copy out, moving the position of the bytes of stroage.
++ for (int i = 0; i < len; i++) {
++ byte b = bytes.get() ;
++ buffer.put(b) ;
++ }
++ if ( TRACKING )
++ log("read>>") ;
++ return len ;
++ }
++
++ @Override
++ synchronized public int read(ByteBuffer buffer, long loc) {
++ checkIfClosed() ;
++ if ( TRACKING )
++ log("read<<@%d", loc) ;
++ if ( loc < 0 || loc > bytes.limit() )
++ throw new StorageException("Out of range(" + name + "[read]): " + loc + " [0," + bytes.limit() + ")") ;
++ if ( loc == bytes.limit() )
++ log.warn("At the limit(" + name + "[read]): " + loc) ;
++ int x = bytes.position() ;
++ bytes.position((int)loc) ;
++ int len = read(buffer) ;
++ bytes.position(x) ;
++ if ( TRACKING )
++ log("read>>@%d",loc) ;
++ return len ;
++ }
++
++ @Override
++ synchronized public int write(ByteBuffer buffer) {
++ checkIfClosed() ;
++ if ( TRACKING )
++ log("write<<%s", ByteBufferLib.details(buffer));
++ int len = buffer.limit() - buffer.position() ;
++ int posn = bytes.position() ;
++
++ int freespace = bytes.capacity() - bytes.position() ;
++
++ if ( len > freespace ) {
++ int inc = len - freespace ;
++ inc += INC_SIZE ;
++ ByteBuffer bb2 = ByteBuffer.allocate(bytes.capacity() + inc) ;
++ bytes.position(0) ;
++ // Copy contents; make written bytes area the same as before.
++ bb2.put(bytes) ;
++ bb2.limit(bytes.limit()) ; // limit is used as the end of active
++ // bytes.
++ bb2.position(posn) ;
++ bytes = bb2 ;
++ }
++
++ if ( bytes.limit() < posn + len )
++ bytes.limit(posn + len) ;
++
++ bytes.put(buffer) ;
++
++ if ( TRACKING )
++ log("write>>") ;
++ return len ;
++ }
++
++ // Invert : write(ByteBuffer) = write(ByteBuffer,posn)
++ @Override
++ synchronized public int write(ByteBuffer buffer, long loc) {
++ checkIfClosed() ;
++ if ( TRACKING )
++ log("write<<@%d", loc) ;
++ if ( loc < 0 || loc > bytes.limit() )
++ // Can write at loc = bytes()
++ throw new StorageException("Out of range(" + name + "[write]): " + loc + " [0," + bytes.limit() + ")") ;
++ int x = bytes.position() ;
++ bytes.position((int)loc) ;
++ int len = write(buffer) ;
++ bytes.position(x) ;
++ if ( TRACKING )
++ log("write>>@%d", loc) ;
++ return len ;
++ }
++
++ @Override
++ synchronized public void truncate(long size) {
++ checkIfClosed() ;
++ if ( TRACKING )
++ log("truncate(%d)", size) ;
++ int x = (int)size ;
++ if ( x < 0 )
++ throw new StorageException("Out of range: " + size) ;
++ if ( x > bytes.limit() )
++ return ;
++
++ if ( bytes.position() > x )
++ bytes.position(x) ;
++ bytes.limit(x) ;
++ }
++
++ @Override
++ synchronized public long size() {
++ checkIfClosed() ;
++ return bytes.limit() ;
++ }
++
++ @Override
++ synchronized public boolean isEmpty() {
++ checkIfClosed() ;
++ return size() == 0 ;
++ }
++
++ @Override
++ synchronized public void sync() {
++ checkIfClosed() ;
++ }
++
++ @Override
++ synchronized public void close() {
++ if ( bytes == null )
++ return ;
++ bytes = null ;
++ }
++
++ private void checkIfClosed() {
++ if ( bytes == null )
++ throw new StorageException("Closed: " + name) ;
++ }
++
++ @Override
++ synchronized public String getLabel() {
++ return name ;
++ }
++
++ @Override
++ synchronized public String toString() {
++ return name ;
++ }
++
++ @Override
++ public String getFilename() {
++ return null ;
++ }
++
++ private void log(String fmt, Object... args) {
++ if ( TRACKING )
++ FmtLog.debug(log, fmt, args);
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/ChannelManager.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/ChannelManager.java
index 0000000,0000000..7b1d041
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/ChannelManager.java
@@@ -1,0 -1,0 +1,114 @@@
++/*
++ * 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.dboe.base.file;
++
++import java.io.IOException ;
++import java.io.RandomAccessFile ;
++import java.nio.channels.FileChannel ;
++import java.util.ArrayList ;
++import java.util.HashMap ;
++import java.util.List ;
++import java.util.Map ;
++
++public class ChannelManager
++{
++ // Make per "location"?
++
++ // Because "FileManager" is already in use
++ // ChannelManager
++
++ // FileBase ==> OpenFileRef, ChannelRef
++
++ public static FileChannel acquire(String filename) {
++ return acquire(filename, "rw") ;
++ }
++
++ public static FileChannel acquire(String filename, String mode) {
++ return openref$(filename, mode) ;
++ }
++
++ static private Map<String, FileChannel> name2channel = new HashMap<>() ;
++ static private Map<FileChannel, String> channel2name = new HashMap<>() ;
++
++ private static FileChannel openref$(String filename, String mode) {
++ // Temp - for now, only journal files are tracked.
++ if ( !filename.endsWith(".jrnl") ) {
++ return open$(filename, mode) ;
++ }
++
++ FileChannel chan = name2channel.get(filename) ;
++ if ( chan != null ) {
++ // Scream - it's currently open.
++ throw new FileException("Already open: " + filename) ;
++ }
++ chan = open$(filename, mode) ;
++ name2channel.put(filename, chan) ;
++ channel2name.put(chan, filename) ;
++ return chan ;
++ }
++
++ private static FileChannel open$(String filename, String mode) {
++ try {
++ // "rwd" - Syncs only the file contents
++ // "rws" - Syncs the file contents and metadata
++ // "rw" - OS write behind possible
++ // "r" - read only
++ @SuppressWarnings("resource")
++ RandomAccessFile out = new RandomAccessFile(filename, mode) ;
++ FileChannel channel = out.getChannel() ;
++ return channel ;
++ } catch (IOException ex) { throw new FileException("Failed to open: "+filename+" (mode="+mode+")", ex) ; }
++ }
++
++ public static void release(String filename) {
++ FileChannel channel = name2channel.get(filename) ;
++ if ( channel != null )
++ release(channel) ;
++ }
++
++ public static void release(FileChannel chan) {
++ // Always close even if not managed.
++ try {
++ chan.close() ;
++ }
++ catch (Exception ex) {}
++ String name = channel2name.remove(chan) ;
++ if ( name != null )
++ name2channel.remove(name) ;
++ }
++
++ public static void reset() {
++ releaseAll(null) ;
++ }
++
++ /** Shutdown all the files matching the prefix (typically a directory) */
++ public static void releaseAll(String prefix) {
++ // Use an iterator explicitly so we can remove from the map.
++ List<FileChannel> x = new ArrayList<>() ;
++ for ( String fn : name2channel.keySet() ) {
++ if ( prefix == null || fn.startsWith(prefix) ) {
++ x.add(name2channel.get(fn)) ;
++ // Don't call release here - potential CME problems.
++ // Could use an explicit iterator on teh keySet and .remove from that but
++ // then we nearly duplicate the code in release.
++ }
++ }
++ for ( FileChannel chan : x )
++ release(chan) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/FileException.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/FileException.java
index 0000000,0000000..5174033
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/FileException.java
@@@ -1,0 -1,0 +1,28 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.seaborne.dboe.DBOpEnvException ;
++
++public class FileException extends DBOpEnvException
++{
++ public FileException() { super() ; }
++ public FileException(String msg) { super(msg) ; }
++ public FileException(Throwable th) { super(th) ; }
++ public FileException(String msg, Throwable th) { super(msg, th) ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/FileFactory.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/FileFactory.java
index 0000000,0000000..ebdc1e4
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/FileFactory.java
@@@ -1,0 -1,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.dboe.base.file ;
++
++public class FileFactory {
++
++ public static BinaryDataFile createBinaryDataFile(FileSet fileset, String ext) {
++ String x = fileset.filename(ext) ;
++ if ( fileset.isMem() ) {
++ return new BinaryDataFileMem() ;
++ } else {
++ BinaryDataFile bdf = new BinaryDataFileRandomAccess(x) ;
++ bdf = new BinaryDataFileWriteBuffered(bdf) ;
++ return bdf ;
++ }
++ }
++
++ public static BinaryDataFile createBinaryDataFile() {
++ return new BinaryDataFileMem() ;
++ }
++
++ public static BufferChannel createBufferChannel(FileSet fileset, String ext) {
++ String x = fileset.filename(ext) ;
++ if ( fileset.isMem() )
++ return BufferChannelMem.create(x) ;
++ else
++ return BufferChannelFile.create(x) ;
++ }
++
++ public static BufferChannel createBufferChannelMem() {
++ return createBufferChannel(FileSet.mem(), null) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/FileSet.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/FileSet.java
index 0000000,0000000..f04e42d
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/FileSet.java
@@@ -1,0 -1,0 +1,115 @@@
++/*
++ * 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.dboe.base.file ;
++
++import java.io.File ;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/**
++ * Naming metadata management to a collection of related files (same directory,
++ * same basename within directory, various extensions).
++ */
++public class FileSet {
++ // Cope with "in-memory" fileset (location == null)
++
++ private static Logger log = LoggerFactory.getLogger(FileSet.class) ;
++
++ private Location location ;
++ private String basename ;
++
++ /** FileSet for "in-memory" */
++ public static FileSet mem() {
++ FileSet fs = new FileSet(Location.mem(), "mem") ;
++ return fs ;
++ }
++
++ // private FileSet() {} // Uninitialized.
++
++ /**
++ * Create a FileSet given Location (directory) and name within the directory
++ */
++ public FileSet(String directory, String basename) {
++ initFileSet(Location.create(directory), basename) ;
++ }
++
++ /**
++ * Create a FileSet given Location (directory) and name within the directory
++ */
++ public FileSet(String filename) {
++ Tuple<String> t = FileOps.splitDirFile(filename) ;
++ String dir = t.get(0) ;
++ String fn = t.get(1) ;
++ if ( dir == null )
++ dir = "." ;
++ initFileSet(Location.create(dir), fn) ;
++ }
++
++ /**
++ * Create a FileSet given Location (directory) and name within the directory
++ */
++ public FileSet(Location directory, String basename) {
++ initFileSet(directory, basename) ;
++ }
++
++ private void initFileSet(Location directory, String basename) {
++ // Default - don't use the locations metadata
++ initFileSet(directory, basename, false) ;
++ }
++
++ private void initFileSet(Location directory, String basename, boolean useLocationMetadata) {
++ this.location = directory ;
++ this.basename = basename ;
++ }
++
++ public Location getLocation() {
++ return location ;
++ }
++
++ public String getBasename() {
++ return basename ;
++ }
++
++ // public MetaFile getMetaFile() { return metafile ; }
++
++ public boolean isMem() {
++ return location.isMem() ;
++ }
++
++ public boolean exists(String ext) {
++ if ( location.isMem() )
++ return true ;
++ String fn = filename(ext) ;
++ File f = new File(fn) ;
++ if ( f.isDirectory() )
++ log.warn("File clashes with a directory") ;
++ return f.exists() && f.isFile() ;
++ }
++
++ @Override
++ public String toString() {
++ return "FileSet:" + filename(null) ;
++ }
++
++ public String filename(String ext) {
++ return location.getPath(basename, ext) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/Location.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/Location.java
index 0000000,0000000..9fbba55
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/Location.java
@@@ -1,0 -1,0 +1,264 @@@
++/*
++ * 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.dboe.base.file ;
++
++import java.io.File ;
++import java.io.IOException ;
++import java.nio.file.Path;
++import java.util.Objects ;
++
++import org.seaborne.dboe.sys.Names ;
++
++/**
++ * Wrapper for a file system directory; can create filenames in that directory.
++ * Enforces some simple consistency policies and provides a "typed string" for a
++ * filename to reduce errors.
++ */
++
++public class Location {
++ static String pathSeparator = File.separator ; // Or just "/"
++
++ private static String memNamePath = Names.memName+pathSeparator ;
++
++ private String pathname ;
++ private MetaFile metafile = null ;
++ private boolean isMem = false ;
++ private boolean isMemUnique = false ;
++
++ static int memoryCount = 0 ;
++
++ /**
++ * Return a fresh memory location : always unique, never .equals to another
++ * location.
++ */
++ static public Location mem() {
++ return mem(null) ;
++ }
++
++ /** Return a memory location with a name */
++ static public Location mem(String name) {
++ Location loc = new Location() ;
++ memInit(loc, name) ;
++ return loc ;
++ }
++
++ /** Return a location for a directory on disk */
++ static public Location create(String directoryName) {
++ if ( directoryName == null )
++ // Fresh, anonymous, memory area
++ return mem() ;
++ Location loc = new Location(directoryName) ;
++ return loc ;
++ }
++
++ /** Return a location for a directory on disk */
++ static public Location create(Path directoryName) {
++ if ( directoryName == null )
++ // Fresh, anonymous, memory area
++ return mem() ;
++ Location loc = new Location(directoryName.toString()) ;
++ return loc ;
++ }
++
++ private Location() {}
++
++ private static void memInit(Location location, String name) {
++ location.pathname = Names.memName ;
++ if ( name != null ) {
++ name = name.replace('\\', '/') ;
++ location.pathname = location.pathname + '/' + name ;
++ } else
++ location.isMemUnique = true ;
++ if ( !location.pathname.endsWith(pathSeparator) )
++ location.pathname = location.pathname + '/' ;
++ location.isMem = true ;
++ location.metafile = new MetaFile(Names.memName, Names.memName) ;
++ }
++
++ private Location(String rootname) {
++ super() ;
++ if ( rootname.equals(Names.memName) ) {
++ memInit(this, null) ;
++ return ;
++ }
++ if ( rootname.startsWith(memNamePath) ) {
++ String name = rootname.substring(memNamePath.length()) ;
++ memInit(this, name) ;
++ return ;
++ }
++
++ ensure(rootname) ;
++ pathname = fixupName(rootname) ;
++ // Metafilename for a directory.
++ String metafileName = getPath(Names.directoryMetafile, Names.extMeta) ;
++
++ metafile = new MetaFile("Location: " + rootname, metafileName) ;
++ }
++
++ // MS Windows:
++ // getCanonicalPath is only good enough for existing files.
++ // It leaves the case as it finds it (upper, lower) and lower cases
++ // not-existing segments. But later creation of a segment with uppercase
++ // changes the exact string returned.
++ private String fixupName(String fsName) {
++ if ( isMem() )
++ return fsName ;
++ File file = new File(fsName) ;
++ try {
++ fsName = file.getCanonicalPath() ;
++ } catch (IOException ex) {
++ throw new FileException("Failed to get canoncial path: " + file.getAbsolutePath(), ex) ;
++ }
++
++ if ( !fsName.endsWith(File.separator) && !fsName.endsWith(pathSeparator) )
++ fsName = fsName + pathSeparator ;
++ return fsName ;
++ }
++
++ public String getDirectoryPath() {
++ return pathname ;
++ }
++
++ public MetaFile getMetaFile() {
++ return metafile ;
++ }
++
++ public boolean isMem() {
++ return isMem ;
++ }
++
++ public boolean isMemUnique() {
++ return isMemUnique ;
++ }
++
++ public Location getSubLocation(String dirname) {
++ String newName = pathname + dirname ;
++ ensure(newName) ;
++ return Location.create(newName) ;
++ }
++
++ private void ensure(String dirname) {
++ if ( isMem() )
++ return ;
++ File file = new File(dirname) ;
++ if ( file.exists() && !file.isDirectory() )
++ throw new FileException("Existing file: " + file.getAbsolutePath()) ;
++ if ( !file.exists() )
++ file.mkdir() ;
++ }
++
++ public String getSubDirectory(String dirname) {
++ return getSubLocation(dirname).getDirectoryPath() ;
++ }
++
++ /**
++ * Return an absolute filename where relative names are resolved from the
++ * location
++ */
++ public String absolute(String filename, String extension) {
++ return (extension == null) ? absolute(filename) : absolute(filename + "." + extension) ;
++ }
++
++ /**
++ * Return an absolute filename where relative names are resolved from the
++ * location
++ */
++ public String absolute(String filename) {
++ File f = new File(filename) ;
++ // Location relative.
++ if ( !f.isAbsolute() )
++ filename = pathname + filename ;
++ return filename ;
++ }
++
++ /** Does the location exist (and it a directory, and is accessible) */
++ public boolean exists() {
++ File f = new File(getDirectoryPath()) ;
++ return f.exists() && f.isDirectory() && f.canRead() ;
++ }
++
++ public boolean exists(String filename) {
++ return exists(filename, null) ;
++ }
++
++ public boolean exists(String filename, String ext) {
++ String fn = getPath(filename, ext) ;
++ File f = new File(fn) ;
++ return f.exists() ;
++ }
++
++ /** Return the name of the file relative to this location */
++ public String getPath(String filename) {
++ return getPath(filename, null) ;
++ }
++
++ /** Return the name of the file, and extension, relative to this location */
++ public String getPath(String filename, String ext) {
++ check(filename, ext) ;
++ if ( ext == null )
++ return pathname + filename ;
++ return pathname + filename + "." + ext ;
++ }
++
++ private void check(String filename, String ext) {
++ if ( filename == null )
++ throw new FileException("Location: null filename") ;
++ if ( filename.contains("/") || filename.contains("\\") )
++ throw new FileException("Illegal file component name: " + filename) ;
++ if ( filename.contains(".") && ext != null )
++ throw new FileException("Filename has an extension: " + filename) ;
++ if ( ext != null ) {
++ if ( ext.contains(".") )
++ throw new FileException("Extension has an extension: " + filename) ;
++ }
++ }
++
++ @Override
++ public int hashCode() {
++ final int prime = 31 ;
++ int result = isMem ? 1 : 2 ;
++ result = prime * result + ((pathname == null) ? 0 : pathname.hashCode()) ;
++ return result ;
++ }
++
++ @Override
++ public boolean equals(Object obj) {
++ if ( this == obj )
++ return true ;
++ if ( obj == null )
++ return false ;
++ if ( getClass() != obj.getClass() )
++ return false ;
++
++ Location other = (Location)obj ;
++ if ( isMem && !other.isMem )
++ return false ;
++ if ( !isMem && other.isMem )
++ return false ;
++ // Not == so ...
++ if ( isMemUnique )
++ return false ;
++
++ return Objects.equals(pathname, other.pathname) ;
++ }
++
++ @Override
++ public String toString() {
++ return "location:" + pathname ;
++ }
++}
[31/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/NodeId.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/NodeId.java
index 0000000,0000000..f2139d9
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/NodeId.java
@@@ -1,0 -1,0 +1,219 @@@
++/*
++ * 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 org.apache.jena.sparql.expr.Expr.CMP_EQUAL;
++import static org.seaborne.tdb2.store.NodeIdType.PTR;
++import static org.seaborne.tdb2.store.NodeIdType.*;
++
++import org.apache.jena.atlas.lib.BitsLong;
++import org.apache.jena.atlas.logging.FmtLog;
++import org.apache.jena.graph.Node;
++import org.seaborne.dboe.sys.Sys;
++import org.seaborne.tdb2.sys.SystemTDB;
++
++final
++public class NodeId implements Comparable<NodeId>
++{
++ public static final int SIZE = Sys.SizeOfLong ;
++
++ public static final NodeId NodeIdInvalid = makeSpecial(0xA1);
++ public static final NodeId NodeDoesNotExist = makeSpecial(0xA3);
++ public static final NodeId NodeIdAny = makeSpecial(0xA4);
++ public static final NodeId NodeIdDefined = makeSpecial(0xA5);
++ public static final NodeId NodeIdUndefined = makeSpecial(0xA6);
++
++ private static NodeId makeSpecial(long v) {
++ // Careful of an initialzer loop (create(type, v1, v2) looks at specials).
++ return NodeIdFactory.createValue(SPECIAL, v);
++ }
++
++ /*package*/ static final boolean enableInlineLiterals = SystemTDB.enableInlineLiterals;
++
++ // Internal consistency checks.
++ private static final boolean CHECKING = true;
++
++ // Code search:
++ // [64 bits]
++
++
++ // Encoding:
++ // 8 bits type, except PTR which is 0 high bit.
++ // 24 bits int
++ // 64 bit value
++ // The high byte of value1==type as integer value
++ // In-memory:
++ // Long:
++ // type PTR high bit zero, then 31+64 bits of value.
++ // Inlines:
++ // type is 8 bits
++ // value1 is 24 bits
++ // value2 is 64 bits
++ // type is a type and is OR'ed into value1 to store.
++ // Short: 64 bit:
++ // type PTR high bit zero, then 63 bits of value.
++ // Inlines:
++ // value1 is not used.
++ // value2 is 56 bits
++ // type is a type and is OR'ed into value2 to store.
++
++ final NodeIdType type;
++ final int value1;
++ final long value2;
++
++ private NodeId(NodeIdType type, int v1, long v2) {
++ if ( CHECKING ) check(type, v1, v2);
++ this.type = type;
++ value1 = v1; // Zero for 64 bit.
++ value2 = v2;
++ }
++
++ private final void check(NodeIdType type, int v1, long v2) {
++ if ( type == PTR )
++ return;
++ if ( type == SPECIAL )
++ return;
++ // 64 bit NodeId.
++ int x = ( type == XSD_DOUBLE )
++ ? (int)BitsLong.unpack(v2, 62, 64) // High two bits
++ : (int)BitsLong.unpack(v2, 56, 64); // else
++ if ( x != 0 )
++ FmtLog.warn(getClass(), "Type set in long: type=%s value=%016X", type, v2);
++ }
++
++ public boolean isPtr() { return type == PTR; }
++
++// public long getPtrLocation() { return value2; }
++// public long getPtrLo() { return value2; }
++// public int getPtrHi() { return value1 & 0x00FFFFFF; }
++
++ // 64 bit
++ public long getPtrLocation() { return value2; }
++ // Long.
++// public long getPtrLo() { return value2; }
++// public int getPtrHi() { return value1; }
++
++ public int getTypeValue() { return type.type(); }
++
++ public boolean isInline() {
++ return isInline(this);
++ }
++
++ public static boolean isInline(NodeId nodeId) {
++ return NodeIdType.isInline(nodeId.type);
++ }
++
++ public boolean isValue() {
++ return type != PTR && NodeIdType.isStorable(type);
++ }
++
++ // Migration
++ public static NodeId inline(Node node) { return NodeIdInline.inline(node); }
++ public static boolean hasInlineDatatype(Node node) { return NodeIdInline.hasInlineDatatype(node); }
++ public static Node extract(NodeId nodeId) { return NodeIdInline.extract(nodeId); }
++
++ // XXX Later.
++// //Static forms only?
++// public boolean isAny() { return isAny(this); }
++// public boolean isDoesNotExist() { return isDoesNotExist(this); }
++// public boolean isDefined() { return isDefined(this); }
++// public boolean isUndefined() { return isDefined(this); }
++//
++ public static final boolean isAny(NodeId nodeId) { return nodeId == NodeIdAny || nodeId == null; }
++ public static final boolean isDoesNotExist(NodeId nodeId) { return nodeId == NodeDoesNotExist; }
++// public static boolean isDefined(NodeId nodeId) { return nodeId == NodeIdDefined; }
++// public static boolean isUndefined(NodeId nodeId) { return nodeId == NodeIdUndefined; }
++
++ /** Create from a long-encoded value */
++ /*package*/ static NodeId createRaw(NodeIdType type, long value) {
++ return new NodeId(type, 0, value);
++ }
++
++ /** Create from a (int,long)-encoded value */
++ /*package*/ static NodeId createRaw(NodeIdType type, int value1, long value2) {
++ return new NodeId(type, value1, value2);
++ }
++
++ public NodeIdType type() { return type; }
++
++ /*package*/ int getValue1() { return value1; }
++ /*package*/ long getValue2() { return value2; }
++
++ @Override
++ public int hashCode() {
++ // Ensure all parts have an effect on the 32 bit hash value.
++ return value1 ^ ((int)value2) ^ ((int)(value2 >> 32));
++ }
++
++ @Override
++ public boolean equals(Object other) {
++ if ( this == other ) return true;
++ if ( other == null ) return false;
++ if ( !(other instanceof NodeId) ) return false;
++ NodeId nOther = ((NodeId)other);
++ return equals(nOther, value1, value2);
++ }
++
++ public boolean equals(NodeId nodeIdOther) {
++ if ( nodeIdOther == null ) return false;
++ if ( this == nodeIdOther ) return true;
++ return equals(nodeIdOther, value1, value2);
++ }
++
++ /*package*/ static boolean equals(NodeId nodeId, int v1, long v2) {
++ return v2 == nodeId.value2 && v1 == nodeId.value1;
++ }
++ @Override
++ public String toString() {
++ if ( this == NodeDoesNotExist ) return "[DoesNotExist]";
++ if ( this == NodeIdAny ) return "[Any]";
++ if ( this == NodeIdInvalid ) return "[Invalid]";
++ if ( this == NodeIdDefined ) return "[Defined]";
++ if ( this == NodeIdUndefined ) return "[Undefined]";
++
++ if ( this.isInline() ) {
++ String displayName = this.type().toString();
++ return String.format("[%s 0x%014X]", displayName, value2);
++ }
++ // [64 bits]
++ //return String.format("[%08X-%016X]", value1, value2);
++ return String.format("[0x%16X]", value2);
++ }
++
++ // ---- Encoding special - inlines.
++
++ /** Compare - provides an ordering of {@code NodeIds}. */
++ @Override
++ public int compareTo(NodeId other) {
++ return compare(this, other);
++ }
++
++ /** Compare - provides an ordering of {@code NodeIds}. */
++ public static int compare(NodeId n1, NodeId n2) {
++ int x = Integer.compare(n1.value1, n2.value1);
++ if ( x == 0 )
++ return CMP_EQUAL;
++ return Long.compare(n1.value2, n2.value2);
++ }
++
++ public final boolean isConcrete() { return isConcrete(this); }
++
++ public static final boolean isConcrete(NodeId nodeId) {
++ return ! NodeIdType.isSpecial(nodeId.type);
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/NodeIdFactory.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/NodeIdFactory.java
index 0000000,0000000..8bddb88
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/NodeIdFactory.java
@@@ -1,0 -1,0 +1,260 @@@
++/*
++ * 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 org.seaborne.tdb2.store.NodeIdType.PTR;
++import static org.seaborne.tdb2.store.NodeIdType.isSpecial;
++
++import java.nio.ByteBuffer;
++import java.util.concurrent.atomic.AtomicInteger;
++
++import org.apache.jena.atlas.lib.BitsInt;
++import org.apache.jena.atlas.lib.BitsLong;
++import org.apache.jena.atlas.lib.Bytes;
++import org.seaborne.tdb2.TDBException;
++import org.seaborne.tdb2.store.value.DoubleNode62;
++
++/** Factory for NodeIds, including to/from disk forms via ByteBuffers and byte[].*/
++final
++public class NodeIdFactory
++{
++ // On-disk: may be shorter (controlled by get/set ByteBuffer and byte[]).
++ // In-memory - always int-long
++
++ // XXX Chance for a cache?
++
++ private static NodeId create(NodeIdType type, int v1, long v2) {
++ if ( isSpecial(type) ) {
++ if ( NodeId.equals(NodeId.NodeDoesNotExist, v1, v2) )
++ return NodeId.NodeDoesNotExist;
++ if ( NodeId.equals(NodeId.NodeIdAny, v1, v2) )
++ return NodeId.NodeIdAny;
++ if ( NodeId.equals(NodeId.NodeIdDefined, v1, v2) )
++ return NodeId.NodeIdDefined;
++ if ( NodeId.equals(NodeId.NodeIdDefined, v1, v2) )
++ return NodeId.NodeIdDefined;
++ if ( NodeId.equals(NodeId.NodeIdUndefined, v1, v2) )
++ return NodeId.NodeIdUndefined;
++ //throw new IllegalArgumentException("Special not recognized");
++ }
++ return createNew(type, v1, v2);
++ }
++
++ public static NodeId createValue(NodeIdType type, long value) {
++ // 64 bit.
++ return createNew(type, 0, value);
++ }
++
++ private static NodeId createNew(NodeIdType type, int v1, long v2) {
++ return NodeId.createRaw(type, v1, v2);
++ }
++
++ public static NodeId createPtr(long lo) {
++ return createNew(PTR, 0, lo);
++ }
++
++ /*package*/ /*long*/ static NodeId createPtrLong(int hi, long lo) {
++ return create(PTR, hi, lo);
++ }
++
++ // ---- Create from binary.
++
++ // 64 bit create
++ private static NodeId create(long value2) {
++ if ( !BitsLong.isSet(value2, 63) )
++ return createPtr(value2);
++ // Inline.
++ long v2 = value2;
++ if ( BitsLong.isSet(v2, 62) ) {
++ // XSD_DOUBLE
++ v2 = DoubleNode62.removeType(v2);
++ return NodeId.createRaw(NodeIdType.XSD_DOUBLE, v2);
++ }
++ int t = (int)BitsLong.unpack(v2, 56, 63); // 7 bits
++ v2 = BitsLong.clear(v2, 56, 64);
++ NodeIdType type = NodeIdType.intToEnum(t);
++ if ( type == NodeIdType.SPECIAL )
++ throw new TDBException(String.format("Attempt to create a special from a long: 0x%016", v2));
++ return NodeId.createRaw(type, v2);
++ }
++
++ // Long create.
++ private static NodeId create(int v1, long v2) {
++ if ( !BitsInt.isSet(v1, 32) )
++ return createPtrLong(v1, v2);
++ int t = v1 >> 24;
++ NodeIdType type = NodeIdType.intToEnum(t);
++ if ( type == NodeIdType.SPECIAL )
++ throw new TDBException(String.format("Attempt to create a special from a long: 0x%016", v2));
++ return createNew(type, 0, v2);
++ }
++
++ // ------- On-disk forms.
++ //
++
++ /** Not relative - get from position zero */
++ public static NodeId get(byte[] b) { return get(b,0); }
++
++ // **** 64 bit NodeId ****
++ /** Relative {@code ByteBuffer} {@code get} */
++ public static NodeId get(ByteBuffer b) {
++ long value2 = b.getLong();
++ return decode(value2);
++ }
++
++ public static NodeId get(byte[] b, int idx) {
++ long value2 = Bytes.getLong(b, idx);
++ return decode(value2);
++ }
++
++ public static NodeId get(ByteBuffer b, int idx) {
++ long value2 = b.getLong(idx);
++ return decode(value2);
++ }
++
++ // 64 bit version
++ private static NodeId decode(long value2) {
++ return NodeIdFactory.create(value2);
++ }
++
++ /** Not relative - set at position zero */
++ public static void set(NodeId nodeId, byte[] b) {
++ long v2 = encode(nodeId);
++ Bytes.setLong(v2, b, 0);
++ }
++
++ private static long encode(NodeId nodeId) {
++ long x = nodeId.value2;
++ switch(nodeId.type()) {
++ case PTR:
++ return x;
++ case XSD_DOUBLE:
++ // XSD_DOUBLE is special.
++ // Set value bit (63) and bit 62
++ x = DoubleNode62.insertType(x);
++ return x ;
++ default:
++ // Bit 62 is zero - tagt is for doubles.
++ x = BitsLong.pack(x, nodeId.getTypeValue(), 56, 62);
++ // Set the high, value bit.
++ x = BitsLong.set(x, 63);
++ return x;
++ }
++ }
++
++ /** Relative {@code set} */
++ public static void set(NodeId nodeId, ByteBuffer b) {
++ long v2 = encode(nodeId);
++ b.putLong(v2);
++ }
++
++ public static void set(NodeId nodeId, byte[] b, int idx) {
++ long v2 = encode(nodeId);
++ Bytes.setLong(v2, b, idx);
++ }
++
++ public static void set(NodeId nodeId, ByteBuffer b, int idx) {
++ long v2 = encode(nodeId);
++ b.putLong(idx, v2);
++ }
++
++ public static void setNext(NodeId nodeId, byte[] b, int idx) {
++ long v2 = encode(nodeId);
++ Bytes.setLong(v2+1, b, idx);
++ }
++
++ // (int,long) versions : check before use
++// /** Relative {@code ByteBuffer} {@code get} */
++// public static NodeId get(ByteBuffer b) {
++// int value1 = b.getInt();
++// long value2 = b.getLong();
++// return decode(value1,value2);
++// }
++//
++// public static NodeId get(byte[] b, int idx) {
++// int value1 = Bytes.getInt(b, idx);
++// long value2 = Bytes.getLong(b, idx+SystemTDB.SizeOfInt);
++// return decode(value1, value2);
++// }
++//
++// public static NodeId get(ByteBuffer b, int idx) {
++// int value1 = b.getInt(idx);
++// long value2 = b.getLong(idx+SystemTDB.SizeOfInt);
++// return decode(value1,value2);
++// }
++//
++// private static NodeId decode(int value1, long value2) {
++// return NodeIdFactory.create(value1, value2);
++// }
++//
++// /** Not relative - set at position zero */
++// public static void set(NodeId nodeId, byte[] b) {
++// int v1 = encode(nodeId.value1);
++// Bytes.setInt(v1, b, 0);
++// Bytes.setLong(nodeId.value2, b, SystemTDB.SizeOfInt);
++// }
++//
++// /** Relative {@code set} */
++// public static void set(NodeId nodeId, ByteBuffer b) {
++// int v1 = encode(nodeId.value1);
++// b.putInt(v1);
++// b.putLong(nodeId.value2);
++// }
++//
++// public static void set(NodeId nodeId, byte[] b, int idx) {
++// int v1 = encode(nodeId.value1);
++// Bytes.setInt(v1, b, idx);
++// Bytes.setLong(nodeId.value2, b, idx+SystemTDB.SizeOfInt);
++// }
++//
++// public static void set(NodeId nodeId, ByteBuffer b, int idx) {
++// int v1 = encode(nodeId.value1);
++// b.putInt(idx, v1);
++// b.putLong(idx+SystemTDB.SizeOfInt, nodeId.value2);
++// }
++//
++// public static void setNext(NodeId nodeId, byte[] b, int idx) {
++// int v1 = encode(nodeId.value1);
++// long v2 = nodeId.value2;
++// // Unsigned 96 bit add!
++// if ( v2 < 0 ) {
++// if ( v2 == Long.MIN_VALUE )
++// v1++ ;
++// else
++// v2--;
++// } else
++// v2++ ;
++// Bytes.setInt(v1, b, idx);
++// Bytes.setLong(v2, b, idx+Integer.SIZE);
++// }
++// private int encode(NodeId nodeId) {
++// long x = nodeId.value1;
++// if ( nodeId.isPtr() )
++// return x;
++// x = BitsInt.pack(x, nodeId.getTypeValue(), 24, 32);
++// return x;
++// }
++
++
++
++
++ private static AtomicInteger counter = new AtomicInteger(0xB0);
++ public static NodeId genUnique() {
++ return NodeIdFactory.create(NodeIdType.SPECIAL, counter.incrementAndGet(), 0);
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/NodeIdInline.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/NodeIdInline.java
index 0000000,0000000..4a7858c
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/NodeIdInline.java
@@@ -1,0 -1,0 +1,328 @@@
++/*
++ * 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 org.seaborne.tdb2.store.NodeIdType.PTR;
++import static org.seaborne.tdb2.store.NodeIdType.*;
++import static org.seaborne.tdb2.store.NodeIdType.XSD_DATE;
++import static org.seaborne.tdb2.store.NodeIdType.XSD_DATETIME;
++import static org.seaborne.tdb2.store.NodeIdType.XSD_DECIMAL;
++import static org.seaborne.tdb2.store.NodeIdType.XSD_FLOAT;
++
++import java.math.BigDecimal;
++import java.util.HashSet;
++import java.util.Set;
++
++import org.apache.jena.atlas.logging.Log;
++import org.apache.jena.datatypes.RDFDatatype;
++import org.apache.jena.datatypes.xsd.XSDDatatype;
++import org.apache.jena.ext.com.google.common.collect.BiMap;
++import org.apache.jena.ext.com.google.common.collect.EnumHashBiMap;
++import org.apache.jena.graph.Node;
++import org.apache.jena.graph.NodeFactory;
++import org.apache.jena.graph.impl.LiteralLabel;
++import org.apache.jena.sparql.graph.NodeConst;
++import org.apache.jena.sparql.util.NodeUtils;
++import org.apache.jena.sparql.util.Utils;
++import org.seaborne.tdb2.TDBException;
++import org.seaborne.tdb2.store.value.*;
++
++/** Encoding values in a {@link NodeId}.
++ *
++ * TDB2 encoding:
++ * <ul>
++ * <li>High bit (bit 63) 0 means the node is in the object table (PTR).
++ * <li>High bit (bit 63) 1, bit 62 1: double as 62 bits. See {@link DoubleNode62}.
++ * <li>High bit (bit 63) 1, bit 62 0: 6 bits of type, 56 bits of value.
++ * </ul>
++ *
++ * If a value would not fit, it will be stored externally so there is no
++ * guarantee that all integers, say, are store inline.
++ *
++ * <ul>
++ * <li>Integer format: signed 56 bit number, the type filed has the XSD type.
++ * <li>Decimal format: 8 bits scale, 48bits of signed valued. See {@link DecimalNode56}.
++ * <li>Date and DateTime
++ * <li>Boolean
++ * <li>Float
++ * </ul>
++ *
++ * @see IntegerNode
++ * @see DecimalNode56
++ * @see DoubleNode62
++ * @see DateTimeNode DateTimeNode for xsd:date and xsd:DateTime
++ * @see FloatNode
++ */
++public class NodeIdInline {
++ /** Datatypes that are candidates for inlining */
++ private static Set<RDFDatatype> datatypes = new HashSet<>();
++ static {
++ datatypes.add(XSDDatatype.XSDdecimal);
++ datatypes.add(XSDDatatype.XSDinteger);
++ datatypes.add(XSDDatatype.XSDdouble);
++ datatypes.add(XSDDatatype.XSDfloat);
++
++ datatypes.add(XSDDatatype.XSDlong);
++ datatypes.add(XSDDatatype.XSDint);
++ datatypes.add(XSDDatatype.XSDshort);
++ datatypes.add(XSDDatatype.XSDbyte);
++
++ datatypes.add(XSDDatatype.XSDpositiveInteger);
++ datatypes.add(XSDDatatype.XSDnonPositiveInteger);
++ datatypes.add(XSDDatatype.XSDnegativeInteger);
++ datatypes.add(XSDDatatype.XSDnonNegativeInteger);
++
++ datatypes.add(XSDDatatype.XSDunsignedLong);
++ datatypes.add(XSDDatatype.XSDunsignedInt);
++ datatypes.add(XSDDatatype.XSDunsignedShort);
++ datatypes.add(XSDDatatype.XSDunsignedByte);
++ datatypes.add(XSDDatatype.XSDdateTimeStamp);
++ datatypes.add(XSDDatatype.XSDdateTime);
++ datatypes.add(XSDDatatype.XSDdate);
++ datatypes.add(XSDDatatype.XSDboolean);
++ };
++
++ // Integer derived types.
++ private static BiMap<NodeIdType, RDFDatatype> derivedTypeMap = EnumHashBiMap.create(NodeIdType.class);
++ static {
++ derivedTypeMap.put(NodeIdType.XSD_LONG, XSDDatatype.XSDlong);
++ derivedTypeMap.put(NodeIdType.XSD_INT, XSDDatatype.XSDint);
++ derivedTypeMap.put(NodeIdType.XSD_SHORT, XSDDatatype.XSDshort);
++ derivedTypeMap.put(NodeIdType.XSD_BYTE, XSDDatatype.XSDbyte);
++
++ derivedTypeMap.put(NodeIdType.XSD_POSITIVE_INTEGER, XSDDatatype.XSDpositiveInteger);
++ derivedTypeMap.put(NodeIdType.XSD_NON_POSITIVE_INTEGER, XSDDatatype.XSDnonPositiveInteger);
++ derivedTypeMap.put(NodeIdType.XSD_NEGATIVE_INTEGER, XSDDatatype.XSDnegativeInteger);
++ derivedTypeMap.put(NodeIdType.XSD_NON_NEGATIVE_INTEGER, XSDDatatype.XSDnonNegativeInteger);
++
++ derivedTypeMap.put(NodeIdType.XSD_UNSIGNEDLONG, XSDDatatype.XSDunsignedLong);
++ derivedTypeMap.put(NodeIdType.XSD_UNSIGNEDINT, XSDDatatype.XSDunsignedInt);
++ derivedTypeMap.put(NodeIdType.XSD_UNSIGNEDSHORT, XSDDatatype.XSDunsignedShort);
++ derivedTypeMap.put(NodeIdType.XSD_UNSIGNEDBYTE, XSDDatatype.XSDunsignedByte);
++ }
++
++ /** Encode a node as an inline literal. Return null if it can't be done */
++ public static NodeId inline(Node node) {
++ if ( node == null ) {
++ Log.warn(NodeId.class, "Null node: " + node);
++ return null;
++ }
++
++ if ( !NodeId.enableInlineLiterals )
++ return null;
++
++ if ( !node.isLiteral() )
++ return null;
++
++ if ( NodeUtils.isSimpleString(node) || NodeUtils.isLangString(node) )
++ return null;
++
++ try { return inline$(node); }
++ catch (Throwable th) {
++ Log.warn(NodeId.class, "Failed to process "+node);
++ return null;
++ }
++ }
++
++ /** Return true if this node has a datatype that look like it is inlineable.
++ * The node may still be out of range (e.g. very large integer).
++ * Only inline(Node)->NodeId can determine that.
++ */
++ public static boolean hasInlineDatatype(Node node) {
++ if ( ! node.isLiteral() )
++ return false;
++ RDFDatatype dtn = node.getLiteralDatatype();
++ return datatypes.contains(dtn);
++ }
++
++ private static NodeId inline$(Node node) {
++ if ( ! hasInlineDatatype(node) )
++ return null;
++ LiteralLabel lit = node.getLiteral();
++ // Decimal is a valid supertype of integer but we handle integers and decimals
++ // differently.
++
++ if ( node.getLiteralDatatype().equals(XSDDatatype.XSDdecimal) ) {
++ // Check lexical form.
++ if ( !XSDDatatype.XSDdecimal.isValidLiteral(lit) )
++ return null;
++
++ // Not lit.getValue() because that may be a narrower type e.g. Integer.
++ // .trim is how Jena does it but it rather savage. spc, \n \r \t.
++ // But at this point we know it's a valid literal so the excessive
++ // chopping by .trim is safe.
++ BigDecimal decimal = new BigDecimal(lit.getLexicalForm().trim());
++
++ // Does range checking.
++ DecimalNode56 dn = DecimalNode56.valueOf(decimal);
++ // null is "does not fit"
++ if ( dn != null )
++ // setType
++ return NodeId.createRaw(XSD_DECIMAL, dn.pack());
++ else
++ return null;
++ } else {
++ // Not decimal.
++ if ( XSDDatatype.XSDinteger.isValidLiteral(lit) ) {
++ // Check length of lexical form to see if it's in range of a long.
++ // Long.MAX_VALUE = 9223372036854775807
++ // Long.MIN_VALUE = -9223372036854775808
++ // 9,223,372,036,854,775,807 is 19 digits.
++
++ // Quick check.
++ if ( lit.getLexicalForm().length() > 19 )
++ return null;
++
++ // Derived types.
++ NodeIdType type = derivedTypeMap.inverse().getOrDefault(lit.getDatatype(), NodeIdType.XSD_INTEGER);
++
++ try {
++ long v = ((Number)lit.getValue()).longValue();
++ v = IntegerNode.pack56(v);
++ // Value -1 is "does not fit"
++ if ( v == -1 )
++ return null;
++ return NodeId.createRaw(type, v);
++ }
++ // Out of range for the type, not a long etc etc.
++ catch (Throwable ex) { return null; }
++ }
++ }
++
++ if ( XSDDatatype.XSDdouble.isValidLiteral(lit) ) {
++ double d = ((Number)lit.getValue()).doubleValue();
++ long v = DoubleNode62.pack(d);
++ if ( v == DoubleNode62.NO_ENCODING )
++ return null ;
++ // The special encoding of XSD_DOUBLE is handling in the "toBytes" and "toByteBuffer" operations.
++ return NodeId.createRaw(XSD_DOUBLE, v);
++ }
++
++ if ( XSDDatatype.XSDfloat.isValidLiteral(lit) ) {
++ float f = ((Number)lit.getValue()).floatValue();
++ long v = FloatNode.pack(f);
++ return NodeId.createRaw(XSD_FLOAT, v);
++ }
++
++ if ( lit.getDatatype().equals(XSDDatatype.XSDdateTimeStamp) && XSDDatatype.XSDdateTimeStamp.isValidLiteral(lit) ) {
++ long v = DateTimeNode.packDateTime(lit.getLexicalForm());
++ if ( v == -1 )
++ return null;
++ return NodeId.createRaw(XSD_DATETIMESTAMP, v);
++ }
++ if ( XSDDatatype.XSDdateTime.isValidLiteral(lit) ) {
++ // Could use the Jena/XSDDateTime object here rather than reparse the lexical form.
++ // But this works and it's close to a release ...
++ long v = DateTimeNode.packDateTime(lit.getLexicalForm());
++ if ( v == -1 )
++ return null;
++ return NodeId.createRaw(XSD_DATETIME, v);
++ }
++
++ if ( XSDDatatype.XSDdate.isValidLiteral(lit) ) {
++ long v = DateTimeNode.packDate(lit.getLexicalForm());
++ if ( v == -1 )
++ return null;
++ return NodeId.createRaw(XSD_DATE, v);
++ }
++
++ if ( XSDDatatype.XSDboolean.isValidLiteral(lit) ) {
++ long v = 0;
++ boolean b = (Boolean)lit.getValue();
++ // return new NodeValueBoolean(b, node);
++ if ( b )
++ v = v | 0x01;
++ return NodeId.createRaw(XSD_BOOLEAN, v);
++ }
++
++ return null;
++ }
++
++ /** Decode an inline nodeID, return null if not an inline node */
++ public static Node extract(NodeId nodeId) {
++ if ( nodeId == NodeId.NodeDoesNotExist )
++ return null;
++
++ NodeIdType type = nodeId.type();
++ if ( type == PTR || type == NodeIdType.SPECIAL)
++ return null;
++ switch (type) {
++// case PTR: return null;
++// case SPECIAL: return null;
++ case XSD_INTEGER :
++ // Derived from integer
++ case XSD_POSITIVE_INTEGER:
++ case XSD_NEGATIVE_INTEGER:
++ case XSD_NON_NEGATIVE_INTEGER:
++ case XSD_NON_POSITIVE_INTEGER:
++ case XSD_LONG:
++ case XSD_INT:
++ case XSD_SHORT:
++ case XSD_BYTE:
++ case XSD_UNSIGNEDLONG:
++ case XSD_UNSIGNEDINT:
++ case XSD_UNSIGNEDSHORT:
++ case XSD_UNSIGNEDBYTE:
++ {
++ long val = IntegerNode.unpack56(nodeId.value2);
++ RDFDatatype dt = derivedTypeMap.getOrDefault(type, XSDDatatype.XSDinteger);
++ Node n = NodeFactory.createLiteral(Long.toString(val), dt);
++ return n;
++ }
++ case XSD_DECIMAL : {
++ BigDecimal d = DecimalNode56.unpackAsBigDecimal(nodeId.value2);
++ String x = d.toPlainString();
++ return NodeFactory.createLiteral(x, XSDDatatype.XSDdecimal);
++ }
++ case XSD_DOUBLE: {
++ double d = DoubleNode62.unpack(nodeId.value2);
++ String xsdStr = Utils.stringForm(d);
++ Node n = NodeFactory.createLiteral(xsdStr, XSDDatatype.XSDdouble);
++ return n ;
++ }
++ case XSD_FLOAT: {
++ float f = FloatNode.unpack(nodeId.value2);
++ String xsdStr = Utils.stringForm(f);
++ Node n = NodeFactory.createLiteral(xsdStr, XSDDatatype.XSDfloat);
++ return n ;
++ }
++ case XSD_DATETIMESTAMP:
++ case XSD_DATETIME: {
++ RDFDatatype dt = (type==XSD_DATETIMESTAMP) ? XSDDatatype.XSDdateTimeStamp : XSDDatatype.XSDdateTime;
++ long val = nodeId.getValue2();
++ String lex = DateTimeNode.unpackDateTime(val);
++ return NodeFactory.createLiteral(lex, dt);
++ }
++ case XSD_DATE : {
++ long val = nodeId.getValue2();
++ String lex = DateTimeNode.unpackDate(val);
++ return NodeFactory.createLiteral(lex, XSDDatatype.XSDdate);
++ }
++ case XSD_BOOLEAN : {
++ long val = nodeId.getValue2();
++ if ( val == 0 )
++ return NodeConst.nodeFalse;
++ if ( val == 1 )
++ return NodeConst.nodeTrue;
++ throw new TDBException("Unrecognized boolean node id : " + val);
++ }
++ default :
++ throw new TDBException("Unrecognized node id type: " + type);
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/NodeIdType.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/NodeIdType.java
index 0000000,0000000..02691ee
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/NodeIdType.java
@@@ -1,0 -1,0 +1,259 @@@
++/*
++ * 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 org.seaborne.tdb2.store.NodeIdType.TYPES.*;
++
++/** Constants for NodeIds.
++ * Note that "PTR" is special - it uses the high bit only set to zero.
++ * Note that "XSD_DOUBLE" is special - it sets the high bit (value/ptr)
++ * and the next bit only, leaving 62 bits of value.
++ * Otherwise a type is encoded as the high byte.
++ *
++ * @see NodeIdInline
++ */
++public enum NodeIdType {
++ PTR(T_PTR, null),
++
++ XSD_INTEGER(T_INTEGER, "Integer"),
++ XSD_DECIMAL(T_DECIMAL, "Decimal"),
++ XSD_FLOAT(T_FLOAT, "Float"),
++ XSD_DOUBLE(T_DOUBLE, "Double"),
++ XSD_DATETIME(T_DATETIME, "DateTime"),
++ XSD_DATETIMESTAMP(T_DATETIMESTAMP, "DateTimeStamp"),
++ XSD_DATE(T_DATE, "Date"),
++ XSD_BOOLEAN(T_BOOLEAN, "Boolean"),
++ XSD_SHORTSTRING(T_SHORTSTRING, "ShortString"),
++ // 1 and greater
++ XSD_POSITIVE_INTEGER(T_POSITIVE_INTEGER, "Positive Integer"),
++ // -1 and down
++ XSD_NEGATIVE_INTEGER(T_NEGATIVE_INTEGER, "Negative Integer"),
++ // postive and zero
++ XSD_NON_NEGATIVE_INTEGER(T_NON_NEGATIVE_INTEGER, "Non-negative Integer"),
++ // negative or zero
++ XSD_NON_POSITIVE_INTEGER(T_NON_POSITIVE_INTEGER, "Non-positive Integer"),
++ XSD_LONG(T_LONG, "Long"),
++ XSD_INT(T_INT, "Int"),
++ XSD_SHORT(T_SHORT, "Short"),
++ XSD_BYTE(T_BYTE, "Byte"),
++ XSD_UNSIGNEDLONG(T_UNSIGNEDLONG, "UnsignedLong"),
++ XSD_UNSIGNEDINT(T_UNSIGNEDINT, "UnsignedInt"),
++ XSD_UNSIGNEDSHORT(T_UNSIGNEDSHORT, "UnsignedShort"),
++ XSD_UNSIGNEDBYTE(T_UNSIGNEDBYTE, "UnsignedByte"),
++
++ // Never stored.
++ SPECIAL(T_SPECIAL, "Special"),
++ // Used here only.
++ INVALID$(T_INVALID, "Invalid")
++
++ //, EXTENSION(T_EXTENSION, "Extension")
++ ;
++ /** The type values - must be stable as many of these go on disk.
++ * enum ordinals are not enough.
++ *
++ * Encode as:
++ * <ul>
++ * <li>PTR : high bit zero, everything else written with a high bit one (done in {@link NodeIdFactory#encode}
++ * <li>T_DOUBLE : Special case: next bit one. 01?? ???? i.e. 11?? on disk (value bit, double bit).
++ * This leaves 62 bits for encoding doubles in the future.
++ * <li>Otherwise, a number in the low byte of the constant, high bits "10".
++ * </ul>
++ * The {@code T_*} constants do not include the high bit.
++ */
++ public static class TYPES {
++ public static final int T_PTR = 0 ;
++
++ public static final int T_DOUBLE = enc(0x40);
++
++ // Value types : 1 to 100
++ public static final int T_INTEGER = enc(1);
++ public static final int T_DECIMAL = enc(2);
++ public static final int T_FLOAT = enc(3);
++ //private static final int T_DOUBLE_X = enc(4);
++
++ public static final int T_DATETIME = enc(5);
++ public static final int T_DATETIMESTAMP = enc(6);
++ public static final int T_DATE = enc(7);
++ public static final int T_BOOLEAN = enc(8);
++ public static final int T_SHORTSTRING = enc(9);
++
++ public static final int T_POSITIVE_INTEGER = enc(10);
++ public static final int T_NEGATIVE_INTEGER = enc(11);
++ public static final int T_NON_NEGATIVE_INTEGER = enc(12);
++ public static final int T_NON_POSITIVE_INTEGER = enc(13);
++ public static final int T_LONG = enc(14);
++ public static final int T_INT = enc(15);
++ public static final int T_SHORT = enc(16);
++ public static final int T_BYTE = enc(17);
++ public static final int T_UNSIGNEDLONG = enc(18);
++ public static final int T_UNSIGNEDINT = enc(19);
++ public static final int T_UNSIGNEDSHORT = enc(20);
++ public static final int T_UNSIGNEDBYTE = enc(21);
++ // 21 is 00010101
++
++ // Never stored : bits 1011 0000 so as not to look like a double.
++ public static final int T_SPECIAL = enc(0x30);
++ public static final int T_INVALID = enc(0x31);
++ public static final int T_EXTENSION = enc(0x3F);
++
++ // Encode/decode of the type value.
++ static int enc(int v) { return v; }
++ static int dec(int v) { return v; }
++ }
++
++ // We provide lots of natural questions to ask of an NodeId type.
++ // All are efficient. There is redundancy but limited to this file.
++
++ static boolean isStorable(NodeIdType type) {
++ return !isSpecial(type);
++ }
++
++ // For numbers, an out-of-range number maybe stored a PTR.
++
++ static boolean isInteger(NodeIdType type) {
++ switch(type) {
++ case XSD_INTEGER:
++ case XSD_POSITIVE_INTEGER:
++ case XSD_NEGATIVE_INTEGER:
++ case XSD_NON_NEGATIVE_INTEGER:
++ case XSD_NON_POSITIVE_INTEGER:
++ case XSD_LONG:
++ case XSD_INT:
++ case XSD_SHORT:
++ case XSD_BYTE:
++ case XSD_UNSIGNEDLONG:
++ case XSD_UNSIGNEDINT:
++ case XSD_UNSIGNEDSHORT:
++ case XSD_UNSIGNEDBYTE:
++ return true;
++ default:
++ return false;
++ }
++ }
++
++ static boolean isDecimal(NodeIdType type) {
++ return type == XSD_DECIMAL;
++ }
++
++ static boolean isDouble(NodeIdType type) {
++ return type == XSD_DOUBLE;
++ }
++
++ static boolean isFloat(NodeIdType type) {
++ return type == XSD_FLOAT;
++ }
++
++ static boolean isNumber(NodeIdType type) {
++ return isInteger(type) || isDecimal(type) || isDouble(type) || isFloat(type);
++ }
++
++ static boolean isSpecial(NodeIdType type) {
++ return type == SPECIAL;
++ }
++
++ static boolean isInline(NodeIdType type) {
++ switch(type) {
++ case XSD_INTEGER:
++ case XSD_DECIMAL:
++ case XSD_DOUBLE:
++ case XSD_FLOAT:
++
++ case XSD_DATETIME:
++ case XSD_DATETIMESTAMP:
++ case XSD_DATE:
++ case XSD_BOOLEAN:
++ case XSD_SHORTSTRING:
++
++ case XSD_POSITIVE_INTEGER:
++ case XSD_NEGATIVE_INTEGER:
++ case XSD_NON_NEGATIVE_INTEGER:
++ case XSD_NON_POSITIVE_INTEGER:
++ case XSD_LONG:
++ case XSD_INT:
++ case XSD_SHORT:
++ case XSD_BYTE:
++ case XSD_UNSIGNEDLONG:
++ case XSD_UNSIGNEDINT:
++ case XSD_UNSIGNEDSHORT:
++ case XSD_UNSIGNEDBYTE:
++ return true;
++ default:
++ return false;
++ }
++ }
++
++ private final int value;
++ private final String displayName;
++
++ public int type() { return TYPES.dec(value); }
++
++ @Override
++ public String toString() { return displayName != null ? displayName : name(); }
++
++ private NodeIdType(int value, String displayName){
++// if ( value != 0 )
++// // Set high bit.
++// value = TYPES.enc(value);
++ this.value = value;
++ this.displayName = displayName;
++ }
++
++ public static NodeIdType intToEnum(int x) {
++ if ( x >= 0x80 )
++ throw new IllegalArgumentException("Value '"+x+"' not legal: too large");
++ if ( x != 0 )
++ x = TYPES.enc(x);
++ NodeIdType t = intToEnum$(x);
++ if ( t == INVALID$ )
++ throw new IllegalArgumentException("Value '"+x+"' not legal for "+NodeIdType.class.getSimpleName());
++ return t ;
++ }
++
++ private static NodeIdType intToEnum$(int x) {
++ //x = TYPES.enc(x);
++ if (x == PTR.value ) return PTR;
++ // XSD_DOUBL is special encoded - handled elsewhere.
++ if (x == XSD_DOUBLE.value ) return XSD_DOUBLE ;
++ if (x == XSD_INTEGER.value ) return XSD_INTEGER ;
++ if (x == XSD_DECIMAL.value ) return XSD_DECIMAL ;
++ if (x == XSD_FLOAT.value ) return XSD_FLOAT ;
++
++ if (x == XSD_DATETIME.value ) return XSD_DATETIME ;
++ if (x == XSD_DATETIMESTAMP.value ) return XSD_DATETIMESTAMP ;
++ if (x == XSD_DATE.value ) return XSD_DATE ;
++
++ if (x == XSD_BOOLEAN.value ) return XSD_BOOLEAN ;
++ if (x == XSD_SHORTSTRING.value ) return XSD_SHORTSTRING ;
++
++ if (x == XSD_POSITIVE_INTEGER.value ) return XSD_POSITIVE_INTEGER;
++ if (x == XSD_NEGATIVE_INTEGER.value ) return XSD_NEGATIVE_INTEGER ;
++ if (x == XSD_NON_NEGATIVE_INTEGER.value ) return XSD_NON_NEGATIVE_INTEGER ;
++ if (x == XSD_NON_POSITIVE_INTEGER.value ) return XSD_NON_POSITIVE_INTEGER ;
++
++ if (x == XSD_LONG.value ) return XSD_LONG ;
++ if (x == XSD_INT.value ) return XSD_INT ;
++ if (x == XSD_SHORT.value ) return XSD_SHORT ;
++ if (x == XSD_BYTE.value ) return XSD_BYTE ;
++ if (x == XSD_UNSIGNEDLONG.value ) return XSD_UNSIGNEDLONG ;
++ if (x == XSD_UNSIGNEDINT.value ) return XSD_UNSIGNEDINT ;
++ if (x == XSD_UNSIGNEDSHORT.value ) return XSD_UNSIGNEDSHORT ;
++ if (x == XSD_UNSIGNEDBYTE.value ) return XSD_UNSIGNEDBYTE ;
++ //if (x == EXTENSION.value ) return EXTENSION ;
++ return INVALID$;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/PrefixMappingCache.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/PrefixMappingCache.java
index 0000000,0000000..ca950d7
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/PrefixMappingCache.java
@@@ -1,0 -1,0 +1,202 @@@
++/*
++ * 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.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 ;
++
++// Unsafe. Non-transactional cache.
++public class PrefixMappingCache implements PrefixMapping {
++
++ private final PrefixMapping other ;
++ private Cache<String, String> prefixToUri = CacheFactory.createCache(100) ;
++ private Cache<String, String> uriToPrefix = CacheFactory.createCache(100) ;
++
++ public PrefixMappingCache(PrefixMapping other) {
++ this.other = other ;
++ }
++
++ private void add(String prefix, String uri) {
++ prefixToUri.put(prefix, uri) ;
++ uriToPrefix.put(uri, prefix);
++ }
++
++ private void remove(String prefix, String uri) {
++ prefixToUri.remove(prefix) ;
++ uriToPrefix.remove(uri);
++ }
++
++ private void clear() {
++ prefixToUri.clear() ;
++ uriToPrefix.clear() ;
++ }
++
++ @Override
++ public PrefixMapping setNsPrefix(String prefix, String uri) {
++ other.setNsPrefix(prefix, uri) ;
++ add(prefix, uri);
++ return this ;
++ }
++
++ @Override
++ public PrefixMapping removeNsPrefix(String prefix) {
++ String uri = getNsPrefixURI(prefix) ;
++ if ( uri != null )
++ remove(prefix, uri);
++ other.removeNsPrefix(prefix) ;
++ return this ;
++ }
++
++ @Override
++ public PrefixMapping clearNsPrefixMap() {
++ prefixToUri.clear() ;
++ uriToPrefix.clear();
++ other.clearNsPrefixMap() ;
++ return this ;
++ }
++
++ @Override
++ public PrefixMapping setNsPrefixes(PrefixMapping pmap) {
++ setNsPrefixes(pmap.getNsPrefixMap()) ;
++ return this ;
++ }
++
++ @Override
++ public PrefixMapping setNsPrefixes(Map<String, String> map) {
++ map.entrySet().forEach(entry->{
++ setNsPrefix(entry.getKey(), entry.getValue()) ;
++ });
++ return this ;
++ }
++
++ @Override
++ public PrefixMapping withDefaultMappings(PrefixMapping map) {
++ other.withDefaultMappings(map) ;
++ clear() ;
++ return this ;
++ }
++
++ @Override
++ public String getNsPrefixURI(String prefix) {
++ String x = prefixToUri.getIfPresent(prefix) ;
++ if ( x == null ) {
++ x = other.getNsPrefixURI(prefix) ;
++ if ( x != null )
++ prefixToUri.put(prefix, x);
++ }
++ return x ;
++ }
++
++ @Override
++ public String getNsURIPrefix(String uri) {
++ String x = uriToPrefix.getIfPresent(uri) ;
++ if ( x == null ) {
++ x = other.getNsURIPrefix(uri) ;
++ if ( x != null )
++ uriToPrefix.put(uri, x);
++ }
++ return x ;
++ }
++
++ @Override
++ public Map<String, String> getNsPrefixMap() {
++ // Ignore cache - get everything from the provider.
++ return other.getNsPrefixMap() ;
++ }
++
++ // From PrefixMappingImpl
++ // 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);
++ }
++ }
++
++ @Override
++ public String qnameFor(String uri) {
++ int split = Util.splitNamespaceXML(uri) ;
++ String ns = uri.substring(0, split);
++ String local = uri.substring(split) ;
++ if ( local.equals("") )
++ return null ;
++ String prefix = getNsURIPrefix(ns) ;
++ return prefix == null ? null : prefix + ":" + local ;
++ }
++
++ @Override
++ public String shortForm(String uri) {
++ Optional<Entry<String, String>> e = findMapping(uri, true) ;
++ if ( ! e.isPresent() )
++ return uri ;
++ return e.get().getKey() + ":" + uri.substring((e.get().getValue()).length()) ;
++ }
++
++ private Optional<Entry<String, String>> findMapping( String uri, boolean partial ) {
++ return getNsPrefixMap().entrySet().stream().sequential().filter(e->{
++ String ss = e.getValue();
++ if (uri.startsWith( ss ) && (partial || ss.length() == uri.length()))
++ return true;
++ return false ;
++ }).findFirst() ;
++ }
++
++ @Override
++ public boolean samePrefixMappingAs(PrefixMapping other) {
++ return other.samePrefixMappingAs(other) ;
++ }
++
++ @Override
++ public PrefixMapping lock() {
++ return this ;
++ }
++
++ @Override
++ public boolean hasNoMappings() {
++ return other.hasNoMappings() ;
++ }
++
++ @Override
++ public int numPrefixes() {
++ 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/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/QuadTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/QuadTable.java
index 0000000,0000000..6d4b366
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/QuadTable.java
@@@ -1,0 -1,0 +1,90 @@@
++/*
++ * 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 org.apache.jena.atlas.iterator.Iter;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.graph.Triple ;
++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 ;
++
++/**
++ * Quad table - a collection of TupleIndexes for 4-tuples together with a node
++ * table.
++ */
++
++public class QuadTable extends TableBase {
++ public QuadTable(TupleIndex[] indexes, NodeTable nodeTable) {
++ super(4, indexes, nodeTable) ;
++ }
++
++ /** Add a quad - return true if it was added, false if it already existed */
++ public void add(Quad quad) {
++ add(quad.getGraph(), quad.getSubject(), quad.getPredicate(), quad.getObject()) ;
++ }
++
++ /**
++ * Add a quad (as graph node and triple) - return true if it was added,
++ * false if it already existed
++ */
++ public void add(Node gn, Triple triple) {
++ add(gn, triple.getSubject(), triple.getPredicate(), triple.getObject()) ;
++ }
++
++ /** Add a quad - return true if it was added, false if it already existed */
++ public void add(Node g, Node s, Node p, Node o) {
++ table.addRow(g, s, p, o) ;
++ }
++
++ /** Delete a quad - return true if it was deleted, false if it didn't exist */
++ public void delete(Quad quad) {
++ delete(quad.getGraph(), quad.getSubject(), quad.getPredicate(), quad.getObject()) ;
++ }
++
++ /**
++ * Delete a quad (as graph node and triple) - return true if it was deleted,
++ * false if it didn't exist
++ */
++ public void delete(Node gn, Triple triple) {
++ delete(gn, triple.getSubject(), triple.getPredicate(), triple.getObject()) ;
++ }
++
++ /** Delete a quad - return true if it was deleted, false if it didn't exist */
++ public void delete(Node g, Node s, Node p, Node o) {
++ table.deleteRow(g, s, p, o) ;
++ }
++
++ /** Find matching quads */
++ public Iterator<Quad> find(Node g, Node s, Node p, Node o) {
++ Iterator<Tuple<NodeId>> iter = table.findAsNodeIds(g, s, p, o) ;
++ if ( iter == null )
++ return Iter.nullIterator() ;
++ Iterator<Quad> iter2 = TupleLib.convertToQuads(table.getNodeTable(), iter) ;
++ return iter2 ;
++ }
++
++ /** Clear - does not clear the associated node tuple table */
++ public void clearQuads() {
++ table.clear() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/StorageTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/StorageTDB.java
index 0000000,0000000..f9b39ec
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/StorageTDB.java
@@@ -1,0 -1,0 +1,41 @@@
++/*
++ * 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.store;
++
++import org.apache.jena.sparql.core.DatasetPrefixStorage;
++import org.seaborne.dboe.base.file.Location;
++import org.seaborne.tdb2.setup.StoreParams;
++
++public class StorageTDB {
++
++ /*package*/ final TripleTable tripleTable;
++ /*package*/ final QuadTable quadTable;
++ /*package*/ final DatasetPrefixStorage prefixes;
++ /*package*/ final Location location;
++ /*package*/ final StoreParams storeParams;
++
++ public StorageTDB(TripleTable tripleTable, QuadTable quadTable, DatasetPrefixStorage prefixes, Location location, StoreParams params) {
++ super();
++ this.tripleTable = tripleTable;
++ this.quadTable = quadTable;
++ this.prefixes = prefixes;
++ this.location = location;
++ this.storeParams = params;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/TableBase.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/TableBase.java
index 0000000,0000000..1241a0b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/TableBase.java
@@@ -1,0 -1,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 org.apache.jena.atlas.lib.Closeable ;
++import org.apache.jena.atlas.lib.Sync ;
++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 ;
++
++public class TableBase implements Sync, Closeable
++{
++ final protected NodeTupleTable table ;
++
++ protected TableBase(int N, TupleIndex[] indexes, NodeTable nodeTable) {
++ table = new NodeTupleTableConcrete(N, indexes, nodeTable) ;
++ }
++
++ public NodeTupleTable getNodeTupleTable() { return table ; }
++
++ @Override
++ public void sync() {
++ table.sync() ;
++ }
++
++ @Override
++ public void close()
++ { table.close() ; }
++
++ public boolean isEmpty() { return table.isEmpty() ; }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/TripleTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/TripleTable.java
index 0000000,0000000..54dcac3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/TripleTable.java
@@@ -1,0 -1,0 +1,74 @@@
++/*
++ * 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 org.apache.jena.atlas.iterator.Iter;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.graph.Node ;
++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 ;
++
++/**
++ * TripleTable - a collection of TupleIndexes for 3-tuples together with a node
++ * table. Normally, based on 3 indexes (SPO, POS, OSP) but other indexing
++ * structures can be configured.
++ */
++
++public class TripleTable extends TableBase {
++ public TripleTable(TupleIndex[] indexes, NodeTable nodeTable) {
++ super(3, indexes, nodeTable) ;
++ }
++
++ /** Add triple */
++ public void add(Triple triple) {
++ add(triple.getSubject(), triple.getPredicate(), triple.getObject()) ;
++ }
++
++ /** Add triple */
++ public void add(Node s, Node p, Node o) {
++ table.addRow(s, p, o) ;
++ }
++
++ /** Delete a triple */
++ public void delete(Triple triple) {
++ delete(triple.getSubject(), triple.getPredicate(), triple.getObject()) ;
++ }
++
++ /** Delete a triple */
++ public void delete(Node s, Node p, Node o) {
++ table.deleteRow(s, p, o) ;
++ }
++
++ /** Find matching triples */
++ public Iterator<Triple> find(Node s, Node p, Node o) {
++ Iterator<Tuple<NodeId>> iter = table.findAsNodeIds(s, p, o) ;
++ if ( iter == null )
++ return Iter.nullIterator() ;
++ Iterator<Triple> iter2 = TupleLib.convertToTriples(table.getNodeTable(), iter) ;
++ return iter2 ;
++ }
++
++ /** Clear - does not clear the associated node tuple table */
++ public void clearTriples() {
++ table.clear() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTable.java
index 0000000,0000000..4cc367e
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTable.java
@@@ -1,0 -1,0 +1,81 @@@
++/*
++ * 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.nodetable;
++
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.apache.jena.atlas.lib.Closeable ;
++import org.apache.jena.atlas.lib.Pair ;
++import org.apache.jena.atlas.lib.Sync ;
++import org.apache.jena.graph.Node ;
++import org.seaborne.tdb2.store.NodeId ;
++
++/** Node table - conceptually a two way mapping of Node<->NodeId
++ * where Nodes can be staored and a NodeId allocated
++ * @see NodeId
++ */
++
++public interface NodeTable extends Sync, Closeable
++{
++ /** Store the node in the node table (if not already present) and return the allocated Id. */
++ public NodeId getAllocateNodeId(Node node) ;
++
++ /** Look up node and return the NodeId - return NodeId.NodeDoesNotExist if not found */
++ public NodeId getNodeIdForNode(Node node) ;
++
++ /** Look up node id and return the Node - return null if not found */
++ public Node getNodeForNodeId(NodeId id) ;
++
++ /** Test whether the node table contains an entry for node */
++ public boolean containsNode(Node node) ;
++
++ /** Test whether the node table contains an entry for node */
++ public boolean containsNodeId(NodeId nodeId) ;
++
++ /** Bulk mapping from {@code Node} to {@code NodeId}, with allocation
++ * if the {@code withAllocation} is true.
++ * The returned list aligns with the input list.
++ */
++ public List<NodeId> bulkNodeToNodeId(List<Node> nodes, boolean withAllocation) ;
++
++ /** Bulk mapping from {@code NodeId} to {@code Node} */
++ public List<Node> bulkNodeIdToNode(List<NodeId> nodeIds) ;
++
++ /** Bulk lookup
++ public List<NodeId> getAllocateNodeIdBulk(List<Node> nodes) ;
++
++ /** Iterate over all nodes (not necessarily fast). Does not include inlined NodeIds */
++ public Iterator<Pair<NodeId, Node>> all() ;
++
++ /** Anything there? */
++ public boolean isEmpty() ;
++
++ /** Return a NodeTable if this instance wraps another, else return null */
++ public NodeTable wrapped() ;
++
++ /** Return the base NodeTable, the end of the wrapped chain */
++ default public NodeTable baseNodeTable() {
++ NodeTable nt = this ;
++ NodeTable nt2 = null ;
++ while ( (nt2 = nt.wrapped()) != null ) {
++ nt = nt2 ;
++ }
++ return nt ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableCache.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableCache.java
index 0000000,0000000..c153d81
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableCache.java
@@@ -1,0 -1,0 +1,352 @@@
++/*
++ * 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.nodetable ;
++
++import java.util.ArrayList ;
++import java.util.Iterator ;
++import java.util.List ;
++
++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.atlas.lib.CacheSet ;
++import org.apache.jena.atlas.lib.Pair ;
++import org.apache.jena.atlas.logging.Log ;
++import org.apache.jena.graph.Node ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.store.NodeId ;
++
++/**
++ * Cache wrapper around a NodeTable. Assumes all access goes through this
++ * wrapper. Read-cache - write caching is done via the object file used by the
++ * base NodeTable.
++ */
++public class NodeTableCache implements NodeTable {
++ // These caches are updated together.
++ // See synchronization in _retrieveNodeByNodeId and _idForNode
++ // The cache is assumed to be single operation-thread-safe.
++ private Cache<Node, NodeId> node2id_Cache = null ;
++ private Cache<NodeId, Node> id2node_Cache = null ;
++
++ // A small cache of "known unknowns" to speed up searching for impossible
++ // things.
++ // Cache update needed on NodeTable changes because a node may become
++ // "known"
++ private CacheSet<Node> notPresent = null ;
++ private NodeTable baseTable ;
++ private final Object lock = new Object() ;
++
++ public static NodeTable create(NodeTable nodeTable, StoreParams params) {
++ int nodeToIdCacheSize = params.getNode2NodeIdCacheSize() ;
++ int idToNodeCacheSize = params.getNodeId2NodeCacheSize() ;
++ if ( nodeToIdCacheSize <= 0 && idToNodeCacheSize <= 0 )
++ return nodeTable ;
++ return new NodeTableCache(nodeTable, nodeToIdCacheSize, idToNodeCacheSize, params.getNodeMissCacheSize()) ;
++ }
++
++ public static NodeTable create(NodeTable nodeTable, int nodeToIdCacheSize, int idToNodeCacheSize, int nodeMissesCacheSize) {
++ if ( nodeToIdCacheSize <= 0 && idToNodeCacheSize <= 0 )
++ return nodeTable ;
++ return new NodeTableCache(nodeTable, nodeToIdCacheSize, idToNodeCacheSize, nodeMissesCacheSize) ;
++ }
++
++ private NodeTableCache(NodeTable baseTable, int nodeToIdCacheSize, int idToNodeCacheSize, int nodeMissesCacheSize) {
++ this.baseTable = baseTable ;
++ if ( nodeToIdCacheSize > 0 )
++ node2id_Cache = CacheFactory.createCache(nodeToIdCacheSize) ;
++ if ( idToNodeCacheSize > 0 )
++ id2node_Cache = CacheFactory.createCache(idToNodeCacheSize) ;
++ if ( nodeMissesCacheSize > 0 )
++ notPresent = CacheFactory.createCacheSet(nodeMissesCacheSize) ;
++ }
++
++ // ---- Cache access, no going to underlying table.
++
++ public Node getNodeForNodeIdCache(NodeId id) {
++ return id2node_Cache.getIfPresent(id) ;
++ }
++
++ public NodeId getNodeIdForNodeCache(Node node) {
++ return node2id_Cache.getIfPresent(node) ;
++ }
++
++ public boolean isCachedNodeId(NodeId id) {
++ return getNodeForNodeIdCache(id) != null ;
++ }
++
++ public boolean isCachedNode(Node node) {
++ return getNodeIdForNodeCache(node) != null ;
++ }
++
++ // ---- Cache access
++
++ @Override
++ public final NodeTable wrapped() {
++ return baseTable ;
++ }
++
++ /** Get the Node for this NodeId, or null if none */
++ @Override
++ public Node getNodeForNodeId(NodeId id) {
++ return _retrieveNodeByNodeId(id) ;
++ }
++
++ /** Find the NodeId for a node, or return NodeId.NodeDoesNotExist */
++ @Override
++ public NodeId getNodeIdForNode(Node node) {
++ return _idForNode(node, false) ;
++ }
++
++ /**
++ * Find the NodeId for a node, allocating a new NodeId if the Node does not
++ * yet have a NodeId
++ */
++ @Override
++ public NodeId getAllocateNodeId(Node node) {
++ return _idForNode(node, true) ;
++ }
++
++ @Override
++ public boolean containsNode(Node node) {
++ NodeId x = getNodeIdForNode(node) ;
++ return NodeId.isDoesNotExist(x) ;
++ }
++
++ @Override
++ public boolean containsNodeId(NodeId nodeId) {
++ Node x = getNodeForNodeId(nodeId) ;
++ return x == null ;
++ }
++
++ // If LRU cache is larger than the bulk unit, all allocated nodes are in the cache.
++// @Override
++// public List<NodeId> bulkNodeToNodeId(List<Node> nodes, boolean withAllocation) {
++// return NodeTable.super.bulkNodeToNodeId(nodes, withAllocation) ;
++// }
++//
++// @Override
++// public List<Node> bulkNodeIdToNode(List<NodeId> nodeIds) {
++// return NodeTable.super.bulkNodeIdToNode(nodeIds) ;
++// }
++
++ @Override
++ public List<NodeId> bulkNodeToNodeId(List<Node> required, boolean withAllocation) {
++ synchronized(lock) {
++ List<Node> nodes = new ArrayList<>() ;
++ for ( Node n : required ) {
++ //
++ if ( getNodeIdForNodeCache(n) == null )
++ nodes.add(n) ;
++ }
++ // Check bulk access.
++ List<NodeId> x = baseTable.bulkNodeToNodeId(nodes, true) ;
++ for ( int i = 0 ; i < nodes.size() ; i++ ) {
++ Node n = nodes.get(i) ;
++ NodeId nid = x.get(i) ;
++ cacheUpdate(n ,nid) ;
++ }
++ return x ;
++ }
++ }
++
++ @Override
++ public List<Node> bulkNodeIdToNode(List<NodeId> nodeIds) {
++ return NodeTableOps.bulkNodeIdToNodeImpl(this, nodeIds) ;
++ }
++
++ // ---- The worker functions
++ // NodeId ==> Node
++ private Node _retrieveNodeByNodeId(NodeId id) {
++ if ( NodeId.isDoesNotExist(id) )
++ return null ;
++ if ( NodeId.isAny(id) )
++ return null ;
++ // Try once outside the synchronized
++ // (Cache access is thread-safe)
++ Node n = cacheLookup(id) ;
++ if ( n != null )
++ return n ;
++
++ synchronized (lock) {
++ // Lock to update two caches consisently.
++ // Verify cache miss
++ n = cacheLookup(id) ;
++ if ( n != null )
++ return n ;
++
++ if ( baseTable == null )
++ System.err.println("" + this) ;
++
++ n = baseTable.getNodeForNodeId(id) ;
++ cacheUpdate(n, id) ;
++ return n ;
++ }
++ }
++
++ // Node ==> NodeId
++ private NodeId _idForNode(Node node, boolean allocate) {
++ if ( node == Node.ANY )
++ return NodeId.NodeIdAny ;
++ // Try once outside the synchronized
++ // (Cache access is thread-safe.)
++ NodeId nodeId = cacheLookup(node) ;
++ if ( nodeId != null )
++ return nodeId ;
++ synchronized (lock) {
++ // Update two caches inside synchronized.
++ // Check stil valid.
++ nodeId = cacheLookup(node) ;
++ if ( nodeId != null )
++ return nodeId ;
++
++ if ( allocate )
++ nodeId = baseTable.getAllocateNodeId(node) ;
++ else
++ nodeId = baseTable.getNodeIdForNode(node) ;
++ // Ensure caches have it. Includes recording "no such node"
++ cacheUpdate(node, nodeId) ;
++ return nodeId ;
++ }
++ }
++
++ // ----------------
++ // ---- Only places that the caches are touched
++
++ /**
++ * Check caches to see if we can map a NodeId to a Node. Returns null on no
++ * cache entry.
++ */
++ private Node cacheLookup(NodeId id) {
++ if ( id2node_Cache == null )
++ return null ;
++ return id2node_Cache.getIfPresent(id) ;
++ }
++
++ /**
++ * Check caches to see if we can map a Node to a NodeId. Returns null on no
++ * cache entry.
++ */
++ private NodeId cacheLookup(Node node) {
++ // Remember things known (currently) not to exist.
++ // Does not matter if notPresent is being updated elsewhere.
++ if ( notPresent != null && notPresent.contains(node) )
++ return null ;
++ if ( node2id_Cache == null )
++ return null ;
++ return node2id_Cache.getIfPresent(node) ;
++ }
++
++ /** Update the Node->NodeId caches */
++ private void cacheUpdate(Node node, NodeId id) {
++ if ( node == null )
++ return ;
++
++ // synchronized is further out.
++ // The "notPresent" cache is used to note whether a node
++ // is known not to exist.
++ // This must be specially handled later if the node is added.
++ if ( NodeId.isDoesNotExist(id) ) {
++ if ( notPresent != null )
++ notPresent.add(node) ;
++ return ;
++ }
++
++ if ( id == NodeId.NodeIdAny ) {
++ Log.warn(this, "Attempt to cache NodeIdAny - ignored") ;
++ return ;
++ }
++
++ if ( node2id_Cache != null )
++ node2id_Cache.put(node, id) ;
++ if ( id2node_Cache != null )
++ id2node_Cache.put(id, node) ;
++ // Remove if previously marked "not present"
++ if ( notPresent != null && notPresent.contains(node) )
++ notPresent.remove(node) ;
++ }
++
++ // ----
++
++ @Override
++ public boolean isEmpty() {
++ synchronized (lock) {
++ if ( node2id_Cache != null )
++ return node2id_Cache.isEmpty() ;
++ if ( id2node_Cache != null )
++ id2node_Cache.isEmpty() ;
++ // Write through.
++ return baseTable.isEmpty() ;
++ }
++ }
++
++ @Override
++ public synchronized void close() {
++ if ( baseTable == null )
++ // Already closed (NodeTables can be shared so .close via two
++ // routes).
++ return ;
++
++ baseTable.close() ;
++ node2id_Cache = null ;
++ id2node_Cache = null ;
++ notPresent = null ;
++ baseTable = null ;
++ }
++
++ @Override
++ public void sync() {
++ baseTable.sync() ;
++ }
++
++ @Override
++ public Iterator<Pair<NodeId, Node>> all() {
++ if ( false )
++ testForConsistency() ;
++ return baseTable.all() ;
++ }
++
++ private void testForConsistency() {
++ Iterator<Node> iter1 = Iter.toList(node2id_Cache.keys()).iterator() ;
++
++ for ( ; iter1.hasNext() ; ) {
++ Node n = iter1.next() ;
++
++ NodeId nId = node2id_Cache.getIfPresent(n) ;
++ if ( !id2node_Cache.containsKey(nId) )
++ throw new TDBException("Inconsistent: " + n + " => " + nId) ;
++ if ( notPresent.contains(n) )
++ throw new TDBException("Inconsistent: " + n + " in notPresent cache (1)") ;
++ }
++ Iterator<NodeId> iter2 = Iter.toList(id2node_Cache.keys()).iterator() ;
++ for ( ; iter2.hasNext() ; ) {
++ NodeId nId = iter2.next() ;
++ Node n = id2node_Cache.getIfPresent(nId) ;
++ if ( !node2id_Cache.containsKey(n) )
++ throw new TDBException("Inconsistent: " + nId + " => " + n) ;
++ if ( notPresent.contains(n) )
++ throw new TDBException("Inconsistent: " + n + " in notPresent cache (2)") ;
++ }
++
++ }
++
++ @Override
++ public String toString() {
++ return "Cache(" + baseTable.toString() + ")" ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableInline.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableInline.java
index 0000000,0000000..4632aa8
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableInline.java
@@@ -1,0 -1,0 +1,70 @@@
++/*
++ * 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.nodetable;
++
++
++import org.apache.jena.graph.Node ;
++import org.seaborne.tdb2.store.NodeId ;
++
++/** NodeTable wrapper to handle inline node ids.
++ * If a node can be made inline, then the underlying table never sees it.
++ * If an inline Nodeid is seen, it is decoded and returned without
++ * the underlying table being called.
++ */
++
++public class NodeTableInline extends NodeTableWrapper
++{
++ // Stack order: Inline > Cache > Actual
++
++ public static NodeTable create(NodeTable nodeTable)
++ {
++ return new NodeTableInline(nodeTable) ;
++ }
++
++ private NodeTableInline(NodeTable nodeTable)
++ {
++ super(nodeTable) ;
++ }
++
++ @Override
++ public final NodeId getAllocateNodeId(Node node)
++ {
++ NodeId nid = NodeId.inline(node) ;
++ if ( nid != null ) return nid ;
++ return super.getAllocateNodeId(node) ;
++ }
++
++ @Override
++ public final NodeId getNodeIdForNode(Node node)
++ {
++ NodeId nid = NodeId.inline(node) ;
++ if ( nid != null ) return nid ;
++ return super.getNodeIdForNode(node) ;
++ }
++ @Override
++ public final Node getNodeForNodeId(NodeId id)
++ {
++ Node n = NodeId.extract(id) ;
++ if ( n != null )
++ return n ;
++ return super.getNodeForNodeId(id) ;
++ }
++
++ @Override
++ public String toString() { return "Inline("+nodeTable.toString()+")" ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableNative.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableNative.java
index 0000000,0000000..8f7efdc
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableNative.java
@@@ -1,0 -1,0 +1,214 @@@
++/*
++ * 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.nodetable ;
++
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.apache.jena.atlas.lib.NotImplemented ;
++import org.apache.jena.atlas.lib.Pair ;
++import org.apache.jena.graph.Node ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.index.Index ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.lib.NodeLib ;
++import org.seaborne.tdb2.store.Hash ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.store.NodeIdFactory;
++
++/** A framework for a NodeTable based on native storage (string file and an index).
++ * This class manages the index, and delegates the node storage.
++ */
++public abstract class NodeTableNative implements NodeTable
++{
++ protected Index nodeHashToId ; // hash -> int
++ private boolean syncNeeded = false ;
++
++ public NodeTableNative(Index nodeToId) {
++ this.nodeHashToId = nodeToId ;
++ }
++ // ---- Public interface for Node <==> NodeId
++
++ /** Get the Node for this NodeId, or null if none */
++ @Override
++ public Node getNodeForNodeId(NodeId id)
++ {
++ return _retrieveNodeByNodeId(id) ;
++ }
++
++ /** Find the NodeId for a node, or return NodeId.NodeDoesNotExist */
++ @Override
++ public NodeId getNodeIdForNode(Node node) { return _idForNode(node, false) ; }
++
++ /** Find the NodeId for a node, allocating a new NodeId if the Node does not yet have a NodeId */
++ @Override
++ public NodeId getAllocateNodeId(Node node) { return _idForNode(node, true) ; }
++
++ @Override
++ public boolean containsNode(Node node) {
++ NodeId x = getNodeIdForNode(node) ;
++ return NodeId.isDoesNotExist(x) ;
++ }
++
++ @Override
++ public boolean containsNodeId(NodeId nodeId) {
++ Node x = getNodeForNodeId(nodeId) ;
++ return x == null ;
++ }
++
++ @Override
++ public List<NodeId> bulkNodeToNodeId(List<Node> nodes, boolean withAllocation) {
++ return NodeTableOps.bulkNodeToNodeIdImpl(this, nodes, withAllocation) ;
++ }
++
++ @Override
++ public List<Node> bulkNodeIdToNode(List<NodeId> nodeIds) {
++ return NodeTableOps.bulkNodeIdToNodeImpl(this, nodeIds) ;
++ }
++
++ // ---- The worker functions
++ // Synchronization:
++ // accessIndex and readNodeFromTable
++
++ // Cache around this class further out in NodeTableCache are synchronized
++ // to maintain cache validatity which indirectly sync access to the NodeTable.
++ // But to be sure, we provide MRSW guarantees on this class.
++ // (otherwise if no cache => disaster)
++ // synchonization happens in accessIndex() and readNodeByNodeId
++
++ // NodeId to Node worker.
++ private Node _retrieveNodeByNodeId(NodeId id)
++ {
++ if ( NodeId.isDoesNotExist(id) )
++ return null ;
++ if ( NodeId.isAny(id) )
++ return null ;
++ synchronized (this) {
++ Node n = readNodeFromTable(id) ;
++ return n ;
++ }
++ }
++
++ // ----------------
++
++ // Node to NodeId worker
++ // Find a node, possibly placing it in the node file as well
++ private NodeId _idForNode(Node node, boolean allocate)
++ {
++ if ( node == Node.ANY )
++ return NodeId.NodeIdAny ;
++
++ // synchronized in accessIndex
++ NodeId nodeId = accessIndex(node, allocate) ;
++ return nodeId ;
++ }
++
++ protected final NodeId accessIndex(Node node, boolean create)
++ {
++ Hash hash = new Hash(nodeHashToId.getRecordFactory().keyLength()) ;
++ NodeLib.setHash(hash, node) ;
++ byte k[] = hash.getBytes() ;
++ // Key only.
++ Record r = nodeHashToId.getRecordFactory().create(k) ;
++
++ synchronized (this) // Pair to readNodeFromTable.
++ {
++ // Key and value, or null
++ Record r2 = nodeHashToId.find(r) ;
++ if ( r2 != null )
++ {
++ // Found. Get the NodeId.
++ NodeId id = NodeIdFactory.get(r2.getValue(), 0) ;
++ return id ;
++ }
++
++ // Not found.
++ if ( ! create )
++ return NodeId.NodeDoesNotExist ;
++ // Write the node, which allocates an id for it.
++ syncNeeded = true ;
++ NodeId id = writeNodeToTable(node) ;
++
++ // Update the r record with the new id.
++ // r.value := id bytes ;
++ NodeIdFactory.set(id, r.getValue(), 0) ;
++
++ // Put in index - may appear because of concurrency
++ if ( ! nodeHashToId.insert(r) )
++ throw new TDBException("NodeTableBase::nodeToId - record mysteriously appeared") ;
++ return id ;
++ }
++ }
++
++ // -------- NodeId<->Node
++ // Synchronization:
++ // write: in accessIndex
++ // read: in _retrieveNodeByNodeId
++ // Only places for accessing the StringFile.
++
++ abstract protected NodeId writeNodeToTable(Node node) ;
++ abstract protected Node readNodeFromTable(NodeId id) ;
++ abstract protected void syncSub() ;
++ abstract protected void closeSub() ;
++
++ // -------- NodeId<->Node
++
++ @Override
++ public synchronized void close()
++ {
++ // Close once. This may be shared (e.g. triples table and quads table).
++ if ( nodeHashToId != null )
++ {
++ nodeHashToId.close() ;
++ closeSub() ;
++ nodeHashToId = null ;
++ }
++ }
++
++ // Not synchronized
++ @Override
++ public Iterator<Pair<NodeId, Node>> all() { return all2() ; }
++
++ private Iterator<Pair<NodeId, Node>> all2()
++ {
++ throw new NotImplemented() ;
++ }
++
++ @Override
++ public void sync()
++ {
++ if ( syncNeeded )
++ {
++ syncSub() ;
++ if ( nodeHashToId != null )
++ nodeHashToId.sync() ;
++ syncNeeded = false ;
++ }
++ }
++
++ @Override
++ public boolean isEmpty()
++ {
++ return nodeHashToId.isEmpty() ;
++ }
++
++ @Override
++ public NodeTable wrapped() {
++ return null ;
++ }
++}
[47/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/MetaFile.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/MetaFile.java
index 0000000,0000000..bbe3221
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/MetaFile.java
@@@ -1,0 -1,0 +1,364 @@@
++/*
++ * 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.dboe.base.file;
++
++import java.io.* ;
++import java.util.* ;
++
++import org.apache.jena.atlas.lib.* ;
++import org.apache.jena.atlas.lib.Closeable ;
++import org.seaborne.dboe.DBOpEnvException ;
++import org.seaborne.dboe.sys.Names ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/** Abstraction and many convenience operations on metadata.
++ * Metadata is recorded in Java properties style - not RDF - because it's relative to the file or context used.
++ * Keys and values are always strings.
++ */
++public class MetaFile implements Sync, Closeable
++{
++ private static Comparator<String> comparator = new ComparatorKeys() ;
++ private static Logger log = LoggerFactory.getLogger(MetaFile.class) ;
++ private String metaFilename = null ;
++ private Properties properties = null ;
++ private String label = null ;
++ private boolean changed = false ;
++ private boolean closed = false ;
++
++ /** Create a MetaFile
++ *
++ * @param label Convenience label.
++ * @param fn On disk filename; {@link Names#memName} for in-memory
++ */
++ public MetaFile(String label, String fn)
++ {
++ this.label = label ;
++ this.metaFilename = fn ;
++
++ if ( fn == null || Names.isMem(fn) )
++ // In-memory.
++ return ;
++
++ // Make absolute (current directory may change later)
++ if ( ! fn.endsWith(Names.extMeta) )
++ fn = fn+"."+Names.extMeta ;
++ File f = new File(fn) ;
++ this.metaFilename = f.getAbsolutePath() ;
++ // Does not load the details yet.
++ // JDI
++ ensureInit() ;
++ }
++
++ private void ensureInit()
++ {
++ if ( properties == null )
++ {
++ properties = new PropertiesSorted(comparator) ;
++ if ( metaFilename != null )
++ loadProperties() ;
++ }
++ }
++
++ /** Does this metafile exist on disk? (In-memory MetaFiles always exist) */
++ public boolean existsMetaData()
++ {
++ if ( isMem() )
++ return true ;
++ File f = new File(metaFilename) ;
++ if ( f.isDirectory() )
++ log.warn("Metadata file clashes with a directory") ;
++ return f.exists() && f.isFile() ;
++ }
++
++ public String getFilename() { return metaFilename ; }
++
++ /** Test for the presence of a property */
++ public boolean hasProperty(String key)
++ {
++ return _getProperty(key, null) != null ;
++ }
++
++ /** Get the property value or null. */
++ public String getProperty(String key)
++ {
++ return _getProperty(key, null) ;
++ }
++
++ /** Get the property value or return supplied default. */
++ public String getProperty(String key, String defaultString)
++ {
++ return _getProperty(key, defaultString) ;
++ }
++
++ /** Get the property value and parse as an integer */
++ public int getPropertyAsInteger(String key)
++ {
++ return Integer.parseInt(_getProperty(key, null)) ;
++ }
++
++ /** Get the property value and parse as an integer or return default value. */
++ public int getPropertyAsInteger(String key, int defaultValue)
++ {
++ String x = getProperty(key) ;
++ if ( x == null )
++ return defaultValue ;
++ return Integer.parseInt(x) ;
++ }
++
++ /** Get property as a string and split on ",". */
++ public String[] getPropertySplit(String key)
++ {
++ String str = getProperty(key) ;
++ if ( str == null )
++ return null ;
++ return str.split(",") ;
++ }
++
++ /** Get property as a string and split on ",", using the default string if not present in the MetaFile. */
++ public String[] getPropertySplit(String key, String defaultString)
++ {
++ String str = getProperty(key, defaultString) ;
++ return str.split(",") ;
++ }
++
++ /** Set property */
++ public void setProperty(String key, String value)
++ {
++ _setProperty(key, value) ;
++ }
++
++ /** Set property, turning integer into a string. */
++ public void setProperty(String key, int value)
++ {
++ _setProperty(key, Integer.toString(value)) ;
++ }
++
++ /** Test whether a property has a value. Null tests equal to not present. */
++ public boolean propertyEquals(String key, String value)
++ {
++ return Objects.equals(getProperty(key), value) ;
++ }
++
++ /** Set property if not already set. */
++ public void ensurePropertySet(String key, String expected)
++ {
++ getOrSetDefault(key, expected) ;
++ }
++
++ /** Get property or the default value - also set the default value if not present */
++ public String getOrSetDefault(String key, String expected)
++ {
++ String x = getProperty(key) ;
++ if ( x == null )
++ {
++ setProperty(key, expected) ;
++ x = expected ;
++ }
++ return x ;
++ }
++
++ /** Check property is an expected value or set if missing */
++ public void checkOrSetMetadata(String key, String expected)
++ {
++ String x = getProperty(key) ;
++ if ( x == null )
++ {
++ setProperty(key, expected) ;
++ return ;
++ }
++ if ( x.equals(expected) )
++ return ;
++
++ inconsistent(key, x, expected) ;
++ }
++
++ /** Check property has the value given - throw exception if not. */
++ public void checkMetadata(String key, String expected)
++ {
++ String value = getProperty(key) ;
++
++ if ( !Objects.equals(value, value) )
++ inconsistent(key, value, expected) ;
++ }
++
++ private static void inconsistent(String key, String actual, String expected)
++ {
++ String msg = String.format("Inconsistent: key=%s value=%s expected=%s",
++ key,
++ (actual==null?"<null>":actual),
++ (expected==null?"<null>":expected) ) ;
++ throw new MetaFileException(msg) ;
++ }
++
++ /** Clear all properties. */
++ public void clear()
++ {
++ _clear() ;
++ }
++
++ // ---- All get/set access through these operations
++ private String _getProperty(String key, String dft)
++ {
++ ensureInit() ;
++ return properties.getProperty(key, dft) ;
++ }
++
++ private void _setProperty(String key, String value)
++ {
++ ensureInit() ;
++ properties.setProperty(key, value) ;
++ changedEvent() ;
++ }
++
++ /** Clear all properties. */
++ private void _clear()
++ {
++ ensureInit() ;
++ properties.clear() ;
++ changedEvent() ;
++ }
++
++ private void changedEvent() { changed = true ; }
++ // ----
++
++ private boolean isMem() { return Names.isMem(metaFilename) ; }
++
++ /** Write to backing file if changed */
++ public void flush()
++ {
++ if ( log.isDebugEnabled() )
++ log.debug("Flush metadata ("+changed+"): "+this.label) ;
++ if ( ! changed )
++ return ;
++
++
++ if ( log.isDebugEnabled() )
++ {
++ ByteArrayOutputStream out = new ByteArrayOutputStream() ;
++ PrintStream ps = new PrintStream(out) ;
++ properties.list(ps) ;
++ ps.flush() ;
++ log.debug("\n"+out.toString()) ;
++ }
++
++ //properties.list(System.out) ;
++
++ saveProperties() ;
++ changed = false ;
++ }
++
++ private void saveProperties()
++ {
++ if ( isMem() )
++ return ;
++ String str = label ;
++ if ( str == null )
++ str = metaFilename ;
++ str = "Metadata: "+str ;
++
++ try {
++ PropertyUtils.storeToFile(properties, str, metaFilename) ;
++ }
++ catch (IOException ex)
++ {
++ log.error("Failed to store properties: "+metaFilename, ex) ;
++ }
++ }
++
++
++ private void loadProperties()
++ {
++ if ( isMem() )
++ {
++ properties = new Properties() ;
++ return ;
++ }
++
++ if ( properties == null )
++ properties = new Properties() ;
++
++ // if ( metaFilename == null )
++ InputStream in = null ;
++ try {
++ // Copes with UTF-8 for Java5.
++ PropertyUtils.loadFromFile(properties, metaFilename) ;
++ }
++ catch (FileNotFoundException ex) {}
++ catch (IOException ex)
++ {
++ log.error("Failed to load properties: "+metaFilename, ex) ;
++ }
++ }
++
++ /** Debugging */
++ public void dump(PrintStream output)
++ {
++ output.println("Metafile: "+metaFilename) ;
++ output.println("Label: "+label) ;
++ output.println("Status: "+(changed?"changed":"unchanged")) ;
++
++ if ( properties == null )
++ {
++ output.println("#<null>") ;
++ return ;
++ }
++ // properties.list() ;
++ SortedSet<Object> x = new TreeSet<>() ;
++ x.addAll(properties.keySet()) ;
++
++ for ( Object k : x )
++ {
++ String key = (String)k ;
++ String value = properties.getProperty(key) ;
++ output.print(key) ;
++ output.print("=") ;
++ output.print(value) ;
++ output.println() ;
++ }
++ }
++
++ @Override
++ public void sync() { flush() ; }
++
++ @Override
++ public void close()
++ {
++ flush() ;
++ closed = true ;
++ metaFilename = null ;
++ properties = null ;
++
++ }
++
++ private static class ComparatorKeys implements Comparator<String>
++ {
++ @Override
++ public int compare(String o1, String o2)
++ {
++ return - o1.compareTo(o2) ;
++ }
++
++ }
++
++ private static class MetaFileException extends DBOpEnvException
++ {
++ MetaFileException(String msg) { super(msg) ; }
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/ProcessFileLock.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/ProcessFileLock.java
index 0000000,0000000..990dcab
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/ProcessFileLock.java
@@@ -1,0 -1,0 +1,215 @@@
++/*
++ * 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.dboe.base.file;
++
++import static java.nio.file.StandardOpenOption.CREATE;
++import static java.nio.file.StandardOpenOption.DSYNC;
++import static java.nio.file.StandardOpenOption.READ;
++import static java.nio.file.StandardOpenOption.WRITE;
++
++import java.io.FileNotFoundException;
++import java.io.IOException;
++import java.nio.ByteBuffer;
++import java.nio.channels.FileChannel;
++import java.nio.channels.FileLock;
++import java.nio.file.NoSuchFileException;
++import java.nio.file.Path;
++import java.nio.file.Paths;
++import java.util.concurrent.ConcurrentHashMap;
++
++import org.apache.jena.atlas.RuntimeIOException;
++import org.apache.jena.atlas.io.IO;
++import org.apache.jena.atlas.lib.StrUtils;
++import org.apache.jena.atlas.logging.Log;
++import org.seaborne.dboe.DBOpEnvException;
++import org.seaborne.dboe.sys.ProcessUtils;
++
++/** A simple packaging around a {@link java.nio.channels.FileLock}.
++ * {@code ProcessFileLock} are not reentrant.
++ */
++public class ProcessFileLock {
++
++ // Static (process-wide) sync.
++ private static Object sync = new Object();
++
++ // Map from path of the file to a ProcessFileLock
++ private static ConcurrentHashMap<Path, ProcessFileLock> locks = new ConcurrentHashMap<>();
++
++ private final Path filepath;
++ private final FileChannel fileChannel;
++ private FileLock fileLock;
++
++ // Different variations for what to do when a lock can not be taken.
++ private enum NoLockAction { EXCEPTION, RETURN, WAIT }
++
++ /** Create a {@code ProcessFileLock} using the named file.
++ * Locks are JVM-wide; each filename is assocauted with one lock object.
++ */
++ public static ProcessFileLock create(String filename) {
++ try {
++ Path abspath = Paths.get(filename).toRealPath();
++ return locks.computeIfAbsent(abspath, ProcessFileLock::new);
++ }
++ catch (IOException e) { IO.exception(e); return null; }
++ }
++
++ /** Return the lock, unlocking the file if this process has it locked. */
++ public static void release(ProcessFileLock lockFile) {
++ if ( lockFile == null )
++ return ;
++ if ( lockFile.isLockedHere() )
++ lockFile.unlock();
++ locks.remove(lockFile.getPath());
++ }
++ /** Create the structure for a ProcessFileLock on file {@code filename}.
++ * This does not take the lock
++ *
++ * @see #lockEx()
++ * @see #tryLock()
++ * @see #unlock()
++ */
++ private ProcessFileLock(Path filename) {
++ try {
++ this.filepath = filename ;
++ // Much the same as ...
++// randomAccessFile = new RandomAccessFile(filename, "rw");
++// fileChannel = randomAccessFile.getChannel();
++ // Quite heavy weight but only used to lock long-term objects.
++ this.fileChannel = FileChannel.open(filename, CREATE, WRITE, READ, DSYNC);
++ fileLock = null;
++ }
++ catch (NoSuchFileException | FileNotFoundException ex) {
++ // The path does not name a possible file in an exists directory.
++ throw new RuntimeIOException("No such file '"+filename+"'", ex);
++ }
++ catch (IOException ex) {
++ throw new RuntimeIOException("Failed to open '"+filename+"'", ex);
++ }
++ }
++
++ /** Lock the file or throw {@link DBOpEnvException} */
++ public void lockEx() {
++ lockOperation(NoLockAction.EXCEPTION);
++ }
++
++ /** Lock the file or wait. */
++ public void lockWait() {
++ lockOperation(NoLockAction.EXCEPTION);
++ }
++
++ /** Lock a file, return true on success else false. */
++ public boolean tryLock() {
++ return lockOperation(NoLockAction.RETURN);
++ }
++
++ /** Release the lock - this must be paired with a "lock" operation. */
++ public void unlock() {
++ synchronized(sync) {
++ try {
++ fileLock.release();
++ } catch (IOException ex) { throw new RuntimeIOException("Failed to unlock '"+filepath+"'", ex); }
++ }
++ }
++
++ /** Return true if this process holds the lock. */
++ public boolean isLockedHere() {
++ if ( fileLock == null )
++ return false;
++ return fileLock.isValid();
++ }
++
++ public Path getPath() {
++ return filepath;
++ }
++
++ /** Take the lock.
++ * <p>
++ * Write our PID into the file and return true if it succeeds.
++ * <p>
++ * Try to get the existing PID if it fails.
++ */
++ private boolean lockOperation(NoLockAction action) {
++ synchronized(sync) {
++ if ( fileLock != null )
++ throw new AlreadyLocked("Failed to get a lock: file='"+filepath+"': Lock already held");
++
++ try {
++ fileLock = (action == NoLockAction.WAIT) ? fileChannel.lock() : fileChannel.tryLock();
++ if ( fileLock == null ) {
++ if ( action == NoLockAction.RETURN )
++ return false ;
++ // Read without the lock.
++ // This isn't perfect but it is only providing helpful information.
++ int pid = readProcessId(-99);
++ if ( pid >= 0 )
++ throw new DBOpEnvException("Failed to get a lock: file='"+filepath+"': held by process "+pid);
++ throw new DBOpEnvException("Failed to get a lock: file='"+filepath+"': failed to get the holder's process id");
++ }
++ // Got the lock. Record our process id.
++ int pid = ProcessUtils.getPid(-1);
++ writeProcessId(pid);
++ return true;
++ } catch (IOException ex) {
++ if ( action == NoLockAction.RETURN )
++ return false;
++ throw new DBOpEnvException("Failed to get a lock: file='"+filepath+"'", ex);
++ }
++ }
++ }
++
++ // I/O for a process id.
++ /** Read the file to get a process id */
++ private int readProcessId(int dft) throws IOException {
++ ByteBuffer bb = ByteBuffer.allocate(128);
++ fileChannel.position(0);
++ int len = fileChannel.read(bb);
++ fileChannel.position(0);
++ if ( len == 0 )
++ return dft;
++ if ( len == 128 )
++ // Too much.
++ return dft;
++ // Bug in Jena 3.3.0
++ //byte[] b = ByteBufferLib.bb2array(bb, 0, len);
++ bb.flip();
++ byte[] b = new byte[len];
++ bb.get(b);
++
++ String pidStr = StrUtils.fromUTF8bytes(b);
++ // Remove all leadign and trailing (vertical and horizontal) whitespace.
++ pidStr = pidStr.replaceAll("[\\s\\t\\n\\r]+$", "");
++ pidStr = pidStr.replaceAll("^[\\s\\t\\n\\r]+", "");
++ try {
++ // Process id.
++ return Integer.parseInt(pidStr);
++ } catch (NumberFormatException ex) {
++ ex.printStackTrace();
++ Log.warn(this, "Bad process id: file='"+filepath+"': read='"+pidStr+"'");
++ return dft;
++ }
++ }
++
++ /** Write the process id to the file. */
++ private void writeProcessId(int pid) throws IOException {
++ byte b[] = StrUtils.asUTF8bytes(Integer.toString(pid)+"\n");
++ fileChannel.truncate(0);
++ int len = fileChannel.write(ByteBuffer.wrap(b));
++ fileChannel.position(0);
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/SegmentedMemBuffer.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/SegmentedMemBuffer.java
index 0000000,0000000..abe06fd
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/file/SegmentedMemBuffer.java
@@@ -1,0 -1,0 +1,279 @@@
++/*
++ * 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.dboe.base.file;
++
++import java.nio.ByteBuffer ;
++import java.util.ArrayList ;
++import java.util.List ;
++
++import org.apache.jena.atlas.io.IO ;
++import org.apache.jena.atlas.lib.ByteBufferLib ;
++import org.apache.jena.atlas.logging.FmtLog ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/** A segmented, expanding buffer of bytes.
++ * This class does not copy the underlying bytes when the file grows.
++ * Hence, the performance is more predictable.
++ * (Resizing a fixed size buffer is a copy c.f. performance issues with
++ * {@code ArrayList} or {@code ByteArrayOutputStream}
++ * as they go from small to large.
++ */
++public class SegmentedMemBuffer {
++ private static Logger log = LoggerFactory.getLogger(SegmentedMemBuffer.class) ;
++
++ // See java.nio.channels.FileChannel
++ private static int DFT_CHUNK = 1024*1024 ;
++ private static int DFT_SEGMENTS = 1000 ;
++ private final int CHUNK ;
++ // The file pointer and marker of the allocated end point.
++ private long dataLength = 0 ;
++ private List<byte[]> space = null ;
++ private boolean isOpen ;
++ private final boolean TRACKING = false ;
++
++ public SegmentedMemBuffer() { this(DFT_CHUNK) ; }
++
++ public SegmentedMemBuffer(int chunk) {
++ this.CHUNK = chunk ;
++ space = new ArrayList<>(DFT_SEGMENTS) ;
++ // "Auto open"
++ isOpen = true ;
++ }
++
++ public void open() {
++ isOpen = true ;
++// if ( storage != null )
++// throw new RuntimeIOException("Already open") ;
++// storage = new ArrayList<>(DFT_SEGMENTS) ;
++ }
++
++ public boolean isOpen() {
++ return space != null ;
++ }
++
++ public int read(long posn, ByteBuffer bb) {
++ if ( TRACKING )
++ log("read<<%s", ByteBufferLib.details(bb));
++ checkOpen() ;
++ checkPosition(posn) ;
++ int len = bb.remaining() ;
++ if ( posn+dataLength > dataLength )
++ len = (int)(dataLength-posn) ;
++ arrayCopyOut(space, posn, bb);
++ return len ;
++ }
++
++ public int read(long posn, byte[] b) {
++ if ( TRACKING )
++ log("read<<[%d]", b.length) ;
++ return read$(posn, b, 0, b.length) ;
++ }
++
++ public int read(long posn, byte[] b, int start, int length) {
++ if ( TRACKING )
++ log("read<<[%d],%s,%s", b.length, start, length) ;
++ return read$(posn, b, start, length) ;
++ }
++
++ private int read$(long posn, byte[] b, int start, int length) {
++ checkOpen() ;
++ if ( posn >= dataLength )
++ return -1 ;
++ checkPosition(posn) ;
++ if ( length == 0 )
++ return 0 ;
++ checkByteArray(b, start, length) ;
++ int len = length ;
++ if ( posn+length > dataLength )
++ len = (int)(dataLength-posn) ;
++ arrayCopyOut(space, posn, b, start, len) ;
++ return len ;
++ }
++
++ public void write(long posn, ByteBuffer bb ) {
++ if ( TRACKING )
++ log("read<<%s", ByteBufferLib.details(bb));
++ checkOpen() ;
++ if ( posn != dataLength )
++ checkPosition(posn) ;
++ arrayCopyIn(bb, space, posn) ;
++ }
++
++ public void write(long posn, byte[] b ) {
++ if ( TRACKING )
++ log("read<<[%d]", b.length) ;
++ write$(posn, b, 0, b.length) ;
++ }
++
++ public void write(long posn, byte[] b, int start, int length) {
++ if ( TRACKING )
++ log("read<<[%d],%d,%d", b.length, start, length) ;
++ write$(posn, b, start, length);
++ }
++
++ private void write$(long posn, byte[] b, int start, int length) {
++ checkOpen() ;
++ checkPosition(posn) ;
++ if ( length == 0 )
++ return ;
++ checkByteArray(b,start,length) ;
++ arrayCopyIn(b, start, space, dataLength, length) ;
++ }
++
++ public void truncate(long length) {
++ if ( TRACKING )
++ log("truncate(%d)", length) ;
++ if ( length < 0 )
++ IO.exception(String.format("truncate: bad length : %d", length)) ;
++ checkOpen() ;
++ dataLength = Math.min(dataLength, length) ;
++ // clear above?
++ }
++
++ public void sync() {
++ checkOpen() ;
++ }
++
++ public void close() {
++ if ( ! isOpen() )
++ return ;
++ isOpen = false ;
++ space.clear() ;
++ space = null ;
++ }
++
++ public long length() {
++ return dataLength ;
++ }
++
++ private void checkOpen() {
++ if ( ! isOpen )
++ IO.exception("Not open") ;
++ }
++
++ private void checkPosition(long posn) {
++ // Allows posn to be exactly the byte beyond the end
++ if ( posn < 0 || posn > dataLength )
++ IO.exception(String.format("Position out of bounds: %d in [0,%d]", posn, dataLength)) ;
++ }
++
++ private void checkByteArray(byte[] b, int start, int length) {
++ if ( start < 0 || start >= b.length )
++ IO.exception(String.format("Start point out of bounds of byte array: %d in [0,%d)", start, b.length)) ;
++ if ( length < 0 || start+length > b.length )
++ IO.exception(String.format("Start/length out of bounds of byte array: %d/%d in [0,%d)", start, length, b.length)) ;
++ }
++
++ private int getSegment(long posn) { return (int)(posn / CHUNK) ; }
++
++ private int getOffset(long posn) { return (int) (posn % CHUNK) ; }
++
++ // c.f. System.arrayCopy
++ private void arrayCopyIn(byte[] src, final int srcStart, List<byte[]> dest, final long destStart, final int length) {
++ if ( length == 0 )
++ return ;
++ int len = length ;
++ int srcPosn = srcStart ;
++ int seg = getSegment(destStart) ;
++ int offset = getOffset(destStart) ;
++ while( len > 0 ) {
++ int z = Math.min(len, CHUNK-offset) ;
++ // Beyond end of file?
++ if ( seg >= dest.size() ) {
++ byte[] buffer = new byte[CHUNK] ;
++ space.add(buffer) ;
++ }
++ System.arraycopy(src, srcPosn, dest.get(seg), offset, z);
++ srcPosn += z ;
++ len -= z ;
++ seg += 1 ;
++ offset += z ;
++ offset %= CHUNK ;
++ }
++ dataLength = Math.max(dataLength, destStart+length) ;
++ }
++
++ private void arrayCopyOut(List<byte[]> src, final long srcStart, byte[] dest, final int destStart, final int length) {
++ int len = length ;
++ len = Math.min(len, (int)(dataLength-srcStart)) ;
++ int dstPosn = destStart ;
++ int seg = getSegment(srcStart) ;
++ int offset = getOffset(srcStart) ;
++ while( len > 0 ) {
++ int z = Math.min(len, CHUNK-offset) ;
++ System.arraycopy(src.get(seg), offset, dest, dstPosn, z);
++ dstPosn += z ;
++ len -= z ;
++ seg += 1 ;
++ offset += z ;
++ offset %= CHUNK ;
++ }
++ }
++
++ private void arrayCopyIn(ByteBuffer bb, List<byte[]> dest, long destStart) {
++ if ( bb.remaining() == 0 )
++ return ;
++ int length = bb.remaining() ;
++ int len = bb.remaining() ;
++ int srcPosn = bb.position() ;
++ int seg = getSegment(destStart) ;
++ int offset = getOffset(destStart) ;
++ while( len > 0 ) {
++ int z = Math.min(len, CHUNK-offset) ;
++ // Beyond end of file?
++ if ( seg >= dest.size() ) {
++ byte[] buffer = new byte[CHUNK] ;
++ space.add(buffer) ;
++ }
++ byte[] bytes = dest.get(seg) ;
++ bb.get(bytes, offset, z) ;
++ srcPosn += z ;
++ len -= z ;
++ seg += 1 ;
++ offset += z ;
++ offset %= CHUNK ;
++ }
++ dataLength = Math.max(dataLength, destStart+length) ;
++ }
++
++ private void arrayCopyOut(List<byte[]> src, long srcStart, ByteBuffer bb) {
++ int len = bb.remaining() ;
++ len = Math.min(len, (int)(dataLength-srcStart)) ;
++ int dstPosn = bb.position() ;
++ int seg = getSegment(srcStart) ;
++ int offset = getOffset(srcStart) ;
++ while( len > 0 ) {
++ int z = Math.min(len, CHUNK-offset) ;
++ byte[] bytes = src.get(seg) ;
++ bb.put(bytes, offset, z) ;
++ dstPosn += z ;
++ len -= z ;
++ seg += 1 ;
++ offset += z ;
++ offset %= CHUNK ;
++ }
++ }
++
++ private void log(String fmt, Object... args) {
++ if ( TRACKING )
++ FmtLog.debug(log, fmt, args);
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/page/BlockConverter.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/page/BlockConverter.java
index 0000000,0000000..d77165c
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/page/BlockConverter.java
@@@ -1,0 -1,0 +1,34 @@@
++/*
++ * 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.dboe.base.page;
++
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.base.block.BlockType ;
++
++/** Convert between Blocks and typed Pages */
++public interface BlockConverter<T extends Page>
++{
++ /** Create a T, given an existing Block */
++ public T fromBlock(Block block) ;
++
++ /** Make a block, given a T */
++ public Block toBlock(T t) ;
++
++ /** Create a new T from an uninitialized Block */
++ public T createFromBlock(Block block, BlockType bType) ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/page/Page.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/page/Page.java
index 0000000,0000000..02dca0b
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/page/Page.java
@@@ -1,0 -1,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.dboe.base.page;
++
++import org.apache.jena.atlas.io.Printable ;
++import org.seaborne.dboe.base.block.Block ;
++
++public interface Page extends Printable
++{
++ public static final int NO_ID = -1 ;
++
++ /** Pages are addressed ints (a page ref does in on-disk blocks)
++ * although block are address in longs
++ */
++ public int getId() ;
++
++ /** Return a string for display that identifies this Page */
++ public String getRefStr() ;
++
++ /** Return the block associated with this page */
++ public Block getBackingBlock() ;
++
++ /**
++ * The underlying block for this page has changed (e.g. it's been
++ * promoted and the promotion may have caused the block to change.
++ */
++ public abstract void reset(Block block) ;
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/page/PageBase.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/page/PageBase.java
index 0000000,0000000..ff1f5db
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/page/PageBase.java
@@@ -1,0 -1,0 +1,57 @@@
++/*
++ * 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.dboe.base.page;
++
++import org.seaborne.dboe.DBOpEnvException ;
++import org.seaborne.dboe.base.block.Block ;
++
++/** A page with a byte buffer */
++public abstract class PageBase implements Page
++{
++ private int id ;
++ private Block block ;
++
++ protected PageBase(Block block)
++ {
++ this.block = block ;
++ long x = block.getId() ;
++ if ( x < 0 )
++ throw new DBOpEnvException("Page id is negative: "+x) ;
++ if ( x > Integer.MAX_VALUE )
++ throw new DBOpEnvException("Page id is large than MAX_INT: "+x) ;
++ this.id = block.getId().intValue() ;
++ }
++
++ @Override
++ final public void reset(Block block2)
++ {
++// if ( block2.getId() != id )
++// Log.warn(this, "Block id changed: "+id+" => "+block2.getId()) ;
++ id = block2.getId().intValue() ;
++ _reset(block2) ;
++ this.block = block2 ;
++ }
++
++ protected abstract void _reset(Block block) ;
++
++ @Override
++ final public Block getBackingBlock() { return block ; }
++
++ @Override
++ final public int getId() { return id ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/page/PageBlockMgr.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/page/PageBlockMgr.java
index 0000000,0000000..533d6d9
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/page/PageBlockMgr.java
@@@ -1,0 -1,0 +1,212 @@@
++/*
++ * 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.dboe.base.page;
++
++import org.apache.jena.atlas.lib.Closeable ;
++import org.apache.jena.atlas.lib.InternalErrorException ;
++import org.apache.jena.atlas.logging.Log ;
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.block.BlockType ;
++
++/** Engine that wraps from blocks to typed pages. */
++
++public class PageBlockMgr<T extends Page> implements Closeable
++{
++ protected final BlockMgr blockMgr ;
++ protected BlockConverter<T> pageFactory ;
++
++ protected PageBlockMgr(BlockConverter<T> pageFactory, BlockMgr blockMgr) {
++ this.pageFactory = pageFactory ;
++ this.blockMgr = blockMgr ;
++ }
++
++ // Sometimes, the subclass must pass null to the constructor then call this.
++ protected void setConverter(BlockConverter<T> pageFactory) { this.pageFactory = pageFactory ; }
++
++ public BlockMgr getBlockMgr() { return blockMgr ; }
++
++ public long allocLimit() { return blockMgr.allocLimit() ; }
++
++ public void resetAlloc(long boundary) {
++ blockMgr.resetAlloc(boundary) ;
++ }
++
++ /** Allocate a new thing */
++ public T create(BlockType bType) {
++ Block block = blockMgr.allocate(-1) ;
++ block.setModified(true) ;
++ T page = pageFactory.createFromBlock(block, bType) ;
++ return page ;
++ }
++
++ /**
++ * Fetch a block for reading.
++ * @param id Block to fetch
++ */
++ public T getRead(int id) {
++ return getRead$(id) ;
++ }
++
++ /**
++ * Fetch a block for reading.
++ *
++ * @param id Block to fetch
++ * @param referencingId
++ * Id of block referring to this one.
++ * For example, a parent in a tree.
++ * May be negative for "none" or "meaningless".
++ */
++ public T getRead(int id, int referencingId) {
++ return getRead$(id) ;
++ }
++
++ /**
++ * Fetch a block for writing.
++ * @param id Block to fetch
++ */
++ public T getWrite(int id) {
++ return getWrite$(id) ;
++ }
++
++ /**
++ * Fetch a block for writing.
++ *
++ * @param id Block to fetch
++ * @param referencingId
++ * Id of block referring to this one.
++ * For example, a parent in a tree.
++ * May be -1 for "none" or "meaningless".
++ */
++ public T getWrite(int id, int referencingId) {
++ return getWrite$(id) ;
++ }
++
++ // ---- The read and write worker operations.
++
++ final protected T getRead$(int id) {
++ Block block = blockMgr.getRead(id) ;
++ // Blocks from the BlockMgrCache may be write-dirty so this test
++ // is wrong in that situation. It is better to use the block as-is
++ // otherwise we'd have two blocks of a given id with different flags
++ // that confuse the block caching.
++// if ( block.isModified() ) {
++// System.err.println("getRead - isModified - "+blockMgr.getLabel()+"["+id+"]") ;
++//// block = new Block(block.getId(), block.getByteBuffer());
++//// block.setModified(false);
++// // Debug.
++// //blockMgr.getRead(id) ;
++// }
++ T page = pageFactory.fromBlock(block) ;
++ return page ;
++ }
++
++ final protected T getWrite$(int id) {
++ Block block = blockMgr.getWrite(id) ;
++ block.setReadOnly(false) ;
++ T page = pageFactory.fromBlock(block) ;
++ return page ;
++ }
++
++ // ----
++
++ public void put(T page) {
++ write(page) ;
++ release(page) ;
++ }
++
++ public void write(T page) {
++ Block blk = pageFactory.toBlock(page) ;
++ blockMgr.write(blk) ;
++ }
++
++ public void release(Page page) {
++ Block block = page.getBackingBlock() ;
++ blockMgr.release(block) ;
++ }
++
++ private void warn(String string) {
++ Log.warn(this, string) ;
++ }
++
++ public void free(Page page) {
++ Block block = page.getBackingBlock() ;
++ blockMgr.free(block) ;
++ }
++
++
++ /** Promote a page to be writable in-place (block id does not change, hnce page does not change id). */
++ public void promoteInPlace(Page page) {
++ Block block = page.getBackingBlock() ;
++ block.getByteBuffer().rewind() ;
++ Block block2 = blockMgr.promote(block) ;
++ block2.setReadOnly(false) ;
++ if ( block2.getId() != block.getId() )
++ throw new InternalErrorException("Block id changed") ;
++ if ( block2 == block )
++ return ;
++ // Change - reset Block in page.
++ // The details should not have changed.
++ // page.reset(block2) ;
++ }
++
++ /** Promote a page - return 'true' if the block changed (.reset()) will have been called */
++ public boolean promoteDuplicate(Page page) {
++ Block block = page.getBackingBlock() ;
++ block.getByteBuffer().rewind() ;
++
++ // --- TODO Always new
++ Block block2 = blockMgr.allocate(-1) ;
++ block2.getByteBuffer().put(block.getByteBuffer()) ;
++ block2.getByteBuffer().rewind() ;
++ block2.setReadOnly(false) ;
++
++ if ( block2 == block )
++ return false ;
++ // Change - reset Block in page.
++ page.reset(block2) ;
++ return true ;
++ }
++
++ public boolean valid(int id) {
++ return blockMgr.valid(id) ;
++ }
++
++ public void dump() {
++ for ( int idx = 0 ; valid(idx) ; idx++ ) {
++ T page = getRead(idx, -1) ;
++ System.out.println(page) ;
++ release(page) ;
++ }
++ }
++
++ /** Signal the start of an update operation */
++ public void startUpdate() { blockMgr.beginUpdate() ; }
++
++ /** Signal the completion of an update operation */
++ public void finishUpdate() { blockMgr.endUpdate() ; }
++
++ /** Signal the start of an update operation */
++ public void startRead() { blockMgr.beginRead() ; }
++
++ /** Signal the completeion of an update operation */
++ public void finishRead() { blockMgr.endRead() ; }
++
++ @Override
++ public void close() { blockMgr.close(); }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/record/Record.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/record/Record.java
index 0000000,0000000..869e705
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/record/Record.java
@@@ -1,0 -1,0 +1,188 @@@
++/*
++ * 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.dboe.base.record;
++
++import static java.lang.String.format ;
++
++import java.util.Arrays ;
++
++import org.apache.jena.atlas.lib.Bytes ;
++import org.seaborne.dboe.sys.SystemIndex ;
++
++/** A record is pair of key and value. It may be all key, in which case value is null. */
++
++final
++public class Record //implements Comparable<Record>
++{
++ /*
++ * Records of fixed size (controlled by the factory).
++ */
++ public static final Record NO_REC = null ;
++
++ final private byte[] key ;
++ final private byte[] value ;
++
++ public Record(byte[] key, byte[] value)
++ {
++ this.key = key ;
++ this.value = value ;
++ if ( SystemIndex.Checking )
++ {
++ if ( value != null && value.length == 0 )
++ throw new RecordException("Zero length value") ;
++ }
++ }
++
++ public byte[] getKey() { return key ; }
++ public byte[] getValue() { return value ; }
++
++ public boolean hasSeparateValue() { return value!=null ; }
++
++ @Override
++ public int hashCode()
++ {
++ return Arrays.hashCode(key) ^ Arrays.hashCode(value) ;
++ }
++
++ @Override
++ public boolean equals(Object other)
++ {
++ if ( this == other ) return true ;
++ if ( ! ( other instanceof Record ) ) return false ;
++ Record r = (Record)other ;
++ return compareByKeyValue(this, r) == 0 ;
++ }
++
++ @Override
++ public String toString()
++ {
++ if ( value == null )
++ return str(key) ;
++ return str(key)+":"+str(value) ;
++ }
++
++ /** Is the key of record1 == key of record2 */
++ public static boolean keyEQ(Record record1, Record record2)
++ {
++ int x = compareByKey(record1, record2) ;
++ return x == 0 ;
++ }
++
++ /** Is the key of record1 != key of record2 */
++ public static boolean keyNE(Record record1, Record record2)
++ {
++ int x = compareByKey(record1, record2) ;
++ return x != 0 ;
++ }
++
++ /** Is the key of record1 < key of record2 */
++ public static boolean keyLT(Record record1, Record record2)
++ {
++ int x = compareByKey(record1, record2) ;
++ return x < 0 ;
++ }
++
++ /** Is the key of record1 <= key of record2 */
++ public static boolean keyLE(Record record1, Record record2)
++ {
++ int x = compareByKey(record1, record2) ;
++ return x <= 0 ;
++ }
++
++ /** Is the key of record1 >= key of record2 */
++ public static boolean keyGE(Record record1, Record record2)
++ {
++ int x = compareByKey(record1, record2) ;
++ return x >= 0 ;
++ }
++
++ /** Is the key of record1 > key of record2 */
++ public static boolean keyGT(Record record1, Record record2)
++ {
++ int x = compareByKey(record1, record2) ;
++ return x > 0 ;
++ }
++
++ /** Is (key, value) of record1 equal to (key,value) of record2 */
++ public static boolean equals(Record record1, Record record2)
++ {
++ int x = compareByKeyValue(record1, record2) ;
++ return x == 0 ;
++ }
++
++
++
++ static public String str(byte[] b)
++ {
++ StringBuilder str = new StringBuilder() ;
++ for ( byte aB : b )
++ {
++ str.append( format( "%02x", aB ) );
++ }
++ return str.toString() ;
++ }
++
++ public static int compareByKey(Record record1, Record record2)
++ {
++ checkKeyCompatible(record1, record2) ;
++ return Bytes.compare(record1.key, record2.key) ;
++ }
++
++ public static int compareByKeyValue(Record record1, Record record2)
++ {
++ checkCompatible(record1, record2) ;
++ int x = Bytes.compare(record1.key, record2.key) ;
++ if ( x == 0 )
++ {
++ if ( record1.value != null )
++ x = Bytes.compare(record1.value, record2.value) ;
++ }
++ return x ;
++ }
++
++ static void checkCompatible(Record record1, Record record2)
++ {
++ if ( ! compatible(record1, record2, true) )
++ throw new RecordException(format("Incompatible: %s, %s", record1, record2)) ;
++ }
++
++ static void checkKeyCompatible(Record record1, Record record2)
++ {
++ if ( ! compatible(record1, record2, false) )
++ throw new RecordException(format("Incompatible: %s, %s", record1, record2)) ;
++ }
++
++ static boolean compatible(Record record1, Record record2, boolean checkValue)
++ {
++ if ( record1.key.length != record2.key.length )
++ return false ;
++
++ if ( checkValue )
++ {
++ if ( record1.value == null && record2.value == null )
++ return true ;
++ if ( record1.value == null )
++ return false ;
++ if ( record2.value == null )
++ return false ;
++ if ( record1.value.length != record2.value.length )
++ return false;
++ }
++ return true ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/record/RecordException.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/record/RecordException.java
index 0000000,0000000..7c192c8
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/record/RecordException.java
@@@ -1,0 -1,0 +1,26 @@@
++/*
++ * 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.dboe.base.record;
++
++import org.seaborne.dboe.DBOpEnvException ;
++
++public class RecordException extends DBOpEnvException
++{
++ public RecordException() {}
++ public RecordException(String msg) { super(msg) ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/record/RecordFactory.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/record/RecordFactory.java
index 0000000,0000000..1413312
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/record/RecordFactory.java
@@@ -1,0 -1,0 +1,183 @@@
++/*
++ * 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.dboe.base.record;
++
++import static java.lang.String.format;
++
++import java.nio.ByteBuffer;
++
++/** Record creator */
++final
++public class RecordFactory
++{
++ private final int keyLength;
++ private final int valueLength;
++ private final int slotLen;
++ private final boolean checking = false;
++
++ public RecordFactory(int keyLength, int valueLength) {
++ if ( keyLength <= 0 )
++ throw new IllegalArgumentException("Bad key length: " + keyLength);
++ if ( valueLength < 0 )
++ throw new IllegalArgumentException("Bad value length: " + valueLength);
++
++ this.keyLength = keyLength;
++ this.valueLength = valueLength;
++ this.slotLen = keyLength + valueLength;
++ }
++
++ /** Return a RecordFactory that makes key-only records of the same key size */
++ public RecordFactory keyFactory() {
++ return new RecordFactory(keyLength, 0);
++ }
++
++ /** Create a key-only record, allocating blank space for the key */
++ public Record createKeyOnly() {
++ return create(new byte[keyLength], null);
++ }
++
++ /** Create a key-only record */
++ public Record createKeyOnly(Record record) {
++ checkKey(record.getKey());
++ if ( record.getValue() == null )
++ return record;
++
++ return create(record.getKey(), null);
++ }
++
++ /** Create a key and value record (value uninitialized) */
++ public Record create(byte[] key) {
++ checkKey(key);
++ byte[] v = null;
++ if ( valueLength > 0 )
++ v = new byte[valueLength];
++ return create(key, v);
++ }
++
++ /** Create a record, allocating space for the key and value (if any) */
++ public Record create() {
++ return create(new byte[keyLength], (valueLength > 0) ? new byte[valueLength] : null);
++ }
++
++ /** Create a key and value record */
++ public Record create(byte[] key, byte[] value) {
++ check(key, value);
++ return new Record(key, value);
++ }
++
++ public void insertInto(Record record, ByteBuffer bb, int idx) {
++ check(record);
++ bb.position(idx * slotLen);
++ bb.put(record.getKey(), 0, keyLength);
++ if ( hasValue() && record.getValue() != null )
++ bb.put(record.getValue(), 0, valueLength);
++ }
++
++ public static final RecordMapper<Record> mapperRecord = new RecordMapper<Record>() {
++ /*
++ * RecordRangeIterator calls getRecordBuffer().get(slotidx);
++ */
++ @Override
++ public Record map(ByteBuffer bb, int idx, byte[] keyBytes, RecordFactory factory) {
++ byte[] key = new byte[factory.keyLength];
++ byte[] value = (factory.hasValue() ? new byte[factory.valueLength] :null );
++ // Is it better to avoid the synchronize needed for bb.position./bb.get
++ // but not use a (relative) bulk bb.get(byte[],,) which may be a native operation?
++
++// int posnKey = idx*slotLen;
++// // Avoid using position() so we can avoid needing synchronized.
++// copyInto(key, bb, posnKey, keyLength);
++// if ( value != null )
++// {
++// int posnValue = idx*slotLen+keyLength;
++// copyInto(value, bb, posnValue, valueLength);
++// }
++
++ // Using bb.get(byte[],,) may be potentially faster but requires the synchronized
++ // There's no absolute version.
++ synchronized(bb)
++ {
++ bb.position(idx*factory.slotLen);
++ bb.get(key, 0, factory.keyLength);
++ if ( value != null )
++ bb.get(value, 0, factory.valueLength);
++ }
++ if ( keyBytes != null )
++ System.arraycopy(key, 0, keyBytes, 0, factory.keyLength);
++ return factory.create(key, value);
++ }
++ };
++
++ public <X> X access(ByteBuffer bb, int idx, byte[] keyBytes, RecordMapper<X> mapper) {
++ return mapper.map(bb, idx, keyBytes, this);
++ }
++
++ public Record buildFrom(ByteBuffer bb, int idx) {
++ return access(bb, idx, null, mapperRecord);
++ }
++
++ private final void copyInto(byte[] dst, ByteBuffer src, int start, int length) {
++ // Thread safe.
++ for ( int i = 0; i < length; i++ )
++ dst[i] = src.get(start+i);
++ // Would otherwise be ...
++// src.position(start);
++// src.get(dst, 0, length);
++ }
++
++ public boolean hasValue() { return valueLength > 0; }
++
++ public int recordLength() { return keyLength + valueLength; }
++
++ public int keyLength() { return keyLength; }
++
++ public int valueLength() { return valueLength; }
++
++ @Override
++ public String toString() {
++ return format("<RecordFactory k=%d v=%d>", keyLength, valueLength);
++ }
++
++ private final void check(Record record) {
++ if ( ! checking ) return;
++ check(record.getKey(), record.getValue());
++ }
++
++ private final void checkKey(byte[] k) {
++ if ( ! checking ) return;
++ if ( k == null )
++ throw new RecordException("Null key byte[]");
++ if ( keyLength != k.length )
++ throw new RecordException(format("Key length error: This RecordFactory manages records of key length %d, not %d", keyLength,
++ k.length));
++ }
++
++ private final void check(byte[] k, byte[] v) {
++ if ( ! checking ) return;
++ checkKey(k);
++ if ( valueLength <= 0 ) {
++ if ( v != null )
++ throw new RecordException("Value array error: This RecordFactory manages records that are all key");
++ } else {
++ // v == null for a key-only record from this factory.
++ if ( v != null && v.length != valueLength )
++ throw new RecordException(format("This RecordFactory manages record of value length %d, not (%d,-)", valueLength,
++ v.length));
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/record/RecordMapper.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/record/RecordMapper.java
index 0000000,0000000..34968e2
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/record/RecordMapper.java
@@@ -1,0 -1,0 +1,30 @@@
++/*
++ * 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.dboe.base.record;
++
++import java.nio.ByteBuffer ;
++
++/** Allow bytes to pull directly out of storage with no copy to record;
++ * also extract the key bytes into an array.
++ * This operation MUST not retain any references to the ByteBuffer storage space.
++ * All in order to avoid remapping Records to higher level objects,
++ * which churns objects (GC issue) and avoids a copy.
++ */
++public interface RecordMapper<X> {
++ X map(ByteBuffer bb, int entryIdx, byte key[], RecordFactory recFactory) ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/recordbuffer/RecordBufferPage.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/recordbuffer/RecordBufferPage.java
index 0000000,0000000..84b251d
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/recordbuffer/RecordBufferPage.java
@@@ -1,0 -1,0 +1,100 @@@
++/*
++ * 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.dboe.base.recordbuffer;
++
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.base.page.Page ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.sys.Sys ;
++
++/**
++ * B+Tree records nodes and hash buckets.
++ * Add link field to a RecordBufferPageBase
++ */
++
++public final class RecordBufferPage extends RecordBufferPageBase
++{
++ // Why not straight to BPlusTreeRecords?
++ // 1 - this may be useful in its own right as a sequence of records on-disk.
++ // 2 - BPlusTreeRecords inherits from BPlusTreePage
++
++
++ // To Constants
++ // Offsets
++ // final public static int COUNT = 0 ;
++ // Adds this field over RecordBufferPageBase
++ final public static int LINK = 4 ;
++ final private static int FIELD_LENGTH = Sys.SizeOfInt ; // Length of the space needed here (not count)
++
++ private int link = Page.NO_ID ;
++
++ public final int getLink() { return link ; }
++
++ public void setLink(int link)
++ {
++ this.link = link ;
++ getBackingBlock().getByteBuffer().putInt(LINK, link) ;
++ }
++
++ @Override
++ protected void _reset(Block block)
++ {
++ // TODO -- should this be format?
++ // Print this
++ super.rebuild(block, this.getCount()) ;
++ //?? use .format
++// // TODO WRONG : block is overlying.
++// this.link = block.getByteBuffer().getInt(LINK) ;
++ }
++
++ public static int calcRecordSize(RecordFactory factory, int blkSize)
++ { return RecordBufferPageBase.calcRecordSize(factory, blkSize, FIELD_LENGTH) ; }
++
++ public static int calcBlockSize(RecordFactory factory, int maxRec)
++ { return RecordBufferPageBase.calcBlockSize(factory, maxRec, FIELD_LENGTH) ; }
++
++ /** The construction methods */
++ public static RecordBufferPage createBlank(Block block,RecordFactory factory)
++ {
++ int count = 0 ;
++ int linkId = NO_ID ;
++ return new RecordBufferPage(block, factory, count, linkId) ;
++ }
++
++ public static RecordBufferPage format(Block block, RecordFactory factory)
++ {
++ int count = block.getByteBuffer().getInt(COUNT) ;
++ int linkId = block.getByteBuffer().getInt(LINK) ;
++ return new RecordBufferPage(block, factory, count, linkId) ;
++ }
++
++ private RecordBufferPage(Block block, RecordFactory factory, int count, int linkId)
++ {
++ super(block, FIELD_LENGTH, factory, count) ;
++ this.link = linkId ;
++ }
++
++ @Override
++ public String toString()
++ { return String.format("RecordBufferPage[id=%d,link=%d]: %s", getBackingBlock().getId(), getLink(), recBuff) ; }
++
++ @Override
++ public String getRefStr() {
++ return String.format("RecordBufferPage[id=%d]", getBackingBlock().getId()) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/recordbuffer/RecordBufferPageBase.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/recordbuffer/RecordBufferPageBase.java
index 0000000,0000000..9559008
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/recordbuffer/RecordBufferPageBase.java
@@@ -1,0 -1,0 +1,105 @@@
++/*
++ * 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.dboe.base.recordbuffer ;
++
++import java.nio.ByteBuffer ;
++
++import org.apache.jena.atlas.io.IndentedWriter ;
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.base.buffer.RecordBuffer ;
++import org.seaborne.dboe.base.page.PageBase ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.sys.Sys ;
++
++/**
++ * The on-disk form of a block of a single RecordBuffer
++ * (i.e. this is not part of a BTree/BPlusTree branch node).
++ * This must be compatible with B+Tree records nodes and hashbuckets.
++ */
++
++public abstract class RecordBufferPageBase extends PageBase // implements Page
++{
++ // Field offsets
++ final public static int COUNT = 0 ;
++ // Length due to this class - subclasses may use more overhead.
++ final private static int FIELD_LENGTH = Sys.SizeOfInt ;
++
++ protected final int headerLength ;
++
++ // Interface: "Page" - id, byteBuffer, count
++ protected RecordBuffer recBuff ;
++ private final RecordFactory factory ;
++
++ // private int offset ; // Bytes of overhead.
++
++ public static int calcRecordSize(RecordFactory factory, int blkSize, int headerOffset) {
++ // Length = X*recordLength + HEADER
++ int x = blkSize - totalOffset(headerOffset) ;
++ return x / factory.recordLength() ;
++ }
++
++ public static int calcBlockSize(RecordFactory factory, int maxRec, int headerOffset) {
++ return totalOffset(headerOffset) + factory.recordLength() * maxRec ;
++ }
++
++ private static int totalOffset(int headerOffset) {
++ return FIELD_LENGTH + headerOffset ;
++ }
++
++ protected RecordBufferPageBase(Block block, int offset, RecordFactory factory, int count) {
++ // This code knows the alignment of the records in the ByteBuffer.
++ super(block) ;
++ this.headerLength = FIELD_LENGTH + offset ; // NB +4 for the count field
++ this.factory = factory ;
++ rebuild(block, count) ;
++ }
++
++ protected void rebuild(Block block, int count) {
++ ByteBuffer bb = block.getByteBuffer() ;
++ bb.clear() ;
++ bb.position(headerLength) ;
++ bb = bb.slice() ;
++ this.recBuff = new RecordBuffer(bb, factory, count) ;
++ }
++
++ public final RecordBuffer getRecordBuffer() {
++ return recBuff ;
++ }
++
++ public final int getCount() {
++ return recBuff.size() ;
++ }
++
++ public final int getMaxSize() {
++ return recBuff.maxSize() ;
++ }
++
++ public void setCount(int count) {
++ recBuff.setSize(count) ;
++ }
++
++ @Override
++ public String toString() {
++ return String.format("RecordBufferPageBase[id=%d]: %s", getBackingBlock().getId(), recBuff) ;
++ }
++
++ @Override
++ public void output(IndentedWriter out) {
++ out.print(toString()) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/recordbuffer/RecordBufferPageMgr.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/recordbuffer/RecordBufferPageMgr.java
index 0000000,0000000..09275a9
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/recordbuffer/RecordBufferPageMgr.java
@@@ -1,0 -1,0 +1,90 @@@
++/*
++ * 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.dboe.base.recordbuffer;
++
++import static org.seaborne.dboe.base.recordbuffer.RecordBufferPage.* ;
++
++import java.nio.ByteBuffer;
++
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.block.BlockType ;
++import org.seaborne.dboe.base.page.BlockConverter ;
++import org.seaborne.dboe.base.page.PageBlockMgr ;
++import org.seaborne.dboe.base.record.RecordException ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++
++/** Manager for a block that is all records.
++ * This must be compatible with B+Tree records nodes and with hash buckets.
++ */
++
++final
++public class RecordBufferPageMgr extends PageBlockMgr<RecordBufferPage>
++{
++ private final RecordFactory factory ;
++
++ public RecordBufferPageMgr(RecordFactory factory, BlockMgr blockMgr) {
++ super(new Block2RecordBufferPage(factory), blockMgr) ;
++ this.factory = factory ;
++ }
++
++ public RecordFactory getRecordFactory() { return factory ; }
++
++ public RecordBufferPage create() {
++ return super.create(BlockType.RECORD_BLOCK) ;
++ }
++
++ public static class Block2RecordBufferPage implements BlockConverter<RecordBufferPage> {
++ private RecordFactory factory ;
++
++ public Block2RecordBufferPage(RecordFactory factory) {
++ this.factory = factory ;
++ }
++
++ @Override
++ public RecordBufferPage createFromBlock(Block block, BlockType blkType) {
++ if ( blkType != BlockType.RECORD_BLOCK )
++ throw new RecordException("Not RECORD_BLOCK: " + blkType) ;
++ // Initially empty
++ RecordBufferPage rb = RecordBufferPage.createBlank(block, factory) ;
++ return rb ;
++ }
++
++ @Override
++ public RecordBufferPage fromBlock(Block block) {
++ synchronized (block) // [[TxTDB:TODO] needed? Right place?
++ {
++ RecordBufferPage rb = RecordBufferPage.format(block, factory) ;
++ // int count = block.getByteBuffer().getInt(COUNT) ;
++ // int linkId = block.getByteBuffer().getInt(LINK) ;
++ // RecordBufferPage rb = new RecordBufferPage(block, linkId,
++ // factory, count) ;
++ return rb ;
++ }
++ }
++
++ @Override
++ public Block toBlock(RecordBufferPage rbp) {
++ int count = rbp.getRecordBuffer().size() ;
++ ByteBuffer bb = rbp.getBackingBlock().getByteBuffer() ;
++ bb.putInt(COUNT, rbp.getCount()) ;
++ bb.putInt(LINK, rbp.getLink()) ;
++ return rbp.getBackingBlock() ;
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/recordbuffer/RecordRangeIterator.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/recordbuffer/RecordRangeIterator.java
index 0000000,0000000..92ae3c1
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/base/recordbuffer/RecordRangeIterator.java
@@@ -1,0 -1,0 +1,161 @@@
++/*
++ * 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.dboe.base.recordbuffer;
++
++import static org.apache.jena.atlas.lib.Alg.decodeIndex ;
++
++import java.util.Iterator ;
++import java.util.NoSuchElementException ;
++
++import org.apache.jena.atlas.lib.Bytes ;
++import org.apache.jena.atlas.lib.Closeable ;
++import org.seaborne.dboe.base.StorageException ;
++import org.seaborne.dboe.base.block.BlockException ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordMapper ;
++
++final public
++class RecordRangeIterator<X> implements Iterator<X>, Closeable
++{
++ /** Iterate over a range of fromRec (inclusive) to toRec (exclusive) */
++ public static <X> Iterator<X> iterator(int pageId, Record fromRec, Record toRec, RecordBufferPageMgr pageMgr, RecordMapper<X> mapper)
++ {
++ if ( ! pageMgr.valid(pageId) ) {
++ String msg = "RecordRangeIterator.iterator -- No such block (pageId="+pageId+", fromRec="+fromRec+", toRec="+toRec+ ")" ;
++// System.err.println(msg) ;
++// System.exit(0) ;
++ throw new BlockException(msg) ;
++ }
++ return new RecordRangeIterator<>(pageId, fromRec, toRec, pageMgr, mapper) ;
++ }
++
++ private final RecordMapper<X> mapper ;
++
++ private RecordBufferPage currentPage ; // Set null when finished.
++
++ private int currentIdx ;
++ private final RecordBufferPageMgr pageMgr ;
++ private final Record maxRec ;
++ private final Record minRec ;
++
++ private X slot = null ;
++ private final byte[] keySlot ;
++
++ private long countRecords = 0 ;
++ private long countBlocks = 0 ;
++
++ private RecordRangeIterator(int id, Record fromRec, Record toRec, RecordBufferPageMgr pageMgr, RecordMapper<X> mapper) {
++ currentIdx = 0 ;
++ this.pageMgr = pageMgr;
++ this.minRec = fromRec ;
++ this.maxRec = toRec ;
++ this.mapper = mapper ;
++ this.keySlot = new byte[pageMgr.getRecordFactory().keyLength()] ;
++
++ if ( toRec != null && fromRec != null && Record.keyLE(toRec, fromRec) ) {
++ currentPage = null ;
++ return ;
++ }
++
++ pageMgr.startRead();
++ currentPage = pageMgr.getRead(id) ;
++
++ if ( currentPage.getCount() == 0 ) {
++ // Empty page.
++ close() ;
++ return ;
++ }
++
++ if ( fromRec != null ) {
++ currentIdx = currentPage.getRecordBuffer().find(fromRec) ;
++ if ( currentIdx < 0 )
++ currentIdx = decodeIndex(currentIdx) ;
++ }
++ }
++
++ @Override
++ public boolean hasNext() {
++ if ( slot != null )
++ return true ;
++ if ( currentPage == null )
++ return false ;
++ // Set slot.
++ while (currentIdx >= currentPage.getCount()) {
++ // Move to next.
++ int link = currentPage.getLink() ;
++ if ( link < 0 ) {
++ close() ;
++ return false ;
++ }
++
++ if ( currentPage != null )
++ pageMgr.release(currentPage) ;
++
++ RecordBufferPage nextPage = pageMgr.getRead(link) ;
++ // Check currentPage -> nextPage is strictly increasing keys.
++ if ( false ) {
++ Record r1 = currentPage.getRecordBuffer().getHigh() ;
++ Record r2 = nextPage.getRecordBuffer().getLow() ;
++ if ( Record.keyGE(r1, r2) )
++ throw new StorageException("RecordRangeIterator: records not strictly increasing: " + r1 + " // " + r2) ;
++ }
++ currentPage = nextPage ;
++ countBlocks++ ;
++ currentIdx = 0 ;
++ }
++
++ slot = currentPage.getRecordBuffer().access(currentIdx, keySlot, mapper) ;
++ currentIdx++ ;
++
++ if ( maxRec != null && Bytes.compare(keySlot, maxRec.getKey()) >= 0 ) {
++ close() ;
++ return false ;
++ }
++
++ if ( slot == null ) {
++ close() ;
++ return false ;
++ }
++ countRecords++ ;
++ return true ;
++ }
++
++ @Override
++ public void close() {
++ if ( currentPage == null )
++ return ;
++ pageMgr.release(currentPage) ;
++ pageMgr.finishRead();
++ currentPage = null ;
++ currentIdx = -99 ;
++ slot = null ;
++ }
++
++ @Override
++ public X next() {
++ if ( !hasNext() )
++ throw new NoSuchElementException() ;
++ X x = slot ;
++ slot = null ;
++ return x ;
++ }
++
++ final public long getCountRecords() { return countRecords ; }
++
++ final public long getCountBlocks() { return countBlocks ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/jenax/Txn.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/jenax/Txn.java
index 0000000,0000000..5f7ea6a
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/jenax/Txn.java
@@@ -1,0 -1,0 +1,41 @@@
++/*
++ * 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.dboe.jenax;
++
++import java.util.function.Supplier ;
++
++import org.apache.jena.sparql.core.Transactional ;
++
++/** Indirection to allow for modification for TDB2 capabilities */
++public class Txn {
++ public static <T extends Transactional> void executeRead(T txn, Runnable r) {
++ org.apache.jena.system.Txn.executeRead(txn, r);
++ }
++
++ public static <T extends Transactional, X> X calculateRead(T txn, Supplier<X> r) {
++ return org.apache.jena.system.Txn.calculateRead(txn, r);
++ }
++
++ public static <T extends Transactional> void executeWrite(T txn, Runnable r) {
++ org.apache.jena.system.Txn.executeWrite(txn, r);
++ }
++
++ public static <T extends Transactional, X> X calculateWrite(T txn, Supplier<X> r) {
++ return org.apache.jena.system.Txn.calculateWrite(txn, r);
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/migrate/L.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/migrate/L.java
index 0000000,0000000..e4e709f
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/migrate/L.java
@@@ -1,0 -1,0 +1,206 @@@
++/*
++ * 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.dboe.migrate;
++
++import java.io.IOException ;
++import java.io.OutputStream ;
++import java.io.OutputStreamWriter ;
++import java.io.Writer ;
++import java.nio.ByteBuffer ;
++import java.nio.charset.StandardCharsets ;
++import java.util.UUID ;
++import java.util.concurrent.* ;
++import java.util.concurrent.locks.Lock ;
++import java.util.function.Supplier ;
++
++import org.apache.jena.atlas.io.IO ;
++import org.apache.jena.atlas.lib.Bytes ;
++import org.apache.jena.atlas.lib.StrUtils ;
++import org.apache.jena.shared.uuid.JenaUUID ;
++
++/** Misc class */
++public class L {
++
++ // Not to be confused with UUID.nameUUIDFromBytes (a helper for version 3 UUIDs)
++ /**
++ * Java UUID to bytes (most significant first)
++ */
++ public static byte[] uuidAsBytes(UUID uuid) {
++ return uuidAsBytes(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits()) ;
++ }
++
++ /**
++ * Jena UUID to bytes (most significant first)
++ */
++ public static byte[] uuidAsBytes(JenaUUID uuid) {
++ return uuidAsBytes(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits()) ;
++ }
++
++ /** UUID, as two longs, as bytes */
++ public static byte[] uuidAsBytes(long mostSignificantBits, long leastSignificantBits) {
++ byte[] bytes = new byte[16] ;
++ Bytes.setLong(mostSignificantBits, bytes, 0);
++ Bytes.setLong(leastSignificantBits, bytes, 8);
++ return bytes ;
++ }
++
++ /** A UUID string to bytes */
++ public static byte[] uuidAsBytes(String str) {
++ return uuidAsBytes(UUID.fromString(str)) ;
++ }
++
++ public static String uuidToString(long mostSignificantBits, long leastSignificantBits) {
++ return new UUID(mostSignificantBits, leastSignificantBits).toString() ;
++ //JenaUUID.toString(mostSignificantBits, leastSignificantBits)
++ }
++
++ private static ExecutorService executor = Executors.newCachedThreadPool() ;
++
++ /**
++ * Run asynchronously on another thread ; the thread has started
++ * when this function returns.
++ */
++ public static void async(Runnable r) {
++ Semaphore semaStart = new Semaphore(0, true) ;
++ Runnable r2 = () -> {
++ semaStart.release(1) ;
++ r.run();
++ } ;
++ executor.execute(r2);
++ semaStart.acquireUninterruptibly();
++ }
++
++ /** Run synchronously but on another thread. */
++ public static void syncOtherThread(Runnable r) {
++ runCallable(()->{
++ r.run();
++ return null ;
++ }) ;
++ }
++
++ /** Run synchronously but on another thread. */
++ public static <T> T syncCallThread(Supplier<T> r) {
++ return runCallable(() -> {
++ T t = r.get() ;
++ return t ;
++ }) ;
++ }
++
++ private static <T> T runCallable(Callable<T> action) {
++ try { return executor.submit(action).get() ; }
++ catch (Exception e) {
++ e.printStackTrace();
++ return null ;
++ }
++ }
++
++
++ /** Execute. Preform the "before" action, then main action.
++ * Always call the "after" runnable if the "bafore" succeeded.
++ * Becareful about argument order.
++ * @param action
++ * @param before
++ * @param after
++ */
++ public static void withBeforeAfter(Runnable action, Runnable before, Runnable after) {
++ before.run();
++ try { action.run(); }
++ finally { after.run(); }
++ }
++
++ /** Execute. Preform the "before" action, then main action.
++ * Always call the "after" runnable if the "bafore" succeeded.
++ * Becareful about argument order.
++ * @param action
++ * @param before
++ * @param after
++ */
++ public static <V> V callWithBeforeAfter(Supplier<V> action, Runnable before, Runnable after) {
++ before.run();
++ try { return action.get() ; }
++ finally { after.run(); }
++ }
++
++ /** Execute; always call the "after" runnable */
++ public static void withAfter(Runnable action, Runnable after) {
++ try { action.run(); }
++ finally { after.run(); }
++ }
++
++ /** Execute and return a value; always call the "after" runnable */
++ public static <V> V callWithAfter(Supplier<V> action, Runnable after) {
++ try { return action.get() ; }
++ finally { after.run(); }
++ }
++
++ /** Run inside a Lock */
++ public static <V> V callWithLock(Lock lock, Supplier<V> r) {
++ return callWithBeforeAfter(r, ()->lock.lock(), ()->lock.unlock()) ;
++ }
++
++ /** Run inside a Lock */
++ public static void withLock(Lock lock, Runnable r) {
++ withBeforeAfter(r, ()->lock.lock(), ()->lock.unlock()) ;
++ }
++
++ // ==> IO.writeWholeFileAsUTF8
++
++ /** Write a string to a file as UTF-8. The file is closed after the operation.
++ * @param filename
++ * @param content String to be writtem
++ * @throws IOException
++ */
++
++ public static void writeStringAsUTF8(String filename, String content) throws IOException {
++ try ( OutputStream out = IO.openOutputFileEx(filename) ) {
++ writeStringAsUTF8(out, content) ;
++ out.flush() ;
++ }
++ }
++
++ /** Read a whole stream as UTF-8
++ *
++ * @param out OutputStream to be read
++ * @param content String to be written
++ * @throws IOException
++ */
++ public static void writeStringAsUTF8(OutputStream out, String content) throws IOException {
++ Writer w = new OutputStreamWriter(out, StandardCharsets.UTF_8) ;
++ w.write(content);
++ w.flush();
++ // Not close.
++ }
++
++ // ==> IO.writeWholeFileAsUTF8
++
++ /** String to ByteBuffer */
++ public static ByteBuffer stringToByteBuffer(String str) {
++ byte[] b = StrUtils.asUTF8bytes(str) ;
++ return ByteBuffer.wrap(b) ;
++ }
++
++ /** ByteBuffer to String */
++ public static String byteBufferToString(ByteBuffer bb) {
++ byte[] b = new byte[bb.remaining()] ;
++ bb.get(b) ;
++ return StrUtils.fromUTF8bytes(b) ;
++ }
++
++
++}
++
[37/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestJournal.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestJournal.java
index 0000000,0000000..6852d85
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestJournal.java
@@@ -1,0 -1,0 +1,149 @@@
++/*
++ * 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.dboe.transaction;
++
++import static org.junit.Assert.assertEquals ;
++import static org.junit.Assert.assertFalse ;
++import static org.junit.Assert.assertNotEquals ;
++import static org.junit.Assert.assertNotNull ;
++import static org.junit.Assert.assertTrue ;
++import static org.junit.Assert.fail ;
++
++import java.nio.ByteBuffer ;
++import java.util.Arrays ;
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.apache.jena.atlas.lib.ByteBufferLib ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++import org.seaborne.dboe.transaction.txn.ComponentIds ;
++import org.seaborne.dboe.transaction.txn.journal.Journal ;
++import org.seaborne.dboe.transaction.txn.journal.JournalEntry ;
++import org.seaborne.dboe.transaction.txn.journal.JournalEntryType ;
++
++/** Journal tests spearate from the transaction coordinator */
++public class TestJournal {
++ // For testing recovery, we need something to recover!
++ // See tests in TestRecovery in dboe-trans-data
++
++ @Test public void journal_01() {
++ Journal jrnl = Journal.create(Location.mem()) ;
++ assertNotNull(jrnl) ;
++ assertTrue(jrnl.isEmpty()) ;
++ }
++
++ @Test public void journal_02() {
++ Journal jrnl = Journal.create(Location.mem()) ;
++ assertNotNull(jrnl) ;
++ JournalEntry e = JournalEntry.COMMIT ;
++ jrnl.writeJournal(e) ;
++ assertFalse(jrnl.isEmpty()) ;
++ assertNotEquals(0, jrnl.position()) ;
++ }
++
++ @Test public void journal_03() {
++ Journal jrnl = Journal.create(Location.mem()) ;
++ assertNotNull(jrnl) ;
++ jrnl.writeJournal(JournalEntry.COMMIT) ;
++ assertNotEquals(0, jrnl.position()) ;
++ JournalEntry e = jrnl.readJournal(0) ;
++ check(JournalEntry.COMMIT, e) ;
++ assertEquals(ComponentIds.idSystem, e.getComponentId());
++ assertEquals(JournalEntryType.COMMIT, e.getType());
++ check(JournalEntry.COMMIT, e) ;
++ }
++
++ @Test public void journal_04() {
++ Journal jrnl = Journal.create(Location.mem()) ;
++ jrnl.writeJournal(JournalEntry.COMMIT) ;
++ jrnl.writeJournal(JournalEntry.ABORT) ;
++ jrnl.writeJournal(JournalEntry.ABORT) ;
++ jrnl.writeJournal(JournalEntry.COMMIT) ;
++ assertFalse(jrnl.isEmpty()) ;
++
++ Iterator<JournalEntry> iter = jrnl.entries(0) ;
++
++ List<JournalEntry> expected = Arrays.asList(JournalEntry.COMMIT,
++ JournalEntry.ABORT,
++ JournalEntry.ABORT,
++ JournalEntry.COMMIT) ;
++ }
++
++ @Test public void journal_05() {
++ Journal jrnl = Journal.create(Location.mem()) ;
++ jrnl.writeJournal(JournalEntry.COMMIT) ;
++ jrnl.writeJournal(JournalEntry.ABORT) ;
++ long x = jrnl.writeJournal(JournalEntry.COMMIT) ;
++ jrnl.writeJournal(JournalEntry.COMMIT) ;
++ assertFalse(jrnl.isEmpty()) ;
++
++ Iterator<JournalEntry> iter = jrnl.entries(x) ;
++
++ List<JournalEntry> expected = Arrays.asList(JournalEntry.COMMIT,
++ JournalEntry.COMMIT) ;
++ }
++
++ @Test public void journal_06() {
++ ByteBuffer bb = ByteBuffer.allocateDirect(100) ;
++ ByteBufferLib.fill(bb, (byte)0XA5);
++ Journal jrnl = Journal.create(Location.mem()) ;
++ JournalEntry e = new JournalEntry(JournalEntryType.REDO, ComponentId.allocLocal(), bb) ;
++ jrnl.writeJournal(e) ;
++ jrnl.sync() ;
++ JournalEntry e2 = jrnl.readJournal(0) ;
++ check(e, e2);
++ }
++
++ @Test public void journal_07() {
++ ByteBuffer bb = ByteBuffer.allocateDirect(100) ;
++ ByteBufferLib.fill(bb, (byte)0XA5);
++ Journal jrnl = Journal.create(Location.mem()) ;
++ JournalEntry e = new JournalEntry(JournalEntryType.REDO, ComponentId.allocLocal(), bb) ;
++
++ jrnl.writeJournal(JournalEntry.COMMIT) ;
++ long locn = jrnl.position() ;
++ jrnl.writeJournal(e) ;
++
++ assertNotEquals(0, locn);
++ jrnl.sync() ;
++ JournalEntry e2 = jrnl.readJournal(locn) ;
++ check(e, e2);
++ }
++
++ private void check(List<JournalEntry> expected, Iterator<JournalEntry> iter) {
++ Iterator<JournalEntry> iter2 = expected.iterator() ;
++ for(;;) {
++ if ( ! iter.hasNext() || ! iter2.hasNext() )
++ break ;
++ check(iter2.next(), iter.next()) ;
++ }
++ if ( iter.hasNext() )
++ fail("Journal iterator longer") ;
++ if ( iter2.hasNext() )
++ fail("Expected iterator longer") ;
++ }
++
++ private void check(JournalEntry expected, JournalEntry actual) {
++ assertEquals(expected.getType(), actual.getType()) ;
++ assertEquals(expected.getComponentId(), actual.getComponentId()) ;
++ assertEquals(expected.getByteBuffer(), actual.getByteBuffer()) ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestStateMgrData.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestStateMgrData.java
index 0000000,0000000..eb6636d
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestStateMgrData.java
@@@ -1,0 -1,0 +1,75 @@@
++/*
++ * 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.dboe.transaction;
++import static org.junit.Assert.* ;
++
++import java.nio.ByteBuffer ;
++
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.BufferChannel ;
++import org.seaborne.dboe.base.file.FileFactory ;
++import org.seaborne.dboe.transaction.txn.StateMgrDataIdx ;
++
++public class TestStateMgrData {
++
++ @Test public void state_data_01() {
++ BufferChannel x = FileFactory.createBufferChannelMem() ;
++ long[] data = {2,3} ;
++ StateMgrDataIdx sm = new StateMgrDataIdx(x, data) ;
++ assertEquals(data.length, sm.getData().length) ;
++ assertEquals(2L, sm.get(0)) ;
++ assertEquals(3L, sm.get(1)) ;
++ // Test initial state written
++ ByteBuffer bb = ByteBuffer.allocate(2*Long.BYTES) ;
++ x.read(bb, 0) ;
++ assertEquals(2L, bb.getLong(0)) ;
++ assertEquals(3L, bb.getLong(Long.BYTES)) ;
++ }
++
++ @Test public void state_data_02() {
++ BufferChannel x = FileFactory.createBufferChannelMem() ;
++ long[] data = {2,3} ;
++ StateMgrDataIdx sm = new StateMgrDataIdx(x, data) ;
++ sm.writeState();
++ sm.set(1, 99L);
++ sm.writeState();
++ ByteBuffer bb = ByteBuffer.allocate(2*Long.BYTES) ;
++ x.read(bb, 0) ;
++ assertEquals(99L, bb.getLong(Long.BYTES)) ;
++ }
++
++ @Test public void state_data_03() {
++ BufferChannel x = FileFactory.createBufferChannelMem() ;
++ {
++ ByteBuffer bb = ByteBuffer.allocate(Long.BYTES) ;
++ bb.putLong(0, -8888) ;
++ bb.rewind();
++ x.write(bb) ;
++ bb.putLong(0, -1234) ;
++ bb.rewind();
++ x.write(bb) ;
++ x.sync();
++ }
++ long[] data = {2,3} ;
++ StateMgrDataIdx sm = new StateMgrDataIdx(x, data) ;
++ assertEquals(-8888L, sm.get(0)) ;
++ assertEquals(-1234L, sm.get(1)) ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestThreadingTransactions.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestThreadingTransactions.java
index 0000000,0000000..4d300cf
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestThreadingTransactions.java
@@@ -1,0 -1,0 +1,120 @@@
++/*
++ * 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.dboe.transaction;
++
++import java.util.concurrent.Semaphore ;
++
++import org.apache.jena.query.ReadWrite ;
++import org.junit.After ;
++import org.junit.Assert ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.dboe.transaction.txn.TransactionCoordinator ;
++
++public class TestThreadingTransactions {
++ static final long InitValue = 3 ;
++ private TransactionalInteger transInt ;
++
++ @Before public void init() {
++ TransactionCoordinator coord = new TransactionCoordinator(Location.mem()) ;
++ transInt = new TransactionalInteger(coord, InitValue) ;
++ coord.start();
++ }
++
++ @After public void after() {
++ transInt.getTxnMgr().shutdown();
++ }
++
++ // Read synchronously in a transaction.
++ void readTxn(String label, TransactionalInteger trans, long expected) {
++ Txn.executeRead(trans, () -> {
++ read(label, trans, expected) ;
++ }) ;
++ }
++
++ void read(String label, TransactionalInteger trans, long expected) {
++ long x = trans.get() ;
++ Assert.assertEquals(label, expected, x);
++ }
++
++ ThreadTxn threadRead(String label, TransactionalInteger trans, long expectedValue) {
++ return ThreadTxn.threadTxnRead(trans, ()->{
++ read(label, trans, expectedValue) ;
++ }) ;
++ }
++
++ @Test public void threadTrans_01() {
++ transInt.begin(ReadWrite.READ) ;
++ read("[01]", transInt, InitValue) ;
++ transInt.end();
++ }
++
++ @Test public void threadTrans_02() {
++ transInt.begin(ReadWrite.READ) ;
++ threadRead("[02]", transInt, InitValue).run() ;
++ transInt.end();
++ }
++
++ @Test public void threadTrans_03() {
++ Semaphore semaBefore = new Semaphore(0, true) ;
++ Semaphore semaAfter = new Semaphore(0, true) ;
++ ThreadTxn async1 = threadRead("[03/1]", transInt, InitValue);
++ ThreadTxn async2 = threadRead("[03/2]", transInt, InitValue);
++
++ transInt.begin(ReadWrite.WRITE) ;
++ read("[03/3]", transInt, InitValue) ;
++ transInt.inc();
++ read("[03/4]", transInt, InitValue+1) ;
++
++ async1.run() ;
++
++ threadRead("[03/5]", transInt, InitValue) ;
++
++ transInt.commit();
++ transInt.end();
++ async2.run();
++ readTxn("[03/6]", transInt, InitValue+1) ;
++ }
++
++ @Test public void threadTrans_04() {
++ Semaphore semaBefore1 = new Semaphore(0, true) ;
++ Semaphore semaBefore2 = new Semaphore(0, true) ;
++ Semaphore semaAfter = new Semaphore(0, true) ;
++
++ ThreadTxn async1 = threadRead("[04/1]", transInt, InitValue);
++ ThreadTxn async2 = threadRead("[04/2]", transInt, InitValue);
++ ThreadTxn async3 = threadRead("[04/3]", transInt, InitValue);
++
++ Txn.executeWrite(transInt, transInt::inc);
++
++ ThreadTxn async4 = threadRead("[04/3]", transInt, InitValue+1);
++ async1.run() ;
++
++ Txn.executeWrite(transInt, transInt::inc); // ++
++ async2.run() ;
++ async4.run() ;
++
++ Txn.executeWrite(transInt, transInt::inc); // ++
++ async3.run() ;
++
++ readTxn("[04/4]", transInt, InitValue+3) ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTransactionCoordinator.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTransactionCoordinator.java
index 0000000,0000000..49d3f2d
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTransactionCoordinator.java
@@@ -1,0 -1,0 +1,177 @@@
++/*
++ * 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.dboe.transaction;
++
++import static org.junit.Assert.assertEquals ;
++
++import org.apache.jena.query.ReadWrite ;
++import org.junit.Test ;
++
++public class TestTransactionCoordinator extends AbstractTestTxn {
++ @Test public void txn_coord_read_1() {
++ assertEquals(0, txnMgr.countActive()) ;
++ assertEquals(0, txnMgr.countFinished()) ;
++ assertEquals(0, txnMgr.countBegin()) ;
++ assertEquals(0, txnMgr.countBeginRead()) ;
++ assertEquals(0, txnMgr.countBeginWrite()) ;
++ assertEquals(0, txnMgr.countActiveReaders()) ;
++ assertEquals(0, txnMgr.countActiveWriter()) ;
++
++ unit.begin(ReadWrite.READ);
++
++ assertEquals(1, txnMgr.countActive()) ;
++ assertEquals(0, txnMgr.countFinished()) ;
++ assertEquals(1, txnMgr.countBegin()) ;
++ assertEquals(1, txnMgr.countBeginRead()) ;
++ assertEquals(0, txnMgr.countBeginWrite()) ;
++
++ assertEquals(1, txnMgr.countActiveReaders()) ;
++ assertEquals(0, txnMgr.countActiveWriter()) ;
++
++ unit.end() ;
++
++ assertEquals(0, txnMgr.countActive()) ;
++ assertEquals(1, txnMgr.countBeginRead()) ;
++ assertEquals(0, txnMgr.countBeginWrite()) ;
++ assertEquals(1, txnMgr.countFinished()) ;
++ assertEquals(1, txnMgr.countBegin()) ;
++ assertEquals(0, txnMgr.countActiveReaders()) ;
++ assertEquals(0, txnMgr.countActiveWriter()) ;
++ }
++
++ @Test public void txn_coord_read_2() {
++ assertEquals(0, txnMgr.countActive()) ;
++ assertEquals(0, txnMgr.countFinished()) ;
++ assertEquals(0, txnMgr.countBegin()) ;
++ assertEquals(0, txnMgr.countBeginRead()) ;
++ assertEquals(0, txnMgr.countBeginWrite()) ;
++
++ unit.begin(ReadWrite.READ);
++
++ assertEquals(1, txnMgr.countActive()) ;
++ assertEquals(0, txnMgr.countFinished()) ;
++ assertEquals(1, txnMgr.countBegin()) ;
++ assertEquals(1, txnMgr.countBeginRead()) ;
++ assertEquals(0, txnMgr.countBeginWrite()) ;
++
++ unit.commit() ;
++
++ assertEquals(0, txnMgr.countActive()) ;
++ assertEquals(1, txnMgr.countBeginRead()) ;
++ assertEquals(0, txnMgr.countBeginWrite()) ;
++ assertEquals(1, txnMgr.countFinished()) ;
++ assertEquals(1, txnMgr.countBegin()) ;
++
++ unit.end() ;
++
++ assertEquals(0, txnMgr.countActive()) ;
++ assertEquals(1, txnMgr.countBeginRead()) ;
++ assertEquals(0, txnMgr.countBeginWrite()) ;
++ assertEquals(1, txnMgr.countFinished()) ;
++ assertEquals(1, txnMgr.countBegin()) ;
++ }
++
++ @Test public void txn_coord_write_1() {
++ assertEquals(0, txnMgr.countActive()) ;
++ assertEquals(0, txnMgr.countFinished()) ;
++ assertEquals(0, txnMgr.countBegin()) ;
++ assertEquals(0, txnMgr.countBeginRead()) ;
++ assertEquals(0, txnMgr.countBeginWrite()) ;
++
++ assertEquals(0, txnMgr.countActiveReaders()) ;
++ assertEquals(0, txnMgr.countActiveWriter()) ;
++
++
++ unit.begin(ReadWrite.WRITE);
++
++ assertEquals(1, txnMgr.countActive()) ;
++ assertEquals(0, txnMgr.countFinished()) ;
++ assertEquals(1, txnMgr.countBegin()) ;
++ assertEquals(0, txnMgr.countBeginRead()) ;
++ assertEquals(1, txnMgr.countBeginWrite()) ;
++
++ assertEquals(0, txnMgr.countActiveReaders()) ;
++ assertEquals(1, txnMgr.countActiveWriter()) ;
++
++ unit.commit() ;
++
++ assertEquals(0, txnMgr.countActive()) ;
++ assertEquals(1, txnMgr.countFinished()) ;
++ assertEquals(1, txnMgr.countBegin()) ;
++ assertEquals(0, txnMgr.countBeginRead()) ;
++ assertEquals(1, txnMgr.countBeginWrite()) ;
++
++ assertEquals(0, txnMgr.countActiveReaders()) ;
++ assertEquals(0, txnMgr.countActiveWriter()) ;
++
++ unit.end() ;
++
++ assertEquals(0, txnMgr.countActive()) ;
++ assertEquals(1, txnMgr.countFinished()) ;
++ assertEquals(1, txnMgr.countBegin()) ;
++ assertEquals(0, txnMgr.countBeginRead()) ;
++ assertEquals(1, txnMgr.countBeginWrite()) ;
++
++ assertEquals(0, txnMgr.countActiveReaders()) ;
++ assertEquals(0, txnMgr.countActiveWriter()) ;
++ }
++
++ @Test public void txn_coord_write_2() {
++ assertEquals(0, txnMgr.countActive()) ;
++ assertEquals(0, txnMgr.countFinished()) ;
++ assertEquals(0, txnMgr.countBegin()) ;
++ assertEquals(0, txnMgr.countBeginRead()) ;
++ assertEquals(0, txnMgr.countBeginWrite()) ;
++ assertEquals(0, txnMgr.countActiveReaders()) ;
++ assertEquals(0, txnMgr.countActiveWriter()) ;
++
++ unit.begin(ReadWrite.WRITE);
++
++ assertEquals(1, txnMgr.countActive()) ;
++ assertEquals(0, txnMgr.countFinished()) ;
++ assertEquals(1, txnMgr.countBegin()) ;
++ assertEquals(0, txnMgr.countBeginRead()) ;
++ assertEquals(1, txnMgr.countBeginWrite()) ;
++
++ assertEquals(0, txnMgr.countActiveReaders()) ;
++ assertEquals(1, txnMgr.countActiveWriter()) ;
++
++ unit.abort() ;
++
++ assertEquals(0, txnMgr.countActive()) ;
++ assertEquals(1, txnMgr.countFinished()) ;
++ assertEquals(1, txnMgr.countBegin()) ;
++ assertEquals(0, txnMgr.countBeginRead()) ;
++ assertEquals(1, txnMgr.countBeginWrite()) ;
++
++ assertEquals(0, txnMgr.countActiveReaders()) ;
++ assertEquals(0, txnMgr.countActiveWriter()) ;
++
++ unit.end() ;
++
++ assertEquals(0, txnMgr.countActive()) ;
++ assertEquals(1, txnMgr.countFinished()) ;
++ assertEquals(1, txnMgr.countBegin()) ;
++ assertEquals(0, txnMgr.countBeginRead()) ;
++ assertEquals(1, txnMgr.countBeginWrite()) ;
++
++ assertEquals(0, txnMgr.countActiveReaders()) ;
++ assertEquals(0, txnMgr.countActiveWriter()) ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTransactionCoordinatorControl.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTransactionCoordinatorControl.java
index 0000000,0000000..56bf401
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTransactionCoordinatorControl.java
@@@ -1,0 -1,0 +1,141 @@@
++/*
++ * 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.dboe.transaction;
++
++import static org.junit.Assert.assertEquals ;
++import static org.junit.Assert.assertFalse ;
++import static org.junit.Assert.assertNotNull ;
++import static org.junit.Assert.assertNull ;
++import static org.junit.Assert.assertTrue ;
++
++import java.util.concurrent.Semaphore ;
++import java.util.concurrent.atomic.AtomicInteger ;
++
++import org.apache.jena.query.ReadWrite ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.dboe.migrate.L ;
++import org.seaborne.dboe.transaction.txn.Transaction ;
++import org.seaborne.dboe.transaction.txn.TransactionCoordinator ;
++import org.seaborne.dboe.transaction.txn.TransactionException ;
++import org.seaborne.dboe.transaction.txn.TransactionalBase ;
++
++public class TestTransactionCoordinatorControl {
++ // The problem with these tests is the need for Lib.sleep as a way to ensure
++ // async threads run if they can. And we are sometimes testing for "they can't".
++
++ static final long InitValue = 3 ;
++ private TransactionCoordinator txnMgr ;
++ protected Transactional unit ;
++
++ @Before public void init() {
++ txnMgr = new TransactionCoordinator(Location.mem()) ;
++ unit = new TransactionalBase(txnMgr) ;
++ txnMgr.start();
++ }
++
++ @After public void after() {
++ txnMgr.shutdown();
++ }
++
++
++ @Test public void txn_coord_disable_writers_1() {
++ AtomicInteger counter1 = new AtomicInteger(0) ;
++ AtomicInteger counter2 = new AtomicInteger(0) ;
++
++ txnMgr.blockWriters();
++ ThreadTxn threadTxn1 = ThreadTxn.threadTxnRead(unit, ()->counter1.incrementAndGet()) ;
++ threadTxn1.run() ;
++ assertEquals(1, counter1.get()) ;
++ }
++
++ @Test public void txn_coord_disable_writers_2() {
++ txnMgr.blockWriters();
++ Transaction txn = L.syncCallThread(()->txnMgr.begin(ReadWrite.WRITE, false)) ;
++ assertNull(txn) ;
++ txnMgr.enableWriters();
++ Transaction txn1 = L.syncCallThread(()->txnMgr.begin(ReadWrite.WRITE, false)) ;
++ assertNotNull(txn1) ;
++ }
++
++ @Test public void txn_coord_disable_writers_3() {
++ txnMgr.blockWriters();
++ Transaction txn = L.syncCallThread(()->txnMgr.begin(ReadWrite.READ, false)) ;
++ assertNotNull(txn) ;
++ txnMgr.enableWriters();
++ Transaction txn1 = L.syncCallThread(()->txnMgr.begin(ReadWrite.WRITE, false)) ;
++ assertNotNull(txn1) ;
++ Transaction txn2 = L.syncCallThread(()->txnMgr.begin(ReadWrite.READ, false)) ;
++ assertNotNull(txn2) ;
++ }
++
++ @Test(expected=TransactionException.class)
++ public void txn_coord_disable_writers_4() {
++ txnMgr.blockWriters();
++ txnMgr.enableWriters();
++ txnMgr.enableWriters();
++ }
++
++ @Test
++ public void txn_coord_disable_writers_() {
++ txnMgr.blockWriters();
++ boolean b = txnMgr.tryBlockWriters() ;
++ assertFalse(b) ;
++ txnMgr.enableWriters();
++ }
++
++ @Test public void txn_coord_exclusive_1() {
++ txnMgr.startExclusiveMode();
++ L.syncOtherThread(()->{
++ Transaction txn1 = txnMgr.begin(ReadWrite.WRITE, false) ;
++ assertNull(txn1) ;
++ Transaction txn2 = txnMgr.begin(ReadWrite.READ, false) ;
++ assertNull(txn2) ;
++ }) ;
++
++ txnMgr.finishExclusiveMode();
++ L.syncOtherThread(()->{
++ Transaction txn1 = txnMgr.begin(ReadWrite.WRITE, false) ;
++ assertNotNull(txn1) ;
++ Transaction txn2 = txnMgr.begin(ReadWrite.READ, false) ;
++ assertNotNull(txn2) ;
++ }) ;
++ }
++
++ @Test public void txn_coord_exclusive_2() {
++ AtomicInteger counter1 = new AtomicInteger(0) ;
++ Semaphore finalSema = new Semaphore(0) ;
++ ThreadTxn ttxn = ThreadTxn.threadTxnWrite(unit, ()->{
++ counter1.incrementAndGet() ;
++ }) ;
++ boolean b = txnMgr.tryExclusiveMode(false);
++ assertFalse(b) ;
++ assertEquals(0, counter1.get()) ;
++ ttxn.run(); // Now run thread
++ assertEquals(1, counter1.get()) ;
++ Txn.executeWrite(unit, ()->{});
++ b = txnMgr.tryExclusiveMode(false);
++ assertTrue(b) ;
++ }
++
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTransactionLifecycle.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTransactionLifecycle.java
index 0000000,0000000..b7f0c43
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTransactionLifecycle.java
@@@ -1,0 -1,0 +1,261 @@@
++/*
++ * 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.dboe.transaction;
++
++import static org.junit.Assert.fail ;
++import org.junit.Test ;
++import org.seaborne.dboe.transaction.txn.TransactionException ;
++
++import org.apache.jena.query.ReadWrite ;
++
++/**
++ * Tests of transaction lifecycle in one JVM.
++ * Journal independent.
++ * Not testing recovery or writing to the journal.
++ */
++public class TestTransactionLifecycle extends AbstractTestTxn {
++ @Test public void txn_read_end() {
++ unit.begin(ReadWrite.READ);
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_read_end_end() {
++ unit.begin(ReadWrite.READ);
++ unit.end() ;
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_read_abort() {
++ unit.begin(ReadWrite.READ);
++ unit.abort() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_read_commit() {
++ unit.begin(ReadWrite.READ);
++ unit.commit() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_read_abort_end() {
++ unit.begin(ReadWrite.READ);
++ unit.abort() ;
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_read_commit_end() {
++ unit.begin(ReadWrite.READ);
++ unit.commit() ;
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_read_commit_abort() {
++ unit.begin(ReadWrite.READ);
++ unit.commit() ;
++ try { unit.abort() ; fail() ; }
++ catch (TransactionException ex) { /* Expected : can continue */ }
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_read_commit_commit() {
++ unit.begin(ReadWrite.READ);
++ unit.commit() ;
++ try { unit.commit() ; fail() ; }
++ catch (TransactionException ex) { /* Expected : can continue */ }
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_read_abort_commit() {
++ unit.begin(ReadWrite.READ);
++ unit.abort() ;
++ try { unit.commit() ; fail() ; }
++ catch (TransactionException ex) { /* Expected : can continue */ }
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_read_abort_abort() {
++ unit.begin(ReadWrite.READ);
++ unit.abort() ;
++ try { unit.abort() ; fail() ; }
++ catch (TransactionException ex) { /* Expected : can continue */ }
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test(expected=TransactionException.class)
++ public void txn_begin_read_begin_read() {
++ unit.begin(ReadWrite.READ);
++ unit.begin(ReadWrite.READ);
++ }
++
++ @Test(expected=TransactionException.class)
++ public void txn_begin_read_begin_write() {
++ unit.begin(ReadWrite.READ);
++ unit.begin(ReadWrite.WRITE);
++ }
++
++ @Test(expected=TransactionException.class)
++ public void txn_begin_write_begin_read() {
++ unit.begin(ReadWrite.WRITE);
++ unit.begin(ReadWrite.READ);
++ }
++
++ @Test(expected=TransactionException.class)
++ public void txn_begin_write_begin_write() {
++ unit.begin(ReadWrite.WRITE);
++ unit.begin(ReadWrite.WRITE);
++ }
++
++ @Test(expected=TransactionException.class)
++ public void txn_write_begin_end() {
++ unit.begin(ReadWrite.WRITE);
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_write_abort() {
++ unit.begin(ReadWrite.WRITE);
++ unit.abort() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_write_commit() {
++ unit.begin(ReadWrite.WRITE);
++ unit.commit() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_write_abort_end() {
++ unit.begin(ReadWrite.WRITE);
++ unit.abort() ;
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_write_abort_end_end() {
++ unit.begin(ReadWrite.WRITE);
++ unit.abort() ;
++ unit.end() ;
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_write_commit_end() {
++ unit.begin(ReadWrite.WRITE);
++ unit.commit() ;
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_write_commit_end_end() {
++ unit.begin(ReadWrite.WRITE);
++ unit.commit() ;
++ unit.end() ;
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_write_commit_abort() {
++ // commit-abort
++ unit.begin(ReadWrite.WRITE);
++ unit.commit() ;
++ try { unit.abort() ; fail() ; }
++ catch (TransactionException ex) { /* Expected : can continue */ }
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_write_commit_commit() {
++ // commit-commit
++ unit.begin(ReadWrite.WRITE);
++ unit.commit() ;
++ try { unit.commit() ; fail() ; }
++ catch (TransactionException ex) { /* Expected : can continue */ }
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_write_abort_commit() {
++ // abort-commit
++ unit.begin(ReadWrite.WRITE);
++ unit.abort() ;
++ try { unit.commit() ; fail() ; }
++ catch (TransactionException ex) { /* Expected : can continue */ }
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_write_abort_abort() {
++ // abort-abort
++ unit.begin(ReadWrite.WRITE);
++ unit.abort() ;
++ try { unit.abort() ; fail() ; }
++ catch (TransactionException ex) { /* Expected : can continue */ }
++ unit.end() ;
++ checkClear() ;
++ }
++
++ private void read() {
++ unit.begin(ReadWrite.READ);
++ unit.end() ;
++ checkClear() ;
++ }
++
++ private void write() {
++ unit.begin(ReadWrite.WRITE);
++ unit.commit() ;
++ unit.end() ;
++ checkClear() ;
++ }
++
++ @Test public void txn_read_read() {
++ read() ;
++ read() ;
++ }
++
++ @Test public void txn_write_read() {
++ write() ;
++ read() ;
++ }
++
++ @Test public void txn_read_write() {
++ read() ;
++ write() ;
++ }
++
++ @Test public void txn_write_write() {
++ write() ;
++ write() ;
++ }
++
++ @Test public void txn_www() {
++ write() ;
++ write() ;
++ write() ;
++ checkClear();
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTransactionLifecycle2.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTransactionLifecycle2.java
index 0000000,0000000..6deca4e
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTransactionLifecycle2.java
@@@ -1,0 -1,0 +1,298 @@@
++/*
++ * 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.dboe.transaction;
++
++import static org.junit.Assert.* ;
++
++import java.util.concurrent.atomic.AtomicReference ;
++
++import org.apache.jena.query.ReadWrite ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.migrate.L ;
++import org.seaborne.dboe.transaction.txn.Transaction ;
++import org.seaborne.dboe.transaction.txn.TransactionCoordinator ;
++import org.seaborne.dboe.transaction.txn.TransactionException ;
++import org.seaborne.dboe.transaction.txn.journal.Journal ;
++
++/**
++ * Details tests of the transaction lifecycle in one JVM
++ * including tests beyond the TransactionalComponentLifecycle
++ *
++ * Journal independent.
++ */
++public class TestTransactionLifecycle2 {
++ // org.junit.rules.ExternalResource ?
++ protected TransactionCoordinator txnMgr ;
++// protected TransInteger counter1 = new TransInteger(0) ;
++// protected TransInteger counter2 = new TransInteger(0) ;
++// protected TransMonitor monitor = new TransMonitor() ;
++
++ @Before public void setup() {
++ Journal jrnl = Journal.create(Location.mem()) ;
++ txnMgr = new TransactionCoordinator(jrnl) ;
++ txnMgr.start() ;
++ }
++
++ @After public void clearup() {
++ txnMgr.shutdown();
++ }
++
++ protected void checkClear() {
++ assertEquals(0, txnMgr.countActive()) ;
++ assertEquals(0, txnMgr.countBegin()-txnMgr.countFinished()) ;
++ }
++
++ @Test public void txn_direct_01() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.READ) ;
++ txn1.end();
++ checkClear() ;
++ }
++
++ @Test(expected=TransactionException.class)
++ public void txn_direct_02() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.WRITE) ;
++ txn1.end();
++ checkClear() ;
++ }
++
++ @Test
++ public void txn_direct_03() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.WRITE) ;
++ txn1.commit() ;
++ txn1.end() ;
++ checkClear() ;
++ }
++
++ @Test
++ public void txn_direct_04() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.WRITE) ;
++ // This tests the TransactionCoordinator
++ // but the TransactiolComponentLifecycle doesn't support multiple
++ // transactions per thread (use of ThreadLocals).
++ // To do that, the transaction object would be needed in all
++ // component API calls. Doable but intrusive.
++ Transaction txn2 = txnMgr.begin(ReadWrite.READ) ;
++ txn1.commit() ;
++ txn2.end() ;
++ txn1.end() ;
++ checkClear() ;
++ }
++
++ @Test
++ public void txn_direct_05() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.WRITE) ;
++ txn1.prepare() ;
++ txn1.commit() ;
++ txn1.end() ;
++ checkClear() ;
++ }
++
++ @Test
++ public void txn_direct_06() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.WRITE) ;
++ // txn1.prepare() ; Optional.
++ txn1.commit() ;
++ txn1.end() ;
++ checkClear() ;
++ }
++
++ @Test
++ public void txn_overlap_WW() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.WRITE, false) ;
++ assertNotNull(txn1) ;
++
++ Transaction txn2 = txnMgr.begin(ReadWrite.WRITE, false) ;
++ assertNull(txn2) ; // Otherwise blocking.
++
++ txn1.commit();
++ txn1.end() ;
++ checkClear() ;
++ }
++
++ @Test
++ public void txn_overlap_WR() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.WRITE, false) ;
++ assertNotNull(txn1) ;
++
++ Transaction txn2 = txnMgr.begin(ReadWrite.READ, false) ;
++ assertNotNull(txn2) ;
++
++ txn1.commit();
++ txn1.end() ;
++ txn2.end();
++ checkClear() ;
++ }
++
++ @Test
++ public void txn_overlap_RW() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.READ, false) ;
++ assertNotNull(txn1) ;
++
++ Transaction txn2 = txnMgr.begin(ReadWrite.WRITE, false) ;
++ assertNotNull(txn2) ;
++ txn1.commit();
++ txn1.end() ;
++ txn2.abort();
++ txn2.end();
++ checkClear() ;
++ }
++
++ @Test
++ public void txn_overlap_RR() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.READ, false) ;
++ assertNotNull(txn1) ;
++
++ Transaction txn2 = txnMgr.begin(ReadWrite.READ, false) ;
++ assertNotNull(txn2) ;
++
++ txn1.commit();
++ txn1.end() ;
++ txn2.end();
++ checkClear() ;
++ }
++
++ @Test
++ public void txn_promote_1() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.READ) ;
++ assertNotNull(txn1) ;
++ boolean b = txn1.promote() ;
++ assertTrue(b) ;
++ assertEquals(ReadWrite.WRITE, txn1.getMode()) ;
++ txn1.commit() ;
++ txn1.end() ;
++ checkClear() ;
++ }
++
++ @Test
++ public void txn_promote_2() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.WRITE) ;
++ boolean b = txn1.promote() ;
++ assertTrue(b) ;
++ b = txn1.promote() ;
++ assertTrue(b) ;
++ txn1.abort() ;
++ txn1.end() ;
++ checkClear() ;
++ }
++
++ @Test(expected=TransactionException.class)
++ public void txn_promote_3() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.READ) ;
++ boolean b = txn1.promote() ;
++ assertTrue(b) ;
++ b = txn1.promote() ;
++ assertTrue(b) ;
++ // Exception - now a writer
++ txn1.end() ;
++ checkClear() ;
++ }
++
++ //Not a @Test
++ public void txn_promote_deadlock() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.READ) ;
++ Transaction txn2 = txnMgr.begin(ReadWrite.WRITE) ;
++ // Deadlock.
++ // Promotion waits for the writer to decide whether it is commiting or not.
++ // This can't be done on one thread.
++ boolean b = txn1.promote() ;
++ assertFalse(b) ;
++ txn1.end() ;
++ txn2.commit();
++ txn2.end() ;
++ checkClear() ;
++ }
++
++ @Test
++ public void txn_promote_thread_writer_1() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.READ) ;
++ L.syncOtherThread(()->{
++ Transaction txn2 = txnMgr.begin(ReadWrite.WRITE) ;
++ txn2.commit();
++ txn2.end() ;
++ }) ;
++
++ boolean b = txn1.promote() ;
++ assertFalse(b) ;
++ txn1.end() ;
++ checkClear() ;
++ }
++
++ @Test
++ public void txn_promote_thread_writer_2() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.READ) ;
++ L.syncOtherThread(()->{
++ Transaction txn2 = txnMgr.begin(ReadWrite.WRITE) ;
++ txn2.abort();
++ txn2.end() ;
++ }) ;
++
++ boolean b = txn1.promote() ;
++ assertTrue(b) ;
++ // Now a writer.
++ txn1.commit();
++ txn1.end() ;
++ checkClear() ;
++ }
++
++ @Test
++ public void txn_promote_thread_writer_3() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.READ) ;
++ boolean b = txn1.promote() ;
++ assertTrue(b) ;
++ AtomicReference<Transaction> ref = new AtomicReference<>(txn1) ;
++ L.syncOtherThread(()->{
++ // Should fail.
++ Transaction txn2 = txnMgr.begin(ReadWrite.WRITE, false) ;
++ ref.set(txn2);
++ }) ;
++ assertNull(ref.get()) ;
++ txn1.abort() ;
++ txn1.end() ;
++ }
++
++ @Test
++ public void txn_promote_thread_writer_4() {
++ Transaction txn1 = txnMgr.begin(ReadWrite.READ) ;
++ boolean b = txn1.promote() ;
++ assertTrue(b) ;
++ AtomicReference<Transaction> ref = new AtomicReference<>(txn1) ;
++ L.syncOtherThread(()->{
++ // Should fail.
++ Transaction txn2 = txnMgr.begin(ReadWrite.WRITE, false) ;
++ ref.set(txn2);
++ }) ;
++ assertNull(ref.get()) ;
++ txn1.abort() ;
++ txn1.end() ;
++
++ L.syncOtherThread(()->{
++ // Should suceed
++ Transaction txn2 = txnMgr.begin(ReadWrite.WRITE, false) ;
++ ref.set(txn2);
++ txn2.abort() ;
++ txn2.end() ;
++ }) ;
++ assertNotNull(ref.get()) ;
++ checkClear() ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTxnId.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTxnId.java
index 0000000,0000000..ad7af38
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTxnId.java
@@@ -1,0 -1,0 +1,52 @@@
++/*
++ * 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.dboe.transaction;
++
++import static org.junit.Assert.assertEquals ;
++import static org.junit.Assert.assertNotEquals ;
++import static org.junit.Assert.assertNotNull ;
++import static org.junit.Assert.assertNotSame ;
++
++import org.junit.Test ;
++import org.seaborne.dboe.transaction.txn.TxnId ;
++import org.seaborne.dboe.transaction.txn.TxnIdFactory ;
++import org.seaborne.dboe.transaction.txn.TxnIdSimple ;
++
++public class TestTxnId {
++ @Test public void txnId_1() {
++ TxnId id1 = TxnIdFactory.createSimple() ;
++ assertNotNull(id1) ;
++ }
++
++ @Test public void txnId_2() {
++ TxnId id1 = TxnIdFactory.createSimple() ;
++ TxnId id2 = TxnIdFactory.createSimple() ;
++ assertNotSame(id1, id2) ;
++ assertNotEquals(id1, id2) ;
++ }
++
++ @Test public void txnId_3() {
++ TxnId id1 = TxnIdFactory.createSimple() ;
++ TxnId id2 = TxnIdSimple.create(id1.bytes()) ;
++ assertNotSame(id1, id2) ;
++ assertEquals(id1, id2) ;
++ assertEquals(id1.name(), id2.name()) ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTxnLib.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTxnLib.java
index 0000000,0000000..0006573
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTxnLib.java
@@@ -1,0 -1,0 +1,197 @@@
++/*
++ * 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.dboe.transaction;
++
++import static org.junit.Assert.assertEquals ;
++import static org.junit.Assert.assertNotEquals ;
++import static org.junit.Assert.fail ;
++
++import org.apache.jena.query.ReadWrite ;
++import org.junit.Test ;
++import org.seaborne.dboe.jenax.Txn ;
++
++public class TestTxnLib extends AbstractTestTxn {
++
++ @Test public void libTxn_1() {
++ long v1 = counter1.value() ;
++ long v2 = counter2.value() ;
++ assertEquals(0, v1) ;
++ assertEquals(0, v2) ;
++
++ Txn.executeRead(unit, () -> {
++ assertEquals(0, counter1.get()) ;
++ assertEquals(0, counter2.get()) ;
++ }) ;
++ }
++
++ @Test public void libTxn_2() {
++ assertEquals(0, counter1.value()) ;
++
++ Txn.executeWrite(unit, () -> {
++ counter1.inc() ;
++ assertEquals("In W, value()", 0, counter1.value()) ;
++ assertEquals("In W, get()",1, counter1.get()) ;
++ }) ;
++
++ assertEquals("Direct value()", 1, counter1.value()) ;
++ assertEquals("Direct get()", 1, counter1.get()) ;
++
++ Txn.executeRead(unit, () -> {
++ assertEquals("In R, value()", 1, counter1.get()) ;
++ assertEquals("In R, get()", 1, counter1.value()) ;
++ }) ;
++ }
++
++ @Test public void libTxn_3() {
++ Txn.executeRead(unit, () -> {
++ assertEquals("In R, value()", 0, counter2.get()) ;
++ assertEquals("In R, get()", 0, counter2.value()) ;
++ }) ;
++
++ Txn.executeWrite(unit, () -> {
++ counter2.inc() ;
++ assertEquals("In W, value()", 0, counter2.value()) ;
++ assertEquals("In W, get()",1, counter2.get()) ;
++ }) ;
++
++ assertEquals("Direct value()", 1, counter2.value()) ;
++ assertEquals("Direct get()", 1, counter2.get()) ;
++
++ Txn.executeRead(unit, () -> {
++ assertEquals("In R, value()", 1, counter2.get()) ;
++ assertEquals("In R, get()", 1, counter2.value()) ;
++ }) ;
++ }
++
++ @Test public void libTxn_4() {
++ long v1 = counter1.value() ;
++ long v2 = counter2.value() ;
++ assertEquals(0, v1) ;
++ assertEquals(0, v2) ;
++
++ //Txn.execWrite(unit, () -> {
++
++ unit.begin(ReadWrite.WRITE);
++ counter1.inc() ;
++ counter2.inc() ;
++ assertEquals("Counter out of step", counter1.get(), counter2.get());
++ assertNotEquals("Counter 1 can see wrong state", counter1.get(), counter1.value() ) ;
++ assertNotEquals("Counter 2 can see wrong state", counter2.get(), counter2.value() ) ;
++ counter2.inc() ;
++ assertNotEquals("Counter 1 and 2 should differ", counter1.get(), counter2.get() ) ;
++ unit.commit() ;
++ unit.end() ;
++ //}) ;
++ assertEquals("Component 1 inconsistent", 1, counter1.value()) ;
++ assertEquals("Component 2 inconsistent", 2, counter2.value()) ;
++
++ Txn.executeRead(unit, () -> {
++ assertEquals("Component 1 inconsistent (R)", 1, counter1.get()) ;
++ assertEquals("Component 2 inconsistent (R)", 2, counter2.get()) ;
++ }) ;
++ }
++
++ @Test public void libTxn_5() {
++ long x =
++ Txn.calculateRead(unit, () -> {
++ assertEquals("In R, value()", 0, counter2.get()) ;
++ assertEquals("In R, get()", 0, counter2.value()) ;
++ return counter2.get() ;
++ }) ;
++ assertEquals("Outside R", 0, x) ;
++ }
++
++ @Test public void libTxn_6() {
++ long x =
++ Txn.calculateWrite(unit, () -> {
++ counter2.inc() ;
++ assertEquals("In W, value()", 0, counter2.value()) ;
++ assertEquals("In W, get()",1, counter2.get()) ;
++ return counter2.get() ;
++ }) ;
++ assertEquals("Outside W",1, x) ;
++ }
++
++ @Test public void libTxn_7() {
++ long x1 =
++ Txn.calculateWrite(unit, () -> {
++ counter2.inc() ;
++ counter2.inc() ;
++ return counter2.get() ;
++ }) ;
++ long x2 = Txn.calculateRead(unit, () -> {
++ return counter2.get() ;
++ }) ;
++ assertEquals("After W and R",x1 , x2) ;
++ }
++
++ // Tests for thread transactions.
++
++ @Test public void libTxnThread_1() {
++ ThreadTxn t = ThreadTxn.threadTxnRead(unit, ()->{}) ;
++ t.run();
++ }
++
++ @Test public void libTxnThread_2() {
++ ThreadTxn t = ThreadTxn.threadTxnWrite(unit, ()-> fail("")) ;
++ }
++
++ @Test(expected=AssertionError.class)
++ public void libTxnThread_3() {
++ ThreadTxn t = ThreadTxn.threadTxnWrite(unit, ()-> fail("")) ;
++ t.run() ;
++ }
++
++ @Test public void libTxnThread_10() {
++ long x1 = counter1.get() ;
++ ThreadTxn t = ThreadTxn.threadTxnWrite(unit, ()->{ counter1.inc() ;}) ;
++ long x2 = counter1.get() ;
++ assertEquals("x2", x1, x2) ;
++ t.run() ;
++ long x3 = counter1.get() ;
++ assertEquals("x3", x1+1, x3) ;
++ }
++
++ @Test public void libTxnThread_11() {
++ long x1 = counter1.get() ;
++ Txn.executeWrite(unit, ()->{
++ counter1.inc();
++ // Read the "before" state
++ ThreadTxn t = ThreadTxn.threadTxnRead(unit, ()->{ long z1 = counter1.get() ; assertEquals("Thread read", x1, z1) ; }) ;
++ counter1.inc();
++ t.run();
++ }) ;
++ long x2 = counter1.get() ;
++ assertEquals("after", x1+2, x2) ;
++ }
++
++ @Test public void libTxnThread_12() {
++ long x1 = counter1.get() ;
++ ThreadTxn t = ThreadTxn.threadTxnRead(unit, () -> {
++ long z1 = counter1.get() ;
++ assertEquals("Thread", x1, z1) ;
++ }) ;
++ Txn.executeWrite(unit, ()->counter1.inc()) ;
++ t.run() ;
++ long x2 = counter1.get() ;
++ assertEquals("after", x1+1, x2) ;
++ }
++
++}
++
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTxnLib2.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTxnLib2.java
index 0000000,0000000..227e2a7
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTxnLib2.java
@@@ -1,0 -1,0 +1,65 @@@
++/*
++ * 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.dboe.transaction;
++
++import org.apache.jena.atlas.lib.Pair ;
++import org.junit.After ;
++import org.junit.Assert ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.dboe.transaction.txn.TransactionCoordinator ;
++
++/** Unusual ways to do things.
++ * Rather than a TransactionalComponent,
++ * TransactionalInteger
++ */
++public class TestTxnLib2 extends Assert {
++ // With setup/teardown / not from AbstractTestTxn
++ private final long InitValue = 7 ;
++ TransactionalInteger integer ;
++
++ @Before public void setup() {
++ TransactionCoordinator coord = new TransactionCoordinator(Location.mem()) ;
++ integer = new TransactionalInteger(coord, InitValue) ;
++ coord.start() ;
++ }
++
++ @After public void clearup() {
++ integer.shutdown();
++ }
++
++ @Test public void libTxn_10() {
++ Txn.executeWrite(integer, integer::inc) ;
++ long x = Txn.calculateRead(integer, integer::get) ;
++ assertEquals(InitValue+1, x) ;
++ }
++
++ @Test public void libTxn_11() {
++ Pair<Long, Long> p = Txn.calculateWrite(integer, () -> {
++ integer.inc() ;
++ return Pair.create(integer.value(), integer.get()) ;
++ }) ;
++ assertEquals(InitValue, p.getLeft().longValue()) ;
++ assertEquals(InitValue+1, p.getRight().longValue()) ;
++ assertEquals(InitValue+1, integer.get()) ;
++ assertEquals(InitValue+1, integer.value()) ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTxnSwitching.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTxnSwitching.java
index 0000000,0000000..2d0b025
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TestTxnSwitching.java
@@@ -1,0 -1,0 +1,192 @@@
++/*
++ * 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.dboe.transaction;
++
++import static org.junit.Assert.assertEquals ;
++import static org.junit.Assert.fail ;
++
++import org.apache.jena.query.ReadWrite ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.dboe.transaction.txn.* ;
++import org.seaborne.dboe.transaction.txn.journal.Journal ;
++
++/** Tests of changing the thread state ... carefully */
++public class TestTxnSwitching {
++ TransInteger integer = new TransInteger(100) ;
++ Journal jrnl = Journal.create(Location.mem()) ;
++
++ //Transactional transactional = TransactionalFactory.create(jrnl, integer) ;
++ TransactionalBase transactional ;
++ TransactionCoordinator txnMgr = new TransactionCoordinator(jrnl) ;
++ {
++ txnMgr.add(integer) ;
++ transactional = new TransactionalBase(txnMgr) ;
++ txnMgr.start() ;
++ }
++
++
++ @Before public void setup() {
++ }
++
++ @After public void clearup() {
++ }
++
++ @Test public void txnSwitch_01() {
++ long z = integer.value() ;
++ transactional.begin(ReadWrite.WRITE);
++ integer.inc();
++
++ assertEquals(integer.value()+1, integer.get()) ;
++ assertEquals(z+1, integer.get()) ;
++
++ TransactionCoordinatorState txnState = transactional.detach() ;
++
++ assertEquals(integer.value(), integer.get()) ;
++ assertEquals(z, integer.get()) ;
++
++ transactional.attach(txnState);
++
++ assertEquals(integer.value()+1, integer.get()) ;
++ assertEquals(z+1, integer.get()) ;
++
++ transactional.commit() ;
++ transactional.end() ;
++ assertEquals(z+1, integer.get()) ;
++ assertEquals(z+1, integer.value()) ;
++ }
++
++ @Test public void txnSwitch_02() {
++ long z = integer.value() ;
++ Txn.executeWrite(transactional, ()->integer.inc());
++ assertEquals(z+1, integer.value()) ;
++
++
++ //Transaction txn = txnMgr.begin(ReadWrite.WRITE) ;
++ transactional.begin(ReadWrite.WRITE);
++ integer.inc();
++ assertEquals(z+2, integer.get()) ;
++ TransactionCoordinatorState txnState = transactional.detach() ;
++ // Can't transactional read.
++ try { integer.read() ; fail() ; } catch (TransactionException ex) {}
++
++ long z1 = Txn.calculateRead(transactional, ()->integer.get()) ;
++ assertEquals(z+1, z1) ;
++ transactional.attach(txnState) ;
++ integer.inc();
++ assertEquals(z+3, integer.get()) ;
++
++ ThreadTxn threadTxn = ThreadTxn.threadTxnRead(transactional, ()->assertEquals(z+1, integer.get())) ;
++ threadTxn.run() ;
++
++ transactional.commit() ;
++ transactional.end() ;
++ }
++
++ // As 02 but with Transaction txn = txnMgr.begin(ReadWrite.WRITE) ;
++ // and txn calls and integer calls. Not transactional calls but txnMgr calls.
++
++ @Test public void txnSwitch_03() {
++ long z = integer.value() ;
++ Txn.executeWrite(transactional, ()->integer.inc());
++ assertEquals(z+1, integer.value()) ;
++
++ Transaction txn = txnMgr.begin(ReadWrite.WRITE) ;
++ integer.inc();
++ assertEquals(z+2, integer.get()) ;
++ TransactionCoordinatorState txnState = txnMgr.detach(txn) ;
++
++ Transaction txnRead = txnMgr.begin(ReadWrite.READ) ;
++ assertEquals(z+1, integer.get()) ;
++ txnRead.end() ;
++
++ try { integer.read() ; fail() ; } catch (TransactionException ex) {}
++
++ txnMgr.attach(txnState);
++
++ integer.inc();
++ assertEquals(z+3, integer.get()) ;
++
++ ThreadTxn.threadTxnRead(transactional, ()->assertEquals(z+1, integer.get())).run();
++ txn.commit();
++ txn.end() ;
++ }
++
++ // Switch between read and write all on one thread.
++ @Test public void txnSwitch_04() {
++ long z = integer.value() ;
++
++ transactional.begin(ReadWrite.READ);
++ TransactionCoordinatorState txnStateR1 = transactional.detach() ;
++
++ ThreadTxn t1 = ThreadTxn.threadTxnRead(transactional, ()->assertEquals(z, integer.get() )) ;
++ ThreadTxn t2 = ThreadTxn.threadTxnRead(transactional, ()->assertEquals(z, integer.get() )) ;
++
++ transactional.begin(ReadWrite.WRITE);
++ integer.inc();
++
++ TransactionCoordinatorState txnStateW1 = transactional.detach() ;
++
++ // Currently, thread has no transaction.
++ long z1 = Txn.calculateRead(transactional, ()->integer.get() );
++ assertEquals(z, z1) ;
++
++ // Back to writer.
++ transactional.attach(txnStateW1) ;
++ integer.inc();
++ TransactionCoordinatorState txnStateW2 = transactional.detach() ;
++
++ try { integer.read() ; fail() ; } catch (TransactionException ex) {}
++ // To reader.
++ transactional.attach(txnStateR1) ;
++ assertEquals(z1, integer.read()) ;
++ t1.run() ;
++
++ // And the writer again.
++ TransactionCoordinatorState txnStateR2 = transactional.detach() ;
++ transactional.attach(txnStateW2) ;
++ integer.inc();
++ transactional.commit();
++ transactional.end() ;
++
++ t2.run() ;
++ transactional.attach(txnStateR2) ;
++ assertEquals(z1, integer.read()) ;
++ transactional.end() ;
++ }
++
++ // Some error cases.
++ @Test(expected=TransactionException.class)
++ public void txnSwitch_10() {
++ transactional.begin(ReadWrite.READ);
++ TransactionCoordinatorState txnState = transactional.detach() ;
++ transactional.attach(txnState);
++ transactional.attach(txnState);
++ }
++ @Test(expected=TransactionException.class)
++ public void txnSwitch_11() {
++ transactional.begin(ReadWrite.READ);
++ TransactionCoordinatorState txnState1 = transactional.detach() ;
++ TransactionCoordinatorState txnState2 = transactional.detach() ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TransactionalInteger.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TransactionalInteger.java
index 0000000,0000000..6118758
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TransactionalInteger.java
@@@ -1,0 -1,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.dboe.transaction;
++
++import org.seaborne.dboe.transaction.txn.TransactionCoordinator ;
++import org.seaborne.dboe.transaction.txn.TransactionalBase ;
++
++/**
++ * A Transactional (unit of begin/commit) of a single integer component.
++ * Testing support. Use {@link TransInteger} for application code.
++ * @see TransInteger
++ */
++public class TransactionalInteger extends TransactionalBase {
++ final private TransInteger integer ;
++
++ public TransactionalInteger(TransactionCoordinator coord, long v) {
++ super(coord) ;
++ integer = new TransInteger(v) ;
++ coord.add(integer) ;
++ }
++
++ public void inc() {
++ integer.inc() ;
++ }
++
++ /** Return the current value.
++ * If inside a transaction, return the tarnsaction view of the value.
++ * If not in a transaction return the state value (effectively
++ * a fast read transaction).
++ */
++ public long get() {
++ return integer.get() ;
++ }
++
++ public void set(long v) {
++ integer.set(v) ;
++ }
++
++ /** Return the currently commited value */
++ public long value() {
++ return integer.value() ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/test/resources/log4j.properties
index 0000000,0000000..d6b299a
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/test/resources/log4j.properties
@@@ -1,0 -1,0 +1,6 @@@
++log4j.rootLogger=INFO, stdlog
++
++log4j.appender.stdlog=org.apache.log4j.ConsoleAppender
++## log4j.appender.stdlog.target=System.err
++log4j.appender.stdlog.layout=org.apache.log4j.PatternLayout
++log4j.appender.stdlog.layout.ConversionPattern=%d{HH:mm:ss} %-5p %-20c{1} :: %m%n
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/fuseki-tdb2/pom.xml
----------------------------------------------------------------------
diff --cc jena-db/fuseki-tdb2/pom.xml
index 0000000,0000000..8205005
new file mode 100644
--- /dev/null
+++ b/jena-db/fuseki-tdb2/pom.xml
@@@ -1,0 -1,0 +1,129 @@@
++<?xml version="1.0" encoding="utf-8"?>
++<!--
++ 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.
++-->
++
++<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
++ <modelVersion>4.0.0</modelVersion>
++
++ <name>Mantis (${project.artifactId})</name>
++ <artifactId>fuseki-tdb2-server</artifactId>
++
++ <parent>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>mantis</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </parent>
++
++ <packaging>jar</packaging>
++ <description>Apache Jena Fuseki combined with Mantis/TDB2</description>
++
++ <dependencies>
++
++ <dependency>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>tdb2</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </dependency>
++
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-fuseki-core</artifactId>
++ <version>${ver.fuseki}</version>
++ </dependency>
++
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-cmds</artifactId>
++ </dependency>
++
++ <dependency>
++ <groupId>org.slf4j</groupId>
++ <artifactId>slf4j-log4j12</artifactId>
++ <scope>runtime</scope>
++ </dependency>
++
++ <dependency>
++ <groupId>log4j</groupId>
++ <artifactId>log4j</artifactId>
++ <scope>runtime</scope>
++ </dependency>
++
++ </dependencies>
++
++ <build>
++ <plugins>
++
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-shade-plugin</artifactId>
++ <version>2.4.3</version>
++ <configuration>
++ <shadedArtifactAttached>false</shadedArtifactAttached>
++ <transformers>
++ <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
++ <!--<mainClass>org.apache.jena.fuseki.cmd.FusekiCmd</mainClass>-->
++ <mainClass>org.seaborne.fuseki.cmd.FusekiTDB2Cmd</mainClass>
++ </transformer>
++ <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
++ <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer" />
++ <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheNoticeResourceTransformer">
++ <addHeader>false</addHeader>
++ </transformer>
++ </transformers>
++ <filters>
++ <filter>
++ <artifact>*:*</artifact>
++ <excludes>
++ <!-- Some jars are signed but shading breaks that.
++ Don't include signing files.
++ -->
++ <exclude>META-INF/*.SF</exclude>
++ <exclude>META-INF/*.DSA</exclude>
++ <exclude>META-INF/*.RSA</exclude>
++ </excludes>
++ </filter>
++ </filters>
++ </configuration>
++ <executions>
++ <execution>
++ <phase>package</phase>
++ <!--<phase /><!- - Switch off -->
++ <goals>
++ <goal>shade</goal>
++ </goals>
++ </execution>
++ </executions>
++ </plugin>
++
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-source-plugin</artifactId>
++ <executions>
++ <execution>
++ <id>attach-sources</id>
++ <goals>
++ <goal>jar-no-fork</goal>
++ </goals>
++ </execution>
++ </executions>
++ </plugin>
++
++ </plugins>
++
++ </build>
++
++</project>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/fuseki-tdb2/src/main/java/org/seaborne/fuseki/cmd/FusekiTDB2Cmd.java
----------------------------------------------------------------------
diff --cc jena-db/fuseki-tdb2/src/main/java/org/seaborne/fuseki/cmd/FusekiTDB2Cmd.java
index 0000000,0000000..25e1314
new file mode 100644
--- /dev/null
+++ b/jena-db/fuseki-tdb2/src/main/java/org/seaborne/fuseki/cmd/FusekiTDB2Cmd.java
@@@ -1,0 -1,0 +1,33 @@@
++/*
++ * 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.fuseki.cmd;
++
++import org.apache.jena.fuseki.Fuseki;
++import org.apache.jena.fuseki.FusekiLogging;
++import org.apache.jena.fuseki.cmd.FusekiCmd;
++
++public class FusekiTDB2Cmd {
++
++ public static void main(String... args) {
++ FusekiLogging.setLogging() ;
++ Fuseki.serverLog.info("Fuseki-TDB2 integration");
++ FusekiCmd.main(args);
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/pom.xml
----------------------------------------------------------------------
diff --cc jena-db/pom.xml
index 0000000,0000000..9be78e4
new file mode 100644
--- /dev/null
+++ b/jena-db/pom.xml
@@@ -1,0 -1,0 +1,421 @@@
++<?xml version="1.0" encoding="utf-8"?>
++<!--
++ 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.
++-->
++
++<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
++ <modelVersion>4.0.0</modelVersion>
++
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>mantis</artifactId>
++ <packaging>pom</packaging>
++ <url>https://github.com/afs/mantis</url>
++ <version>0.3.1-SNAPSHOT</version>
++ <name>Mantis :: Database Operation Environment</name>
++ <description>Mantis :: Database Operation Environment</description>
++
++ <licenses>
++ <license>
++ <name>Apache License 2.0</name>
++ <url>http://www.apache.org/licenses/LICENSE-2.0</url>
++ </license>
++ </licenses>
++
++ <developers>
++ <developer>
++ <name>Andy Seaborne</name>
++ </developer>
++ </developers>
++ <!--
++ <contributors></contributors>
++ <mailingLists></mailingLists>
++ -->
++
++ <issueManagement>
++ <url>https://github.com/afs/mantis/issues</url>
++ </issueManagement>
++
++ <ciManagement>
++ <url>https://travis-ci.org/afs/mantis</url>
++ </ciManagement>
++
++ <scm>
++ <url>https://github.com/afs/mantis</url>
++ <connection>scm:git:https://github.com/afs/mantis</connection>
++ <developerConnection>scm:git:git@github.com:afs/mantis.git</developerConnection>
++ <tag>HEAD</tag>
++ </scm>
++
++ <properties>
++ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
++ <maven.build.timestamp.format>yyyy-MM-dd'T'HH:mm:ssZ</maven.build.timestamp.format>
++ <build.time.xsd>${maven.build.timestamp}</build.time.xsd>
++ <ver.jena>3.4.0</ver.jena>
++ <ver.tdb>${ver.jena}</ver.tdb>
++ <ver.fuseki>${ver.jena}</ver.fuseki>
++ <ver.junit>4.12</ver.junit>
++ <ver.slf4j>1.7.25</ver.slf4j>
++ <ver.log4j>1.2.17</ver.log4j>
++ </properties>
++
++ <modules>
++ <module>dboe-base</module>
++ <module>dboe-transaction</module>
++ <module>dboe-index</module>
++ <module>dboe-index-test</module>
++ <module>dboe-trans-data</module>
++ <module>tdb2</module>
++ <module>tdb2-cmds</module>
++ <module>fuseki-tdb2</module>
++ </modules>
++
++ <dependencyManagement>
++
++ <dependencies>
++ <!-- For clarity, Jena dependencies do not incldue TDB -->
++ <!-- For now, use more precise control
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>apache-jena-libs</artifactId>
++ <version>${ver.jena}</version>
++ <exclusions>
++ <exclusion>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-tdb</artifactId>
++ </exclusion>
++ </exclusions>
++ </dependency>
++ -->
++
++ <!-- ARQ is essential anyway.
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-core</artifactId>
++ <version>${ver.jena}</version>
++ </dependency>
++ -->
++
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-arq</artifactId>
++ <version>${ver.jena}</version>
++ </dependency>
++
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-cmds</artifactId>
++ <version>${ver.jena}</version>
++ </dependency>
++
++ <!-- Tests -->
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-base</artifactId>
++ <version>${ver.jena}</version>
++ <classifier>tests</classifier>
++ <scope>test</scope>
++ </dependency>
++
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-core</artifactId>
++ <version>${ver.jena}</version>
++ <classifier>tests</classifier>
++ <scope>test</scope>
++ </dependency>
++
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-arq</artifactId>
++ <version>${ver.jena}</version>
++ <classifier>tests</classifier>
++ <scope>test</scope>
++ </dependency>
++
++ <dependency>
++ <groupId>junit</groupId>
++ <artifactId>junit</artifactId>
++ <version>${ver.junit}</version>
++ <scope>test</scope>
++ </dependency>
++
++ <!-- Logging -->
++
++ <dependency>
++ <groupId>org.slf4j</groupId>
++ <artifactId>slf4j-api</artifactId>
++ <version>${ver.slf4j}</version>
++ </dependency>
++
++ <dependency>
++ <groupId>org.slf4j</groupId>
++ <artifactId>slf4j-jdk14</artifactId>
++ <version>${ver.slf4j}</version>
++ <optional>true</optional>
++ </dependency>
++
++ <dependency>
++ <groupId>org.slf4j</groupId>
++ <artifactId>slf4j-log4j12</artifactId>
++ <version>${ver.slf4j}</version>
++ <optional>true</optional>
++ </dependency>
++
++ <!-- And intercept any uses of Jakarta Commons Logging
++ e.g. Apache Common HTTP client.
++ -->
++ <dependency>
++ <groupId>org.slf4j</groupId>
++ <artifactId>jcl-over-slf4j</artifactId>
++ <version>${ver.slf4j}</version>
++ <optional>true</optional>
++ </dependency>
++
++ <dependency>
++ <groupId>log4j</groupId>
++ <artifactId>log4j</artifactId>
++ <version>${ver.log4j}</version>
++ <optional>true</optional>
++ </dependency>
++
++ </dependencies>
++
++ </dependencyManagement>
++
++ <dependencies>
++ <dependency>
++ <groupId>junit</groupId>
++ <artifactId>junit</artifactId>
++ </dependency>
++
++ <!-- Logging in tests -->
++ <dependency>
++ <groupId>org.slf4j</groupId>
++ <artifactId>slf4j-log4j12</artifactId>
++ <scope>test</scope>
++ </dependency>
++
++ <dependency>
++ <groupId>log4j</groupId>
++ <artifactId>log4j</artifactId>
++ <scope>test</scope>
++ </dependency>
++
++ </dependencies>
++
++ <build>
++ <pluginManagement>
++ <plugins>
++
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-compiler-plugin</artifactId>
++ <version>3.6.0</version>
++ <configuration>
++ <encoding>UTF-8</encoding>
++ <debug>true</debug>
++ <debuglevel>source,lines,vars</debuglevel>
++ <optimize>true</optimize>
++ <source>1.8</source>
++ <target>1.8</target>
++ </configuration>
++ </plugin>
++
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-surefire-plugin</artifactId>
++ <version>2.19</version>
++ <!--
++ <configuration>
++ <includes>
++ <include>**/TS_*.java</include>
++ </includes>
++ </configuration>
++ -->
++ </plugin>
++
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-deploy-plugin</artifactId>
++ <version>2.8.2</version>
++ </plugin>
++
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-release-plugin</artifactId>
++ <version>2.5.3</version>
++ <configuration>
++ <goals>deploy</goals>
++ <autoVersionSubmodules>true</autoVersionSubmodules>
++ </configuration>
++ </plugin>
++
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-resources-plugin</artifactId>
++ <version>3.0.0</version>
++ <configuration>
++ <encoding>UTF-8</encoding>
++ </configuration>
++ </plugin>
++
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-dependency-plugin</artifactId>
++ <version>3.0.0</version>
++ <configuration>
++ <overWriteReleases>false</overWriteReleases>
++ <overWriteIfNewer>true</overWriteIfNewer>
++ </configuration>
++ </plugin>
++
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-jar-plugin</artifactId>
++ <version>3.0.2</version>
++ <executions>
++ <execution>
++ <goals>
++ <goal>test-jar</goal>
++ </goals>
++ </execution>
++ </executions>
++ </plugin>
++
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-source-plugin</artifactId>
++ <version>3.0.1</version>
++ <executions>
++ <execution>
++ <id>attach-sources</id>
++ <!-- <phase>package</phase> package is the default -->
++ <goals>
++ <goal>jar-no-fork</goal>
++ </goals>
++ </execution>
++ <execution>
++ <id>attach-sources-test</id>
++ <goals>
++ <goal>test-jar-no-fork</goal>
++ </goals>
++ </execution>
++ </executions>
++ </plugin>
++
++ </plugins>
++
++ </pluginManagement>
++
++ </build>
++
++ <profiles>
++ <profile>
++ <id>release</id>
++ <activation>
++ <property>
++ <name>performRelease</name>
++ <value>true</value>
++ </property>
++ </activation>
++ <build>
++ <plugins>
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-javadoc-plugin</artifactId>
++ <version>2.9.1</version>
++ <executions>
++ <execution>
++ <id>attach-javadocs</id>
++ <goals>
++ <goal>jar</goal>
++ </goals>
++ </execution>
++ </executions>
++ </plugin>
++ <plugin>
++ <groupId>org.apache.maven.plugins</groupId>
++ <artifactId>maven-gpg-plugin</artifactId>
++ <version>1.6</version>
++ <!-- Does this interfer with external -Darguments=-Dgpg.keyname=
++ i.e. is it additive?
++ <configuration>
++ <gpgArguments>
++ <arg>- -digest-algo=SHA512</arg> <comment fix </gpgArguments>
++ </configuration>
++ -->
++ <executions>
++ <execution>
++ <id>sign-artifacts</id>
++ <phase>verify</phase>
++ <goals>
++ <goal>sign</goal>
++ </goals>
++ </execution>
++ </executions>
++ </plugin>
++ </plugins>
++ </build>
++ </profile>
++
++ </profiles>
++
++ <distributionManagement>
++ <snapshotRepository>
++ <id>ossrh.snapshots</id>
++ <name>Sonatype Snapshots Repository</name>
++ <url>https://oss.sonatype.org/content/repositories/snapshots</url>
++ </snapshotRepository>
++ <repository>
++ <id>ossrh.releases</id>
++ <name>Sonatype Gateway to Maven Central</name>
++ <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
++ </repository>
++ </distributionManagement>
++
++ <repositories>
++ <!-- Apache Snapshot Repository -->
++ <repository>
++ <id>apache-repository-snapshots</id>
++ <url>https://repository.apache.org/snapshots</url>
++ <releases>
++ <enabled>false</enabled>
++ </releases>
++ <snapshots>
++ <enabled>true</enabled>
++ <updatePolicy>daily</updatePolicy>
++ <checksumPolicy>fail</checksumPolicy>
++ </snapshots>
++ </repository>
++
++ <!-- Sonatype snapshot repository -->
++ <repository>
++ <id>sonatype.public</id>
++ <name>Sonatype Snapshots Repository</name>
++ <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
++ <releases>
++ <enabled>false</enabled>
++ </releases>
++ <snapshots>
++ <enabled>true</enabled>
++ <updatePolicy>daily</updatePolicy>
++ <checksumPolicy>fail</checksumPolicy>
++ </snapshots>
++ </repository>
++
++ </repositories>
++
++</project>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2-cmds/.gitignore
----------------------------------------------------------------------
diff --cc jena-db/tdb2-cmds/.gitignore
index 0000000,0000000..731afb6
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2-cmds/.gitignore
@@@ -1,0 -1,0 +1,2 @@@
++DB*
++D.*
[40/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/soak/CmdTestBPlusTree.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/soak/CmdTestBPlusTree.java
index 0000000,0000000..9422821
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/soak/CmdTestBPlusTree.java
@@@ -1,0 -1,0 +1,104 @@@
++/*
++ * 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.dboe.trans.bplustree.soak;
++
++import org.seaborne.dboe.base.file.BlockAccessMem ;
++import org.seaborne.dboe.index.test.BaseSoakTest ;
++import org.seaborne.dboe.index.test.IndexTestLib ;
++import org.seaborne.dboe.sys.SystemIndex ;
++import org.seaborne.dboe.sys.Sys ;
++import org.seaborne.dboe.trans.bplustree.BPT ;
++import org.seaborne.dboe.trans.bplustree.BPlusTree ;
++import org.seaborne.dboe.trans.bplustree.BPlusTreeFactory ;
++import org.seaborne.dboe.trans.bplustree.BlockTracker ;
++
++public class CmdTestBPlusTree extends BaseSoakTest
++{
++ static public void main(String... argv) {
++ //argv = new String[] {"50", "150", "1000000"} ;
++// System.setProperty("bpt:checking", "false") ;
++// System.setProperty("bpt:duplication", "true") ;
++ new CmdTestBPlusTree(argv).mainRun() ;
++ }
++
++ protected CmdTestBPlusTree(String[] argv) {
++ super(argv) ;
++ }
++
++ @Override
++ protected void before() {
++ SystemIndex.setNullOut(true) ;
++ BlockTracker.collectHistory = false ;
++ // Forced mode
++ if ( true ) {
++ BlockAccessMem.SafeMode = true ;
++ BPT.CheckingNode = trueOrFalse("bpt:checking", false) ;
++ boolean duplication = trueOrFalse("bpt:duplication", false) ;
++ BPT.forcePromoteModes = true ;
++ BPT.promoteDuplicateNodes = duplication ;
++ BPT.promoteDuplicateRecords = duplication ;
++ }
++ if ( false ) {
++ // Transactions.
++ }
++
++ System.out.printf(" BPT.CheckingNode = %s\n", BPT.CheckingNode) ;
++ System.out.printf(" BPT.forcePromoteModes = %s\n", BPT.forcePromoteModes) ;
++ System.out.printf(" BPT.promoteDuplicateNodes = %s\n", BPT.promoteDuplicateRecords) ;
++ System.out.printf(" BPT.promoteDuplicateRecords = %s\n", BPT.promoteDuplicateRecords) ;
++ }
++
++ private boolean trueOrFalse(String property, boolean dftValue) {
++ String s = System.getProperty(property) ;
++ if ( s == null )
++ return dftValue ;
++ if ( s.equalsIgnoreCase("true") || s.equalsIgnoreCase("T") || s.equalsIgnoreCase("1") )
++ return true ;
++ if ( s.equalsIgnoreCase("false") || s.equalsIgnoreCase("F") || s.equalsIgnoreCase("0") )
++ return false ;
++ System.err.println("Not recognized: "+property+"="+s);
++ return dftValue ;
++ }
++
++ @Override
++ protected void after() {}
++
++ @Override
++ protected void runOneTest(int testCount, int order, int size, boolean debug) {
++ runOneTest(testCount, order, size) ;
++ }
++
++ @Override
++ protected void runOneTest(int testCount, int order, int size) {
++// //System.err.println("runOneTest("+order+","+size+")") ;
++ BPlusTree bpt = BPlusTreeFactory.makeMem(order, Sys.SizeOfInt, 0) ;
++ bpt = BPlusTreeFactory.addTracking(bpt) ;
++ bpt.nonTransactional() ;
++ IndexTestLib.randTest(bpt, 5*size, size, true);
++ bpt.close() ;
++
++ // Transaction.
++// BPlusTree bpt = BPlusTreeFactory.makeMem(order, SystemLz.SizeOfInt, 0) ;
++// Journal journal = Journal.create(Location.mem()) ;
++// Transactional holder = TransactionalFactory.create(journal, bpt) ;
++// holder.begin(ReadWrite.WRITE);
++// IndexTestLib.randTest(bpt, 5*size, size, true);
++// holder.commit() ;
++// holder.end() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/soak/CmdTestBPlusTreeRewriter.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/soak/CmdTestBPlusTreeRewriter.java
index 0000000,0000000..1688bdc
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/bplustree/soak/CmdTestBPlusTreeRewriter.java
@@@ -1,0 -1,0 +1,67 @@@
++/*
++ * 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.dboe.trans.bplustree.soak;
++
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.index.test.BaseSoakTest ;
++import org.seaborne.dboe.sys.SystemIndex ;
++import org.seaborne.dboe.trans.bplustree.BPT ;
++import org.seaborne.dboe.trans.bplustree.rewriter.TestBPlusTreeRewriterNonTxn ;
++
++public class CmdTestBPlusTreeRewriter extends BaseSoakTest
++{
++ static public void main(String... argv) {
++ new CmdTestBPlusTreeRewriter(argv).mainRun() ;
++ }
++
++ protected CmdTestBPlusTreeRewriter(String[] argv) {
++ super(argv) ;
++ }
++
++ static int KeySize = 4 ;
++ static int ValueSize = 8 ;
++
++ @Override
++ protected void before() {
++ SystemIndex.setNullOut(true) ;
++ // Forced mode
++ if ( false ) {
++ BPT.forcePromoteModes = true ;
++ BPT.promoteDuplicateNodes = true ;
++ BPT.promoteDuplicateRecords = true ;
++ }
++ if ( false ) {
++ // Transactions.
++ }
++ }
++
++ @Override
++ protected void after() { }
++
++ @Override
++ protected void runOneTest(int testCount, int order, int size, boolean debug) {
++ runOneTest(testCount, order, size) ;
++ }
++
++ @Override
++ protected void runOneTest(int testCount, int order, int size) {
++ RecordFactory recordFactory = new RecordFactory(KeySize, ValueSize) ;
++ TestBPlusTreeRewriterNonTxn.runOneTest(order, size, recordFactory, false) ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TS_TransData.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TS_TransData.java
index 0000000,0000000..d310e6b
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TS_TransData.java
@@@ -1,0 -1,0 +1,34 @@@
++/*
++ * 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.dboe.trans.data;
++
++import org.junit.runner.RunWith ;
++import org.junit.runners.Suite ;
++import org.junit.runners.Suite.SuiteClasses ;
++
++@RunWith(Suite.class)
++@SuiteClasses( {
++ TestTransIndexMem.class
++ , TestTransBlob.class
++ , TestTransBlobPersistent.class
++ , TestTransBinaryDataFileGeneral.class
++ , TestTransBinaryDataFile.class
++})
++
++public class TS_TransData { }
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransBinaryDataFile.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransBinaryDataFile.java
index 0000000,0000000..0dfa56d
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransBinaryDataFile.java
@@@ -1,0 -1,0 +1,219 @@@
++/*
++ * 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.dboe.trans.data;
++
++import static org.junit.Assert.assertArrayEquals;
++import static org.junit.Assert.assertEquals;
++import static org.junit.Assert.assertNotEquals;
++
++import org.apache.jena.atlas.lib.Bytes ;
++import org.apache.jena.atlas.lib.StrUtils ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.* ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.dboe.transaction.ThreadTxn ;
++import org.seaborne.dboe.transaction.Transactional ;
++import org.seaborne.dboe.transaction.TransactionalFactory ;
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++import org.seaborne.dboe.transaction.txn.journal.Journal ;
++
++
++public class TestTransBinaryDataFile {
++ private Journal journal ;
++ private BinaryDataFile baseBinData ;
++ private TransBinaryDataFile transBinData ;
++ private Transactional transactional ;
++
++ @Before public void before() {
++ // XXX Builder.
++ journal = Journal.create(Location.mem()) ;
++ baseBinData = new BinaryDataFileMem() ;
++ BufferChannel chan = FileFactory.createBufferChannelMem() ;
++ ComponentId cid = ComponentId.allocLocal() ;
++ transBinData = new TransBinaryDataFile(baseBinData, cid, chan) ;
++ transBinData.open();
++ transactional = TransactionalFactory.createTransactional(journal, transBinData) ;
++ }
++
++ @After public void after() { }
++
++// private static ByteBuffer str2bb(String x) {
++// byte[] d = StrUtils.asUTF8bytes(x) ;
++// ByteBuffer bb = ByteBuffer.wrap(d) ;
++// return bb ;
++// }
++
++ private static long writeOne(Transactional transactional, TransBinaryDataFile transBinaryFile, String data) {
++ return
++ Txn.calculateWrite(transactional, ()->{
++ byte[] bytes = StrUtils.asUTF8bytes(data) ;
++ int len = bytes.length ;
++ byte[] lenBytes = new byte[4] ;
++ Bytes.setInt(len, lenBytes);
++ // To work with strings, we write length,bytes.
++ long x = transBinaryFile.write(lenBytes);
++ transBinaryFile.write(bytes);
++ return x ;
++ }) ;
++ }
++
++ private static String readOne(Transactional transactional, TransBinaryDataFile transBinaryFile, long posn) {
++ return Txn.calculateRead(transactional, ()->{
++ byte[] lenBytes = new byte[4] ;
++ long x = posn ;
++ int got = transBinaryFile.read(x, lenBytes) ;
++ x += got ;
++
++ int len = Bytes.getInt(lenBytes) ;
++ byte[] bytes = new byte[len] ;
++ got = transBinaryFile.read(x, bytes) ;
++ x += got ;
++ return StrUtils.fromUTF8bytes(bytes) ;
++ }) ;
++ }
++
++ @Test public void transObjectFile_str1() {
++ String str = "Hello World" ;
++ long x = writeOne(transactional, transBinData, str) ;
++ String str2 = readOne(transactional, transBinData, x) ;
++ assertEquals(str, str2) ;
++ }
++
++ @Test public void transObjectFile_str2() {
++ String str1 = "" ;
++ String str2 = "$" ;
++ long x1 = writeOne(transactional, transBinData, str1) ;
++ long x2 = writeOne(transactional, transBinData, str2) ;
++ assertNotEquals("("+x1+","+x2+")", x1, x2) ;
++
++ String out2 = readOne(transactional, transBinData, x2) ;
++ String out1 = readOne(transactional, transBinData, x1) ;
++ assertEquals(str1, out1) ;
++ assertEquals(str2, out2) ;
++ }
++
++ static byte[] bytes0 = new byte[0] ;
++ static int len0 = 0 ;
++
++ static byte[] bytes1 = new byte[] {(byte)1,(byte)2,(byte)3} ;
++ static int len1 = bytes1.length ;
++
++ static byte[] bytes2 = StrUtils.asUTF8bytes("TheNext") ;
++ static int len2 = bytes2.length ;
++
++
++ @Test public void transObjectFile_1() {
++ Txn.executeWrite(transactional, ()->{
++ long x = transBinData.write(bytes1) ;
++ assertEquals(0L, x) ;
++ assertEquals(len1, transBinData.length()) ;
++ }) ;
++ }
++
++ @Test public void transObjectFile_2() {
++ Txn.executeWrite(transactional, ()->{
++ long x = transBinData.write(bytes1) ;
++ assertEquals(0L, x) ;
++ assertEquals(len1, transBinData.length()) ;
++ byte[] bytes1a = new byte[len1] ;
++ int len = transBinData.read(0, bytes1a) ;
++ assertEquals(len1, len) ;
++ assertArrayEquals(bytes1, bytes1a);
++ }) ;
++ }
++
++ @Test public void transObjectFile_3() {
++ Txn.executeWrite(transactional, ()->{
++ long x1 = transBinData.write(bytes1) ;
++ long x2 = transBinData.write(bytes2) ;
++ byte[] bytes1a = new byte[len1] ;
++ byte[] bytes2a = new byte[len2] ;
++ int len1a = transBinData.read(0, bytes1a) ;
++ int len2a = transBinData.read(len1a, bytes2a) ;
++ assertEquals(len1, len1a) ;
++ assertArrayEquals(bytes1, bytes1a);
++ assertEquals(len2, len2a) ;
++ assertArrayEquals(bytes2, bytes2a);
++ }) ;
++ }
++
++ @Test public void transObjectFile_4() {
++ Txn.executeWrite(transactional, ()->{
++ long x1 = transBinData.write(bytes1) ;
++ long x2 = transBinData.write(bytes2) ;
++ }) ;
++ Txn.executeRead(transactional, ()->{
++ byte[] bytes1a = new byte[len1] ;
++ byte[] bytes2a = new byte[len2] ;
++ int len1a = transBinData.read(0, bytes1a) ;
++ int len2a = transBinData.read(len1a, bytes2a) ;
++ assertEquals(len1, len1a) ;
++ assertArrayEquals(bytes1, bytes1a);
++ assertEquals(len2, len2a) ;
++ assertArrayEquals(bytes2, bytes2a);
++ }) ;
++ }
++
++ // As above but reverse the read order
++ @Test public void transObjectFile_5() {
++ Txn.executeWrite(transactional, ()->{
++ long x1 = transBinData.write(bytes1) ;
++ long x2 = transBinData.write(bytes2) ;
++ }) ;
++ Txn.executeRead(transactional, ()->{
++ byte[] bytes1a = new byte[len1] ;
++ byte[] bytes2a = new byte[len2] ;
++
++ int len2a = transBinData.read(len1, bytes2a) ;
++ int len1a = transBinData.read(0, bytes1a) ;
++
++ assertEquals(len1, len1a) ;
++ assertArrayEquals(bytes1, bytes1a);
++ assertEquals(len2, len2a) ;
++ assertArrayEquals(bytes2, bytes2a);
++ }) ;
++ }
++
++
++ @Test public void transObjectFile_6() {
++ Txn.executeWrite(transactional, ()->{
++ long x1 = transBinData.write(bytes1) ;
++ long x2 = transBinData.write(bytes2) ;
++ }) ;
++ Txn.executeRead(transactional, ()->{
++ byte[] bytes2a = new byte[len2] ;
++ int len2a = transBinData.read(len1, bytes2a) ;
++ assertEquals(len2, len2a) ;
++ assertArrayEquals(bytes2, bytes2a);
++ }) ;
++ }
++
++ @Test public void transObjectFile_7() {
++ ThreadTxn.threadTxnWriteAbort(transactional, ()->{
++ long x1 = transBinData.write(bytes1) ;
++ }) ;
++
++ Txn.executeRead(transactional, ()->{
++ assertEquals(0L, transBinData.length()) ;
++ }) ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransBinaryDataFileGeneral.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransBinaryDataFileGeneral.java
index 0000000,0000000..add5983
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransBinaryDataFileGeneral.java
@@@ -1,0 -1,0 +1,58 @@@
++/*
++ * 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.dboe.trans.data;
++
++import org.apache.jena.query.ReadWrite ;
++import org.seaborne.dboe.base.file.* ;
++import org.seaborne.dboe.transaction.Transactional ;
++import org.seaborne.dboe.transaction.TransactionalFactory ;
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++import org.seaborne.dboe.transaction.txn.journal.Journal ;
++
++public class TestTransBinaryDataFileGeneral extends AbstractTestBinaryDataFile {
++ private Journal journal ;
++ private BinaryDataFile baseBinData ;
++ private TransBinaryDataFile transBinData ;
++ private Transactional transactional ;
++
++ @Override
++ protected BinaryDataFile createBinaryDataFile() {
++ // XXX Builder.
++ journal = Journal.create(Location.mem()) ;
++ baseBinData = new BinaryDataFileMem() ;
++ BufferChannel chan = FileFactory.createBufferChannelMem() ;
++ ComponentId cid = ComponentId.allocLocal() ;
++ transBinData = new TransBinaryDataFile(baseBinData, cid, chan) ;
++ transBinData.open();
++ transactional = TransactionalFactory.createTransactional(journal, transBinData) ;
++ //Non-transactional usage of a disposed file.
++ transactional.begin(ReadWrite.WRITE) ;
++ return transBinData ;
++
++ }
++
++ @Override
++ protected void releaseBinaryDataFile(BinaryDataFile file) {
++ if ( file.isOpen() ) {
++ transactional.commit() ;
++ transactional.end() ;
++ baseBinData.close() ;
++ }
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransBlob.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransBlob.java
index 0000000,0000000..114dcf1
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransBlob.java
@@@ -1,0 -1,0 +1,129 @@@
++/*
++ * 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.dboe.trans.data;
++
++import java.util.concurrent.atomic.AtomicReference ;
++
++import org.apache.jena.query.ReadWrite ;
++import org.junit.After ;
++import org.junit.Assert ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.BufferChannel ;
++import org.seaborne.dboe.base.file.BufferChannelMem ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.dboe.transaction.ThreadTxn ;
++import org.seaborne.dboe.transaction.Transactional ;
++import org.seaborne.dboe.transaction.TransactionalFactory ;
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++import org.seaborne.dboe.transaction.txn.journal.Journal ;
++
++public class TestTransBlob extends Assert {
++ private Journal journal ;
++ private TransBlob transBlob ;
++ private Transactional transactional ;
++
++ @Before public void before() {
++ journal = Journal.create(Location.mem()) ;
++
++ BufferChannel chan = BufferChannelMem.create("TestTransBlob") ;
++ ComponentId cid = ComponentId.allocLocal() ;
++ transBlob = new TransBlob(cid, chan) ;
++ transactional = TransactionalFactory.createTransactional(journal, transBlob) ;
++ }
++
++ @After public void after() { }
++
++ public static void write(Transactional transactional, TransBlob transBlob, String data) {
++ Txn.executeWrite(transactional, ()->{
++ transBlob.setString(data);
++ }) ;
++ }
++
++ public static String read(Transactional transactional, TransBlob transBlob) {
++ return Txn.calculateRead(transactional, ()->{
++ return transBlob.getString() ;
++ }) ;
++ }
++
++ void threadRead(String expected) {
++ AtomicReference<String> result = new AtomicReference<>() ;
++ ThreadTxn.threadTxnRead(transactional, ()-> {
++ String s = transBlob.getString() ;
++ result.set(s);
++ }).run();
++ Assert.assertEquals(expected, result.get());
++ }
++
++ // testing with real files in TestTransBlobPersistent
++
++ @Test public void transBlob_1() {
++ String str = "Hello World" ;
++ write(transactional, transBlob, str) ;
++ String str2 = read(transactional, transBlob) ;
++ assertEquals(str, str2) ;
++ String str3 = transBlob.getString() ;
++ assertEquals(str, str3) ;
++
++ }
++
++ // Verify visibility and transactions.
++ @Test public void transBlob_2() {
++ String str1 = "one" ;
++ String str2 = "two" ;
++ write(transactional, transBlob, str1) ;
++ transactional.begin(ReadWrite.WRITE);
++ transBlob.setString(str2);
++
++ // Difefrent therad and transaction.
++ threadRead(str1) ;
++
++ transactional.commit() ;
++ transactional.end() ;
++ threadRead(str2) ;
++ }
++
++ // Verify visibility and transactions.
++ @Test public void transBlob_3() {
++ String str1 = "one" ;
++ String str2 = "two" ;
++ write(transactional, transBlob, str1) ;
++ String s1 = transBlob.getString() ;
++ assertEquals(str1, s1) ;
++ String s2 = read(transactional, transBlob) ;
++ assertEquals(str1, s2) ;
++
++ // Start now.
++ ThreadTxn tt = ThreadTxn.threadTxnRead(transactional, ()-> {
++ String sr = transBlob.getString() ;
++ Assert.assertEquals(str1, sr) ;
++ }) ;
++
++ write(transactional, transBlob, str2) ;
++
++ Txn.executeWrite(transactional, ()->{
++ transBlob.setString(str2) ;
++ String s = transBlob.getString() ;
++ assertEquals(str2, s) ;
++ }) ;
++ // Run later, after W transaction.
++ tt.run();
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransBlobPersistent.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransBlobPersistent.java
index 0000000,0000000..053d7dc
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransBlobPersistent.java
@@@ -1,0 -1,0 +1,116 @@@
++/*
++ * 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.dboe.trans.data;
++
++import org.apache.jena.util.FileUtils ;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.junit.* ;
++import org.seaborne.dboe.base.file.BufferChannel ;
++import org.seaborne.dboe.base.file.BufferChannelFile ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.jenax.Txn;
++import org.seaborne.dboe.transaction.Transactional ;
++import org.seaborne.dboe.transaction.TransactionalFactory ;
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++import org.seaborne.dboe.transaction.txn.journal.Journal ;
++
++public class TestTransBlobPersistent extends Assert {
++ private final static String DIR = "target/blobtest" ;
++ private final static String JRNL = DIR+"/journal.jrnl" ;
++ private final static String DATA = DIR+"/blob.data" ;
++
++ @BeforeClass public static void beforeClass() {
++ FileOps.ensureDir(DIR);
++ }
++
++ @Before public void before() {
++ FileOps.deleteSilent(JRNL) ;
++ FileOps.deleteSilent(DATA) ;
++ }
++
++ @AfterClass public static void afterClass() {
++ FileOps.deleteSilent(JRNL) ;
++ FileOps.deleteSilent(DATA) ;
++ }
++
++ @Test public void transBlobFile_1() throws Exception {
++ Journal journal = Journal.create(Location.create(DIR)) ;
++ BufferChannel chan = BufferChannelFile.create(DATA) ;
++ ComponentId cid = ComponentId.allocLocal() ;
++ TransBlob transBlob = new TransBlob(cid, chan) ;
++ Transactional transactional = TransactionalFactory.createTransactional(journal, transBlob) ;
++ String str = "Hello" ;
++
++ TestTransBlob.write(transactional, transBlob, str) ;
++
++ chan.close() ;
++ journal.close() ;
++ String s = FileUtils.readWholeFileAsUTF8(DATA) ;
++ assertEquals(str, s);
++ }
++
++ @Test public void transBlobFile_2() throws Exception {
++ Journal journal = Journal.create(Location.create(DIR)) ;
++ BufferChannel chan = BufferChannelFile.create(DATA) ;
++ ComponentId cid = ComponentId.allocLocal() ;
++ TransBlob transBlob = new TransBlob(cid, chan) ;
++ Transactional transactional = TransactionalFactory.createTransactional(journal, transBlob) ;
++ String str = "Hello1" ;
++
++ Txn.executeWrite(transactional, ()->{
++ transBlob.setString("one");
++ }) ;
++
++ Txn.executeWrite(transactional, ()->{
++ transBlob.setString("two");
++ }) ;
++
++ chan.close() ;
++ journal.close() ;
++ String s = FileUtils.readWholeFileAsUTF8(DATA) ;
++ assertEquals("two", s);
++ }
++
++ // restart.
++ @Test public void transBlobFile_3() throws Exception {
++ String str = "Hello World" ;
++ // Write out.
++ {
++ Journal journal = Journal.create(Location.create(DIR)) ;
++ BufferChannel chan = BufferChannelFile.create(DATA) ;
++ ComponentId cid = ComponentId.allocLocal() ;
++ TransBlob transBlob = new TransBlob(cid, chan) ;
++ Transactional transactional = TransactionalFactory.createTransactional(journal, transBlob) ;
++ TestTransBlob.write(transactional, transBlob, str) ;
++ chan.close();
++ journal.close();
++ }
++ // Restart
++ {
++ Journal journal = Journal.create(Location.create(DIR)) ;
++ BufferChannel chan = BufferChannelFile.create(DATA) ;
++ ComponentId cid = ComponentId.allocLocal() ;
++ TransBlob transBlob = new TransBlob(cid, chan) ;
++ Transactional transactional = TransactionalFactory.createTransactional(journal, transBlob) ;
++ String s = TestTransBlob.read(transactional, transBlob) ;
++ assertEquals(str, s);
++ }
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransIndexMem.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransIndexMem.java
index 0000000,0000000..85cc9ff
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransIndexMem.java
@@@ -1,0 -1,0 +1,34 @@@
++/*
++ * 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.dboe.trans.data;
++
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.index.Index ;
++import org.seaborne.dboe.index.IndexMap ;
++import org.seaborne.dboe.index.test.AbstractTestIndex ;
++
++public class TestTransIndexMem extends AbstractTestIndex
++{
++ @Override
++ protected Index makeIndex(int kLen, int vLen)
++ {
++ RecordFactory rf = new RecordFactory(kLen, vLen) ;
++ return new IndexMap(rf) ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/recovery/TestRecovery.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/recovery/TestRecovery.java
index 0000000,0000000..adaf2c0
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/recovery/TestRecovery.java
@@@ -1,0 -1,0 +1,126 @@@
++/*
++ * 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.dboe.trans.recovery;
++
++import java.nio.ByteBuffer ;
++import java.util.Arrays ;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.junit.* ;
++import org.seaborne.dboe.base.file.BufferChannel ;
++import org.seaborne.dboe.base.file.BufferChannelFile ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.migrate.L ;
++import org.seaborne.dboe.trans.data.TransBlob ;
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++import org.seaborne.dboe.transaction.txn.TransactionCoordinator ;
++import org.seaborne.dboe.transaction.txn.journal.Journal ;
++import org.seaborne.dboe.transaction.txn.journal.JournalEntry ;
++import org.seaborne.dboe.transaction.txn.journal.JournalEntryType ;
++
++// We need something to recover io order to test recovery.
++
++public class TestRecovery extends Assert {
++ private final static String DIR = "target/recovery" ;
++ private final static String JRNL = DIR + "/journal.jrnl" ;
++ private final static String DATA = DIR + "/blob.data" ;
++ private final static String DATA1 = DIR + "/blob.data-1" ;
++ private final static String DATA2 = DIR + "/blob.data-2" ;
++
++ @BeforeClass public static void beforeClass() {
++ FileOps.ensureDir(DIR);
++ }
++
++ @Before public void before() {
++ FileOps.deleteSilent(JRNL) ;
++ FileOps.deleteSilent(DATA) ;
++ FileOps.deleteSilent(DATA1) ;
++ FileOps.deleteSilent(DATA2) ;
++ }
++
++ @AfterClass public static void afterClass() {
++ FileOps.deleteSilent(JRNL) ;
++ FileOps.deleteSilent(DATA) ;
++ }
++
++ // Fake journal recovery.
++ @Test public void recoverBlobFile_1() throws Exception {
++ String str = "Hello Journal" ;
++ ComponentId cid = ComponentId.allocLocal() ;
++// ComponentIdRegistry registry = new ComponentIdRegistry() ;
++// registry.register(cid, "Blob", 1) ;
++
++ // Write out a journal.
++ {
++ Journal journal = Journal.create(Location.create(DIR)) ;
++ journal.write(JournalEntryType.REDO, cid, L.stringToByteBuffer(str)) ;
++ journal.writeJournal(JournalEntry.COMMIT) ;
++ journal.close();
++ }
++
++ TransactionCoordinator coord = new TransactionCoordinator(Location.create(DIR)) ;
++ BufferChannel chan = BufferChannelFile.create(DATA) ;
++ TransBlob tBlob = new TransBlob(cid, chan) ;
++ coord.add(tBlob) ;
++ coord.start();
++
++ ByteBuffer blob = tBlob.getBlob() ;
++ assertNotNull(blob);
++ String s = L.byteBufferToString(blob) ;
++ assertEquals(str,s) ;
++ coord.shutdown();
++ }
++
++ @Test public void recoverBlobFile_2() throws Exception {
++ String str1 = "Recovery One" ;
++ String str2 = "Recovery Two" ;
++ ComponentId cid1 = ComponentId.allocLocal() ;
++ ComponentId cid2 = ComponentId.allocLocal() ;
++
++ // Write out a journal for two components.
++ {
++ Journal journal = Journal.create(Location.create(DIR)) ;
++ journal.write(JournalEntryType.REDO, cid1, L.stringToByteBuffer(str1)) ;
++ journal.write(JournalEntryType.REDO, cid2, L.stringToByteBuffer(str2)) ;
++ journal.writeJournal(JournalEntry.COMMIT) ;
++ journal.close();
++ }
++
++ Journal journal = Journal.create(Location.create(DIR)) ;
++ BufferChannel chan = BufferChannelFile.create(DATA) ;
++ TransBlob tBlob1 = new TransBlob(cid1, chan) ;
++ TransBlob tBlob2 = new TransBlob(cid2, chan) ;
++
++ TransactionCoordinator coord = new TransactionCoordinator(journal, Arrays.asList(tBlob1, tBlob2)) ;
++ coord.start();
++
++ ByteBuffer blob1 = tBlob1.getBlob() ;
++ assertNotNull(blob1);
++ String s1 = L.byteBufferToString(blob1) ;
++ assertEquals(str1,s1) ;
++
++ ByteBuffer blob2 = tBlob2.getBlob() ;
++ assertNotNull(blob2);
++ String s2 = L.byteBufferToString(blob2) ;
++ assertEquals(str2,s2) ;
++
++ assertNotEquals(str1,str2) ;
++ coord.shutdown();
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/test/resources/log4j.properties
index 0000000,0000000..d6b299a
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/test/resources/log4j.properties
@@@ -1,0 -1,0 +1,6 @@@
++log4j.rootLogger=INFO, stdlog
++
++log4j.appender.stdlog=org.apache.log4j.ConsoleAppender
++## log4j.appender.stdlog.target=System.err
++log4j.appender.stdlog.layout=org.apache.log4j.PatternLayout
++log4j.appender.stdlog.layout.ConversionPattern=%d{HH:mm:ss} %-5p %-20c{1} :: %m%n
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/pom.xml
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/pom.xml
index 0000000,0000000..8c4b21f
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/pom.xml
@@@ -1,0 -1,0 +1,41 @@@
++<?xml version="1.0" encoding="utf-8"?>
++<!--
++ 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.
++-->
++
++<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
++ <modelVersion>4.0.0</modelVersion>
++ <artifactId>dboe-transaction</artifactId>
++ <packaging>jar</packaging>
++ <name>Mantis (${project.artifactId})</name>
++
++ <parent>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>mantis</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </parent>
++
++ <dependencies>
++
++ <dependency>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>dboe-base</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </dependency>
++
++ </dependencies>
++
++</project>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/ComponentIdRegistry.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/ComponentIdRegistry.java
index 0000000,0000000..1fe339e
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/ComponentIdRegistry.java
@@@ -1,0 -1,0 +1,92 @@@
++/*
++ * 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.dboe.transaction;
++
++
++
++public class ComponentIdRegistry {
++// // Not stable across JVMs hence "local"
++// private ComponentId localCid = ComponentId.create("Local", L.uuidAsBytes(UUID.randomUUID())) ;
++//
++// // No! byte[].equals is Object.equals
++//
++// // ComponentId equality is by bytes (not display label)
++// // so this maps bytes to a better form.
++// private Map<Holder, ComponentId> registry = new ConcurrentHashMap<>() ;
++//
++// public ComponentIdRegistry() { }
++//
++// public ComponentId registerLocal(String label, int index) {
++// return register(localCid, label, index) ;
++// }
++//
++// public ComponentId register(ComponentId base, String label, int index) {
++// byte[] bytes = base.bytes() ;
++// bytes = Arrays.copyOf(bytes, bytes.length) ;
++// int x = Bytes.getInt(bytes, bytes.length - SystemBase.SizeOfInt) ;
++// x = x ^ index ;
++// Bytes.setInt(x, bytes, bytes.length-SystemBase.SizeOfInt) ;
++// ComponentId cid = new ComponentId(label+"-"+index, bytes) ;
++// Holder h = new Holder(bytes) ;
++// registry.put(h, cid) ;
++// return cid ;
++// }
++//
++// public ComponentId lookup(byte[] bytes) {
++// Holder h = new Holder(bytes) ;
++// return registry.get(h) ;
++// }
++//
++// public void reset() {
++// registry.clear() ;
++// }
++//
++// // Makes equality the value of the bytes.
++// static class Holder {
++// private final byte[] bytes ;
++//
++// Holder(byte[] bytes) { this.bytes = bytes ; }
++//
++// @Override
++// public int hashCode() {
++// final int prime = 31 ;
++// int result = 1 ;
++// result = prime * result + Arrays.hashCode(bytes) ;
++// return result ;
++// }
++//
++// @Override
++// public boolean equals(Object obj) {
++// if ( this == obj )
++// return true ;
++// if ( obj == null )
++// return false ;
++// if ( getClass() != obj.getClass() )
++// return false ;
++// Holder other = (Holder)obj ;
++// if ( !Arrays.equals(bytes, other.bytes) )
++// return false ;
++// return true ;
++// }
++//
++// @Override
++// public String toString() {
++// return Bytes.asHex(bytes) ;
++// }
++// }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/ThreadTxn.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/ThreadTxn.java
index 0000000,0000000..bd29e8f
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/ThreadTxn.java
@@@ -1,0 -1,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.dboe.transaction;
++
++import java.util.Objects ;
++import java.util.concurrent.Executor ;
++import java.util.concurrent.Semaphore ;
++import java.util.concurrent.atomic.AtomicReference ;
++
++import org.apache.jena.query.ReadWrite ;
++
++import org.seaborne.dboe.sys.Sys ;
++import org.apache.jena.sparql.core.Transactional ;
++
++/**
++ * An action that will happen on a different thread later when {@link #run} is
++ * called. A thread is created and the transaction started during a call to the
++ * creation operations {@link #threadTxnRead} or {@link #threadTxnWrite}.
++ * The associated Runnable is called and the transaction completed when
++ * {@link #run} is called. Being on a thread, the state of the world the
++ * forked transaction sees is outside the creating thread which may itself be in a
++ * transaction. Warning: creating a write transaction inside a write transaction
++ * will cause deadlock.
++ */
++public class ThreadTxn {
++
++ /** Create a thread-backed delayed READ transaction action. */
++ public static ThreadTxn threadTxnRead(Transactional trans, Runnable action) {
++ return ThreadTxn.create(trans, ReadWrite.READ, action, false) ;
++ }
++
++ /** Create a thread-backed delayed WRITE action.
++ * If called from inside a write transaction on the {@code trans},
++ * this will deadlock.
++ */
++ public static ThreadTxn threadTxnWrite(Transactional trans, Runnable action) {
++ return ThreadTxn.create(trans, ReadWrite.WRITE, action, true) ;
++ }
++
++ /** Create a thread-backed delayed WRITE-abort action (testing). */
++ public static ThreadTxn threadTxnWriteAbort(Transactional trans, Runnable action) {
++ return ThreadTxn.create(trans, ReadWrite.WRITE, action, false) ;
++ }
++
++ private final Semaphore semaStart ;
++ private final Semaphore semaFinish ;
++ private final AtomicReference<RuntimeException> thrownRuntimeException = new AtomicReference<>(null) ;
++ private final AtomicReference<Error> thrownError = new AtomicReference<>(null) ;
++ private final Runnable action ;
++
++ private ThreadTxn(Runnable action) {
++ this.action = action ;
++ this.semaStart = new Semaphore(0, true) ;
++ this.semaFinish = new Semaphore(0, true) ;
++ }
++
++ /**
++ * Perform the Runnable, reporting any
++ * {@link java.lang.RuntimeException} or {@link java.lang.Error}
++ */
++ public void run() {
++ semaStart.release();
++ semaFinish.acquireUninterruptibly() ;
++ if ( thrownError.get() != null )
++ throw thrownError.get() ;
++ if ( thrownRuntimeException.get() != null )
++ throw thrownRuntimeException.get() ;
++ }
++
++ // Called on the async thread.
++ private void trigger() {
++ try { action.run(); }
++ catch (Error error) { thrownError.set(error) ; throw error ;}
++ catch (RuntimeException ex) { thrownRuntimeException.set(ex) ; throw ex ; }
++ }
++
++ // System-shared executor.
++ private static Executor executor = Sys.executor ;
++
++ /*package*/ static ThreadTxn create(Transactional trans, ReadWrite mode, Runnable action, boolean isCommit) {
++ Objects.requireNonNull(trans) ;
++ Objects.requireNonNull(mode) ;
++ Objects.requireNonNull(action) ;
++
++ ThreadTxn threadAction = new ThreadTxn(action) ;
++ // Startup semaphore so that the thread has started by the
++ // time we exit this setup function.
++ Semaphore semaStartup = new Semaphore(0, true) ;
++ executor.execute( ()-> {
++ // NB. trans.begin then semaStartup.release() ;
++ // This ensures that the transaction has really started.
++ trans.begin(mode) ;
++
++ // Signal the creator (see below) that the transaction has started.
++ semaStartup.release() ;
++
++ // Wait for the signal to run the action.
++ threadAction.semaStart.acquireUninterruptibly();
++
++ try {
++ // Performane the action, catch and record any RuntimeException or Error.
++ threadAction.trigger() ;
++
++ // Finish transaction (if no throwable)
++ if ( mode == ReadWrite.WRITE ) {
++ if ( isCommit )
++ trans.commit();
++ else
++ trans.abort() ;
++ trans.end() ;
++ } else {
++ // Read
++ if ( isCommit )
++ trans.commit();
++ trans.end() ;
++ }
++ }
++ catch (Throwable ex) {
++ // Suppress now it has trigger transaction mechanism in
++ // the presence of an unchecked exception.
++ // Passed to the main thread via ThreadTxn
++ }
++ finally { threadAction.semaFinish.release() ; }
++ }) ;
++ // Don't return until the transaction has started.
++ semaStartup.acquireUninterruptibly();
++ return threadAction ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/TransInteger.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/TransInteger.java
index 0000000,0000000..5f4996c
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/TransInteger.java
@@@ -1,0 -1,0 +1,242 @@@
++/*
++ * 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.dboe.transaction;
++
++import java.io.IOException ;
++import java.nio.ByteBuffer ;
++import java.util.concurrent.atomic.AtomicLong ;
++
++import org.apache.jena.atlas.io.IO ;
++import org.apache.jena.atlas.lib.FileOps ;
++import org.apache.jena.atlas.lib.InternalErrorException ;
++import org.apache.jena.atlas.logging.Log ;
++import org.apache.jena.query.ReadWrite ;
++import org.seaborne.dboe.migrate.L ;
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++import org.seaborne.dboe.transaction.txn.TransactionalComponentLifecycle ;
++import org.seaborne.dboe.transaction.txn.TxnId ;
++
++/** A transaction component with an integer supporting MR+SW (=one writer AND many readers).
++ * @see TransactionalInteger
++ */
++public class TransInteger extends TransactionalComponentLifecycle<TransInteger.IntegerState> {
++
++ private final AtomicLong value = new AtomicLong(-1712) ;
++ private final String filename ;
++
++ /** Per transaction state - and per thread safe because we subclass
++ * TransactionalComponentLifecycle
++ */
++ static class IntegerState {
++ long txnValue ;
++ public IntegerState(long v) { this.txnValue = v ; }
++ }
++
++ static int counter = 0 ;
++
++ /** In-memory, non persistent, transactional integer */
++ public TransInteger() { this(0L) ; }
++
++ /** In-memory, non persistent, transactional integer */
++ public TransInteger(long v) {
++ this(null, ComponentId.allocLocal()) ;
++ value.set(v) ;
++ }
++
++ /** Persistent, transactional integer. The persistent state is held in
++ * filename. When first initialized, the value is 0L.
++ * @param filename Persistent state
++ * @param cid Component id
++ */
++ public TransInteger(String filename, ComponentId cid) {
++ super(cid) ;
++ this.filename = filename ;
++ // Set the value now for "fast read" transactions.
++ readLocation() ;
++ }
++
++ private void readLocation() {
++ if ( filename != null ) {
++ if ( ! FileOps.exists(filename) ) {
++ value.set(0L) ;
++ writeLocation() ;
++ return ;
++ }
++ long x = read(filename) ;
++ value.set(x);
++ }
++ }
++
++ private void writeLocation() {
++ writeLocation(value.get()) ;
++ }
++
++ private void writeLocation(long value) {
++ if ( filename != null ) {
++ write(filename, value) ;
++ }
++ }
++
++ //-- Read/write the value
++ // This should really be checksum'ed or other internal check to make sure IO worked.
++ private static long read(String filename) {
++ try {
++ String str = IO.readWholeFileAsUTF8(filename) ;
++ if ( str.endsWith("\n") ) {
++ str = str.substring(0, str.length()-1) ;
++ }
++ str = str.trim() ;
++ return Long.parseLong(str) ;
++ }
++ catch (IOException ex) {
++ Log.error(TransInteger.class, "IOException: " + ex.getMessage(), ex) ;
++ IO.exception(ex) ;
++ }
++ catch (NumberFormatException ex) {
++ Log.error(TransInteger.class, "NumberformatException: " + ex.getMessage()) ;
++ throw new InternalErrorException(ex) ;
++ }
++ // Not reached.
++ return Long.MIN_VALUE ;
++ }
++
++
++ private static void write(String filename, long value) {
++ try { L.writeStringAsUTF8(filename, Long.toString(value)) ; }
++ catch (IOException ex) {}
++ catch (NumberFormatException ex) {}
++ }
++
++ private boolean recoveryAction = false ;
++
++ @Override
++ public void startRecovery() {
++ recoveryAction = false ;
++ }
++
++ @Override
++ public void recover(ByteBuffer ref) {
++ long x = ref.getLong() ;
++ value.set(x) ;
++ recoveryAction = true ;
++ }
++
++
++ @Override
++ public void finishRecovery() {
++ if ( recoveryAction )
++ writeLocation();
++ // Leave true as a record.
++ }
++
++ @Override
++ public void cleanStart() {
++ recoveryAction = false ;
++ }
++
++ /** Set the value, return the old value*/
++ public void inc() {
++ checkWriteTxn() ;
++ IntegerState ts = getDataState() ;
++ ts.txnValue++ ;
++ }
++
++ /** Set the value, return the old value*/
++ public long set(long x) {
++ checkWriteTxn() ;
++ IntegerState ts = getDataState() ;
++ long v = ts.txnValue ;
++ ts.txnValue = x ;
++ return v ;
++ }
++
++
++ /** Return the current value in a transaction. s*/
++ public long read() {
++ checkTxn();
++ return getDataState().txnValue ;
++ }
++
++ /** Return the current value.
++ * If inside a transaction, return the transaction view of the value.
++ * If not in a transaction return the state value (effectively
++ * a read transaction, optimized by the fact that reading the
++ * {@code TransInteger} state is atomic).
++ */
++ public long get() {
++ if ( super.isActiveTxn() )
++ return getDataState().txnValue ;
++ else
++ return value.get() ;
++ }
++
++ /** Read the current global state (that is, the last committed value) outside a transaction. */
++ public long value() {
++ return value.get() ;
++ }
++
++ @Override
++ protected IntegerState _begin(ReadWrite readWrite, TxnId txnId) {
++ return createState();
++ }
++
++ private IntegerState createState() {
++ return new IntegerState(value.get()) ;
++ }
++
++ @Override
++ protected IntegerState _promote(TxnId txnId, IntegerState state) {
++ return createState();
++ }
++
++ @Override
++ protected ByteBuffer _commitPrepare(TxnId txnId, IntegerState state) {
++ ByteBuffer x = ByteBuffer.allocate(Long.BYTES) ;
++ x.putLong(state.txnValue) ;
++ return x ;
++ }
++
++ @Override
++ protected void _commit(TxnId txnId, IntegerState state) {
++ writeLocation(state.txnValue) ;
++ }
++
++ @Override
++ protected void _commitEnd(TxnId txnId, IntegerState state) {
++ value.set(state.txnValue) ;
++ }
++ @Override
++ protected void _abort(TxnId txnId, IntegerState state) {
++ // Nothing
++ }
++
++ @Override
++ protected void _complete(TxnId txnId, IntegerState state) {
++ // Nothing
++ }
++
++ @Override
++ protected void _shutdown() {
++ }
++
++ @Override
++ public String toString() {
++ return String.valueOf(super.getComponentId()) ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/TransLogger.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/TransLogger.java
index 0000000,0000000..21bbd47
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/TransLogger.java
@@@ -1,0 -1,0 +1,151 @@@
++/*
++ * 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.dboe.transaction;
++
++import java.nio.ByteBuffer ;
++
++import org.apache.jena.atlas.logging.FmtLog ;
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++import org.seaborne.dboe.transaction.txn.SysTransState ;
++import org.seaborne.dboe.transaction.txn.Transaction ;
++import org.seaborne.dboe.transaction.txn.TransactionalComponent ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/**
++ * Logging for transaction steps. This class is stateless in the transaction.
++ * When operations are called in the {@link TransactionalComponent} lifecycle,
++ * it logs the event.
++ */
++
++public class TransLogger implements TransactionalComponent {
++ private final Logger log ;
++ private final boolean everyEvent ;
++
++ /** Create a logger for begin-commit/abort-end */
++ public TransLogger() {
++ this(null, false) ;
++ }
++
++ /** Create a logger, either just begin-commit/abort-end or all steps */
++ public TransLogger(Logger logger) {
++ this(logger, false) ;
++ }
++
++ /** Create a logger, either just begin-commit/abort-end or all steps */
++ public TransLogger(Logger logger, boolean all) {
++ if ( logger == null )
++ logger = LoggerFactory.getLogger(TransLogger.class) ;
++ this.log = logger ;
++ this.everyEvent = all ;
++ }
++
++ @Override
++ public ComponentId getComponentId() {
++// if ( everyEvent )
++// log.info("getComponentId") ;
++ return null ;
++ }
++
++ @Override
++ public void startRecovery() {
++ if ( everyEvent )
++ log.info("startRecovery") ;
++ }
++
++ @Override
++ public void recover(ByteBuffer ref) {
++ // Is not called because this compoent vener writes a redo/undo action to the log.
++ if ( everyEvent )
++ log.info("recover") ;
++ }
++
++ @Override
++ public void finishRecovery() {
++ if ( everyEvent )
++ log.info("finishRecovery") ;
++ }
++
++ @Override
++ public void cleanStart() {
++ if ( everyEvent )
++ log.info("cleanStart") ;
++ }
++
++ @Override
++ public void begin(Transaction transaction) {
++ txnStep("begin", transaction) ;
++ }
++
++ @Override
++ public boolean promote(Transaction transaction) {
++ txnStep("promote", transaction) ;
++ return true ;
++ }
++
++ @Override
++ public ByteBuffer commitPrepare(Transaction transaction) {
++ if ( everyEvent )
++ txnStep("commitPrepare", transaction) ;
++ return null ;
++ }
++
++ @Override
++ public void commit(Transaction transaction) {
++ txnStep("commit", transaction) ;
++ }
++
++ @Override
++ public void commitEnd(Transaction transaction) {
++ if ( everyEvent )
++ txnStep("commitEnd", transaction) ;
++ }
++
++ @Override
++ public void abort(Transaction transaction) {
++ txnStep("abort", transaction) ;
++ }
++
++ @Override
++ public void complete(Transaction transaction) {
++ txnStep("complete", transaction) ;
++ }
++
++ @Override
++ public SysTransState detach() {
++ log.info("detach") ;
++ return null ;
++ }
++
++ @Override
++ public void attach(SysTransState systemState) {
++ log.info("attach") ;
++ }
++
++ @Override
++ public void shutdown() {
++ if ( everyEvent )
++ log.info("shutdown") ;
++ }
++
++ private void txnStep(String opName, Transaction transaction) {
++ FmtLog.info(log, "%-8s %s", transaction.getTxnId(), opName) ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/TransMonitor.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/TransMonitor.java
index 0000000,0000000..668f97b
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/TransMonitor.java
@@@ -1,0 -1,0 +1,191 @@@
++/*
++ * 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.dboe.transaction;
++
++import java.io.PrintStream ;
++import java.nio.ByteBuffer ;
++import java.util.LinkedHashMap ;
++import java.util.Map ;
++import java.util.concurrent.atomic.LongAdder ;
++import java.util.stream.Collectors ;
++
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++import org.seaborne.dboe.transaction.txn.SysTransState ;
++import org.seaborne.dboe.transaction.txn.Transaction ;
++import org.seaborne.dboe.transaction.txn.TransactionalComponent ;
++
++/** This class is stateless in the transaction but it records counts of
++ * every {@link TransactionalComponent} operations.
++ * For each operation called "ABC" there is a member field "counterABC".
++ */
++public class TransMonitor implements TransactionalComponent {
++
++ // LongAdder for stats (better from mostly write, not consistent read)
++
++ /** Counters, in initialization order */
++ private Map<String, LongAdder> counters = new LinkedHashMap<>() ;
++ private final ComponentId componentId ;
++
++ private LongAdder allocCounter(String string) {
++ LongAdder counter = new LongAdder() ;
++ counters.put(string, counter) ;
++ return counter ;
++ }
++ public TransMonitor(ComponentId cid) {
++ this.componentId = cid ;
++ }
++
++ /** Reset all counters to zero */
++ public void reset() {
++ counters.forEach( (s,c) -> c.reset()) ;
++ }
++
++ /** Get a copy of the counters with current values.
++ * The values are as of the point of this being called and are not changed
++ * by any later calls to monitored operations.
++ */
++ public Map<String, Long> getAll() {
++ return counters.entrySet().stream()
++ .collect(Collectors.toMap(
++ e -> e.getKey(),
++ e -> e.getValue().sum()
++ ));
++ }
++
++ /** Print the counters state. */
++ public void print() {
++ print(System.out) ;
++ }
++
++ /** Print the counters state. */
++ public void print(PrintStream ps) {
++ ps.println("Transaction Counters:") ;
++ counters.forEach( (s,c) -> {
++ ps.printf(" %-15s %4d\n", s, c.longValue()) ;
++ }) ;
++ }
++
++ public LongAdder counterGetComponentId = allocCounter("getComponentId") ;
++
++ @Override
++ public ComponentId getComponentId() {
++ counterGetComponentId.increment() ;
++ return componentId ;
++ }
++
++ public LongAdder counterStartRecovery = allocCounter("startRecovery") ;
++
++ @Override
++ public void startRecovery() {
++ counterStartRecovery.increment() ;
++ }
++
++ public LongAdder counterRecover = allocCounter("recover") ;
++
++ @Override
++ public void recover(ByteBuffer ref) {
++ counterRecover.increment() ;
++ }
++
++ public LongAdder counterFinishRecovery = allocCounter("finishRecovery") ;
++
++ @Override
++ public void finishRecovery() {
++ counterFinishRecovery.increment() ;
++ }
++
++ public LongAdder counterCleanStart = allocCounter("finishRecovery") ;
++
++ @Override
++ public void cleanStart() {
++ counterCleanStart.increment() ;
++ }
++
++ public LongAdder counterBegin = allocCounter("begin") ;
++
++ @Override
++ public void begin(Transaction transaction) {
++ counterBegin.increment() ;
++ }
++
++ public LongAdder counterPromote = allocCounter("promote") ;
++
++ @Override
++ public boolean promote(Transaction transaction) {
++ counterPromote.increment() ;
++ return true ;
++ }
++
++ public LongAdder counterCommitPrepare = allocCounter("commitPrepare") ;
++
++ @Override
++ public ByteBuffer commitPrepare(Transaction transaction) {
++ counterCommitPrepare.increment() ;
++ return null ;
++ }
++
++ public LongAdder counterCommit = allocCounter("commit") ;
++
++ @Override
++ public void commit(Transaction transaction) {
++ counterCommit.increment() ;
++ }
++
++ public LongAdder counterCommitEnd = allocCounter("commitEnd") ;
++
++ @Override
++ public void commitEnd(Transaction transaction) {
++ counterCommitEnd.increment() ;
++ }
++
++ public LongAdder counterAbort = allocCounter("abort") ;
++
++ @Override
++ public void abort(Transaction transaction) {
++ counterAbort.increment() ;
++ }
++
++ public LongAdder counterComplete = allocCounter("complete") ;
++
++ @Override
++ public void complete(Transaction transaction) {
++ counterComplete.increment() ;
++ }
++
++ public LongAdder counterDetach = allocCounter("detach") ;
++
++ @Override
++ public SysTransState detach() {
++ counterDetach.increment() ;
++ return null ;
++ }
++
++ public LongAdder counterAttach = allocCounter("attach") ;
++
++ @Override
++ public void attach(SysTransState systemState) {
++ counterAttach.increment() ;
++ }
++
++ public LongAdder counterShutdown = allocCounter("shutdown") ;
++
++ @Override
++ public void shutdown() {
++ counterShutdown.increment() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/Transactional.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/Transactional.java
index 0000000,0000000..fdef2b3
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/Transactional.java
@@@ -1,0 -1,0 +1,98 @@@
++/*
++ * 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.dboe.transaction;
++
++import org.apache.jena.query.ReadWrite ;
++import org.seaborne.dboe.jenax.Txn ;
++
++/** Interface that encapsulates the begin/abort|commit/end operations.
++ * <p>The read lifecycle is:
++ * <pre> begin(READ) ... end()</pre>
++ * <p>{@code commit} and {@code abort} are allowed.
++ * <p>The write lifecycle is:
++ * <pre> begin(WRITE) ... abort() or commit()</pre>
++ * <p>{@code end()} is optional but preferred.
++ * <p>
++ * Helper code is available {@link Txn} so, for example:
++ * <pre>Txn.execRead(dataset, ()-> { ... sparql query ... });</pre>
++ * <pre>Txn.execWrite(dataset, ()-> { ... sparql update ... });</pre>
++ * <p>
++ * Directly called, code might look like:
++ * <pre>
++ * Transactional object = ...
++ * object.begin(ReadWrite.READ) ;
++ * try {
++ * ... actions inside a read transaction ...
++ * } finally { object.end() ; }
++ * </pre>
++ * or
++ * <pre>
++ * Transactional object = ...
++ * object.begin(ReadWrite.WRITE) ;
++ * try {
++ * ... actions inside a write transaction ...
++ * object.commit() ;
++ * } finally {
++ * // This causes an abort if {@code commit} has not been called.
++ * object.end() ;
++ * }
++ * </pre>
++ * Exceptions will not be thrown.
++ * If any do occur, this indicates serious internal problems with the transaction system.
++ */
++public interface Transactional extends org.apache.jena.sparql.core.Transactional
++{
++ /** Start either a READ or WRITE transaction */
++ @Override
++ public void begin(ReadWrite readWrite) ;
++
++ /** Attempt to promote a read transaction to a write transaction.
++ * This is not guaranteed to succeed - any changes by another write transaction
++ * may restrict promotion.
++ * <p>
++ * In the MR+SW implementation, any intervening write transaction will block promotion.
++ * <p>
++ * Promoting a transaction which is already a write transaction will return true.
++ * <p>
++ * Consider also:
++ * <pre>
++ * .end() ;
++ * .begin(WRITE) ;
++ * </pre>
++ * to see any intermediate commits from another writer.
++ *
++ * @return boolean indicating whether the transaction is now a write transaction or not.
++ */
++ public boolean promote() ;
++
++ /** Commit a transaction - finish the transaction and make any changes permanent (if a "write" transaction) */
++ @Override
++ public void commit() ;
++
++ /** Abort a transaction - finish the transaction and undo any changes (if a "write" transaction) */
++ @Override
++ public void abort() ;
++
++ /** Finish the transaction - if a write transaction and commit() has not been called, then abort. */
++ @Override
++ public void end() ;
++
++ /** Say whether inside a transaction. */
++ @Override
++ public boolean isInTransaction() ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/TransactionalFactory.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/TransactionalFactory.java
index 0000000,0000000..9daa686
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/TransactionalFactory.java
@@@ -1,0 -1,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.dboe.transaction;
++
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.transaction.txn.TransactionCoordinator ;
++import org.seaborne.dboe.transaction.txn.TransactionalBase ;
++import org.seaborne.dboe.transaction.txn.TransactionalComponent ;
++import org.seaborne.dboe.transaction.txn.TransactionalSystem ;
++import org.seaborne.dboe.transaction.txn.journal.Journal ;
++
++/** Helper operations for creating a {@link Transactional}.
++ * The operations capture some common patterns.
++ */
++public class TransactionalFactory {
++
++ /** Create, and start, management of a number of {@link TransactionalComponent}s */
++ public static Transactional createTransactional(Location location, TransactionalComponent ... elements) {
++ TransactionCoordinator coord = new TransactionCoordinator(location) ;
++ return createTransactional(coord, elements) ;
++ }
++
++ /** Create, and start, management of a number of {@link TransactionalComponent}s */
++ public static Transactional createTransactional(Journal journal, TransactionalComponent ... elements) {
++ TransactionCoordinator coord = new TransactionCoordinator(journal) ;
++ return createTransactional(coord, elements) ;
++ }
++
++ private static Transactional createTransactional(TransactionCoordinator coord, TransactionalComponent[] elements) {
++ for ( TransactionalComponent tc : elements ) {
++ coord.add(tc) ;
++ }
++ TransactionalBase base = new TransactionalBase(coord) ;
++ coord.start() ;
++ return base ;
++ }
++
++ /** Create, but do not start, a {@link TransactionalSystem} from a {@link TransactionCoordinator} */
++ public static TransactionalSystem createTransactionalSystem(TransactionCoordinator coord) {
++ return new TransactionalBase(coord) ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/TransactionalMonitor.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/TransactionalMonitor.java
index 0000000,0000000..a9e1d8f
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/TransactionalMonitor.java
@@@ -1,0 -1,0 +1,38 @@@
++/*
++ * 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.dboe.transaction;
++
++import org.apache.jena.query.ReadWrite ;
++
++/** Interface for the Transactional interface */
++public interface TransactionalMonitor {
++ default void startBegin(ReadWrite mode) {}
++ default void finishBegin(ReadWrite mode) {}
++
++ default void startPromote() {}
++ default void finishPromote() {}
++
++ default void startCommit() {}
++ default void finishCommit() {}
++
++ default void startAbort() {}
++ default void finishAbort() {}
++
++ default void startEnd() {}
++ default void finishEnd() {}
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/ComponentGroup.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/ComponentGroup.java
index 0000000,0000000..f38760e
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/ComponentGroup.java
@@@ -1,0 -1,0 +1,77 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import java.util.Arrays ;
++import java.util.HashMap ;
++import java.util.Map ;
++import java.util.Objects ;
++import java.util.function.BiConsumer ;
++import java.util.function.Consumer ;
++
++import org.apache.jena.atlas.logging.Log ;
++
++final
++public class ComponentGroup {
++ private Map<ComponentId, TransactionalComponent> group = new HashMap<>() ;
++
++ public ComponentGroup(TransactionalComponent...components) {
++ Arrays.asList(components).forEach(this::add);
++ }
++
++ private ComponentGroup(Map<ComponentId, TransactionalComponent> group) {
++ this.group.putAll(group);
++ }
++
++ public void add(TransactionalComponent component) {
++ Objects.requireNonNull(component) ;
++ //Log.info(this, "add("+component.getComponentId()+")") ;
++ if ( component.getComponentId() == null )
++ Log.warn(this, "Null component id - likely to be overwritten: "+component) ;
++
++ if ( group.containsKey(component.getComponentId()) ) {
++ Log.warn(this, component.getComponentId().toString()) ;
++ Log.warn(this, "Add component already in the group: "+component) ;
++ }
++
++ group.put(component.getComponentId(), component) ;
++ }
++
++ /*package*/ void remove(ComponentId componentId) {
++ group.remove(componentId) ;
++ }
++
++ public TransactionalComponent findComponent(ComponentId componentId) {
++ return group.get(componentId) ;
++ }
++
++ public void forEachComponent(Consumer<? super TransactionalComponent> action) {
++ group.values().forEach(action) ;
++ }
++
++ public void forEach(BiConsumer<ComponentId, TransactionalComponent> action) {
++ group.forEach(action);
++ }
++
++ public void addAll(ComponentGroup components) {
++ this.group.putAll(components.group);
++ }
++
++ public int size() { return group.size() ; }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/ComponentId.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/ComponentId.java
index 0000000,0000000..31081cd
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/ComponentId.java
@@@ -1,0 -1,0 +1,123 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import java.util.Arrays ;
++import java.util.UUID ;
++
++import org.apache.jena.atlas.lib.Bytes ;
++
++/** A {@code ComponentId} consists of two parts: a globally unique context
++ * (roughly - the domain where the {@code ComponentId} is valid)
++ * and an id within the context.
++ * Context is often a single coordinator but can be, for example,
++ * a distributed transaction coordinator.
++ */
++
++public class ComponentId {
++ // Fixed size.
++ public static final int SIZE = 4 ;
++ private final UUID coordinatorId ;
++ private final byte[] bytes ;
++ // Just a helper for development. Not persisted in the journal.
++ private final String displayName ;
++
++ /** Create a new ComponentId from the given bytes.
++ * The bytes are <em>not</em> copied.
++ * The caller must not modify them after this call.
++ * The static method {@link #create(String, byte[])}
++ * does the copy.
++ */
++ private ComponentId(String label, UUID coordinatorId, byte[] bytes) {
++ this.coordinatorId = coordinatorId ;
++ if ( label == null )
++ label = "" ;
++ if ( bytes.length > SIZE )
++ throw new IllegalArgumentException("Bytes for ComponentId too long "+bytes.length+" > "+SIZE) ;
++ if ( bytes.length < SIZE )
++ // Make safe.
++ bytes = Arrays.copyOf(bytes, SIZE) ;
++ this.bytes = bytes ;
++ this.displayName = label ;
++ }
++
++ public byte[] getBytes() { return bytes ; }
++
++ public UUID getBaseId() { return coordinatorId ; }
++
++ public String label() { return displayName ; }
++
++ @Override
++ public String toString() { return displayName+"["+Bytes.asHex(bytes)+"]" ; }
++
++ @Override
++ public int hashCode() {
++ final int prime = 31 ;
++ int result = 1 ;
++ result = prime * result + Arrays.hashCode(bytes) ;
++ return result ;
++ }
++
++ @Override
++ public boolean equals(Object obj) {
++ if ( this == obj )
++ return true ;
++ if ( obj == null )
++ return false ;
++ if ( getClass() != obj.getClass() )
++ return false ;
++ ComponentId other = (ComponentId)obj ;
++ if ( !Arrays.equals(bytes, other.bytes) )
++ return false ;
++ return true ;
++ }
++
++ /** Create a ComponentId from the given bytes */
++ public static ComponentId create(UUID coordinatorBase, byte[] bytes) {
++ bytes = Arrays.copyOf(bytes, bytes.length) ;
++ return new ComponentId(null, coordinatorBase, bytes) ;
++ }
++
++ /** Given a base componentId, create a derived (different) one.
++ * This is deterministically done based on baseComponentId and index.
++ * The label is just for display purposes.
++ */
++ public static ComponentId alloc(String label, UUID coordinatorBase, int index) {
++ byte[] bytes = Bytes.intToBytes(index) ;
++ return new ComponentId(label, coordinatorBase, bytes) ;
++ }
++
++// private static ComponentId create(byte[] bytes, String label, int index) {
++// bytes = Arrays.copyOf(bytes, bytes.length) ;
++// int x = Bytes.getInt(bytes, bytes.length-SystemBase.SizeOfInt) ;
++// x = x ^ index ;
++// Bytes.setInt(x, bytes, bytes.length - SystemBase.SizeOfInt) ;
++// ComponentId cid = new ComponentId(label+"-"+index, bytes) ;
++// return cid ;
++// }
++
++ static int counter = 0 ;
++ /** Return a fresh ComponentId (not preserved across JVM runs) */
++ public static ComponentId allocLocal() {
++ counter++ ;
++ UUID uuid = UUID.randomUUID() ;
++ return alloc("Local-"+counter, uuid, counter) ;
++ }
++
++}
++
[18/50] [abbrv] jena git commit: Update cmds
Posted by an...@apache.org.
Update cmds
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/cf4b7a82
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/cf4b7a82
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/cf4b7a82
Branch: refs/heads/jena-tdb2
Commit: cf4b7a8202f6b20d33c6ba1b7e396e85e6befeab
Parents: df59082
Author: Andy Seaborne <an...@seaborne.org>
Authored: Mon Sep 4 17:13:08 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Mon Sep 4 17:13:08 2017 +0100
----------------------------------------------------------------------
.../src/main/java/tdb2/cmdline/CmdSub.java | 49 +++++++++-----------
.../src/main/java/tdb2/cmdline/CmdTDB.java | 10 ++--
tdb2-cmds/src/main/java/tdb2/tdbbackup.java | 39 +++++++++++++---
tdb2-cmds/src/main/java/tdb2/tdbcompact.java | 45 ++++++++++++++++++
tdb2-cmds/src/main/java/tdb2/tdbdump.java | 3 +-
tdb2-cmds/src/main/java/tdb2/tdbstats.java | 3 +-
tdb2-cmds/tdb2 | 2 +-
.../java/org/seaborne/tdb2/sys/TDBInternal.java | 12 ++++-
8 files changed, 119 insertions(+), 44 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/cf4b7a82/tdb2-cmds/src/main/java/tdb2/cmdline/CmdSub.java
----------------------------------------------------------------------
diff --git a/tdb2-cmds/src/main/java/tdb2/cmdline/CmdSub.java b/tdb2-cmds/src/main/java/tdb2/cmdline/CmdSub.java
index 03b12af..bda20c5 100644
--- a/tdb2-cmds/src/main/java/tdb2/cmdline/CmdSub.java
+++ b/tdb2-cmds/src/main/java/tdb2/cmdline/CmdSub.java
@@ -24,37 +24,34 @@ import java.util.Map;
import jena.cmd.CmdException;
-public class CmdSub
-{
- public interface Exec { public void exec(String[] argv) ; }
- Map<String, Exec> dispatch = new HashMap<>() ;
-
- String subCmd ;
- String args[] ;
-
- public CmdSub(String ...argv)
- {
+public class CmdSub {
+ public interface Exec {
+ public void exec(String[] argv) ;
+ }
+ private Map<String, Exec> dispatch = new HashMap<>() ;
+
+ private String subCmd ;
+ private String args[] ;
+
+ public CmdSub(String... argv) {
subCmd = subCommand(argv) ;
args = cmdline(argv) ;
}
-
- protected void exec()
- {
+
+ protected void exec() {
Exec exec = dispatch.get(subCmd) ;
if ( exec == null )
- throw new CmdException("No subcommand: "+subCmd) ;
+ throw new CmdException("No subcommand: " + subCmd) ;
exec.exec(args) ;
}
- protected static String[] cmdline(String ... argv)
- {
- String [] a = new String[argv.length-1] ;
- System.arraycopy(argv, 1, a, 0, argv.length-1) ;
- return a ;
+ protected static String[] cmdline(String... argv) {
+ String[] a = new String[argv.length - 1] ;
+ System.arraycopy(argv, 1, a, 0, argv.length - 1) ;
+ return a ;
}
- protected static String subCommand(String ... argv)
- {
+ protected static String subCommand(String... argv) {
if ( argv.length == 0 )
throw new CmdException("Missing subcommand") ;
@@ -63,14 +60,12 @@ public class CmdSub
throw new CmdException("Argument found where subcommand expected") ;
return subCmd ;
}
-
- protected void addSubCommand(String subCmdName, Exec exec)
- {
+
+ protected void addSubCommand(String subCmdName, Exec exec) {
dispatch.put(subCmdName, exec) ;
}
-
- protected Collection<String> subCommandNames()
- {
+
+ protected Collection<String> subCommandNames() {
return dispatch.keySet() ;
}
}
http://git-wip-us.apache.org/repos/asf/jena/blob/cf4b7a82/tdb2-cmds/src/main/java/tdb2/cmdline/CmdTDB.java
----------------------------------------------------------------------
diff --git a/tdb2-cmds/src/main/java/tdb2/cmdline/CmdTDB.java b/tdb2-cmds/src/main/java/tdb2/cmdline/CmdTDB.java
index 556cf67..da799fd 100644
--- a/tdb2-cmds/src/main/java/tdb2/cmdline/CmdTDB.java
+++ b/tdb2-cmds/src/main/java/tdb2/cmdline/CmdTDB.java
@@ -28,9 +28,8 @@ import org.apache.jena.sparql.core.DatasetGraph ;
import org.apache.jena.system.JenaSystem ;
import org.seaborne.dboe.base.file.Location;
import org.seaborne.tdb2.TDB2;
-import org.seaborne.tdb2.store.DatasetGraphTDB;
-import org.seaborne.tdb2.sys.TDBInternal;
-import tdb2.cmdline.ModTDBDataset;
+import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
+import org.seaborne.tdb2.sys.TDBInternal ;
public abstract class CmdTDB extends CmdARQ
{
@@ -70,9 +69,8 @@ public abstract class CmdTDB extends CmdARQ
return getDataset().asDatasetGraph() ;
}
- protected DatasetGraphTDB getDatasetGraphTDB() {
- DatasetGraph dsg = getDatasetGraph() ;
- return TDBInternal.getDatasetGraphTDB(dsg) ;
+ protected DatasetGraphSwitchable getDatabaseContainer() {
+ return TDBInternal.getDatabaseContainer(getDatasetGraph());
}
protected Dataset getDataset() {
http://git-wip-us.apache.org/repos/asf/jena/blob/cf4b7a82/tdb2-cmds/src/main/java/tdb2/tdbbackup.java
----------------------------------------------------------------------
diff --git a/tdb2-cmds/src/main/java/tdb2/tdbbackup.java b/tdb2-cmds/src/main/java/tdb2/tdbbackup.java
index 3f75741..8291514 100644
--- a/tdb2-cmds/src/main/java/tdb2/tdbbackup.java
+++ b/tdb2-cmds/src/main/java/tdb2/tdbbackup.java
@@ -1,4 +1,4 @@
-/**
+/*
* 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
@@ -18,11 +18,38 @@
package tdb2;
-public class tdbbackup
+import arq.cmdline.ModLangOutput ;
+import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
+import org.seaborne.tdb2.sys.DatabaseOps ;
+import tdb2.cmdline.CmdTDB;
+
+public class tdbbackup extends CmdTDB
{
- // For now, implement as "dump".
- static public void main(String... argv) {
- tdbdump.main(argv);
+ static ModLangOutput modLangOutput = new ModLangOutput() ;
+
+ static public void main(String... argv)
+ {
+ CmdTDB.init() ;
+ new tdbbackup(argv).mainRun() ;
}
-}
+ protected tdbbackup(String[] argv)
+ {
+ super(argv) ;
+ addModule(modLangOutput) ;
+ }
+
+ @Override
+ protected String getSummary()
+ {
+ return getCommandName()+" : Backup a TDB dataset" ;
+ }
+
+ @Override
+ protected void exec()
+ {
+ DatasetGraphSwitchable dsg = getDatabaseContainer();
+ String fn = DatabaseOps.backup(dsg);
+ System.out.println("Backup written to "+fn);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/cf4b7a82/tdb2-cmds/src/main/java/tdb2/tdbcompact.java
----------------------------------------------------------------------
diff --git a/tdb2-cmds/src/main/java/tdb2/tdbcompact.java b/tdb2-cmds/src/main/java/tdb2/tdbcompact.java
new file mode 100644
index 0000000..373e822
--- /dev/null
+++ b/tdb2-cmds/src/main/java/tdb2/tdbcompact.java
@@ -0,0 +1,45 @@
+/*
+ * 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 tdb2;
+
+import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
+import org.seaborne.tdb2.sys.DatabaseOps ;
+import tdb2.cmdline.CmdTDB;
+
+public class tdbcompact extends CmdTDB {
+ static public void main(String... argv) {
+ CmdTDB.init() ;
+ new tdbcompact(argv).mainRun() ;
+ }
+
+ protected tdbcompact(String[] argv) {
+ super(argv) ;
+ }
+
+ @Override
+ protected String getSummary() {
+ return getCommandName() + " : Compact a TDB2 dataset" ;
+ }
+
+ @Override
+ protected void exec() {
+ DatasetGraphSwitchable dsg = getDatabaseContainer() ;
+ DatabaseOps.compact(dsg) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/cf4b7a82/tdb2-cmds/src/main/java/tdb2/tdbdump.java
----------------------------------------------------------------------
diff --git a/tdb2-cmds/src/main/java/tdb2/tdbdump.java b/tdb2-cmds/src/main/java/tdb2/tdbdump.java
index e562196..f54220c 100644
--- a/tdb2-cmds/src/main/java/tdb2/tdbdump.java
+++ b/tdb2-cmds/src/main/java/tdb2/tdbdump.java
@@ -52,8 +52,7 @@ public class tdbdump extends CmdTDB
@Override
protected void exec()
{
- DatasetGraph dsg = super.getDatasetGraphTDB() ;
-
+ DatasetGraph dsg = getDatasetGraph() ;
// Prefer stream over fully pretty output formats.
RDFFormat fmt = modLangOutput.getOutputStreamFormat() ;
// Stream writing happens naturally - no need to call StreamRDFWriter.
http://git-wip-us.apache.org/repos/asf/jena/blob/cf4b7a82/tdb2-cmds/src/main/java/tdb2/tdbstats.java
----------------------------------------------------------------------
diff --git a/tdb2-cmds/src/main/java/tdb2/tdbstats.java b/tdb2-cmds/src/main/java/tdb2/tdbstats.java
index 162bff2..7f53199 100644
--- a/tdb2-cmds/src/main/java/tdb2/tdbstats.java
+++ b/tdb2-cmds/src/main/java/tdb2/tdbstats.java
@@ -33,6 +33,7 @@ import org.seaborne.tdb2.store.DatasetGraphTDB;
import org.seaborne.tdb2.store.NodeId;
import org.seaborne.tdb2.store.nodetable.NodeTable;
import org.seaborne.tdb2.store.nodetupletable.NodeTupleTable;
+import org.seaborne.tdb2.sys.TDBInternal ;
import tdb2.cmdline.CmdTDB;
import tdb2.cmdline.CmdTDBGraph;
@@ -90,7 +91,7 @@ public class tdbstats extends CmdTDBGraph {
@Override
protected void exec() {
- DatasetGraphTDB dsg = getDatasetGraphTDB();
+ DatasetGraphTDB dsg = TDBInternal.getDatasetGraphTDB(getDatasetGraph());
Node gn = getGraphName();
StatsResults results = stats(dsg, gn);
Stats.write(System.out, results);
http://git-wip-us.apache.org/repos/asf/jena/blob/cf4b7a82/tdb2-cmds/tdb2
----------------------------------------------------------------------
diff --git a/tdb2-cmds/tdb2 b/tdb2-cmds/tdb2
index 583ca7e..d2772db 100755
--- a/tdb2-cmds/tdb2
+++ b/tdb2-cmds/tdb2
@@ -79,7 +79,7 @@ TDB2_PKG="tdb2"
case $CMD in
"")
;;
- tdbbackup | tdbdump | tdbloader | tdbquery | tdbstats | tdbupdate)
+ tdbbackup | tdbdump | tdbloader | tdbquery | tdbstats | tdbupdate | tdbcompact)
CMD_CLS="$TDB2_PKG"."$CMD"
;;
## tools.*)
http://git-wip-us.apache.org/repos/asf/jena/blob/cf4b7a82/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java b/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java
index 3bd7427..0b57de8 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/sys/TDBInternal.java
@@ -106,10 +106,20 @@ public class TDBInternal {
* Return the DatasetGraphTDB for a DatasetGraph, or null.
* Use the {@link DatasetGraphTDB} with care.
*/
+ public static DatasetGraphSwitchable getDatabaseContainer(DatasetGraph dsg) {
+ if ( dsg instanceof DatasetGraphSwitchable )
+ return (DatasetGraphSwitchable)dsg;
+ throw new TDBException("Not a TDB database container");
+ }
+
+ /**
+ * Return the DatasetGraphTDB for a DatasetGraph, or null.
+ * Use the {@link DatasetGraphTDB} with care.
+ */
public static DatasetGraphTDB getDatasetGraphTDB(DatasetGraph dsg) {
return unwrap(dsg);
}
-
+
/**
* Return the DatasetGraphTDB for a DatasetGraph, or throw an exception.
*/
[46/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/FileLib.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/FileLib.java
index 0000000,0000000..e1a827b
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/FileLib.java
@@@ -1,0 -1,0 +1,85 @@@
++/*
++ * 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.dboe.sys;
++
++import java.io.FileNotFoundException ;
++import java.io.IOException ;
++import java.io.RandomAccessFile ;
++import java.nio.channels.FileChannel ;
++
++import org.apache.jena.atlas.io.IO ;
++import org.seaborne.dboe.base.file.ChannelManager ;
++import org.seaborne.dboe.base.file.FileException ;
++
++// => IO
++public class FileLib
++{
++ // Check whether still used.
++
++ public static FileChannel openUnmanaged(String filename) {
++ return openUnmanaged(filename, "rw") ;
++ }
++
++ // And operation from BufferChannelFile
++
++ public static FileChannel openUnmanaged(String filename, String mode) {
++ try {
++ @SuppressWarnings("resource")
++ RandomAccessFile out = new RandomAccessFile(filename, mode) ;
++ FileChannel channel = out.getChannel() ;
++ return channel ;
++ }
++ catch (FileNotFoundException e) {
++ IO.exception(e) ;
++ return null ;
++ }
++ }
++
++ // TODO remove and call ChannelManager directly
++ public static FileChannel openManaged(String filename) {
++ return openManaged(filename, "rw") ;
++ }
++
++ // TODO remove and call ChannelManager directly
++ public static FileChannel openManaged(String filename, String mode) {
++ return ChannelManager.acquire(filename, mode) ;
++ }
++
++ public static long size(FileChannel channel) {
++ try {
++ return channel.size() ;
++ } catch (IOException ex)
++ { IO.exception(ex) ; return -1L ; }
++ }
++
++ public static void truncate(FileChannel channel, long posn) {
++ try { channel.truncate(posn) ; }
++ catch (IOException ex) { IO.exception(ex) ; }
++ }
++
++ public static void close(FileChannel channel) {
++ ChannelManager.release(channel) ;
++ }
++
++ public static void sync(FileChannel channel) {
++ try {
++ channel.force(true) ;
++ } catch (IOException ex)
++ { throw new FileException("FileBase.sync", ex) ; }
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/Names.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/Names.java
index 0000000,0000000..0729e67
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/Names.java
@@@ -1,0 -1,0 +1,150 @@@
++/*
++ * 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.dboe.sys;
++
++/** Names of things in TDB */
++public class Names
++{
++ /** Filename of the TDB configuration file */
++ public static final String TDB_CONFIG_FILE = "tdb.cfg" ;
++
++ /** Filename of the TDB lock file */
++ public static final String TDB_LOCK_FILE = "tdb.lock" ;
++
++ /* System files */
++ public static final String extJournal = "jrnl" ;
++ /* Component Transactional State */
++ public static final String extState = "cts" ;
++
++ public static final String journalFileBase = "journal" ;
++ public static final String journalFile = journalFileBase+"."+extJournal ;
++
++ // ++ Elsewhere
++ /* RDF indexes */
++ public static final String primaryIndexTriples = "SPO" ;
++ public static final String[] tripleIndexes = { primaryIndexTriples, "POS", "OSP" } ;
++
++ public static final String primaryIndexQuads = "GSPO" ;
++ public static final String[] quadIndexes = { primaryIndexQuads, "GPOS", "GOSP", "POSG", "OSPG", "SPOG"} ;
++
++ public static final String primaryIndexPrefix = "GPU" ;
++ public static final String[] prefixIndexes = { primaryIndexPrefix } ;
++ // ++ Elsewhere
++
++ /* B+Trees - nodes file and records file */
++ public static final String extBptState = "bpt" ;
++ public static final String extBptTree = "idn" ;
++ public static final String extBptRecords = "dat" ;
++
++// /* B+Trees - single file per tree */
++// public static final String btExt = "idx" ;
++
++ /* ExtHash - dictionary file*/
++ public static final String extHashExt = "exh" ;
++ public static final String extHashBucketExt = "dat" ;
++
++ public static final String datasetConfig = "config-tdb" ; // name of the TDB configuration file.
++
++ /* Node files */
++ public static final String extBdfState = "bdf" ; // Node state
++ public static final String extObjNodeData = "obj" ;
++ public static final String nodeTableBaseName = "nodes" ; // Node table
++
++ /** Prefixes file */
++ public static final String prefixTableBaseName = "prefixes" ; // Prefix node table
++
++ /** Optimizer / stats */
++ public static final String optStats = "stats.opt" ;
++ public static final String optFixed = "fixed.opt" ;
++ public static final String optNone = "none.opt" ;
++ public static final String optDefault = optFixed ;
++
++ public static final String extMeta = "info" ;
++ public static final String directoryMetafile = "this" ; // Root name of the directory for a metafile.
++
++ /** Name to indicate in-memory */
++ public static final String memName = "--mem--" ;
++
++ public static boolean isMem(String name) { return memName.equals(name) ; }
++
++ // ---- Names for Java properties in metadata files
++
++ public static String makeKey(String root, String...elements)
++ { return makeName(root, elements) ; }
++
++ public static String makeName(String root, String...elements)
++ {
++ StringBuilder sb = new StringBuilder() ;
++ sb.append(root) ;
++ for ( String s : elements )
++ {
++ if ( ! s.startsWith(".") )
++ sb.append(".") ;
++ sb.append(s) ;
++ }
++ return sb.toString() ;
++ }
++
++ // Component elements.
++ public static final String elNode = "node" ;
++ public static final String elBPlusTree = "bptree" ;
++ public static final String elIndex = "index" ;
++ public static final String elObject = "object" ;
++
++ public static final String elType = "type" ;
++ public static final String elLayout = "layout" ;
++ public static final String elVersion = "version" ;
++ public static final String elTimestamp = "timestamp" ;
++ public static final String elCreated = "created" ;
++
++ // Root names.
++ public static final String keyNS = "tdb" ;
++ public static final String keyNSNode = makeName(keyNS, elNode) ;
++ public static final String keyNSBPlusTree = makeName(keyNS, elBPlusTree) ;
++
++ // Location metadata - in the directory wide metadata file.
++ public static final String kVersion = makeName(keyNS, elVersion) ;
++ public static final String kCreatedDate = makeName(keyNS, elTimestamp) ;
++
++ // Node table metadata
++ public static final String kNodeTableType = makeName(keyNS, elNode, elType) ;
++ public static final String kNodeTableLayout = makeName(keyNS, elNode, elLayout) ;
++
++// // Object file
++// public static final String kObjectTableType = makeName(keyNS, elObject, elType) ;
++//
++// // Default index metadata - in the index metadata file.
++//
++// public static final String kIndexType = makeName(keyNS, elIndex, elType) ;
++// public static final String kIndexFileLayout = makeName(keyNS, elIndex, elLayout) ;
++
++ // See also BPlusTreeParams for keyNSBPlusTree derived names.
++
++// // Current values
++// public static final String currentIndexType = IndexType.BPlusTree.getName() ;
++// public static final String currentIndexFileVersion = "v1" ;
++
++ // Property strings - Setup
++
++ public static final String pNode2NodeIdCacheSize = "tdb.cache.node2nodeid.size" ;
++ public static final String pNodeId2NodeCacheSize = "tdb.cache.nodeid2node.size" ;
++ public static final String pNodeMissesCacheSize = "tdb.cache.nodeMiss.size" ;
++ public static final String pBlockWriteCacheSize = "tdb.cache.blockwrite.size" ;
++ public static final String pBlockReadCacheSize = "tdb.cache.blockread.size" ;
++ public static final String pSyncTick = "tdb.synctick" ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/ProcessUtils.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/ProcessUtils.java
index 0000000,0000000..46cb252
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/ProcessUtils.java
@@@ -1,0 -1,0 +1,156 @@@
++/*
++ * 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.dboe.sys;
++
++import java.io.BufferedReader;
++import java.io.IOException;
++import java.io.InputStreamReader;
++import java.lang.management.ManagementFactory;
++import java.util.ArrayList;
++import java.util.List;
++
++public class ProcessUtils {
++
++ private static int myPid = -1;
++
++ /**
++ * Tries to get the PID of the current process caching it for future calls
++ * since it won't change throughout the life of the process
++ *
++ * @param fallback
++ * Fallback PID to return if unable to determine the PID i.e. an
++ * error code to return
++ *
++ * @return PID of current process or provided {@code fallback} if unable to
++ * determine PID
++ */
++ public static int getPid(int fallback) {
++ if (myPid != -1)
++ return myPid;
++
++ String runtimeBeanName = ManagementFactory.getRuntimeMXBean().getName();
++ if (runtimeBeanName == null) {
++ return useFallbackPid(fallback);
++ }
++
++ // Bean name will have format PID@hostname so we try to parse the PID
++ // portion
++ int index = runtimeBeanName.indexOf("@");
++ if (index < 0)
++ return useFallbackPid(fallback);
++ try {
++ // Parse and cache for future reuse
++ String pidData = runtimeBeanName.substring(0, index);
++ myPid = Integer.parseInt(pidData);
++ return myPid;
++ } catch (NumberFormatException e) {
++ // Invalid PID
++ return useFallbackPid(fallback);
++ }
++ }
++
++ private static int useFallbackPid(int fallback) {
++ // In the case where we can't determine our PID then treat ourselves as
++ // no owner and cache for future use
++ myPid = fallback;
++ return myPid;
++ }
++
++ /**
++ * Determines whether a given PID is alive
++ *
++ * @param pid
++ * PID
++ * @return True if the given PID is alive or unknown, false if it is dead
++ */
++ public static boolean isAlive(int pid) {
++ String pidStr = Integer.toString(pid);
++ try {
++ List<String> data = getProcessInfo(pidStr);
++
++ // Expect a line to contain the PID to indicate the process is
++ // alive
++ for (String lineData : data) {
++ if (lineData.contains(pidStr))
++ return true;
++ }
++
++ // Did not find any lines mentioning the PID so we can safely
++ // assume that process is dead
++ return false;
++ } catch (IOException e) {
++ // If any error running the process to check for the live process
++ // then our check failed and for safety we assume the process is
++ // alive
++
++ Sys.errlog
++ .warn("Your platform does not support checking process liveness so TDB disk locations cannot be reliably locked to prevent possible corruption due to unsafe multi-JVM usage");
++ return true;
++ }
++ }
++
++ /**
++ * Gets whether the platform we are running on will cause us to treat
++ * negative (i.e. invalid) PIDs as alive because of the format in which the
++ * command line process monitor application for the system returns errors
++ * for invalid PIDs
++ *
++ * @return True if a negative PID is treated as alive on this platform or we
++ * cannot determine liveness for PIDs on this platform, false
++ * otherwise
++ */
++ public static boolean negativePidsTreatedAsAlive() {
++ return isAlive(-1);
++ }
++
++ /**
++ * Gets process information based on the given PID string
++ *
++ * @param pidStr
++ * PID string
++ * @return Output of running the OSes appropriate command line task info
++ * application
++ * @throws IOException
++ * Thrown if there is a problem running the command line
++ * application or reading the data returned
++ */
++ private static List<String> getProcessInfo(String pidStr) throws IOException {
++ Process p;
++ if (Sys.isWindows) {
++ // Use the Windows tasklist utility
++ ProcessBuilder builder = new ProcessBuilder("tasklist", "/FI", "PID eq " + pidStr);
++ builder.redirectErrorStream(true);
++ p = builder.start();
++ } else {
++ // Use the ps utility
++ ProcessBuilder builder = new ProcessBuilder("ps", "-p", pidStr);
++ builder.redirectErrorStream(true);
++ p = builder.start();
++ }
++
++ // Run and read data from the process
++ try(BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
++ List<String> data = new ArrayList<>();
++ String line = null;
++ while ((line = reader.readLine()) != null) {
++ data.add(line);
++ }
++ return data;
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/Sys.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/Sys.java
index 0000000,0000000..356cb76
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/Sys.java
@@@ -1,0 -1,0 +1,96 @@@
++/*
++ * 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.dboe.sys;
++
++import java.nio.ByteOrder;
++import java.util.concurrent.Executor ;
++import java.util.concurrent.Executors ;
++
++import org.apache.jena.atlas.logging.Log ;
++import org.seaborne.dboe.DBOpEnvException ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/** Low level environment */
++public class Sys
++{
++ static final Logger log = LoggerFactory.getLogger("Sys") ;
++
++ /** System log - use for general messages (a few) and warnings.
++ * Generally, do not log events unless you want every user to see them every time.
++ * Libraries and embedded systems should be seen and not heard.
++ * @see #errlog
++ */
++
++ /** General system log */
++ public static final Logger syslog = LoggerFactory.getLogger("System") ;
++ /** Send warnings and error */
++ public static final Logger errlog = LoggerFactory.getLogger("System") ;
++
++ /** Size, in bytes, of a Java long */
++ public static final int SizeOfLong = Long.BYTES ; // Long.SIZE/Byte.SIZE ;
++
++ /** Size, in bytes, of a Java int */
++ public static final int SizeOfInt = Integer.BYTES ; //Integer.SIZE/Byte.SIZE ;
++
++ public static final boolean is64bitSystem = determineIf64Bit() ;
++
++ public static final ByteOrder NetworkOrder = ByteOrder.BIG_ENDIAN ;
++
++ // To make the class initialize
++ static public void init() {}
++
++ public static void panic(Class<? > clazz, String string) {
++ Log.error(clazz, string) ;
++ throw new DBOpEnvException(string) ;
++ }
++ public static final boolean isWindows = determineIfWindows() ; // Memory mapped files behave differently.
++
++ //Or look in File.listRoots.
++ //Alternative method:
++ // http://stackoverflow.com/questions/1293533/name-of-the-operating-system-in-java-not-os-name
++
++ private static boolean determineIfWindows() {
++ String s = System.getProperty("os.name") ;
++ if ( s == null )
++ return false ;
++ return s.startsWith("Windows ") ;
++ }
++
++ /** A general thread pool */
++ public static Executor executor = Executors.newCachedThreadPool() ;
++
++ private static boolean determineIf64Bit() {
++ String s = System.getProperty("sun.arch.data.model") ;
++ if ( s != null ) {
++ boolean b = s.equals("64") ;
++ syslog.debug("System architecture: " + (b ? "64 bit" : "32 bit")) ;
++ return b ;
++ }
++ // Not a SUN VM
++ s = System.getProperty("java.vm.info") ;
++ if ( s == null ) {
++ log.warn("Can't determine the data model") ;
++ return false ;
++ }
++ log.debug("Can't determine the data model from 'sun.arch.data.model' - using java.vm.info") ;
++ boolean b = s.contains("64") ;
++ syslog.debug("System architecture: (from java.vm.info) " + (b ? "64 bit" : "32 bit")) ;
++ return b ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/SystemFile.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/SystemFile.java
index 0000000,0000000..5971904
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/SystemFile.java
@@@ -1,0 -1,0 +1,23 @@@
++/*
++ * 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.dboe.sys;
++
++public class SystemFile {
++ public static final int ObjectFileWriteBufferSize = 8*1024 ;
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/SystemIndex.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/SystemIndex.java
index 0000000,0000000..0304b9c
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/sys/SystemIndex.java
@@@ -1,0 -1,0 +1,149 @@@
++/*
++ * 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.dboe.sys;
++
++import org.seaborne.dboe.DBOpEnvException ;
++import org.seaborne.dboe.base.block.FileMode ;
++
++public class SystemIndex
++{
++ /** Size, in bytes, of a pointer between blocks */
++ public static final int SizeOfPointer = Sys.SizeOfInt ;
++
++ public static final boolean is64bitSystem = Sys.is64bitSystem ;
++
++ // To make the class initialize
++ static public void init() {}
++
++ /** Size, in bytes, of a block */
++ public static final int BlockSize = 8*1024 ; // intValue("BlockSize", 8*1024) ;
++
++ /** Size, in bytes, of a block for testing */
++ public static final int BlockSizeTest = 1024 ; // intValue("BlockSizeTest", 1024) ;
++
++ /** Size, in bytes, of a block for testing */
++ public static final int BlockSizeTestMem = 500 ;
++
++// /** Size, in bytes, of a memory block */
++// public static final int BlockSizeMem = 32*8 ; //intValue("BlockSizeMem", 32*8 ) ;
++
++ /** Order of an in-memory BTree or B+Tree */
++ public static final int OrderMem = 5 ; // intValue("OrderMem", 5) ;
++
++ /** Size, in bytes, of a segment (used for memory mapped files) */
++ public static final int SegmentSize = 8*1024*1024 ; // intValue("SegmentSize", 8*1024*1024) ;
++
++ // ---- Cache sizes (within the JVM)
++
++ /** Size of Node to NodeId cache.
++ * Used to map from Node to NodeId spaces.
++ * Used for loading and for query preparation.
++ */
++ public static final int Node2NodeIdCacheSize = intValue("Node2NodeIdCacheSize", ( is64bitSystem ? 100*1000 : 50*1000 )) ;
++
++ /** Size of NodeId to Node cache.
++ * Used to map from NodeId to Node spaces.
++ * Used for retriveing results.
++ */
++ public static final int NodeId2NodeCacheSize = intValue("NodeId2NodeCacheSize", ( is64bitSystem ? 500*1000 : 50*1000 ) ) ;
++
++ /** Size of Node lookup miss cache. */
++ public static final int NodeMissCacheSize = 100 ;
++
++ /** Size of the delayed-write block cache (32 bit systems only) (per file) */
++ public static final int BlockWriteCacheSize = intValue("BlockWriteCacheSize", 2*1000) ;
++
++ /** Size of read block cache (32 bit systems only). Increase JVM size as necessary. Per file. */
++ public static final int BlockReadCacheSize = intValue("BlockReadCacheSize", 10*1000) ;
++
++ private static int intValue(String name, int dft) { return dft ; }
++
++
++ public static void setNullOut(boolean nullOut)
++ { NullOut = nullOut ; }
++
++ /** Are we nulling out unused space in bytebuffers (records, points etc) */
++ public static boolean getNullOut()
++ { return NullOut ; }
++
++ /** null out (with the FillByte) freed up space in buffers */
++ public static boolean NullOut = false ;
++
++ /** FillByte value for NullOut */
++ public static final byte FillByte = (byte)0xFF ;
++
++ public static boolean Checking = false ; // This isn't used enough!
++
++ // ---- File mode
++
++ private static FileMode fileMode = null ;
++ public static FileMode fileMode()
++ {
++ if ( fileMode == null )
++ fileMode = determineFileMode() ;
++ return fileMode ;
++ }
++
++ public static void setFileMode(FileMode newFileMode)
++ {
++ if ( fileMode != null )
++ {
++ Sys.log.warn("System file mode already determined - setting it has no effect") ;
++ return ;
++ }
++ fileMode = newFileMode ;
++ }
++
++ // So the test suite can setup thing up ... very carefully.
++ /*package*/ static void internalSetFileMode(FileMode newFileMode)
++ {
++ fileMode = newFileMode ;
++ }
++
++ private static FileMode determineFileMode()
++ {
++ // Be careful that this is not called very, very early, before --set might be seen.
++ // Hence delayed access above in fileMode().
++
++ //String x = ARQ.getContext().getAsString(SystemTDB.symFileMode, "default") ;
++ String x = "default" ;
++
++ if ( x.equalsIgnoreCase("direct") )
++ {
++ Sys.syslog.info("File mode: direct (forced)") ;
++ return FileMode.direct ;
++ }
++ if ( x.equalsIgnoreCase("mapped") )
++ {
++ Sys.syslog.info("File mode: mapped (forced)") ;
++ return FileMode.mapped ;
++ }
++
++ if ( x.equalsIgnoreCase("default") )
++ {
++ if ( is64bitSystem )
++ {
++ Sys.syslog.debug("File mode: Mapped") ;
++ return FileMode.mapped ;
++ }
++ Sys.syslog.debug("File mode: Direct") ;
++ return FileMode.direct ;
++ }
++ throw new DBOpEnvException("Unrecognized file mode (not one of 'default', 'direct' or 'mapped': "+x) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/test/BufferTestLib.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/test/BufferTestLib.java
index 0000000,0000000..2da791d
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/test/BufferTestLib.java
@@@ -1,0 -1,0 +1,62 @@@
++/*
++ * 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.dboe.test;
++
++import java.nio.ByteBuffer ;
++
++import org.seaborne.dboe.base.block.Block ;
++
++public class BufferTestLib
++{
++ public static boolean sameValue(Block block1, Block block2)
++ {
++ if ( block1.getId() != block2.getId()) return false ;
++ ByteBuffer bb1 = block1.getByteBuffer() ;
++ ByteBuffer bb2 = block2.getByteBuffer() ;
++
++ if ( bb1.capacity() != bb2.capacity() ) return false ;
++
++ for ( int i = 0 ; i < bb1.capacity() ; i++ )
++ if ( bb1.get(i) != bb2.get(i) ) return false ;
++ return true ;
++ }
++
++ public static boolean sameValue(ByteBuffer bb1, ByteBuffer bb2)
++ {
++ if ( bb1.capacity() != bb2.capacity() ) return false ;
++
++ int posn1 = bb1.position();
++ int limit1 = bb1.limit();
++ int posn2 = bb2.position();
++ int limit2 = bb2.limit();
++
++ bb1.clear() ;
++ bb2.clear() ;
++
++ try {
++ for ( int i = 0 ; i < bb1.capacity() ; i++ )
++ if ( bb1.get(i) != bb2.get(i) ) return false ;
++ return true ;
++ } finally {
++ bb1.position(posn1) ;
++ bb1.limit(limit1) ;
++ bb2.position(posn2) ;
++ bb2.limit(limit2) ;
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/main/java/org/seaborne/dboe/test/RecordLib.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/main/java/org/seaborne/dboe/test/RecordLib.java
index 0000000,0000000..569b21a
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/main/java/org/seaborne/dboe/test/RecordLib.java
@@@ -1,0 -1,0 +1,109 @@@
++/*
++ * 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.dboe.test;
++
++
++import java.util.ArrayList ;
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import org.apache.jena.atlas.lib.Bytes ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++
++/** Record support operations (mainly for testing using ints) */
++
++public class RecordLib
++{
++ // Size of a record when testing (one integer)
++ public final static int TestRecordLength = 4 ;
++
++ public final static RecordFactory recordFactory = new RecordFactory(TestRecordLength, 0) ;
++
++ public static Record intToRecord(int v) { return intToRecord(v, recordFactory) ; }
++ public static Record intToRecord(int v, int recLen) { return intToRecord(v, new RecordFactory(recLen, 0)) ; }
++
++ public static Record intToRecord(int v, RecordFactory factory)
++ {
++ byte[] vb = Bytes.packInt(v) ;
++
++ int recLen = factory.recordLength() ;
++ byte[] bb = new byte[recLen] ;
++ int x = 0 ; // Start point in bb.
++ if ( recLen > 4 )
++ x = recLen-4 ;
++
++ int len = Math.min(4, recLen) ;
++ int z = 4-len ; // Start point in vb
++
++ // Furthest right bytes.
++ for ( int i = len-1 ; i >= 0 ; i-- )
++ bb[x+i] = vb[z+i] ;
++
++ return factory.create(bb) ;
++ }
++
++ public static List<Record> intToRecord(int[] v) { return intToRecord(v, recordFactory) ; }
++
++ public static List<Record> intToRecord(int[] v, int recLen)
++ { return intToRecord(v, new RecordFactory(recLen, 0)) ; }
++
++ static List<Record> intToRecord(int[] v, RecordFactory factory)
++ {
++ List<Record> x = new ArrayList<>() ;
++ for ( int i : v )
++ x.add(intToRecord(i, factory)) ;
++ return x ;
++ }
++
++ public static int recordToInt(Record key)
++ {
++ return Bytes.getInt(key.getKey()) ;
++ }
++
++ public static List<Integer> toIntList(Iterator<Record> iter)
++ {
++ return Iter.toList(Iter.map(iter, item->recordToInt(item))) ;
++ }
++
++ public static Record r(int v)
++ {
++ return RecordLib.intToRecord(v, RecordLib.TestRecordLength) ;
++ }
++
++ public static int r(Record rec)
++ {
++ return RecordLib.recordToInt(rec) ;
++ }
++
++ public static List<Integer> toIntList(int... vals)
++ {
++ List<Integer> x = new ArrayList<>() ;
++ for ( int i : vals )
++ x.add(i) ;
++ return x ;
++ }
++
++ public static List<Integer> r(Iterator<Record> iter)
++ {
++ return RecordLib.toIntList(iter) ;
++ }
++
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/ConfigTestDBOE.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/ConfigTestDBOE.java
index 0000000,0000000..174ebdc
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/ConfigTestDBOE.java
@@@ -1,0 -1,0 +1,76 @@@
++/*
++ * 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.dboe;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.seaborne.dboe.sys.Sys ;
++
++public class ConfigTestDBOE
++{
++ private static String testingDataRoot = "testing" ;
++ // Place under target
++ private static final String testingDir = "target/dboe-testing" ;
++ static boolean nonDeleteableMMapFiles = Sys.isWindows ;
++
++ static boolean initialized = false ;
++
++ private static void init()
++ {
++ FileOps.ensureDir("target") ;
++ FileOps.ensureDir(testingDir) ;
++ initialized = true ;
++ }
++
++ private static int count = 0 ;
++
++ public static void setTestingDataRoot(String dir) { testingDataRoot = dir ; }
++ public static String getTestingDataRoot() { return testingDataRoot ; }
++
++ /** return a directory */
++ public static final String getCleanDir() {
++ init() ;
++ String dir = nonDeleteableMMapFiles ? getTestingDirUnique() : getTestingDir() ;
++ FileOps.ensureDir(dir);
++ FileOps.clearDirectory(dir) ;
++ return dir ;
++ }
++ /** Get a empty directory name that has not been used before in this JVM */
++
++ private static final String getTestingDirUnique()
++ {
++ init() ;
++ String dn = testingDir+"/D-"+(++count) ;
++ FileOps.ensureDir(dn) ;
++ FileOps.clearDirectory(dn) ;
++ return dn ;
++ }
++
++ public static final String getTestingDir()
++ {
++ init() ;
++ return testingDir ;
++ }
++
++ public static final void deleteTestingDir()
++ {
++ if ( ! FileOps.exists(testingDir) )
++ return ;
++ FileOps.clearDirectory(testingDir) ;
++ FileOps.deleteSilent(testingDir) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/TC_DBOE_IO.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/TC_DBOE_IO.java
index 0000000,0000000..35a697d
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/TC_DBOE_IO.java
@@@ -1,0 -1,0 +1,60 @@@
++/*
++ * 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.dboe;
++
++import org.apache.log4j.Level ;
++import org.apache.log4j.Logger ;
++import org.junit.AfterClass ;
++import org.junit.BeforeClass ;
++import org.junit.runner.RunWith ;
++import org.junit.runners.Suite ;
++import org.seaborne.dboe.base.block.FileMode ;
++import org.seaborne.dboe.base.block.TS_Block ;
++import org.seaborne.dboe.base.buffer.TS_Buffer ;
++import org.seaborne.dboe.base.file.TS_File ;
++import org.seaborne.dboe.base.record.TS_Record ;
++import org.seaborne.dboe.base.recordfile.TS_RecordFile ;
++import org.seaborne.dboe.sys.SystemIndex ;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TS_Block.class
++ , TS_File.class
++ , TS_Buffer.class
++ , TS_Record.class
++ , TS_RecordFile.class
++} )
++
++public class TC_DBOE_IO {
++ static {
++ if ( false )
++ SystemIndex.setFileMode(FileMode.direct) ;
++ }
++
++ @BeforeClass static public void beforeClass()
++ {
++ //org.apache.log4j.LogManager.resetConfiguration() ;
++ //org.apache.log4j.PropertyConfigurator.configure("log4j.properties") ;
++ Logger.getLogger("org.apache.jena.tdb.info").setLevel(Level.WARN) ;
++ //Logger.getLogger("com.hp.hpl.jena.tdb.exec").setLevel(Level.WARN) ;
++ }
++
++ @AfterClass static public void afterClass() {
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/AbstractTestBlockMgr.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/AbstractTestBlockMgr.java
index 0000000,0000000..1b8c695
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/AbstractTestBlockMgr.java
@@@ -1,0 -1,0 +1,133 @@@
++/*
++ * 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.dboe.base.block ;
++
++import java.nio.ByteBuffer ;
++
++import static org.apache.jena.atlas.lib.ByteBufferLib.fill ;
++import org.junit.Assert ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++
++public abstract class AbstractTestBlockMgr extends Assert {
++ static final public int BlkSize = 256 ;
++
++ protected BlockMgr blockMgr = null ;
++
++ @Before
++ public void before() {
++ blockMgr = make() ;
++ blockMgr.beginUpdate() ;
++ }
++
++ @After
++ public void after() {
++ if ( blockMgr != null ) {
++ blockMgr.endUpdate() ;
++ blockMgr.close() ;
++ }
++ }
++
++ @Test
++ public void file01() {
++ long x = blockMgr.allocLimit() ;
++ assertTrue("First allocLimit : " + x, x >= 0) ;
++ // Assume no recycling.
++ Block block = blockMgr.allocate(BlkSize) ;
++ assertTrue("Block inside allocate boundary", block.getId() >= x) ;
++ ByteBuffer bb = block.getByteBuffer() ;
++ fill(bb, (byte)1) ;
++ blockMgr.write(block) ;
++ blockMgr.release(block) ;
++ }
++
++ @Test
++ public void file02() {
++ Block block = blockMgr.allocate(BlkSize) ;
++ ByteBuffer bb = block.getByteBuffer() ;
++ fill(bb, (byte)1) ;
++ long id = block.getId() ;
++ blockMgr.write(block) ;
++ blockMgr.release(block) ;
++
++ Block block2 = blockMgr.getRead(id) ;
++ ByteBuffer bb2 = block2.getByteBuffer() ;
++ assertEquals(bb2.capacity(), BlkSize) ;
++ assertEquals(bb2.get(0), (byte)1) ;
++ assertEquals(bb2.get(BlkSize - 1), (byte)1) ;
++ blockMgr.release(block2) ;
++ }
++
++ @Test
++ public void file03() {
++ Block block = blockMgr.allocate(BlkSize) ;
++ ByteBuffer bb = block.getByteBuffer() ;
++ fill(bb, (byte)2) ;
++ long id = block.getId() ;
++ blockMgr.write(block) ;
++ blockMgr.release(block) ;
++
++ Block block2 = blockMgr.getRead(id) ;
++ ByteBuffer bb2 = block2.getByteBuffer() ;
++ assertEquals(bb2.capacity(), BlkSize) ;
++ assertEquals(bb2.get(0), (byte)2) ;
++ assertEquals(bb2.get(BlkSize - 1), (byte)2) ;
++ blockMgr.release(block2) ;
++ }
++
++ @Test
++ public void multiAccess01() {
++ Block block1 = blockMgr.allocate(BlkSize) ;
++ Block block2 = blockMgr.allocate(BlkSize) ;
++ long id1 = block1.getId() ;
++ long id2 = block2.getId() ;
++
++ ByteBuffer bb1 = block1.getByteBuffer() ;
++ ByteBuffer bb2 = block2.getByteBuffer() ;
++
++ fill(bb1, (byte)1) ;
++ fill(bb2, (byte)2) ;
++
++ blockMgr.write(block1) ;
++ blockMgr.write(block2) ;
++ blockMgr.release(block1) ;
++ blockMgr.release(block2) ;
++
++ Block block3 = blockMgr.getRead(id1) ;
++ Block block4 = blockMgr.getRead(id2) ;
++
++ ByteBuffer bb_1 = block3.getByteBuffer() ;
++ ByteBuffer bb_2 = block4.getByteBuffer() ;
++
++ contains(bb_1, (byte)1) ;
++ contains(bb_2, (byte)2) ;
++
++ blockMgr.release(block3) ;
++ blockMgr.release(block4) ;
++ }
++
++ protected abstract BlockMgr make() ;
++
++ protected static void contains(ByteBuffer bb, byte fillValue) {
++ for ( int i = 0 ; i < bb.limit() ; i++ )
++ assertEquals("Index: " + i, bb.get(i), fillValue) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/TS_Block.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/TS_Block.java
index 0000000,0000000..5a91b2c
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/TS_Block.java
@@@ -1,0 -1,0 +1,33 @@@
++/*
++ * 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.dboe.base.block;
++
++import org.junit.runner.RunWith;
++import org.junit.runners.Suite;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestBlockMgrMem.class
++ , TestBlockMgrDirect.class
++ , TestBlockMgrMapped.class
++ , TestBlockMgrTracked.class
++})
++
++
++public class TS_Block
++{}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/TestBlockMgrDirect.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/TestBlockMgrDirect.java
index 0000000,0000000..79c4d68
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/TestBlockMgrDirect.java
@@@ -1,0 -1,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.dboe.base.block;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.junit.AfterClass;
++import org.junit.BeforeClass;
++import org.seaborne.dboe.ConfigTestDBOE ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.block.BlockMgrFactory ;
++import org.seaborne.dboe.base.block.BlockMgrFileAccess ;
++import org.seaborne.dboe.base.file.BlockAccess ;
++import org.seaborne.dboe.base.file.BlockAccessDirect ;
++
++public class TestBlockMgrDirect extends AbstractTestBlockMgr
++{
++ static final String filename = ConfigTestDBOE.getTestingDir()+"/block-mgr" ;
++
++ @BeforeClass static public void remove1() { FileOps.delete(filename) ; }
++ @AfterClass static public void remove2() { FileOps.delete(filename) ; }
++
++ @Override
++ protected BlockMgr make()
++ {
++ // Make directly - no wrapper, no cache, no free block mgt.
++ FileOps.delete(filename) ;
++ BlockAccess file = new BlockAccessDirect(filename, BlkSize) ;
++ BlockMgr mgr = new BlockMgrFileAccess(file, BlkSize) ;
++ if ( BlockMgrFactory.AddTracker )
++ mgr = BlockMgrFactory.tracker(mgr) ;
++ return mgr ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/TestBlockMgrMapped.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/TestBlockMgrMapped.java
index 0000000,0000000..851e715
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/TestBlockMgrMapped.java
@@@ -1,0 -1,0 +1,63 @@@
++/*
++ * 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.dboe.base.block;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.apache.jena.atlas.logging.LogCtl ;
++import org.junit.After ;
++import org.junit.AfterClass ;
++import org.junit.BeforeClass ;
++import org.seaborne.dboe.ConfigTestDBOE ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.block.BlockMgrFileAccess ;
++import org.seaborne.dboe.base.file.BlockAccess ;
++import org.seaborne.dboe.base.file.BlockAccessMapped ;
++
++public class TestBlockMgrMapped extends AbstractTestBlockMgr
++{
++ static boolean logging = false ;
++
++ static { if ( logging ) LogCtl.setLog4j() ; }
++
++ static final String filename = ConfigTestDBOE.getTestingDir()+"/block-mgr" ;
++
++ // Windows is iffy about deleting memory mapped files.
++
++ @After public void after1() { clearBlockMgr() ; }
++
++ private void clearBlockMgr()
++ {
++ if ( blockMgr != null )
++ {
++ blockMgr.close() ;
++ FileOps.deleteSilent(filename) ;
++ blockMgr = null ;
++ }
++ }
++
++ @BeforeClass static public void remove1() { FileOps.deleteSilent(filename) ; }
++ @AfterClass static public void remove2() { FileOps.deleteSilent(filename) ; }
++
++ @Override
++ protected BlockMgr make()
++ {
++ clearBlockMgr() ;
++ BlockAccess file = new BlockAccessMapped(filename, BlkSize) ;
++ return new BlockMgrFileAccess(file, BlkSize) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/TestBlockMgrMem.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/TestBlockMgrMem.java
index 0000000,0000000..be1a953
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/TestBlockMgrMem.java
@@@ -1,0 -1,0 +1,30 @@@
++/*
++ * 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.dboe.base.block;
++
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.block.BlockMgrFactory ;
++
++
++public class TestBlockMgrMem extends AbstractTestBlockMgr
++{
++ @Override
++ protected BlockMgr make()
++ { return BlockMgrFactory.createMem("mem", BlkSize) ; }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/TestBlockMgrTracked.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/TestBlockMgrTracked.java
index 0000000,0000000..ba7e056
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/block/TestBlockMgrTracked.java
@@@ -1,0 -1,0 +1,141 @@@
++/*
++ * 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.dboe.base.block;
++
++import java.nio.ByteBuffer ;
++
++import org.junit.AfterClass ;
++import org.junit.Assert ;
++import org.junit.BeforeClass ;
++import org.junit.Test ;
++
++public class TestBlockMgrTracked extends Assert
++{
++ // Mainly testing the tracking
++
++ static boolean b ;
++
++ @BeforeClass
++ static public void beforeClass()
++ {
++ b = BlockMgrTracker.verbose ;
++ BlockMgrTracker.verbose = false ;
++ }
++
++ @AfterClass
++ static public void afterClass()
++ {
++ BlockMgrTracker.verbose = b ;
++ }
++
++ @Test public void track_01()
++ {
++ BlockMgr mgr = BlockMgrFactory.createMem("BPTRecord", 4) ;
++ mgr = BlockMgrFactory.tracker(mgr) ;
++ mgr.beginUpdate() ;
++ Block block = mgr.allocate(4) ;
++ ByteBuffer bb = block.getByteBuffer() ;
++ bb.putInt(0,1234) ;
++ mgr.write(block) ;
++ mgr.release(block) ;
++ // -----
++ Block block2 = mgr.getRead(block.getId()) ;
++ ByteBuffer bb2 = block2.getByteBuffer() ;
++ assertArrayEquals(bb.array(), bb2.array()) ;
++ mgr.release(block2) ;
++ mgr.endUpdate() ;
++ }
++
++ // Multiple overlapping read operations.
++ static BlockMgr setup()
++ {
++ BlockMgr mgr = BlockMgrFactory.createMem("BPTRecord", 4) ;
++ mgr = BlockMgrFactory.tracker(mgr) ;
++ return mgr ;
++ }
++
++ static void write(BlockMgr mgr, int value)
++ {
++ mgr.beginUpdate() ;
++ Block block = mgr.allocate(4) ;
++ ByteBuffer bb = block.getByteBuffer() ;
++ bb.putInt(0,value) ;
++ mgr.write(block) ;
++ mgr.release(block) ;
++ mgr.endUpdate() ;
++ }
++
++ @Test public void track_02()
++ {
++ BlockMgr mgr = setup() ;
++ write(mgr, 1234) ;
++ write(mgr, 5678) ;
++
++ mgr.beginRead() ;
++ mgr.beginRead() ;
++
++ Block b0 = mgr.getRead(0) ;
++ Block b1 = mgr.getRead(1) ;
++
++ mgr.release(b1) ;
++ mgr.release(b0) ;
++
++ mgr.endRead() ;
++ mgr.endRead() ;
++ }
++
++ @Test(expected=BlockException.class)
++ public void track_03()
++ {
++ BlockMgr mgr = setup() ;
++ write(mgr, 1234) ;
++ write(mgr, 5678) ;
++
++ mgr.beginRead() ;
++ Block b0 = mgr.getWrite(0) ;
++ mgr.endRead() ;
++ }
++
++ @Test(expected=BlockException.class)
++ public void track_04()
++ {
++ BlockMgr mgr = setup() ;
++ write(mgr, 1234) ;
++ mgr.beginRead() ;
++ Block b0 = mgr.getRead(0) ;
++ mgr.promote(b0) ;
++ mgr.endRead() ;
++ }
++
++ @Test(expected=BlockException.class)
++ public void track_05()
++ {
++ BlockMgr mgr = setup() ;
++ mgr.beginRead() ;
++ mgr.endUpdate() ;
++ }
++
++ @Test(expected=BlockException.class)
++ public void track_06()
++ {
++ BlockMgr mgr = setup() ;
++ mgr.beginUpdate() ;
++ mgr.endRead() ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/buffer/TS_Buffer.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/buffer/TS_Buffer.java
index 0000000,0000000..a294196
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/buffer/TS_Buffer.java
@@@ -1,0 -1,0 +1,31 @@@
++/*
++ * 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.dboe.base.buffer;
++
++import org.junit.runner.RunWith;
++import org.junit.runners.Suite;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestRecordBuffer.class
++ , TestPtrBuffer.class
++})
++
++
++public class TS_Buffer
++{}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/buffer/TestPtrBuffer.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/buffer/TestPtrBuffer.java
index 0000000,0000000..82b410f
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/buffer/TestPtrBuffer.java
@@@ -1,0 -1,0 +1,315 @@@
++/*
++ * 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.dboe.base.buffer;
++
++import java.nio.ByteBuffer ;
++
++import org.junit.AfterClass ;
++import org.junit.Assert ;
++import org.junit.BeforeClass ;
++import org.junit.Test ;
++import org.seaborne.dboe.sys.SystemIndex ;
++
++public class TestPtrBuffer extends Assert
++{
++ static boolean originalNullOut ;
++ @BeforeClass static public void beforeClass()
++ {
++ originalNullOut = SystemIndex.getNullOut() ;
++ SystemIndex.setNullOut(true) ;
++ }
++
++ @AfterClass static public void afterClass()
++ {
++ SystemIndex.setNullOut(originalNullOut) ;
++ }
++
++ // Testing the test framework!
++ @Test public void ptrbuffer01()
++ {
++ PtrBuffer pb = make(4) ;
++ contains(pb, 2, 4, 6, 8) ;
++ }
++
++ // No BinarySearch test
++
++ // Shift at LHS
++ @Test public void ptrbuffer03()
++ {
++ PtrBuffer pb = make(4,5) ;
++ contains(pb, 2, 4, 6, 8) ;
++
++ pb.shiftUp(0) ;
++ pb.set(0, 99) ;
++ contains(pb, 99, 2, 4, 6, 8) ;
++
++ pb.shiftDown(0) ;
++ contains(pb, 2, 4, 6, 8) ;
++ }
++
++ @Test public void ptrbuffer04()
++ {
++ PtrBuffer pb = make(4,5) ;
++ contains(pb, 2, 4, 6, 8) ;
++ pb.shiftDown(0) ;
++
++ contains(pb, 4, 6, 8) ;
++ pb.shiftUp(0) ;
++
++ pb.set(0,1) ;
++ contains(pb, 1, 4, 6, 8) ;
++ }
++
++
++ // Shift at middle
++ @Test public void ptrbuffer05()
++ {
++ PtrBuffer pb = make(4,5) ;
++ contains(pb, 2, 4, 6, 8) ;
++ pb.shiftUp(2) ;
++ pb.set(2, 0) ;
++ contains(pb, 2, 4, 0, 6, 8) ;
++ pb.shiftDown(2) ;
++ contains(pb, 2, 4, 6, 8) ;
++ }
++
++ @Test public void ptrbuffer06()
++ {
++ PtrBuffer pb = make(4,5) ;
++ contains(pb, 2, 4, 6, 8) ;
++ pb.shiftDown(2) ;
++ contains(pb, 2, 4, 8) ;
++ pb.shiftUp(2) ;
++ assertTrue(pb.isClear(2)) ;
++ contains(pb, 2, 4, -1, 8) ;
++ }
++
++ // Shift RHS - out of bounds
++ @Test public void ptrbuffer07()
++ {
++ PtrBuffer pb = make(4,5) ;
++ contains(pb, 2, 4, 6, 8) ;
++ pb.shiftUp(3) ;
++ pb.set(3, 1) ;
++ contains(pb, 2, 4, 6, 1, 8) ;
++ pb.shiftDown(3) ;
++ contains(pb, 2, 4, 6, 8) ;
++ }
++
++ @Test public void ptrbuffer08()
++ {
++ PtrBuffer pb = make(4,5) ;
++ contains(pb, 2, 4, 6, 8) ;
++ pb.shiftDown(3) ;
++ contains(pb, 2, 4, 6) ;
++ pb.shiftUp(2) ;
++ contains(pb, 2, 4, -1, 6) ;
++ }
++
++ // Errors - IllegalArgumentException
++ @Test(expected=BufferException.class)
++ public void ptrbuffer09()
++ {
++ PtrBuffer pb = make(4,5) ;
++ contains(pb, 2, 4, 6, 8) ;
++ pb.shiftDown(4) ;
++ }
++
++ @Test(expected=BufferException.class)
++ public void ptrbuffer10()
++ {
++ PtrBuffer pb = make(4,5) ;
++ contains(pb, 2, 4, 6, 8) ;
++ pb.shiftUp(4) ;
++ }
++
++ @Test(expected=BufferException.class)
++ public void ptrbuffer11()
++ {
++ PtrBuffer pb = make(5,5) ;
++ contains(pb, 2, 4, 6, 8, 10) ;
++ pb.add(12) ;
++ }
++
++ // Copy, duplicate, clear
++ @Test public void ptrbuffer12()
++ {
++ PtrBuffer pb = make(5,5) ;
++ contains(pb, 2, 4, 6, 8, 10) ;
++ PtrBuffer pb2 = pb.duplicate() ;
++ pb2.set(1, 99) ;
++ contains(pb, 2, 4, 6, 8, 10) ;
++ contains(pb2, 2, 99, 6, 8, 10) ;
++ }
++
++ @Test public void ptrbuffer13()
++ {
++ PtrBuffer pb = make(5,5) ;
++ contains(pb, 2, 4, 6, 8, 10) ;
++ pb.clear(1, 3) ;
++ contains(pb, 2, -1, -1, -1, 10) ;
++ }
++
++ @Test public void ptrbuffer14()
++ {
++ PtrBuffer pb = make(5,5) ;
++ contains(pb, 2, 4, 6, 8, 10) ;
++
++ PtrBuffer pb2 = make(5,5) ;
++ contains(pb2, 2, 4, 6, 8, 10) ;
++
++ pb.copy(0, pb2, 1, 4) ;
++ contains(pb2, 2, 2, 4, 6, 8) ;
++ }
++
++ // Remove tests
++
++ @Test public void ptrbuffer15()
++ {
++ PtrBuffer pb = make(5,5) ;
++ contains(pb, 2, 4, 6, 8, 10) ;
++ pb.removeTop() ;
++ contains(pb, 2, 4, 6, 8) ;
++ pb.remove(1) ;
++ contains(pb, 2, 6, 8) ;
++ pb.remove(2) ;
++ contains(pb, 2, 6) ;
++ pb.remove(0) ;
++ contains(pb, 6) ;
++ pb.remove(0) ;
++ contains(pb) ;
++ }
++
++ @Test public void ptrbuffer20()
++ {
++ PtrBuffer pb1 = make(5,5) ;
++ contains(pb1, 2, 4, 6, 8, 10) ;
++ PtrBuffer pb2 = make(0,5) ;
++ contains(pb2) ;
++
++ pb1.shiftRight(pb2) ;
++ contains(pb1, 2, 4, 6, 8) ;
++ contains(pb2, 10) ;
++ }
++
++ @Test public void ptrbuffer21()
++ {
++ PtrBuffer pb1 = make(3,5) ;
++ contains(pb1, 2, 4, 6) ;
++ PtrBuffer pb2 = make(0,5) ;
++ contains(pb2) ;
++
++ pb1.shiftRight(pb2) ;
++ contains(pb1, 2, 4) ;
++ contains(pb2, 6) ;
++ }
++
++ @Test public void ptrbuffer22()
++ {
++ PtrBuffer pb1 = make(3,5) ;
++ contains(pb1, 2, 4, 6) ;
++ PtrBuffer pb2 = make(2,5) ;
++ contains(pb2, 2, 4) ;
++
++ pb1.shiftRight(pb2) ;
++ contains(pb1, 2, 4) ;
++ contains(pb2, 6, 2, 4) ;
++ }
++
++ @Test public void ptrbuffer24()
++ {
++ PtrBuffer pb1 = make(0,5) ;
++ contains(pb1) ;
++ PtrBuffer pb2 = make(5,5) ;
++ contains(pb2, 2, 4, 6, 8, 10) ;
++
++ pb1.shiftLeft(pb2) ;
++ contains(pb1, 2) ;
++ contains(pb2, 4, 6, 8, 10) ;
++ }
++
++ @Test public void ptrbuffer25()
++ {
++ PtrBuffer pb1 = make(0,5) ;
++ contains(pb1) ;
++ PtrBuffer pb2 = make(3,5) ;
++ contains(pb2, 2, 4, 6) ;
++
++ pb1.shiftLeft(pb2) ;
++ contains(pb1, 2) ;
++ contains(pb2, 4, 6) ;
++ }
++
++ @Test public void ptrbuffer26()
++ {
++ PtrBuffer pb1 = make(2,5) ;
++ contains(pb1, 2, 4) ;
++ PtrBuffer pb2 = make(3,5) ;
++ contains(pb2, 2, 4, 6) ;
++
++ pb1.shiftLeft(pb2) ;
++ contains(pb1, 2, 4, 2) ;
++ contains(pb2, 4, 6) ;
++ }
++
++ @Test public void ptrbuffer27()
++ {
++ PtrBuffer pb1 = make(2,4) ;
++ PtrBuffer pb2 = make(2,4) ;
++ pb1.copyToTop(pb2) ;
++ contains(pb2, 2,4,2,4) ;
++ }
++
++ @Test public void ptrbuffer28()
++ {
++ PtrBuffer pb1 = make(0,5) ;
++ PtrBuffer pb2 = make(2,4) ;
++ pb1.copyToTop(pb2) ;
++ contains(pb2, 2,4) ;
++ }
++
++ @Test public void ptrbuffer29()
++ {
++ PtrBuffer pb1 = make(0,5) ;
++ PtrBuffer pb2 = make(2,4) ;
++ pb2.copyToTop(pb1) ;
++ contains(pb1, 2,4) ;
++ }
++
++ // ---- Support
++ private static void contains(PtrBuffer pb, int... vals)
++ {
++ assertEquals("Length mismatch: ", vals.length, pb.size()) ;
++ for ( int i = 0 ; i < vals.length ; i++ )
++ if ( vals[i] == -1 )
++ assertTrue(pb.isClear(i)) ;
++ else
++ assertEquals("Value mismatch: ", vals[i], pb.get(i)) ;
++ }
++
++ // Make : 2,4,6,8, ..
++ private static PtrBuffer make(int n) { return make(n,n) ; }
++ private static PtrBuffer make(int n, int len)
++ {
++ ByteBuffer bb = ByteBuffer.allocate(4*len) ;
++ PtrBuffer pb = new PtrBuffer(bb, 0) ;
++ for ( int i = 0 ; i < n ; i++ )
++ pb.add(2+2*i) ;
++ return pb ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/buffer/TestRecordBuffer.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/buffer/TestRecordBuffer.java
index 0000000,0000000..d4b9726
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/buffer/TestRecordBuffer.java
@@@ -1,0 -1,0 +1,345 @@@
++/*
++ * 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.dboe.base.buffer;
++
++import static org.seaborne.dboe.test.RecordLib.intToRecord ;
++import static org.seaborne.dboe.test.RecordLib.r ;
++
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.junit.Assert ;
++import org.junit.AfterClass ;
++import org.junit.BeforeClass ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.buffer.BufferException ;
++import org.seaborne.dboe.base.buffer.RecordBuffer ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.sys.SystemIndex ;
++import org.seaborne.dboe.test.RecordLib ;
++
++public class TestRecordBuffer extends Assert
++{
++ static RecordFactory recordFactory = new RecordFactory(RecordLib.TestRecordLength, 0) ;
++
++ static boolean originalNullOut ;
++ @BeforeClass static public void beforeClass()
++ {
++ originalNullOut = SystemIndex.getNullOut() ;
++ SystemIndex.setNullOut(true) ;
++ }
++
++ @AfterClass static public void afterClass()
++ {
++ SystemIndex.setNullOut(originalNullOut) ;
++ }
++
++ @Test public void recBuffer01()
++ {
++ RecordBuffer rb = make(4, 4) ;
++ contains(rb, 2, 4, 6, 8) ;
++ }
++
++ @Test public void recBuffer02()
++ {
++ RecordBuffer rb = make(4, 4) ;
++ int idx = -1 ;
++ idx = find(rb, 6) ;
++ assertEquals(2, idx) ;
++ idx = find(rb, 8) ;
++
++ assertEquals(3, idx) ;
++ idx = find(rb, 4) ;
++ assertEquals(1, idx) ;
++ idx = find(rb, 2) ;
++ assertEquals(0, idx) ;
++
++ idx = find(rb, 3) ;
++ assertEquals(-2, idx) ;
++ idx = find(rb, 0) ;
++ assertEquals(-1, idx) ;
++ idx = find(rb, 10) ;
++ assertEquals(-5, idx) ;
++ }
++
++ // Shift at LHS
++ @Test public void recBuffer03()
++ {
++ RecordBuffer rb = make(4,5) ;
++ contains(rb, 2, 4, 6, 8) ;
++ rb.shiftUp(0) ;
++ rb.set(0, r(0)) ;
++ contains(rb, 0, 2, 4, 6, 8) ;
++ rb.shiftDown(0) ;
++ contains(rb, 2, 4, 6, 8) ;
++ }
++
++ @Test public void recBuffer04()
++ {
++ RecordBuffer rb = make(4,5) ;
++ contains(rb, 2, 4, 6, 8) ;
++ rb.shiftDown(0) ;
++
++ contains(rb, 4, 6, 8) ;
++ rb.shiftUp(0) ;
++
++ rb.set(0,r(1)) ;
++ contains(rb, 1, 4, 6, 8) ;
++ }
++
++
++ // Shift at middle
++ @Test public void recBuffer05()
++ {
++ RecordBuffer rb = make(4,5) ;
++ contains(rb, 2, 4, 6, 8) ;
++ rb.shiftUp(2) ;
++ rb.set(2, r(0)) ;
++ contains(rb, 2, 4, 0, 6, 8) ;
++ rb.shiftDown(2) ;
++ contains(rb, 2, 4, 6, 8) ;
++ }
++
++ @Test public void recBuffer06()
++ {
++ RecordBuffer rb = make(4,5) ;
++ contains(rb, 2, 4, 6, 8) ;
++ rb.shiftDown(2) ;
++ contains(rb, 2, 4, 8) ;
++ rb.shiftUp(2) ;
++ contains(rb, 2, 4, -1, 8) ;
++ }
++
++ // Shift RHS - out of bounds
++ @Test public void recBuffer07()
++ {
++ RecordBuffer rb = make(4,5) ;
++ contains(rb, 2, 4, 6, 8) ;
++ rb.shiftUp(3) ;
++ rb.set(3, r(1)) ;
++ contains(rb, 2, 4, 6, 1, 8) ;
++ rb.shiftDown(3) ;
++ contains(rb, 2, 4, 6, 8) ;
++ }
++
++ @Test public void recBuffer08()
++ {
++ RecordBuffer rb = make(4,5) ;
++ contains(rb, 2, 4, 6, 8) ;
++ rb.shiftDown(3) ;
++ contains(rb, 2, 4, 6) ;
++ rb.shiftUp(2) ;
++ contains(rb, 2, 4, -1, 6) ;
++ }
++
++ // Errors
++
++ @Test(expected=BufferException.class)
++ public void recBuffer09()
++ {
++ RecordBuffer rb = make(4,5) ;
++ contains(rb, 2, 4, 6, 8) ;
++ rb.shiftDown(4) ;
++ }
++
++ @Test(expected=BufferException.class)
++ public void recBuffer10()
++ {
++ RecordBuffer rb = make(4,5) ;
++ contains(rb, 2, 4, 6, 8) ;
++ rb.shiftUp(4) ;
++ }
++
++ @Test(expected=BufferException.class)
++ public void recBuffer11()
++ {
++ RecordBuffer rb = make(5,5) ;
++ contains(rb, 2, 4, 6, 8, 10) ;
++ rb.add(r(12)) ;
++ }
++
++ // Copy, duplicate, clear
++ @Test public void recBuffer12()
++ {
++ RecordBuffer rb = make(5,5) ;
++ contains(rb, 2, 4, 6, 8, 10) ;
++ RecordBuffer rb2 = rb.duplicate() ;
++ rb2.set(1, r(99)) ;
++ contains(rb, 2, 4, 6, 8, 10) ;
++ contains(rb2, 2, 99, 6, 8, 10) ;
++ }
++
++ @Test public void recBuffer13()
++ {
++ RecordBuffer rb = make(5,5) ;
++ contains(rb, 2, 4, 6, 8, 10) ;
++ rb.clear(1, 3) ;
++ contains(rb, 2, -1, -1, -1, 10) ;
++ }
++
++ @Test public void recBuffer14()
++ {
++ RecordBuffer rb = make(5,5) ;
++ contains(rb, 2, 4, 6, 8, 10) ;
++ RecordBuffer rb2 = make(5,5) ;
++ contains(rb2, 2, 4, 6, 8, 10) ;
++ rb.copy(0, rb2, 1, 4) ;
++ contains(rb2, 2, 2, 4, 6, 8) ;
++ }
++
++ // Remove tests
++
++ @Test public void recBuffer15()
++ {
++ RecordBuffer rb = make(5,5) ;
++ contains(rb, 2, 4, 6, 8, 10) ;
++ rb.removeTop() ;
++ contains(rb, 2, 4, 6, 8) ;
++ rb.remove(1) ;
++ contains(rb, 2, 6, 8) ;
++ rb.remove(2) ;
++ contains(rb, 2, 6) ;
++ rb.remove(0) ;
++ contains(rb, 6) ;
++ rb.remove(0) ;
++ contains(rb) ;
++ }
++
++ @Test public void recBufferIterate01()
++ {
++ RecordBuffer rb = make(5,5) ;
++ same(rb.iterator(), 2,4,6,8,10) ;
++ }
++
++ @Test public void recBufferIterate02()
++ {
++ RecordBuffer rb = make(3,5) ;
++ Iterator<Record> iter = rb.iterator() ;
++ same(iter, 2, 4, 6) ;
++ }
++
++ @Test public void recBufferIterate03()
++ {
++ RecordBuffer rb = make(3,5) ;
++ Iterator<Record> iter = rb.iterator( intToRecord(4), null) ;
++ same(iter, 4, 6) ;
++ }
++
++ @Test public void recBufferIterate04()
++ {
++ RecordBuffer rb = make(3,5) ;
++ Iterator<Record> iter = rb.iterator( intToRecord(3), null) ;
++ same(iter, 4, 6) ;
++ }
++
++ @Test public void recBufferIterate05()
++ {
++ RecordBuffer rb = make(3,5) ;
++ Iterator<Record> iter = rb.iterator( intToRecord(1), null) ;
++ same(iter, 2, 4, 6) ;
++ }
++
++ @Test public void recBufferIterate06()
++ {
++ RecordBuffer rb = make(3,5) ;
++ Iterator<Record> iter = rb.iterator( null, intToRecord(1)) ;
++ same(iter) ;
++ }
++
++ @Test public void recBufferIterate07()
++ {
++ RecordBuffer rb = make(3,5) ;
++ Iterator<Record> iter = rb.iterator( null, intToRecord(2)) ;
++ same(iter ) ;
++ }
++
++ @Test public void recBufferIterate08()
++ {
++ RecordBuffer rb = make(3,5) ;
++ Iterator<Record> iter = rb.iterator( null, intToRecord(3)) ;
++ same(iter,2 ) ;
++ }
++
++ @Test public void recBufferIterate09()
++ {
++ RecordBuffer rb = make(5,5) ;
++ Iterator<Record> iter = rb.iterator( null, intToRecord(99)) ;
++ same(iter, 2, 4, 6, 8, 10) ;
++ }
++
++ @Test public void recBufferIterate10()
++ {
++ RecordBuffer rb = make(5,5) ;
++ Iterator<Record> iter = rb.iterator( intToRecord(4), intToRecord(8)) ;
++ same(iter, 4, 6 ) ;
++ }
++
++ @Test public void recBufferIterate11()
++ {
++ RecordBuffer rb = make(5,5) ;
++ Iterator<Record> iter = rb.iterator( intToRecord(3), intToRecord(9)) ;
++ same(iter, 4, 6, 8 ) ;
++ }
++
++ // ---- Support
++ private static void contains(RecordBuffer rb, int... vals)
++ {
++ assertEquals("Length mismatch: ", vals.length, rb.size()) ;
++
++ for ( int i = 0 ; i < vals.length ; i++ )
++ if ( vals[i] == -1 )
++ assertTrue(rb.isClear(i)) ;
++ else
++ {
++ Record r = RecordLib.intToRecord(vals[i]) ;
++ Record r2 = rb.get(i) ;
++ int x = RecordLib.recordToInt(r2) ;
++ assertEquals("Value mismatch: ", vals[i], x) ;
++ }
++ }
++
++ private static void same(Iterator<Record> iter, int... vals)
++ {
++ List<Integer> list = RecordLib.toIntList(iter) ;
++ assertEquals("Length mismatch: ", vals.length, list.size()) ;
++
++ for ( int i = 0 ; i < vals.length ; i++ )
++ {
++ int x = list.get(i) ;
++ assertEquals("Value mismatch: ", vals[i], x) ;
++ }
++ }
++
++
++ public int find(RecordBuffer rb, int v)
++ {
++ return rb.find(r(v)) ;
++ }
++
++ private static RecordBuffer make(int n, int len)
++ {
++ RecordBuffer rb = new RecordBuffer(recordFactory, len) ;
++ for ( int i = 0 ; i < n ; i++ )
++ {
++ Record r = RecordLib.intToRecord(2*i+2) ;
++ rb.add(r) ;
++ }
++ return rb ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/AbstractTestBinaryDataFile.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/AbstractTestBinaryDataFile.java
index 0000000,0000000..a40003c
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/AbstractTestBinaryDataFile.java
@@@ -1,0 -1,0 +1,83 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.apache.jena.atlas.lib.StrUtils ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.BinaryDataFile ;
++import static org.junit.Assert.* ;
++
++public abstract class AbstractTestBinaryDataFile {
++ private BinaryDataFile file ;
++ protected abstract BinaryDataFile createBinaryDataFile() ;
++
++ static final String stringData = "Hello world\n";
++ static final byte[] data = StrUtils.asUTF8bytes(stringData) ;
++
++ // Default action.
++ protected void releaseBinaryDataFile(BinaryDataFile file) {
++ file.close() ;
++ }
++
++ @Before public void before() {
++ file = createBinaryDataFile() ;
++ file.open();
++ file.truncate(0) ;
++ }
++
++ @After public void after() {
++ releaseBinaryDataFile(file) ;
++ }
++
++ @Test public void basic_open() {
++ assertTrue(file.isOpen()) ;
++ }
++
++ @Test public void basic_open_close() {
++ assertTrue(file.isOpen()) ;
++ file.close() ;
++ assertFalse(file.isOpen()) ;
++ }
++
++ @Test public void writeread_01() {
++ assertEquals(0, file.length()) ;
++ }
++
++ @Test public void writeread_02() {
++ assertEquals(0, file.length()) ;
++ file.write(data);
++ assertNotEquals(0, file.length()) ;
++ assertEquals(data.length, file.length()) ;
++ }
++
++ @Test public void writeread_03() {
++ long x = file.write(data);
++ byte[] data2 = new byte[data.length+100] ;
++ int x1 = file.read(x, data2) ;
++ assertEquals(data.length, x1) ;
++ int x2 = file.read(data.length, data2) ;
++ assertEquals(-1, x2) ;
++ }
++
++
++
++}
++
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/AbstractTestBlockAccessFixedSize.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/AbstractTestBlockAccessFixedSize.java
index 0000000,0000000..284ac5a
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/AbstractTestBlockAccessFixedSize.java
@@@ -1,0 -1,0 +1,101 @@@
++/*
++ * 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.dboe.base.file;
++
++import static org.seaborne.dboe.test.BufferTestLib.sameValue ;
++import org.junit.Assert ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.base.file.BlockAccess ;
++import org.seaborne.dboe.base.file.FileException ;
++
++public abstract class AbstractTestBlockAccessFixedSize extends Assert
++{
++ // Fixed block tests.
++
++ int blkSize ;
++
++ protected AbstractTestBlockAccessFixedSize(int blkSize)
++ {
++ this.blkSize = blkSize ;
++ }
++
++ protected abstract BlockAccess make() ;
++ protected static Block data(BlockAccess file, int len)
++ {
++ Block b = file.allocate(len) ;
++ for (int i = 0 ; i < len ; i++ )
++ b.getByteBuffer().put((byte)(i&0xFF)) ;
++ return b ;
++ }
++
++ private BlockAccess file ;
++ @Before public void before() { file = make() ; }
++ @After public void after() { file.close() ; }
++
++ @Test public void fileaccess_01()
++ {
++ assertTrue(file.isEmpty()) ;
++ }
++
++ @Test public void fileaccess_02()
++ {
++ Block b = data(file, blkSize) ;
++ file.write(b) ;
++ }
++
++ @Test public void fileaccess_03()
++ {
++ Block b1 = data(file, blkSize) ;
++ file.write(b1) ;
++ long x = b1.getId() ;
++ Block b9 = file.read(x) ;
++ assertNotSame(b1, b9) ;
++ assertTrue(sameValue(b1, b9)) ;
++ b9 = file.read(x) ;
++ assertNotSame(b1, b9) ;
++ assertTrue(sameValue(b1, b9)) ;
++ }
++
++ @Test public void fileaccess_04()
++ {
++ Block b1 = data(file, blkSize) ;
++ Block b2 = data(file, blkSize) ;
++ file.write(b1) ;
++ file.write(b2) ;
++
++ long x = b1.getId() ;
++ Block b8 = file.read(b1.getId()) ;
++ Block b9 = file.read(b1.getId()) ;
++ assertNotSame(b8, b9) ;
++ assertTrue(b8.getId() == b9.getId()) ;
++ }
++
++ @Test(expected=FileException.class)
++ public void fileaccess_05()
++ {
++ Block b1 = data(file, 10) ;
++ Block b2 = data(file, 20) ;
++ file.write(b1) ;
++
++ // Should not work. b2 not written.
++ Block b2a = file.read(b2.getId()) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/AbstractTestBlockAccessVarSize.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/AbstractTestBlockAccessVarSize.java
index 0000000,0000000..2fd3722
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/AbstractTestBlockAccessVarSize.java
@@@ -1,0 -1,0 +1,49 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.junit.Test ;
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.base.file.BlockAccess ;
++import static org.seaborne.dboe.test.BufferTestLib.* ;
++
++public abstract class AbstractTestBlockAccessVarSize extends AbstractTestBlockAccessFixedSize
++{
++ protected AbstractTestBlockAccessVarSize()
++ {
++ super(25) ;
++ }
++
++ @Test
++ public void fileaccess_50()
++ {
++ BlockAccess file = make() ;
++ Block b1 = data(file, 10) ;
++ Block b2 = data(file, 20) ;
++ file.write(b1) ;
++ file.write(b2) ;
++
++ Block b1a = file.read(b1.getId()) ;
++ Block b2a = file.read(b2.getId()) ;
++
++ assertNotSame(b1a, b1) ;
++ assertNotSame(b2a, b2) ;
++ sameValue(b1, b1a) ;
++ sameValue(b2, b2a) ;
++ }
++}
[38/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalComponentBase.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalComponentBase.java
index 0000000,0000000..18e091f
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalComponentBase.java
@@@ -1,0 -1,0 +1,76 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import java.nio.ByteBuffer ;
++
++import org.apache.jena.query.ReadWrite ;
++
++/**
++ * A transaction component that does nothing - can be used as a helper for
++ * management tasks hooked into the transaction component lifecycle but which
++ * are not stateful across restarts.
++ */
++public class TransactionalComponentBase<X> extends TransactionalComponentLifecycle<X> {
++
++ public TransactionalComponentBase(ComponentId id) {
++ super(id) ;
++ }
++
++ @Override
++ public void startRecovery() {}
++
++ @Override
++ public void recover(ByteBuffer ref) {}
++
++ @Override
++ public void finishRecovery() {}
++
++ @Override
++ public void cleanStart() {}
++
++ @Override
++ protected X _begin(ReadWrite readWrite, TxnId txnId) {
++ return null ;
++ }
++
++ @Override
++ protected ByteBuffer _commitPrepare(TxnId txnId, X state) {
++ return null ;
++ }
++
++ @Override
++ protected void _commit(TxnId txnId, X state) {}
++
++ @Override
++ protected void _commitEnd(TxnId txnId, X state) {}
++
++ @Override
++ protected void _abort(TxnId txnId, X state) {}
++
++ @Override
++ protected void _complete(TxnId txnId, X state) {}
++
++ @Override
++ protected void _shutdown() {}
++
++ @Override
++ protected X _promote(TxnId txnId, X state) { return null; }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalComponentLifecycle.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalComponentLifecycle.java
index 0000000,0000000..422753f
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalComponentLifecycle.java
@@@ -1,0 -1,0 +1,480 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import static org.seaborne.dboe.transaction.txn.TxnState.* ;
++
++import java.nio.ByteBuffer ;
++import java.util.Objects ;
++
++import org.apache.jena.query.ReadWrite ;
++
++import org.apache.jena.atlas.lib.InternalErrorException ;
++
++/**
++ * Base implementation of the component interface for {@link TransactionalComponent}.
++ */
++public abstract class TransactionalComponentLifecycle<X> implements TransactionalComponent {
++
++ // Pass down recovery operations.
++ // This class has no transaction-recorded state.
++ @Override public abstract void startRecovery();
++ @Override public abstract void recover(ByteBuffer ref);
++ @Override public abstract void finishRecovery();
++
++ // ---- Normal operation
++
++ private static final boolean CHECKING = false ;
++ private ThreadLocal<TxnState> trackTxn = CHECKING ? ThreadLocal.withInitial(() -> INACTIVE) : null ;
++
++ // Access to these two must be via the getter/setters below only.
++ // Allows stuff for thread switching.
++ private ThreadLocal<Transaction> threadTxn = new ThreadLocal<>() ;
++ private ThreadLocal<X> componentState = new ThreadLocal<>() ;
++ private final ComponentId componentId ;
++
++ protected TransactionalComponentLifecycle(ComponentId componentId) {
++ this.componentId = componentId ;
++ }
++
++ @Override
++ public ComponentId getComponentId() {
++ return componentId ;
++ }
++
++// // Very dangerous!
++// protected void setForThread(Transaction txn, X state) {
++// threadTxn.set(txn);
++// componentState.set(state);
++// }
++
++ /** Start a transaction */
++ @Override
++ final
++ public void begin(Transaction transaction) {
++ Objects.requireNonNull(transaction) ;
++ setTransaction(transaction);
++ checkState(INACTIVE, COMMITTED, ABORTED) ;
++ setTrackTxn(ACTIVE);
++ X x = _begin(transaction.getMode(), transaction.getTxnId()) ;
++ setDataState(x);
++ }
++
++ /** Promote a component in a transaction */
++ @Override
++ final
++ public boolean promote(Transaction transaction) {
++ Objects.requireNonNull(transaction) ;
++ checkState(ACTIVE) ;
++ X newState = _promote(transaction.getTxnId(), getDataState());
++ if ( newState == null )
++ return false;
++ setDataState(newState);
++ return true;
++ }
++
++ /** Commit a transaction (make durable): prepare - commit - cleanup */
++ @Override
++ final
++ public ByteBuffer commitPrepare(Transaction transaction) {
++ checkAligned(transaction) ;
++ checkState(ACTIVE) ;
++ try { return _commitPrepare(transaction.getTxnId(), getDataState()) ; }
++ finally { setTrackTxn(PREPARE) ; }
++ }
++
++ @Override
++ final
++ public void commit(Transaction transaction) {
++ checkAligned(transaction) ;
++ checkState(PREPARE) ;
++ _commit(transaction.getTxnId(), getDataState());
++ setTrackTxn(COMMIT) ;
++ }
++
++ @Override
++ final
++ public void commitEnd(Transaction transaction) {
++ checkAligned(transaction) ;
++ checkState(COMMIT) ;
++ _commitEnd(transaction.getTxnId(), getDataState());
++ setTrackTxn(COMMITTED) ;
++ internalComplete(transaction) ;
++ }
++
++ @Override
++ final
++ public void abort(Transaction transaction) {
++ checkAligned(transaction) ;
++ checkState(ACTIVE, PREPARE, COMMIT) ;
++ _abort(transaction.getTxnId(), getDataState()) ;
++ setTrackTxn(ABORTED) ;
++ internalComplete(transaction) ;
++ }
++
++ private void internalComplete(Transaction transaction) {
++ _complete(transaction.getTxnId(), getDataState());
++ setTrackTxn(INACTIVE) ;
++ releaseThreadState() ;
++ }
++
++ @Override
++ final
++ public void complete(Transaction transaction) {
++ if ( transaction.hasFinished() )
++ return ;
++ checkAligned(transaction) ;
++ ReadWrite m = getReadWriteMode() ;
++ switch(m) {
++ case READ:
++ checkState(ACTIVE, COMMITTED, ABORTED) ;
++ break ;
++ case WRITE:
++ // If bad, force abort?
++ checkState(COMMITTED, ABORTED) ;
++ break ;
++ }
++ _complete(transaction.getTxnId(), getDataState());
++ switch(m) {
++ case READ:
++ internalComplete(transaction);
++ break ;
++ case WRITE:
++ // complete happened in the commit or abort.
++ break ;
++ }
++ }
++
++ @Override
++ final
++ public void shutdown() {
++ _shutdown() ;
++ clearInternal() ;
++ }
++
++ @Override
++ final public SysTransState detach() {
++ TxnState txnState = getTxnState() ;
++ if ( txnState == null )
++ return null ;
++ checkState(ACTIVE) ;
++ setTrackTxn(DETACHED) ;
++ SysTransState transState = new SysTransState(this, getTransaction(), getDataState()) ;
++ //****** Thread locals
++ releaseThreadState() ;
++ return transState ;
++ }
++
++ @Override
++ public void attach(SysTransState state) {
++ @SuppressWarnings("unchecked")
++ X x = (X)state.getState() ;
++// // reset to not thread not in
++// if ( CHECKING )
++// trackTxn : ThreadLocal<TxnState>
++//
++//
++ setTransaction(state.getTransaction());
++ setDataState(x);
++ setTrackTxn(ACTIVE) ;
++ }
++
++ // -- Access object members.
++
++ public static class ComponentState<X> {
++ final TxnState state;
++ final Transaction txn ;
++ final X componentState ;
++ ComponentState(TxnState state, Transaction txn, X componentState) {
++ super() ;
++ this.state = state ;
++ this.txn = txn ;
++ this.componentState = componentState ;
++ }
++ }
++
++ public ComponentState<X> getComponentState() {
++ return new ComponentState<>(getTrackTxn(), getTransaction(), getDataState()) ;
++ }
++
++ public void setComponentState(ComponentState<X> state) {
++ setTrackTxn(state.state);
++ setTransaction(state.txn);
++ setDataState(state.componentState);
++
++ }
++
++ protected void releaseThreadState() {
++ // Remove thread locals
++ if ( trackTxn != null )
++ trackTxn.remove() ;
++ componentState.remove();
++
++// java version "1.8.0_31"
++// Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
++// Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)
++//
++// openjdk version "1.8.0_40-internal"
++// OpenJDK Runtime Environment (build 1.8.0_40-internal-b09)
++// OpenJDK 64-Bit Server VM (build 25.40-b13, mixed mode)
++
++ // This one is very important else the memory usage grows. Not clear why.
++ // A Transaction has an internal AtomicReference. Replacing the AtomicReference
++ // with a plain member variable slows the growth down greatly.
++ threadTxn.remove() ;
++ }
++
++ protected void clearInternal() {
++ trackTxn = null ;
++ threadTxn = null ;
++ componentState = null ;
++ }
++
++ //protected ComponentState<X> getState()
++
++ protected X getDataState() { return componentState.get() ; }
++ protected void setDataState(X data) { componentState.set(data) ; }
++
++ protected Transaction getTransaction() { return threadTxn.get(); }
++ protected void setTransaction(Transaction txn) { threadTxn.set(txn); }
++
++ private void setTrackTxn(TxnState newState) {
++ if ( ! CHECKING ) return ;
++ trackTxn.set(newState);
++ }
++
++ // This is our record of the state - it is not necessarily the transactions
++ // view during changes. This class tracks the expected incomign state and
++ // the transaction
++ private TxnState getTrackTxn() {
++ if ( ! CHECKING ) return null ;
++ return trackTxn.get();
++ }
++ // -- Access object members.
++
++ // XXX Align to javadoc in TransactionalComponent.
++
++ /* There are two lifecycles, one for write transaction, one
++ * for read transactions. This affects how transaction end so
++ * when/if promoted read->write transactions happen, a promoted
++ * transaction will follow the write lifecycle.
++ *
++ * In both lifecyles, the implementer can assume that calls
++ * happen at the right points and called only as needed. Framework
++ * takes care of checking.
++ *
++ * Read lifecycle:
++ * A read transaction be be just begin(READ)-end() but may also
++ * have commit or abort before end. The _commitRead and _abortRead
++ * calls note if an explicit commit or abort occurs but may not be
++ * called. _endRead is always called exactly once.
++ *
++ * _commitRead
++ * _abortRead
++ * _endRead
++ * _complete
++ *
++ * Write lifecycle:
++ * A write transaction must have a commit() or abort() before end().
++ * The fraemwork will check this.
++ *
++ * If the transaction commits:
++ * _commitPrepareWrite
++ * _commitWrite -- The transaction is
++ * _commitEndWrite
++ *
++ * If the transaction aborts:
++ * _abortWrite
++ *
++ * After any lifecycle, a final call of
++ * _complete()
++ *
++ * indicates ths transaction has fully finished.
++ *
++ * Typically, an implementation does not need to take action in every call.
++ */
++
++// /**
++// *
++// * @param readWrite
++// * @param txnId
++// * @return
++// */
++// protected abstract X _begin(ReadWrite readWrite, TxnId txnId) ;
++//
++// /**
++// *
++// * @param txnId
++// * @param state
++// * @return
++// */
++// protected abstract ByteBuffer _commitPrepareWrite(TxnId txnId, X state) ;
++//
++// /**
++// *
++// * @param txnId
++// * @param state
++// */
++// protected abstract void _commitWrite(TxnId txnId, X state) ;
++//
++// /**
++// *
++// * @param txnId
++// * @param state
++// */
++// protected abstract void _commitEndWrite(TxnId txnId, X state) ;
++//
++// /**
++// *
++// * @param txnId
++// * @param state
++// */
++// protected abstract void _abortWrite(TxnId txnId, X state) ;
++//
++// /**
++// *
++// * @param txnId
++// * @param state
++// * @return
++// */
++// protected abstract ByteBuffer _commitRead(TxnId txnId, X state) ;
++//
++// /**
++// *
++// * @param txnId
++// * @param state
++// * @return
++// */
++// protected abstract ByteBuffer _abortRead(TxnId txnId, X state) ;
++//
++// /**
++// *
++// * @param txnId
++// * @param state
++// */
++// protected abstract void _complete(TxnId txnId, X state) ;
++//
++// /**
++// *
++// */
++// protected abstract void _shutdown() ;
++
++ protected abstract X _begin(ReadWrite readWrite, TxnId txnId) ;
++ protected abstract X _promote(TxnId txnId, X oldState) ;
++ protected abstract ByteBuffer _commitPrepare(TxnId txnId, X state) ;
++ protected abstract void _commit(TxnId txnId, X state) ;
++ protected abstract void _commitEnd(TxnId txnId, X state) ;
++ protected abstract void _abort(TxnId txnId, X state) ;
++ protected abstract void _complete(TxnId txnId, X state) ;
++ protected abstract void _shutdown() ;
++
++ protected ReadWrite getReadWriteMode() {
++ Transaction txn = getTransaction() ;
++ return txn.getMode() ;
++ }
++
++ protected boolean isActiveTxn() {
++ TxnState txnState = getTxnState() ;
++ if ( txnState == null )
++ return false ;
++ switch(getTxnState()) {
++ case INACTIVE: case END_ABORTED: case END_COMMITTED:
++ return false ;
++ case ACTIVE: case DETACHED: case PREPARE: case ABORTED: case COMMIT: case COMMITTED:
++ return true ;
++ //null: default: return false ;
++ // Get the compiler to check all states covered.
++ }
++ // Should not happen.
++ throw new InternalErrorException("Unclear transaction state") ;
++ }
++
++ protected boolean isReadTxn() { return ! isWriteTxn() ; }
++
++ protected boolean isWriteTxn() {
++ Transaction txn = getTransaction();
++ return txn.isWriteTxn() ;
++ }
++
++ protected void checkTxn() {
++ if ( ! isActiveTxn() )
++ throw new TransactionException("Not in a transaction") ;
++ }
++
++// protected void requireWriteTxn() {
++// Transaction txn = getTransaction();
++// if ( txn == null )
++// throw new TransactionException("Not a transaction");
++// else
++// txn.requireWriteTxn() ;
++// }
++
++ protected void checkWriteTxn() {
++ Transaction txn = getTransaction();
++ if ( txn == null )
++ throw new TransactionException("Not a transaction");
++ else
++ txn.requireWriteTxn() ;
++ }
++
++ // -- Access object members.
++
++ private TxnState getTxnState() {
++ Transaction txn = getTransaction() ;
++ if ( txn == null )
++ return null ;
++ return txn.getState() ;
++ }
++
++ private void checkAligned(Transaction transaction) {
++ if ( ! CHECKING ) return ;
++ Transaction txn = getTransaction();
++ if ( txn != transaction )
++ throw new TransactionException("Transaction is not the transaction of the thread") ;
++ }
++
++ private void checkState(TxnState expected) {
++ if ( ! CHECKING ) return ;
++ TxnState s = getTrackTxn() ;
++ if ( s != expected )
++ throw new TransactionException("Transaction is in state "+s+": expected state "+expected) ;
++ }
++
++ private void checkState(TxnState expected1, TxnState expected2) {
++ if ( ! CHECKING ) return ;
++ TxnState s = getTrackTxn() ;
++ if ( s != expected1 && s != expected2 )
++ throw new TransactionException("Transaction is in state "+s+": expected state "+expected1+" or "+expected2) ;
++ }
++
++ // Avoid varargs ... undue worry?
++ private void checkState(TxnState expected1, TxnState expected2, TxnState expected3) {
++ if ( ! CHECKING ) return ;
++ TxnState s = getTrackTxn() ;
++ if ( s != expected1 && s != expected2 && s != expected3 )
++ throw new TransactionException("Transaction is in state "+s+": expected state "+expected1+", "+expected2+" or "+expected3) ;
++ }
++
++ // private void checkStateNot(State unexpected) {
++// State s = state.get();
++// if ( s == unexpected )
++// throw new TransactionException("Transaction in unexpected state "+s) ;
++// }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalComponentWrapper.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalComponentWrapper.java
index 0000000,0000000..7ee8a75
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalComponentWrapper.java
@@@ -1,0 -1,0 +1,107 @@@
++/*
++ * 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.dboe.transaction.txn ;
++
++import java.nio.ByteBuffer ;
++
++public class TransactionalComponentWrapper implements TransactionalComponent {
++ protected final TransactionalComponent other ;
++
++ public TransactionalComponentWrapper(TransactionalComponent other) {
++ this.other = other ;
++ }
++
++ @Override
++ public void startRecovery() {
++ other.startRecovery() ;
++ }
++
++ @Override
++ public void recover(ByteBuffer ref) {
++ other.recover(ref) ;
++ }
++
++ @Override
++ public void finishRecovery() {
++ other.finishRecovery() ;
++ }
++
++ @Override
++ public void cleanStart() {
++ other.cleanStart() ;
++ }
++
++ @Override
++ public ComponentId getComponentId() {
++ return other.getComponentId() ;
++ }
++
++ @Override
++ public void begin(Transaction transaction) {
++ other.begin(transaction) ;
++ }
++
++ @Override
++ public boolean promote(Transaction transaction) {
++ return other.promote(transaction) ;
++ }
++
++ @Override
++ public ByteBuffer commitPrepare(Transaction transaction) {
++ return other.commitPrepare(transaction) ;
++ }
++
++ @Override
++ public void commit(Transaction transaction) {
++ other.commit(transaction) ;
++ }
++
++ @Override
++ public void commitEnd(Transaction transaction) {
++ other.commitEnd(transaction) ;
++ }
++
++ @Override
++ public void abort(Transaction transaction) {
++ other.abort(transaction) ;
++ }
++
++ @Override
++ public void complete(Transaction transaction) {
++ other.complete(transaction) ;
++ }
++
++ @Override
++ public SysTransState detach() {
++ return other.detach() ;
++ }
++
++ @Override
++ public void attach(SysTransState systemState) {
++ other.attach(systemState) ;
++ }
++
++ @Override
++ public void shutdown() {
++ other.shutdown() ;
++ }
++
++ @Override
++ public String toString() { return "W:"+other.toString() ; }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalMRSW.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalMRSW.java
index 0000000,0000000..89ce3b2
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalMRSW.java
@@@ -1,0 -1,0 +1,136 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import java.nio.ByteBuffer ;
++import java.util.concurrent.locks.Lock ;
++import java.util.concurrent.locks.ReadWriteLock ;
++import java.util.concurrent.locks.ReentrantReadWriteLock ;
++
++import org.apache.jena.atlas.logging.Log ;
++
++import org.apache.jena.query.ReadWrite ;
++
++/** Implementation of the component interface for {@link TransactionalComponent}.
++ * Useful for in-memory transactions that do not provide durability or abort (undo).
++ * When retro fitting to other systems, that may be the best that can be done.
++ */
++public class TransactionalMRSW extends TransactionalComponentLifecycle<Object> {
++ // MRSW implementation of TransactionMVCC
++ // XXX Update to Jena style TransactionalLock
++ private ReadWriteLock lock = new ReentrantReadWriteLock() ;
++
++ public TransactionalMRSW(ComponentId componentId) {
++ super(componentId) ;
++ }
++
++ // ---- Recovery phase
++ @Override
++ public void startRecovery() {}
++
++ @Override
++ public void recover(ByteBuffer ref) {
++ Log.warn(this, "Called to recover a transaction (ignored)") ;
++ }
++
++ @Override
++ public void finishRecovery() { }
++
++ @Override
++ public void cleanStart() {}
++
++ private Lock getLock() {
++ return ( ReadWrite.WRITE.equals(getReadWriteMode()) ) ? lock.writeLock() : lock.readLock() ;
++ }
++
++ @Override
++ protected Object _begin(ReadWrite readWrite, TxnId thisTxnId) {
++ Lock lock = getLock() ;
++ // This is the point that makes this MRSW (readers OR writer), not MR+SW (readers and a writer)
++ lock.lock();
++ if ( isWriteTxn() )
++ startWriteTxn();
++ else
++ startReadTxn();
++ return createState();
++ }
++
++ private Object createState() {
++ return new Object();
++ }
++
++ @Override
++ protected Object _promote(TxnId txnId, Object state) {
++ // We have a read lock, the transaction coordinator has said
++ // it's OK (from it's point-of-view) to promote so this should succeed.
++ // We have a read lock - theer are no other writers.
++ boolean b = lock.writeLock().tryLock();
++ if ( ! b ) {
++ Log.warn(this, "Failed to promote");
++ return false;
++ }
++ lock.readLock().unlock();
++ return createState();
++ }
++
++ // Checks.
++
++ protected void startReadTxn() {}
++ protected void startWriteTxn() {}
++ protected void finishReadTxn() {}
++ protected void finishWriteTxn() {}
++
++ @Override
++ protected ByteBuffer _commitPrepare(TxnId txnId, Object obj) {
++ return null ;
++ }
++
++ @Override
++ protected void _commit(TxnId txnId, Object obj) {
++ clearup() ;
++ }
++
++ @Override
++ protected void _commitEnd(TxnId txnId, Object obj) {
++ clearup() ;
++ }
++
++ @Override
++ protected void _abort(TxnId txnId, Object obj) {
++ clearup() ;
++ }
++
++ @Override
++ protected void _complete(TxnId txnId, Object obj) {
++ }
++
++ @Override
++ protected void _shutdown() {
++ lock = null ;
++ }
++
++ private void clearup() {
++ Lock lock = getLock() ;
++ if ( isWriteTxn() )
++ finishWriteTxn();
++ else
++ finishReadTxn();
++ lock.unlock();
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalSystem.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalSystem.java
index 0000000,0000000..05d3a51
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TransactionalSystem.java
@@@ -1,0 -1,0 +1,82 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import org.apache.jena.query.ReadWrite ;
++import org.seaborne.dboe.transaction.Transactional ;
++
++/** Implementation side of a {@link Transactional}.
++ * {@link Transactional} presents the application facing view
++ * whereas this has all the possible steps of an implementation.
++ * Normally, the implementation of {@link #commit} is split up.
++ */
++public interface TransactionalSystem extends Transactional {
++
++ @Override
++ public default void commit() {
++ commitPrepare() ;
++ commitExec() ;
++ }
++
++ /** Do the 2-phase "prepare" step after which
++ * the transaction coordinator decides whether to commit
++ * or abort. A TransactionalSystem must be prepared for
++ * both possibilities.
++ */
++ public void commitPrepare();
++
++ /** Do the 2-phase "commit" step */
++ public void commitExec();
++
++ /** Suspend this transaction, detaching from the current thread.
++ * A new transaction on this thread can performed but the detached
++ * transaction still exists and if it is a write transaction
++ * it can still block other write transactions.
++ */
++ public TransactionCoordinatorState detach() ;
++
++ /**
++ * Attach a transaction to this thread.
++ * A transaction system implementation usually imposes a rule that
++ * only one thread can have a transaction attached at a time.
++ */
++ public void attach(TransactionCoordinatorState coordinatorState) ;
++
++ /** Get the associated {@link TransactionCoordinator} */
++ public TransactionCoordinator getTxnMgr() ;
++
++ /** Return the Read/Write state from the point of view of the caller.
++ * Return null when not in a transaction.
++ */
++ public ReadWrite getState() ;
++
++ @Override
++ public default boolean isInTransaction() { return getState() != null ; }
++
++ /** Return an information view of the transaction for this thread, if any.
++ * Returns null when there is no active transaction for this tread.
++ */
++ public TransactionInfo getTransactionInfo() ;
++
++ /** Return the transaction object for this thread.
++ * Low-level use only.
++ * To get information about the current transaction, call {@link #getTransactionInfo}.
++ */
++ public Transaction getThreadTransaction() ;
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnId.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnId.java
index 0000000,0000000..61eb649
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnId.java
@@@ -1,0 -1,0 +1,63 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++
++/**
++ * {@code TxnId} is a identfier for a transaction.
++ * A component in a transaction can use it as a unique key.
++ * The {@code TxnId}
++ * <ul>
++ * <li>must be unique across a JVM run
++ * <li>unique across JVm runs if used as a persistent name
++ * <li>Must provide value equality semantics (two {@code TxnId} are {@code .equals}
++ * if
++ * </ul>
++ * <p>
++ * It is preferrable that the TxnId is global unique over time and space.
++ */
++public interface TxnId {
++// public static TxnId create() { return TxnIdSimple.create() ; }
++//
++// public static TxnId create(byte[] bytes) {
++// switch(bytes.length) {
++// case 8: return TxnIdSimple.create(bytes) ;
++// case 16: return TxnIdUuid.create(bytes) ;
++// default:
++// throw new TransactionException("TxnId bytes unrecognized: length="+bytes.length) ;
++// }
++// }
++//
++ // Reminder to implement.
++ @Override
++ public int hashCode() ;
++ @Override
++ public boolean equals(Object other) ;
++
++ public String name() ;
++ public byte[] bytes() ;
++ /** A long that is a subset, or all or, the bytes.
++ * This should be unique for the lifetime of the transaction and
++ * ideally unique per system instance. It is not a persistent record
++ * of a transaction, it is for a transaction identifier in running code.
++ * ("system" maybe larger than on e JVM).
++ */
++ public long runtime() ;
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnIdFactory.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnIdFactory.java
index 0000000,0000000..1fece18
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnIdFactory.java
@@@ -1,0 -1,0 +1,60 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import org.apache.commons.lang3.NotImplementedException ;
++
++/** Factory for some forms of {@link TxnId}.
++ * This is ony some possible {@link TxnIdGenerator}
++ *
++ * @see TxnId
++ */
++public class TxnIdFactory {
++ /** Generator for {@link TxnId}s for the counter based implemention. */
++ public static final TxnIdGenerator txnIdGenSimple = ()->TxnIdSimple.create() ;
++ /** Generator for {@link TxnId}s for the UUID based implemention. */
++ public static final TxnIdGenerator txnIdGenUuid = ()->TxnIdUuid.create() ;
++
++ /** Return the default, good enough for one JVM
++ * (usually the simple counter based implemention)
++ */
++ public static TxnId create() {
++ return createSimple() ;
++ }
++
++ /** Return a TxnId from the counter based implemention. */
++ public static TxnId createSimple() {
++ return txnIdGenSimple.generate() ;
++ }
++
++ /** Return a TxnId from the UUID based implemention. */
++ public static TxnId createUuid() {
++ return txnIdGenUuid.generate() ;
++ }
++
++ public static TxnId create(byte[] bytes) {
++ switch(bytes.length) {
++ case 8 : return TxnIdSimple.create(bytes) ;
++ case 16 :return TxnIdUuid.create(bytes) ;
++ default:
++ throw new NotImplementedException("Unrcognized bytes length: "+bytes.length) ;
++ }
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnIdGenerator.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnIdGenerator.java
index 0000000,0000000..09c291f
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnIdGenerator.java
@@@ -1,0 -1,0 +1,38 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++
++/**
++ * Generator of {@link TxnId}s.
++ * {@code TxnId} is a identfier for a transaction.
++ * A component in a transaction can use it as a unique key.
++ * The {@code TxnId}
++ * <ul>
++ * <li>must be unique across a JVM run
++ * <li>unique across JVm runs if used as a persistent name
++ * <li>Must provide value equality semantics (two {@code TxnId} are {@code .equals}
++ * if
++ * </ul>
++ * <p>
++ * It is preferrable that the TxnId is global unique over time and space.
++ */
++public interface TxnIdGenerator {
++ public TxnId generate() ;
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnIdSimple.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnIdSimple.java
index 0000000,0000000..8a0a3b8
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnIdSimple.java
@@@ -1,0 -1,0 +1,83 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import java.util.concurrent.atomic.AtomicLong ;
++
++import org.apache.jena.atlas.lib.Bytes ;
++
++/**
++ * Simple TxnId, mainly for debugging.
++ */
++public class TxnIdSimple implements TxnId {
++ private static AtomicLong counter = new AtomicLong(0) ;
++
++ static TxnIdSimple create() {
++ return new TxnIdSimple(counter.incrementAndGet()) ;
++ }
++
++ public static TxnIdSimple create(byte[] bytes) {
++ return new TxnIdSimple(Bytes.getLong(bytes)) ;
++ }
++
++ private final long x ;
++
++ public TxnIdSimple(long x) {
++ this.x = x ;
++ }
++
++ @Override
++ public String name() {
++ return String.format("0x%04X",x) ;
++ }
++
++ @Override
++ public byte[] bytes() {
++ return Bytes.packLong(x) ;
++ }
++
++ @Override
++ public int hashCode() {
++ return Long.hashCode(x) ;
++ }
++
++ @Override
++ public boolean equals(Object obj) {
++ if ( this == obj )
++ return true ;
++ if ( obj == null )
++ return false ;
++ if ( getClass() != obj.getClass() )
++ return false ;
++ TxnIdSimple other = (TxnIdSimple)obj ;
++ if ( x != other.x )
++ return false ;
++ return true ;
++ }
++
++ @Override
++ public String toString() {
++ return "txn:"+x ;
++ }
++
++ @Override
++ public long runtime() {
++ return x ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnIdUuid.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnIdUuid.java
index 0000000,0000000..92ef964
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnIdUuid.java
@@@ -1,0 -1,0 +1,108 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++import java.util.UUID ;
++
++import org.apache.jena.atlas.lib.Bytes ;
++import org.seaborne.dboe.migrate.L ;
++
++import org.apache.jena.shared.uuid.JenaUUID ;
++
++/** {@link TxnId} based on a {@link UUID}.
++ */
++public class TxnIdUuid implements TxnId {
++
++ static TxnIdUuid create() {
++ UUID id = JenaUUID.generate().asUUID() ; // UUID.randomUUID() ;
++ return new TxnIdUuid(id) ;
++ }
++
++ public static TxnIdUuid create(byte[] bytes) {
++ long mostSignificantBits = Bytes.getLong(bytes, 0) ;
++ long leastSignificantBits = Bytes.getLong(bytes, 8) ;
++ return new TxnIdUuid(mostSignificantBits, leastSignificantBits) ;
++ }
++
++ private long mostSignificantBits ;
++ private long leastSignificantBits ;
++ private byte[] bytes = null ;
++ private String name = null ;
++
++ /*package*/ TxnIdUuid(UUID id) {
++ mostSignificantBits = id.getMostSignificantBits() ;
++ leastSignificantBits = id.getLeastSignificantBits() ;
++ }
++
++ /*package*/ TxnIdUuid(long mostSig, long leastSig) {
++ mostSignificantBits = mostSig ;
++ leastSignificantBits = leastSig ;
++ }
++
++ @Override
++ public String name() {
++ if ( name == null )
++ name = L.uuidToString(mostSignificantBits, leastSignificantBits) ;
++ return name ;
++ }
++
++ @Override
++ public byte[] bytes() {
++ if ( bytes == null )
++ bytes = L.uuidAsBytes(mostSignificantBits, leastSignificantBits) ;
++ return bytes ;
++ }
++
++ @Override
++ public long runtime() {
++ // In type 1, the mostSignificantBits have the timestamp in it.
++ return mostSignificantBits ;
++ }
++
++ @Override
++ public int hashCode() {
++ final int prime = 31 ;
++ int result = 1 ;
++ result = prime * result + (int)(leastSignificantBits ^ (leastSignificantBits >>> 32)) ;
++ result = prime * result + (int)(mostSignificantBits ^ (mostSignificantBits >>> 32)) ;
++ return result ;
++ }
++
++ @Override
++ public boolean equals(Object obj) {
++ if ( this == obj )
++ return true ;
++ if ( obj == null )
++ return false ;
++ if ( getClass() != obj.getClass() )
++ return false ;
++ TxnIdUuid other = (TxnIdUuid)obj ;
++ if ( leastSignificantBits != other.leastSignificantBits )
++ return false ;
++ if ( mostSignificantBits != other.mostSignificantBits )
++ return false ;
++ return true ;
++ }
++
++ @Override
++ public String toString() {
++ //return name() ;
++ return String.format("[%04X]", mostSignificantBits&0xFFFF) ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnState.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnState.java
index 0000000,0000000..dd33056
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/TxnState.java
@@@ -1,0 -1,0 +1,21 @@@
++/*
++ * 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.dboe.transaction.txn;
++
++/** The states of the transaction lifecycle */
++public enum TxnState { INACTIVE, ACTIVE, DETACHED, PREPARE, COMMIT, COMMITTED, ABORTED, END_COMMITTED, END_ABORTED }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/journal/Journal.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/journal/Journal.java
index 0000000,0000000..023b698
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/journal/Journal.java
@@@ -1,0 -1,0 +1,333 @@@
++/*
++ * 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.dboe.transaction.txn.journal;
++
++import static org.seaborne.dboe.sys.Sys.SizeOfInt ;
++
++import java.nio.ByteBuffer ;
++import java.util.Iterator ;
++import java.util.zip.Adler32 ;
++
++import org.apache.jena.atlas.iterator.IteratorSlotted ;
++import org.apache.jena.atlas.lib.ByteBufferLib ;
++import org.apache.jena.atlas.lib.Closeable ;
++import org.apache.jena.atlas.lib.FileOps ;
++import org.apache.jena.atlas.lib.Sync ;
++import org.seaborne.dboe.base.file.BufferChannel ;
++import org.seaborne.dboe.base.file.BufferChannelFile ;
++import org.seaborne.dboe.base.file.BufferChannelMem ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.sys.Names ;
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++import org.seaborne.dboe.transaction.txn.PrepareState ;
++import org.seaborne.dboe.transaction.txn.TransactionException ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/** A transaction journal.
++* The journal is append-only for writes, with truncation of the file
++* every so often. It is read during recovery.
++* The size of entries depends on per-component redo/undo records;
++* the control records like COMMIT are quite small.
++* Entries have a CRC to ensure that part-entries are not acted on.
++*/
++
++public final
++class Journal implements Sync, Closeable
++{
++ private static final boolean LOGGING = false ;
++ private static Logger log = LoggerFactory.getLogger(Journal.class) ;
++
++ private static boolean logging() {
++ return LOGGING && log.isInfoEnabled() ;
++ }
++
++ private static void log(String fmt, Object...args) {
++ if ( ! logging() )
++ return ;
++ log.info(String.format(fmt, args));
++ }
++
++ private BufferChannel channel ;
++ private long position ;
++
++ // Header: fixed, inc CRC
++ // length of data 4 bytes
++ // CRC of whole entry. 4 bytes
++ // entry type 4 bytes (1 byte and 3 alignment)
++ // component 16 bytes (fixed??)
++ // Data area : variable
++ // Bytes
++
++ private static final int posnLength = 0 ;
++ private static final int posnCRC = posnLength + SizeOfInt ;
++ private static final int posnEntry = posnCRC + SizeOfInt ;
++ private static final int posnComponent = posnEntry + SizeOfInt ;
++ // Start of the component data area.
++ private static final int posnData = posnComponent + ComponentId.SIZE ;
++
++ // Currently, the header is fixed size so this is the size.
++ private static int HeaderLen = posnData-posnLength ;
++
++ private ByteBuffer header = ByteBuffer.allocate(HeaderLen) ;
++
++ public static boolean exists(Location location) {
++ if ( location.isMem() )
++ return false ;
++ return FileOps.exists(journalFilename(location)) ;
++ }
++
++ public static Journal create(Location location) {
++ BufferChannel chan ;
++ String channelName = journalFilename(location) ;
++ if ( location.isMem() )
++ chan = BufferChannelMem.create(channelName) ;
++ else
++ chan = BufferChannelFile.create(channelName) ;
++ return create(chan) ;
++ }
++
++ public static Journal create(BufferChannel chan) {
++ return new Journal(chan) ;
++ }
++
++ private static String journalFilename(Location location) {
++ return location.absolute(Names.journalFile) ;
++ }
++
++ private Journal(BufferChannel channel) {
++ this.channel = channel ;
++ position = 0 ;
++ }
++
++ // synchronized : excessive?
++ // Given the calling context, we know it's thread safe.
++
++ synchronized public long writeJournal(JournalEntry entry) {
++ long posn = write(entry.getType(), entry.getComponentId(), entry.getByteBuffer()) ;
++
++ if ( entry.getPosition() < 0 ) {
++ entry.setPosition(posn) ;
++ entry.setEndPosition(position) ;
++ }
++ return posn ;
++ }
++
++// /** Write an entry and return its location in the journal */
++// synchronized public void write(List<PrepareState> prepareStates) {
++// prepareStates.forEach(this::write) ;
++// }
++
++ public long write(PrepareState prepareState) {
++ return write(JournalEntryType.REDO, prepareState.getComponent(), prepareState.getData()) ;
++ }
++
++ /** Write an entry and return it's location in the journal */
++ synchronized public long write(JournalEntryType type, ComponentId componentId, ByteBuffer buffer) {
++ // Check buffer set right.
++ if ( LOGGING ) {
++ log("write@%-3d >> %s %s %s", position, type.name(),
++ componentId == null ? "<null>" : componentId.label(),
++ buffer == null ? "<null>" : ByteBufferLib.details(buffer)) ;
++ }
++
++ long posn = position ;
++ int len = -1 ;
++ int bufferLimit = -1 ;
++ int bufferPosition = -1 ;
++ if ( buffer != null ) {
++ bufferLimit = buffer.limit() ;
++ bufferPosition = buffer.position() ;
++ buffer.rewind() ;
++ len = buffer.remaining() ;
++ }
++
++ // Header: (length/4, crc/4, entry/4, component/16)
++
++ header.clear() ;
++ header.putInt(len) ;
++ header.putInt(0) ; // Set CRC to zero
++ header.putInt(type.id) ;
++ header.put(componentId.getBytes()) ;
++ header.flip() ;
++ // Need to put CRC in before writing.
++
++ Adler32 adler = new Adler32() ;
++ adler.update(header.array()) ;
++
++ if ( len > 0 ) {
++ adler.update(buffer) ;
++ buffer.rewind() ;
++ }
++
++ int crc = (int)adler.getValue() ;
++ header.putInt(posnCRC, crc) ;
++ if ( LOGGING )
++ log("write@ -- crc = %s", Integer.toHexString(crc) ) ;
++ channel.write(header) ;
++ if ( len > 0 ) {
++ channel.write(buffer) ;
++ buffer.position(bufferPosition) ;
++ buffer.limit(bufferLimit) ;
++ }
++ position += HeaderLen + len ;
++ if ( LOGGING )
++ log("write@%-3d << %s", position, componentId.label()) ;
++
++ if ( len > 0 ) {
++ buffer.position(bufferPosition) ;
++ buffer.limit(bufferLimit) ;
++ }
++
++ return posn ;
++ }
++
++ synchronized public JournalEntry readJournal(long id) {
++ return _readJournal(id) ;
++ }
++
++ private JournalEntry _readJournal(long id) {
++ long x = channel.position() ;
++ if ( x != id )
++ channel.position(id) ;
++ JournalEntry entry = _read() ;
++ long x2 = channel.position() ;
++ entry.setPosition(id) ;
++ entry.setEndPosition(x2) ;
++ if ( x != id )
++ channel.position(x) ;
++ return entry ;
++ }
++
++ // read one entry at the channel position.
++ // Move position to end of read.
++ private JournalEntry _read() {
++ if ( LOGGING ) {
++ log("read@%-3d >>", channel.position()) ;
++ }
++
++ header.clear() ;
++ int lenRead = channel.read(header) ;
++ if ( lenRead == -1 ) {
++ // probably broken file.
++ throw new TransactionException("Read off the end of a journal file") ;
++ // return null ;
++ }
++ if ( lenRead != header.capacity() )
++ throw new TransactionException("Partial read of journal file") ;
++
++ header.rewind() ;
++ // Header: (length/4, crc/4, entry/4, component/16)
++ int len = header.getInt() ;
++ int checksum = header.getInt() ;
++ header.putInt(posnCRC, 0) ;
++ int entryType = header.getInt() ;
++ byte[] bytes = new byte[ComponentId.SIZE] ;
++ header.get(bytes) ;
++ ComponentId component = ComponentId.create(null, bytes) ;
++
++ Adler32 adler = new Adler32() ;
++ adler.update(header.array()) ;
++
++ ByteBuffer bb = null ;
++ if ( len > 0 ) {
++ bb = ByteBuffer.allocate(len) ;
++ lenRead = channel.read(bb) ;
++ if ( lenRead != len )
++ throw new TransactionException("Failed to read the journal entry data: wanted " + len + " bytes, got " + lenRead) ;
++ bb.rewind() ;
++ adler.update(bb) ;
++ bb.rewind() ;
++ }
++
++ int crc = (int)adler.getValue() ;
++ if ( checksum != crc )
++ throw new TransactionException("Checksum error reading from the Journal. "+Integer.toHexString(checksum)+" / "+Integer.toHexString(crc)) ;
++
++ JournalEntryType type = JournalEntryType.type(entryType) ;
++ JournalEntry entry = new JournalEntry(type, component, bb) ;
++ if ( LOGGING )
++ log("read@%-3d >> %s", channel.position(), entry) ;
++ return entry ;
++ }
++
++ /**
++ * Iterator of entries from current point in Journal, going forward. Must be
++ * JournalEntry aligned at start.
++ */
++ private class IteratorEntries extends IteratorSlotted<JournalEntry> {
++ JournalEntry slot = null ;
++ final long endPoint ;
++ long iterPosn ;
++
++ public IteratorEntries(long startPosition) {
++ iterPosn = startPosition ;
++ endPoint = channel.size() ;
++ }
++
++ @Override
++ protected JournalEntry moveToNext() {
++ // synchronized necessary? Outer policy is single thread?
++ synchronized (Journal.this) {
++ if ( iterPosn >= endPoint )
++ return null ;
++ JournalEntry e = _readJournal(iterPosn) ;
++ iterPosn = e.getEndPosition() ;
++ return e ;
++ }
++ }
++
++ @Override
++ protected boolean hasMore() {
++ return iterPosn < endPoint ;
++ }
++ }
++
++ public Iterator<JournalEntry> entries() {
++ return new IteratorEntries(0) ;
++ }
++
++ synchronized public Iterator<JournalEntry> entries(long startPosition) {
++ return new IteratorEntries(startPosition) ;
++ }
++
++ @Override
++ public void sync() { channel.sync() ; }
++
++ @Override
++ public void close() { channel.close() ; }
++
++ public long size() { return channel.size() ; }
++
++ public boolean isEmpty() { return channel.size() == 0 ; }
++
++ public void truncate(long size) { channel.truncate(size) ; }
++
++ public void reset() {
++ truncate(0) ;
++ sync() ;
++ }
++
++// public void append() { position(size()) ; }
++
++ public long position() { return channel.position() ; }
++
++// public void position(long posn) { channel.position(posn) ; }
++
++ public String getFilename() { return channel.getFilename() ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/journal/JournalControl.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/journal/JournalControl.java
index 0000000,0000000..9066e00
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/journal/JournalControl.java
@@@ -1,0 -1,0 +1,296 @@@
++/*
++ * 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.dboe.transaction.txn.journal;
++
++import java.util.Iterator ;
++
++import org.seaborne.dboe.base.file.BufferChannelFile ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++
++public class JournalControl
++{
++ private static Logger log = LoggerFactory.getLogger(JournalControl.class) ;
++
++ // In TransactionCoordinator
++// // Interface
++// public static void recovery(TransactionCoordinator txnCoord)
++// {
++// txnCoord.getJournal() ;
++//
++// }
++//
++// public static void replay(Transaction transaction)
++// {}
++
++ /** Dump a journal - debug support function - opens the journal specially - inconsistent views possible */
++ public static void print(String filename) {
++ BufferChannelFile chan = BufferChannelFile.createUnmanaged(filename, "r") ;
++ Journal journal = Journal.create(chan) ;
++ JournalControl.print(journal) ;
++ chan.close() ;
++ }
++
++ public static void print(Journal journal) {
++ System.out.println("Size: "+journal.size()) ;
++ Iterator<JournalEntry> iter = journal.entries() ;
++
++ for ( ; iter.hasNext() ; )
++ {
++ JournalEntry e = iter.next() ;
++ //System.out.println("Posn: "+journal.position()+" : ("+(journal.size()-journal.position())+")") ;
++ System.out.println(JournalEntry.format(e)) ;
++ }
++ }
++
++// /** Recover a base storage DatasetGraph */
++// public static void recovery(Location location)
++// {
++// if ( location.isMem() )
++// return ;
++//
++// // Do we need to recover?
++// Journal journal = findJournal(location) ;
++// if ( journal == null || journal.isEmpty() )
++// return ;
++//
++// for ( FileRef fileRef : dsg.getConfig().nodeTables.keySet() )
++// recoverNodeDat(dsg, fileRef) ;
++// recoverFromJournal(dsg.getConfig(), journal) ;
++//
++// journal.close() ;
++// // Recovery complete. Tidy up. Node journal files have already been handled.
++// if ( journal.getFilename() != null )
++// {
++// if ( FileOps.exists(journal.getFilename()) )
++// FileOps.delete(journal.getFilename()) ;
++// }
++// }
++//
++// private static Journal findJournal(Location location)
++// {
++// String journalFilename = location.absolute(Names.journalFile) ;
++// File f = new File(journalFilename) ;
++// //if ( FileOps.exists(journalFilename)
++//
++// if ( f.exists() && f.isFile() && f.length() > 0 )
++// return Journal.create(location) ;
++// else
++// return null ;
++// }
++//
++// /** Recovery from a journal.
++// * Find if there is a commit record; if so, replay the journal to that point.
++// * Try to see if there is another commit record ...
++// * Return true if a recovery was attempted; return false if we decided no work needed.
++// */
++// public static boolean recoverFromJournal(StorageConfig sConf, Journal jrnl)
++// {
++// if ( jrnl.isEmpty() )
++// return false ;
++//
++// long posn = 0 ;
++// for ( ;; )
++// {
++// // Any errors indicate a partially written journal.
++// // A commit was not written properly in the prepare phase.
++// // e.g. JVM died half-way though writing the prepare phase data.
++// // The valid journal ends at this point. Exit loop and clean up.
++//
++// long x ;
++// try { x = scanForCommit(jrnl, posn) ; }
++// catch (TDBException ex) { x = -1 ; }
++//
++// if ( x == -1 ) break ;
++// recoverSegment(jrnl, posn, x, sConf) ;
++// posn = x ;
++// }
++//
++// // We have replayed the journals - clean up.
++// jrnl.truncate(0) ;
++// jrnl.sync() ;
++// syncAll(sConf) ;
++// return true ;
++// }
++//
++// /** Scan to a commit entry, starting at a given position in the journal.
++// * Return address of entry after commit if found, else -1.
++// */
++// private static long scanForCommit(Journal jrnl, long startPosn)
++// {
++// Iterator<JournalEntry> iter = jrnl.entries(startPosn) ;
++// try {
++// for ( ; iter.hasNext() ; )
++// {
++// JournalEntry e = iter.next() ;
++// if ( e.getType() == JournalEntryType.Commit )
++// return e.getEndPosition() ;
++// }
++// return -1 ;
++// } finally { Iter.close(iter) ; }
++// }
++//
++// /** Recover one transaction from the start position given.
++// * Scan to see if theer is a commit; if found, play the
++// * journal from the start point to the commit.
++// * Return true is a commit was found.
++// * Leave journal positioned just after commit or at end if none found.
++// */
++// private static void recoverSegment(Journal jrnl, long startPosn, long endPosn, StorageConfig sConf)
++// {
++// Iterator<JournalEntry> iter = jrnl.entries(startPosn) ;
++// iter = jrnl.entries(startPosn) ;
++// try {
++// for ( ; iter.hasNext() ; )
++// {
++// JournalEntry e = iter.next() ;
++// if ( e.getType() == JournalEntryType.Commit )
++// {
++// if ( e.getEndPosition() != endPosn )
++// log.warn(format("Inconsistent: end at %d; expected %d", e.getEndPosition(), endPosn)) ;
++// return ;
++// }
++// replay(e, sConf) ;
++// }
++// } finally { Iter.close(iter) ; }
++// }
++//
++// /** Recover a node data file (".dat").
++// * Node data files are append-only so recovering, then not using the data is safe.
++// * Node data file is a precursor for full recovery that works from the master journal.
++// */
++// private static void recoverNodeDat(DatasetGraphTDB dsg, FileRef fileRef)
++// {
++// // See DatasetBuilderTxn - same name generation code.
++// // [TxTDB:TODO]
++//
++// RecordFactory recordFactory = new RecordFactory(SystemTDB.LenNodeHash, SystemTDB.SizeOfNodeId) ;
++// NodeTable baseNodeTable = dsg.getConfig().nodeTables.get(fileRef) ;
++// String objFilename = fileRef.getFilename()+"-"+Names.extJournal ;
++// objFilename = dsg.getLocation().absolute(objFilename) ;
++// File jrnlFile = new File(objFilename) ;
++// if ( jrnlFile.exists() && jrnlFile.length() > 0 )
++// {
++// syslog.info("Recovering node data: "+fileRef.getFilename()) ;
++// ObjectFile dataJrnl = FileFactory.createObjectFileDisk(objFilename) ;
++// NodeTableTrans ntt = new NodeTableTrans(null, objFilename, baseNodeTable, new IndexMap(recordFactory), dataJrnl) ;
++// ntt.append() ;
++// ntt.close() ;
++// dataJrnl.close() ;
++// baseNodeTable.sync() ;
++// }
++// if ( jrnlFile.exists() )
++// FileOps.delete(objFilename) ;
++// }
++//
++// public static void replay(Transaction transaction)
++// {
++// if ( syslog.isDebugEnabled())
++// syslog.debug("Replay "+transaction.getLabel()) ;
++// Journal journal = transaction.getJournal() ;
++// DatasetGraphTDB dsg = transaction.getBaseDataset() ;
++// // Currently, we (crudely) replay the whole journal.
++// replay(journal, dsg.getConfig()) ;
++// }
++//
++// /** Replay a journal onto a dataset */
++// public static void replay(Journal journal, DatasetGraphTDB dsg)
++// {
++// replay(journal, dsg.getConfig()) ;
++// }
++//
++// /** Replay a journal onto a store configuration (the file resources) */
++// private static void replay(Journal journal, StorageConfig sConf)
++// {
++// if ( journal.size() == 0 )
++// return ;
++//
++// journal.position(0) ;
++// try {
++// Iterator<JournalEntry> iter = journal.entries() ;
++//
++// for ( ; iter.hasNext() ; )
++// {
++// JournalEntry e = iter.next() ;
++// replay(e, sConf) ;
++//
++// // There is no point sync here.
++// // No writes via the DSG have been done.
++// // so all internal flags "syncNeeded" are false.
++// //dsg.sync() ;
++// }
++// }
++// catch (RuntimeException ex)
++// {
++// // Bad news travels fast.
++// syslog.error("Exception during journal replay", ex) ;
++// throw ex ;
++// }
++//
++// Collection<BlockMgr> x = sConf.blockMgrs.values() ;
++// for ( BlockMgr blkMgr : x )
++// blkMgr.syncForce() ;
++// // Must do a hard sync before this.
++// journal.truncate(0) ;
++// }
++//
++// /** return true for "go on" */
++// private static boolean replay(JournalEntry e, StorageConfig sConf)
++// {
++// switch (e.getType())
++// {
++// case Block:
++// {
++// BlockMgr blkMgr = sConf.blockMgrs.get(e.getFileRef()) ;
++// Block blk = e.getBlock() ;
++// log.debug("Replay: {} {}",e.getFileRef(), blk) ;
++// blk.setModified(true) ;
++// blkMgr.overwrite(blk) ;
++// return true ;
++// }
++// case Buffer:
++// {
++// BufferChannel chan = sConf.bufferChannels.get(e.getFileRef()) ;
++// ByteBuffer bb = e.getByteBuffer() ;
++// log.debug("Replay: {} {}",e.getFileRef(), bb) ;
++// chan.write(bb, 0) ; // YUK!
++// return true ;
++// }
++//
++// case Commit:
++// return false ;
++// case Abort:
++// case Object:
++// case Checkpoint:
++// errlog.warn("Unexpected block type: "+e.getType()) ;
++// }
++// return false ;
++// }
++//
++// private static void syncAll(StorageConfig sConf)
++// {
++// Collection<BlockMgr> x = sConf.blockMgrs.values() ;
++// for ( BlockMgr blkMgr : x )
++// blkMgr.syncForce() ;
++// Collection<BufferChannel> y = sConf.bufferChannels.values() ;
++// for ( BufferChannel bChan : y )
++// bChan.sync() ;
++// //sConf.nodeTables ;
++// }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/journal/JournalEntry.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/journal/JournalEntry.java
index 0000000,0000000..c6ac343
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/journal/JournalEntry.java
@@@ -1,0 -1,0 +1,89 @@@
++/*
++ * 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.dboe.transaction.txn.journal;
++
++import java.nio.ByteBuffer ;
++
++import org.apache.jena.atlas.lib.ByteBufferLib ;
++import org.apache.jena.atlas.lib.Bytes ;
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++import org.seaborne.dboe.transaction.txn.ComponentIds ;
++
++public class JournalEntry
++{
++// static public final JournalEntry Redo = new JournalEntry(JournalEntryType.REDO) ;
++// static public final JournalEntry Undo = new JournalEntry(JournalEntryType.UNDO) ;
++
++
++ // Zero payload JournalEntry - create once.
++ static public final JournalEntry COMMIT = new JournalEntry(JournalEntryType.COMMIT, ComponentIds.idSystem) ;
++ static public final JournalEntry ABORT = new JournalEntry(JournalEntryType.ABORT, ComponentIds.idSystem) ;
++
++ private long position = -1 ; // Location in the Journal (if known).
++ private long endPosition = -1 ; // End location in the Journal: offset of next entry start.
++
++ private final JournalEntryType type ;
++ private final ComponentId componentId ;
++ private final ByteBuffer data ;
++
++ private JournalEntry(JournalEntryType type, ComponentId id) {
++ this(type, id, null) ;
++ }
++
++ public JournalEntry(JournalEntryType type, ComponentId componentId, ByteBuffer bytes) {
++ this.type = type ;
++ this.componentId = componentId ;
++ this.data = bytes ;
++ }
++
++ void setPosition(long posn) { position = posn ; }
++ void setEndPosition(long endPosn) { endPosition = endPosn ; }
++
++ public long getPosition() { return position ; }
++ long getEndPosition() { return endPosition ; }
++
++ public JournalEntryType getType() { return type ; }
++ public ComponentId getComponentId() { return componentId ; }
++ public ByteBuffer getByteBuffer() { return data ; }
++
++ @Override
++ public String toString()
++ {
++ return "JournalEntry: "+type+" "+componentId ;
++ }
++
++ static public String format(JournalEntry entry)
++ {
++ StringBuilder sbuff = new StringBuilder() ;
++
++ sbuff.append("Entry: ") ;
++ sbuff.append(" "+entry.type) ;
++ if ( entry.componentId != null ) {
++ String label = entry.componentId.label() ;
++ if ( label != null )
++ sbuff.append(label) ;
++ sbuff.append(" [..") ;
++ int z = Bytes.getInt(entry.componentId.getBytes(), entry.componentId.getBytes().length-4) ;
++ sbuff.append(Integer.toHexString(z)) ;
++ sbuff.append("]") ;
++ }
++ if ( entry.data != null )
++ sbuff.append(" "+ByteBufferLib.details(entry.data)) ;
++ return sbuff.toString() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/journal/JournalEntryType.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/journal/JournalEntryType.java
index 0000000,0000000..48398b2
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/journal/JournalEntryType.java
@@@ -1,0 -1,0 +1,57 @@@
++/*
++ * 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.dboe.transaction.txn.journal;
++
++import org.apache.jena.atlas.lib.InternalErrorException ;
++import org.apache.jena.atlas.logging.Log ;
++
++/**
++ * Types of Journal entry.
++ * This set is quite general and so not all cases may be used in practice.
++ * <p>
++ * The id must be stable across new versions on the code as it ends up
++ * in the journal on-disk so we are explicit about id even though there is
++ * {@link Enum#ordinal}
++ */
++public enum JournalEntryType
++{
++ /*
++ * REDO, UNDO -- Actions (UNDO unused)
++ * COMMIT, ABORT -- Transaction action (ABORT unused)
++ * CHECKPOINT -- data written to the journal as a safe spill file (unused)
++ */
++ REDO(1), UNDO(2), COMMIT(3), ABORT(4)
++ /*, CHECKPOINT(6)*/
++ ;
++
++ final int id ;
++ JournalEntryType(int x) { id = x ; }
++ int getId() { return id ; }
++ static public JournalEntryType type(int x)
++ {
++ if ( x == REDO.id ) return REDO ;
++ else if ( x == UNDO.id ) return UNDO ;
++ else if ( x == COMMIT.id ) return COMMIT ;
++ else if ( x == ABORT.id ) return ABORT ;
++ //else if ( x == CHECKPOINT.id ) return CHECKPOINT ;
++ else {
++ Log.error(JournalEntryType.class, "Unknown type: "+x) ;
++ throw new InternalErrorException("Unknown type: "+x) ;
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/package-info.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/package-info.java
index 0000000,0000000..60f3bdb
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/main/java/org/seaborne/dboe/transaction/txn/package-info.java
@@@ -1,0 -1,0 +1,12 @@@
++/** Transactions.
++ * Key clases:
++ * <ul>
++ * <li>{@link org.seaborne.dboe.transaction.txn.Transaction Transaction}
++ * <li>{@link org.seaborne.dboe.transaction.txn.TransactionCoordinator TransactionCoordinator}
++ * <li>
++ * </ul>
++ *
++ */
++
++package org.seaborne.dboe.transaction.txn;
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/AbstractTestTxn.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/AbstractTestTxn.java
index 0000000,0000000..8454c7d
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/AbstractTestTxn.java
@@@ -1,0 -1,0 +1,63 @@@
++/*
++ * 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.dboe.transaction;
++
++import static org.junit.Assert.assertEquals ;
++
++import java.util.Arrays ;
++import java.util.List ;
++
++import org.junit.After ;
++import org.junit.Before ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.transaction.TransInteger ;
++import org.seaborne.dboe.transaction.TransMonitor ;
++import org.seaborne.dboe.transaction.Transactional ;
++import org.seaborne.dboe.transaction.txn.* ;
++import org.seaborne.dboe.transaction.txn.journal.Journal ;
++
++public abstract class AbstractTestTxn {
++ protected TransactionCoordinator txnMgr ;
++ protected TransInteger counter1 = new TransInteger(0) ;
++ protected TransInteger counter2 = new TransInteger(0) ;
++ protected TransMonitor monitor = new TransMonitor(ComponentId.allocLocal()) ;
++ protected Transactional unit ;
++
++ @Before public void setup() {
++ Journal jrnl = Journal.create(Location.mem()) ;
++ List<TransactionalComponent> cg = Arrays.asList
++ (counter1, new TransactionalComponentWrapper(counter2), monitor) ;
++ txnMgr = new TransactionCoordinator(jrnl, cg) ;
++ unit = new TransactionalBase(txnMgr) ;
++ txnMgr.start() ;
++ }
++
++ @After public void clearup() {
++ txnMgr.shutdown();
++ }
++
++ protected void checkClear() {
++ assertEquals(0, txnMgr.countActive()) ;
++ assertEquals(0, txnMgr.countBegin()-txnMgr.countFinished()) ;
++ assertEquals(0, txnMgr.countActiveReaders()) ;
++ assertEquals(0, txnMgr.countActiveWriter()) ;
++
++
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TS_Transactions.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TS_Transactions.java
index 0000000,0000000..d859939
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-transaction/src/test/java/org/seaborne/dboe/transaction/TS_Transactions.java
@@@ -1,0 -1,0 +1,43 @@@
++/*
++ * 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.dboe.transaction;
++
++import org.junit.runner.RunWith ;
++import org.junit.runners.Suite ;
++import org.junit.runners.Suite.SuiteClasses ;
++
++@RunWith(Suite.class)
++@SuiteClasses( {
++ TestTxnId.class
++ , TestJournal.class
++ , TestStateMgrData.class
++ , TestTransactionLifecycle.class
++ , TestTransactionLifecycle2.class
++ , TestTransactionCoordinator.class
++ , TestTransactionCoordinatorControl.class
++ , TestTxnLib.class
++ , TestTxnLib2.class
++ , TestThreadingTransactions.class
++ , TestTxnSwitching.class
++
++
++})
++public class TS_Transactions {
++
++}
++
[42/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeRecordsMgr.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeRecordsMgr.java
index 0000000,0000000..aae6b9f
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeRecordsMgr.java
@@@ -1,0 -1,0 +1,115 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.base.block.BlockType ;
++import org.seaborne.dboe.base.page.BlockConverter ;
++import org.seaborne.dboe.base.page.PageBlockMgr ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPage ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPageMgr ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPageMgr.Block2RecordBufferPage ;
++
++/** Bridge for making, getting and putting BPTreeRecords over a RecordBufferPageMgr */
++final public class BPTreeRecordsMgr extends PageBlockMgr<BPTreeRecords>
++{
++ // Only "public" for external very low level tools in development to access this class.
++ // Assume package access.
++
++ private final RecordBufferPageMgr rBuffPageMgr ;
++ private final BPlusTree bpTree ;
++
++ BPTreeRecordsMgr(BPlusTree bpTree, RecordFactory recordFactory, RecordBufferPageMgr rBuffPageMgr) {
++ super(null , rBuffPageMgr.getBlockMgr()) ;
++ this.bpTree = bpTree ;
++ super.setConverter(new Block2BPTreeRecords(this, recordFactory)) ;
++ // bpt is uninitialized at this point.
++ // so record rBuffPageMgr
++ this.rBuffPageMgr = rBuffPageMgr ;
++ }
++
++ /** Converter BPTreeRecords -- make a RecordBufferPage and wraps it.*/
++ static class Block2BPTreeRecords implements BlockConverter<BPTreeRecords> {
++ private Block2RecordBufferPage recordBufferConverter ;
++ private BPTreeRecordsMgr recordsMgr ;
++
++ Block2BPTreeRecords(BPTreeRecordsMgr mgr, RecordFactory recordFactory) {
++ this.recordsMgr = mgr ;
++ this.recordBufferConverter = new RecordBufferPageMgr.Block2RecordBufferPage(recordFactory) ;
++ }
++
++ @Override
++ public BPTreeRecords fromBlock(Block block) {
++ RecordBufferPage rbp = recordBufferConverter.fromBlock(block) ;
++ return new BPTreeRecords(recordsMgr, rbp) ;
++ }
++
++ @Override
++ public Block toBlock(BPTreeRecords t) {
++ return recordBufferConverter.toBlock(t.getRecordBufferPage()) ;
++ }
++
++ @Override
++ public BPTreeRecords createFromBlock(Block block, BlockType bType) {
++ RecordBufferPage rbp = recordBufferConverter.createFromBlock(block, bType) ;
++ return new BPTreeRecords(recordsMgr, rbp) ;
++ }
++ }
++
++ public BPTreeRecords create() {
++ return super.create(BlockType.RECORD_BLOCK) ;
++//
++// RecordBufferPage rbp = rBuffPageMgr.create() ;
++// BPTreeRecords bRec = new BPTreeRecords(bpTree, rbp) ;
++// return bRec ;
++ }
++
++ public RecordBufferPageMgr getRecordBufferPageMgr() { return rBuffPageMgr ; }
++ public BPlusTree getBPTree() { return bpTree ; }
++
++ boolean isWritable(int id) {
++ //System.err.println("BPTreeRecordsMgr.isWritable") ;
++ return false ;
++ }
++
++ @Override
++ public void startRead() {
++ rBuffPageMgr.startRead() ;
++ }
++
++ @Override
++ public void finishRead() {
++ rBuffPageMgr.finishRead() ;
++ }
++
++ @Override
++ public void startUpdate() {
++ rBuffPageMgr.startUpdate() ;
++ }
++
++ @Override
++ public void finishUpdate() {
++ rBuffPageMgr.finishUpdate() ;
++ }
++
++ @Override
++ public void close() {
++ rBuffPageMgr.close() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPlusTree.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPlusTree.java
index 0000000,0000000..395c651
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPlusTree.java
@@@ -1,0 -1,0 +1,544 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import java.nio.ByteBuffer ;
++import java.util.Iterator ;
++
++import org.apache.commons.lang3.NotImplementedException ;
++import org.apache.jena.atlas.io.IndentedWriter ;
++import org.apache.jena.atlas.iterator.Iter ;
++import org.apache.jena.atlas.lib.InternalErrorException ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.base.record.RecordMapper ;
++import org.seaborne.dboe.index.RangeIndex ;
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++import org.seaborne.dboe.transaction.txn.TransactionalComponentLifecycle ;
++import org.seaborne.dboe.transaction.txn.TxnId ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++import org.apache.jena.query.ReadWrite ;
++
++/**
++ *
++ * B-Tree taken from:
++ * <pre>
++ * Introduction to Algorithms, Second Edition
++ * Chapter 18: B-Trees
++ * by Thomas H. Cormen, Charles E. Leiserson,
++ * Ronald L. Rivest and Clifford Stein
++ * </pre>
++ * Includes implementation of removal
++ * then the B-Tree code converted to a B+Tree,
++ * then made MVCC/transactional.
++ * <p>
++ * Notes:
++ * <ul>
++ * <li>
++ * Stores "records", which are a key and value (the value may be absent).
++ * <li>
++ * In this B+Tree implementation, the (key,value) pairs are held in
++ * RecordBuffer, which wraps a ByteBuffer that only has records in it.
++ * BPTreeRecords provides the B+Tree view of a RecordBuffer. All records
++ * are in RecordBuffer - the "tree" part is an index for finding the right
++ * page. The tree only holds keys, copies from the (key, value) pairs in
++ * the RecordBuffers.
++ * <li>
++ * The version above splits nodes on the way down when full,
++ * not when needed where a split can bubble up from below.
++ * It means it only ever walks down the tree on insert.
++ * Similarly, the delete code ensures a node is suitable
++ * before decending.
++ * </ul>
++ */
++
++public class BPlusTree extends TransactionalComponentLifecycle<BptTxnState> implements RangeIndex
++{
++ /*
++ * Insertion:
++ * There are two styles for handling node splitting.
++ *
++ * Classically, when a leaf is split, the separating key is inserted into
++ * the parent, which may itself be full and so that is split, etc propagting
++ * up to the root (splitting the root is the only time the depth of the
++ * BTree increases). This involves walking back up the tree.
++ *
++ * It is more convenient to have a spare slot in a tree node, so that the
++ * new key can be inserted, then the keys and child pointers split.
++ *
++ * Modification: during insertion, splitting is applied to any full node
++ * traversed on the way down, resulting in any node passed through having
++ * some space for a new key. When splitting starts at a leaf, only the
++ * immediate parent is changed because it must have space for the new key.
++ * There is no cascade back to the top of the tree (it would have happened on
++ * the way down); in other words, splitting is done early. This is insertion
++ * in a single downward pass.
++ *
++ * When compared to the classic approach including the extra slot for
++ * convenient inserting, the space useage is approximately the same.
++ *
++ * Deletion:
++ * Deletion always occurs at a leaf; if it's an internal node, swap the key
++ * with the right-most left key (predecessor) or left-most right key (successor),
++ * and delete in the leaf.
++ *
++ * The classic way is to propagate node merging back up from the leaf. The
++ * book outlines a way that checks that a nod eis delte-suitable (min+1 in size)
++ * on the way down. This is implemented here; this is one-pass(ish).
++ *
++ * Variants:
++ * http://en.wikipedia.org/wiki/Btree
++ *
++ * B+Tree: Tree contains keys, and only the leaves have the values. Used for
++ * secondary indexes (external pointers) but also for general on-disk usage
++ * because more keys are packed into a level. Can chain the leaves for a
++ * sorted-order traversal.
++ *
++ * B*Tree: Nodes are always 2/3 full. When a node is full, keys are shared adjacent
++ * nodes and if all they are all full do 2 nodes get split into 3 nodes.
++ * Implementation wise, it is more complicated; can cause more I/O.
++ *
++ * B#Tree: A B+Tree where the operations try to swap nodes between immediate
++ * sibling nodes instead of immediately splitting (like delete, only on insert).
++ */
++
++ private static Logger log = LoggerFactory.getLogger(BPlusTree.class) ;
++
++ // Root id across transactions
++ // Changes as the tree evolves in write transactions.
++ private int rootIdx = -199 ;
++ private BPTStateMgr stateManager ;
++ private BPTreeNodeMgr nodeManager ;
++ private BPTreeRecordsMgr recordsMgr;
++ private final BPlusTreeParams bpTreeParams ;
++ private Mode mode = Mode.TRANSACTIONAL ;
++ private BptTxnState nonTxnState = null ;
++
++ // Construction is a two stage process
++ // 1/ Create the object, uninitialized
++ // (Setup data structures, without referring to any BPlusTree methods)
++ // 2/ initialize
++ /*package*/ BPlusTree(ComponentId componentId, BPlusTreeParams bpTreeParams) {
++ super(componentId) ;
++ this.rootIdx = -99 ;
++ this.bpTreeParams = bpTreeParams ;
++ this.nodeManager = null ;
++ this.recordsMgr = null ;
++ }
++
++ /*package*/ void init(BPTStateMgr stateManager, BPTreeNodeMgr nodeManager, BPTreeRecordsMgr recordsMgr) {
++ // Second part of creating.
++ // Some of these point to the BPlusTree object so we create te BPlusTree as
++ // absic structure then initialize fully here.
++ this.rootIdx = stateManager.getRoot() ;
++ this.stateManager = stateManager ;
++ this.nodeManager = nodeManager ;
++ this.recordsMgr = recordsMgr ;
++ }
++
++ private BPTreeNode getRootRead() {
++ if ( isTransactional() ) {
++ super.checkTxn() ;
++ int rootId = super.getDataState().getRoot() ;
++ return nodeManager.getRead(rootId, BPlusTreeParams.RootParent) ;
++ }
++ return nodeManager.getRead(rootIdx, BPlusTreeParams.RootParent) ;
++ }
++
++ private BPTreeNode getRootWrite() {
++ if ( isTransactional() ) {
++ super.checkWriteTxn() ;
++ int rootId = super.getDataState().getRoot() ;
++ return nodeManager.getRead(rootId, BPlusTreeParams.RootParent) ;
++ }
++ return nodeManager.getRead(rootIdx, BPlusTreeParams.RootParent) ;
++ }
++
++ private boolean isTransactional() {
++ return mode == Mode.TRANSACTIONAL || mode == Mode.TRANSACTIONAL_AUTOCOMMIT ;
++ }
++
++ private void releaseRootRead(BPTreeNode rootNode) {
++ rootNode.release() ;
++ }
++
++ private void releaseRootWrite(BPTreeNode rootNode) {
++ rootNode.release() ;
++ }
++
++ private void setRoot(BPTreeNode node) {
++ throw new InternalErrorException("BPlusTree.setRoot") ;
++ }
++
++ public void newRoot(BPTreeNode newRoot) {
++ if ( isTransactional() )
++ getDataState().setRoot(newRoot.getId()) ;
++ else
++ rootIdx = newRoot.getId() ;
++ }
++
++// // Very, very dangerous operation.
++// public void $testForce$(int rootIdx) {
++// this.rootIdx = rootIdx ;
++// }
++
++ public int getRootId() {
++ if ( super.isActiveTxn() )
++ return super.getDataState().getRoot() ;
++ else
++ return rootIdx ;
++ }
++
++ BptTxnState state() {
++ if ( mode == Mode.TRANSACTIONAL ) {
++ if ( super.isActiveTxn() )
++ return super.getDataState() ;
++ return null ;
++ }
++ return nonTxnState ;
++ }
++
++ /** Get the parameters describing this B+Tree */
++ public BPlusTreeParams getParams() { return bpTreeParams ; }
++
++ /** Only use for careful manipulation of structures */
++ public BPTStateMgr getStateManager() { return stateManager ; }
++
++ /** Only use for careful manipulation of structures */
++ public BPTreeNodeMgr getNodeManager() { return nodeManager ; }
++
++ /** Only use for careful manipulation of structures */
++ public BPTreeRecordsMgr getRecordsMgr() { return recordsMgr ; }
++
++ @Override
++ public RecordFactory getRecordFactory() {
++ return bpTreeParams.recordFactory ;
++ }
++
++ @Override
++ public Record find(Record record) {
++ startReadBlkMgr() ;
++ BPTreeNode root = getRootRead() ;
++ Record v = BPTreeNode.search(root, record) ;
++ releaseRootRead(root) ;
++ finishReadBlkMgr() ;
++ return v ;
++ }
++
++ @Override
++ public boolean contains(Record record) {
++ Record r = find(record) ;
++ return r != null ;
++ }
++
++ @Override
++ public Record minKey() {
++ startReadBlkMgr() ;
++ BPTreeNode root = getRootRead() ;
++ Record r = BPTreeNode.minRecord(root) ;
++ releaseRootRead(root) ;
++ finishReadBlkMgr() ;
++ return r ;
++ }
++
++ @Override
++ public Record maxKey() {
++ startReadBlkMgr() ;
++ BPTreeNode root = getRootRead() ;
++ Record r = BPTreeNode.maxRecord(root) ;
++ releaseRootRead(root) ;
++ finishReadBlkMgr() ;
++ return r ;
++ }
++
++ @Override
++ public boolean insert(Record record) {
++ return insertAndReturnOld(record) == null ;
++ }
++
++ /** Add a record into the B+Tree */
++ public Record insertAndReturnOld(Record record) {
++ startUpdateBlkMgr() ;
++ BPTreeNode root = getRootWrite() ;
++ Record r = BPTreeNode.insert(root, record) ;
++ releaseRootWrite(root) ;
++ finishUpdateBlkMgr() ;
++ return r ;
++ }
++
++ @Override
++ public boolean delete(Record record) {
++ return deleteAndReturnOld(record) != null ;
++ }
++
++ public Record deleteAndReturnOld(Record record) {
++ startUpdateBlkMgr() ;
++ BPTreeNode root = getRootWrite() ;
++ Record r = BPTreeNode.delete(root, record) ;
++ releaseRootWrite(root) ;
++ finishUpdateBlkMgr() ;
++ return r ;
++ }
++
++ private static Record noMin = null ;
++ private static Record noMax = null ;
++
++ @Override
++ public Iterator<Record> iterator() {
++ return iterator(noMin, noMax) ;
++ }
++
++ @Override
++ public Iterator<Record> iterator(Record fromRec, Record toRec) {
++ startReadBlkMgr() ;
++ BPTreeNode root = getRootRead() ;
++ releaseRootRead(root) ;
++ finishReadBlkMgr() ;
++ return BPTreeRangeIterator.create(root, fromRec, toRec) ;
++ //return iterator(fromRec, toRec, RecordFactory.mapperRecord) ;
++ }
++
++ @Override
++ public <X> Iterator<X> iterator(Record minRec, Record maxRec, RecordMapper<X> mapper) {
++ throw new NotImplementedException("Mapping iterator") ;
++ }
++
++ // Internal calls.
++ void startReadBlkMgr() {
++ nodeManager.startRead() ;
++ recordsMgr.startRead() ;
++ }
++
++ void finishReadBlkMgr() {
++ nodeManager.finishRead() ;
++ recordsMgr.finishRead() ;
++ }
++
++ private void startUpdateBlkMgr() {
++ nodeManager.startUpdate() ;
++ recordsMgr.startUpdate() ;
++ }
++
++ private void finishUpdateBlkMgr() {
++ nodeManager.finishUpdate() ;
++ recordsMgr.finishUpdate() ;
++ }
++
++ @Override
++ public boolean isEmpty() {
++ startReadBlkMgr() ;
++ BPTreeNode root = getRootRead() ;
++ boolean b = !root.hasAnyKeys() ;
++ releaseRootRead(root) ;
++ finishReadBlkMgr() ;
++ return b ;
++ }
++
++ private static int SLICE = 10000 ;
++ @Override
++ public void clear() {
++ Record[] records = new Record[SLICE] ;
++ while(true) {
++ Iterator<Record> iter = iterator() ;
++ int i = 0 ;
++ for ( i = 0 ; i < SLICE ; i++ ) {
++ if ( ! iter.hasNext() )
++ break ;
++ Record r = iter.next() ;
++ records[i] = r ;
++ }
++ if ( i == 0 )
++ break ;
++ for ( int j = 0 ; j < i ; j++ ) {
++ delete(records[j]) ;
++ records[j] = null ;
++ }
++ }
++ }
++
++ @Override
++ public void sync() {
++ if ( nodeManager.getBlockMgr() != null )
++ nodeManager.getBlockMgr().sync() ;
++ if ( recordsMgr.getBlockMgr() != null )
++ recordsMgr.getBlockMgr().sync() ;
++ }
++
++ @Override
++ public void close() {
++ nodeManager.close() ;
++ recordsMgr.close() ;
++ stateManager.close() ;
++ }
++
++// public void closeIterator(Iterator<Record> iter)
++// {
++// }
++
++ @Override
++ public long size() {
++ Iterator<Record> iter = iterator() ;
++ return Iter.count(iter) ;
++ }
++
++ @Override
++ public void check() {
++ BPTreeNode root = getRootRead() ;
++ try { root.checkNodeDeep() ; }
++ finally { releaseRootRead(root) ; }
++ }
++
++ public void dump() {
++ // Caution - nesting via startReadBlkMgr
++ startReadBlkMgr() ;
++ BPTreeNode root = getRootRead() ;
++ boolean b = BPT.Logging ;
++ BPT.Logging = false ;
++ try { root.dump() ; }
++ finally {
++ releaseRootRead(root) ;
++ BPT.Logging = b ;
++ }
++ finishReadBlkMgr() ;
++ }
++
++ public void dump(IndentedWriter out) {
++ BPTreeNode root = getRootRead() ;
++ try { root.dump(out) ; }
++ finally { releaseRootRead(root) ; }
++ }
++
++ public void nonTransactional() {
++ setMode(Mode.MUTABLE) ;
++ }
++
++ private void setMode(Mode newMode) {
++
++ mode = newMode ;
++
++ switch(mode) {
++ case IMMUTABLE :
++ nonTxnState = new BptTxnState(BPlusTreeParams.RootId,
++ nodeManager.allocLimit(),
++ recordsMgr.allocLimit()) ;
++ break ;
++ case IMMUTABLE_ALL:
++ nonTxnState = new BptTxnState(BPlusTreeParams.RootId,
++ Long.MAX_VALUE,
++ Long.MAX_VALUE) ;
++ break ;
++ case MUTABLE :
++ nonTxnState = new BptTxnState(BPlusTreeParams.RootId, 0, 0) ;
++ break ;
++ case MUTABLE_ROOT :
++ // Imperfect.
++ nonTxnState = new BptTxnState(BPlusTreeParams.RootId, 1, 1) ;
++ break ;
++ case TRANSACTIONAL :
++ nonTxnState= null ;
++ break ;
++ case TRANSACTIONAL_AUTOCOMMIT :
++ // TODO TRANSACTIONAL_AUTOCOMMIT
++ throw new NotImplementedException("TRANSACTIONAL_AUTOCOMMIT not implemented");
++ }
++ }
++
++ @Override
++ public void startRecovery() {}
++
++ @Override
++ public void recover(ByteBuffer ref) {
++ stateManager.setState(ref) ;
++ rootIdx = stateManager.getRoot() ;
++ nodeManager.resetAlloc(stateManager.getNodeBlocksLimit()) ;
++ recordsMgr.resetAlloc(stateManager.getRecordsBlocksLimit()) ;
++ }
++
++ @Override
++ public void finishRecovery() {
++ stateManager.sync();
++ }
++
++ @Override
++ public void cleanStart() { }
++
++ @Override
++ protected BptTxnState _begin(ReadWrite readWrite, TxnId txnId) {
++ return createState();
++ }
++
++ private BptTxnState createState() {
++ return new BptTxnState(rootIdx,
++ nodeManager.allocLimit(),
++ recordsMgr.allocLimit()) ;
++ }
++
++ /* The persistent transactional state of a B+Tree is new root and the
++ * allocation limits of both block managers.
++ */
++
++ @Override
++ protected BptTxnState _promote(TxnId txnId, BptTxnState oldState) {
++ BptTxnState newState = createState();
++ return newState;
++ }
++
++ @Override
++ protected ByteBuffer _commitPrepare(TxnId txnId, BptTxnState state) {
++ nodeManager.getBlockMgr().sync();
++ recordsMgr.getBlockMgr().sync();
++
++ long nodeLimit = nodeManager.allocLimit() ;
++ long recordsLimit = recordsMgr.allocLimit() ;
++ // But don't write it yet.
++ stateManager.setState(state.getRoot(), nodeLimit, recordsLimit);
++ return stateManager.getState() ;
++ }
++
++ @Override
++ protected void _commit(TxnId txnId, BptTxnState state) {
++ if ( isWriteTxn() ) {
++ rootIdx = state.getRoot() ;
++ stateManager.sync();
++ }
++ }
++
++ @Override
++ protected void _commitEnd(TxnId txnId, BptTxnState state) {
++ }
++
++ @Override
++ protected void _abort(TxnId txnId, BptTxnState state) {
++ rootIdx = state.initialroot ;
++ // Truncate - logically in block manager space.
++ nodeManager.resetAlloc(state.boundaryBlocksNode) ;
++ recordsMgr.resetAlloc(state.boundaryBlocksRecord) ;
++ stateManager.setState(state.initialroot, state.boundaryBlocksNode, state.boundaryBlocksRecord);
++ stateManager.sync();
++ }
++
++ @Override
++ protected void _complete(TxnId txnId, BptTxnState state) {
++
++ }
++
++ @Override
++ protected void _shutdown() {}
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPlusTreeFactory.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPlusTreeFactory.java
index 0000000,0000000..27e3e05
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPlusTreeFactory.java
@@@ -1,0 -1,0 +1,332 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import org.seaborne.dboe.DBOpEnvException ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.block.BlockMgrFactory ;
++import org.seaborne.dboe.base.block.BlockMgrLogger ;
++import org.seaborne.dboe.base.file.BufferChannel ;
++import org.seaborne.dboe.base.file.BufferChannelMem ;
++import org.seaborne.dboe.base.file.FileFactory ;
++import org.seaborne.dboe.base.file.FileSet ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPage ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPageMgr ;
++import org.seaborne.dboe.index.RangeIndex ;
++import org.seaborne.dboe.sys.Names ;
++import org.seaborne.dboe.sys.SystemIndex ;
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++
++/** Make BPlusTrees - this code works in close association with the BPlusTree constructor */
++public class BPlusTreeFactory {
++ private BPlusTreeFactory() {}
++
++ /** Create the java structures to correspond to
++ * the supplied block managers for the persistent storage.
++ * Initialize the persistent storage to the empty B+Tree if it does not exist.
++ * This is primitive operation that underpins creation of a sB+Tree.
++ */
++ public static BPlusTree create(ComponentId id, BPlusTreeParams params, BufferChannel chan, BlockMgr blkMgrNodes, BlockMgr blkMgrLeaves) {
++ if ( id == null )
++ id = ComponentId.allocLocal() ;
++ BPlusTree bpt = attach(id, params, false, chan, blkMgrNodes, blkMgrLeaves) ;
++ return bpt ;
++ }
++
++ /** Create the java structures to correspond to
++ * the supplied block managers for the persistent storage.
++ * Initialize the persistent storage to the empty B+Tree if it does not exist.
++ */
++ public static BPlusTree createNonTxn(BPlusTreeParams params, BufferChannel chan, BlockMgr blkMgrNodes, BlockMgr blkMgrLeaves) {
++ // Allocate a random ComponentId
++ BPlusTree bpt = create(null, params, chan, blkMgrNodes, blkMgrLeaves) ;
++ bpt.nonTransactional() ;
++ return bpt ;
++ }
++
++ /** Reset an existing B+Tree with different storage units.
++ * For each, null means "use same as original"
++ */
++ public static BPlusTree rebuild(BPlusTree bpt, BufferChannel chan, BlockMgr blkMgrNodes, BlockMgr blkMgrLeaves) {
++ if ( chan == null )
++ chan = bpt.getStateManager().getBufferChannel() ;
++ if ( blkMgrNodes == null )
++ blkMgrNodes = bpt.getNodeManager().getBlockMgr() ;
++ if ( blkMgrLeaves == null )
++ blkMgrLeaves = bpt.getNodeManager().getBlockMgr() ;
++ BPlusTree bpt2 = attach(bpt.getComponentId(), bpt.getParams(), true, chan, blkMgrNodes, blkMgrLeaves) ;
++ return bpt2 ;
++ }
++
++ public static RangeIndex makeBPlusTree(ComponentId cid, FileSet fs, int blkSize,
++ int readCacheSize, int writeCacheSize,
++ int dftKeyLength, int dftValueLength) {
++ RecordFactory recordFactory = makeRecordFactory(dftKeyLength, dftValueLength) ;
++ int order = BPlusTreeParams.calcOrder(blkSize, recordFactory.recordLength()) ;
++ RangeIndex rIndex = createBPTree(cid, fs, order, blkSize, readCacheSize, writeCacheSize, recordFactory) ;
++ return rIndex ;
++ }
++
++ public static RecordFactory makeRecordFactory(int keyLen, int valueLen) {
++ return new RecordFactory(keyLen, valueLen) ;
++ }
++
++ /** Create a B+Tree using defaults */
++ public static BPlusTree createBPTree(ComponentId cid, FileSet fileset, RecordFactory factory)
++ {
++ int readCacheSize = SystemIndex.BlockReadCacheSize ;
++ int writeCacheSize = SystemIndex.BlockWriteCacheSize ;
++ int blockSize = SystemIndex.BlockSize ;
++ if ( fileset.isMem() )
++ {
++ readCacheSize = 0 ;
++ writeCacheSize = 0 ;
++ blockSize = SystemIndex.BlockSizeTest ;
++ }
++
++ return createBPTreeByBlockSize(cid, fileset, blockSize, readCacheSize, writeCacheSize, factory) ;
++ }
++
++ /** Create a B+Tree by BlockSize */
++ public static BPlusTree createBPTreeByBlockSize(ComponentId cid, FileSet fileset,
++ int blockSize,
++ int readCacheSize, int writeCacheSize,
++ RecordFactory factory)
++ {
++ return createBPTree(cid, fileset, -1, blockSize, readCacheSize, writeCacheSize, factory) ;
++ }
++
++ /** Create a B+Tree by Order */
++ public static BPlusTree createBPTreeByOrder(ComponentId cid, FileSet fileset,
++ int order,
++ int readCacheSize, int writeCacheSize,
++ RecordFactory factory)
++ {
++ return createBPTree(cid, fileset, order, -1, readCacheSize, writeCacheSize, factory) ;
++ }
++
++ /** Create a B+Tree by Order */
++ public static BPlusTree createBPTreeByOrder(ComponentId cid, FileSet fileset,
++ int order,
++ RecordFactory factory)
++ {
++ return createBPTree(cid, fileset, order, -1, SystemIndex.BlockReadCacheSize, SystemIndex.BlockWriteCacheSize, factory) ;
++ }
++
++ /** Knowing all the parameters, create a B+Tree */
++ public static BPlusTree createBPTree(ComponentId cid, FileSet fileset, int order, int blockSize,
++ int readCacheSize, int writeCacheSize,
++ RecordFactory factory)
++ {
++ // ---- Checking
++ if (blockSize < 0 && order < 0) throw new IllegalArgumentException("Neither blocksize nor order specified") ;
++ if (blockSize >= 0 && order < 0) order = BPlusTreeParams.calcOrder(blockSize, factory.recordLength()) ;
++ if (blockSize >= 0 && order >= 0)
++ {
++ int order2 = BPlusTreeParams.calcOrder(blockSize, factory.recordLength()) ;
++ if (order != order2) throw new IllegalArgumentException("Wrong order (" + order + "), calculated = "
++ + order2) ;
++ }
++
++ // Iffy - does not allow for slop.
++ if (blockSize < 0 && order >= 0) {
++ // Only in-memory.
++ blockSize = BPlusTreeParams.calcBlockSize(order, factory) ;
++ }
++
++ BPlusTreeParams params = new BPlusTreeParams(order, factory) ;
++ BufferChannel bptState = FileFactory.createBufferChannel(fileset, Names.extBptState) ;
++ BlockMgr blkMgrNodes = BlockMgrFactory.create(fileset, Names.extBptTree, blockSize, readCacheSize, writeCacheSize) ;
++ BlockMgr blkMgrRecords = BlockMgrFactory.create(fileset, Names.extBptRecords, blockSize, readCacheSize, writeCacheSize) ;
++ return BPlusTreeFactory.create(cid, params, bptState, blkMgrNodes, blkMgrRecords) ;
++ }
++
++ /**
++ * Create the in-memory structures to correspond to the supplied block
++ * managers for the persistent storage. Does not initalize the B+Tree - it
++ * assumes the block managers correspond to an existing B+Tree.
++ */
++ private static BPlusTree attach(ComponentId cid, BPlusTreeParams params,
++ boolean isReset,
++ BufferChannel rootData, BlockMgr blkMgrNodes, BlockMgr blkMgrRecords) {
++ // Creating and initializing the BPlusTree object is a two stage process.
++
++ // * Create the Java object so it can be in other structures
++ // but it is not fully initialized yet.
++ // * Create datastructures being careful not to use the object
++ // * Ensure formatted
++ // * Initialize.
++
++ BPlusTree bpt = new BPlusTree(cid, params) ;
++ BPTStateMgr stateMgr = new BPTStateMgr(rootData) ;
++ blkMgrNodes.resetAlloc(stateMgr.getNodeBlocksLimit());
++ blkMgrRecords.resetAlloc(stateMgr.getRecordsBlocksLimit());
++
++ BPTreeNodeMgr nodeManager = new BPTreeNodeMgr(bpt, blkMgrNodes) ;
++
++ RecordBufferPageMgr recordPageMgr = new RecordBufferPageMgr(params.getRecordFactory(), blkMgrRecords) ;
++ BPTreeRecordsMgr recordsMgr = new BPTreeRecordsMgr(bpt, params.getRecordFactory(), recordPageMgr) ;
++
++ createIfAbsent(isReset, stateMgr, nodeManager, recordsMgr) ;
++
++ bpt.init(stateMgr, nodeManager, recordsMgr) ;
++ if ( BPT.CheckingNode ) {
++ nodeManager.startRead();
++ BPTreeNode root = nodeManager.getRead(bpt.getRootId(), BPlusTreeParams.RootParent) ;
++ root.checkNodeDeep() ;
++ nodeManager.release(root) ;
++ nodeManager.finishRead();
++ }
++ return bpt ;
++ }
++
++ /** (Testing mainly) Make an in-memory B+Tree, with copy-in, copy-out block managers */
++ public static BPlusTree makeMem(int order, int keyLength, int valueLength)
++ { return makeMem(null, order, keyLength, valueLength) ; }
++
++ /** (Testing mainly) Make an in-memory B+Tree, with copy-in, copy-out block managers */
++ public static BPlusTree makeMem(String name, int order, int keyLength, int valueLength)
++ { return makeMem(name, order, -1, keyLength, valueLength) ; }
++
++ /** (Testing mainly) Make an in-memory B+Tree, with copy-in, copy-out block managers */
++ public static BPlusTree makeMem(int order, int minDataRecords, int keyLength, int valueLength)
++ { return makeMem(null, order, minDataRecords, keyLength, valueLength) ; }
++
++ /** (Testing mainly) Make an in-memory B+Tree, with copy-in, copy-out block managers */
++ public static BPlusTree makeMem(String name, int order, int minDataRecords, int keyLength, int valueLength) {
++ if ( name == null )
++ name = "Mem" ;
++ BPlusTreeParams params = new BPlusTreeParams(order, keyLength, valueLength) ;
++
++ int blkSize ;
++ if ( minDataRecords > 0 ) {
++ int maxDataRecords = 2 * minDataRecords ;
++ // int rSize = RecordBufferPage.HEADER+(maxRecords*params.getRecordLength()) ;
++ blkSize = RecordBufferPage.calcBlockSize(params.getRecordFactory(), maxDataRecords) ;
++ } else
++ blkSize = params.getCalcBlockSize() ;
++
++ // By FileSet
++ BufferChannel chan = BufferChannelMem.create(name+"(root)") ;
++ BlockMgr mgr1 = BlockMgrFactory.createMem(name + "(nodes)", params.getCalcBlockSize()) ;
++ BlockMgr mgr2 = BlockMgrFactory.createMem(name + "(records)", blkSize) ;
++ ComponentId cid = ComponentId.allocLocal() ;
++ BPlusTree bpTree = BPlusTreeFactory.create(cid, params, chan, mgr1, mgr2) ;
++ return bpTree ;
++ }
++
++ /** Debugging */
++ public static BPlusTree addTracking(BPlusTree bpTree) {
++ BufferChannel mgrRoot = null ;
++ BlockMgr mgr1 = bpTree.getNodeManager().getBlockMgr() ;
++ BlockMgr mgr2 = bpTree.getRecordsMgr().getBlockMgr() ;
++ mgr1 = BlockTracker.track(mgr1) ;
++ mgr2 = BlockTracker.track(mgr2) ;
++ return BPlusTreeFactory.rebuild(bpTree, mgrRoot, mgr1, mgr2) ;
++ }
++
++ /** Debugging */
++ public static BPlusTree addLogging(BPlusTree bpTree) {
++ BufferChannel mgrRoot = null ;
++ BlockMgr mgr1 = bpTree.getNodeManager().getBlockMgr() ;
++ BlockMgr mgr2 = bpTree.getRecordsMgr().getBlockMgr() ;
++ mgr1 = new BlockMgrLogger(mgr1, false) ;
++ mgr2 = new BlockMgrLogger(mgr2, false) ;
++ return BPlusTreeFactory.rebuild(bpTree, mgrRoot, mgr1, mgr2) ;
++ }
++
++ /** Create if does not exist */
++ private static int createIfAbsent(boolean isReset, BPTStateMgr stateMgr, BPTreeNodeMgr nodeManager, BPTreeRecordsMgr recordsMgr) {
++
++ int rootId = stateMgr.getRoot() ;
++
++ if ( nodeManager.getBlockMgr().isEmpty() != recordsMgr.getBlockMgr().isEmpty() )
++ throw new BPTreeException(
++ "Node block manager empty = "+nodeManager.getBlockMgr().isEmpty()+
++ " // "+
++ "Records block manager empty = "+recordsMgr.getBlockMgr().isEmpty()) ;
++
++ if ( ! nodeManager.getBlockMgr().isEmpty() ) {
++ return rootId ;
++ }
++// else {
++// if ( isReset )
++// throw new BPTreeException("Reset on uninitialized B+Tree") ;
++// }
++
++ // Create/format
++
++ // Fresh BPlusTree root node.
++ int rootIdx = createEmptyBPT(stateMgr, nodeManager, recordsMgr) ;
++ if ( rootIdx != 0 )
++ throw new InternalError() ;
++
++ // Sync created blocks to disk - any caches are now clean.
++ stateMgr.sync();
++ nodeManager.getBlockMgr().sync() ;
++ recordsMgr.getBlockMgr().sync() ;
++ return rootIdx ;
++ }
++
++ /** Allocate root node space. The root is a Node with a Records block.
++ * @param stateMgr */
++ private static int createEmptyBPT(BPTStateMgr stateMgr, BPTreeNodeMgr nodeManager, BPTreeRecordsMgr recordsMgr) {
++ // Create an empty records block.
++
++ nodeManager.startUpdate();
++ recordsMgr.startUpdate();
++ // Empty tree.
++ stateMgr.setState(0, 0, 0);
++ try {
++ BPTreeRecords recordsPage = recordsMgr.create() ;
++ if ( recordsPage.getId() != BPlusTreeParams.RootId )
++ throw new DBOpEnvException("Root blocks must be at position zero (got "+recordsPage.getId()+")") ;
++ // Empty data block.
++ recordsMgr.write(recordsPage) ;
++ recordsMgr.release(recordsPage) ;
++
++ // Not this - we haven't full initialized and the BPTreeRecords has null BPTreeRecordsMgr
++ //recordsPage.write();
++ //recordsPage.release() ;
++
++ BPTreeNode n = nodeManager.createNode(BPlusTreeParams.RootParent) ;
++ // n.ptrs is currently invalid. count was 0 so thinks it has a pointer.
++ // Force to right layout.
++ n.ptrs.setSize(0) ; // No pointers
++ n.ptrs.add(recordsPage.getId()) ; // Add the page below
++
++ //n.ptrs.set(0, page.getId()) ; // This is the same as the size is one.
++
++ n.setIsLeaf(true) ;
++ n.setCount(0) ; // Count is count of records.
++ int rootId = n.getId() ;
++ nodeManager.write(n) ;
++ nodeManager.release(n) ;
++ // This makes the next blocks alocated 1 and 1 - just like a transaction.
++ // Blocks 0/0 are always an empty tree unless the bulk loader built the tree.
++ stateMgr.setState(0, 1, 1) ;
++ return rootId ;
++ } finally {
++ recordsMgr.finishUpdate();
++ nodeManager.finishUpdate();
++ }
++ // stateMgr.setState(0, 1, 1);
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPlusTreeParams.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPlusTreeParams.java
index 0000000,0000000..e94322c
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPlusTreeParams.java
@@@ -1,0 -1,0 +1,235 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import static org.seaborne.dboe.sys.SystemIndex.SizeOfPointer ;
++import org.apache.jena.atlas.logging.Log ;
++import org.seaborne.dboe.DBOpEnvException ;
++import org.seaborne.dboe.base.file.MetaFile ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.sys.Names ;
++
++/** Configuration for a B+Tree */
++final public class BPlusTreeParams
++{
++ // Metadata
++ //public static final String NS = BPlusTreeParams.class.getName() ;
++ public static final String NS = Names.keyNSBPlusTree ;
++ public static final String ParamOrder = NS+".order" ;
++ public static final String ParamKeyLength = NS+".keyLength" ;
++ public static final String ParamValueLength = NS+".valueLength" ;
++ public static final String ParamBlockSize = NS+".blockSize" ;
++
++ /* The gap is extra space in a node - some books have node size as 2*N
++ * (often for the classic insertion algorithm where it's easier to implement
++ * by inserting then splitting).
++ */
++ private static final int Gap = 0 ;
++
++ public static final int RootId = 0 ;
++ public static final int RootParent = -2 ;
++ public static final int NoParent = -99 ;
++ // Used when getting a block and we don't need/want/know the parent.
++ public static final int UnsetParent = -98 ;
++
++ // Per instance settings
++
++ /** Order of the BTree */
++ final int order ;
++
++ /** Record factory */
++ final RecordFactory recordFactory ;
++
++ /** Factory for key-only records */
++ final RecordFactory keyFactory ;
++
++ // ---- Derived constants.
++
++ /** Maximum number of keys per non-leaf block */
++ final int MaxRec ;
++
++ /** Maximum number of pointers per block per non-leaf block */
++ final int MaxPtr ;
++
++ /** Minimum number of keys per non-leaf block */
++ final int MinRec ;
++
++ /** Minimum number of pointers per block */
++ final int MinPtr ;
++
++ /** Index of the split point */
++ final int SplitIndex ;
++
++ /** High index of keys array */
++ final int HighRec ;
++
++ /** High index of pointers array */
++ final int HighPtr ;
++
++ /** Space in a block needed for extra information - the count
++ * The parent is not stored on-disk because a block is always created by fetching from it's parent.
++ */
++ static int BlockHeaderSize = 4 ;
++
++ @Override
++ public String toString() {
++ return String.format("Order=%d : Records [key=%d, value=%d] : records=[%d,%d] : pointers=[%d,%d] : split=%d",
++ order,
++ keyFactory.keyLength() ,
++ recordFactory.valueLength() ,
++ MinRec, MaxRec,
++ MinPtr, MaxPtr,
++ SplitIndex
++ ) ;
++ }
++
++ public static BPlusTreeParams readMeta(MetaFile mf) {
++ try {
++ int pOrder = mf.getPropertyAsInteger(ParamOrder) ;
++ int pKeyLen = mf.getPropertyAsInteger(ParamKeyLength) ;
++ int pRecLen = mf.getPropertyAsInteger(ParamValueLength) ;
++ return new BPlusTreeParams(pOrder, pKeyLen, pRecLen) ;
++ } catch (NumberFormatException ex)
++ {
++ Log.error(BPlusTreeParams.class, "Badly formed metadata for B+Tree") ;
++ throw new DBOpEnvException("Failed to read metadata") ;
++ }
++ }
++
++ public void addToMetaData(MetaFile mf) {
++ mf.setProperty(ParamOrder, order) ;
++ mf.setProperty(ParamKeyLength, recordFactory.keyLength()) ;
++ mf.setProperty(ParamValueLength, recordFactory.valueLength()) ;
++ mf.flush() ;
++ }
++
++ public BPlusTreeParams(int order, int keyLen, int valLen) {
++ this(order, new RecordFactory(keyLen, valLen)) ;
++ }
++
++ public BPlusTreeParams(int order, RecordFactory factory) {
++ // BTrees of order one aren't strictly BTrees
++ // Order 1 => Min size = 0 and max size = 2*N-1 = 1.
++ // If there is a gap, then the code may be defensive enough
++ // and something will work. The B+Trees may have empty nodes
++ // (i.e. no keys, single child).
++
++ if ( order < 2 )
++ throw new IllegalArgumentException("BPTree: illegal order (min 2): "+order);
++
++ this.order = order ;
++ recordFactory = factory ;
++ keyFactory = factory.keyFactory() ;
++
++ // Derived constants.
++ MaxRec = 2*order-1 + Gap ;
++ MaxPtr = 2*order + Gap ;
++ MinRec = order-1 ;
++ MinPtr = order ;
++
++ SplitIndex = order-1+Gap;
++
++ HighPtr = MaxPtr - 1 ;
++ HighRec = HighPtr-1 ;
++ }
++
++ public int getOrder() {
++ return order ;
++ }
++
++ public int getPtrLength() {
++ return SizeOfPointer ;
++ }
++
++ public int getRecordLength() {
++ return recordFactory.recordLength() ;
++ }
++
++ public RecordFactory getRecordFactory(){
++ return recordFactory ;
++ }
++
++ public int getKeyLength() {
++ return keyFactory.recordLength() ;
++ }
++
++ public RecordFactory getKeyFactory() {
++ return keyFactory ;
++ }
++
++ public int getCalcBlockSize() {
++ return calcBlockSize(order, recordFactory) ;
++ }
++
++ /**
++ * Return the best fit for the blocksize and the record length. Knows about
++ * block header space.
++ */
++ public static int calcOrder(int blockSize, RecordFactory factory) {
++ return calcOrder(blockSize, factory.recordLength()) ;
++ }
++
++ /**
++ * Return the best fit for the blocksize and the record length. Knows about
++ * block header space.
++ */
++ public static int calcOrder(int blockSize, int recordLength) {
++ // Length = X*recordLength+(X+1)*PtrLength
++ // => X = (Length-PtrLength)/(recordLength+PtrLength)
++ // BTree order N
++ // MaxRec = 2N-1+Gap = X
++ // N = (X+1-Gap)/2
++ blockSize -= BlockHeaderSize ;
++
++ int X = (blockSize-recordLength)/(recordLength+SizeOfPointer) ;
++ int order = (X+1-Gap)/2 ;
++ return order ;
++ }
++
++ /** return the size of a block */
++ public static int calcBlockSize(int bpTreeOrder, RecordFactory factory) {
++ BPlusTreeParams p = new BPlusTreeParams(bpTreeOrder, factory) ;
++ int x = p.getMaxRec() * factory.recordLength() + p.getMaxPtr() * SizeOfPointer ;
++ x += BlockHeaderSize ;
++ return x ;
++ }
++
++ public int getMaxRec() {
++ return MaxRec ;
++ }
++
++ public int getMaxPtr() {
++ return MaxPtr ;
++ }
++
++ public int getMinRec() {
++ return MinRec ;
++ }
++
++ public int getMinPtr() {
++ return MinPtr ;
++ }
++
++// /** return the size of a block */
++// public static int calcBlockSize(int bTreeOrder, int recordLength) {
++// BTreeParams p = new BTreeParams(bTreeOrder, recordLength, 0) ;
++// int x = p.getMaxRec()*recordLength + p.getMaxPtr()*PtrLength ;
++// x += BlockHeaderSize ;
++// return x ;
++// }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPlusTreeTools.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPlusTreeTools.java
index 0000000,0000000..f3998ef
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPlusTreeTools.java
@@@ -1,0 -1,0 +1,148 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import java.io.IOException ;
++import java.io.RandomAccessFile ;
++import java.nio.ByteBuffer ;
++import java.nio.channels.FileChannel ;
++
++import org.apache.jena.atlas.lib.ByteBufferLib ;
++import org.seaborne.dboe.base.buffer.RecordBuffer ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPage ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPageMgr ;
++
++/** Tools for working with B+Trees and datastructures associated with them, rather directly */
++class BPlusTreeTools {
++ /*public*/private static void binDump(String filename)
++ {
++ try(RandomAccessFile fh = new RandomAccessFile(filename, "r")) {
++ ByteBuffer bb = ByteBuffer.allocate(8*1024) ;
++ FileChannel ch = fh.getChannel() ;
++ int idx = 0 ;
++ while(true)
++ {
++ int x = ch.read(bb) ;
++ if ( x < 0 )
++ break ;
++ ByteBufferLib.print(bb) ;
++ bb.clear() ;
++ }
++ } catch (IOException ex)
++ {
++ ex.printStackTrace();
++ }
++ }
++
++// /** Scan/dump a file of RecordBuffers */
++// /*public*/private static void bpt_scan_record_buffer(String filename, boolean verbose)
++// {
++// BlockMgr blkMgr = BlockMgrFactory.createStdFileNoCache(filename, SystemIndex.BlockSize) ;
++// bpt_scan_record_buffer(blkMgr, verbose) ;
++// blkMgr.close();
++// }
++//
++// /*public*/private static void bpt_scan_record_buffer(BPlusTree bpt, boolean verbose)
++// {
++// bpt_scan_record_buffer(bpt.getRecordsMgr().getBlockMgr(), verbose) ;
++// }
++//
++// /*public*/private static void bpt_scan_record_buffer(BlockMgr blkMgr, boolean verbose)
++// {
++// RecordFactory f = SystemIndex.indexRecordTripleFactory ;
++// RecordBufferPageMgr recordPageMgr = new RecordBufferPageMgr(f, blkMgr) ;
++// bpt_scan_record_buffer(recordPageMgr,verbose) ;
++// }
++
++
++ /*public*/private static void bpt_scan_record_buffer(RecordBufferPageMgr recordPageMgr, boolean verbose)
++ {
++ System.out.print("[Scan Records] start\n") ;
++ int idx = 0 ;
++ int n = 0 ;
++ int total = 0 ;
++ if ( verbose ) System.out.printf("recordPageMgr = %s\n", recordPageMgr) ;
++
++ // Blocks in scan order
++ try {
++ while ( idx >= 0 )
++ {
++ if ( verbose ) System.out.printf("idx = %d\n", idx) ;
++ RecordBufferPage page = recordPageMgr.getRead(idx) ;
++ if ( verbose ) System.out.printf("%04d :: id=%04d -> link=%04d [count=%d, max=%d]\n", n, page.getId(), page.getLink(), page.getCount(), page.getMaxSize()) ;
++ RecordBuffer rb = page.getRecordBuffer() ;
++ if ( verbose ) System.out.printf(" :: %d %d\n", rb.getSize(), rb.maxSize() ) ;
++ total += rb.size();
++ idx = page.getLink() ;
++ n++ ;
++ recordPageMgr.release(page) ;
++ }
++ } catch (Exception ex)
++ {
++ System.out.println("Exception: "+ex) ;
++ }
++
++ System.out.printf("[Scan Records] Count = %d in %d blocks (avg: %.2f)\n", total, n, ((float)total)/n) ;
++ }
++
++// /*public*/private static void bpt_scan_nodes(String filename, boolean verbose)
++// {
++// RecordFactory f = FactoryGraphTDB.indexRecordTripleFactory ;
++// BPlusTree.
++// BlockMgr blkMgr = BlockMgrFactory.createStdFileNoCache(filename, SystemIndex.BlockSize) ;
++// bpt_scan_nodes(bpt, blkMgr, verbose) ;
++// blkMgr.close();
++// }
++
++ /*public*/private static void bpt_scan_nodes(BPlusTree bpt, boolean verbose)
++ {
++ System.out.print("[Scan Nodes] start\n") ;
++ BPTreeNodeMgr nodeMgr = new BPTreeNodeMgr(bpt, bpt.getNodeManager().getBlockMgr()) ;
++
++ int idx = 0 ;
++ int n = 0 ;
++ int total = 0 ;
++ if ( verbose ) System.out.printf("BPTreeNodeMgr = %s\n", nodeMgr) ;
++
++ // Blocks in file order
++ try {
++ while ( idx >= 0 )
++ {
++ if ( verbose ) System.out.printf("idx = %d\n", idx) ;
++
++ BPTreeNode node = nodeMgr.getRead(idx, 0) ;
++ if ( node == null )
++ break ;
++ System.out.println(node) ;
++
++ // if ( verbose )
++ // System.out.printf("%04d :: id=%04d -> link=%04d [count=%d, max=%d]\n", n, page.getId(), page.getLink(), page.getCount(), page.getMaxSize()) ;
++ n++ ;
++ idx ++ ;
++ nodeMgr.release(node) ;
++ }
++ } catch (Exception ex)
++ {
++ System.out.println("Exception: "+ex) ;
++ ex.printStackTrace() ;
++ }
++
++ System.out.printf("[Scan Nodes] Count = %d in %d blocks (avg: %.2f)\n", total, n, ((float)total)/n) ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BlockTracker.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BlockTracker.java
index 0000000,0000000..0271891
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BlockTracker.java
@@@ -1,0 -1,0 +1,426 @@@
++/*
++ * 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.dboe.trans.bplustree ;
++
++import static org.seaborne.dboe.trans.bplustree.BlockTracker.Action.Alloc ;
++import static org.seaborne.dboe.trans.bplustree.BlockTracker.Action.BeginRead ;
++import static org.seaborne.dboe.trans.bplustree.BlockTracker.Action.BeginUpdate ;
++import static org.seaborne.dboe.trans.bplustree.BlockTracker.Action.EndRead ;
++import static org.seaborne.dboe.trans.bplustree.BlockTracker.Action.EndUpdate ;
++import static org.seaborne.dboe.trans.bplustree.BlockTracker.Action.Free ;
++import static org.seaborne.dboe.trans.bplustree.BlockTracker.Action.GetRead ;
++import static org.seaborne.dboe.trans.bplustree.BlockTracker.Action.GetWrite ;
++import static org.seaborne.dboe.trans.bplustree.BlockTracker.Action.Promote ;
++import static org.seaborne.dboe.trans.bplustree.BlockTracker.Action.Release ;
++import static org.seaborne.dboe.trans.bplustree.BlockTracker.Action.Write ;
++
++import java.util.ArrayList ;
++import java.util.List ;
++
++import org.apache.jena.atlas.lib.Pair ;
++import org.apache.jena.ext.com.google.common.collect.HashMultiset ;
++import org.apache.jena.ext.com.google.common.collect.Multiset ;
++import org.seaborne.dboe.DBOpEnvException ;
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.base.block.BlockException ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.block.BlockMgrTracker ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/** Track the lifecycles of allocate-write, getRead-promote-write and getWrite-write.
++ * Does not track read only or iterators blocks.
++ */
++
++// In MVCC, there are many read blocks that are forgotten.
++// Promotion does not release them (should it?).
++
++// In the B+Tree iteraor, pages are get()'ed but pages
++// don't expose a "get for iterator" and always use getRead.
++// But iterators don't release and don't always finish.
++
++
++public class BlockTracker implements BlockMgr {
++ public static Logger logger = LoggerFactory.getLogger(BlockTracker.class) ;
++
++ public static boolean collectHistory = true ;
++
++ static enum Action {
++ Alloc, Promote, GetRead, GetWrite, Write, Release, Free,
++ BeginIter, EndIter, IterRead,
++ BeginRead, EndRead,
++ BeginUpdate, EndUpdate
++ }
++ static final Long NoId = (long)-9 ;
++
++ // ---- State for tracking
++ // Track and count block references and releases
++ // No - the page is dirty.
++ protected final Multiset<Long> activeWriteBlocks = HashMultiset.create() ;
++ protected final Multiset<Long> activeReadBlocks = HashMultiset.create() ;
++ // Track the operations
++ protected final List<Pair<Action, Long>> actions = new ArrayList<>() ;
++ // ---- State for tracking
++
++ protected final BlockMgr blockMgr ;
++
++ private void clearBlockTracking() {
++ activeReadBlocks.clear() ;
++ activeWriteBlocks.clear() ;
++ actions.clear() ;
++ }
++
++ public void clearHistory() {
++ actions.clear() ;
++ }
++
++ public void clearAll() {
++ clearBlockTracking() ;
++ }
++
++ private int inRead = 0 ;
++ private int inUpdate = 0 ;
++ private final Logger log ;
++ private final String label ;
++
++ public static BlockMgr track(BlockMgr blkMgr) {
++ return track(blkMgr.getLabel(), blkMgr) ;
++ }
++
++ private static BlockMgr track(String label, BlockMgr blkMgr) {
++ return new BlockTracker(label, blkMgr) ;
++ }
++
++ private BlockTracker(BlockMgr blockMgr) {
++ this(LoggerFactory.getLogger(BlockMgrTracker.class), blockMgr.getLabel(), blockMgr) ;
++ }
++
++ private BlockTracker(String label, BlockMgr blockMgr) {
++ this(logger, label, blockMgr) ;
++ }
++
++ private BlockTracker(Logger logger, String label, BlockMgr blockMgr) {
++ this.blockMgr = blockMgr ;
++ this.log = logger ;
++ this.label = blockMgr.getLabel() ;
++ }
++
++ private void add(Action action, Long id) {
++ if ( collectHistory )
++ actions.add(new Pair<>(action, id)) ;
++ }
++
++ @Override
++ public Block allocate(int blockSize) {
++ Block block ;
++ synchronized (this) {
++ checkUpdate(Alloc) ;
++ block = blockMgr.allocate(blockSize) ;
++ Long id = block.getId() ;
++ activeWriteBlocks.add(id) ;
++ add(Alloc, id) ;
++ }
++ return block ;
++ }
++
++ @Override
++ public Block getRead(long id) {
++ // What if this is a write block already?
++ synchronized (this) {
++ checkRead(GetRead) ;
++ Long x = id ;
++ add(GetRead, x) ;
++
++ if ( activeWriteBlocks.contains(x) )
++ activeWriteBlocks.add(x) ;
++ else
++ activeReadBlocks.add(x) ;
++ }
++ return blockMgr.getRead(id) ;
++ }
++
++ @Override
++ public Block getWrite(long id) {
++ synchronized (this) {
++ checkUpdate(GetWrite) ;
++ Long x = id ;
++ add(GetWrite, x) ;
++ activeWriteBlocks.add(x) ;
++ }
++ return blockMgr.getWrite(id) ;
++ }
++
++ @Override
++ public Block promote(Block block) {
++ synchronized (this) {
++ checkUpdate(Promote) ;
++ Long id = block.getId() ;
++ add(Promote, id) ;
++
++ if ( !activeWriteBlocks.contains(id) && !activeReadBlocks.contains(id) )
++ error(Promote, id + " is not an active block") ;
++
++ while ( activeReadBlocks.contains(id) )
++ activeReadBlocks.remove(id) ;
++
++ // Double promotion results in only one entry.
++ if ( !activeWriteBlocks.contains(id) )
++ activeWriteBlocks.add(id) ;
++ }
++ return blockMgr.promote(block) ;
++ }
++
++ @Override
++ public void release(Block block) {
++ synchronized (this) {
++ Long id = block.getId() ;
++ add(Release, id) ;
++
++ // Iterator blocks are not released.
++// if ( !activeReadBlocks.contains(id) && !activeWriteBlocks.contains(id) )
++// error(Release, id + " is not an active block") ;
++
++ // May have been promoted.
++ if ( activeWriteBlocks.contains(id) )
++ activeWriteBlocks.remove(id) ;
++ else
++ activeReadBlocks.remove(block.getId()) ;
++ }
++ blockMgr.release(block) ;
++ }
++
++ @Override
++ public void write(Block block) {
++ if ( logger.isInfoEnabled() && block.getId() == 2 )
++ debugPoint();
++ writeTracker(block) ;
++ blockMgr.write(block) ;
++ }
++
++ @Override
++ synchronized public void overwrite(Block block) {
++ writeTracker(block) ;
++ blockMgr.overwrite(block) ;
++ }
++
++ private void writeTracker(Block block) {
++ synchronized (this) {
++ checkUpdate(Write) ;
++ Long id = block.getId() ;
++ add(Write, id) ;
++ if ( !activeWriteBlocks.contains(id) )
++ error(Write, id + " is not an active write block") ;
++ }
++ }
++
++ @Override
++ public void free(Block block) {
++ synchronized (this) {
++ checkUpdate(Free) ;
++ Long id = block.getId() ;
++ add(Free, id) ;
++ if ( activeReadBlocks.contains(id) )
++ warn(Free, id + " is a read block") ;
++
++ if ( !activeWriteBlocks.contains(id) )
++ error(Free, id + " is not a write block") ;
++
++ activeWriteBlocks.remove(id) ;
++ if ( activeWriteBlocks.count(id) != 0 )
++ warn(Free, id + " has "+activeWriteBlocks.count(id)+" outstanding write registrations") ;
++ }
++ blockMgr.free(block) ;
++ }
++
++ @Override
++ public void sync() {
++ blockMgr.sync() ;
++ }
++
++ @Override
++ public void syncForce() {
++ blockMgr.syncForce() ;
++ }
++
++ @Override
++ public void close() {
++ blockMgr.close() ;
++ }
++
++ @Override
++ public boolean isEmpty() {
++ return blockMgr.isEmpty() ;
++ }
++
++ @Override
++ public long allocLimit() {
++ return blockMgr.allocLimit() ;
++ }
++
++ @Override
++ public void resetAlloc(long boundary) {
++ blockMgr.resetAlloc(boundary) ;
++ }
++
++ @Override
++ public boolean valid(int id) {
++ return blockMgr.valid(id) ;
++ }
++
++ @Override
++ public boolean isClosed() {
++ return blockMgr.isClosed() ;
++ }
++
++ @Override
++ synchronized public void beginRead() {
++ synchronized (this) {
++ if ( inUpdate != 0 )
++ error(BeginRead, "beginRead when already in update") ;
++ inRead++ ;
++ }
++ blockMgr.beginRead() ;
++ }
++
++ @Override
++ synchronized public void endRead() {
++ synchronized (this) {
++ if ( inRead == 0 )
++ error(EndRead, "endRead but not in read") ;
++ if ( inUpdate != 0 )
++ error(EndRead, "endRead when in update") ;
++
++ checkEmpty("Outstanding write blocks at end of read operations!", activeWriteBlocks) ;
++
++ if ( inRead == 0 ) {
++ // Check at end of multiple reads or a write
++ checkEmpty("Outstanding read blocks at end of read operations", activeReadBlocks) ;
++ clearBlockTracking() ;
++ }
++ inRead-- ;
++ }
++ blockMgr.endRead() ;
++ }
++
++ @Override
++ public void beginUpdate() {
++ synchronized (this) {
++ if ( inRead > 0 )
++ error(BeginUpdate, "beginUpdate when already in read") ;
++ if ( inUpdate > 0 )
++ error(BeginUpdate, "beginUpdate when already in update") ;
++ inUpdate++ ;
++ clearBlockTracking();
++ }
++ blockMgr.beginUpdate() ;
++ }
++
++ @Override
++ public void endUpdate() {
++ synchronized (this) {
++ if ( inUpdate == 0 )
++ error(EndUpdate, "endUpdate but not in update") ;
++ if ( inRead > 0 )
++ error(EndUpdate, "endUpdate when in read") ;
++
++ checkEmpty("Outstanding read blocks at end of update operations", activeReadBlocks) ;
++
++ checkEmpty("Outstanding write blocks at end of update operations", activeWriteBlocks) ;
++
++ inUpdate-- ;
++ clearBlockTracking() ;
++ }
++ blockMgr.endUpdate() ;
++ }
++
++ private void checkUpdate(Action action) {
++ if ( inUpdate == 0 )
++ error(action, "called outside update") ;
++ }
++
++ private void checkRead(Action action) {
++ if ( inUpdate == 0 && inRead == 0 )
++ error(action, "Called outside update and read") ;
++ }
++
++ private void checkEmpty(String string, Multiset<Long> blocks) {
++ if ( !blocks.isEmpty() ) {
++ error(string) ;
++ for ( Long id : blocks )
++ warn(" Block: " + id) ;
++ if ( collectHistory )
++ history() ;
++ throw new DBOpEnvException() ;
++ // debugPoint() ;
++ }
++ }
++
++ private String msg(String string) {
++ if ( label == null )
++ return string ;
++ return label + ": " + string ;
++ }
++
++ private void info(String string) {
++ log.info(msg(string)) ;
++ }
++
++ private void warn(String string) {
++ log.warn(msg(string)) ;
++ }
++
++ private void warn(Action action, String string) {
++ warn(action + ": " + string) ;
++ }
++
++ private void error(String string) {
++ log.error(msg(string)) ;
++ }
++
++ private void error(Action action, String string) {
++ error(action + ": " + string) ;
++ history() ;
++ throw new BlockException(msg(action + ": " + string)) ;
++ // debugPoint() ;
++ }
++
++ // Do nothing - but use as a breakpoint point.
++ private void debugPoint() {
++ return ;
++ }
++
++ private void history() {
++ info("History") ;
++ for ( Pair<Action, Long> p : actions ) {
++ if ( p.getRight() != NoId )
++ log.info(String.format("%s: %-12s %d", label, p.getLeft(), p.getRight())) ;
++ else
++ log.info(String.format("%s: %-12s", label, p.getLeft())) ;
++ }
++ }
++
++ @Override
++ public String toString() {
++ return "BlockMgrTracker" + ((label == null) ? "" : (": " + label)) ;
++ }
++
++ @Override
++ public String getLabel() {
++ return label ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BptTxnState.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BptTxnState.java
index 0000000,0000000..a0e45bb
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BptTxnState.java
@@@ -1,0 -1,0 +1,63 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++/** Transactional state of a {@link BPlusTree} */
++final class BptTxnState {
++ final int initialroot ;
++ private int root = -1 ;
++
++ // Point at which we start adding blocks in a write transaction.
++ // The unmodifiable area is [0,boundary) and is different for each block manager.
++
++ final long boundaryBlocksNode ;
++ final long boundaryBlocksRecord ;
++
++ BptTxnState(int initRoot, long boundaryNode, long boundaryRecords) {
++ this.initialroot = initRoot ;
++ this.root = initRoot ;
++ this.boundaryBlocksNode = boundaryNode ;
++ this.boundaryBlocksRecord = boundaryRecords ;
++ }
++
++ boolean modifiableNodeBlock(int id) {
++ if ( BPT.forcePromoteModes )
++ return ! BPT.promoteDuplicateNodes ;
++ return id >= boundaryBlocksNode ;
++ }
++
++ boolean modifiableRecordsBlock(int id) {
++ if ( BPT.forcePromoteModes )
++ return ! BPT.promoteDuplicateRecords ;
++ return id >= boundaryBlocksRecord ;
++ }
++
++ @Override
++ public String toString() {
++ return "BptTxnState: [root="+root+", n="+boundaryBlocksNode+", r="+boundaryBlocksRecord+"]";
++ }
++
++ public int getRoot() {
++ return root;
++ }
++
++ public void setRoot(int root) {
++ this.root = root;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/Mode.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/Mode.java
index 0000000,0000000..c9090c7
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/Mode.java
@@@ -1,0 -1,0 +1,53 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++/** Tree mode - changing the mode on an existing tree is not supported.
++ * The normal mode of operation is {@link Mode#TRANSACTIONAL}
++ */
++public enum Mode {
++ /**
++ * B+Tree changes are applied in place. MRSW applies.
++ */
++ MUTABLE,
++ /**
++ * All operations create new replicated blocks; a replicated block
++ * within the operation is not replicated.
++ */
++ IMMUTABLE,
++ /**
++ * All changes create new replicated blocks; replicated blocks
++ * are re-replicated. (testing)
++ */
++ IMMUTABLE_ALL,
++ /**
++ * As above except the root alone is mutated, hence it is a fixed, known
++ * id. (testing)
++ */
++ MUTABLE_ROOT,
++ /**
++ * Transactional lifecycle, where blocks below the water marks are
++ * immutable.
++ */
++ TRANSACTIONAL,
++ /**
++ * Transactional lifecycle, with automatic transactions for update
++ * operations outside an explicit transaction.
++ */
++ TRANSACTIONAL_AUTOCOMMIT
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/rewriter/BPTreeNodeBuilder.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/rewriter/BPTreeNodeBuilder.java
index 0000000,0000000..2fe5fa7
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/rewriter/BPTreeNodeBuilder.java
@@@ -1,0 -1,0 +1,180 @@@
++/*
++ * 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.dboe.trans.bplustree.rewriter ;
++
++import java.util.Iterator ;
++import java.util.NoSuchElementException ;
++
++import org.apache.jena.atlas.lib.Pair ;
++import org.seaborne.dboe.base.buffer.PtrBuffer ;
++import org.seaborne.dboe.base.buffer.RecordBuffer ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.trans.bplustree.BPTreeNode ;
++import org.seaborne.dboe.trans.bplustree.BPTreeNodeMgr ;
++
++/** Take a stream of (block id,split record) pairs and generate B+Tree Nodes */
++class BPTreeNodeBuilder implements Iterator<Pair<Integer, Record>> {
++ private Pair<Integer, Record> slot ;
++ private Iterator<Pair<Integer, Record>> iter ;
++ private final BPTreeNodeMgr mgr ;
++
++ private final boolean leafLayer ;
++ private final RecordFactory recordFactory ;
++
++ BPTreeNodeBuilder(Iterator<Pair<Integer, Record>> iter, BPTreeNodeMgr mgr, boolean leafLayer, RecordFactory recordFactory) {
++ this.iter = iter ;
++ this.mgr = mgr ;
++ this.leafLayer = leafLayer ;
++ this.recordFactory = recordFactory ;
++ }
++
++ @Override
++ public boolean hasNext() {
++ if ( slot != null )
++ return true ;
++
++ if ( iter == null )
++ return false ;
++
++ if ( !iter.hasNext() ) {
++ // Start of next block, no more input.
++ iter = null ;
++ return false ;
++ }
++
++ // At least one element to put in a new node.
++ // Unknown parent. Does not matter (parent is only in-memory)
++
++ BPTreeNode bptNode = mgr.createNode(-1) ;
++ bptNode.setIsLeaf(leafLayer) ;
++
++ RecordBuffer recBuff = bptNode.getRecordBuffer() ;
++ PtrBuffer ptrBuff = bptNode.getPtrBuffer() ;
++ recBuff.setSize(0) ;
++ ptrBuff.setSize(0) ; // Creation leaves this junk.
++
++ final boolean debug = false ;
++ int rMax = recBuff.maxSize() ;
++ int pMax = ptrBuff.maxSize() ;
++ if ( debug )
++ System.out.printf("Max: (%d, %d)\n", rMax, pMax) ;
++
++ for ( ; iter.hasNext() ; ) {
++
++ int X = bptNode.getCount() ;
++ int X2 = bptNode.getMaxSize() ;
++ int P = ptrBuff.size() ;
++ int P2 = ptrBuff.maxSize() ;
++ int R = recBuff.size() ;
++ int R2 = recBuff.maxSize() ;
++
++ // bptNode.getMaxSize() is drivel
++ // System.out.printf("N: %d/%d : P %d/%d : R %d/%d\n", X, X2, P, P2,
++ // R, R2) ;
++
++ Pair<Integer, Record> pair = iter.next() ;
++ if ( debug )
++ System.out.println("** Item: " + pair) ;
++ Record r = pair.cdr() ;
++
++ // [Issue: FREC]
++ // The record buffer size is wrong.
++ // Writes the whole record, only need to write the key part.
++ // **** r = recordFactory.createKeyOnly(r) ;
++
++ // [Issue: FREC]
++ // The record is key-only (which is correct) but until FREC fixed,
++ // we need key,value
++ r = recordFactory.create(r.getKey()) ;
++ // -- End FREC
++
++ // Always add - so ptrBuff is one ahead when we finish.
++ // There is always one more ptr than record in a B+Tree node.
++ if ( ptrBuff.isFull() )
++ System.err.println("PtrBuffer is full") ;
++
++ // Add pointer.
++ ptrBuff.add(pair.car()) ;
++
++ // [Issue: FREC]
++ // Either test shoudl work but due to the missetting of record
++ // buffer size
++ // testing recBuff does not work.
++ // if ( recBuff.isFull() )
++ // .... test ptrBuff
++ if ( ptrBuff.isFull() ) {
++ // End of this block.
++
++ // Does not add to ptrBuff so the one extra slot is done.
++ // Instead, the high point goes to the next level up.
++
++ // Internal consistency check.
++ if ( !ptrBuff.isFull() )
++ System.err.println("PtrBuffer is not full") ;
++
++ // The split point for the next level up.
++ slot = new Pair<>(bptNode.getId(), pair.cdr()) ;
++
++ if ( debug )
++ System.out.printf("Write(1): %d\n", bptNode.getId()) ;
++ if ( debug )
++ System.out.println(bptNode) ;
++ if ( debug )
++ System.out.println("Slot = " + slot) ;
++ mgr.put(bptNode) ;
++ // No count increment needed.
++ return true ;
++ }
++
++ recBuff.add(r) ;
++ bptNode.setCount(bptNode.getCount() + 1) ;
++ }
++
++ // If we get here, the input stream ran out before we finished a
++ // complete block.
++ // Fix up block (remove the last record)
++ Record r = recBuff.getHigh() ;
++ recBuff.removeTop() ;
++ bptNode.setCount(bptNode.getCount() - 1) ;
++ slot = new Pair<>(bptNode.getId(), r) ;
++
++ if ( debug )
++ System.out.printf("Write(2): %d\n", bptNode.getId()) ;
++ if ( debug )
++ System.out.println(bptNode) ;
++ if ( debug )
++ System.out.println("Slot = " + slot) ;
++ mgr.put(bptNode) ;
++ return true ;
++ }
++
++ @Override
++ public Pair<Integer, Record> next() {
++ if ( !hasNext() )
++ throw new NoSuchElementException() ;
++ Pair<Integer, Record> x = slot ;
++ slot = null ;
++ return x ;
++ }
++
++ @Override
++ public void remove() {
++ throw new UnsupportedOperationException() ;
++ }
++}
[11/50] [abbrv] jena git commit: Compaction tests
Posted by an...@apache.org.
Compaction tests
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/eee1a6ab
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/eee1a6ab
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/eee1a6ab
Branch: refs/heads/jena-tdb2
Commit: eee1a6abb34ff8226495edfcd711dff18c02d498
Parents: d8fd29a
Author: Andy Seaborne <an...@seaborne.org>
Authored: Sun Sep 3 17:38:49 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Sun Sep 3 17:38:49 2017 +0100
----------------------------------------------------------------------
.../org/seaborne/tdb2/sys/TestDatabaseOps.java | 83 +++++++++++++++++---
1 file changed, 70 insertions(+), 13 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/eee1a6ab/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java b/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java
index 09b9804..fa90400 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/sys/TestDatabaseOps.java
@@ -17,13 +17,15 @@
package org.seaborne.tdb2.sys;
-import static org.junit.Assert.assertEquals ;
+import static org.junit.Assert.* ;
import static org.junit.Assert.assertFalse ;
import static org.junit.Assert.assertNotEquals ;
import static org.junit.Assert.assertTrue ;
import org.apache.commons.io.FileUtils ;
import org.apache.jena.atlas.lib.FileOps ;
+import org.apache.jena.graph.Graph ;
+import org.apache.jena.graph.Triple ;
import org.apache.jena.riot.RDFDataMgr ;
import org.apache.jena.sparql.core.DatasetGraph ;
import org.apache.jena.sparql.core.Quad ;
@@ -43,8 +45,11 @@ public class TestDatabaseOps
static String DIRx = ConfigTest.getCleanDir() ;
static Location DIR = Location.create(DIRx);
- static Quad quad1 = SSE.parseQuad("(_ _:a <p> 1)") ;
- static Quad quad2 = SSE.parseQuad("(_ <s> <p> 1)") ;
+ static Quad quad1 = SSE.parseQuad("(_ <s> <p> 1)") ;
+ static Quad quad2 = SSE.parseQuad("(_ _:a <p> 2)") ;
+ static Triple triple1 = quad1.asTriple();
+ static Triple triple2 = quad2.asTriple();
+ static Triple triple3 = SSE.parseTriple("(<s> <q> 3)") ;
@Before
public void before() {
@@ -58,15 +63,15 @@ public class TestDatabaseOps
FileUtils.deleteQuietly(IOX.asFile(DIR));
}
- @Test public void compact_1() {
+ @Test public void compact_dsg_1() {
DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(DIR);
DatasetGraphSwitchable dsgs = (DatasetGraphSwitchable)dsg;
DatasetGraph dsg1 = dsgs.get();
Location loc1 = ((DatasetGraphTDB)dsg1).getLocation();
Txn.executeWrite(dsg, ()-> {
- dsg.add(quad1) ;
dsg.add(quad2) ;
+ dsg.add(quad1) ;
}) ;
DatabaseMgr.compact(dsg);
@@ -79,32 +84,84 @@ public class TestDatabaseOps
assertNotEquals(loc1, loc2);
Txn.executeRead(dsg, ()-> {
- assertTrue(dsg.contains(quad1)) ;
assertTrue(dsg.contains(quad2)) ;
+ assertTrue(dsg.contains(quad1)) ;
}) ;
// dsg1 was closed and expelled. We must carefully reopen its storage only.
+ DatasetGraph dsgOld = StoreConnection.connectCreate(loc1).getDatasetGraph();
+
+ Txn.executeWrite(dsgOld, ()->dsgOld.delete(quad2));
+ Txn.executeRead(dsg, ()->assertTrue(dsg.contains(quad2)) );
+ Txn.executeRead(dsg2, ()->assertTrue(dsg2.contains(quad2)) ) ;
+ }
+
+ @Test public void compact_graph_2() {
+ // graphs across compaction.
+ DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(DIR);
+ Graph g = dsg.getDefaultGraph();
+
+ DatasetGraphSwitchable dsgs = (DatasetGraphSwitchable)dsg;
+ DatasetGraph dsg1 = dsgs.get();
+ Location loc1 = ((DatasetGraphTDB)dsg1).getLocation();
+
+ Txn.executeWrite(dsg, ()-> {
+ dsg.add(quad2) ;
+ dsg.add(quad1) ;
+ }) ;
+ DatabaseMgr.compact(dsg);
+ Txn.executeRead(dsg, ()-> {
+ assertEquals(2, g.size());
+ assertTrue(g.contains(triple2));
+ }) ;
+ // Check is not attached to the old graph.
DatasetGraph dsgOld = StoreConnection.connectCreate(loc1).getDatasetGraph();
+
+ Txn.executeWrite(dsgOld, ()->dsgOld.getDefaultGraph().delete(triple2));
+ Txn.executeRead(dsg, ()->assertTrue(g.contains(triple2)) );
- Txn.executeWrite(dsgOld, ()->dsgOld.delete(quad1));
- Txn.executeRead(dsg, ()->assertTrue(dsg.contains(quad1)) );
- Txn.executeRead(dsg2, ()->assertTrue(dsg2.contains(quad1)) ) ;
+ Txn.executeWrite(dsg, ()->g.add(triple3));
+ Txn.executeRead(dsgOld, ()->assertFalse(dsgOld.getDefaultGraph().contains(triple3)) );
}
+
+ @Test public void compact_prefixes_3() {
+ // prefixes axcross compaction.
+ DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(DIR);
+ Graph g = dsg.getDefaultGraph();
+ Txn.executeWrite(dsg, ()-> g.getPrefixMapping().setNsPrefix("ex", "http://example/") );
+
+ DatasetGraphSwitchable dsgs = (DatasetGraphSwitchable)dsg;
+ DatasetGraph dsg1 = dsgs.get();
+ Location loc1 = ((DatasetGraphTDB)dsg1).getLocation();
+
+ DatabaseMgr.compact(dsg);
+
+ Txn.executeRead(dsg, ()-> {
+ assertEquals("ex", g.getPrefixMapping().getNsURIPrefix("http://example/"));
+ assertEquals("http://example/", g.getPrefixMapping().getNsPrefixURI("ex"));
+ }) ;
+
+ // Check is not attached to the old graph.
+ DatasetGraph dsgOld = StoreConnection.connectCreate(loc1).getDatasetGraph();
-// @Test public void compact_2() {
-// }
+ Txn.executeWrite(dsgOld, ()->dsgOld.getDefaultGraph().getPrefixMapping().removeNsPrefix("ex"));
+ Txn.executeRead(dsg, ()->assertEquals("http://example/", g.getPrefixMapping().getNsPrefixURI("ex")));
+
+ Txn.executeWrite(dsg, ()->g.getPrefixMapping().setNsPrefix("ex2", "http://exampl2/") );
+ Txn.executeRead(dsgOld, ()->assertNull(dsgOld.getDefaultGraph().getPrefixMapping().getNsPrefixURI("ex")));
+ }
@Test public void backup_1() {
DatasetGraph dsg = DatabaseMgr.connectDatasetGraph(DIR);
Txn.executeWrite(dsg, ()-> {
- dsg.add(quad1) ;
dsg.add(quad2) ;
+ dsg.add(quad1) ;
}) ;
String file1 = DatabaseMgr.backup(dsg);
DatasetGraph dsg2 = RDFDataMgr.loadDatasetGraph(file1);
Txn.executeRead(dsg, ()-> {
- assertTrue(dsg.contains(quad2)) ;
+ assertTrue(dsg.contains(quad1)) ;
assertEquals(2, dsg.getDefaultGraph().size());
assertTrue(dsg2.getDefaultGraph().isIsomorphicWith(dsg.getDefaultGraph()));
}) ;
[15/50] [abbrv] jena git commit: [maven-release-plugin] prepare
release mantis-0.3.0
Posted by an...@apache.org.
[maven-release-plugin] prepare release mantis-0.3.0
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/a23065e3
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/a23065e3
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/a23065e3
Branch: refs/heads/jena-tdb2
Commit: a23065e34ca5b93d3975b03809bf78836dd1e796
Parents: ef68a8d
Author: Andy Seaborne <an...@seaborne.org>
Authored: Mon Sep 4 12:56:29 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Mon Sep 4 12:56:29 2017 +0100
----------------------------------------------------------------------
dboe-base/pom.xml | 2 +-
dboe-index-test/pom.xml | 4 ++--
dboe-index/pom.xml | 4 ++--
dboe-trans-data/pom.xml | 10 +++++-----
dboe-transaction/pom.xml | 4 ++--
fuseki-tdb2/pom.xml | 4 ++--
pom.xml | 7 +++----
tdb2-cmds/pom.xml | 4 ++--
tdb2/pom.xml | 4 ++--
9 files changed, 21 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/a23065e3/dboe-base/pom.xml
----------------------------------------------------------------------
diff --git a/dboe-base/pom.xml b/dboe-base/pom.xml
index 1843969..4179450 100644
--- a/dboe-base/pom.xml
+++ b/dboe-base/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</parent>
<dependencies>
http://git-wip-us.apache.org/repos/asf/jena/blob/a23065e3/dboe-index-test/pom.xml
----------------------------------------------------------------------
diff --git a/dboe-index-test/pom.xml b/dboe-index-test/pom.xml
index 658d621..48c1b63 100644
--- a/dboe-index-test/pom.xml
+++ b/dboe-index-test/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</parent>
<dependencies>
@@ -34,7 +34,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-index</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/jena/blob/a23065e3/dboe-index/pom.xml
----------------------------------------------------------------------
diff --git a/dboe-index/pom.xml b/dboe-index/pom.xml
index 2b21bbe..dcc92cb 100644
--- a/dboe-index/pom.xml
+++ b/dboe-index/pom.xml
@@ -26,7 +26,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</parent>
<dependencies>
@@ -34,7 +34,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-base</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</dependency>
</dependencies>
http://git-wip-us.apache.org/repos/asf/jena/blob/a23065e3/dboe-trans-data/pom.xml
----------------------------------------------------------------------
diff --git a/dboe-trans-data/pom.xml b/dboe-trans-data/pom.xml
index 08bd822..a579aa4 100644
--- a/dboe-trans-data/pom.xml
+++ b/dboe-trans-data/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</parent>
<dependencies>
@@ -33,26 +33,26 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-transaction</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</dependency>
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-index</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</dependency>
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-index-test</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-base</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
http://git-wip-us.apache.org/repos/asf/jena/blob/a23065e3/dboe-transaction/pom.xml
----------------------------------------------------------------------
diff --git a/dboe-transaction/pom.xml b/dboe-transaction/pom.xml
index 76b7902..f45beb7 100644
--- a/dboe-transaction/pom.xml
+++ b/dboe-transaction/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</parent>
<dependencies>
@@ -33,7 +33,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-base</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</dependency>
</dependencies>
http://git-wip-us.apache.org/repos/asf/jena/blob/a23065e3/fuseki-tdb2/pom.xml
----------------------------------------------------------------------
diff --git a/fuseki-tdb2/pom.xml b/fuseki-tdb2/pom.xml
index 248881c..6c3383c 100644
--- a/fuseki-tdb2/pom.xml
+++ b/fuseki-tdb2/pom.xml
@@ -25,7 +25,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</parent>
<packaging>jar</packaging>
@@ -36,7 +36,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>tdb2</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/jena/blob/a23065e3/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index af22a7d..72b8aba 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
<artifactId>mantis</artifactId>
<packaging>pom</packaging>
<url>https://github.com/afs/mantis</url>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
<name>Mantis :: Database Operation Environment</name>
<description>Mantis :: Database Operation Environment</description>
@@ -56,7 +56,7 @@
<url>https://github.com/afs/mantis</url>
<connection>scm:git:https://github.com/afs/mantis</connection>
<developerConnection>scm:git:git@github.com:afs/mantis.git</developerConnection>
- <tag>HEAD</tag>
+ <tag>mantis-0.3.0</tag>
</scm>
<properties>
@@ -354,8 +354,7 @@
i.e. is it additive?
<configuration>
<gpgArguments>
- <arg>- -digest-algo=SHA512</arg> <comment fix
- </gpgArguments>
+ <arg>- -digest-algo=SHA512</arg> <comment fix </gpgArguments>
</configuration>
-->
<executions>
http://git-wip-us.apache.org/repos/asf/jena/blob/a23065e3/tdb2-cmds/pom.xml
----------------------------------------------------------------------
diff --git a/tdb2-cmds/pom.xml b/tdb2-cmds/pom.xml
index 9cd77bf..9885c77 100644
--- a/tdb2-cmds/pom.xml
+++ b/tdb2-cmds/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</parent>
<dependencies>
@@ -35,7 +35,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>tdb2</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/jena/blob/a23065e3/tdb2/pom.xml
----------------------------------------------------------------------
diff --git a/tdb2/pom.xml b/tdb2/pom.xml
index 0dd7f62..886e2da 100644
--- a/tdb2/pom.xml
+++ b/tdb2/pom.xml
@@ -27,7 +27,7 @@
<parent>
<groupId>org.seaborne.mantis</groupId>
<artifactId>mantis</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</parent>
<dependencies>
@@ -43,7 +43,7 @@
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>dboe-trans-data</artifactId>
- <version>0.3.0-SNAPSHOT</version>
+ <version>0.3.0</version>
</dependency>
<dependency>
[24/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Values/manifest.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Values/manifest.ttl
index 0000000,0000000..3396af5
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Values/manifest.ttl
@@@ -1,0 -1,0 +1,76 @@@
++# 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.
++
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
++@prefix qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
++
++<> rdf:type mf:Manifest ;
++ rdfs:label "Value tests" ;
++ mf:entries
++ (
++ [ mf:name "Value-00" ;
++ mf:action
++ [ qt:query <value-00.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-01" ;
++ mf:action
++ [ qt:query <value-01.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-02" ;
++ mf:action
++ [ qt:query <value-02.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-03" ;
++ mf:action
++ [ qt:query <value-03.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++
++ [ mf:name "Value-04" ;
++ mf:action
++ [ qt:query <value-04.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-05" ;
++ mf:action
++ [ qt:query <value-05.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-06" ;
++ mf:action
++ [ qt:query <value-06.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-07" ;
++ mf:action
++ [ qt:query <value-07.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-08" ;
++ mf:action
++ [ qt:query <value-08.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ [ mf:name "Value-09" ;
++ mf:action
++ [ qt:query <value-09.rq> ;
++ qt:data <data-1.ttl> ] ;
++ ]
++ ) .
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Values/value-00.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Values/value-00.rq
index 0000000,0000000..d1fe80b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Values/value-00.rq
@@@ -1,0 -1,0 +1,1 @@@
++SELECT * { ?s ?p ?o }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Values/value-01.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Values/value-01.rq
index 0000000,0000000..664f67a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Values/value-01.rq
@@@ -1,0 -1,0 +1,1 @@@
++SELECT * { ?s ?p 1 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Values/value-02.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Values/value-02.rq
index 0000000,0000000..5dfe5ec
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Values/value-02.rq
@@@ -1,0 -1,0 +1,1 @@@
++SELECT * { ?s ?p 1.5 }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Values/value-03.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Values/value-03.rq
index 0000000,0000000..7134be8
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Values/value-03.rq
@@@ -1,0 -1,0 +1,1 @@@
++SELECT * { ?s ?p "1" }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Values/value-04.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Values/value-04.rq
index 0000000,0000000..030116d
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Values/value-04.rq
@@@ -1,0 -1,0 +1,1 @@@
++SELECT * { ?s ?p "1"@en }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Values/value-05.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Values/value-05.rq
index 0000000,0000000..fbd8d9b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Values/value-05.rq
@@@ -1,0 -1,0 +1,5 @@@
++SELECT *
++{
++ ?s ?p ?o .
++ FILTER(?o = 1)
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Values/value-06.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Values/value-06.rq
index 0000000,0000000..8f34124
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Values/value-06.rq
@@@ -1,0 -1,0 +1,6 @@@
++PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
++
++SELECT *
++{
++ ?s ?p "2008-04-29+01:00"^^xsd:date .
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Values/value-07.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Values/value-07.rq
index 0000000,0000000..cafd777
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Values/value-07.rq
@@@ -1,0 -1,0 +1,6 @@@
++PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
++
++SELECT *
++{
++ ?s ?p ?x . FILTER (?x = "2008-04-29+01:00"^^xsd:date) .
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Values/value-08.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Values/value-08.rq
index 0000000,0000000..e6fc284
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Values/value-08.rq
@@@ -1,0 -1,0 +1,6 @@@
++PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
++
++SELECT *
++{
++ ?s ?p "2008-04-29T09:13:15+01:00"^^xsd:dateTime .
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/Values/value-09.rq
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/Values/value-09.rq
index 0000000,0000000..02dcc20
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/Values/value-09.rq
@@@ -1,0 -1,0 +1,7 @@@
++PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
++
++SELECT *
++{
++ # Out of range - not an immediate literal
++ ?s ?p "-3000-04-29T09:13:15Z"^^xsd:dateTime
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/testing/manifest.ttl
----------------------------------------------------------------------
diff --cc jena-db/tdb2/testing/manifest.ttl
index 0000000,0000000..aeaf80e
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/testing/manifest.ttl
@@@ -1,0 -1,0 +1,31 @@@
++# 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.
++
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
++@prefix qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
++
++<> rdf:type mf:Manifest ;
++ rdfs:label "TDB - Scripts" ;
++ mf:include (
++ <Basic/manifest.ttl>
++ <Pattern/manifest.ttl>
++ <Quads/manifest.ttl>
++ <Values/manifest.ttl>
++ <UnionGraph/manifest.ttl>
++ ) .
++
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/use-fuseki-tdb2.md
----------------------------------------------------------------------
diff --cc jena-db/use-fuseki-tdb2.md
index 0000000,0000000..e64d99f
new file mode 100644
--- /dev/null
+++ b/jena-db/use-fuseki-tdb2.md
@@@ -1,0 -1,0 +1,60 @@@
++There is a combined Fuseki server jar:
++
++Release builds are available from the central maven repository:
++
++http://central.maven.org/maven2/org/seaborne/mantis/fuseki-tdb2-server/
++
++In addition, you will need a copy of Apache Jena Fuseki to get the web pages.
++
++```
++## Set the environment variable FUSEKI_HOME to the location of a
++## Fuseki2 distribution to pick up the admin UI web pages.
++export FUSEKI_HOME=????
++export FUSEKI_BASE="$FUSEKI_HOME"
++# Alternatively, copy or link "webapp" in this directory
++# to the webapp of a distribution.
++
++# Run:
++java -jar target/fuseki-tdb2-server-X.Y.Z.jar --conf config.ttl
++```
++
++where a sample `config.ttl` for a service `/data` storing the database
++in `DB2` is:
++
++```
++@prefix : <#> .
++@prefix fuseki: <http://jena.apache.org/fuseki#> .
++@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
++@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
++@prefix tdb2: <http://jena.apache.org/2016/tdb#> .
++@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .
++
++[] rdf:type fuseki:Server ;
++ fuseki:services (
++ <#service_tdb2>
++ ) .
++
++<#service_tdb2> rdf:type fuseki:Service ;
++ rdfs:label "TDB2 Service (RW)" ;
++ fuseki:name "data" ;
++ fuseki:serviceQuery "query" ;
++ fuseki:serviceQuery "sparql" ;
++ fuseki:serviceUpdate "update" ;
++ fuseki:serviceUpload "upload" ;
++ fuseki:serviceReadWriteGraphStore "data" ;
++ # A separate read-only graph store endpoint:
++ fuseki:serviceReadGraphStore "get" ;
++ fuseki:dataset <#tdb_dataset_readwrite> ;
++ .
++
++<#tdb_dataset_readwrite> rdf:type tdb2:DatasetTDB2 ;
++ tdb2:location "DB2" ;
++ ## This works: tdb2:unionDefaultGraph true ;
++ .
++```
++
++The key difference is the declared `rdf:type` of the dataset.
++
++Note that the Fuseki UI does not provide a way to create TDB2 databases;
++a configuration file must be used. Once setup, upload, query and graph
++editting will be routed to the TDB2 database.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/use-tdb2-cmds.md
----------------------------------------------------------------------
diff --cc jena-db/use-tdb2-cmds.md
index 0000000,0000000..b420c9d
new file mode 100644
--- /dev/null
+++ b/jena-db/use-tdb2-cmds.md
@@@ -1,0 -1,0 +1,21 @@@
++*TDB2 is not compatible with Apache Jena TDB (TDB1).*
++
++The TDB2 command line tools are provided as a single combined jar
++``tdb2-cmds-VERSION.jar` containing all necessary dependencies. Each
++command has help message; the arguments are the mostly the same as TDB1.
++
++* `tdb2.tdbbackup`
++* `tdb2.tdbdump`
++* `tdb2.tdbcompact` (not in v 0.3.0)
++* `tdb2.tdbloader`
++* `tdb2.tdbquery`
++* `tdb2.tdbstats`
++* `tdb2.tdbupdate`
++
++[Command line jar (release builds)](http://central.maven.org/maven2/org/seaborne/mantis/tdb2-cmds/
++
++Example usage:
++
++```
++java -cp JAR tdb2.tdbloader --loc <DB location> file1 file2 ...
++```
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/use-tdb2.md
----------------------------------------------------------------------
diff --cc jena-db/use-tdb2.md
index 0000000,0000000..9208366
new file mode 100644
--- /dev/null
+++ b/jena-db/use-tdb2.md
@@@ -1,0 -1,0 +1,27 @@@
++*TDB2 is not compatible with Apache Jena TDB (TDB1).*
++
++The maven artifact, a non-Apache build, is in maven central:
++```
++ <dependency>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>tdb2</artifactId>
++ <version>0.3.0</version>
++ </dependency>
++```
++
++Simple migration is to use `TDB2Factory` in placeTDFCatory to create
++datasets. `DatasetGraph` objects are now created via `DatabaseMgr`.
++
++Example code: **`TDB2Factory`**
++
++```
++ public static void main(String[] args) {
++ Dataset ds = TDB2Factory.createDatasetGraph() ;
++ Txn.execWrite(ds, ()->{
++ RDFDataMgr.read(ds, "SomeData.ttl");
++ }) ;
++ Txn.execRead(dsg, ()->{
++ RDFDataMgr.write(System.out, ds, Lang.TRIG) ;
++ }) ;
++ }
++```
[23/50] [abbrv] jena git commit: Remove unused,
untested TransIndexMap.
Posted by an...@apache.org.
Remove unused, untested TransIndexMap.
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/71a70fd7
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/71a70fd7
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/71a70fd7
Branch: refs/heads/jena-tdb2
Commit: 71a70fd76ebc35cda26258bad0459e97f9860b04
Parents: 73e2cce
Author: Andy Seaborne <an...@seaborne.org>
Authored: Fri Sep 15 10:57:30 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Fri Sep 15 10:57:30 2017 +0100
----------------------------------------------------------------------
.../seaborne/dboe/trans/data/TransIndexMap.java | 142 -------------------
1 file changed, 142 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/71a70fd7/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransIndexMap.java
----------------------------------------------------------------------
diff --git a/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransIndexMap.java b/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransIndexMap.java
deleted file mode 100644
index 337fd07..0000000
--- a/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransIndexMap.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * 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.dboe.trans.data;
-
-import java.util.Arrays ;
-import java.util.HashMap ;
-import java.util.Iterator ;
-import java.util.Map ;
-
-import org.apache.jena.atlas.lib.Bytes ;
-import org.seaborne.dboe.base.record.Record ;
-import org.seaborne.dboe.base.record.RecordFactory ;
-import org.seaborne.dboe.index.Index ;
-import org.seaborne.dboe.transaction.txn.TransactionalMRSW ;
-
-/** MRSW in-memory "transaction" */
-public class TransIndexMap extends TransactionalMRSW implements Index
-{
- private final Map<ByteArray, ByteArray> index = new HashMap<>() ;
- private final RecordFactory recordFactory ;
-
- public TransIndexMap(RecordFactory recordFactory) {
- super(null) ;
- this.recordFactory = recordFactory ;
- }
-
- @Override
- public Record find(Record record) {
- ByteArray k = wrap(record.getKey()) ;
- ByteArray v = index.get(k) ;
- if ( v == null )
- return null ;
- return record(k, v) ;
- }
-
- @Override
- public boolean contains(Record record) {
- Record r = find(record) ;
- if ( r == null )
- return false ;
- if ( !recordFactory.hasValue() )
- return true ;
- return Bytes.compare(record.getValue(), r.getValue()) == 0 ;
- }
-
- @Override
- public boolean insert(Record record) {
- Record r = find(record) ;
- if ( r != null && r.equals(record) )
- return false ;
- index.put(wrap(record.getKey()), wrap(record.getValue())) ;
- return true ;
- }
-
- @Override
- public boolean delete(Record record) {
- ByteArray x = index.remove(wrap(record.getKey())) ;
- if ( x == null )
- return false ;
- return true ;
- }
-
- @Override
- public Iterator<Record> iterator() {
- return index.entrySet().stream().map(e -> record(e.getKey(), e.getValue())).iterator();
- }
-
- @Override
- public RecordFactory getRecordFactory() {
- return recordFactory ;
- }
-
- @Override
- public boolean isEmpty() {
- return index.isEmpty() ;
- }
-
- @Override
- public void clear() {
- index.clear() ;
- }
-
- @Override
- public void check() {}
-
- @Override
- public long size() {
- return index.size() ;
- }
-
- @Override
- public void sync()
- {}
-
- @Override
- public void close()
- {}
-
- private static ByteArray wrap(byte[] b) { return new ByteArray(b) ; }
- private Record record(ByteArray k, ByteArray v) { return recordFactory.create(k.bytes, v.bytes) ; }
-
- private static class ByteArray
- {
- byte[] bytes ;
- ByteArray(byte[] bytes) { this.bytes = bytes ; }
-
- @Override
- public int hashCode()
- {
- final int prime = 31 ;
- int result = 1 ;
- result = prime * result + Arrays.hashCode(bytes) ;
- return result ;
- }
- @Override
- public boolean equals(Object obj)
- {
- if (this == obj) return true ;
- if (obj == null) return false ;
- if (getClass() != obj.getClass()) return false ;
- ByteArray other = (ByteArray)obj ;
- if (!Arrays.equals(bytes, other.bytes)) return false ;
- return true ;
- }
- }
-
-}
[17/50] [abbrv] jena git commit: Tweak documentation
Posted by an...@apache.org.
Tweak documentation
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/df590825
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/df590825
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/df590825
Branch: refs/heads/jena-tdb2
Commit: df5908256c889b28b4ab18dfa0d9bba18c79490a
Parents: dcfa94e
Author: Andy Seaborne <an...@seaborne.org>
Authored: Mon Sep 4 16:36:35 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Mon Sep 4 16:36:35 2017 +0100
----------------------------------------------------------------------
use-fuseki-tdb2.md | 9 ++++--
use-tdb2-cmds.md | 3 +-
use-tdb2.md | 73 +++++++++----------------------------------------
3 files changed, 20 insertions(+), 65 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/df590825/use-fuseki-tdb2.md
----------------------------------------------------------------------
diff --git a/use-fuseki-tdb2.md b/use-fuseki-tdb2.md
index bafdc30..4c02612 100644
--- a/use-fuseki-tdb2.md
+++ b/use-fuseki-tdb2.md
@@ -2,11 +2,11 @@ There is a combined Fuseki server jar:
Release builds are available from the central maven repository:
-https://central.maven.org/maven2/org/seaborne/mantis/fuseki-tdb2/)
+https://central.maven.org/maven2/org/seaborne/mantis/fuseki-tdb2/
and development builds at:
-https://oss.sonatype.org/content/repositories/snapshots/org/seaborne/mantis/fuseki-tdb2/)
+https://oss.sonatype.org/content/repositories/snapshots/org/seaborne/mantis/fuseki-tdb2/
In addition, you will need a copy of Apache Jena Fuseki to get the web pages.
@@ -15,6 +15,7 @@ In addition, you will need a copy of Apache Jena Fuseki to get the web pages.
## Set the environment variable FUSEKI_HOME to the location of a
## Fuseki2 distribution to pick up the admin UI web pages.
export FUSEKI_HOME=????
+export FUSEKI_BASE="$FUSEKI_HOME"
# Alternatively, copy or link "webapp" in this directory
# to the webapp of a distribution.
@@ -59,4 +60,6 @@ in `DB2` is:
The key difference is the declared `rdf:type` of the dataset.
-Note that the Fuseki UI does not provide a way to create TDB2 databases; a configuration file must be used. Once setup, upload, query and graph editting will be routed to the TDB2 database.
+Note that the Fuseki UI does not provide a way to create TDB2 databases;
+a configuration file must be used. Once setup, upload, query and graph
+editting will be routed to the TDB2 database.
http://git-wip-us.apache.org/repos/asf/jena/blob/df590825/use-tdb2-cmds.md
----------------------------------------------------------------------
diff --git a/use-tdb2-cmds.md b/use-tdb2-cmds.md
index f2846ce..b420c9d 100644
--- a/use-tdb2-cmds.md
+++ b/use-tdb2-cmds.md
@@ -6,6 +6,7 @@ command has help message; the arguments are the mostly the same as TDB1.
* `tdb2.tdbbackup`
* `tdb2.tdbdump`
+* `tdb2.tdbcompact` (not in v 0.3.0)
* `tdb2.tdbloader`
* `tdb2.tdbquery`
* `tdb2.tdbstats`
@@ -13,8 +14,6 @@ command has help message; the arguments are the mostly the same as TDB1.
[Command line jar (release builds)](http://central.maven.org/maven2/org/seaborne/mantis/tdb2-cmds/
-[Development builds (Sonatype snapshot repository)](https://oss.sonatype.org/content/repositories/snapshots/org/seaborne/mantis/tdb2-cmds/)
-
Example usage:
```
http://git-wip-us.apache.org/repos/asf/jena/blob/df590825/use-tdb2.md
----------------------------------------------------------------------
diff --git a/use-tdb2.md b/use-tdb2.md
index 2101437..9208366 100644
--- a/use-tdb2.md
+++ b/use-tdb2.md
@@ -1,74 +1,27 @@
*TDB2 is not compatible with Apache Jena TDB (TDB1).*
-
-TDB2 example:
-
-Set the repositories (see below) and use:
+The maven artifact, a non-Apache build, is in maven central:
```
<dependency>
<groupId>org.seaborne.mantis</groupId>
<artifactId>tdb2</artifactId>
- <version>X.Y.Z</version>
+ <version>0.3.0</version>
</dependency>
```
+Simple migration is to use `TDB2Factory` in placeTDFCatory to create
+datasets. `DatasetGraph` objects are now created via `DatabaseMgr`.
Example code: **`TDB2Factory`**
-For disk location
-
-```
- public static void main(String[] args) {
- Quad q1 = SSE.parseQuad("(_ <s> <p> 1 )") ;
- # In-memory dataset.
- DatasetGraph dsg = TDB2Factory.createDatasetGraph() ;
- # Transactions are required.
- Txn.execWrite(dsg, ()->{
- dsg.add(q1) ;
- }) ;
-
- Txn.execRead(dsg, ()->{
- RDFDataMgr.write(System.out, dsg, Lang.TRIG) ;
- }) ;
- System.out.println("-----------") ;
-
- Quad q2 = SSE.parseQuad("(_ <s> <p> 2 )") ;
- TransactionalSystem txnSystem = ((DatasetGraphTDB)dsg).getTxnSystem() ;
- dsg.begin(ReadWrite.READ);
- Transaction txn = txnSystem.getThreadTransaction() ;
- boolean b = txn.promote() ;
- if ( ! b ) {
- System.out.println("Did not promote");
- throw new RuntimeException() ;
- }
-
- dsg.add(q2) ;
- dsg.commit() ;
- dsg.end() ;
-
- Txn.execRead(dsg, ()->{
- RDFDataMgr.write(System.out, dsg, Lang.TRIG) ;
- }) ;
- }
-```
-
-Maven repositories setup:
-
-For development builds:
-
```
- <repositories>
- <!-- Sonatype snapshot repository -->
- <repository>
- <id>sonatype.public</id>
- <name>Sonatype Snapshots Repository</name>
- <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
- <releases>
- <enabled>false</enabled>
- </releases>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </repository>
- </repositories>
+ public static void main(String[] args) {
+ Dataset ds = TDB2Factory.createDatasetGraph() ;
+ Txn.execWrite(ds, ()->{
+ RDFDataMgr.read(ds, "SomeData.ttl");
+ }) ;
+ Txn.execRead(dsg, ()->{
+ RDFDataMgr.write(System.out, ds, Lang.TRIG) ;
+ }) ;
+ }
```
[19/50] [abbrv] jena git commit: Fix central.maven link
Posted by an...@apache.org.
Fix central.maven link
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/4d02f575
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/4d02f575
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/4d02f575
Branch: refs/heads/jena-tdb2
Commit: 4d02f5750207fc82a801ed3ad4104cc5f98bab38
Parents: cf4b7a8
Author: Andy Seaborne <an...@seaborne.org>
Authored: Mon Sep 4 23:13:48 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Mon Sep 4 23:13:48 2017 +0100
----------------------------------------------------------------------
use-fuseki-tdb2.md | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/4d02f575/use-fuseki-tdb2.md
----------------------------------------------------------------------
diff --git a/use-fuseki-tdb2.md b/use-fuseki-tdb2.md
index 4c02612..e64d99f 100644
--- a/use-fuseki-tdb2.md
+++ b/use-fuseki-tdb2.md
@@ -2,12 +2,7 @@ There is a combined Fuseki server jar:
Release builds are available from the central maven repository:
-https://central.maven.org/maven2/org/seaborne/mantis/fuseki-tdb2/
-
-and development builds at:
-
-https://oss.sonatype.org/content/repositories/snapshots/org/seaborne/mantis/fuseki-tdb2/
-
+http://central.maven.org/maven2/org/seaborne/mantis/fuseki-tdb2-server/
In addition, you will need a copy of Apache Jena Fuseki to get the web pages.
[43/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeNode.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeNode.java
index 0000000,0000000..978896c
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeNode.java
@@@ -1,0 -1,0 +1,1507 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import static org.seaborne.dboe.base.record.Record.keyGT ;
++import static org.seaborne.dboe.base.record.Record.keyLT ;
++import static org.seaborne.dboe.base.record.Record.keyNE ;
++import static org.seaborne.dboe.trans.bplustree.BPT.* ;
++
++import java.util.ArrayList ;
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.apache.jena.atlas.io.IndentedLineBuffer ;
++import org.apache.jena.atlas.io.IndentedWriter ;
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.buffer.PtrBuffer ;
++import org.seaborne.dboe.base.buffer.RecordBuffer ;
++import org.seaborne.dboe.base.page.PageBlockMgr ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.sys.SystemIndex ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++public final class BPTreeNode extends BPTreePage
++{
++ private static Logger log = LoggerFactory.getLogger(BPTreeNode.class) ;
++ @Override protected Logger getLogger() { return log ; }
++
++ /*package*/ Block block ;
++ /** Page id.
++ * Pages are addressed by ints (a page ref does in on-disk blocks)
++ * although blocks are addressed in longs.
++ * 1k pages => 2Tbyte file limit.
++ */
++ /*package*/int id ; // Or block.getId()
++
++ private int parent ;
++ private int count ; // Number of records. Number of pointers is +1
++
++ // "Leaf" of the BPTree is the lowest level of ptr/key splits, not the data blocks.
++ // We need to know this to know which block manager the block pointers refer to.
++ private boolean isLeaf ;
++
++ private RecordBuffer records ;
++ /*package*/ void setRecordBuffer(RecordBuffer r) { records = r ; }
++
++ // Accessed by BPlusTreeFactory
++ /*package*/ PtrBuffer ptrs ;
++ /*package*/ void setPtrBuffer(PtrBuffer pb) { ptrs = pb ; }
++
++ /* B+Tree
++ *
++ * Two block managers :
++ * one for Nodes (BPlusTreePages => BPlusTreeNode)
++ * one for Leaves (RecordBufferPages)
++ * The split key is the held in the highest in the block
++ *
++ * A "leaf" node is a leaf of the B+Tree part, and points to
++ * highest record in a RecordBuffer
++ *
++ * Example for N = 2
++ * 2*N: MaxRec = 4, MaxPtr = 5,
++ * Max-1: HighRec = 3, HighPtr = 4
++ * N-1: MinRec = 1, MinPtr = 2
++ *
++ * which is why a tree of order <2 does not make sense.
++ *
++ *
++ * BPTreeNode:
++ *
++ * +------------------------+
++ * |-| K0 | K1 | K2 | K3 |--|
++ * +------------------------+
++ * | P0 | P1 | P2 | P3 | P4 |
++ * +------------------------+
++ *
++ * +------------------------+
++ * | | K0 | K1 | ** | ** |--|
++ * +------------------------+
++ * | P0 | P1 | P2 | ** | ** |
++ * +------------------------+
++ *
++ * BPTreeRecords -> RecordBuffer:
++ *
++ * +------------------------+
++ * | K0 | K1 | K2 | ** | ** |
++ * +------------------------+
++ *
++ * The size of records blocks and size of tree nodes don't have to be the same.
++ * They use different page managers, and are in different files.
++ *
++ * The minimal tree is one, leaf, root BPTreeNode and one BPTreeRecords page.
++ *
++ * Pictures:
++ * /--\ \--\
++ * means a block with free space introduced between records[i] and records[i+1], ptrs[i+1]/ptrs[i+2]
++ * Lower half is a valid structure (except for overall size)
++ *
++ * /--/ /--\
++ * means a block with free space introduced between records[i] and records[i+1], ptrs[i]/ptrs[i+1]
++ * Upper half is a valid structure (except for overall size)
++ */
++
++ // Branch nodes only need create branch nodes (splitting sideways)
++ // Leaf nodes only create leaf nodes.
++ // The root is an exception.
++
++ private BPTreeNode create(int parent, boolean isLeaf) {
++ return create(bpTree, parent, isLeaf) ;
++ }
++
++ private static BPTreeNode create(BPlusTree bpTree, int parent, boolean isLeaf) {
++ BPTreeNode n = bpTree.getNodeManager().createNode(parent) ;
++ n.isLeaf = isLeaf ;
++ return n ;
++ }
++
++ /*package*/ BPTreeNode(BPlusTree bpTree) {
++ super(bpTree) ;
++ // Other set by BPTreeNodeMgr.formatBPTreeNode
++ }
++
++ // ---- [[TXN]] ** work for transactions.
++ void checkTxn() {}
++ void checkWriteTxn() {}
++
++// static BPTreeNode xensureModifiableRoot(BPTreeNode root, Object state) {
++// BPTreeNode root2 = promote1(root, root, NO_ID)(null, root) ;
++// if ( root != root2 && root.getId() != root2.getId() ) {
++// System.err.println("Cloned root") ;
++// if ( state == null )
++// System.err.println("... no state") ;
++// // [[TXN]] ** Root clone
++// // get state and update root.
++// }
++// return root2 ;
++// }
++
++ // ----
++
++ @Override
++ public void reset(Block block) {
++ this.block = block ;
++ // reformat block (sets record and pointer buffers)
++ BPTreeNodeMgr.formatBPTreeNode(this, bpTree, block, isLeaf, parent, count) ;
++ }
++
++ /** Get the page at slot idx - switch between B+Tree and records files */
++ /*package*/ BPTreePage get(int idx) {
++ if ( false && logging(log) ) {
++ String leafOrNode = isLeaf ? "L" : "N" ;
++ log(log, "%d[%s].get(%d)", id, leafOrNode, idx) ;
++ }
++ int subId = ptrs.get(idx) ;
++ PageBlockMgr<? extends BPTreePage> pbm = getPageBlockMgr() ;
++ // Always get a "read" block - it must be promoted to a "write" block
++ // to update it. Getting a write block is unhelpful as many blocks
++ // during a write operation are only read.
++ return pbm.getRead(subId, this.getId()) ;
++ }
++
++ private PageBlockMgr<? extends BPTreePage> getPageBlockMgr() {
++ if ( isLeaf )
++ return bpTree.getRecordsMgr() ;
++ else
++ return bpTree.getNodeManager() ;
++ }
++
++ // ---------- Public calls.
++ // None of these are called recursively.
++
++ /** Find a record, using the active comparator */
++ public static Record search(BPTreeNode root, Record rec) {
++ root.internalCheckNodeDeep() ;
++ if ( ! root.isRoot() )
++ throw new BPTreeException("Search not starting from the root: " + root) ;
++ AccessPath path = new AccessPath(root) ;
++ Record r = root.internalSearch(path, rec) ;
++ return r ;
++ }
++
++ /** Insert a record - return existing value if any, else null */
++ public static Record insert(BPTreeNode root, Record record) {
++ if ( logging(log) ) {
++ log(log, "** insert(%s) / root=%d", record, root.getId()) ;
++ if ( DumpTree )
++ root.dump() ;
++ }
++
++ if ( !root.isRoot() )
++ throw new BPTreeException("Insert begins but this is not the root") ;
++
++ if ( root.isFull() ) {
++ // Root full - root split is a special case.
++ splitRoot(root) ;
++ if ( DumpTree )
++ root.dump() ;
++ }
++
++ AccessPath path = new AccessPath(root) ;
++ // Root ready - call insert proper.
++ Record result = root.internalInsert(path, record) ;
++
++ root.internalCheckNodeDeep() ;
++
++ if ( logging(log) ) {
++ log(log, "** insert(%s) / finish", record) ;
++ if ( DumpTree )
++ root.dump() ;
++ }
++ return result ;
++ }
++
++ /** Delete a record - return the old value if there was one, else null */
++ public static Record delete(BPTreeNode root, Record rec) {
++ if ( logging(log) ) {
++ log(log, "** delete(%s) / start", rec) ;
++ if ( BPT.DumpTree )
++ root.dump() ;
++ }
++ if ( !root.isRoot() )
++ throw new BPTreeException("Delete begins but this is not the root") ;
++
++ AccessPath path = new AccessPath(root) ;
++
++ if ( root.isLeaf && root.count == 0 ) {
++ // Special case. Just a records block. Allow that to go too small.
++ BPTreePage page = root.get(0) ;
++ if ( BPT.CheckingNode && !(page instanceof BPTreeRecords) )
++ BPT.error("Zero size leaf root but not pointing to a records block") ;
++ trackPath(path, root, 0, page) ;
++ Record r = page.internalDelete(path, rec) ;
++ page.release() ;
++ if ( r != null )
++ root.write() ;
++ if ( BPT.DumpTree )
++ root.dump() ;
++ return r ;
++ }
++
++ // Entry: checkNodeDeep() ;
++ Record v = root.internalDelete(path, rec) ;
++ // Fix the root in case it became empty in deletion process.
++ if ( !root.isLeaf && root.count == 0 ) {
++ reduceRoot(root) ;
++ root.bpTree.newRoot(root) ;
++ root.internalCheckNodeDeep() ;
++ }
++
++ if ( logging(log) ) {
++ log(log, "** delete(%s) / finish", rec) ;
++ if ( BPT.DumpTree )
++ root.dump() ;
++ }
++ return v ;
++ }
++
++ /** Iterator over the pages below that have records between minRec (inclusive) and maxRec(exclusive).
++ * There may be other records as as well.
++ * @param minRec
++ * @param maxRec
++ * @return Iterator<BPTreePage>
++ */
++ Iterator<BPTreePage> iterator(Record minRec, Record maxRec) {
++ if ( minRec != null && maxRec != null && Record.keyGE(minRec, maxRec) )
++ return null ;//throw new IllegalArgumentException("minRec >= maxRec: "+minRec+" >= "+maxRec ) ;
++
++ int x1 = 0 ;
++ if ( minRec != null ) {
++ x1 = findSlot(minRec) ;
++ // If there is an exact match, we still need to go down that place to get the max.
++ // If there is no match, it returns -(i+1) and we need to go down the tree at i.
++ // Same effect - start at x1
++ // TODO Optimization - get max record on min side once and for all if exact match.
++ x1 = apply(x1) ;
++ }
++
++ int x2 = this.getCount() ; // Highest place to look. Inclusive.
++ if ( maxRec != null ) {
++ // If there is an exact match, we need to go down that place to get the record upto max.
++ // If there is no match, it returns -(i+1) and we need to go down the tree at i to get from last key to max (exclusive).
++ // Same effect - start at x2 inclusive.
++ x2 = findSlot(maxRec) ;
++ x2 = apply(x2) ;
++ }
++ // Pages from pointer slots x1 to x2 (inc because while we exclude maxRec,
++ // keys are only a max of the subtree they mark out.
++
++ // XXX Just grab them now - later, keep indexes and fetch on next().
++ // XXX Epoch tracking
++
++ List<BPTreePage> x = new ArrayList<>(x2-x1+1) ;
++ for ( int i = x1 ; i <= x2 ; i++ )
++ x.add(get(i)) ;
++
++ return x.iterator() ;
++ }
++
++// // OUT OF DATE WITH MVCC
++// /**
++// * Returns the id of the records buffer page for this record. Records Buffer
++// * Page NOT read; record may not exist
++// */
++// static int recordsPageId(BPTreeNode node, Record fromRec) {
++// // Used by BPlusTree.iterator
++// // Walk down the B+tree part of the structure ...
++// while (!node.isLeaf) {
++// BPTreePage page = (fromRec == null) ? node.get(0) : node.findHere(null, fromRec) ;
++// // Not a leaf so we can cast safely.
++// BPTreeNode n = (BPTreeNode)page ;
++// // Release if not root.
++// if ( !node.isRoot() )
++// node.release() ;
++// node = n ;
++// }
++// // ... then find the id of the next step down,
++// // but do not touch the records buffer page.
++// int id ;
++// if ( fromRec == null ) {
++// // Just get the lowest starting place.
++// id = node.getPtrBuffer().getLow() ;
++// } else {
++// // Get the right id based on starting record.
++// int idx = node.findSlot(fromRec) ;
++// idx = apply(idx) ;
++// id = node.getPtrBuffer().get(idx) ;
++// }
++// if ( !node.isRoot() )
++// node.release() ;
++// return id ;
++// }
++
++ final static Record minRecord(BPTreeNode root) {
++ AccessPath path = new AccessPath(root) ;
++ return root.internalMinRecord(path) ;
++ }
++
++ final static Record maxRecord(BPTreeNode root) {
++ AccessPath path = new AccessPath(root) ;
++ return root.internalMaxRecord(path) ;
++ }
++
++ @Override
++ protected Record internalMaxRecord(AccessPath path) {
++ BPTreePage page = get(count) ;
++ trackPath(path, this, count, page) ;
++ Record r = page.internalMaxRecord(path) ;
++ page.release() ;
++ return r ;
++ }
++
++ @Override
++ protected Record internalMinRecord(AccessPath path) {
++ BPTreePage page = get(0) ;
++ trackPath(path, this, 0, page) ;
++ Record r = page.internalMinRecord(path) ;
++ page.release() ;
++ return r ;
++ }
++
++ @Override
++ final Record getLowRecord() {
++ return records.getLow() ;
++ }
++
++ @Override
++ final Record getHighRecord() {
++ return records.getHigh() ;
++ }
++
++ // count is the number of pointers.
++
++ @Override
++ public final int getMaxSize() { return bpTree.getParams().getOrder() ; }
++
++ @Override
++ public final int getCount() { return count ; }
++
++ @Override
++ public final void setCount(int count) { this.count = count ; }
++
++ @Override
++ public Block getBackingBlock() { return block ; }
++
++ @Override
++ public BlockMgr getBlockMgr() { return bpTree.getNodeManager().getBlockMgr() ; }
++
++ /** Do not use without great care */
++ public final RecordBuffer getRecordBuffer() { return records ; }
++ /** Do not use without great care */
++ public final PtrBuffer getPtrBuffer() { return ptrs ; }
++
++ final void setParent(int parentId) { this.parent = parentId ; }
++ public final int getParent() { return parent ; }
++
++
++ public final void setIsLeaf(boolean isLeaf) { this.isLeaf = isLeaf ; }
++ public final boolean isLeaf() { return this.isLeaf ; }
++
++ @Override
++ public final int getId() { return id ; }
++
++ @Override
++ public String getRefStr() {
++ return String.format("BPTNode[id=%d]", getBackingBlock().getId()) ;
++ }
++
++ @Override
++ final void write() { bpTree.getNodeManager().write(this) ; }
++
++ final private static void trackPath(AccessPath path, BPTreeNode node, int idx, BPTreePage page) {
++ if ( path != null )
++ path.add(node, idx, page) ;
++ }
++
++ final private static void resetTrackPath(AccessPath path, BPTreeNode node, int idx, BPTreePage page) {
++ if ( path != null ) {
++ path.reset(node, idx, page) ;
++ }
++ }
++
++ @Override
++ final boolean promote() {
++ if ( bpTree.getNodeManager().isWritable(this.getId()) )
++ return false ;
++ // This calls reset is needed.
++ // The id, records buffer and pointer buffers need resetting if the block changed.
++ boolean promoteInPlace = bpTree.state().modifiableNodeBlock(getId()) ;
++ if ( promoteInPlace ) {
++ bpTree.getNodeManager().promoteInPlace(this) ;
++ return false ;
++ } else {
++ Block oldBlock = block ;
++ boolean b = bpTree.getNodeManager().promoteDuplicate(this) ;
++ if ( b ) {
++ bpTree.getNodeManager().getBlockMgr().release(oldBlock);
++ }
++ return b ;
++ }
++ }
++
++ @Override
++ final void release() { bpTree.getNodeManager().release(this) ; }
++
++ @Override
++ final void free() { bpTree.getNodeManager().free(this) ; }
++
++ // ============ SEARCH
++
++ /*
++ * Do a (binary) search of the node to find the record.
++ * Returns:
++ * +ve or 0 => the index of the record
++ * -ve => The insertion point : the immediate higher record or length as (-i-1)
++ * Convert to +ve and decend to find the RecordBuffer with the record in it.
++ */
++
++ @Override
++ final Record internalSearch(AccessPath path, Record rec) {
++ if ( BPT.CheckingNode )
++ internalCheckNode() ;
++ BPTreePage page = findHere(path, rec) ;
++ Record r = page.internalSearch(path, rec) ;
++ page.release() ;
++ return r ;
++ }
++
++ /** Find the next page to look at as we walk down the tree */
++ private final BPTreePage findHere(AccessPath path, Record rec) {
++ int idx = findSlot(rec) ;
++ idx = apply(idx) ;
++ // Find index, or insertion point (immediate higher slot) as (-i-1)
++ // A key is the highest element of the records up to this point
++ // so we search down at slot idx (between something smaller and
++ // something larger).
++ BPTreePage page = get(idx) ;
++ trackPath(path, this, idx, page) ;
++ return page ;
++ }
++
++ // ============ INSERT
++
++ /*
++ * Traverse this page, ensuring the node below is not full before
++ * decending. Therefore there is always space to do the actual insert.
++ */
++
++ @Override
++ final Record internalInsert(AccessPath path, Record record) {
++ if ( logging(log) )
++ log(log, "internalInsert: %s [%s]", record, this) ;
++
++ internalCheckNode() ;
++
++ int idx = findSlot(record) ;
++
++
++ if ( logging(log) )
++ log(log, "internalInsert: idx=%d (=>%d)", idx, apply(idx)) ;
++
++ idx = apply(idx) ;
++ BPTreePage page = get(idx) ;
++ trackPath(path, this, idx, page) ;
++
++ if ( logging(log) )
++ log(log, "internalInsert: next: %s", page) ;
++
++ if ( page.isFull() ) {
++ // Need to split the page before descending.
++ split(path, idx, page) ;
++ // Did it shift the insert index?
++ // Examine the record we pulled up in the split.
++ if ( Record.keyGT(record, records.get(idx)) ) {
++ page.release() ;
++ // Yes. Get the new (upper) page
++ idx = idx + 1 ;
++ page = get(idx) ;
++ path.reset(this, idx, page);
++ }
++ internalCheckNode() ;
++ }
++
++ Record r = page.internalInsert(path, record) ;
++ page.release() ;
++ return r ;
++ }
++
++ /*
++ * Split a non-root node y, held at slot idx in its parent,
++ * which is 'this'and is large enough for a new entry without
++ * another split because we split full blocks on the way down.
++ * Do this by splitting the node in two (call to BPTree.split)
++ * and inserting the new key/pointer pair.
++ * WRITE(y)
++ * WRITE(z)
++ * WRITE(this)
++ */
++ private void split(AccessPath path, int idx, BPTreePage y) {
++ // logging = true ;
++ if ( logging(log) ) {
++ log(log, "split >> y=%s this=%s idx=%d", y.getRefStr(), this.getRefStr(), idx) ;
++ log(log, "split -- %s", y) ;
++ }
++
++ internalCheckNode() ;
++ if ( BPT.CheckingNode ) {
++ if ( !y.isFull() )
++ BPT.error("Node is not full") ;
++ if ( this.ptrs.get(idx) != y.getId() ) {
++ int a = this.ptrs.get(idx) ;
++ int b = y.getId() ;
++ BPT.error("Node to be split isn't in right place [%d/%d]", a, b) ;
++ }
++ }
++ internalCheckNodeDeep() ;
++
++ // Either-Or
++// promotePage(path, this) ;
++// promote1(y, this, idx) ;
++ // Includes promote "this" because "this" is in the path.
++ promotePage(path, y) ;
++
++ Record splitKey = y.getSplitKey() ;
++ splitKey = keyRecord(splitKey) ;
++
++ if ( logging(log) )
++ log(log, "Split key: %s", splitKey) ;
++
++ BPTreePage z = y.split() ;
++ if ( logging(log) ) {
++ log(log, "Split: %s", y) ;
++ log(log, "Split: %s", z) ;
++ }
++
++ // Key only.
++ if ( splitKey.hasSeparateValue() )
++ splitKey = keyRecord(splitKey) ;
++
++ // Insert new node. "add" shuffle's up as well.
++ records.add(idx, splitKey) ;
++ ptrs.add(idx + 1, z.getId()) ;
++ count++ ;
++
++ if ( logging(log) ) {
++ log(log, "split << %s", this) ;
++ log(log, "split << %s", y) ;
++ log(log, "split << %s", z) ;
++ }
++
++ y.write() ;
++ z.write() ;
++ z.release() ;
++ // y.release() ; y release management done by caller.
++ this.write() ;
++ if ( BPT.CheckingNode ) {
++ if ( Record.keyNE(splitKey, y.maxRecord()) )
++ BPT.error("Split key %d but max subtree %s", splitKey, y.maxRecord()) ;
++ internalCheckNodeDeep() ;
++ }
++ }
++
++ @Override
++ final Record getSplitKey() {
++ int ix = params.SplitIndex ;
++ Record split = records.get(ix) ;
++ return split ;
++ }
++
++ /** Split this block - return the split record (key only needed) */
++ @Override
++ final BPTreePage split() {
++ // Median record : will go in parent.
++ int ix = params.SplitIndex ;
++
++ // New block.
++ BPTreeNode z = create(this.parent, isLeaf) ;
++
++ // Leave the low end untouched and copy, and clear the high end.
++ // z becomes the new upper node, not the lower node.
++ // 'this' is the lower block.
++
++ int maxRec = maxRecords() ;
++ // Copy from top of y into z.
++ records.copy(ix + 1, z.records, 0, maxRec - (ix + 1)) ;
++ records.clear(ix, maxRec - ix) ; // Clear copied and median slot
++ records.setSize(ix) ; // Reset size
++
++ ptrs.copy(ix + 1, z.ptrs, 0, params.MaxPtr - (ix + 1)) ;
++ ptrs.clear(ix + 1, params.MaxPtr - (ix + 1)) ;
++ ptrs.setSize(ix + 1) ;
++
++ // Set sizes of subnodes
++ setCount(ix) ; // Median is ix
++ internalCheckNode() ; // y finished
++
++ z.isLeaf = isLeaf ;
++ z.setCount(maxRec - (ix + 1)) ; // Number copied into z
++
++ // Caller puts the blocks in split(int, BTreePage)
++ z.internalCheckNode() ;
++ return z ;
++ }
++
++ /*
++ * Split the root and leave the root block as the root.
++ * This is the only point the height of the tree increases.
++ *
++ * Allocate new blocks.
++ * Copy root low into left
++ * Copy root high into right
++ * Set counts.
++ * Create new root settings (two pointers, one key record)
++ * WRITE(left)
++ * WRITE(right)
++ * WRITE(root)
++ */
++ private static void splitRoot(BPTreeNode root) {
++ BPlusTree bpTree = root.bpTree ;
++
++ if ( BPT.CheckingNode )
++ if ( ! root.isRoot() )
++ BPT.error("Not root: %d (root is id zero)", root.getId()) ;
++ root.internalCheckNode() ;
++ promoteRoot(root) ;
++
++ // Median record
++ int splitIdx = root.params.SplitIndex ;
++ Record rec = root.records.get(splitIdx) ;
++
++ if ( logging(log) ) {
++ log(log, "** Split root %d (%s)", splitIdx, rec) ;
++ log(log, "splitRoot >> %s", root) ;
++ }
++
++ // New blocks.
++ BPTreeNode left = create(bpTree, root.getId(), root.isLeaf) ;
++ BPTreeNode right = create(bpTree, root.getId(), root.isLeaf) ;
++
++ // int maxRecords = maxRecords() ;
++
++ // New left
++ root.records.copy(0, left.records, 0, splitIdx) ;
++ root.ptrs.copy(0, left.ptrs, 0, splitIdx + 1) ;
++ left.count = splitIdx ;
++
++ // New right
++ root.records.copy(splitIdx + 1, right.records, 0, root.maxRecords() - (splitIdx + 1)) ;
++ root.ptrs.copy(splitIdx + 1, right.ptrs, 0, root.params.MaxPtr - (splitIdx + 1)) ;
++ right.count = root.maxRecords() - (splitIdx + 1) ;
++
++ if ( logging(log) ) {
++ log(log, "splitRoot -- left: %s", left) ;
++ log(log, "splitRoot -- right: %s", right) ;
++ }
++
++ // So left.count+right.count = bTree.NumRec-1
++
++ // Clear root by reformatting. New root not a leaf. Has count of 1 after
++ // formatting.
++ BPTreeNodeMgr.formatForRoot(root, false) ;
++ // Make a non-leaf.
++
++ // Insert two subnodes, divided by the median record
++ root.count = 1 ;
++
++ root.records.add(0, rec) ;
++ root.ptrs.setSize(2) ;
++ root.ptrs.set(0, left.getId()) ; // slot 0
++ root.ptrs.set(1, right.getId()) ; // slot 1
++
++ if ( logging(log) ) {
++ log(log, "splitRoot << %s", root) ;
++ log(log, "splitRoot << %s", left) ;
++ log(log, "splitRoot << %s", right) ;
++ }
++
++ left.write() ;
++ right.write() ;
++ left.release() ;
++ right.release() ;
++ root.write() ;
++
++ if ( BPT.CheckingNode ) {
++ root.internalCheckNode() ;
++ left.internalCheckNode() ;
++ right.internalCheckNode() ;
++ }
++ }
++
++ // ============ DELETE
++
++ /*
++ * Delete
++ * Descend, making sure that the node is not minimum size at each descend.
++ * If it is, rebalenace.
++ */
++
++ @Override
++ final Record internalDelete(AccessPath path, Record rec) {
++ if ( logging(log) )
++ log(log, ">> internalDelete(%s) : %s", rec, this) ;
++ internalCheckNode() ;
++
++ int x = findSlot(rec) ;
++ int y = apply(x) ;
++ BPTreePage page = get(y) ;
++ trackPath(path, this, y, page) ;
++
++ if ( page.isMinSize() ) {
++ // Ensure that a node is at least min+1 so a delete can happen.
++ // Can't be the root - we decended in the get().
++ rebalance(path, page, y) ; // Ignore return - need to refind.
++ page.release(); // TODO But rebalance may have freed this?
++ // Rebalance may have moved the record due to shuffling.
++ x = findSlot(rec) ;
++ y = apply(x) ;
++ page = get(y) ;
++ promote1(page, this, y) ;
++ resetTrackPath(path, this, y, page) ;
++ if ( BPT.CheckingNode ) {
++ internalCheckNode() ;
++ page.checkNode() ;
++ }
++ this.write() ;
++ // Needed in case the record being deleted is not in the
++ // tree, which mean there is no work done and
++ // this page is not written.
++ page.write() ;
++ }
++
++ // Go to bottom
++ // Need to return the deleted key/value.
++ Record r2 = page.internalDelete(path, rec) ;
++ if ( x >= 0 ) {
++ // And hence r2 != null.
++ // The deleted key was in the tree as well as the records.
++ // Change to the new key for the subtree.
++ // Path is already promoted by the delete.
++ // promote1(this, ??, ??) ;
++ Record mx = page.maxRecord() ;
++ records.set(x, keyRecord(mx)) ;
++ this.write() ;
++ }
++ if ( logging(log) )
++ log(log, "<< internalDelete(%s) : %s", rec, this) ;
++
++ page.release() ;
++ return r2 ;
++ }
++
++ /*
++ * Reduce the root when it has only one pointer and no records.
++ * WRITE(root)
++ * RELEASE(old child)
++ * This is the only point the height of the tree decreases.
++ */
++
++ private static void reduceRoot(BPTreeNode root) {
++ if ( logging(log) )
++ log(log, "reduceRoot >> %s", root) ;
++
++ if ( BPT.CheckingNode && (!root.isRoot() || root.count != 0) )
++ BPT.error("Not an empty root") ;
++
++ if ( root.isLeaf ) {
++ if ( logging(log) )
++ log(log, "reduceRoot << leaf root") ;
++ return ;
++ }
++
++ // Must have been cloned due to delete lower down
++ promoteRoot(root) ;
++
++ BPTreePage sub = root.get(0) ;
++ promote1(sub, root, 0) ;
++ BPTreeNode n = cast(sub) ;
++ // Can pull up into the root.
++ // Leave root node in same block (rather than swap to new root).
++ BPTreeNodeMgr.formatForRoot(root, n.isLeaf) ;
++ n.records.copy(0, root.records, 0, n.count) ;
++ n.ptrs.copy(0, root.ptrs, 0, n.count + 1) ;
++ root.isLeaf = n.isLeaf ;
++ root.count = n.count ;
++ root.write() ;
++ // Free up.
++ n.free() ;
++ if ( BPT.CheckingNode )
++ root.internalCheckNodeDeep() ;
++
++ if ( logging(log) )
++ log(log, "reduceRoot << %s", root) ;
++ }
++
++ /*
++ * Rebalance "node" at slot idx in parent (this)
++ * The node will then be greater than the minimum size
++ * and one-pass delete is then possible.
++ *
++ * try to shift right, from the left sibling (if exists)
++ * WRITE(left)
++ * WRITE(n)
++ * WRITE(this)
++ * try to shift left, from the right sibling (if exists)
++ * WRITE(right)
++ * WRITE(n)
++ * WRITE(this)
++ * else
++ * merge with left or right sibling
++ * Suboperations do all the write-back of nodes.
++ *
++ * return the page which might be coalesced from left or right..
++ */
++ private BPTreePage rebalance(AccessPath path, BPTreePage node, int idx) {
++ if ( logging(log) ) {
++ log(log, "rebalance(id=%d, idx=%d)", node.getId(), idx) ;
++ log(log, ">> this: %s", this) ;
++ log(log, ">> node: %s", node) ;
++ }
++ internalCheckNode() ;
++// promotePage(path, this) ;
++// promote1(node, this, idx) ;
++ // Includes promote "this"
++ promotePage(path, node) ;
++
++ // Try left first
++ BPTreePage left = null ;
++ if ( idx > 0 )
++ left = get(idx - 1) ;
++
++ // *** SHIFTING : need to change the marker record in the parent.
++ // *** getHighRecord of lower block.
++
++ if ( left != null && !left.isMinSize() ) {
++ if ( logging(log) )
++ log(log, "rebalance/shiftRight") ;
++ // Move elements around.
++ promote1(left, this, idx-1) ;
++
++ shiftRight(left, node, idx - 1) ;
++
++ if ( logging(log) )
++ log(log, "<< rebalance: %s", this) ;
++ if ( BPT.CheckingNode ) {
++ left.checkNode() ;
++ node.checkNode() ;
++ this.internalCheckNode() ;
++ }
++ left.release() ;
++ return node ;
++ }
++
++ BPTreePage right = null ;
++ if ( idx < count )
++ right = get(idx + 1) ;
++
++ if ( right != null && !right.isMinSize() ) {
++ if ( logging(log) )
++ log(log, "rebalance/shiftLeft") ;
++
++ promote1(right, this, idx+1) ;
++
++ shiftLeft(node, right, idx) ;
++
++ if ( logging(log) )
++ log(log, "<< rebalance: %s", this) ;
++ if ( BPT.CheckingNode ) {
++ right.checkNode() ;
++ node.checkNode() ;
++ this.internalCheckNode() ;
++ }
++ if ( left != null )
++ left.release() ;
++ right.release() ;
++ return node ;
++ }
++
++ // Couldn't shift. Collapse two pages.
++ if ( BPT.CheckingNode && left == null && right == null )
++ BPT.error("No siblings") ;
++
++ if ( left != null ) {
++ promote1(left, this, idx-1 ) ;
++ if ( logging(log) )
++ log(log, "rebalance/merge/left: left=%d n=%d [%d]", left.getId(), node.getId(), idx - 1) ;
++ if ( BPT.CheckingNode && left.getId() == node.getId() )
++ BPT.error("Left and n the same: %s", left) ;
++ BPTreePage page = merge(left, node, idx - 1) ;
++ if ( right != null )
++ // HACK : We didn't use it.
++ right.release() ;
++ //left release?
++ return page ;
++ } else {
++ // left == null
++ // rigth != null
++ promote1(right, this, idx+1 ) ;
++ // TODO ** HERE is it tracked correctly? Turmn tracking on, test_clear_02 and enable read checking in Lifecycle track.free.
++ if ( logging(log) )
++ log(log, "rebalance/merge/right: n=%d right=%d [%d]", node.getId(), right.getId(), idx) ;
++ if ( BPT.CheckingNode && right.getId() == node.getId() )
++ BPT.error("N and right the same: %s", right) ;
++ BPTreePage page = merge(node, right, idx) ;
++ return page ;
++ }
++ }
++
++ /** Merge left with right ; fills left, frees right */
++ private BPTreePage merge(BPTreePage left, BPTreePage right, int dividingSlot) {
++ if ( logging(log) ) {
++ log(log, ">> merge(@%d): %s", dividingSlot, this) ;
++ log(log, ">> left: %s", left) ;
++ log(log, ">> right: %s", right) ;
++ }
++
++ // /==\ + key + /==\ ==> /====\
++ Record splitKey = records.get(dividingSlot) ;
++ BPTreePage page = left.merge(right, splitKey) ;
++ // Must release right (not done in merge)
++ if ( logging(log) )
++ log(log, "-- merge: %s", page) ;
++
++ left.write() ;
++ left.release() ;
++ right.free() ;
++
++ if ( page == right )
++ BPT.error("Returned page is not the left") ;
++
++ if ( BPT.CheckingNode ) {
++ if ( isLeaf ) {
++ // If two data blocks, then the split key is not included
++ // (it's already there, with its value).
++ // Size is N+N and max could be odd so N+N and N+N+1 are
++ // possible.
++ if ( left.getCount() + 1 != left.getMaxSize() && left.getCount() != left.getMaxSize() )
++ BPT.error("Inconsistent data node size: %d/%d", left.getCount(), left.getMaxSize()) ;
++ } else if ( !left.isFull() ) {
++ // If not two data blocks, the left side should now be full
++ // (N+N+split)
++ BPT.error("Inconsistent node size: %d/%d", left.getCount(), left.getMaxSize()) ;
++ }
++ }
++
++ // Remove from parent (which is "this")
++ shuffleDown(dividingSlot) ;
++ this.write() ;
++ internalCheckNodeDeep() ;
++ if ( logging(log) ) {
++ log(log, "<< merge: %s", this) ;
++ log(log, "<< left: %s", left) ;
++ }
++ return left ;
++ }
++
++ @Override
++ BPTreePage merge(BPTreePage right, Record splitKey) {
++ return merge(this, splitKey, cast(right)) ;
++ }
++
++ private static BPTreeNode merge(BPTreeNode left, Record splitKey, BPTreeNode right) {
++ // Merge blocks - does not adjust the parent.
++ // Copy right to top of left.
++ // Caller releases 'right' (needed for testing code).
++
++ left.records.add(splitKey) ;
++
++ // Copy over right to top of left.
++ right.records.copyToTop(left.records) ;
++ right.ptrs.copyToTop(left.ptrs) ;
++
++ // Update count
++ left.count = left.count + right.count + 1 ;
++ left.internalCheckNode() ;
++
++ right.records.clear() ;
++ right.ptrs.clear() ;
++ return left ;
++ }
++
++ private void shiftRight(BPTreePage left, BPTreePage right, int i) {
++ if ( logging(log) ) {
++ log(log, ">> shiftRight: this: %s", this) ;
++ log(log, ">> shiftRight: left: %s", left) ;
++ log(log, ">> shiftRight: right: %s", right) ;
++ }
++ Record r1 = records.get(i) ;
++ Record r2 = left.shiftRight(right, r1) ;
++ r2 = keyRecord(r2) ;
++ this.records.set(i, r2) ;
++
++ left.write() ;
++ right.write() ;
++ // Do later -- this.put();
++ if ( logging(log) ) {
++ log(log, "<< shiftRight: this: %s", this) ;
++ log(log, "<< shiftRight: left: %s", left) ;
++ log(log, "<< shiftRight: right: %s", right) ;
++ }
++ }
++
++ private void shiftLeft(BPTreePage left, BPTreePage right, int i) {
++ if ( logging(log) ) {
++ log(log, ">> shiftLeft: this: %s", this) ;
++ log(log, ">> shiftLeft: left: %s", left) ;
++ log(log, ">> shiftLeft: right: %s", right) ;
++ }
++ Record r1 = records.get(i) ;
++ Record r2 = left.shiftLeft(right, r1) ;
++ r2 = keyRecord(r2) ;
++ this.records.set(i, r2) ;
++
++ left.write() ;
++ right.write() ;
++ // Do this later - this.put();
++ if ( logging(log) ) {
++ log(log, "<< shiftLeft: this: %s", this) ;
++ log(log, "<< shiftLeft: left: %s", left) ;
++ log(log, "<< shiftLeft: right: %s", right) ;
++ }
++ }
++
++ @Override
++ Record shiftRight(BPTreePage other, Record splitKey) {
++ BPTreeNode node = cast(other) ;
++ if ( BPT.CheckingNode ) {
++ if ( count == 0 )
++ BPT.error("Node is empty - can't shift a slot out") ;
++ if ( node.isFull() )
++ BPT.error("Destination node is full") ;
++ }
++ // Records: promote moving element, replace with splitKey
++ Record r = this.records.getHigh() ;
++ this.records.removeTop() ;
++ node.records.add(0, splitKey) ;
++
++ // Pointers just shift
++ this.ptrs.shiftRight(node.ptrs) ;
++
++ this.count-- ;
++ node.count++ ;
++ this.internalCheckNode() ;
++ node.internalCheckNode() ;
++ return r ;
++ }
++
++ @Override
++ Record shiftLeft(BPTreePage other, Record splitKey) {
++ BPTreeNode node = cast(other) ;
++ if ( BPT.CheckingNode ) {
++ if ( count == 0 )
++ BPT.error("Node is empty - can't shift a slot out") ;
++ if ( isFull() )
++ BPT.error("Destination node is full") ;
++ }
++ Record r = node.records.getLow() ;
++ // Records: promote moving element, replace with splitKey
++ this.records.add(splitKey) ;
++ node.records.shiftDown(0) ;
++
++ // Pointers just shift
++ this.ptrs.shiftLeft(node.ptrs) ;
++
++ this.count++ ;
++ node.count-- ;
++ return r ;
++ }
++
++ private void shuffleDown(int x) {
++ // x is the index in the parent and may be on eover the end.
++ if ( logging(log) ) {
++ log(log, "ShuffleDown: i=%d count=%d MaxRec=%d", x, count, maxRecords()) ;
++ log(log, "ShuffleDown >> %s", this) ;
++ }
++
++ if ( BPT.CheckingNode && x >= count )
++ BPT.error("shuffleDown out of bounds") ;
++
++ // Just the top to clear
++
++ if ( x == count - 1 ) {
++ records.removeTop() ;
++ ptrs.removeTop() ;
++
++ count-- ;
++ if ( logging(log) ) {
++ log(log, "shuffleDown << Clear top") ;
++ log(log, "shuffleDown << %s", this) ;
++ }
++ internalCheckNode() ;
++ return ;
++ }
++
++ // Shuffle down. Removes key and pointer just above key.
++
++ records.shiftDown(x) ;
++ ptrs.shiftDown(x + 1) ;
++ count-- ;
++ if ( logging(log) )
++ log(log, "shuffleDown << %s", this) ;
++ internalCheckNode() ;
++ }
++
++ // ---- Utilities
++
++ private static final BPTreeNode cast(BPTreePage other) {
++ try {
++ return (BPTreeNode)other ;
++ }
++ catch (ClassCastException ex) {
++ BPT.error("Wrong type: " + other) ;
++ return null ;
++ }
++ }
++
++ final int findSlot(Record rec) {
++ int x = records.find(rec) ;
++ return x ;
++ }
++
++ final boolean isRoot() {
++ // No BPT remembered root node currently
++ // if ( bpTree.root == this ) return true ;
++ return this.parent == BPlusTreeParams.RootParent ;
++ }
++
++ private Record keyRecord(Record record) {
++ return bpTree.getRecordFactory().createKeyOnly(record) ;
++ }
++
++ // Fixup/remove?
++ private final int maxRecords() {
++ return params.MaxRec ;
++ }
++
++ @Override
++ final boolean isFull() {
++ if ( BPT.CheckingNode && count > maxRecords() )
++ BPT.error("isFull: Moby block: %s", this) ;
++
++ // Count is number of records.
++ return count >= maxRecords() ;
++ }
++
++ /** Return true if there are no keys here or below this node */
++ @Override
++ final boolean hasAnyKeys() {
++ if ( this.count > 0 )
++ return true ;
++ if ( !isRoot() )
++ return false ;
++
++ // The root can be zero size and point to a single data block.
++ BPTreePage page = get(0) ;
++ boolean b = page.hasAnyKeys() ;
++ page.release() ;
++ return b ;
++ }
++
++ @Override
++ final boolean isMinSize() {
++ int min = params.getMinRec() ;
++ if ( BPT.CheckingNode && count < min )
++ BPT.error("isMinSize: Dwarf block: %s", this) ;
++
++ return count <= min ;
++ }
++
++ // ========== Other
++
++ @Override
++ public String toString() {
++ StringBuilder b = new StringBuilder() ;
++ if ( isLeaf )
++ b.append("LEAF: ") ;
++ else
++ b.append("NODE: ") ;
++ String labelStr = "??" ;
++ if ( parent >= 0 )
++ labelStr = Integer.toString(parent) ;
++ else if ( parent == BPlusTreeParams.RootParent )
++ labelStr = "root" ;
++ if ( isLeaf )
++ labelStr = labelStr + "/leaf" ;
++
++ b.append(String.format("%d [%s] (size %d) -- ", getId(), labelStr, count)) ;
++ for ( int i = 0 ; i < maxRecords() ; i++ ) {
++ b.append(childStr(i)) ;
++ b.append(" (") ;
++ b.append(recstr(records, i)) ;
++ b.append(") ") ;
++ }
++ b.append(childStr(params.HighPtr)) ;
++ return b.toString() ;
++ }
++
++ @Override
++ protected String typeMark() {
++ String mark = isLeaf() ? "Leaf" : "Node" ;
++ if ( isRoot() )
++ mark = mark+"/Root" ;
++ return mark ;
++ }
++
++ private final String recstr(RecordBuffer records, int idx) {
++ if ( records.isClear(idx) )
++ return "----" ;
++
++ Record r = records._get(idx) ;
++ return r.toString() ;
++ }
++
++ public void dump() {
++ boolean b = BPT.Logging ;
++ BPT.Logging = false ;
++ try { dump(IndentedWriter.stdout) ; }
++ finally { BPT.Logging = b ; }
++ }
++
++ public void dump(IndentedWriter out) {
++ output(out) ;
++ out.ensureStartOfLine() ;
++ out.flush() ;
++ }
++
++ public String dumpToString() {
++ IndentedLineBuffer buff = new IndentedLineBuffer() ;
++ output(buff) ;
++ return buff.asString() ;
++ }
++
++ @Override
++ public void output(IndentedWriter out) {
++ out.print(toString()) ;
++ out.incIndent() ;
++ for ( int i = 0 ; i < count + 1 ; i++ ) {
++ out.println() ;
++ BPTreePage page = get(i) ;
++ page.output(out) ;
++ page.release() ;
++
++ }
++ out.decIndent() ;
++ }
++
++ private String childStr(int i) {
++ if ( i >= ptrs.size() )
++ return "*" ;
++ int x = ptrs.get(i) ;
++ return Integer.toString(x) ;
++ }
++
++ // =========== Checking
++ // internal checks - only if checking
++
++ // Check node does not assume a valid tree - may be in mid-operation.
++ private final void internalCheckNode() {
++ if ( BPT.CheckingNode )
++ checkNode(null, null) ;
++ }
++
++ private final void internalCheckNodeDeep() {
++ // This distrubes trackign operations and blocks.
++ // Hooks left but switch off.
++ if ( false )
++ checkNodeDeep() ;
++ }
++
++ @Override
++ final void checkNode() {
++ checkNode(null, null) ;
++ }
++
++ @Override
++ final void checkNodeDeep() {
++ if ( isRoot() ) {
++ // if ( !isLeaf && count == 0 )
++ // error("Root is of size zero (one pointer) but not a leaf") ;
++ if ( parent != BPlusTreeParams.RootParent )
++ BPT.error("Root parent is wrong") ;
++ // if ( count == 0 )
++ // return ;
++ }
++ checkNodeDeep(null, null) ;
++ }
++
++ // Checks of a single node - no looking at children
++ // min - inclusive; max - inclusive (allows for duplicates)
++ final private void checkNode(Record min, Record max) {
++ int id = getId() ;
++ if ( count != records.size() )
++ BPT.error("Inconsistent: id=%d, count=%d, records.size()=%d : %s", id, count, records.size(), this) ;
++
++ if ( !isLeaf && count + 1 != ptrs.size() )
++ BPT.error("Inconsistent: id=%d, count+1=%d, ptrs.size()=%d ; %s", id, count + 1, ptrs.size(), this) ;
++
++ // No BPT remembered root node currently
++ // if ( bpTree.root != null && !isRoot() && count < params.MinRec)
++ if ( !isRoot() && count < params.MinRec ) {
++ // warning("Runt node: %s", this) ;
++ BPT.error("Runt node: %s", this) ;
++ }
++ if ( !isRoot() && count > maxRecords() )
++ BPT.error("Over full node: %s", this) ;
++ if ( !isLeaf && parent == id )
++ BPT.error("Parent same as id: %s", this) ;
++ Record k = min ;
++
++ // Test records in the allocated area
++ for ( int i = 0 ; i < count ; i++ ) {
++ if ( records.get(i) == null )
++ BPT.error("Node: %d : Invalid record @%d :: %s", id, i, this) ;
++ if ( k != null && keyGT(k, records.get(i)) ) {
++ Record r = records.get(i) ;
++ // keyGT(k, r) ;
++ BPT.error("Node: %d: Not sorted (%d) (%s, %s) :: %s ", id, i, k, r, this) ;
++ }
++ k = records.get(i) ;
++ }
++
++ if ( k != null && max != null && keyGT(k, max) )
++ BPT.error("Node: %d - Record is too high (max=%s):: %s", id, max, this) ;
++
++ if ( SystemIndex.getNullOut() ) {
++ // Test records in the free area
++ for ( int i = count ; i < maxRecords() ; i++ ) {
++ if ( !records.isClear(i) )
++ BPT.error("Node: %d - not clear (idx=%d) :: %s", id, i, this) ;
++ }
++ }
++
++ // Pointer checks.
++ int i = 0 ;
++ // Check not empty at bottom.
++ for ( ; i < count + 1 ; i++ ) {
++ if ( ptrs.get(i) < 0 )
++ BPT.error("Node: %d: Invalid child pointer @%d :: %s", id, i, this) ;
++// // This does Block IO so disturbs tracking.
++// if ( BPT.CheckingTree && isLeaf ) {
++// int ptr = ptrs.get(i) ;
++// BPTreeRecords records = bpTree.getRecordsMgr().getRead(ptr) ;
++// int rid = records.getId() ;
++// if ( rid != ptrs.get(i) )
++// BPT.error("Records: Block @%d has a different id: %d :: %s", rid, i, this) ;
++// int link = records.getLink() ;
++// // Don't check if -1 which does not exist.
++// if ( link != -1 && i != count ) {
++// BPTreeRecords page = bpTree.getRecordsMgr().getRead(ptrs.get(i)) ;
++// int rid2 = page.getLink() ;
++// if ( link != rid2 )
++// BPT.error("Records: Link not to next block @%d/@%d has a different id: %d :: %s", rid, rid2, i, records) ;
++// bpTree.getRecordsMgr().release(page) ;
++// }
++// records.release() ;
++// }
++ }
++
++ // Check empty is empty
++ if ( SystemIndex.getNullOut() ) {
++ int x = params.MaxPtr ;
++ for ( ; i < x ; i++ ) {
++ if ( !ptrs.isClear(i) )
++ BPT.error("Node: %d: Unexpected pointer @%d :: %s", id, i, this) ;
++ }
++ }
++ }
++
++ private void checkNodeDeep(Record min, Record max) {
++ checkNode(min, max) ;
++ int id = getId() ;
++ // Check pointers.
++ int limit = (count == 0) ? 0 : count + 1 ;
++
++ for ( int i = 0 ; i < limit ; i++ ) {
++ Record min1 = min ;
++ Record max1 = max ;
++ BPTreePage n = get(i) ;
++
++ if ( i != count ) {
++ Record keySubTree = n.getHighRecord() ; // high key in immediate
++ // child
++ Record keyHere = records.get(i) ; // key in this
++
++ if ( keySubTree == null )
++ BPT.error("Node: %d: Can't get high record from %d", id, n.getId()) ;
++
++ if ( keySubTree.getKey() == null )
++ BPT.error("Node: %d: Can't get high record is missing it's key from %d", id, n.getId()) ;
++
++ if ( keyHere == null )
++ BPT.error("Node: %d: record is null", id) ;
++
++ if ( keyHere.getKey() == null )
++ BPT.error("Node: %d: Record key is null", id) ;
++
++ if ( keyGT(keySubTree, keyHere) )
++ BPT.error("Node: %d: Child key %s is greater than this key %s", id, keySubTree, keyHere) ;
++
++ Record keyMax = n.maxRecord() ; // max key in subTree
++ Record keyMin = n.internalMinRecord(null) ;
++
++ if ( keyNE(keyHere, keyMax) )
++ BPT.error("Node: %d: Key %s is not the max [%s] of the sub-tree idx=%d", id, keyHere, keyMax, i) ;
++
++ if ( min != null && keyGT(min, keyMin) )
++ BPT.error("Node: %d: Minimun for this node should be %s but it's %s", id, min, keyMin) ;
++ if ( max != null && keyLT(max, keyMax) )
++ BPT.error("Node: %d: Maximum for this node should be %s but it's %s", id, max, keyMax) ;
++ if ( min != null && keyGT(min, keyHere) )
++ BPT.error("Node: %d: Key too small: %s - min should be %s", id, keyHere, min) ;
++ // keyHere == keyMax ??
++ if ( max != null && keyLT(max, keyHere) )
++ BPT.error("Node: %d: Key too large: %s - max should be %s", id, keyHere, max) ;
++ }
++
++ // Look deeper.
++ if ( !(n instanceof BPTreeNode) ) {
++ // Records.
++ n.checkNodeDeep() ;
++ n.release() ;
++ continue ;
++ }
++
++ // Valid pointer?
++ if ( isLeaf ) {
++ if ( !bpTree.getRecordsMgr().getBlockMgr().valid(ptrs.get(i)) )
++ BPT.error("Node: %d: Dangling ptr (records) in block @%d :: %s", id, i, this) ;
++ } else {
++ if ( !bpTree.getNodeManager().valid(ptrs.get(i)) )
++ BPT.error("Node: %d: Dangling ptr in block @%d :: %s", id, i, this) ;
++ }
++
++ // Calc new min/max.
++ if ( i == 0 )
++ max1 = records.get(0) ;
++ else if ( i == count ) {
++ min1 = records.get(count - 1) ;
++ max1 = null ;
++ } else {
++ min1 = records.get(i - 1) ;
++ max1 = records.get(i) ;
++ }
++ // if ( n.parent != id )
++ // error("Node: %d [%d]: Parent/child mismatch :: %s", id, n.parent,
++ // this) ;
++
++ ((BPTreeNode)n).checkNodeDeep(min1, max1) ;
++ n.release() ;
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeNodeMgr.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeNodeMgr.java
index 0000000,0000000..e929762
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeNodeMgr.java
@@@ -1,0 -1,0 +1,228 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import static org.seaborne.dboe.base.block.BlockType.BPTREE_BRANCH ;
++import static org.seaborne.dboe.base.block.BlockType.BPTREE_LEAF ;
++import static org.seaborne.dboe.base.block.BlockType.RECORD_BLOCK ;
++
++import java.nio.ByteBuffer ;
++
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.block.BlockType ;
++import org.seaborne.dboe.base.buffer.PtrBuffer ;
++import org.seaborne.dboe.base.buffer.RecordBuffer ;
++import org.seaborne.dboe.base.page.BlockConverter ;
++import org.seaborne.dboe.base.page.PageBlockMgr ;
++
++/** BPlusTreePageMgr = BPlusTreeNode manager */
++public final class BPTreeNodeMgr extends PageBlockMgr<BPTreeNode>
++{
++ // Only "public" for external very low level tools in development to access this class.
++ // Assume package access.
++
++ public BPTreeNodeMgr(BPlusTree bpTree, BlockMgr blockMgr) {
++ super(new Block2BPTreeNode(bpTree), blockMgr) ;
++ }
++
++ /** Allocate space for a fresh node. */
++ public BPTreeNode createNode(int parent) {
++ BPTreeNode n = create(BPTREE_BRANCH) ;
++ n.setIsLeaf(false) ;
++ n.setParent(parent) ;
++ return n ;
++ }
++
++ @Override
++ public BPTreeNode getWrite(int id) {
++ return super.getWrite(id, BPlusTreeParams.UnsetParent) ;
++ }
++
++ @Override
++ public BPTreeNode getRead(int id) {
++ return super.getRead(id, BPlusTreeParams.UnsetParent) ;
++ }
++
++ /** Fetch a block - fill in the parent id, which is not in the on-disk bytes */
++ @Override
++ public BPTreeNode getRead(int id, int parent) {
++ BPTreeNode n = super.getRead$(id) ;
++ n.setParent(parent);
++ return n ;
++ }
++
++ /** Fetch a block - fill in the parent id, which is not in the on-disk bytes */
++ @Override
++ public BPTreeNode getWrite(int id, int parent) {
++ BPTreeNode n = super.getWrite$(id) ;
++ n.setParent(parent);
++ return n ;
++ }
++
++ boolean isWritable(int id) {
++ //System.err.println("BPTreeNodeMgr.isWritable") ;
++ return false ;
++// return bpTree.state.modifiableNodeBlock(id) ;
++ }
++
++ private static class Block2BPTreeNode implements BlockConverter<BPTreeNode>
++ {
++ private final BPlusTree bpTree ;
++
++ Block2BPTreeNode(BPlusTree bpTree) { this.bpTree = bpTree ; }
++
++ @Override
++ public BPTreeNode createFromBlock(Block block, BlockType bType) {
++ return overlay(bpTree, block, bType == RECORD_BLOCK, 0) ;
++ }
++
++ @Override
++ public BPTreeNode fromBlock(Block block) {
++ // synchronized - needed for multiple reader?
++ synchronized (block) {
++ int x = block.getByteBuffer().getInt(0) ;
++ BlockType type = getType(x) ;
++
++ if ( type != BPTREE_BRANCH && type != BPTREE_LEAF )
++ throw new BPTreeException("Wrong block type: " + type) ;
++ int count = decodeCount(x) ;
++ return overlay(bpTree, block, (type == BPTREE_LEAF), count) ;
++ }
++ }
++
++ @Override
++ public Block toBlock(BPTreeNode node) {
++ // It's manipulated in-place so no conversion needed,
++ // Just the count needs to be fixed up.
++// ByteBuffer bb = node.getBackingByteBuffer() ;
++// BlockType bType = (node.isLeaf ? BPTREE_LEAF : BPTREE_BRANCH ) ;
++
++ Block block = node.getBackingBlock() ;
++ BlockType bType = (node.isLeaf() ? BPTREE_LEAF : BPTREE_BRANCH ) ;
++
++ int c = encodeCount(bType, node.getCount()) ;
++ block.getByteBuffer().putInt(0, c) ;
++ return block ;
++ }
++ }
++
++// // Leaves have a count of -(count+1)
++// // (same as the binary search encoding of "not found")
++// private static final int encCount(int i) { return -(i+1) ; }
++// private static final int decCount(int i) { return -i-1 ; }
++
++ // ----
++ private static final BlockType getType(int x) {
++ return BlockType.extract(x >>> 24) ;
++ }
++
++ private static final int encodeCount(BlockType type, int i) {
++ return (type.id() << 24) | (i & 0x00FFFFFF) ;
++ }
++
++ private static final int decodeCount(int i) {
++ return i & 0x00FFFFFF ;
++ }
++
++ /** byte[] layout.
++ *
++ * New:
++ * 0: Block type
++ * 1-3: Count
++ * Internal nodes:
++ * 4-X: Records: b+tree.MaxRec*record length
++ * X- : Pointers: b+tree.MaxPtr*ptr length
++ */
++ private static BPTreeNode overlay(BPlusTree bpTree, Block block, boolean asLeaf, int count) {
++ // if ( byteBuffer.order() != Const.NetworkOrder )
++ // throw new BTreeException("ByteBuffer in wrong order") ;
++
++ // Fix up the id later.
++ BPTreeNode n = new BPTreeNode(bpTree) ;
++ // The count is zero at the root only.
++ // When the root is zero, it's a leaf.
++ formatBPTreeNode(n, bpTree, block, asLeaf, BPlusTreeParams.NoParent, count) ;
++ return n ;
++ }
++
++ static void formatBPTreeNode(BPTreeNode n, BPlusTree bpTree, Block block, boolean leaf, int parent, int count) {
++ BPlusTreeParams params = bpTree.getParams() ;
++
++ int ptrBuffLen = params.MaxPtr * params.getPtrLength() ;
++ // Only store the key part of records in a B+Tree block
++ // OLD - Node table has real value part - what's going on?
++
++ // [Issue:FREC]
++ // Allocate space for record, key and value, despite slight over
++ // allocation.
++ int recBuffLen = params.MaxRec * params.getRecordLength() ;
++
++ // [Issue:FREC] Should be: key space only.
++ // int recBuffLen = params.MaxRec * params.getKeyLength() ;
++
++ n.id = block.getId().intValue() ;
++ n.setParent(parent) ;
++ n.setCount(count) ;
++ n.setIsLeaf(leaf) ;
++
++ int header = BPlusTreeParams.BlockHeaderSize ;
++ int rStart = header ;
++ int pStart = header + recBuffLen ;
++
++ // Find the number of pointers.
++ int numPtrs = -1 ;
++
++ // The root can have count zero - which means one pointer always.
++ // Junk when creating a new new node.
++ if ( n.getCount() < 0 ) {
++ numPtrs = 0 ;
++ n.setCount(decodeCount(n.getCount())) ;
++ } else
++ numPtrs = n.getCount() + 1 ;
++
++ // Block dependent
++
++ n.block = block ;
++ ByteBuffer byteBuffer = block.getByteBuffer() ;
++
++ // -- Records area
++ byteBuffer.position(rStart) ;
++ byteBuffer.limit(rStart + recBuffLen) ;
++ ByteBuffer bbr = byteBuffer.slice() ;
++ // bbr.limit(recBuffLen) ;
++ n.setRecordBuffer(new RecordBuffer(bbr, n.params.keyFactory, n.getCount())) ;
++
++ // -- Pointers area
++ byteBuffer.position(pStart) ;
++ byteBuffer.limit(pStart + ptrBuffLen) ;
++
++ ByteBuffer bbi = byteBuffer.slice() ;
++ // bbi.limit(ptrBuffLen) ;
++ n.setPtrBuffer(new PtrBuffer(bbi, numPtrs)) ;
++
++ // Reset
++ byteBuffer.rewind() ;
++ }
++
++ static final void formatForRoot(BPTreeNode n, boolean asLeaf) {
++ BPTreeNodeMgr.formatBPTreeNode(n, n.bpTree, n.getBackingBlock(), asLeaf, BPlusTreeParams.RootParent, 0) ;
++ // Tweak for the root-specials. The node is not consistent yet.
++ // Has one dangling pointer.
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreePage.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreePage.java
index 0000000,0000000..a780ad3
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreePage.java
@@@ -1,0 -1,0 +1,135 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.page.Page ;
++import org.seaborne.dboe.base.record.Record ;
++import org.slf4j.Logger ;
++
++/** Abstraction of a B+Tree node - either an branch (BTreeNode) or records block (BTreeRecords) */
++abstract public class BPTreePage implements Page
++{
++ protected BPTreePage(BPlusTree bpTree) {
++ this.bpTree = bpTree ;
++ // bpTree can be null in testing.
++ this.params = ( bpTree == null ) ? null : bpTree.getParams() ;
++ }
++
++ protected final BPlusTree bpTree ;
++ protected final BPlusTreeParams params ;
++
++ /** Short form for logging */
++ protected String label() {
++ return String.format("%d[%s]", getId(), typeMark()) ;
++ }
++
++ protected abstract String typeMark() ;
++
++ protected abstract Logger getLogger() ;
++
++ abstract BlockMgr getBlockMgr() ;
++
++ /** Split in two, return the new (upper) page.
++ * Split key is highest key of the old (lower) page.
++ * Does NOT put pages back to any underlying block manager
++ */
++ abstract BPTreePage split() ;
++
++ /** Move the element from the high end of this to the low end of other,
++ * possible including the splitKey
++ * Return the new split point (highest record in left tree for records; moved element for nodes)
++ */
++ abstract Record shiftRight(BPTreePage other, Record splitKey) ;
++
++ /** Move the element from the high end of other to the high end of this,
++ * possible including the splitKey
++ * Return the new split point (highest record in left tree; moved element for nodes)
++ */
++ abstract Record shiftLeft(BPTreePage other, Record splitKey) ;
++
++ /** Merge this (left) and the page imemdiately to it's right other into a single block
++ */
++ abstract BPTreePage merge(BPTreePage right, Record splitKey) ;
++ //* Return the new page (may be left or right)
++
++ /** Test whether this page is full (has no space for a new element) - used in "insert" */
++ abstract boolean isFull() ;
++
++ /** Test whether this page is of minimum size (removing a record would violate the packing limits) - used in "delete" */
++ abstract boolean isMinSize() ;
++
++ abstract int getCount() ;
++
++ abstract void setCount(int count) ;
++
++ abstract int getMaxSize() ;
++
++ /** Test whether this page has any keys */
++ abstract boolean hasAnyKeys() ;
++
++ /** Find a record; return null if not found */
++ abstract Record internalSearch(AccessPath path, Record rec) ;
++
++ /** Insert a record - return existing value if any, else null - put back modifed blocks */
++ abstract Record internalInsert(AccessPath path, Record record) ;
++
++ /** Delete a record - return the old value if there was one, else null - put back modifed blocks */
++ abstract Record internalDelete(AccessPath path, Record record) ;
++
++ /** Least in page */
++ abstract Record getLowRecord() ;
++
++ /** Greatest in page */
++ abstract Record getHighRecord() ;
++
++ /** Least in subtree */
++ abstract Record internalMinRecord(AccessPath path) ;
++
++ /** Greatest in subtree */
++ abstract Record internalMaxRecord(AccessPath path) ;
++
++ // For checking ...
++
++ /** Least in subtree */
++ Record minRecord() { return internalMinRecord(null) ; }
++
++ /** Greatest in subtree */
++ Record maxRecord() { return internalMaxRecord(null) ; }
++
++ /** Write, or at least ensure will be written */
++ abstract void write() ;
++
++ /** Turn a read page into a write page. Return true if any changes were made. */
++ abstract boolean promote() ;
++
++ /** Mark as no longer needed */
++ abstract void release() ;
++
++ /** Discard with this block (for ever) */
++ abstract void free() ;
++
++ /** Check - just this level.*/
++ abstract void checkNode() ;
++
++ /** Check - here and below */
++ abstract void checkNodeDeep() ;
++
++ /** Return the split point for this record (need only be a key)*/
++ abstract Record getSplitKey() ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeRangeIterator.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeRangeIterator.java
index 0000000,0000000..dd6da35
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeRangeIterator.java
@@@ -1,0 -1,0 +1,152 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import java.util.* ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import org.apache.jena.atlas.lib.InternalErrorException ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.trans.bplustree.AccessPath.AccessStep ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/** Iterator over records that does not assume records block linkage */
++class BPTreeRangeIterator implements Iterator<Record> {
++ static Logger log = LoggerFactory.getLogger(BPTreeRangeIterator.class) ;
++
++ public static Iterator<Record> create(BPTreeNode node, Record minRec, Record maxRec) {
++ if ( minRec != null && maxRec != null && Record.keyGE(minRec, maxRec) )
++ return Iter.nullIter();
++ return new BPTreeRangeIterator(node, minRec, maxRec) ;
++ }
++
++ // Convert path to a stack of iterators
++ private final Deque<Iterator<BPTreePage>> stack = new ArrayDeque<>();
++ final private Record minRecord ;
++ final private Record maxRecord ;
++ private Iterator<Record> current ;
++ private Record slot = null ;
++ private boolean finished = false ;
++
++ BPTreeRangeIterator(BPTreeNode node, Record minRec, Record maxRec ) {
++ this.minRecord = minRec ;
++ this.maxRecord = maxRec ;
++ BPTreeRecords r = loadStack(node) ;
++ current = getRecordsIterator(r, minRecord, maxRecord) ;
++ }
++
++ @Override
++ public boolean hasNext() {
++ if ( finished )
++ return false ;
++ if ( slot != null )
++ return true ;
++ while(current != null && !current.hasNext()) {
++ current = moveOnCurrent() ;
++ }
++ if ( current == null ) {
++ end() ;
++ return false ;
++ }
++ slot = current.next() ;
++ return true ;
++
++ }
++
++ // Move across the head of the stack until empty - then move next level.
++ private Iterator<Record> moveOnCurrent() {
++ Iterator<BPTreePage> iter = null ;
++ while(!stack.isEmpty()) {
++ iter = stack.peek() ;
++ if ( iter.hasNext() )
++ break ;
++ stack.pop() ;
++ }
++
++ if ( iter == null || ! iter.hasNext() )
++ return null ;
++ BPTreePage p = iter.next() ;
++ BPTreeRecords r = null ;
++ if (p instanceof BPTreeNode) {
++ r = loadStack((BPTreeNode)p) ;
++ }
++ else {
++ r = (BPTreeRecords)p ;
++ }
++ return getRecordsIterator(r, minRecord, maxRecord) ;
++ }
++
++ // ---- Places we touch blocks.
++
++ private static Iterator<Record> getRecordsIterator(BPTreeRecords records, Record minRecord, Record maxRecord) {
++ records.bpTree.startReadBlkMgr();
++ Iterator<Record> iter = records.getRecordBuffer().iterator(minRecord, maxRecord) ;
++ records.bpTree.finishReadBlkMgr();
++ return iter ;
++ }
++
++ private BPTreeRecords loadStack(BPTreeNode node) {
++ AccessPath path = new AccessPath(null) ;
++ node.bpTree.startReadBlkMgr();
++
++ if ( minRecord == null )
++ node.internalMinRecord(path) ;
++ else
++ node.internalSearch(path, minRecord) ;
++ List<AccessStep> steps = path.getPath() ;
++ for ( AccessStep step : steps ) {
++ BPTreeNode n = step.node ;
++ Iterator<BPTreePage> it = n.iterator(minRecord, maxRecord) ;
++ if ( it == null || ! it.hasNext() )
++ continue ;
++ BPTreePage p = it.next() ;
++ stack.push(it) ;
++ }
++ BPTreePage p = steps.get(steps.size()-1).page ;
++ if ( ! ( p instanceof BPTreeRecords ) )
++ throw new InternalErrorException("Last path step not to a records block") ;
++ node.bpTree.finishReadBlkMgr();
++ return (BPTreeRecords)p ;
++ }
++
++ // ----
++
++ private void end() {
++ finished = true ;
++ current = null ;
++ }
++
++ // ----
++
++ public void close() {
++ if ( ! finished )
++ end() ;
++ }
++
++ @Override
++ public Record next() {
++ if ( ! hasNext() )
++ throw new NoSuchElementException() ;
++ Record r = slot ;
++ if ( r == null )
++ throw new InternalErrorException("Null slot after hasNext is true") ;
++ slot = null ;
++ return r ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeRecords.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeRecords.java
index 0000000,0000000..e4e8e76
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeRecords.java
@@@ -1,0 -1,0 +1,388 @@@
++/*
++ * 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.dboe.trans.bplustree ;
++
++import static java.lang.String.format ;
++import static org.apache.jena.atlas.lib.Alg.decodeIndex ;
++import static org.seaborne.dboe.trans.bplustree.BPT.CheckingNode ;
++import static org.seaborne.dboe.trans.bplustree.BPT.promotePage ;
++
++import org.apache.jena.atlas.io.IndentedWriter ;
++import org.seaborne.dboe.base.StorageException ;
++import org.seaborne.dboe.base.block.Block ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.buffer.RecordBuffer ;
++import org.seaborne.dboe.base.page.Page ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPage ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/**
++ * B+Tree wrapper over a block of records in a RecordBufferPage.
++ * This class adds no persistent state to a RecordBufferPage.
++ */
++public final class BPTreeRecords extends BPTreePage {
++ private static Logger log = LoggerFactory.getLogger(BPTreeRecords.class) ;
++
++ @Override
++ protected Logger getLogger() {
++ return log ;
++ }
++
++ private final RecordBufferPage rBuffPage ;
++ private final BPTreeRecordsMgr bprRecordsMgr ;
++ private RecordBuffer rBuff ; // Used heavily. Derived from
++ // rBuffPage
++
++ BPTreeRecords(BPTreeRecordsMgr mgr, RecordBufferPage rbp) {
++ super(mgr.getBPTree()) ;
++ this.bprRecordsMgr = mgr ;
++ rBuffPage = rbp ;
++ rBuff = rBuffPage.getRecordBuffer() ;
++ }
++
++ RecordBufferPage getRecordBufferPage() {
++ return rBuffPage ;
++ }
++
++ RecordBuffer getRecordBuffer() {
++ return rBuff ;
++ }
++
++ public final Record get(int idx) {
++ return rBuff.get(idx) ;
++ }
++
++ @Override
++ public final Block getBackingBlock() {
++ return rBuffPage.getBackingBlock() ;
++ }
++
++ @Override
++ public BlockMgr getBlockMgr() {
++ return bpTree.getRecordsMgr().getBlockMgr() ;
++ }
++
++ @Override
++ public void reset(Block block) {
++ rBuffPage.reset(block) ;
++ rBuff = rBuffPage.getRecordBuffer() ;
++ }
++
++ int getLink() {
++ return rBuffPage.getLink() ;
++ }
++
++ @Override
++ public boolean isFull() {
++ return (rBuff.size() >= rBuff.maxSize()) ;
++ }
++
++ @Override
++ public boolean hasAnyKeys() {
++ return rBuff.size() > 0 ;
++ }
++
++ @Override
++ public boolean isMinSize() {
++ // 50% packing minimum.
++ // If of max length 5 (i.e. odd), min size is 2. Integer division works.
++ return (rBuff.size() <= rBuff.maxSize() / 2) ;
++ }
++
++ @Override
++ Record internalSearch(AccessPath path, Record rec) {
++ int i = rBuff.find(rec) ;
++ if ( i < 0 )
++ return null ;
++ return rBuff.get(i) ;
++ }
++
++ @Override
++ final public void write() {
++ bprRecordsMgr.write(this) ;
++ }
++
++ @Override
++ final boolean promote() {
++ if ( bprRecordsMgr.isWritable(getId()) )
++ return false ;
++ // reset() will be called if necessary.
++ boolean promoteInPlace = (bpTree == null) ? true : bpTree.state().modifiableRecordsBlock(getId()) ;
++
++ if ( promoteInPlace ) {
++ bprRecordsMgr.promoteInPlace(this) ;
++ // TODO Is this needed?
++ // Is this replicated in BPTreeNode?
++ if ( getBackingBlock().isReadOnly() )
++ bprRecordsMgr.getBlockMgr().promote(getBackingBlock()) ;
++ return false ;
++ } else {
++ Block oldBlock = getBackingBlock() ;
++ boolean b = bprRecordsMgr.promoteDuplicate(this) ;
++ if ( b )
++ bprRecordsMgr.getBlockMgr().release(oldBlock) ;
++ return b ;
++ }
++
++ }
++
++ @Override
++ final public void release() {
++ bprRecordsMgr.release(this) ;
++ }
++
++ @Override
++ final public void free() {
++ bprRecordsMgr.free(this) ;
++ }
++
++ @Override
++ Record internalInsert(AccessPath path, Record record) {
++ // Delay promotion until we know change will happen.
++ int i = rBuff.find(record) ;
++ Record r2 = null ;
++ if ( i < 0 ) {
++ i = decodeIndex(i) ;
++ if ( rBuff.size() >= rBuff.maxSize() )
++ throw new StorageException("RecordBlock.put overflow") ;
++ promotePage(path, this) ;
++ rBuff.add(i, record) ;
++ } else {
++ r2 = rBuff.get(i) ;
++ if ( Record.compareByKeyValue(record, r2) != 0 ) {
++ // Replace : return old
++ promotePage(path, this) ;
++ rBuff.set(i, record) ;
++ } else
++ // No promotion, no write
++ return r2 ;
++ }
++ write() ;
++ return r2 ;
++ }
++
++ @Override
++ Record internalDelete(AccessPath path, Record record) {
++ int i = rBuff.find(record) ;
++ if ( i < 0 )
++ return null ;
++ promotePage(path, this) ;
++ Record r2 = rBuff.get(i) ;
++ rBuff.remove(i) ;
++ write() ;
++ return r2 ;
++ }
++
++ @Override
++ public Record getSplitKey() {
++ int splitIdx = rBuff.size() / 2 - 1 ;
++ Record r = rBuff.get(splitIdx) ;
++ return r ;
++ }
++
++ /**
++ * Split: place old high half in 'other'. Return the new (upper)
++ * BPTreeRecords(BPTreePage).
++ * Split is the high end of the low page.
++ */
++ @Override
++ public BPTreePage split() {
++ BPTreeRecords other = insertNewPage() ;
++ int splitIdx = rBuff.size() / 2 - 1 ;
++ Record r = rBuff.get(splitIdx) ; // Only need key for checking later.
++ int moveLen = rBuff.size() - (splitIdx + 1) ; // Number to move.
++ // Copy high end to new.
++ rBuff.copy(splitIdx + 1, other.getRecordBufferPage().getRecordBuffer(), 0, moveLen) ;
++ rBuff.clear(splitIdx + 1, moveLen) ;
++ rBuff.setSize(splitIdx + 1) ;
++
++ if ( CheckingNode ) {
++ if ( !Record.keyEQ(r, maxRecord()) ) {
++ System.err.println(rBuff) ;
++ System.err.println(other.rBuff) ;
++ error("BPTreeRecords.split: Not returning expected record") ;
++ }
++ }
++ return other ;
++ }
++
++ private BPTreeRecords insertNewPage() {
++ // MVCC - link can not be maintained.
++ if ( false /* ! bpTree.isTransaction() */ ) {
++ BPTreeRecords other = create(rBuffPage.getLink()) ;
++ rBuffPage.setLink(other.getId()) ;
++ return other ;
++ }
++ BPTreeRecords other = create(Page.NO_ID) ;
++ rBuffPage.setLink(Page.NO_ID) ;
++ return other ;
++ }
++
++ private BPTreeRecords create(int linkId) {
++ BPTreeRecords newPage = bprRecordsMgr.create() ;
++ newPage.getRecordBufferPage().setLink(linkId) ;
++ return newPage ;
++ }
++
++ @Override
++ public Record shiftRight(BPTreePage other, Record splitKey) {
++ // Error checking by RecordBuffer
++ BPTreeRecords page = cast(other) ;
++ rBuff.shiftRight(page.rBuff) ;
++ if ( rBuff.size() == 0 )
++ return null ;
++ return rBuff.getHigh() ;
++ }
++
++ @Override
++ public Record shiftLeft(BPTreePage other, Record splitKey) {
++ // Error checking by RecordBuffer
++ BPTreeRecords page = cast(other) ;
++ rBuff.shiftLeft(page.rBuff) ;
++ if ( rBuff.size() == 0 )
++ return null ;
++ return rBuff.getHigh() ;
++ }
++
++ @Override
++ BPTreePage merge(BPTreePage right, Record splitKey) {
++ // Split key ignored - it's for the B+Tree case of pushing down a key
++ // Records blocks have all the key/values in them anyway.
++ return merge(this, cast(right)) ;
++ }
++
++ private static BPTreeRecords merge(BPTreeRecords left, BPTreeRecords right) {
++ // Copy right to top of left.
++ // The other way round needs a shift as well.
++ right.rBuff.copyToTop(left.rBuff) ;
++ // Same as: right.rBuff.copy(0, left.rBuff, left.rBuff.size(),
++ // right.rBuff.size()) ;
++ right.rBuff.clear() ;
++
++ // The right page is released by the caller. left is still in use.
++ // So the test code can poke around in the right block after merge.
++ // left.bpTree.getRecordsMgr().release(left.getId()) ;
++
++ // Fix up the link chain.
++ left.rBuffPage.setLink(right.rBuffPage.getLink()) ;
++ return left ;
++ }
++
++ private static BPTreeRecords cast(BPTreePage page) {
++ try {
++ return (BPTreeRecords)page ;
++ }
++ catch (ClassCastException ex) {
++ error("Wrong type: " + page) ;
++ return null ;
++ }
++ }
++
++ @Override
++ final public Record internalMinRecord(AccessPath path) {
++ return getLowRecord() ;
++ }
++
++ @Override
++ final public Record internalMaxRecord(AccessPath path) {
++ return getHighRecord() ;
++ }
++
++ private static void error(String msg, Object... args) {
++ msg = format(msg, args) ;
++ System.out.println(msg) ;
++ System.out.flush() ;
++ throw new BPTreeException(msg) ;
++ }
++
++ @Override
++ public final Record getLowRecord() {
++ if ( rBuff.size() == 0 )
++ return null ;
++ return rBuff.getLow() ;
++ }
++
++ @Override
++ public final Record getHighRecord() {
++ if ( rBuff.size() == 0 )
++ return null ;
++ return rBuff.getHigh() ;
++ }
++
++ @Override
++ public final int getMaxSize() {
++ return rBuff.maxSize() ;
++ }
++
++ @Override
++ public final int getCount() {
++ return rBuff.size() ;
++ }
++
++ @Override
++ public final void setCount(int count) {
++ rBuff.setSize(count) ;
++ }
++
++ @Override
++ public String toString() {
++ return String.format("BPTreeRecords[id=%d, link=%d]: %s", getId(), getLink(), rBuff.toString()) ;
++ }
++
++ @Override
++ protected String typeMark() {
++ return "Data" ;
++ }
++
++ @Override
++ public final void checkNode() {
++ if ( !CheckingNode )
++ return ;
++ if ( rBuff.size() < 0 || rBuff.size() > rBuff.maxSize() )
++ error("Misized: %s", this) ;
++
++ for ( int i = 1 ; i < getCount() ; i++ ) {
++ Record r1 = rBuff.get(i - 1) ;
++ Record r2 = rBuff.get(i) ;
++ if ( Record.keyGT(r1, r2) )
++ error("Not sorted: %s", this) ;
++ }
++ }
++
++ @Override
++ public final void checkNodeDeep() {
++ checkNode() ;
++ }
++
++ @Override
++ public int getId() {
++ return rBuffPage.getId() ;
++ }
++
++ @Override
++ public String getRefStr() {
++ return String.format("BPTRecord[id=%d]", getBackingBlock().getId()) ;
++ }
++
++ @Override
++ public void output(IndentedWriter out) {
++ out.print(toString()) ;
++ }
++}
[45/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/AbstractTestChannel.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/AbstractTestChannel.java
index 0000000,0000000..ae14bab
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/AbstractTestChannel.java
@@@ -1,0 -1,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.dboe.base.file;
++
++import java.nio.ByteBuffer ;
++
++import org.junit.Assert ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.BufferChannel ;
++
++public abstract class AbstractTestChannel extends Assert
++{
++ protected abstract BufferChannel open() ;
++
++ private BufferChannel store ;
++ @Before public void before() { store = open() ; }
++ @After public void after() { store.close() ; }
++
++ static final int blkSize = 100 ;
++
++ protected static ByteBuffer data(int len)
++ {
++ ByteBuffer b = ByteBuffer.allocate(len) ;
++ for (int i = 0 ; i < len ; i++ )
++ b.put((byte)(i&0xFF)) ;
++ b.clear() ;
++ return b ;
++ }
++
++ protected static boolean same(ByteBuffer bb1, ByteBuffer bb2)
++ {
++ if ( bb1.capacity() != bb2.capacity() ) return false ;
++ bb1.clear() ;
++ bb2.clear() ;
++ for ( int i = 0 ; i < bb1.capacity() ; i++ )
++ if ( bb1.get(i) != bb2.get(i) ) return false ;
++ return true ;
++ }
++
++ @Test public void storage_01()
++ {
++ assertEquals(0, store.size()) ;
++ }
++
++ @Test public void storage_02()
++ {
++ ByteBuffer b = data(blkSize) ;
++ store.write(b) ;
++ long x = store.size() ;
++ assertEquals(blkSize, x) ;
++ }
++
++ @Test public void storage_03()
++ {
++ ByteBuffer b1 = data(blkSize) ;
++ long posn = store.position() ;
++ store.write(b1) ;
++ ByteBuffer b9 = ByteBuffer.allocate(blkSize) ;
++ int r = store.read(b9, posn) ;
++ assertEquals(blkSize, r) ;
++ assertTrue(same(b1, b9)) ;
++ }
++
++ @Test public void storage_04()
++ {
++ ByteBuffer b1 = data(blkSize) ;
++ ByteBuffer b2 = data(blkSize/2) ;
++
++ store.write(b2, 0) ;
++ store.write(b1, 0) ;
++
++ assertEquals(blkSize, store.size()) ;
++ ByteBuffer b9 = ByteBuffer.allocate(5) ;
++ int z = store.read(b9) ;
++ assertEquals(5, z) ;
++ }
++
++ @Test public void storage_05()
++ {
++ ByteBuffer b1 = data(blkSize) ;
++ ByteBuffer b1a = ByteBuffer.allocate(blkSize) ;
++ ByteBuffer b2 = data(blkSize/2) ;
++ ByteBuffer b2a = ByteBuffer.allocate(blkSize/2) ;
++ store.write(b1) ;
++ store.write(b2) ;
++ store.position(0) ;
++ store.read(b1a) ;
++ assertTrue(same(b1, b1a)) ;
++ store.read(b2a) ;
++ assertTrue(same(b2, b2a)) ;
++ }
++
++ @Test public void storage_06()
++ {
++ ByteBuffer b1 = data(blkSize) ;
++ store.write(b1) ;
++ store.truncate(0) ;
++ assertEquals(0, store.size()) ;
++ // Check for:
++ // http://bugs.sun.com/view_bug.do?bug_id=6191269
++ assertEquals(0, store.position()) ;
++ }
++
++ @Test public void storage_07()
++ {
++ ByteBuffer b1 = data(blkSize) ;
++ store.write(b1) ;
++ store.position(10) ;
++ b1.rewind() ;
++ store.write(b1) ;
++ assertEquals(blkSize+10, store.size()) ;
++ }
++
++
++ @Test public void storage_08()
++ {
++ ByteBuffer b1 = data(blkSize) ;
++ ByteBuffer b2 = data(blkSize) ;
++ store.write(b1) ;
++ store.write(b2) ;
++ store.position(10) ;
++ b1.rewind() ;
++ store.write(b1) ;
++ assertEquals(2*blkSize, store.size()) ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TS_File.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TS_File.java
index 0000000,0000000..368ffb4
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TS_File.java
@@@ -1,0 -1,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.dboe.base.file;
++
++import org.junit.runner.RunWith ;
++import org.junit.runners.Suite ;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestMetaFile.class
++ , TestSegmentedMemBuffer.class
++ , TestChannelMem.class
++ , TestChannelFile.class
++
++ , TestBlockAccessMem.class
++ , TestBlockAccessByteArray.class
++ , TestBlockAccessDirect.class
++ , TestBlockAccessMapped.class
++
++ , TestBinaryDataMem.class
++ , TestBinaryDataFileWriteBufferedMem.class
++ , TestBinaryDataRAFInitial.class
++ , TestBinaryDataRAF.class
++ , TestBinaryDataFileWriteBufferedFile.class
++
++ , TestProcessFileLock.class
++})
++
++
++public class TS_File
++{
++ public static String FILE = "target/test-read-append-file" ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBinaryDataFileWriteBufferedFile.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBinaryDataFileWriteBufferedFile.java
index 0000000,0000000..50adda1
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBinaryDataFileWriteBufferedFile.java
@@@ -1,0 -1,0 +1,35 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.seaborne.dboe.base.file.BinaryDataFile ;
++import org.seaborne.dboe.base.file.BinaryDataFileRandomAccess ;
++import org.seaborne.dboe.base.file.BinaryDataFileWriteBuffered ;
++
++public class TestBinaryDataFileWriteBufferedFile extends AbstractTestBinaryDataFile {
++ public static String FILE = TS_File.FILE ;
++
++ @Override
++ protected BinaryDataFile createBinaryDataFile() {
++ FileOps.delete(FILE);
++ BinaryDataFileRandomAccess file = new BinaryDataFileRandomAccess(FILE) ;
++ return new BinaryDataFileWriteBuffered(file) ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBinaryDataFileWriteBufferedMem.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBinaryDataFileWriteBufferedMem.java
index 0000000,0000000..69c7f77
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBinaryDataFileWriteBufferedMem.java
@@@ -1,0 -1,0 +1,31 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.seaborne.dboe.base.file.BinaryDataFile ;
++import org.seaborne.dboe.base.file.BinaryDataFileMem ;
++import org.seaborne.dboe.base.file.BinaryDataFileWriteBuffered ;
++
++public class TestBinaryDataFileWriteBufferedMem extends AbstractTestBinaryDataFile {
++ @Override
++ protected BinaryDataFile createBinaryDataFile() {
++ BinaryDataFileMem file = new BinaryDataFileMem() ;
++ return new BinaryDataFileWriteBuffered(file) ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBinaryDataMem.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBinaryDataMem.java
index 0000000,0000000..c519029
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBinaryDataMem.java
@@@ -1,0 -1,0 +1,31 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.seaborne.dboe.base.file.BinaryDataFile ;
++import org.seaborne.dboe.base.file.BinaryDataFileMem ;
++
++public class TestBinaryDataMem extends AbstractTestBinaryDataFile {
++
++ @Override
++ protected BinaryDataFile createBinaryDataFile() {
++ return new BinaryDataFileMem() ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBinaryDataRAF.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBinaryDataRAF.java
index 0000000,0000000..f4ef7fc
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBinaryDataRAF.java
@@@ -1,0 -1,0 +1,33 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.seaborne.dboe.base.file.BinaryDataFile ;
++import org.seaborne.dboe.base.file.BinaryDataFileRandomAccess ;
++
++public class TestBinaryDataRAF extends AbstractTestBinaryDataFile {
++ public static String FILE = TS_File.FILE ;
++
++ @Override
++ protected BinaryDataFile createBinaryDataFile() {
++ FileOps.delete(FILE);
++ return new BinaryDataFileRandomAccess(FILE) ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBinaryDataRAFInitial.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBinaryDataRAFInitial.java
index 0000000,0000000..0a572e2
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBinaryDataRAFInitial.java
@@@ -1,0 -1,0 +1,57 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.apache.jena.atlas.RuntimeIOException ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.BinaryDataFileRandomAccess ;
++import static org.junit.Assert.* ;
++
++// Additional tests that do not want the @Before/@After of AbstractTestBinaryDataFile
++public class TestBinaryDataRAFInitial {
++ public static String FILE = TS_File.FILE ;
++ private BinaryDataFileRandomAccess file ;
++
++ @Test public void open_01() {
++ file = new BinaryDataFileRandomAccess(FILE) ;
++ assertFalse(file.isOpen()) ;
++ file.open();
++ assertTrue(file.isOpen()) ;
++ file.close() ;
++ assertFalse(file.isOpen()) ;
++ }
++
++ @Test (expected=RuntimeIOException.class)
++ public void open_02() {
++ file = new BinaryDataFileRandomAccess(FILE) ;
++ file.open();
++ file.close() ;
++ file.sync();
++ }
++
++ @Test (expected=RuntimeIOException.class)
++ public void open_03() {
++ file = new BinaryDataFileRandomAccess(FILE) ;
++ file.open();
++ file.close() ;
++ file.truncate(0);
++ }
++
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBlockAccessByteArray.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBlockAccessByteArray.java
index 0000000,0000000..37881d1
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBlockAccessByteArray.java
@@@ -1,0 -1,0 +1,32 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.seaborne.dboe.base.file.BlockAccess ;
++import org.seaborne.dboe.base.file.BlockAccessByteArray ;
++
++public class TestBlockAccessByteArray extends AbstractTestBlockAccessVarSize
++{
++
++ @Override
++ protected BlockAccess make()
++ {
++ return new BlockAccessByteArray("test") ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBlockAccessDirect.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBlockAccessDirect.java
index 0000000,0000000..2b0605f
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBlockAccessDirect.java
@@@ -1,0 -1,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.dboe.base.file;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.junit.AfterClass ;
++import org.seaborne.dboe.ConfigTestDBOE ;
++import org.seaborne.dboe.base.file.BlockAccess ;
++import org.seaborne.dboe.base.file.BlockAccessDirect ;
++
++public class TestBlockAccessDirect extends AbstractTestBlockAccessFixedSize
++{
++ static String filename = ConfigTestDBOE.getTestingDir()+"/test-file-access-direct" ;
++
++ static final int BlockSize = 50 ;
++ public TestBlockAccessDirect()
++ {
++ super(BlockSize) ;
++ }
++
++ @AfterClass public static void cleanup() { FileOps.deleteSilent(filename) ; }
++
++ @Override
++ protected BlockAccess make()
++ {
++ FileOps.deleteSilent(filename) ;
++ return new BlockAccessDirect(filename, BlockSize) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBlockAccessMapped.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBlockAccessMapped.java
index 0000000,0000000..4223ebb
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBlockAccessMapped.java
@@@ -1,0 -1,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.dboe.base.file;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.junit.AfterClass ;
++import org.seaborne.dboe.ConfigTestDBOE ;
++import org.seaborne.dboe.base.file.BlockAccess ;
++import org.seaborne.dboe.base.file.BlockAccessMapped ;
++
++public class TestBlockAccessMapped extends AbstractTestBlockAccessFixedSize
++{
++ static String filename = ConfigTestDBOE.getTestingDir()+"/test-file-access-mapped" ;
++
++ static final int BlockSize = 64 ;
++ public TestBlockAccessMapped()
++ {
++ super(BlockSize) ;
++ }
++
++ @AfterClass public static void cleanup() { FileOps.deleteSilent(filename) ; }
++
++ static int counter = 0 ;
++
++ @Override
++ protected BlockAccess make()
++ {
++ String fn = filename + "-"+(counter++) ;
++ FileOps.deleteSilent(fn) ;
++ return new BlockAccessMapped(fn, BlockSize) ;
++
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBlockAccessMem.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBlockAccessMem.java
index 0000000,0000000..78a219f
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestBlockAccessMem.java
@@@ -1,0 -1,0 +1,37 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.seaborne.dboe.base.file.BlockAccess ;
++import org.seaborne.dboe.base.file.BlockAccessMem ;
++
++public class TestBlockAccessMem extends AbstractTestBlockAccessFixedSize
++{
++ static final int BlockSize = 50 ;
++ public TestBlockAccessMem()
++ {
++ super(BlockSize) ;
++ }
++
++ @Override
++ protected BlockAccess make()
++ {
++ return new BlockAccessMem("test", BlockSize) ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestChannelFile.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestChannelFile.java
index 0000000,0000000..b99dac9
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestChannelFile.java
@@@ -1,0 -1,0 +1,38 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.junit.AfterClass ;
++import org.seaborne.dboe.ConfigTestDBOE ;
++import org.seaborne.dboe.base.file.BufferChannel ;
++import org.seaborne.dboe.base.file.BufferChannelFile ;
++
++public class TestChannelFile extends AbstractTestChannel
++{
++ static String filename = ConfigTestDBOE.getTestingDir()+"/test-storage" ;
++
++ @AfterClass public static void cleanup() { FileOps.deleteSilent(filename) ; }
++
++ @Override
++ protected BufferChannel open()
++ {
++ FileOps.deleteSilent(filename) ;
++ return BufferChannelFile.create(filename) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestChannelMem.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestChannelMem.java
index 0000000,0000000..1fb079d
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestChannelMem.java
@@@ -1,0 -1,0 +1,34 @@@
++/*
++ * 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.dboe.base.file;
++
++import org.seaborne.dboe.base.file.BufferChannel ;
++import org.seaborne.dboe.base.file.BufferChannelMem ;
++
++
++public class TestChannelMem extends AbstractTestChannel
++{
++ static int counter = 0 ;
++
++ @Override
++ protected BufferChannel open()
++ {
++ return BufferChannelMem.create("Test-"+(counter++)) ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestMetaFile.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestMetaFile.java
index 0000000,0000000..c1427d1
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestMetaFile.java
@@@ -1,0 -1,0 +1,74 @@@
++/*
++ * 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.dboe.base.file;
++
++import java.io.File ;
++
++import org.junit.Assert ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.ConfigTestDBOE ;
++import org.seaborne.dboe.base.file.MetaFile ;
++import org.seaborne.dboe.sys.Names ;
++
++public class TestMetaFile extends Assert
++{
++ String testfile = null ;
++ String testfileMeta = null ;
++
++ @Before public void before()
++ {
++ testfile = ConfigTestDBOE.getTestingDir()+"/file" ;
++ testfileMeta = ConfigTestDBOE.getTestingDir()+"/file."+Names.extMeta ;
++ File f = new File(testfileMeta) ;
++ f.delete() ;
++ }
++
++ @Test public void meta1()
++ {
++ clear() ;
++ MetaFile f = new MetaFile("META", testfile) ;
++ assertFalse(new File(testfileMeta).exists()) ;
++ f.setProperty("key", "value") ;
++ f.flush() ;
++ assertTrue(new File(f.getFilename()).exists()) ;
++ }
++
++ @Test public void meta2()
++ {
++ clear() ;
++ MetaFile f = new MetaFile("META", testfile) ;
++ f.setProperty("test.value1", "1") ;
++ f.flush();
++ MetaFile f2 = new MetaFile("META", testfile) ;
++ assertEquals("1", f2.getProperty("test.value1")) ;
++ assertNull(f2.getProperty("test.value.other")) ;
++ }
++
++ // Test MetaBase
++
++ @After public void afterClass()
++ { clear() ; }
++
++ private void clear()
++ {
++ File f = new File(testfileMeta) ;
++ f.delete() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestProcessFileLock.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestProcessFileLock.java
index 0000000,0000000..39b0652
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestProcessFileLock.java
@@@ -1,0 -1,0 +1,107 @@@
++/*
++ * 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.dboe.base.file;
++
++import static org.junit.Assert.*;
++import static org.junit.Assert.assertFalse;
++import static org.junit.Assert.assertNotSame;
++import static org.junit.Assert.assertSame;
++
++import java.io.File;
++import java.io.IOException;
++
++import org.apache.jena.atlas.lib.FileOps;
++import org.junit.Before;
++import org.junit.BeforeClass;
++import org.junit.Test;
++import org.seaborne.dboe.base.file.ProcessFileLock;
++import org.seaborne.dboe.sys.Names;
++
++public class TestProcessFileLock {
++ // TestLocationLockStoreConnection
++
++ private static final String DIR = "target/locktest";
++ private static final String lockfile = DIR+"/"+Names.TDB_LOCK_FILE;
++
++
++ @BeforeClass public static void beforeClass() {
++ FileOps.ensureDir(DIR);
++ }
++
++ @Before public void beforeTest() {
++ File f = new File(lockfile);
++ try {
++ f.delete();
++ f.createNewFile();
++ }
++ catch (IOException e) {
++ e.printStackTrace();
++ }
++ }
++
++ @Test public void process_lock_1() {
++ ProcessFileLock lock = ProcessFileLock.create(lockfile);
++ String fn = new File(lockfile).getAbsolutePath();
++ assertEquals(fn, lock.getPath().toString());
++ }
++
++ @Test public void process_lock_2() {
++ ProcessFileLock lock1 = ProcessFileLock.create(lockfile);
++ ProcessFileLock lock2 = ProcessFileLock.create(lockfile);
++ assertSame(lock1, lock2);
++ }
++
++ @Test public void process_lock_3() {
++ ProcessFileLock lock1 = ProcessFileLock.create(lockfile);
++ ProcessFileLock.release(lock1);
++ ProcessFileLock lock2 = ProcessFileLock.create(lockfile);
++ assertNotSame(lock1, lock2);
++ }
++
++ @Test public void process_lock_4() {
++ ProcessFileLock lock = ProcessFileLock.create(lockfile);
++ assertFalse(lock.isLockedHere());
++ lock.lockEx();
++ assertTrue(lock.isLockedHere());
++ lock.unlock();
++ assertFalse(lock.isLockedHere());
++ }
++
++ @Test(expected=AlreadyLocked.class)
++ public void process_lock_5() {
++ ProcessFileLock lock = ProcessFileLock.create(lockfile);
++ lock.lockEx();
++ lock.lockEx();
++ }
++
++ @Test(expected=AlreadyLocked.class)
++ public void process_lock_6() {
++ ProcessFileLock lock = ProcessFileLock.create(lockfile);
++ lock.lockEx();
++ boolean b = lock.tryLock();
++ assertFalse(b);
++ }
++
++ @Test(expected=AlreadyLocked.class)
++ public void process_lock_7() {
++ ProcessFileLock lock = ProcessFileLock.create(lockfile);
++ lock.tryLock();
++ lock.tryLock();
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestSegmentedMemBuffer.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestSegmentedMemBuffer.java
index 0000000,0000000..c11cd75
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/file/TestSegmentedMemBuffer.java
@@@ -1,0 -1,0 +1,158 @@@
++/*
++ * 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.dboe.base.file;
++
++import java.nio.ByteBuffer ;
++import java.util.Arrays ;
++
++import org.junit.Assert ;
++import org.junit.Test ;
++
++public class TestSegmentedMemBuffer extends Assert {
++ private static byte[] data1 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } ;
++ private static byte[] data2 = { 10,11,12 } ;
++
++ @Test public void membuffer_00() {
++ SegmentedMemBuffer space = new SegmentedMemBuffer() ;
++ assertTrue(space.isOpen()) ;
++ assertEquals(0, space.length()) ;
++ space.close() ;
++ assertFalse(space.isOpen()) ;
++ space.close() ;
++ }
++
++ @Test public void membuffer_01() {
++ SegmentedMemBuffer space = new SegmentedMemBuffer() ;
++ writeread1(space) ;
++ }
++
++ @Test public void membuffer_02() {
++ SegmentedMemBuffer space = new SegmentedMemBuffer() ;
++ writeread2(space) ;
++ }
++
++ @Test public void membuffer_03() {
++ SegmentedMemBuffer space = new SegmentedMemBuffer() ;
++ writeread1(space) ;
++ space.truncate(0);
++ writeread2(space) ;
++ }
++
++ @Test public void membuffer_11() {
++ SegmentedMemBuffer space = new SegmentedMemBuffer(2) ;
++ writeread1(space) ;
++ }
++
++ @Test public void membuffer_12() {
++ SegmentedMemBuffer space = new SegmentedMemBuffer(2) ;
++ writeread2(space) ;
++ }
++
++ @Test public void membuffer_13() {
++ SegmentedMemBuffer space = new SegmentedMemBuffer(2) ;
++ writeread1(space) ;
++ space.truncate(0);
++ writeread2(space) ;
++ }
++
++ @Test public void membuffer_21() {
++ SegmentedMemBuffer space = new SegmentedMemBuffer() ;
++ writeread1a(space) ;
++ }
++
++ @Test public void membuffer_22() {
++ SegmentedMemBuffer space = new SegmentedMemBuffer() ;
++ writeread2a(space) ;
++ }
++
++ @Test public void membuffer_23() {
++ SegmentedMemBuffer space = new SegmentedMemBuffer() ;
++ writeread1(space) ;
++ space.truncate(0);
++ writeread2a(space) ;
++ }
++
++ @Test public void membuffer_31() {
++ SegmentedMemBuffer space = new SegmentedMemBuffer(2) ;
++ writeread1a(space) ;
++ }
++
++ @Test public void membuffer_32() {
++ SegmentedMemBuffer space = new SegmentedMemBuffer(2) ;
++ writeread2(space) ;
++ }
++
++ @Test public void membuffer_33() {
++ SegmentedMemBuffer space = new SegmentedMemBuffer(2) ;
++ writeread1a(space) ;
++ space.truncate(0);
++ writeread2a(space) ;
++ }
++
++ private void writeread1(SegmentedMemBuffer space) {
++ long x = space.length() ;
++ space.write(x, data1) ;
++ assertEquals(x+data1.length, space.length()) ;
++ byte[] bytes2 = new byte[data1.length+10] ;
++ int y = space.read(x, bytes2) ;
++ assertEquals(data1.length, y) ;
++ byte[] bytes3 = Arrays.copyOf(bytes2, y) ;
++ assertArrayEquals(data1, bytes3);
++ }
++
++ private void writeread2(SegmentedMemBuffer space) {
++ // Offset.
++ space.write(0, data2) ;
++ long x = data2.length ;
++ space.write(x, data1) ;
++ assertEquals(x+data1.length, space.length()) ;
++ byte[] bytes2 = new byte[data1.length+10] ;
++ int y = space.read(x, bytes2) ;
++ assertEquals(data1.length, y) ;
++ byte[] bytes3 = Arrays.copyOf(bytes2, y) ;
++ assertArrayEquals(data1, bytes3);
++ }
++
++ private void writeread1a(SegmentedMemBuffer space) {
++ long x = space.length() ;
++ ByteBuffer bb1 = ByteBuffer.wrap(data1) ;
++ space.write(x, bb1) ;
++ assertEquals(x+data1.length, space.length()) ;
++ ByteBuffer bb2 = ByteBuffer.allocate(data1.length) ;
++ int y = space.read(x, bb2) ;
++ assertEquals(data1.length, y) ;
++ byte[] bytes3 = Arrays.copyOf(bb2.array(), y) ;
++ assertArrayEquals(data1, bytes3);
++ }
++
++ private void writeread2a(SegmentedMemBuffer space) {
++ // Offset.
++ space.write(0, ByteBuffer.wrap(data2)) ;
++ long x = data2.length ;
++ ByteBuffer bb1 = ByteBuffer.wrap(data1) ;
++ space.write(x, bb1) ;
++ assertEquals(x+data1.length, space.length()) ;
++ ByteBuffer bb2 = ByteBuffer.allocate(data1.length) ;
++ int y = space.read(x, bb2) ;
++ assertEquals(data1.length, y) ;
++ byte[] bytes3 = Arrays.copyOf(bb2.array(), y) ;
++ assertArrayEquals(data1, bytes3);
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/record/TS_Record.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/record/TS_Record.java
index 0000000,0000000..b33eca8
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/record/TS_Record.java
@@@ -1,0 -1,0 +1,34 @@@
++/*
++ * 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.dboe.base.record;
++
++import org.junit.runner.RunWith;
++import org.junit.runners.Suite;
++import org.seaborne.dboe.base.buffer.TestPtrBuffer ;
++import org.seaborne.dboe.base.buffer.TestRecordBuffer ;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestRecord.class ,
++ TestPtrBuffer.class ,
++ TestRecordBuffer.class
++})
++
++
++public class TS_Record
++{}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/record/TestRecord.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/record/TestRecord.java
index 0000000,0000000..a1e14bf
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/record/TestRecord.java
@@@ -1,0 -1,0 +1,77 @@@
++/*
++ * 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.dboe.base.record;
++
++import static org.seaborne.dboe.test.RecordLib.intToRecord ;
++import static org.seaborne.dboe.test.RecordLib.recordToInt ;
++import org.junit.Assert ;
++import org.junit.Test;
++import org.seaborne.dboe.base.record.Record ;
++
++public class TestRecord extends Assert
++{
++ static final public int RecLen = 4 ;
++
++ @Test public void int1()
++ {
++ Record r = intToRecord(1234, 4) ;
++ int v = recordToInt(r) ;
++ assertEquals(v , 1234) ;
++ }
++
++ @Test public void int2()
++ {
++ // Negative numbers only work for length 4.
++ Record r = intToRecord(-99, 4) ;
++ int v = recordToInt(r) ;
++ assertEquals(v , -99) ;
++ }
++
++ @Test public void record1()
++ {
++ Record r1 = intToRecord(1, RecLen) ;
++ Record r2 = intToRecord(1, RecLen) ;
++ assertTrue(Record.keyEQ(r1,r2)) ;
++ assertTrue(Record.keyGE(r1,r2)) ;
++ assertTrue(Record.keyLE(r1,r2)) ;
++ assertFalse(Record.keyLT(r1,r2)) ;
++ assertFalse(Record.keyGT(r1,r2)) ;
++ }
++
++ @Test public void record2()
++ {
++ Record r1 = intToRecord(1000, RecLen) ;
++ Record r2 = intToRecord(2222, RecLen) ;
++ assertFalse(Record.keyEQ(r1,r2)) ;
++ assertFalse(Record.keyGE(r1,r2)) ;
++ assertTrue(Record.keyLE(r1,r2)) ;
++ assertTrue(Record.keyLT(r1,r2)) ;
++ assertFalse(Record.keyGT(r1,r2)) ;
++ }
++
++ @Test public void record3()
++ {
++ Record r1 = intToRecord(1000, RecLen) ;
++ Record r2 = intToRecord(0, RecLen) ;
++ assertFalse(Record.keyEQ(r1,r2)) ;
++ assertTrue(Record.keyGE(r1,r2)) ;
++ assertFalse(Record.keyLE(r1,r2)) ;
++ assertFalse(Record.keyLT(r1,r2)) ;
++ assertTrue(Record.keyGT(r1,r2)) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/recordfile/TS_RecordFile.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/recordfile/TS_RecordFile.java
index 0000000,0000000..34821f1
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/recordfile/TS_RecordFile.java
@@@ -1,0 -1,0 +1,31 @@@
++/*
++ * 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.dboe.base.recordfile;
++
++import org.junit.runner.RunWith;
++import org.junit.runners.Suite;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestRecordBufferPage.class
++})
++
++public class TS_RecordFile
++{
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/recordfile/TestRecordBufferPage.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/recordfile/TestRecordBufferPage.java
index 0000000,0000000..d801e73
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/java/org/seaborne/dboe/base/recordfile/TestRecordBufferPage.java
@@@ -1,0 -1,0 +1,124 @@@
++/*
++ * 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.dboe.base.recordfile;
++
++import org.junit.Assert ;
++import org.junit.AfterClass ;
++import org.junit.BeforeClass ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.block.BlockMgrFactory ;
++import org.seaborne.dboe.base.buffer.RecordBuffer ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPage ;
++import org.seaborne.dboe.base.recordbuffer.RecordBufferPageMgr ;
++import org.seaborne.dboe.sys.SystemIndex ;
++
++public class TestRecordBufferPage extends Assert
++{
++ // Testing: records are 2 bytes, 3 records per block.
++
++ static final int TestRecordSize = 2 ; // Size, in bytes.
++ static final int TestNumRecord = 3 ; // Size, in bytes.
++ static RecordFactory factory = new RecordFactory(2, 0) ;
++
++ static boolean originalNullOut ;
++ @BeforeClass static public void beforeClass()
++ {
++ originalNullOut = SystemIndex.getNullOut() ;
++ SystemIndex.setNullOut(true) ;
++ }
++
++ @AfterClass static public void afterClass()
++ {
++ SystemIndex.setNullOut(originalNullOut) ;
++ }
++
++ @Test public void recBufferPage01()
++ {
++ BlockMgr blkMgr = makeBlockMgr() ;
++ blkMgr.beginUpdate() ;
++ RecordBufferPageMgr rpm = new RecordBufferPageMgr(factory, blkMgr) ;
++ RecordBufferPage page = rpm.create() ;
++ fill(page.getRecordBuffer(), 10, 20, 30) ;
++ assertEquals(10, get(page, 0)) ;
++ assertEquals(20, get(page, 1)) ;
++ assertEquals(30, get(page, 2)) ;
++ rpm.release(page) ;
++ blkMgr.endUpdate() ;
++ }
++
++ @Test public void recBufferPage02()
++ {
++ BlockMgr blkMgr = makeBlockMgr() ;
++ blkMgr.beginUpdate() ;
++ RecordBufferPageMgr rpm = new RecordBufferPageMgr(factory, blkMgr) ;
++ int x = -99 ;
++ {
++ RecordBufferPage page1 = rpm.create() ;
++ fill(page1.getRecordBuffer(), 10, 20, 30) ;
++ x = page1.getId() ;
++ rpm.put(page1) ;
++ page1 = null ;
++ }
++ blkMgr.endUpdate() ;
++ blkMgr.beginRead() ;
++ {
++ RecordBufferPage page2 = rpm.getRead(x) ;
++ assertEquals(10, get(page2, 0)) ;
++ assertEquals(20, get(page2, 1)) ;
++ assertEquals(30, get(page2, 2)) ;
++ rpm.release(page2) ;
++ }
++ blkMgr.endRead() ;
++ }
++
++
++ private static void fill(RecordBuffer rb, int ... nums)
++ {
++ for ( int num : nums )
++ {
++ Record rec = record( num );
++ rb.add( rec );
++ }
++ }
++
++ private static int get(RecordBufferPage rbp, int idx) { return get(rbp.getRecordBuffer(), idx) ; }
++
++ private static int get(RecordBuffer rb, int idx)
++ {
++ Record r = rb.get(idx) ;
++ int v = (r.getKey()[0])<<8 | ((r.getKey()[1])&0xFF) ;
++ return v ;
++ }
++
++ private static Record record(int i)
++ {
++ byte b[] = new byte[]{
++ (byte)((i>>8)&0xFF),
++ (byte)(i&0xFF)} ;
++ Record r = factory.create(b) ;
++ return r ;
++ }
++
++ private static BlockMgr makeBlockMgr()
++ {
++ return BlockMgrFactory.createMem("RecordBuffer", RecordBufferPage.calcBlockSize(factory, TestNumRecord)) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-base/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --cc jena-db/dboe-base/src/test/resources/log4j.properties
index 0000000,0000000..d6b299a
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-base/src/test/resources/log4j.properties
@@@ -1,0 -1,0 +1,6 @@@
++log4j.rootLogger=INFO, stdlog
++
++log4j.appender.stdlog=org.apache.log4j.ConsoleAppender
++## log4j.appender.stdlog.target=System.err
++log4j.appender.stdlog.layout=org.apache.log4j.PatternLayout
++log4j.appender.stdlog.layout.ConversionPattern=%d{HH:mm:ss} %-5p %-20c{1} :: %m%n
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index-test/.gitignore
----------------------------------------------------------------------
diff --cc jena-db/dboe-index-test/.gitignore
index 0000000,0000000..b83d222
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index-test/.gitignore
@@@ -1,0 -1,0 +1,1 @@@
++/target/
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index-test/README.md
----------------------------------------------------------------------
diff --cc jena-db/dboe-index-test/README.md
index 0000000,0000000..bae93dd
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index-test/README.md
@@@ -1,0 -1,0 +1,1 @@@
++Test support for dboe-index code.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index-test/pom.xml
----------------------------------------------------------------------
diff --cc jena-db/dboe-index-test/pom.xml
index 0000000,0000000..b06a773
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index-test/pom.xml
@@@ -1,0 -1,0 +1,54 @@@
++<?xml version="1.0" encoding="utf-8"?>
++<!--
++ 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.
++-->
++
++<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
++ <modelVersion>4.0.0</modelVersion>
++
++ <artifactId>dboe-index-test</artifactId>
++ <packaging>jar</packaging>
++ <name>Mantis (${project.artifactId})</name>
++
++ <parent>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>mantis</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </parent>
++
++ <dependencies>
++
++ <dependency>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>dboe-index</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </dependency>
++
++ <dependency>
++ <groupId>org.apache.jena</groupId>
++ <artifactId>jena-cmds</artifactId>
++ </dependency>
++
++ <dependency>
++ <!-- Bring junit into scope-compile -->
++ <groupId>junit</groupId>
++ <artifactId>junit</artifactId>
++ <scope>compile</scope>
++ </dependency>
++
++ </dependencies>
++
++</project>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/TS_Index.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/TS_Index.java
index 0000000,0000000..0fe386d
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/TS_Index.java
@@@ -1,0 -1,0 +1,29 @@@
++/*
++ * 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.dboe.index;
++
++import org.junit.runner.RunWith ;
++import org.junit.runners.Suite ;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestIndexMem.class
++} )
++
++public class TS_Index
++{ }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/TestIndexMem.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/TestIndexMem.java
index 0000000,0000000..78f4009
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/TestIndexMem.java
@@@ -1,0 -1,0 +1,34 @@@
++/*
++ * 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.dboe.index;
++
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.index.Index ;
++import org.seaborne.dboe.index.IndexMap ;
++import org.seaborne.dboe.index.test.AbstractTestIndex ;
++
++public class TestIndexMem extends AbstractTestIndex
++{
++ @Override
++ protected Index makeIndex(int kLen, int vLen)
++ {
++ RecordFactory rf = new RecordFactory(kLen, vLen) ;
++ return new IndexMap(rf) ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/AbstractTestIndex.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/AbstractTestIndex.java
index 0000000,0000000..75efad7
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/AbstractTestIndex.java
@@@ -1,0 -1,0 +1,159 @@@
++/*
++ * 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.dboe.index.test;
++
++import static org.seaborne.dboe.index.test.IndexTestLib.* ;
++import static org.seaborne.dboe.test.RecordLib.intToRecord ;
++import org.junit.Assert ;
++import org.junit.After;
++import org.junit.Test;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.index.Index ;
++import org.seaborne.dboe.test.RecordLib ;
++
++//import org.apache.jena.tdb.base.record.RecordLib;
++
++public abstract class AbstractTestIndex extends Assert
++{
++ Index index = null ;
++
++ @After public void afterTest()
++ {
++ if ( index != null )
++ index.close();
++ index = null ;
++ }
++
++ // ---- Overridable maker
++ protected abstract Index makeIndex(int kLen, int vLen) ;
++
++ @Test public void __basic() {
++ makeIndex(4,0) ;
++ }
++
++ @Test public void index_ins_0()
++ {
++ // Empty tree
++ int[] keys = {};
++ test(keys) ;
++ }
++
++ @Test public void index_ins_1()
++ {
++ int[] keys = {1};
++ test(keys) ;
++ }
++
++ @Test public void index_ins_2()
++ {
++ int[] keys = new int[20] ;
++ for ( int i = 0 ; i < keys.length ; i++ )
++ keys[i] = i ;
++ test(keys) ;
++ }
++
++ @Test public void index_ins_3()
++ {
++ int[] keys = new int[20] ;
++ for ( int i = keys.length-1 ; i >= 0 ; i-- )
++ keys[i] = i ;
++ test(keys) ;
++ }
++
++ @Test public void index_ins_4()
++ {
++ int[] keys = new int[10] ;
++ for ( int i = 0 ; i < keys.length ; i++ )
++ keys[i] = 1<<i ;
++ test(keys) ;
++ }
++
++ @Test public void index_ins_5()
++ {
++ int[] keys = new int[10] ;
++ for ( int i = keys.length-1 ; i >= 0 ; i-- )
++ keys[i] = 1<<i ;
++ test(keys) ;
++ }
++
++ @Test public void index_find_1()
++ {
++ int[] keys = {1};
++ Index index = test(keys) ;
++ Record r = intToRecord(1, RecordLib.TestRecordLength) ;
++ r = index.find(r) ;
++ assertNotNull(r) ;
++ }
++
++ @Test public void index_find_2()
++ {
++ int[] keys = {1,2,3,4,5,6,7,8,9};
++ Index index = test(keys) ;
++ Record r = intToRecord(20, RecordLib.TestRecordLength) ;
++ r = index.find(r) ;
++ assertNull(r) ;
++ }
++
++ @Test public void index_del_1()
++ {
++ int[] keys1 = {0, 1, 2};
++ int[] keys2 = {0, 1, 2};
++ int[] keys3 = {} ;
++ test(keys1, keys2, keys3) ;
++ }
++
++ @Test public void index_del_2()
++ {
++ int[] keys1 = {0, 1, 2};
++ int[] keys2 = {0, 1};
++ int[] keys3 = {2} ;
++ test(keys1, keys2, keys3) ;
++ }
++
++ @Test public void index_del_3()
++ {
++ int[] keys1 = {0, 1, 2};
++ int[] keys2 = {0, 99};
++ int[] keys3 = {2, 1} ;
++ test(keys1, keys2, keys3) ;
++ }
++
++ private Index test(int[] insKeys, int[] delKeys, int[] expected)
++ {
++ index = makeIndex(4,0) ;
++ testInsert(index, insKeys) ;
++ long x = index.size() ;
++ if ( x >= 0 )
++ assertEquals(insKeys.length, x) ;
++
++ if ( delKeys != null )
++ {
++ testDelete(index, delKeys) ;
++
++ }
++
++ if ( expected != null )
++ testIndexContents(index, expected) ;
++ return index ;
++ }
++
++ private Index test(int[] keys)
++ {
++ return test(keys, null, keys) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/AbstractTestRangeIndex.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/AbstractTestRangeIndex.java
index 0000000,0000000..ab3f82c
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/AbstractTestRangeIndex.java
@@@ -1,0 -1,0 +1,434 @@@
++/*
++ * 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.dboe.index.test ;
++
++import static org.seaborne.dboe.index.test.IndexTestLib.add ;
++import static org.seaborne.dboe.index.test.IndexTestLib.randTest ;
++import static org.seaborne.dboe.index.test.IndexTestLib.testInsert ;
++import static org.seaborne.dboe.index.test.IndexTestLib.testInsertDelete ;
++import static org.seaborne.dboe.test.RecordLib.intToRecord ;
++import static org.seaborne.dboe.test.RecordLib.r ;
++import static org.seaborne.dboe.test.RecordLib.toIntList ;
++
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.junit.Assert ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.index.RangeIndex ;
++
++public abstract class AbstractTestRangeIndex extends Assert {
++ // ---- Overridable maker
++ protected RangeIndex makeRangeIndex(int order) {
++ return makeRangeIndex(order, order) ;
++ }
++
++ protected abstract RangeIndex makeRangeIndex(int order, int minRecords) ;
++
++ @Test public void __basic() {
++ makeRangeIndex(4,0) ;
++ }
++
++ @Test
++ public void tree_ins_0_0() {
++ // Empty tree
++ int[] keys = {} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsert(rIndex, keys) ;
++ assertTrue(rIndex.isEmpty()) ;
++ assertNull(rIndex.minKey()) ;
++ assertNull(rIndex.maxKey()) ;
++ }
++
++ @Test
++ public void tree_ins_0_1() {
++ int[] keys = {0, 1, 2} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsert(rIndex, keys) ;
++ assertFalse(rIndex.isEmpty()) ;
++ assertEquals(0, r(rIndex.minKey())) ;
++ assertEquals(2, r(rIndex.maxKey())) ;
++ }
++
++ @Test
++ public void tree_ins_2_01() {
++ int[] keys = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsert(rIndex, keys) ;
++ assertEquals(0, r(rIndex.minKey())) ;
++ assertEquals(9, r(rIndex.maxKey())) ;
++ }
++
++ @Test
++ public void tree_ins_2_02() {
++ int[] keys = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsert(rIndex, keys) ;
++ assertEquals(0, r(rIndex.minKey())) ;
++ assertEquals(9, r(rIndex.maxKey())) ;
++ }
++
++ @Test
++ public void tree_ins_2_03() {
++ int[] keys = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsert(rIndex, keys) ;
++ assertEquals(0, r(rIndex.minKey())) ;
++ assertEquals(9, r(rIndex.maxKey())) ;
++ }
++
++ @Test
++ public void tree_ins_2_04() {
++ int[] keys = {0, 9, 2, 7, 4, 5, 6, 3, 8, 1} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsert(rIndex, keys) ;
++ assertEquals(0, r(rIndex.minKey())) ;
++ assertEquals(9, r(rIndex.maxKey())) ;
++ }
++
++ @Test
++ public void tree_ins_2_05() {
++ int[] keys = {0, 18, 4, 14, 8, 10, 12, 6, 16, 2} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsert(rIndex, keys) ;
++ assertFalse(rIndex.contains(r(1))) ;
++ assertFalse(rIndex.contains(r(999))) ;
++ assertFalse(rIndex.contains(r(-9))) ;
++ assertFalse(rIndex.contains(r(7))) ;
++ assertEquals(0, r(rIndex.minKey())) ;
++ assertEquals(18, r(rIndex.maxKey())) ;
++ }
++
++ @Test
++ public void tree_del_0_1() {
++ int[] keys1 = {0, 1, 2} ;
++ int[] keys2 = {0, 1, 2} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsertDelete(rIndex, keys1, keys2) ;
++ }
++
++ @Test
++ public void tree_del_0_2() {
++ int[] keys1 = {0, 1, 2} ;
++ int[] keys2 = {2, 1, 0} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsertDelete(rIndex, keys1, keys2) ;
++ }
++
++ @Test
++ public void tree_del_0_3() {
++ int[] keys1 = {0, 1, 2} ;
++ int[] keys2 = {1, 0, 2} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsertDelete(rIndex, keys1, keys2) ;
++ }
++
++ @Test
++ public void tree_del_2_01() {
++ int[] keys1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} ;
++ int[] keys2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsertDelete(rIndex, keys1, keys2) ;
++ }
++
++ @Test
++ public void tree_del_2_02() {
++ int[] keys1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} ;
++ int[] keys2 = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsertDelete(rIndex, keys1, keys2) ;
++ }
++
++ @Test
++ public void tree_del_2_03() {
++ int[] keys1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} ;
++ int[] keys2 = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsertDelete(rIndex, keys1, keys2) ;
++ }
++
++ @Test
++ public void tree_del_2_04() {
++ int[] keys1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} ;
++ int[] keys2 = {0, 9, 2, 7, 4, 5, 6, 3, 8, 1} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsertDelete(rIndex, keys1, keys2) ;
++ }
++
++ @Test
++ public void tree_del_2_05() {
++ int[] keys1 = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0} ;
++ int[] keys2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsertDelete(rIndex, keys1, keys2) ;
++ }
++
++ @Test
++ public void tree_del_2_06() {
++ int[] keys1 = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0} ;
++ int[] keys2 = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsertDelete(rIndex, keys1, keys2) ;
++ }
++
++ @Test
++ public void tree_del_2_07() {
++ int[] keys1 = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0} ;
++ int[] keys2 = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsertDelete(rIndex, keys1, keys2) ;
++ }
++
++ @Test
++ public void tree_del_2_08() {
++ int[] keys1 = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0} ;
++ int[] keys2 = {0, 9, 2, 7, 4, 5, 6, 3, 8, 1} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsertDelete(rIndex, keys1, keys2) ;
++ }
++
++ @Test
++ public void tree_del_2_09() {
++ int[] keys1 = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9} ;
++ int[] keys2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsertDelete(rIndex, keys1, keys2) ;
++ }
++
++ @Test
++ public void tree_del_2_10() {
++ int[] keys1 = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9} ;
++ int[] keys2 = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsertDelete(rIndex, keys1, keys2) ;
++ }
++
++ @Test
++ public void tree_del_2_11() {
++ int[] keys1 = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9} ;
++ int[] keys2 = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsertDelete(rIndex, keys1, keys2) ;
++ }
++
++ @Test
++ public void tree_del_2_12() {
++ int[] keys1 = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9} ;
++ int[] keys2 = {0, 9, 2, 7, 4, 5, 6, 3, 8, 1} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ testInsertDelete(rIndex, keys1, keys2) ;
++ }
++
++ @Test
++ public void tree_iter_2_01() {
++ int[] keys = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ add(rIndex, keys) ;
++ List<Integer> x = toIntList(rIndex.iterator(r(4), r(6))) ;
++ List<Integer> expected = toIntList(4, 5) ;
++ assertEquals(expected, x) ;
++ }
++
++ @Test
++ public void tree_iter_2_02() {
++ int[] keys = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ add(rIndex, keys) ;
++ List<Integer> x = toIntList(rIndex.iterator(r(4), r(7))) ;
++ List<Integer> expected = toIntList(4, 5, 6) ;
++ assertEquals(expected, x) ;
++ }
++
++ @Test
++ public void tree_iter_2_03() {
++ int[] keys = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ add(rIndex, keys) ;
++ List<Integer> x = toIntList(rIndex.iterator(r(4), null)) ;
++ List<Integer> expected = toIntList(4, 5, 6, 7, 8, 9) ;
++ assertEquals(expected, x) ;
++ }
++
++ @Test
++ public void tree_iter_2_04() {
++ int[] keys = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ add(rIndex, keys) ;
++ List<Integer> x = toIntList(rIndex.iterator(null, null)) ;
++ List<Integer> expected = toIntList(keys) ;
++ assertEquals(expected, x) ;
++ }
++
++ @Test
++ public void tree_iter_2_05() {
++ int[] keys = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ add(rIndex, keys) ;
++ List<Integer> x = toIntList(rIndex.iterator(null, r(4))) ;
++ List<Integer> expected = toIntList(0, 1, 2, 3) ;
++ assertEquals(expected, x) ;
++ }
++
++ @Test
++ public void tree_iter_2_07() {
++ int[] keys = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ add(rIndex, keys) ;
++ List<Integer> x = toIntList(rIndex.iterator(null, r(99))) ;
++ List<Integer> expected = toIntList(keys) ;
++ assertEquals(expected, x) ;
++ }
++
++ @Test
++ public void tree_iter_2_08() {
++ int[] keys = {1, 2, 3, 4, 5, 6, 7, 8, 9} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ add(rIndex, keys) ;
++ List<Integer> x = toIntList(rIndex.iterator(r(0), r(99))) ;
++ List<Integer> expected = toIntList(keys) ;
++ assertEquals(expected, x) ;
++ }
++
++ @Test
++ public void tree_iter_2_09() {
++ int[] keys = {1, 2, 3, 4, /* 5, 6, */7, 8, 9, 10, 11} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ add(rIndex, keys) ;
++ List<Integer> x = toIntList(rIndex.iterator(r(5), r(7))) ;
++ List<Integer> expected = toIntList() ;
++ assertEquals(expected, x) ;
++ }
++
++ // Root
++ @Test
++ public void tree_iter_0_01() {
++ int[] keys = {1, 2, 3, 4, 5} ;
++ RangeIndex rIndex = makeRangeIndex(5) ;
++ add(rIndex, keys) ;
++ Iterator<Record> iter = rIndex.iterator(r(2), r(4)) ;
++ while ( iter.hasNext() )
++ iter.next() ;
++
++ List<Integer> x = toIntList(rIndex.iterator(r(2), r(4))) ;
++ List<Integer> expected = toIntList(2, 3) ;
++ assertEquals(expected, x) ;
++ }
++
++ @Test
++ public void tree_iter_0_02() {
++ int[] keys = {1, 2, 3, 4, 5} ;
++ RangeIndex rIndex = makeRangeIndex(5) ;
++ add(rIndex, keys) ;
++ List<Integer> x = toIntList(rIndex.iterator(null, null)) ;
++ List<Integer> expected = toIntList(keys) ;
++ assertEquals(expected, x) ;
++ }
++
++ @Test
++ public void tree_iter_0_03() {
++ int[] keys = {1, 2, 3, 4, 5} ;
++ RangeIndex rIndex = makeRangeIndex(5) ;
++ add(rIndex, keys) ;
++ List<Integer> x = toIntList(rIndex.iterator(r(5), null)) ;
++ List<Integer> expected = toIntList(5) ;
++ assertEquals(expected, x) ;
++ }
++
++ @Test
++ public void tree_iter_0_04() {
++ int[] keys = {1, 2, 3, 4, 5} ;
++ RangeIndex rIndex = makeRangeIndex(5) ;
++ add(rIndex, keys) ;
++ List<Integer> x = toIntList(rIndex.iterator(r(0), r(0))) ;
++ List<Integer> expected = toIntList() ;
++ assertEquals(expected, x) ;
++ }
++
++ @Test
++ public void tree_iter_0_05() {
++ int[] keys = {1, 2, 3, 4, 5} ;
++ RangeIndex rIndex = makeRangeIndex(5) ;
++ add(rIndex, keys) ;
++ List<Integer> x = toIntList(rIndex.iterator(r(1), r(0))) ;
++ List<Integer> expected = toIntList() ;
++ assertEquals(expected, x) ;
++ }
++
++ @Test
++ public void tree_ret_1() {
++ int[] keys = {1, 2, 3, 4, 5} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ add(rIndex, keys) ;
++ boolean b = rIndex.insert(intToRecord(3)) ;
++ assertFalse(b) ;
++ b = rIndex.insert(intToRecord(9)) ;
++ assertTrue(b) ;
++ }
++
++ @Test
++ public void tree_ret_2() {
++ int[] keys = {1, 2, 3, 4, 5} ;
++ RangeIndex rIndex = makeRangeIndex(2) ;
++ add(rIndex, keys) ;
++ boolean b = rIndex.delete(intToRecord(9)) ;
++ assertFalse(b) ;
++ b = rIndex.insert(intToRecord(1)) ;
++ assertFalse(b) ;
++ }
++
++ @Test
++ public void tree_2_N() {
++ for ( int i = 0 ; i < 10 ; i++ )
++ randTest(makeRangeIndex(2), 999, 20) ;
++ }
++
++ @Test
++ public void tree_3_N() {
++ for ( int i = 0 ; i < 10 ; i++ )
++ randTest(makeRangeIndex(3), 9999, 100) ;
++ }
++
++ @Test public void tree_clear_00() { testClear(0) ; }
++
++ @Test public void tree_clear_01() { testClear(5) ; }
++
++ @Test public void tree_clear_02() { testClear(15) ; }
++
++ @Test public void tree_clear_03() { testClear(998) ; }
++
++ @Test public void tree_clear_04() { testClear(999) ; }
++
++ @Test public void tree_clear_05() { testClear(1000) ; }
++
++ @Test public void tree_clear_06() { testClear(1001) ; }
++
++ @Test public void tree_clear_07() { testClear(5500) ; }
++
++ protected void testClear(int N) {
++ int[] keys = new int[N] ; // Slice is 1000.
++ for ( int i = 0 ; i < keys.length ; i++ )
++ keys[i] = i ;
++ RangeIndex rIndex = makeRangeIndex(3) ;
++ add(rIndex, keys) ;
++ if ( N > 0 )
++ assertFalse(rIndex.isEmpty()) ;
++ rIndex.clear() ;
++ assertTrue(rIndex.isEmpty()) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/BaseSoakTest.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/BaseSoakTest.java
index 0000000,0000000..bd5ddf6
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/BaseSoakTest.java
@@@ -1,0 -1,0 +1,140 @@@
++/*
++ * 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.dboe.index.test;
++
++import java.util.List ;
++
++import jena.cmd.CmdException ;
++import jena.cmd.CmdGeneral ;
++
++import org.apache.jena.atlas.lib.Lib ;
++import org.apache.jena.atlas.lib.RandomLib ;
++import org.apache.jena.atlas.logging.LogCtl ;
++
++public abstract class BaseSoakTest extends CmdGeneral {
++ static { LogCtl.setLog4j() ; }
++
++ protected final int MinOrder = 2 ;
++ protected final int MinSize = 1 ;
++ protected int MaxOrder = -1 ;
++ protected int MaxSize = -1 ;
++ protected int NumTest = -1 ;
++
++ protected BaseSoakTest(String[] argv) {
++ super(argv) ;
++ }
++
++ protected abstract void before() ;
++ protected abstract void after() ;
++
++ @Override
++ protected String getSummary() {
++ return "Usage: "+Lib.className(this)+" maxOrder maxSize NumTests" ;
++ }
++
++ @Override
++ protected void processModulesAndArgs() {
++ List<String> args = super.getPositional() ;
++ if ( args.size() != 3 )
++ throw new CmdException("Usage: maxOrder maxSize NumTests") ;
++
++ try { MaxOrder = Integer.parseInt(args.get(0)) ; }
++ catch (NumberFormatException ex)
++ { throw new CmdException("Bad number for MaxOrder") ; }
++
++ try { MaxSize = Integer.parseInt(args.get(1)) ; }
++ catch (NumberFormatException ex)
++ { throw new CmdException("Bad number for MaxSize") ; }
++
++ try { NumTest = Integer.parseInt(args.get(2)) ; }
++ catch (NumberFormatException ex)
++ { throw new CmdException("Bad number for NumTest") ; }
++ }
++
++ @Override
++ protected void exec() {
++ int successes = 0 ;
++ int failures = 0 ;
++
++ // Number of dots.
++ int numOnLine = 50 ;
++ int testsPerTick ;
++ if ( NumTest < 20 )
++ testsPerTick = 5 ;
++ else if ( NumTest < 200 )
++ testsPerTick = 50 ;
++ else
++ testsPerTick = 500 ;
++
++
++ // ---- Format for line counter.
++ int numLines = (int)Math.ceil( ((double)NumTest) / (testsPerTick * numOnLine) ) ;
++ // Start of last line.
++ int z = (numLines-1)*(testsPerTick * numOnLine) ;
++ int digits = 1 ;
++ if ( z > 0 )
++ digits = 1+(int)Math.floor(Math.log10(z));
++ String format = "[%"+digits+"d] " ;
++
++ System.out.printf("TEST : %,d tests : Max Order=%d Max Items=%,d [tests per tick=%d]\n", NumTest, MaxOrder, MaxSize, testsPerTick) ;
++
++ before() ;
++
++ int testCount = 1 ;
++
++ for ( testCount = 1 ; testCount <= NumTest ; testCount++ ) {
++ if ( testCount % testsPerTick == 0 )
++ System.out.print(".") ;
++ if ( testCount % (testsPerTick * numOnLine) == 0 )
++ System.out.println("") ;
++ if ( testCount % (testsPerTick * numOnLine) == 1 )
++ System.out.printf(format, testCount-1) ;
++
++ int idx = testCount - 1 ;
++ int order = ( MinOrder == MaxOrder ) ? MinOrder : MinOrder + RandomLib.random.nextInt(MaxOrder-MinOrder) ;
++ int size = ( MinSize == MaxSize ) ? MinSize : MinSize + RandomLib.random.nextInt(MaxSize-MinSize) ; try {
++ //System.out.printf("TEST : %,d : Order=%-2d : Size=%d\n", testCount, order, size) ;
++ runOneTest(testCount, order, size) ;
++ successes++ ;
++ }
++ catch (AssertionError | RuntimeException ex) {
++ System.err.printf("-- Fail: (order=%d, size=%d)\n", order, size) ;
++ ex.printStackTrace(System.err) ;
++ System.err.printf("--------------------------\n") ;
++ failures++ ;
++ }
++ }
++
++ // Did the last loop print a new line?
++ if ( (testCount-1) % (testsPerTick*numOnLine) != 0 )
++ System.out.println();
++
++ after() ;
++ System.err.flush() ;
++ System.out.flush() ;
++ System.out.printf("DONE : %,d tests : Success=%,d ; Failures=%,d\n", NumTest, successes, failures);
++ }
++
++ protected abstract void runOneTest(int testCount, int order, int size, boolean debug) ;
++
++ protected abstract void runOneTest(int testCount, int order, int size) ;
++
++ @Override
++ protected String getCommandName() { return Lib.className(this) ; }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/IndexMaker.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/IndexMaker.java
index 0000000,0000000..317639a
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/IndexMaker.java
@@@ -1,0 -1,0 +1,26 @@@
++/*
++ * 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.dboe.index.test;
++
++import org.seaborne.dboe.index.Index ;
++
++public interface IndexMaker
++{
++ Index makeIndex() ;
++ String getLabel() ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/IndexTestGenerator.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/IndexTestGenerator.java
index 0000000,0000000..65b3412
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/IndexTestGenerator.java
@@@ -1,0 -1,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.dboe.index.test;
++
++import org.apache.jena.atlas.lib.RandomLib ;
++import org.apache.jena.atlas.test.ExecGenerator ;
++
++public class IndexTestGenerator implements ExecGenerator
++{
++ int maxNumKeys ;
++ int maxValue ;
++ IndexMaker maker ;
++
++ public IndexTestGenerator(IndexMaker maker, int maxValue, int maxNumKeys)
++ {
++ if ( maxValue <= maxNumKeys )
++ throw new IllegalArgumentException("RangeIndexTestGenerator: Max value less than number of keys") ;
++ this.maker = maker ;
++ this.maxValue = maxValue ;
++ this.maxNumKeys = maxNumKeys ;
++ }
++
++ @Override
++ public void executeOneTest()
++ {
++ int numKeys = RandomLib.random.nextInt(maxNumKeys)+1 ;
++ IndexTestLib.randTest(maker.makeIndex(), maxValue, numKeys) ;
++ }
++}
[44/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/IndexTestLib.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/IndexTestLib.java
index 0000000,0000000..f4dd9a8
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/IndexTestLib.java
@@@ -1,0 -1,0 +1,218 @@@
++/*
++ * 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.dboe.index.test ;
++
++import static java.lang.String.format ;
++import static org.apache.jena.atlas.lib.ListUtils.asList ;
++import static org.apache.jena.atlas.lib.ListUtils.unique ;
++import static org.apache.jena.atlas.test.Gen.rand ;
++import static org.apache.jena.atlas.test.Gen.strings ;
++import static org.junit.Assert.assertEquals ;
++import static org.junit.Assert.assertNotNull ;
++import static org.junit.Assert.fail ;
++import static org.seaborne.dboe.test.RecordLib.intToRecord ;
++import static org.seaborne.dboe.test.RecordLib.r ;
++import static org.seaborne.dboe.test.RecordLib.toIntList ;
++
++import java.util.* ;
++
++import org.apache.jena.atlas.lib.RandomLib ;
++import org.apache.jena.ext.com.google.common.primitives.Ints;
++import org.junit.Assert ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.index.Index ;
++import org.seaborne.dboe.index.RangeIndex ;
++import org.seaborne.dboe.test.RecordLib ;
++
++public class IndexTestLib {
++
++ // ---------- Utilities
++
++ // public static RangeIndex buildRangeIndex(RangeIndexMaker maker, int[]
++ // keys)
++ // {
++ // RangeIndex index = maker.make() ;
++ // IndexTestLib.add(index, keys) ;
++ // return index ;
++ // }
++
++ public static Index buildIndex(IndexMaker maker, int[] keys) {
++ Index index = maker.makeIndex() ;
++ IndexTestLib.add(index, keys) ;
++ return index ;
++ }
++
++ private static Random random = RandomLib.qrandom ;
++
++ public static void testIteration(RangeIndex index, int[] keys, int numIterations) {
++ // Shared across test-lets
++ SortedSet<Integer> x = new TreeSet<>() ;
++ for ( int v : keys )
++ x.add(v) ;
++
++ for ( int i = 0 ; i < numIterations ; i++ ) {
++ int lo = random.nextInt(keys.length) ;
++ int hi = random.nextInt(keys.length) ;
++ if ( lo > hi ) {
++ int t = lo ;
++ lo = hi ;
++ hi = t ;
++ }
++ // Does not consider nulls for min, max)
++ // That is assumed to be part of functional testing.
++ // Tweak lo and hi
++ if ( lo != 0 && random.nextFloat() < 0.5 )
++ lo-- ; // Negatives confuse the int/record code.
++ if ( random.nextFloat() < 0.5 )
++ hi++ ;
++
++ List<Integer> slice = r(index.iterator(r(lo), r(hi))) ;
++ List<Integer> expected = new ArrayList<>(keys.length) ;
++ for ( Integer ii : x.subSet(lo, hi) )
++ expected.add(ii) ;
++ if ( ! expected.equals(slice) )
++ assertEquals(format("(%d,%d)", lo, hi), expected, slice) ;
++ }
++ }
++
++ /* One random test : print the keys if there was a problem */
++
++ public static void randTest(Index index, int maxValue, int numKeys) {
++ randTest(index, maxValue, numKeys, true) ;
++ }
++ public static void randTest(Index index, int maxValue, int numKeys, boolean includeIteratorCheck) {
++ if ( numKeys >= 5000 )
++ System.err.printf("Warning: too many keys\n") ;
++
++ int[] keys1 = rand(numKeys, 0, maxValue) ;
++ int[] keys2 = permute2(keys1) ;
++ //int[] keys2 = permute(keys1, 4 * numKeys) ;
++ //System.err.printf("int[] keys1 = {%s} ;\n", strings(keys1)) ;
++ //System.err.printf("int[] keys2 = {%s}; \n", strings(keys2)) ;
++ try {
++ testInsert(index, keys1) ;
++ if ( true ) {
++ // Checking tests.
++ testIndexContents(index, keys2) ;
++ // Test iteration - quite expensive.
++ if ( includeIteratorCheck && index instanceof RangeIndex )
++ testIteration((RangeIndex)index, keys1, 10) ;
++ }
++ testDelete(index, keys2) ;
++ }
++ catch (AssertionError | RuntimeException ex) {
++ System.err.printf("Index : %s\n", index.getClass().getName()) ;
++ System.err.printf("int[] keys1 = {%s} ;\n", strings(keys1)) ;
++ System.err.printf("int[] keys2 = {%s}; \n", strings(keys2)) ;
++ throw ex ;
++ }
++ }
++
++ /** Pull items out of the list in a random order */
++ private static int[] permute2(int[] x) {
++ int[] ints = Arrays.copyOf(x, x.length);
++ List<Integer> list = Ints.asList(ints);
++ Collections.shuffle(list, random);
++ return ints;
++ }
++
++ private static Random randInit()
++ {
++ // Cheap random numbers, well seeded.
++ int seed = random.nextInt() ;
++ return new Random(seed) ;
++ }
++
++ // ---- Test utils
++
++ public static void testInsert(Index index, int[] keys) {
++ IndexTestLib.add(index, keys) ;
++ testIndexContents(index, keys) ;
++ }
++
++ public static Index testInsert(IndexMaker maker, int[] keys) {
++ Index index = maker.makeIndex() ;
++ testInsert(index, keys) ;
++ return index ;
++ }
++
++ public static void testInsertDelete(Index index, int[] buildKeys, int[] deleteKeys) {
++ testInsert(index, buildKeys) ;
++ testDelete(index, deleteKeys) ;
++ }
++
++ public static void testDelete(Index index, int[] vals) {
++ long size1 = index.size() ;
++
++ int count = 0 ;
++ count = delete(index, vals) ;
++
++ List<Record> x = intToRecord(vals, RecordLib.TestRecordLength) ;
++ for ( Record r : x )
++ Assert.assertFalse(index.contains(r)) ;
++ long size2 = index.size() ;
++
++ assertEquals(size1 - count, size2) ;
++ }
++
++ public static int delete(Index index, int... vals) {
++ int count = 0 ;
++ for ( int v : vals ) {
++ boolean b = index.delete(r(v)) ;
++ if ( b )
++ count++ ;
++ }
++ return count ;
++ }
++
++ public static void add(Index index, int... vals) {
++ // System.out.println("Add: "+Arrays.toString(vals)) ;
++ List<Record> x = intToRecord(vals, RecordLib.TestRecordLength) ;
++ for ( Record r : x ) {
++ // System.out.println(" Add: "+r) ;
++ index.insert(r) ;
++ }
++ }
++
++ public static void testIndexContents(Index index, int... records) {
++ List<Integer> x = toIntList(index.iterator()) ;
++
++ // Make a unique list of expected records. Remove duplicates
++ List<Integer> y = unique(asList(records)) ;
++
++ assertEquals("Expected records size and tree size different", y.size(), index.size()) ;
++ assertEquals("Expected records size and iteration over all keys are of different sizes", y.size(), x.size()) ;
++
++ if ( index instanceof RangeIndex ) {
++ // Check sorted order
++ for ( int i = 0 ; i < x.size() - 2 ; i++ ) {
++ if ( x.get(i) > x.get(i + 1) ) {
++ fail("check failed: " + strings(records)) ;
++ return ;
++ }
++ }
++ }
++
++ // Check each expected record is in the tree
++ for ( int k : y ) {
++ Record rec = intToRecord(k) ;
++ Record r2 = index.find(rec) ;
++ assertNotNull(r2) ;
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/RangeIndexMaker.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/RangeIndexMaker.java
index 0000000,0000000..10c7b00
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index-test/src/main/java/org/seaborne/dboe/index/test/RangeIndexMaker.java
@@@ -1,0 -1,0 +1,27 @@@
++/*
++ * 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.dboe.index.test;
++
++import org.seaborne.dboe.index.RangeIndex ;
++
++public interface RangeIndexMaker extends IndexMaker
++{
++ RangeIndex makeRangeIndex() ;
++ @Override
++ String getLabel() ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index-test/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --cc jena-db/dboe-index-test/src/test/resources/log4j.properties
index 0000000,0000000..d6b299a
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index-test/src/test/resources/log4j.properties
@@@ -1,0 -1,0 +1,6 @@@
++log4j.rootLogger=INFO, stdlog
++
++log4j.appender.stdlog=org.apache.log4j.ConsoleAppender
++## log4j.appender.stdlog.target=System.err
++log4j.appender.stdlog.layout=org.apache.log4j.PatternLayout
++log4j.appender.stdlog.layout.ConversionPattern=%d{HH:mm:ss} %-5p %-20c{1} :: %m%n
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index/pom.xml
----------------------------------------------------------------------
diff --cc jena-db/dboe-index/pom.xml
index 0000000,0000000..28943de
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index/pom.xml
@@@ -1,0 -1,0 +1,42 @@@
++<?xml version="1.0" encoding="utf-8"?>
++<!--
++ 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.
++-->
++
++<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
++ <modelVersion>4.0.0</modelVersion>
++
++ <artifactId>dboe-index</artifactId>
++ <packaging>jar</packaging>
++ <name>Mantis (${project.artifactId})</name>
++
++ <parent>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>mantis</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </parent>
++
++ <dependencies>
++
++ <dependency>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>dboe-base</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </dependency>
++
++ </dependencies>
++
++</project>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/Index.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/Index.java
index 0000000,0000000..ddf4800
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/Index.java
@@@ -1,0 -1,0 +1,91 @@@
++/*
++ * 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.dboe.index;
++
++import java.util.Iterator ;
++import java.util.stream.Stream ;
++
++import org.apache.jena.atlas.lib.Closeable ;
++import org.apache.jena.atlas.lib.Sync ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++
++public interface Index extends Iterable<Record>, Sync, Closeable
++{
++ /** Find one record - and return the record actually in the index (may have a value part) */
++ public Record find(Record record) ;
++
++ /** Return whether the index contains the record or not. */
++ public boolean contains(Record record) ;
++
++ /** Insert a record - return true if an insertion was actually needed */
++ public boolean insert(Record record) ;
++
++ /** Delete a record - Return true if a record was actually removed */
++ public boolean delete(Record record) ;
++
++// public default void bulkInsert(Collection<Record> inserts) {
++// for ( Record r : inserts )
++// insert(r) ;
++// }
++//
++// public default void bulkDelete(Collection<Record> inserts) {
++// for ( Record r : inserts )
++// delete(r) ;
++// }
++
++ /** Bulk changes as given by a stream of changes.
++ * This is operations consumes the stream.
++ * @param changes
++ */
++ public default void bulkChanges(Stream<IndexChange> changes) {
++ changes.forEach(chg -> {
++ switch (chg.action) {
++ case ADD :
++ insert(chg.record) ;
++ break ;
++ case DELETE :
++ delete(chg.record) ;
++ break ;
++ }
++ }) ;
++ }
++
++ /** Iterate over the whole index */
++ @Override
++ public Iterator<Record> iterator() ;
++
++ /** Get the Record factory associated with this index */
++ public RecordFactory getRecordFactory() ;
++
++ /** Close the index - can not be used again through this object */
++ @Override
++ public void close() ;
++
++ /** Answer whether the index is empty or not. May return false for unknown or meaningless */
++ public boolean isEmpty() ;
++
++ /** Clear the index */
++ public void clear() ;
++
++ /** Perform checks on this index */
++ public void check() ;
++
++ /** Return size if known else return -1 : does not count the peristent storage */
++ public long size() ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexChange.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexChange.java
index 0000000,0000000..b296ae8
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexChange.java
@@@ -1,0 -1,0 +1,40 @@@
++/*
++ * 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.dboe.index;
++
++import java.util.Objects ;
++
++import org.seaborne.dboe.base.record.Record ;
++
++import org.apache.jena.sparql.core.DatasetChanges ;
++
++/** Temporary class to refine what to put into Jena itself.
++ * @see DatasetChanges
++ */
++public class IndexChange {
++ enum Action { ADD, DELETE }
++ final Action action ;
++ final Record record ;
++ public IndexChange(Action action, Record record) {
++ Objects.requireNonNull(action, "Action can not be null") ;
++ Objects.requireNonNull(record, "Record can not be null") ;
++ this.action = action ;
++ this.record = record ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexConst.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexConst.java
index 0000000,0000000..08797f4
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexConst.java
@@@ -1,0 -1,0 +1,52 @@@
++/*
++ * 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.dboe.index;
++
++import org.seaborne.dboe.base.block.FileMode ;
++import org.seaborne.dboe.sys.SystemIndex ;
++
++public class IndexConst {
++
++ private static IndexParams stdParams = new IndexParamsStd() ;
++ public static IndexParams getDftParams() { return stdParams ; }
++
++ private static class IndexParamsStd implements IndexParams {
++
++ @Override
++ public FileMode getFileMode() {
++ return SystemIndex.fileMode() ;
++ }
++
++ @Override
++ public Integer getBlockSize() {
++ return SystemIndex.BlockSize ;
++ }
++
++ @Override
++ public Integer getBlockReadCacheSize() {
++ return SystemIndex.BlockReadCacheSize ;
++ }
++
++ @Override
++ public Integer getBlockWriteCacheSize() {
++ return SystemIndex.BlockWriteCacheSize ;
++ }
++
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexLogger.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexLogger.java
index 0000000,0000000..ab2acf9
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexLogger.java
@@@ -1,0 -1,0 +1,64 @@@
++/*
++ * 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.dboe.index;
++
++import java.util.Iterator ;
++
++import org.seaborne.dboe.base.record.Record ;
++import org.slf4j.Logger ;
++
++public final class IndexLogger extends IndexWrapper
++{
++ private final Logger log ;
++
++ public IndexLogger(RangeIndex rIdx, Logger log)
++ {
++ super(rIdx) ;
++ this.log = log ;
++ }
++
++ @Override
++ public boolean insert(Record record)
++ {
++ log.info("Add: {}", record) ;
++ return super.insert(record) ;
++ }
++
++ @Override
++ public boolean delete(Record record)
++ {
++ log.info("Delete: {}", record) ;
++ return super.delete(record) ;
++ }
++
++ @Override
++ public Record find(Record record)
++ {
++ log.info("Find: {}", record) ;
++ Record r2 = super.find(record) ;
++ log.info("Find: "+record+" ==> "+r2) ;
++ return r2 ;
++ }
++
++ @Override
++ public Iterator<Record> iterator()
++ {
++ log.info("iterator()") ;
++ return super.iterator() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexMap.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexMap.java
index 0000000,0000000..b176a84
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexMap.java
@@@ -1,0 -1,0 +1,171 @@@
++/*
++ * 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.dboe.index;
++
++import java.util.Arrays ;
++import java.util.HashMap ;
++import java.util.Iterator ;
++import java.util.Map ;
++
++import org.apache.jena.atlas.lib.Bytes ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++
++/** A simple implementation of {@link Index} for testing */
++public class IndexMap implements Index
++{
++ private final Map<ByteArray, ByteArray> index = new HashMap<>() ;
++ private final RecordFactory recordFactory ;
++
++ public IndexMap(RecordFactory recordFactory)
++ {
++ this.recordFactory = recordFactory ;
++ }
++
++ @Override
++ public Record find(Record record)
++ {
++ ByteArray k = wrap(record.getKey()) ;
++ ByteArray v = index.get(k) ;
++ if ( v == null )
++ return null ;
++ return record(k, v) ;
++ }
++
++ @Override
++ public boolean contains(Record record)
++ {
++ Record r = find(record) ;
++ if ( r == null )
++ return false ;
++ if ( ! recordFactory.hasValue() )
++ return true ;
++ return Bytes.compare(record.getValue(), r.getValue()) == 0 ;
++ }
++
++ @Override
++ public boolean insert(Record record)
++ {
++ Record r = find(record) ;
++ if ( r != null && r.equals(record) )
++ return false ;
++ index.put(wrap(record.getKey()), wrap(record.getValue())) ;
++ return true ;
++ }
++
++ @Override
++ public boolean delete(Record record)
++ {
++ ByteArray x = index.remove(wrap(record.getKey())) ;
++ if ( x == null )
++ return false ;
++ return true ;
++ }
++
++ @Override
++ public Iterator<Record> iterator()
++ {
++ return new Iterator<Record>() {
++
++ Iterator<Map.Entry<ByteArray, ByteArray>> iter = index.entrySet().iterator() ;
++
++ @Override
++ public boolean hasNext()
++ {
++ return iter.hasNext() ;
++ }
++
++ @Override
++ public Record next()
++ {
++ Map.Entry<ByteArray, ByteArray> e = iter.next() ;
++ return record(e.getKey(), e.getValue()) ;
++ }
++
++ @Override
++ public void remove()
++ { throw new UnsupportedOperationException() ;}
++ } ;
++
++ }
++
++ @Override
++ public RecordFactory getRecordFactory()
++ {
++ return recordFactory ;
++ }
++
++ @Override
++ public boolean isEmpty()
++ {
++ return index.isEmpty() ;
++ }
++
++ @Override
++ public void clear()
++ {
++ index.clear() ;
++ }
++
++ @Override
++ public void check()
++ {}
++
++ @Override
++ public long size()
++ {
++ return index.size() ;
++ }
++
++ @Override
++ public void sync()
++ {}
++
++ @Override
++ public void close()
++ {}
++
++ private static ByteArray wrap(byte[] b) { return new ByteArray(b) ; }
++ private Record record(ByteArray k, ByteArray v) { return recordFactory.create(k.bytes, v.bytes) ; }
++
++ private static class ByteArray
++ {
++ byte[] bytes ;
++ ByteArray(byte[] bytes) { this.bytes = bytes ; }
++
++ @Override
++ public int hashCode()
++ {
++ final int prime = 31 ;
++ int result = 1 ;
++ result = prime * result + Arrays.hashCode(bytes) ;
++ return result ;
++ }
++ @Override
++ public boolean equals(Object obj)
++ {
++ if (this == obj) return true ;
++ if (obj == null) return false ;
++ if (getClass() != obj.getClass()) return false ;
++ ByteArray other = (ByteArray)obj ;
++ if (!Arrays.equals(bytes, other.bytes)) return false ;
++ return true ;
++ }
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexParams.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexParams.java
index 0000000,0000000..f3f25c9
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexParams.java
@@@ -1,0 -1,0 +1,37 @@@
++/*
++ * 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.dboe.index;
++
++import org.seaborne.dboe.base.block.BlockParams ;
++import org.seaborne.dboe.base.block.FileMode ;
++
++public interface IndexParams extends BlockParams {
++ /** File Mode */
++ @Override public FileMode getFileMode() ;
++
++ /** Block size - this is only configurable when the on-disk are created.
++ * After that, the same value as at creation must be used each time.
++ */
++ @Override public Integer getBlockSize() ;
++
++ /** Block read cache size (mmap'ed files do not have a block cache)*/
++ @Override public Integer getBlockReadCacheSize() ;
++
++ /** Block write cache size (mmap'ed files do not have a block cache)*/
++ @Override public Integer getBlockWriteCacheSize() ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexWrapper.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexWrapper.java
index 0000000,0000000..95de7f2
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/IndexWrapper.java
@@@ -1,0 -1,0 +1,91 @@@
++/*
++ * 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.dboe.index ;
++
++import java.util.Iterator ;
++
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++
++public class IndexWrapper implements Index {
++ protected final Index index ;
++
++ public IndexWrapper(Index idx) {
++ this.index = idx ;
++ }
++
++ @Override
++ public Record find(Record record) {
++ return index.find(record) ;
++ }
++
++ @Override
++ public boolean contains(Record record) {
++ return index.contains(record) ;
++ }
++
++ @Override
++ public boolean insert(Record record) {
++ return index.insert(record) ;
++ }
++
++ @Override
++ public boolean delete(Record record) {
++ return index.delete(record) ;
++ }
++
++ @Override
++ public Iterator<Record> iterator() {
++ return index.iterator() ;
++ }
++
++ @Override
++ public boolean isEmpty() {
++ return index.isEmpty() ;
++ }
++
++ @Override
++ public void clear() {
++ index.clear() ;
++ }
++
++ @Override
++ public void sync() {
++ index.sync() ;
++ }
++
++ @Override
++ public void close() {
++ index.close() ;
++ }
++
++ @Override
++ public RecordFactory getRecordFactory() {
++ return index.getRecordFactory() ;
++ }
++
++ @Override
++ public void check() {
++ index.check() ;
++ }
++
++ @Override
++ public long size() {
++ return index.size() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/RangeIndex.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/RangeIndex.java
index 0000000,0000000..b53c7f5
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/RangeIndex.java
@@@ -1,0 -1,0 +1,38 @@@
++/*
++ * 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.dboe.index;
++
++import java.util.Iterator ;
++
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordMapper ;
++
++
++public interface RangeIndex extends Index
++{
++ /** Return records between min (inclusive) and max (exclusive), based on the record keys */
++ public Iterator<Record> iterator(Record recordMin, Record recordMax) ;
++
++ public <X> Iterator<X> iterator(Record recordMin, Record recordMax, RecordMapper<X> mapper) ;
++
++ /** Return the record containing the least key - may or may not have the associated value */
++ public Record minKey() ;
++
++ /** Return the record containing the greatest key - may or may not have the associated value */
++ public Record maxKey() ;
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/RangeIndexLogger.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/RangeIndexLogger.java
index 0000000,0000000..7a7d70d
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/RangeIndexLogger.java
@@@ -1,0 -1,0 +1,71 @@@
++/*
++ * 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.dboe.index;
++
++import java.util.Iterator ;
++
++import org.seaborne.dboe.base.record.Record ;
++import org.slf4j.Logger ;
++
++public final class RangeIndexLogger extends RangeIndexWrapper
++{
++ private final Logger log ;
++
++ public RangeIndexLogger(RangeIndex rIdx, Logger log)
++ {
++ super(rIdx) ;
++ this.log = log ;
++ }
++
++ @Override
++ public boolean insert(Record record)
++ {
++ log.info("Add: "+record) ;
++ return super.insert(record) ;
++ }
++
++ @Override
++ public boolean delete(Record record)
++ {
++ log.info("Delete: "+record) ;
++ return super.delete(record) ;
++ }
++
++ @Override
++ public Record find(Record record)
++ {
++ log.info("Find: "+record) ;
++ Record r2 = super.find(record) ;
++ log.info("Find: "+record+" ==> "+r2) ;
++ return r2 ;
++ }
++
++ @Override
++ public Iterator<Record> iterator()
++ {
++ log.info("iterator()") ;
++ return super.iterator() ;
++ }
++
++ @Override
++ public Iterator<Record> iterator(Record minRec, Record maxRec)
++ {
++ log.info("iterator("+minRec+", "+maxRec+")") ;
++ return super.iterator(minRec, maxRec) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/RangeIndexWrapper.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/RangeIndexWrapper.java
index 0000000,0000000..f5510e5
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index/src/main/java/org/seaborne/dboe/index/RangeIndexWrapper.java
@@@ -1,0 -1,0 +1,105 @@@
++/*
++ * 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.dboe.index;
++
++import java.util.Iterator ;
++
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.base.record.RecordMapper ;
++
++public class RangeIndexWrapper implements RangeIndex
++{
++ // Could extend IndexWrapper but it's nice to have one place to look and set breakpoints.
++ protected final RangeIndex rIndex ;
++
++ public RangeIndexWrapper(RangeIndex rIdx) { this.rIndex = rIdx ; }
++
++ @Override
++ public Record find(Record record)
++ { return rIndex.find(record) ; }
++
++ @Override
++ public boolean contains(Record record)
++ { return rIndex.contains(record) ; }
++
++ @Override
++ public Record minKey()
++ { return rIndex.minKey() ; }
++
++ @Override
++ public Record maxKey()
++ { return rIndex.maxKey() ; }
++
++ @Override
++ public boolean insert(Record record)
++ { return rIndex.insert(record) ; }
++
++ @Override
++ public boolean delete(Record record)
++ { return rIndex.delete(record) ; }
++
++// public Record addAndReturnOld(Record record)
++// { return bpt.addAndReturnOld(record) ; }
++
++// public Record deleteAndReturnOld(Record record)
++// { return bpt.deleteAndReturnOld(record) ; }
++
++ @Override
++ public Iterator<Record> iterator()
++ { return rIndex.iterator() ; }
++
++ @Override
++ public Iterator<Record> iterator(Record minRec, Record maxRec)
++ { return rIndex.iterator(minRec, maxRec) ; }
++
++ @Override
++ public <X> Iterator<X> iterator(Record minRec, Record maxRec, RecordMapper<X> mapper)
++ { return rIndex.iterator(minRec, maxRec, mapper) ; }
++
++ @Override
++ public boolean isEmpty()
++ { return rIndex.isEmpty() ; }
++
++ @Override
++ public void clear()
++ { rIndex.clear() ; }
++
++ @Override
++ public void sync()
++ { rIndex.sync() ; }
++
++ @Override
++ public void close()
++ { rIndex.close() ; }
++
++ public RangeIndex getWrapped()
++ { return rIndex ; }
++
++ @Override
++ public RecordFactory getRecordFactory()
++ { return rIndex.getRecordFactory() ; }
++
++ @Override
++ public void check()
++ { rIndex.check() ; }
++
++ @Override
++ public long size()
++ { return rIndex.size() ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-index/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --cc jena-db/dboe-index/src/test/resources/log4j.properties
index 0000000,0000000..d6b299a
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-index/src/test/resources/log4j.properties
@@@ -1,0 -1,0 +1,6 @@@
++log4j.rootLogger=INFO, stdlog
++
++log4j.appender.stdlog=org.apache.log4j.ConsoleAppender
++## log4j.appender.stdlog.target=System.err
++log4j.appender.stdlog.layout=org.apache.log4j.PatternLayout
++log4j.appender.stdlog.layout.ConversionPattern=%d{HH:mm:ss} %-5p %-20c{1} :: %m%n
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/pom.xml
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/pom.xml
index 0000000,0000000..50756aa
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/pom.xml
@@@ -1,0 -1,0 +1,63 @@@
++<?xml version="1.0" encoding="utf-8"?>
++<!--
++ 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.
++-->
++
++<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
++ <modelVersion>4.0.0</modelVersion>
++ <artifactId>dboe-trans-data</artifactId>
++ <packaging>jar</packaging>
++ <name>Mantis (${project.artifactId})</name>
++
++ <parent>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>mantis</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </parent>
++
++ <dependencies>
++
++ <dependency>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>dboe-transaction</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </dependency>
++
++ <dependency>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>dboe-index</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ </dependency>
++
++ <dependency>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>dboe-index-test</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ <scope>test</scope>
++ </dependency>
++
++ <dependency>
++ <groupId>org.seaborne.mantis</groupId>
++ <artifactId>dboe-base</artifactId>
++ <version>0.3.1-SNAPSHOT</version>
++ <classifier>tests</classifier>
++ <scope>test</scope>
++ </dependency>
++
++
++ </dependencies>
++
++</project>
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/randtest
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/randtest
index 0000000,0000000..1e716dd
new file mode 100755
--- /dev/null
+++ b/jena-db/dboe-trans-data/randtest
@@@ -1,0 -1,0 +1,57 @@@
++#!/bin/bash
++
++M2="$HOME/.m2/repo"
++
++CPX="
++${M2}/com/fasterxml/jackson/core/jackson-annotations/2.3.0/jackson-annotations-2.3.0.jar
++${M2}/com/fasterxml/jackson/core/jackson-core/2.3.3/jackson-core-2.3.3.jar
++${M2}/com/fasterxml/jackson/core/jackson-databind/2.3.3/jackson-databind-2.3.3.jar
++${M2}/com/github/jsonld-java/jsonld-java/0.5.1/jsonld-java-0.5.1.jar
++${M2}/commons-codec/commons-codec/1.6/commons-codec-1.6.jar
++${M2}/junit/junit/4.12-beta-3/junit-4.12-beta-3.jar
++${M2}/log4j/log4j/1.2.17/log4j-1.2.17.jar
++${M2}/org/apache/commons/commons-csv/1.0/commons-csv-1.0.jar
++${M2}/org/apache/commons/commons-lang3/3.3.2/commons-lang3-3.3.2.jar
++${M2}/org/apache/httpcomponents/httpclient-cache/4.2.6/httpclient-cache-4.2.6.jar
++${M2}/org/apache/httpcomponents/httpclient/4.2.6/httpclient-4.2.6.jar
++${M2}/org/apache/httpcomponents/httpcore/4.2.5/httpcore-4.2.5.jar
++${M2}/org/apache/jena/jena-arq/2.13.0-SNAPSHOT/jena-arq-2.13.0-SNAPSHOT.jar
++${M2}/org/apache/jena/jena-core/2.13.0-SNAPSHOT/jena-core-2.13.0-SNAPSHOT.jar
++${M2}/org/apache/jena/jena-iri/1.1.2-SNAPSHOT/jena-iri-1.1.2-SNAPSHOT.jar
++${M2}/org/apache/thrift/libthrift/0.9.2/libthrift-0.9.2.jar
++${M2}/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar
++${M2}/org/slf4j/jcl-over-slf4j/1.7.6/jcl-over-slf4j-1.7.6.jar
++${M2}/org/slf4j/slf4j-api/1.7.6/slf4j-api-1.7.6.jar
++${M2}/org/slf4j/slf4j-log4j12/1.7.6/slf4j-log4j12-1.7.6.jar
++${M2}/xerces/xercesImpl/2.11.0/xercesImpl-2.11.0.jar
++${M2}/xml-apis/xml-apis/1.4.01/xml-apis-1.4.01.jar
++"
++
++CP=""
++for x in $CPX
++do
++ if [[ $CP == "" ]]
++ then
++ CP="$x"
++ else
++ CP="$CP:$x"
++ fi
++done
++
++MANTIS="$HOME/Mantis"
++for x in dboe-base dboe-index dboe-index-test dboe-transaction
++do
++ CP="$MANTIS/$x/target/classes:$CP"
++ CP="$MANTIS/$x/target/test-classes:$CP"
++done
++
++ARGS=""
++#ARGS="-Xmx1G"
++ARGS="$ARGS -Dbpt:checking=true"
++ARGS="$ARGS -Dbpt:duplication=true"
++
++
++CP="target/classes:target/test-classes:$CP"
++#echo $CP
++#java -cp "$CP" org.seaborne.dboe.trans.bplustree.rewriter.CmdTestBPlusTreeRewriter "$@"
++java $ARGS -cp "$CP" org.seaborne.dboe.trans.bplustree.soak.CmdTestBPlusTree "$@"
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/AccessPath.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/AccessPath.java
index 0000000,0000000..af62e04
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/AccessPath.java
@@@ -1,0 -1,0 +1,69 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import java.util.ArrayList ;
++import java.util.List ;
++import java.util.stream.Collectors ;
++
++import org.apache.jena.atlas.lib.InternalErrorException ;
++
++public class AccessPath {
++ static class AccessStep {
++ final BPTreeNode node ;
++ final int idx ;
++ final BPTreePage page ;
++ AccessStep(BPTreeNode node, int idx, BPTreePage page) {
++ this.node = node ;
++ this.idx = idx ;
++ this.page = page ;
++ }
++
++ @Override
++ public String toString() {
++ return "("+node.label()+", "+idx+")->"+page.getId() ;
++ }
++ }
++
++ private final BPTreeNode root ;
++ private List<AccessStep> traversed = new ArrayList<>() ;
++
++ public AccessPath(BPTreeNode root) {
++ this.root = root ;
++ }
++
++ public void add(BPTreeNode node, int idx, BPTreePage page) {
++ traversed.add(new AccessStep(node, idx, page)) ;
++ }
++
++ public void reset(BPTreeNode node, int idx, BPTreePage page) {
++ AccessStep s = traversed.remove(traversed.size()-1) ;
++ AccessStep s2 = new AccessStep(node, idx, page) ;
++ if ( s.node != s2.node )
++ throw new InternalErrorException("Bad attempt to reset: "+this+" with "+s2) ;
++ traversed.add(new AccessStep(node, idx, page)) ;
++ }
++
++ public List<AccessStep> getPath() { return traversed ; }
++
++ @Override
++ public String toString() {
++ return traversed.stream().map(x-> x.toString()).collect(Collectors.toList()).toString() ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPT.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPT.java
index 0000000,0000000..f849367
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPT.java
@@@ -1,0 -1,0 +1,248 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import static java.lang.String.format ;
++import static org.apache.jena.atlas.lib.Alg.decodeIndex ;
++
++import java.util.List ;
++import java.util.Optional ;
++
++import org.apache.jena.atlas.lib.InternalErrorException ;
++import org.apache.jena.atlas.logging.FmtLog ;
++import org.seaborne.dboe.base.block.BlockMgr ;
++import org.seaborne.dboe.base.file.BufferChannel ;
++import org.seaborne.dboe.sys.SystemIndex ;
++import org.seaborne.dboe.trans.bplustree.AccessPath.AccessStep ;
++import org.slf4j.Logger ;
++
++/** B+Tree assist functions */
++public final class BPT {
++ public static boolean Logging = false ; // Turn on/off logging
++
++ public static boolean forcePromoteModes = false ;
++ public static boolean promoteDuplicateRecords = false ;
++ public static boolean promoteDuplicateNodes = false ;
++
++ // Check within BPTreeNode
++ public static boolean CheckingNode = false ;
++ // Check on exit of B+Tree modifiying operations
++ // Not done?
++ public static boolean CheckingConcurrency = SystemIndex.Checking ;
++
++ /** Enable detailed internal consistency checking */
++ public static void checking(boolean onOrOff) {
++ CheckingNode = onOrOff ;
++ }
++
++ /** Dump before and after top level update operations **/
++ public static boolean DumpTree = false ;
++
++ /** Output a lot of detailed information. */
++ public static void infoAll(boolean onOrOff) {
++ DumpTree = true ;
++ Logging = true ;
++ }
++
++ static boolean logging(Logger log) {
++ return Logging && log.isDebugEnabled() ;
++ }
++
++ static void log(Logger log, String fmt, Object... args) {
++ if ( logging(log) ) {
++ FmtLog.debug(log, fmt, args);
++ }
++ }
++
++ static void warning(String msg, Object... args) {
++ msg = format(msg, args) ;
++ System.out.println("Warning: " + msg) ;
++ System.out.flush() ;
++ }
++
++ static void error(String msg, Object... args) {
++ msg = format(msg, args) ;
++ System.out.println() ;
++ System.out.println(msg) ;
++ System.out.flush() ;
++ throw new BPTreeException(msg) ;
++ }
++
++ /** Convert a find index return to the insert location in the array */
++ static int apply(int idx) {
++ if ( idx >= 0 )
++ return idx ;
++ return decodeIndex(idx) ;
++ }
++
++ // ---- Promotion of pages.
++
++ /** Promote a single page. Assumes the path to this page has been handled in some way elsewhere */
++ static boolean promote1(BPTreePage page, BPTreeNode node, int idx) {
++ //System.out.println("promote1: "+page.getBlockMgr().getLabel()+" "+page.getBackingBlock().getId()) ;
++ boolean changed = page.promote() ;
++ node.ptrs.set(idx, page.getId()) ;
++ return changed ;
++ }
++
++ /** Promote a B+Tree root */
++ static boolean promoteRoot(BPTreeNode root) {
++ if ( ! root.isRoot() )
++ throw new InternalErrorException("Not a root") ;
++ boolean changed = root.promote() ;
++ root.bpTree.newRoot(root) ;
++ return changed ;
++ }
++
++ /** Promote a B+Tree page */
++ static void promotePage(AccessPath path, BPTreePage page) {
++ Logger pageLog = page.getLogger() ;
++ boolean loggingCall = logging(pageLog) ;
++ if ( loggingCall )
++ log(pageLog, "Promote :: Path=%s Page=%s", path, page) ;
++ // ---- Checking if the access path is consistent.
++ if ( BPT.CheckingNode && path != null ) {
++ if ( path.getPath().size() > 2) {
++ // Check every one except the last is not a leaf node.
++ List<AccessStep> y = path.getPath().subList(0, path.getPath().size()-2) ;
++ Optional<AccessStep> z = y.stream().filter(e -> e.node.isLeaf() ).findFirst() ;
++ if ( z.isPresent() )
++ error("promote: Leaf %s found in path but not at the tail: %s") ;
++ }
++ // Check the page/index pointers
++ Optional<AccessStep> z2 = path.getPath().stream().filter(e -> e.node.ptrs.get(e.idx) != e.page.getId()).findFirst() ;
++ if ( z2.isPresent() )
++ error("promote: path error: %s in %s", z2.get(), path) ;
++ }
++
++ // ---- Clone the access path nodes.
++ // Path is the route to this page - it does not include this page.
++ // Work from the bottom to the top, the reverse order of AccessPath
++ if ( loggingCall )
++ log(pageLog, " page>> %s", page.label()) ;
++ boolean changed = page.promote();
++ if ( loggingCall ) {
++ if ( changed )
++ log(pageLog, " page<< %s", page.label()) ;
++ else
++ log(pageLog, " .. no change") ;
++ }
++
++ if ( changed )
++ page.write() ; // Being careful.
++
++ // Even if the page did not change, make sure the chain is dealt with.
++ // e.g. promote in place policies.
++ //if ( changed ) {
++ if ( path != null ) {
++ // Sequence of promote1 calls? + root.
++
++ List<AccessStep> steps = path.getPath() ;
++
++ int newPtr = page.getId() ;
++ BPTreePage newPage = null ;
++ boolean previousChanged = changed ;
++ BPTreeNode newRoot = null ;
++
++ if ( logging(pageLog) )
++ log(pageLog, "Path: %s", path) ;
++ // Duplicate from bottom to top.
++ for ( int i = steps.size() - 1 ; i >= 0 ; i-- ) {
++ AccessStep s = steps.get(i) ;
++ // duplicate
++ BPTreeNode n = s.node ;
++ if ( logging(pageLog) )
++ log(pageLog, " >> %s", n) ;
++
++ changed = n.promote() ;
++
++ if ( previousChanged ) {
++ // Even if n did not change, if it's sub changed, need to update s.idx.
++ n.ptrs.set(s.idx, newPtr) ;
++ } else {
++ if ( ! changed ) {
++ if ( logging(pageLog) )
++ log(pageLog, " .. no change") ;
++ continue ;
++ }
++ }
++
++ previousChanged = changed ;
++
++ if ( logging(pageLog) )
++ log(pageLog, " << %s", n) ;
++
++ if ( n.isRoot() ) {
++ if ( newRoot != null)
++ throw new InternalErrorException("New root already found") ;
++ newRoot = n ;
++ }
++ newPtr = n.getId() ;
++ n.write() ;
++
++ }
++ if ( newRoot != null ) {
++ if ( loggingCall )
++ log(pageLog, " new root %s", newRoot) ;
++ page.bpTree.newRoot(newRoot) ;
++ }
++ } // end of "if ( path != null )"
++ }
++
++ /**
++ * The initial tree is a single root node with no records block below it. It
++ * is an illegal tree. We make it by creating a real tree, deleting and
++ * freeing the records block from the root, then resetting the records block
++ * manager. This is to avoid having specialized creating code in
++ * BPlusTreeFactory solely for the rewriter.
++ */
++ public static BPlusTree createRootOnlyBPTree(BPlusTreeParams bptParams,
++ BufferChannel bptState,
++ BlockMgr blkMgrNodes,
++ BlockMgr blkMgrRecords) {
++ BPlusTree bpt = BPlusTreeFactory.createNonTxn(bptParams, bptState, blkMgrNodes, blkMgrRecords) ;
++
++ BPTreeRecordsMgr recordsMgr = bpt.getRecordsMgr() ;
++
++ BPTreeRecords recordsPage = recordsMgr.getWrite(0) ;
++// recordsPage.getRecordBuffer().clear();
++// recordsMgr.write(recordsPage) ;
++ recordsMgr.free(recordsPage);
++// recordsMgr.release(recordsPage);
++ recordsMgr.resetAlloc(0);
++
++ BPTreeNodeMgr nodeMgr = bpt.getNodeManager() ;
++
++ // Alter the root node.
++ BPTreeNode root = nodeMgr.getWrite(BPlusTreeParams.RootId, BPlusTreeParams.RootParent) ;
++ int rootId = root.getId() ;
++ if ( rootId != 0 )
++ throw new BPTreeException("**** Not the root: " + rootId) ;
++
++ // Undo the records block.
++ root.getPtrBuffer().clear() ;
++ root.getRecordBuffer().clear() ;
++ //root.setCount(-1);
++ nodeMgr.write(root);
++ nodeMgr.release(root);
++
++ // Now a broken tree of one root block and no records.
++ return bpt ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTStateMgr.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTStateMgr.java
index 0000000,0000000..cb7049c
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTStateMgr.java
@@@ -1,0 -1,0 +1,89 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import org.apache.jena.atlas.logging.FmtLog ;
++import org.seaborne.dboe.base.file.BufferChannel ;
++import org.seaborne.dboe.transaction.txn.StateMgrData ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/** Manage the persistent state of the tree
++ *
++ * This consists of last commited root, and the limits on the blocks for both
++ * nodes and records.
++ *
++ * (rootId/int-as-long, nodeAllocLimit/long, recordsAllocLimit/long)
++ */
++public class BPTStateMgr extends StateMgrData {
++ private static Logger log = LoggerFactory.getLogger(BPTStateMgr.class) ;
++
++ private static int idxRoot = 0 ;
++ private static int idxNodeBlocksLimit = 1 ;
++ private static int idxRecordsBlocksLimit = 2 ;
++
++ private int currentRoot() { return (int)super.get(idxRoot) ; }
++ private long nodeBlocksLimit() { return super.get(idxNodeBlocksLimit) ; }
++ private long recordsBlocksLimit() { return super.get(idxRecordsBlocksLimit) ; }
++
++ private void currentRoot(int x) { super.set(idxRoot, x) ; }
++ private void nodeBlocksLimit(long x) { super.set(idxNodeBlocksLimit, x) ; }
++ private void recordsBlocksLimit(long x) { super.set(idxRecordsBlocksLimit, x) ; }
++
++ private boolean LOGGING = BPT.Logging ;
++
++ public BPTStateMgr(BufferChannel storage) {
++ // These values are the values for a null tree (no blocks).
++ super(storage, 0L, 0L, 0L) ;
++ }
++
++ /*package*/ void setState(int rootIdx, long nodeBlkLimit, long recordsBlkLimit) {
++ currentRoot(rootIdx) ;
++ nodeBlocksLimit(nodeBlkLimit) ;
++ recordsBlocksLimit(recordsBlkLimit) ;
++ log("Set") ;
++ setDirtyFlag() ;
++ // But don't write it.
++ }
++ @Override
++ protected void writeStateEvent() {
++ log("Write") ;
++ }
++
++ @Override
++ protected void readStateEvent() {
++ log("Read") ;
++ }
++
++ private void log(String operation) {
++ if ( LOGGING )
++ FmtLog.info(log, "%s state: root=%d // node block limit = %d // records block limit %d", operation, currentRoot(), nodeBlocksLimit(), recordsBlocksLimit()) ;
++ }
++
++ public int getRoot() {
++ return currentRoot() ;
++ }
++
++ public long getNodeBlocksLimit() {
++ return nodeBlocksLimit() ;
++ }
++
++ public long getRecordsBlocksLimit() {
++ return recordsBlocksLimit() ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeException.java
----------------------------------------------------------------------
diff --cc jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeException.java
index 0000000,0000000..423785a
new file mode 100644
--- /dev/null
+++ b/jena-db/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/bplustree/BPTreeException.java
@@@ -1,0 -1,0 +1,26 @@@
++/*
++ * 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.dboe.trans.bplustree;
++
++import org.seaborne.dboe.DBOpEnvException ;
++
++public class BPTreeException extends DBOpEnvException
++{
++ public BPTreeException() {}
++ public BPTreeException(String msg) { super(msg) ; }
++}
[33/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParamsConst.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParamsConst.java
index 0000000,0000000..b3a352a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParamsConst.java
@@@ -1,0 -1,0 +1,104 @@@
++/*
++ * 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.setup;
++
++import org.seaborne.dboe.base.block.FileMode ;
++import org.seaborne.dboe.sys.Names ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++
++public class StoreParamsConst {
++ // SystemParams are built with a SystemParamsBuilder
++ // Initial values are the system defaults.
++
++ /** Database and query configuration */
++ // Key names are the base name - encode/decode may add a prefix.
++
++ public static final String fFileMode = "file_mode" ;
++ public static final FileMode fileMode = SystemTDB.fileMode() ;
++
++ public static final String fBlockReadCacheSize = "block_read_cache_size" ;
++ public static final int blockReadCacheSize = SystemTDB.BlockReadCacheSize ;
++
++ public static final String fBlockWriteCacheSize = "block_write_cache_size" ;
++ public static final int blockWriteCacheSize = SystemTDB.BlockWriteCacheSize ;
++
++ public static final String fNode2NodeIdCacheSize = "node2nodeid_cache_size" ;
++ public static final int Node2NodeIdCacheSize = SystemTDB.Node2NodeIdCacheSize ;
++
++ public static final String fNodeId2NodeCacheSize = "nodeid2node_cache_size" ;
++ public static final int NodeId2NodeCacheSize = SystemTDB.NodeId2NodeCacheSize ;
++
++ public static final String fNodeMissCacheSize = "node_miss_cache_size" ;
++ public static final int NodeMissCacheSize = SystemTDB.NodeMissCacheSize ;
++
++ /** Database layout - ignored after a database is created */
++ public static final String fBlockSize = "block_size" ;
++ public static final int blockSize = SystemTDB.BlockSize ;
++
++ public static final String fNodeTableBaseName = "nodetable" ;
++ public static final String nodeTableBaseName = Names.nodeTableBaseName ;
++
++ public static final String fPrimaryIndexTriples = "triple_index_primary" ;
++ public static final String primaryIndexTriples = Names.primaryIndexTriples ;
++
++ public static final String fTripleIndexes = "triple_indexes" ;
++ public static final String[] tripleIndexes = Names.tripleIndexes ;
++
++ public static final String fPrimaryIndexQuads = "quad_index_primary" ;
++ public static final String primaryIndexQuads = Names.primaryIndexQuads ;
++
++ public static final String fQuadIndexes = "quad_indexes" ;
++ public static final String[] quadIndexes = Names.quadIndexes ;
++
++ public static final String fPrefixTableBaseName = "prefixtable" ;
++ public static final String prefixTableBaseName = Names.prefixTableBaseName ;
++
++ public static final String fPrimaryIndexPrefix = "prefix_index_primary" ;
++ public static final String primaryIndexPrefix = Names.primaryIndexPrefix ;
++
++ public static final String fPrefixIndexes = "prefix_indexes" ;
++ public static final String[] prefixIndexes = Names.prefixIndexes ;
++
++ // Must be after the constants above to get initialization order right
++ // because StoreParamsBuilder uses these constants.
++
++ /** The system default parameters for on-disk databases. */
++ static StoreParams dftStoreParams = StoreParams.builder().build() ;
++
++ /** The system default parameters for in-memory databases. */
++ static StoreParams dftMemStoreParams = StoreParams.builder()
++ .fileMode(FileMode.direct)
++ // Small block caches, mainly so it behaves like a direct on-disk database.
++ .blockReadCacheSize(10)
++ .blockWriteCacheSize(10)
++ .node2NodeIdCacheSize(10000)
++ .nodeId2NodeCacheSize(10000)
++ .nodeMissCacheSize(100)
++ .build() ;
++
++ /** The "small store" parameters. */
++ static StoreParams smallStoreParams = StoreParams.builder()
++ .fileMode(FileMode.direct)
++ .blockReadCacheSize(100)
++ .blockWriteCacheSize(100)
++ .node2NodeIdCacheSize(10000)
++ .nodeId2NodeCacheSize(10000)
++ .nodeMissCacheSize(100)
++ .build() ;
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParamsDynamic.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParamsDynamic.java
index 0000000,0000000..3d21185
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParamsDynamic.java
@@@ -1,0 -1,0 +1,53 @@@
++/*
++ * 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.setup;
++
++import org.seaborne.dboe.base.block.FileMode ;
++
++/** Store parameters that can be adjusted after a store has been created,
++ * and given different values when the JVM attachs to a store area.
++ * (They are still fixed for any given database once created in a JVM.)
++ */
++
++public interface StoreParamsDynamic {
++
++ /** Store-wide file access mode */
++ public FileMode getFileMode() ;
++ public boolean isSetFileMode() ;
++
++ /** Block read cache (note: mapped files do not have a block cache) */
++ public Integer getBlockReadCacheSize() ;
++ public boolean isSetBlockReadCacheSize() ;
++
++ /** Block write cache (note: mapped files do not have a block cache) */
++ public Integer getBlockWriteCacheSize() ;
++ public boolean isSetBlockWriteCacheSize() ;
++
++ /** Node cache for Node->NodeId. */
++ public Integer getNode2NodeIdCacheSize() ;
++ public boolean isSetNode2NodeIdCacheSize() ;
++
++ /** Node cache for NodeId->Node. Important for SPARQL results. */
++ public Integer getNodeId2NodeCacheSize() ;
++ public boolean isSetNodeId2NodeCacheSize() ;
++
++ /** Node cache for recording known misses */
++ public Integer getNodeMissCacheSize() ;
++ public boolean isSetNodeMissCacheSize() ;
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParamsFactory.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParamsFactory.java
index 0000000,0000000..5f5aa4b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParamsFactory.java
@@@ -1,0 -1,0 +1,93 @@@
++/*
++ * 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.setup;
++
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.sys.Names;
++import org.seaborne.tdb2.TDB2Factory ;
++
++public class StoreParamsFactory {
++ /** Choose the StoreParams. This is the policy applied when creating or reattaching to a database.
++ * (extracted and put here to keep the size of DatasetBuildStd
++ * <p>
++ * If the location has parameters in a <tt>tdb.cfg</tt> file, use them, as modified by any
++ * application-supplied internal parameters.
++ * <p>
++ * Otherwise, if this is a new database, use the application provided
++ * parameters or if there are no application provided
++ * parameters, use the system default parameters.
++ * Write the parameters used to the location in <tt>tdb.cfg</tt>
++ * <p>If this is an existing database and there are no location recorded parameters,
++ * use system default parameters, modified by application parameters.
++ * <p>
++ * Notes:
++ * <ul>
++ * <li><i>Modification</i> involves setting any of the parameters than can vary from run to run.
++ * These are the cache sizes and the file mode.
++ * <li><i>Block size</i>: it is critical that this set correctly. Silent corruption
++ * of a database may occur if this is changed. At the moment, it is not possible to provide
++ * a complete check of block size.
++ * <ul>
++ * <p>
++ * Do not edit store parameters recorded at a location after the database has been created.
++ * Only the dynamic parameters cna be safely changed. That is better done though the application
++ * providing some parameters in the {@link TDB2Factory} call.
++ * <p>
++ * This includes changing filenames, indexing choices and block size.
++ * Otherwise, the database may be permanetly and irrecovably corrupted.
++ * You have been warned.
++ *
++ * @param location The place where the database is or will be.
++ * @param isNew Whether the database is being created or whether there is an existing database.
++ * @param pApp Application-provide store parameters.
++ * @param pLoc Store parameters foud at the location.
++ * @param pDft System default store parameters.
++ * @return StoreParams
++ *
++ * @see StoreParams
++ * @see StoreParamsDynamic
++ */
++ public static StoreParams decideStoreParams(Location location, boolean isNew, StoreParams pApp, StoreParams pLoc, StoreParams pDft) {
++ StoreParams p = null ;
++ if ( pLoc != null ) {
++ // pLoc so use it, modify by pApp.
++ // Covers new and reconnect cases.
++ p = pLoc ;
++ if ( pApp != null )
++ p = StoreParamsBuilder.modify(pLoc, pApp) ;
++ return p ;
++ }
++ // No pLoc.
++ // Use pApp if available. Write to location if new.
++ if ( pApp != null ) {
++ if ( isNew ) {
++ if ( ! location.isMem() ) {
++ String filename = location.getPath(Names.TDB_CONFIG_FILE) ;
++ StoreParamsCodec.write(filename, pApp) ;
++ }
++ return pApp ;
++ }
++ // Not new : pLoc is implicitly pDft.
++ return StoreParamsBuilder.modify(pDft, pApp) ;
++ }
++ // no pLoc, no pApp
++ return pDft ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/TDBBuilder.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/TDBBuilder.java
index 0000000,0000000..88e18fc
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/TDBBuilder.java
@@@ -1,0 -1,0 +1,290 @@@
++/*
++ * 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.setup;
++
++import java.io.File ;
++import java.io.FileFilter ;
++import java.util.UUID ;
++
++import org.apache.jena.atlas.lib.tuple.TupleMap ;
++import org.apache.jena.sparql.engine.main.QC ;
++import org.apache.jena.sparql.engine.optimizer.reorder.ReorderLib ;
++import org.seaborne.dboe.DBOpEnvException ;
++import org.seaborne.dboe.base.file.* ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.index.Index ;
++import org.seaborne.dboe.index.RangeIndex ;
++import org.seaborne.dboe.sys.Names ;
++import org.seaborne.dboe.trans.bplustree.BPlusTree ;
++import org.seaborne.dboe.trans.bplustree.BPlusTreeFactory ;
++import org.seaborne.dboe.trans.data.TransBinaryDataFile ;
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++import org.seaborne.dboe.transaction.txn.TransactionCoordinator ;
++import org.seaborne.dboe.transaction.txn.TransactionalBase ;
++import org.seaborne.dboe.transaction.txn.TransactionalSystem ;
++import org.seaborne.dboe.transaction.txn.journal.Journal ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.solver.OpExecutorTDB1 ;
++import org.seaborne.tdb2.store.* ;
++import org.seaborne.tdb2.store.nodetable.NodeTable ;
++import org.seaborne.tdb2.store.nodetable.NodeTableCache ;
++import org.seaborne.tdb2.store.nodetable.NodeTableInline ;
++import org.seaborne.tdb2.store.nodetable.NodeTableTRDF ;
++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.SystemTDB ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++// Takes from TDB2Builder
++// Converted to statics.
++
++/** Build TDB2 databases.
++ * <p>
++ * <b>Do not call these operations directly - use StoreConnection.</b>
++ */
++public class TDBBuilder {
++ private Logger log = LoggerFactory.getLogger(TDBBuilder.class) ;
++
++ public static DatasetGraphTxn build(Location location) {
++ return build(location, StoreParams.getDftStoreParams()) ;
++ }
++
++ public static DatasetGraphTxn build(Location location, StoreParams appParams) {
++ StoreParams locParams = StoreParamsCodec.read(location) ;
++ StoreParams dftParams = StoreParams.getDftStoreParams() ;
++ // This can write the chosen parameters if necessary (new database, appParams != null, locParams == null)
++ boolean newArea = isNewDatabaseArea(location) ;
++ if ( newArea ) {
++ }
++ StoreParams params = StoreParamsFactory.decideStoreParams(location, newArea, appParams, locParams, dftParams) ;
++ return create(location, params).build$() ;
++ }
++
++ private DatasetGraphTxn build$() {
++ NodeTable nodeTable = buildNodeTable(params.getNodeTableBaseName()) ;
++
++ TripleTable tripleTable = buildTripleTable(nodeTable) ;
++ QuadTable quadTable = buildQuadTable(nodeTable) ;
++
++ NodeTable nodeTablePrefixes = buildNodeTable(params.getPrefixTableBaseName()) ;
++ DatasetPrefixesTDB prefixes = buildPrefixTable(nodeTablePrefixes) ;
++
++ TransactionalSystem trans = new TransactionalBase(txnCoord) ;
++ DatasetGraphTxn dsg = new DatasetGraphTDB(trans,
++ tripleTable, quadTable, prefixes,
++ ReorderLib.fixed(), location, params) ;
++ QC.setFactory(dsg.getContext(), OpExecutorTDB1.OpExecFactoryTDB) ;
++ txnCoord.start() ;
++ return dsg ;
++ }
++
++ public static TransactionCoordinator buildTransactionCoordinator(Location location) {
++ Journal journal = Journal.create(location) ;
++ TransactionCoordinator txnCoord = new TransactionCoordinator(journal) ;
++ return txnCoord ;
++ }
++
++ public static String choosePrimaryForIndex(StoreParams params, String index) {
++ String primary3 = params.getPrimaryIndexTriples() ;
++ String primary4 = params.getPrimaryIndexQuads() ;
++
++ if ( index.length() == primary3.length() )
++ return primary3 ;
++ if ( index.length() == primary4.length() )
++ return primary4 ;
++ throw new DBOpEnvException("Can't find primary for '"+index+"'") ;
++ }
++
++ // ---- Object starts
++ final Location location ;
++ final StoreParams params ;
++ final ComponentIdMgr componentIdMgr ;
++ final TransactionCoordinator txnCoord ;
++
++ private TDBBuilder(TransactionCoordinator txnCoord, Location location, StoreParams params, ComponentIdMgr componentIdMgr) {
++ this.txnCoord = txnCoord ;
++ this.location = location ;
++ this.params = params ;
++ this.componentIdMgr = componentIdMgr ;
++ }
++
++ public Location getLocation() { return location ; }
++ public StoreParams getParams() { return params ; }
++ public TransactionCoordinator getTxnCoord() { return txnCoord ; }
++
++ public static TDBBuilder create(Location location) {
++ return create(location, StoreParams.getDftStoreParams()) ;
++ }
++
++ public static TDBBuilder create(Location location, StoreParams params) {
++ TransactionCoordinator txnCoord = buildTransactionCoordinator(location) ;
++ return new TDBBuilder(txnCoord, location, params, new ComponentIdMgr(UUID.randomUUID())) ;
++ }
++
++ public static TDBBuilder create(TransactionCoordinator txnCoord, Location location, StoreParams params) {
++ return new TDBBuilder(txnCoord, location, params, new ComponentIdMgr(UUID.randomUUID())) ;
++ }
++
++ /** Look at a directory and see if it is a new area */
++ private static boolean isNewDatabaseArea(Location location) {
++ if ( location.isMem() )
++ return true ;
++ File d = new File(location.getDirectoryPath()) ;
++ if ( !d.exists() )
++ return true ;
++ FileFilter ff = fileFilterNewDB ;
++ File[] entries = d.listFiles(ff) ;
++ return entries.length == 0 ;
++ }
++
++ /** FileFilter
++ * Skips "..", ".", "tdb.lock" and "tdb.cfg"
++ *
++ */
++ private static FileFilter fileFilterNewDB = (pathname)->{
++ String fn = pathname.getName() ;
++ if ( fn.equals(".") || fn.equals("..") )
++ return false ;
++ if ( pathname.isDirectory() )
++ return true ;
++ if ( fn.equals(Names.TDB_LOCK_FILE) )
++ return false ;
++ if ( fn.equals(Names.TDB_CONFIG_FILE) )
++ return false ;
++
++ return true ;
++ } ;
++
++ public TripleTable buildTripleTable(NodeTable nodeTable) {
++ String primary = params.getPrimaryIndexTriples() ;
++ String[] indexes = params.getTripleIndexes() ;
++
++ // Validation checks - common index forms.
++ if ( indexes.length != 3 && indexes.length != 2 )
++ error(log, "Wrong number of triple table indexes: "+String.join(",", indexes)) ;
++ log.debug("Triple table: "+primary+" :: "+String.join(",", indexes)) ;
++
++ TupleIndex tripleIndexes[] = makeTupleIndexes(primary, indexes) ;
++
++ if ( tripleIndexes.length != indexes.length )
++ error(log, "Wrong number of triple table tuples indexes: "+tripleIndexes.length) ;
++ TripleTable tripleTable = new TripleTable(tripleIndexes, nodeTable) ;
++ return tripleTable ;
++ }
++
++ public QuadTable buildQuadTable(NodeTable nodeTable) {
++ String primary = params.getPrimaryIndexQuads() ;
++ String[] indexes = params.getQuadIndexes() ;
++
++ // Validation checks - common index forms.
++ if ( indexes.length != 6 && indexes.length != 4 )
++ error(log, "Wrong number of quad table indexes: "+String.join(",", indexes)) ;
++ log.debug("Quad table: "+primary+" :: "+String.join(",", indexes)) ;
++
++ TupleIndex tripleIndexes[] = makeTupleIndexes(primary, indexes) ;
++
++ if ( tripleIndexes.length != indexes.length )
++ error(log, "Wrong number of triple table tuples indexes: "+tripleIndexes.length) ;
++ QuadTable tripleTable = new QuadTable(tripleIndexes, nodeTable) ;
++ return tripleTable ;
++ }
++
++ public DatasetPrefixesTDB buildPrefixTable(NodeTable prefixNodes) {
++ String primary = params.getPrimaryIndexPrefix() ;
++ String[] indexes = params.getPrefixIndexes() ;
++
++ TupleIndex prefixIndexes[] = makeTupleIndexes(primary, indexes) ;
++ if ( prefixIndexes.length != 1 )
++ error(log, "Wrong number of triple table tuples indexes: "+prefixIndexes.length) ;
++
++ // No cache - the prefix mapping is a cache
++ //NodeTable prefixNodes = makeNodeTable(location, pnNode2Id, pnId2Node, -1, -1, -1) ;
++ NodeTupleTable prefixTable = new NodeTupleTableConcrete(primary.length(),
++ prefixIndexes,
++ prefixNodes) ;
++ DatasetPrefixesTDB prefixes = new DatasetPrefixesTDB(prefixTable) ;
++ log.debug("Prefixes: "+primary+" :: "+String.join(",", indexes)) ;
++ return prefixes ;
++ }
++
++ // ---- Build structures
++
++ public TupleIndex[] makeTupleIndexes(String primary, String[] indexNames) {
++ int indexRecordLen = primary.length()*SystemTDB.SizeOfNodeId ;
++ TupleIndex indexes[] = new TupleIndex[indexNames.length] ;
++ for (int i = 0 ; i < indexes.length ; i++) {
++ String indexName = indexNames[i] ;
++ String indexLabel = indexNames[i] ;
++ indexes[i] = buildTupleIndex(primary, indexName, indexLabel) ;
++ }
++ return indexes ;
++ }
++
++ public TupleIndex buildTupleIndex(String primary, String index, String name) {
++ TupleMap cmap = TupleMap.create(primary, index) ;
++ RecordFactory rf = new RecordFactory(SystemTDB.SizeOfNodeId * cmap.length(), 0) ;
++ RangeIndex rIdx = buildRangeIndex(rf, index) ;
++ TupleIndex tIdx = new TupleIndexRecord(primary.length(), cmap, index, rf, rIdx) ;
++ return tIdx ;
++ }
++
++ public RangeIndex buildRangeIndex(RecordFactory recordFactory, String name) {
++ ComponentId cid = componentIdMgr.getComponentId(name) ;
++ FileSet fs = new FileSet(location, name) ;
++ BPlusTree bpt = BPlusTreeFactory.createBPTree(cid, fs, recordFactory) ;
++ txnCoord.add(bpt) ;
++ return bpt ;
++ }
++
++ public NodeTable buildNodeTable(String name) {
++ NodeTable nodeTable = buildBaseNodeTable(name) ;
++ nodeTable = NodeTableCache.create(nodeTable, params) ;
++ nodeTable = NodeTableInline.create(nodeTable) ;
++ return nodeTable ;
++ }
++
++ public NodeTable buildBaseNodeTable(String name) {
++ RecordFactory recordFactory = new RecordFactory(SystemTDB.LenNodeHash, SystemTDB.SizeOfNodeId) ;
++ Index index = buildRangeIndex(recordFactory, name) ;
++
++ String dataname = name+"-data" ;
++ TransBinaryDataFile transBinFile = buildBinaryDataFile(dataname) ;
++ txnCoord.add(transBinFile) ;
++ return new NodeTableTRDF(index, transBinFile) ;
++ }
++
++ public TransBinaryDataFile buildBinaryDataFile(String name) {
++ ComponentId cid = componentIdMgr.getComponentId(name) ;
++ FileSet fs = new FileSet(location, name) ;
++ BinaryDataFile binFile = FileFactory.createBinaryDataFile(fs, Names.extObjNodeData) ;
++ BufferChannel pState = FileFactory.createBufferChannel(fs, Names.extBdfState) ;
++ // ComponentId mgt.
++ TransBinaryDataFile transBinFile = new TransBinaryDataFile(binFile, cid, pState) ;
++ return transBinFile ;
++ }
++
++ private void error(Logger log, String msg)
++ {
++ if ( log != null )
++ log.error(msg) ;
++ throw new TDBException(msg) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/TDBDatasetDetails.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/TDBDatasetDetails.java
index 0000000,0000000..4d4797a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/TDBDatasetDetails.java
@@@ -1,0 -1,0 +1,75 @@@
++/*
++ * 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.setup;
++
++import org.apache.jena.atlas.lib.ArrayUtils ;
++import org.apache.jena.atlas.logging.Log ;
++import org.seaborne.tdb2.store.DatasetGraphTDB ;
++import org.seaborne.tdb2.store.nodetable.NodeTable ;
++import org.seaborne.tdb2.store.nodetable.NodeTableCache ;
++import org.seaborne.tdb2.store.nodetable.NodeTableInline ;
++import org.seaborne.tdb2.store.tupletable.TupleIndex ;
++
++public class TDBDatasetDetails {
++ public final TupleIndex[] tripleIndexes ;
++ public final TupleIndex[] quadIndexes ;
++ public final NodeTable ntTop ;
++ public NodeTableInline ntInline ;
++ public NodeTableCache ntCache ;
++ public NodeTable ntBase ;
++
++
++ public TDBDatasetDetails(DatasetGraphTDB dsg) {
++ ntTop = dsg.getTripleTable().getNodeTupleTable().getNodeTable() ;
++ tripleIndexes = ArrayUtils.copy(dsg.getTripleTable().getNodeTupleTable().getTupleTable().getIndexes()) ;
++ quadIndexes = ArrayUtils.copy(dsg.getQuadTable().getNodeTupleTable().getTupleTable().getIndexes()) ;
++
++ fillInNodeTableDetails() ;
++ fillInIndexDetails() ;
++ }
++
++ private void fillInNodeTableDetails() {
++ // Nodetable.
++ NodeTable ntx = ntTop ;
++ while(ntx.wrapped() != null ) {
++ if ( ntx instanceof NodeTableInline ) {
++ if ( ntInline != null )
++ Log.warn(this, "Multiple NodeTableInline") ;
++ ntInline = (NodeTableInline)ntx ;
++ }
++ else if ( ntx instanceof NodeTableCache ) {
++ if ( ntCache != null )
++ Log.warn(this, "Multiple NodeTableCache") ;
++ ntCache = (NodeTableCache)ntx ;
++ }
++ ntx = ntx.wrapped() ;
++ }
++
++ ntBase = ntx ;
++
++ if ( ntInline == null )
++ Log.warn(this, "No NodeTableInline") ;
++ if ( ntCache == null )
++ Log.warn(this, "No NodeTableCache") ;
++ if ( ntBase == null )
++ Log.warn(this, "No base NodeTable") ;
++ }
++
++ private void fillInIndexDetails() {
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/Abortable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/Abortable.java
index 0000000,0000000..14dfa58
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/Abortable.java
@@@ -1,0 -1,0 +1,20 @@@
++/*
++ * 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.solver;
++
++interface Abortable { public void abort() ; }
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/BindingNodeId.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/BindingNodeId.java
index 0000000,0000000..57b73a9
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/BindingNodeId.java
@@@ -1,0 -1,0 +1,112 @@@
++/*
++ * 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.solver;
++
++import java.util.HashMap;
++import java.util.Iterator ;
++import java.util.Map;
++
++import org.apache.jena.atlas.lib.Map2 ;
++
++
++
++import org.apache.jena.sparql.core.Var ;
++import org.apache.jena.sparql.engine.binding.Binding ;
++import org.seaborne.tdb2.store.NodeId ;
++
++/** Class for a Binding-like structure except it works on NodeIds, not on Nodes */
++public class BindingNodeId extends Map2<Var, NodeId>
++{
++ // This is the parent binding - which may be several steps up the chain.
++ // This just carried around for later use when we go BindingNodeId back to Binding.
++ private final Binding parentBinding ;
++
++ // Possible optimization: there are at most 3 possible values so HashMap is overkill.
++ // Use a chain of small objects.
++
++ private BindingNodeId(Map<Var, NodeId> map1, Map2<Var, NodeId> map2, Binding parentBinding)
++ {
++ super(map1, map2) ;
++ this.parentBinding = parentBinding ;
++ }
++
++ // Make from an existing BindingNodeId
++ public BindingNodeId(BindingNodeId other)
++ {
++ this(new HashMap<Var, NodeId>(), other, other.getParentBinding()) ;
++ }
++
++ // Make from an existing Binding
++ public BindingNodeId(Binding binding)
++ {
++ this(new HashMap<Var, NodeId>(), null, binding) ;
++ }
++
++ public BindingNodeId()
++ {
++ this(new HashMap<Var, NodeId>(), null, null) ;
++ }
++
++ public Binding getParentBinding() { return parentBinding ; }
++
++ //@Override public NodeId get(Var v) { return super.get(v) ; }
++
++ @Override public void put(Var v, NodeId n)
++ {
++ if ( v == null || n == null )
++ throw new IllegalArgumentException("("+v+","+n+")") ;
++ super.put(v, n) ;
++ }
++
++ public void putAll(BindingNodeId other)
++ {
++ Iterator<Var> vIter = other.iterator() ;
++
++ for ( ; vIter.hasNext() ; )
++ {
++ Var v = vIter.next() ;
++ if ( v == null )
++ throw new IllegalArgumentException("Null key") ;
++ NodeId n = other.get(v) ;
++ if ( n == null )
++ throw new IllegalArgumentException("("+v+","+n+")") ;
++ super.put(v, n) ;
++ }
++ }
++
++ @Override
++ public String toString()
++ {
++ StringBuilder sb = new StringBuilder() ;
++
++ boolean first = true ;
++ for ( Var v : this )
++ {
++ if ( ! first )
++ sb.append(" ") ;
++ first = false ;
++ NodeId x = get(v) ;
++ sb.append(v) ;
++ sb.append(" = ") ;
++ sb.append(x) ;
++ }
++
++ return sb.toString() ;
++
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/BindingTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/BindingTDB.java
index 0000000,0000000..3eed2d4
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/BindingTDB.java
@@@ -1,0 -1,0 +1,154 @@@
++/*
++ * 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.solver;
++
++import java.util.* ;
++
++import org.apache.jena.atlas.logging.Log ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.riot.out.NodeFmtLib ;
++import org.apache.jena.sparql.core.Var ;
++import org.apache.jena.sparql.engine.binding.Binding ;
++import org.apache.jena.sparql.engine.binding.BindingBase ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.store.nodetable.NodeTable ;
++
++/** Bind that delays turning a NodeId into a Node until explicitly needed by get() */
++
++public class BindingTDB extends BindingBase
++{
++ private final NodeTable nodeTable ;
++ private final BindingNodeId idBinding ;
++
++ private static final boolean caching = false ;
++ // Whether the cache is worthwhile is unclear - the NodeTable keeps a cache.
++ private final Map<Var,Node> cache = ( caching ? new HashMap<>() : null ) ;
++
++ public BindingTDB(BindingNodeId idBinding, NodeTable nodeTable)
++ {
++ // BindingNodeId contains the bindings actually used copied down when created.
++ super(idBinding.getParentBinding()) ;
++ this.idBinding = idBinding ;
++ this.nodeTable = nodeTable ;
++ }
++
++ @Override
++ protected int size1() { return idBinding.size(); }
++
++ private List<Var> vars = null ;
++
++ /** Iterate over all the names of variables. */
++ @Override
++ protected Iterator<Var> vars1()
++ {
++ if ( vars == null )
++ vars = calcVars() ;
++ return vars.iterator() ;
++ }
++
++ private List<Var> calcVars()
++ {
++ List<Var> vars = new ArrayList<>(4) ;
++ // Only if not in parent.
++ // A (var/value) binding may have been copied down to record it's NodeId.
++
++ Binding b = idBinding.getParentBinding() ;
++
++ Iterator<Var> iter = idBinding.iterator() ;
++ for ( Var v : idBinding )
++ {
++ if ( b == null || ! b.contains(v) )
++ vars.add(v) ;
++ }
++ return vars ;
++ }
++
++ @Override
++ protected boolean isEmpty1()
++ {
++ return size1() == 0 ;
++ }
++
++ @Override
++ public boolean contains1(Var var)
++ {
++ return idBinding.containsKey(var) ;
++ }
++
++ public BindingNodeId getBindingId() { return idBinding ; }
++
++ public NodeId getNodeId(Var var)
++ {
++ NodeId id = idBinding.get(var) ;
++ if ( id != null )
++ return id ;
++
++ if ( parent == null )
++ return null ;
++
++ // Maybe in the parent.
++ if ( parent instanceof BindingTDB )
++ return ((BindingTDB)parent).getNodeId(var) ;
++ return null ;
++ }
++
++ @Override
++ public Node get1(Var var)
++ {
++ try {
++ Node n = cacheGet(var) ;
++ if ( n != null )
++ return n ;
++
++ NodeId id = idBinding.get(var) ;
++ if ( id == null )
++ return null ;
++ n = nodeTable.getNodeForNodeId(id) ;
++ // Update cache.
++ cachePut(var, n) ;
++ return n ;
++ } catch (Exception ex)
++ {
++ Log.error(this, String.format("get1(%s)", var), ex) ;
++ return null ;
++ }
++ }
++
++ private void cachePut(Var var, Node n)
++ {
++ if ( cache != null ) cache.put(var, n) ;
++ }
++
++ private Node cacheGet(Var var)
++ {
++ if ( cache == null ) return null ;
++ return cache.get(var) ;
++ }
++
++ @Override
++ protected void format(StringBuffer sbuff, Var var)
++ {
++ NodeId id = idBinding.get(var) ;
++ String extra = "" ;
++ if ( id != null )
++ extra = "/"+id ;
++ Node node = get(var) ;
++ String tmp = NodeFmtLib.displayStr(node) ;
++ sbuff.append("( ?"+var.getVarName()+extra+" = "+tmp+" )") ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/OpExecutorTDB1.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/OpExecutorTDB1.java
index 0000000,0000000..f103917
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/OpExecutorTDB1.java
@@@ -1,0 -1,0 +1,427 @@@
++/*
++ * 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.solver;
++
++import java.util.function.Predicate;
++
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.atlas.logging.Log ;
++import org.apache.jena.graph.Graph ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.sparql.ARQInternalErrorException ;
++import org.apache.jena.sparql.algebra.Op ;
++import org.apache.jena.sparql.algebra.op.* ;
++import org.apache.jena.sparql.algebra.optimize.TransformFilterPlacement ;
++import org.apache.jena.sparql.core.BasicPattern ;
++import org.apache.jena.sparql.core.Quad ;
++import org.apache.jena.sparql.core.Substitute ;
++import org.apache.jena.sparql.core.Var ;
++import org.apache.jena.sparql.engine.ExecutionContext ;
++import org.apache.jena.sparql.engine.QueryIterator ;
++import org.apache.jena.sparql.engine.iterator.QueryIterPeek ;
++import org.apache.jena.sparql.engine.main.OpExecutor ;
++import org.apache.jena.sparql.engine.main.OpExecutorFactory ;
++import org.apache.jena.sparql.engine.main.QC ;
++import org.apache.jena.sparql.engine.main.iterator.QueryIterGraph ;
++import org.apache.jena.sparql.engine.optimizer.reorder.ReorderProc ;
++import org.apache.jena.sparql.engine.optimizer.reorder.ReorderTransformation ;
++import org.apache.jena.sparql.expr.ExprList ;
++import org.apache.jena.sparql.mgt.Explain ;
++import org.seaborne.tdb2.store.DatasetGraphTDB ;
++import org.seaborne.tdb2.store.GraphTDB ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/** TDB executor for algebra expressions. It is the standard ARQ executor
++ * except for basic graph patterns and filtered basic graph patterns (currently).
++ *
++ * See also: StageGeneratorDirectTDB, a non-reordering
++ */
++public class OpExecutorTDB1 extends OpExecutor
++{
++ private static final Logger log = LoggerFactory.getLogger(OpExecutorTDB1.class) ;
++
++ public final static OpExecutorFactory OpExecFactoryTDB = new OpExecutorFactory()
++ {
++ @Override
++ public OpExecutor create(ExecutionContext execCxt)
++ { return new OpExecutorTDB1(execCxt) ; }
++ } ;
++
++ private final boolean isForTDB ;
++
++ // A new compile object is created for each op compilation.
++ // So the execCxt is changing as we go through the query-compile-execute process
++ public OpExecutorTDB1(ExecutionContext execCxt)
++ {
++ super(execCxt) ;
++ // NB. The dataset may be a TDB one, or a general one.
++ // Any merged union graph magic (for a TDB dataset was handled
++ // in QueryEngineTDB).
++
++ isForTDB = (execCxt.getActiveGraph() instanceof GraphTDB) ;
++ }
++
++ @Override
++ protected QueryIterator exec(Op op, QueryIterator input) {
++ if ( level < 0 )
++ // Print only at top level (and we're called before level++)
++ Explain.explain("TDB", op, super.execCxt.getContext()) ;
++ return super.exec(op, input) ;
++ }
++
++ // Retrieving nodes isn't so bad because they will be needed anyway.
++ // And if their duplicates, likely to be cached.
++ // Need to work with SolverLib which wraps the NodeId bindgins with a converter.
++
++ @Override
++ protected QueryIterator execute(OpDistinct opDistinct, QueryIterator input)
++ {
++ return super.execute(opDistinct, input) ;
++ }
++
++ @Override
++ protected QueryIterator execute(OpReduced opReduced, QueryIterator input)
++ {
++ return super.execute(opReduced, input) ;
++ }
++
++ @Override
++ protected QueryIterator execute(OpFilter opFilter, QueryIterator input)
++ {
++ if ( ! isForTDB )
++ return super.execute(opFilter, input) ;
++
++ // If the filter does not apply to the input??
++ // Where does ARQ catch this?
++
++ // (filter (bgp ...))
++ if ( OpBGP.isBGP(opFilter.getSubOp()) )
++ {
++ // Still may be a TDB graph in a non-TDB dataset (e.g. a named model)
++ GraphTDB graph = (GraphTDB)execCxt.getActiveGraph() ;
++ OpBGP opBGP = (OpBGP)opFilter.getSubOp() ;
++ return executeBGP(graph, opBGP, input, opFilter.getExprs(), execCxt) ;
++ }
++
++ // (filter (quadpattern ...))
++ if ( opFilter.getSubOp() instanceof OpQuadPattern )
++ {
++ OpQuadPattern quadPattern = (OpQuadPattern)opFilter.getSubOp() ;
++ DatasetGraphTDB ds = (DatasetGraphTDB)execCxt.getDataset() ;
++ return optimizeExecuteQuads(ds, input,
++ quadPattern.getGraphNode(), quadPattern.getBasicPattern(),
++ opFilter.getExprs(), execCxt) ;
++ }
++
++ // (filter (anything else))
++ return super.execute(opFilter, input) ;
++ }
++
++ // ---- Triple patterns
++
++ @Override
++ protected QueryIterator execute(OpBGP opBGP, QueryIterator input)
++ {
++ if ( ! isForTDB )
++ return super.execute(opBGP, input) ;
++
++ GraphTDB graph = (GraphTDB)execCxt.getActiveGraph() ;
++ return executeBGP(graph, opBGP, input, null, execCxt) ;
++
++ }
++
++ @Override
++ protected QueryIterator execute(OpQuadPattern quadPattern, QueryIterator input)
++ {
++ if ( ! isForTDB )
++ return super.execute(quadPattern, input) ;
++
++ // DatasetGraph dg = execCxt.getDataset() ;
++ // if ( ! ( dg instanceof DatasetGraphTDB ) )
++ // throw new InternalErrorException("Not a TDB backed dataset in quad pattern execution") ;
++
++ DatasetGraphTDB ds = (DatasetGraphTDB)execCxt.getDataset() ;
++ BasicPattern bgp = quadPattern.getBasicPattern() ;
++ Node gn = quadPattern.getGraphNode() ;
++ return optimizeExecuteQuads(ds, input, gn, bgp, null, execCxt) ;
++ }
++
++ @Override
++ protected QueryIterator execute(OpGraph opGraph, QueryIterator input)
++ {
++ // Path evaluation or dataset sets which do not go straight to the DatasetGraphTDB
++ return new QueryIterGraph(input, opGraph, execCxt) ;
++ }
++
++ /** Execute a BGP (and filters) on a TDB graph, which may be in default storage or it may be a named graph */
++ private static QueryIterator executeBGP(GraphTDB graph, OpBGP opBGP, QueryIterator input, ExprList exprs,
++ ExecutionContext execCxt)
++ {
++ // Is it the real default graph (normal route or explicitly named)?
++ if ( ! isDefaultGraphStorage(graph.getGraphName()))
++ {
++ // Not default storage - it's a named graph in storage.
++ DatasetGraphTDB ds = graph.getDSG() ;
++ return optimizeExecuteQuads(ds, input, graph.getGraphName(), opBGP.getPattern(), exprs, execCxt) ;
++ }
++
++ // Execute a BGP on the real default graph
++ return optimizeExecuteTriples(graph, input, opBGP.getPattern(), exprs, execCxt) ;
++ }
++
++ /** Execute, with optimization, a basic graph pattern on the default graph storage */
++ private static QueryIterator optimizeExecuteTriples(GraphTDB graph, QueryIterator input,
++ BasicPattern pattern, ExprList exprs,
++ ExecutionContext execCxt)
++ {
++ if ( ! input.hasNext() )
++ return input ;
++
++ // -- Input
++ // Must pass this iterator into the next stage.
++ if ( pattern.size() >= 2 )
++ {
++ // Must be 2 or triples to reorder.
++ ReorderTransformation transform = graph.getDSG().getReorderTransform() ;
++ if ( transform != null )
++ {
++ QueryIterPeek peek = QueryIterPeek.create(input, execCxt) ;
++ input = peek ; // Must pass on
++ pattern = reorder(pattern, peek, transform) ;
++ }
++ }
++ // -- Filter placement
++
++ Op op = null ;
++ if ( exprs != null )
++ op = TransformFilterPlacement.transform(exprs, pattern) ;
++ else
++ op = new OpBGP(pattern) ;
++
++ return plainExecute(op, input, execCxt) ;
++ }
++
++ /** Execute, with optimization, a quad pattern */
++ private static QueryIterator optimizeExecuteQuads(DatasetGraphTDB ds,
++ QueryIterator input,
++ Node gn, BasicPattern bgp,
++ ExprList exprs, ExecutionContext execCxt)
++ {
++ if ( ! input.hasNext() )
++ return input ;
++
++ // ---- Graph names with special meaning.
++
++ gn = decideGraphNode(gn, execCxt) ;
++ if ( gn == null )
++ return optimizeExecuteTriples(ds.getDefaultGraphTDB(), input, bgp, exprs, execCxt) ;
++
++ // ---- Execute quads+filters
++ if ( bgp.size() >= 2 )
++ {
++ ReorderTransformation transform = ds.getReorderTransform() ;
++
++ if ( transform != null )
++ {
++ QueryIterPeek peek = QueryIterPeek.create(input, execCxt) ;
++ input = peek ; // Original input now invalid.
++ bgp = reorder(bgp, peek, transform) ;
++ }
++ }
++ // -- Filter placement
++ Op op = null ;
++ if ( exprs != null )
++ op = TransformFilterPlacement.transform(exprs, gn, bgp) ;
++ else
++ op = new OpQuadPattern(gn, bgp) ;
++
++ return plainExecute(op, input, execCxt) ;
++ }
++
++ /** Execute without modification of the op - does <b>not</b> apply special graph name translations */
++ private static QueryIterator plainExecute(Op op, QueryIterator input, ExecutionContext execCxt)
++ {
++ // -- Execute
++ // Switch to a non-reordering executor
++ // The Op may be a sequence due to TransformFilterPlacement
++ // so we need to do a full execution step, not go straight to the SolverLib.
++
++ ExecutionContext ec2 = new ExecutionContext(execCxt) ;
++ ec2.setExecutor(plainFactory) ;
++
++ // Solve without going through this executor again.
++ // There would be issues of nested patterns but this is only a
++ // (filter (bgp...)) or (filter (quadpattern ...)) or sequences of these.
++ // so there are no nested patterns to reorder.
++ return QC.execute(op, input, ec2) ;
++ }
++
++ private static BasicPattern reorder(BasicPattern pattern, QueryIterPeek peek, ReorderTransformation transform)
++ {
++ if ( transform != null )
++ {
++ // This works by getting one result from the peek iterator,
++ // and creating the more gounded BGP. The tranform is used to
++ // determine the best order and the transformation is returned. This
++ // transform is applied to the unsubstituted pattern (which will be
++ // substituted as part of evaluation.
++
++ if ( ! peek.hasNext() )
++ throw new ARQInternalErrorException("Peek iterator is already empty") ;
++
++ BasicPattern pattern2 = Substitute.substitute(pattern, peek.peek() ) ;
++ // Calculate the reordering based on the substituted pattern.
++ ReorderProc proc = transform.reorderIndexes(pattern2) ;
++ // Then reorder original patten
++ pattern = proc.reorder(pattern) ;
++ }
++ return pattern ;
++ }
++
++ /** Handle special graph node names.
++ * Returns null for default graph in storage (use the triple table).
++ * Returns Node.ANY for the union graph
++ */
++ public static Node decideGraphNode(Node gn, ExecutionContext execCxt)
++ {
++ // ---- Graph names with special meaning.
++
++ // Graph names with special meaning:
++ // Quad.defaultGraphIRI -- the IRI used in GRAPH <> to mean the default graph.
++ // Quad.defaultGraphNodeGenerated -- the internal marker node used for the quad form of queries.
++ // Quad.unionGraph -- the IRI used in GRAPH <> to mean the union of named graphs
++
++ if ( isDefaultGraphStorage(gn) )
++ {
++ // Storage concrete, default graph.
++ // Either outside GRAPH (no implicit union)
++ // or using the "name" of the default graph
++ return null ;
++ }
++
++ // Not default storage graph.
++ // ---- Union (RDF Merge) of named graphs
++
++ if ( Quad.isUnionGraph(gn) )
++ return Node.ANY ;
++ boolean doingUnion = false ;
++
++ return gn ;
++ }
++
++ // Is this a query against the real default graph in the storage (in a 3-tuple table).
++ private static boolean isDefaultGraphStorage(Node gn)
++ {
++ if ( gn == null )
++ return true ;
++
++ // Is it the implicit name for default graph.
++ if ( Quad.isDefaultGraph(gn) )
++ // Not accessing the union of named graphs as the default graph
++ // and pattern is directed to the default graph.
++ return true ;
++
++ return false ;
++ }
++
++ @Override
++ protected QueryIterator execute(OpDatasetNames dsNames, QueryIterator input)
++ {
++ DatasetGraphTDB ds = (DatasetGraphTDB)execCxt.getDataset() ;
++ Predicate<Tuple<NodeId>> filter = QC2.getFilter(execCxt.getContext()) ;
++ Node gn = dsNames.getGraphNode() ;
++ if ( Var.isVar(gn) )
++ return SolverLib.graphNames(ds, dsNames.getGraphNode(), input, filter, execCxt) ;
++ else
++ return SolverLib.testForGraphName(ds, dsNames.getGraphNode(), input, filter, execCxt) ;
++ }
++
++ // ---- OpExecute factories and plain executor.
++
++ private static OpExecutorFactory plainFactory = new OpExecutorPlainFactoryTDB() ;
++ private static class OpExecutorPlainFactoryTDB implements OpExecutorFactory
++ {
++ @Override
++ public OpExecutor create(ExecutionContext execCxt)
++ {
++ return new OpExecutorPlainTDB(execCxt) ;
++ }
++ }
++
++ /** An op executor that simply executes a BGP or QuadPattern without any reordering */
++ private static class OpExecutorPlainTDB extends OpExecutor
++ {
++ Predicate<Tuple<NodeId>> filter = null ;
++
++ public OpExecutorPlainTDB(ExecutionContext execCxt)
++ {
++ super(execCxt) ;
++ filter = QC2.getFilter(execCxt.getContext()) ;
++ }
++
++ @Override
++ public QueryIterator execute(OpBGP opBGP, QueryIterator input)
++ {
++ Graph g = execCxt.getActiveGraph() ;
++
++ if ( g instanceof GraphTDB )
++ {
++ BasicPattern bgp = opBGP.getPattern() ;
++ Explain.explain("Execute", bgp, execCxt.getContext()) ;
++ // Triple-backed (but may be named as explicit default graph).
++ //return SolverLib.execute((GraphTDB)g, bgp, input, filter, execCxt) ;
++ GraphTDB gtdb = (GraphTDB)g ;
++ Node gn = decideGraphNode(gtdb.getGraphName(), execCxt) ;
++ return SolverLib.execute(gtdb.getDSG(), gn, bgp, input, filter, execCxt) ;
++ }
++ Log.warn(this, "Non-GraphTDB passed to OpExecutorPlainTDB") ;
++ return super.execute(opBGP, input) ;
++ }
++
++ @Override
++ public QueryIterator execute(OpQuadPattern opQuadPattern, QueryIterator input)
++ {
++ Node gn = opQuadPattern.getGraphNode() ;
++ gn = decideGraphNode(gn, execCxt) ;
++
++ if ( execCxt.getDataset() instanceof DatasetGraphTDB )
++ {
++ DatasetGraphTDB ds = (DatasetGraphTDB)execCxt.getDataset() ;
++ Explain.explain("Execute", opQuadPattern.getPattern(), execCxt.getContext()) ;
++ BasicPattern bgp = opQuadPattern.getBasicPattern() ;
++ return SolverLib.execute(ds, gn, bgp, input, filter, execCxt) ;
++ }
++ // Maybe a TDB named graph inside a non-TDB dataset.
++ Graph g = execCxt.getActiveGraph() ;
++ if ( g instanceof GraphTDB )
++ {
++ // Triples graph from TDB (which is the default graph of the dataset),
++ // used a named graph in a composite dataset.
++ BasicPattern bgp = opQuadPattern.getBasicPattern() ;
++ Explain.explain("Execute", bgp, execCxt.getContext()) ;
++ // Don't pass in G -- gn may be different.
++ return SolverLib.execute(((GraphTDB)g).getDSG(), gn, bgp, input, filter, execCxt) ;
++ }
++ Log.warn(this, "Non-DatasetGraphTDB passed to OpExecutorPlainTDB") ;
++ return super.execute(opQuadPattern, input) ;
++ }
++
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/QC2.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/QC2.java
index 0000000,0000000..b96ece2
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/QC2.java
@@@ -1,0 -1,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.solver;
++
++import java.util.function.Predicate;
++
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.sparql.util.Context ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++
++public class QC2
++{
++ public static Predicate<Tuple<NodeId>> getFilter(Context context)
++ {
++ Object x = context.get(SystemTDB.symTupleFilter) ;
++
++ try {
++ @SuppressWarnings("unchecked")
++ Predicate<Tuple<NodeId>> f = (Predicate<Tuple<NodeId>>)x ;
++ return f ;
++ } catch (ClassCastException ex)
++ {
++ throw new TDBException("Not a Filter<Tuple<NodeId>>:"+x, ex) ;
++ }
++ }
++
++ public static void setFilter(Context context, Predicate<Tuple<NodeId>> filter)
++ {
++ context.set(SystemTDB.symTupleFilter, filter) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/QueryEngineTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/QueryEngineTDB.java
index 0000000,0000000..dfece29
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/QueryEngineTDB.java
@@@ -1,0 -1,0 +1,206 @@@
++/*
++ * 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.solver;
++
++import org.apache.jena.atlas.lib.Lib ;
++import org.apache.jena.query.Query ;
++import org.apache.jena.sparql.algebra.Algebra ;
++import org.apache.jena.sparql.algebra.Op ;
++import org.apache.jena.sparql.core.DatasetDescription ;
++import org.apache.jena.sparql.core.DatasetGraph ;
++import org.apache.jena.sparql.core.DynamicDatasets ;
++import org.apache.jena.sparql.core.Substitute ;
++import org.apache.jena.sparql.engine.Plan ;
++import org.apache.jena.sparql.engine.QueryEngineFactory ;
++import org.apache.jena.sparql.engine.QueryEngineRegistry ;
++import org.apache.jena.sparql.engine.QueryIterator ;
++import org.apache.jena.sparql.engine.binding.Binding ;
++import org.apache.jena.sparql.engine.binding.BindingFactory ;
++import org.apache.jena.sparql.engine.iterator.QueryIteratorWrapper ;
++import org.apache.jena.sparql.engine.main.QueryEngineMain ;
++import org.apache.jena.sparql.mgt.Explain ;
++import org.apache.jena.sparql.util.Context ;
++import org.seaborne.tdb2.TDB2 ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.migrate.A2 ;
++import org.seaborne.tdb2.store.DatasetGraphTDB ;
++import org.seaborne.tdb2.sys.TDBInternal ;
++
++// This exists to intercept the query execution setup.
++// e.g choose the transformation optimizations
++// then to make the quad form.
++// TDB also uses a custom OpExecutor to intercept certain part
++// of the Op evaluations
++
++public class QueryEngineTDB extends QueryEngineMain
++{
++ // ---- Wiring
++ static public QueryEngineFactory getFactory() { return factory ; }
++ static public void register() { QueryEngineRegistry.addFactory(factory) ; }
++ static public void unregister() { QueryEngineRegistry.removeFactory(factory) ; }
++
++ private Binding initialInput ;
++
++ // ---- Object
++ protected QueryEngineTDB(Op op, DatasetGraphTDB dataset, Binding input, Context context)
++ {
++ super(op, dataset, input, context) ;
++ this.initialInput = input ;
++ }
++
++ private boolean doingDynamicDatasetBySpecialDataset = false ;
++
++ protected QueryEngineTDB(Query query, DatasetGraphTDB dataset, Binding input, Context cxt)
++ {
++ super(query, dataset, input, cxt) ;
++ DatasetDescription dsDesc = DatasetDescription.create(query, context) ;
++
++ if ( dsDesc != null )
++ {
++ doingDynamicDatasetBySpecialDataset = true ;
++ super.dataset = DynamicDatasets.dynamicDataset(dsDesc, dataset, cxt.isTrue(TDB2.symUnionDefaultGraph) ) ;
++ }
++ this.initialInput = input ;
++ }
++
++ // Choose the algebra-level optimizations to invoke.
++ @Override
++ protected Op modifyOp(Op op)
++ {
++ op = Substitute.substitute(op, initialInput) ;
++ // Optimize (high-level)
++ op = super.modifyOp(op) ;
++
++ // Quadification
++ // Only apply if not a rewritten DynamicDataset
++ if ( ! doingDynamicDatasetBySpecialDataset )
++ op = Algebra.toQuadForm(op) ;
++
++ // Record it.
++ setOp(op) ;
++ return op ;
++ }
++
++ @Override
++ public QueryIterator eval(Op op, DatasetGraph dsg, Binding input, Context context)
++ {
++ // Top of execution of a query.
++ // Op is quad'ed by now but there still may be some (graph ....) forms e.g. paths
++
++ // Fix DatasetGraph for global union.
++ if ( context.isTrue(TDB2.symUnionDefaultGraph) && ! doingDynamicDatasetBySpecialDataset )
++ {
++ op = A2.unionDefaultGraphQuads(op) ;
++ Explain.explain("REWRITE(Union default graph)", op, context) ;
++ }
++ QueryIterator results = super.eval(op, dsg, input, context) ;
++ results = new QueryIteratorMaterializeBinding(results) ;
++ return results ;
++ }
++
++ /** Copy from any TDB internal BindingTDB to a Binding that
++ * does not have any connection to the database.
++ */
++ static class QueryIteratorMaterializeBinding extends QueryIteratorWrapper
++ {
++ public QueryIteratorMaterializeBinding(QueryIterator qIter)
++ {
++ super(qIter) ;
++ }
++
++ @Override
++ protected Binding moveToNextBinding()
++ {
++ Binding b = super.moveToNextBinding() ;
++ b = BindingFactory.materialize(b) ;
++ return b ;
++ }
++ }
++
++ // Execution time (needs wiring to ARQ).
++ public long getMillis() { return -1 ; }
++
++ // ---- Factory
++ protected static QueryEngineFactory factory = new QueryEngineFactoryTDB() ;
++
++ protected static class QueryEngineFactoryTDB implements QueryEngineFactory
++ {
++ private static boolean isHandledByTDB(DatasetGraph dataset) {
++ return TDBInternal.isBackedByTDB(dataset);
++ }
++
++ protected DatasetGraphTDB dsgToQuery(DatasetGraph dataset) {
++ try {
++ return TDBInternal.requireStorage(dataset);
++ } catch (TDBException ex) {
++ // Check to a more specific message.
++ throw new TDBException("Internal inconsistency: trying to execute query on unrecognized kind of DatasetGraph: "+Lib.className(dataset)) ;
++ }
++ }
++
++ @Override
++ public boolean accept(Query query, DatasetGraph dataset, Context context)
++ { return isHandledByTDB(dataset) ; }
++
++ @Override
++ public Plan create(Query query, DatasetGraph dataset, Binding input, Context context)
++ {
++ QueryEngineTDB engine = new QueryEngineTDB(query, dsgToQuery(dataset), input, context) ;
++ return engine.getPlan() ;
++ }
++
++ @Override
++ public boolean accept(Op op, DatasetGraph dataset, Context context)
++ { return isHandledByTDB(dataset) ; }
++
++ @Override
++ public Plan create(Op op, DatasetGraph dataset, Binding binding, Context context)
++ {
++ QueryEngineTDB engine = new QueryEngineTDB(op, dsgToQuery(dataset), binding, context) ;
++ return engine.getPlan() ;
++ }
++ }
++
++// // By rewrite, not using a general purpose dataset with the right graphs in.
++// private static Op dynamicDatasetOp(Op op, Context context)
++// {
++// Transform transform = null ;
++//
++// try {
++// @SuppressWarnings("unchecked")
++// Set<Node> defaultGraphs = (Set<Node>)(context.get(SystemTDB.symDatasetDefaultGraphs)) ;
++// @SuppressWarnings("unchecked")
++// Set<Node> namedGraphs = (Set<Node>)(context.get(SystemTDB.symDatasetNamedGraphs)) ;
++// if ( defaultGraphs != null || namedGraphs != null )
++// transform = new TransformDynamicDataset(defaultGraphs,
++// namedGraphs,
++// context.isTrue(TDB.symUnionDefaultGraph)) ;
++// } catch (ClassCastException ex)
++// {
++// Log.warn(QueryEngineTDB.class, "Bad dynamic dataset description (ClassCastException)", ex) ;
++// transform = null ;
++// return op ;
++// }
++//
++// // Apply dynamic dataset modifications.
++// if ( transform != null )
++// op = Transformer.transform(transform, op) ;
++// return op ;
++// }
++//
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/QueryIterTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/QueryIterTDB.java
index 0000000,0000000..49b9cee
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/QueryIterTDB.java
@@@ -1,0 -1,0 +1,58 @@@
++/*
++ * 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.solver;
++
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.apache.jena.sparql.engine.ExecutionContext ;
++import org.apache.jena.sparql.engine.QueryIterator ;
++import org.apache.jena.sparql.engine.binding.Binding ;
++import org.apache.jena.sparql.engine.iterator.QueryIterPlainWrapper ;
++
++public class QueryIterTDB extends QueryIterPlainWrapper
++{
++ final private QueryIterator originalInput ;
++ private List<Abortable> killList ;
++
++ // The original input needs closing as well.
++ public QueryIterTDB(Iterator<Binding> iterBinding, List<Abortable> killList , QueryIterator originalInput, ExecutionContext execCxt)
++ {
++ super(iterBinding, execCxt) ;
++ this.originalInput = originalInput ;
++ this.killList = killList ;
++ }
++
++ @Override
++ protected void closeIterator()
++ {
++ if ( originalInput != null )
++ originalInput.close();
++ super.closeIterator() ;
++ }
++
++ @Override
++ protected void requestCancel()
++ {
++ if ( killList != null )
++ for ( Abortable it : killList )
++ it.abort() ;
++ if ( originalInput != null )
++ originalInput.cancel();
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/SolverLib.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/SolverLib.java
index 0000000,0000000..43dd3ab
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/SolverLib.java
@@@ -1,0 -1,0 +1,340 @@@
++/*
++ * 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.solver;
++
++import java.util.* ;
++import java.util.function.Function ;
++import java.util.function.Predicate ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import org.apache.jena.atlas.iterator.IteratorWrapper ;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.atlas.lib.tuple.TupleFactory ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.graph.Triple ;
++import org.apache.jena.query.QueryCancelledException ;
++import org.apache.jena.sparql.core.BasicPattern ;
++import org.apache.jena.sparql.core.Quad ;
++import org.apache.jena.sparql.core.Var ;
++import org.apache.jena.sparql.engine.ExecutionContext ;
++import org.apache.jena.sparql.engine.QueryIterator ;
++import org.apache.jena.sparql.engine.binding.Binding ;
++import org.apache.jena.sparql.engine.binding.BindingFactory ;
++import org.apache.jena.sparql.engine.binding.BindingMap ;
++import org.apache.jena.sparql.engine.iterator.QueryIterNullIterator ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.lib.NodeLib ;
++import org.seaborne.tdb2.store.DatasetGraphTDB ;
++import org.seaborne.tdb2.store.GraphTDB ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.store.nodetable.NodeTable ;
++import org.seaborne.tdb2.store.nodetupletable.NodeTupleTable ;
++import org.seaborne.tdb2.sys.TDBInternal ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/** Utilities used within the TDB BGP solver : local TDB store */
++public class SolverLib
++{
++ private static Logger log = LoggerFactory.getLogger(SolverLib.class) ;
++
++ /** Non-reordering execution of a basic graph pattern, given a iterator of bindings as input */
++ public static QueryIterator execute(GraphTDB graph, BasicPattern pattern,
++ QueryIterator input, Predicate<Tuple<NodeId>> filter,
++ ExecutionContext execCxt)
++ {
++ // Maybe default graph or named graph.
++ NodeTupleTable ntt = graph.getNodeTupleTable() ;
++ return execute(ntt, graph.getGraphName(), pattern, input, filter, execCxt) ;
++ }
++
++ /** Non-reordering execution of a quad pattern, given a iterator of bindings as input.
++ * GraphNode is Node.ANY for execution over the union of named graphs.
++ * GraphNode is null for execution over the real default graph.
++ */
++ public static QueryIterator execute(DatasetGraphTDB ds, Node graphNode, BasicPattern pattern,
++ QueryIterator input, Predicate<Tuple<NodeId>> filter,
++ ExecutionContext execCxt)
++ {
++ NodeTupleTable ntt = ds.chooseNodeTupleTable(graphNode) ;
++ return execute(ntt, graphNode, pattern, input, filter, execCxt) ;
++ }
++
++ public static Iterator<BindingNodeId> convertToIds(Iterator<Binding> iterBindings, NodeTable nodeTable)
++ { return Iter.map(iterBindings, convFromBinding(nodeTable)) ; }
++
++ /** Convert from Iterator<BindingNodeId> to Iterator<Binding>, conversion "on demand"
++ * (in convToBinding(BindingNodeId, NodeTable)
++ */
++ public static Iterator<Binding> convertToNodes(Iterator<BindingNodeId> iterBindingIds, NodeTable nodeTable)
++ { return Iter.map(iterBindingIds, bindingNodeIds -> convToBinding(bindingNodeIds, nodeTable)) ; }
++
++ // The worker. Callers choose the NodeTupleTable.
++ // graphNode may be Node.ANY, meaning we should make triples unique.
++ // graphNode may be null, meaning default graph
++
++ private static QueryIterator execute(NodeTupleTable nodeTupleTable, Node graphNode, BasicPattern pattern,
++ QueryIterator input, Predicate<Tuple<NodeId>> filter,
++ ExecutionContext execCxt)
++ {
++ if ( Quad.isUnionGraph(graphNode) )
++ graphNode = Node.ANY ;
++ if ( Quad.isDefaultGraph(graphNode) )
++ graphNode = null ;
++
++ List<Triple> triples = pattern.getList() ;
++ boolean anyGraph = (graphNode==null ? false : (Node.ANY.equals(graphNode))) ;
++
++ int tupleLen = nodeTupleTable.getTupleTable().getTupleLen() ;
++ if ( graphNode == null ) {
++ if ( 3 != tupleLen )
++ throw new TDBException("SolverLib: Null graph node but tuples are of length "+tupleLen) ;
++ } else {
++ if ( 4 != tupleLen )
++ throw new TDBException("SolverLib: Graph node specified but tuples are of length "+tupleLen) ;
++ }
++
++ // Convert from a QueryIterator (Bindings of Var/Node) to BindingNodeId
++ NodeTable nodeTable = nodeTupleTable.getNodeTable() ;
++
++ Iterator<BindingNodeId> chain = Iter.map(input, SolverLib.convFromBinding(nodeTable)) ;
++ List<Abortable> killList = new ArrayList<>() ;
++
++ for ( Triple triple : triples )
++ {
++ Tuple<Node> tuple = null ;
++ if ( graphNode == null )
++ // 3-tuples
++ tuple = TupleFactory.tuple(triple.getSubject(), triple.getPredicate(), triple.getObject()) ;
++ else
++ // 4-tuples.
++ tuple = TupleFactory.tuple(graphNode, triple.getSubject(), triple.getPredicate(), triple.getObject()) ;
++ chain = solve(nodeTupleTable, tuple, anyGraph, chain, filter, execCxt) ;
++ chain = makeAbortable(chain, killList) ;
++ }
++
++ // DEBUG POINT
++ if ( false )
++ {
++ if ( chain.hasNext())
++ chain = Iter.debug(chain) ;
++ else
++ System.out.println("No results") ;
++ }
++
++ // Timeout wrapper ****
++ // QueryIterTDB gets called async.
++ // Iter.abortable?
++ // Or each iterator has a place to test.
++ // or pass in a thing to test?
++
++
++ // Need to make sure the bindings here point to parent.
++ Iterator<Binding> iterBinding = convertToNodes(chain, nodeTable) ;
++
++ // "input" will be closed by QueryIterTDB but is otherwise unused.
++ // "killList" will be aborted on timeout.
++ return new QueryIterTDB(iterBinding, killList, input, execCxt) ;
++ }
++
++ /** Create an abortable iterator, storing it in the killList.
++ * Just return the input iterator if kilList is null.
++ */
++ static <T> Iterator<T> makeAbortable(Iterator<T> iter, List<Abortable> killList)
++ {
++ if ( killList == null )
++ return iter ;
++ IterAbortable<T> k = new IterAbortable<>(iter) ;
++ killList.add(k) ;
++ return k ;
++ }
++
++ /** Iterator that adds an abort operation which can be called
++ * at any time, including from another thread, and causes the
++ * iterator to throw an exception when next touched (hasNext, next).
++ */
++ static class IterAbortable<T> extends IteratorWrapper<T> implements Abortable
++ {
++ volatile boolean abortFlag = false ;
++
++ public IterAbortable(Iterator<T> iterator)
++ {
++ super(iterator) ;
++ }
++
++ /** Can call asynchronously at anytime */
++ @Override
++ public void abort() {
++ abortFlag = true ;
++ }
++
++ @Override
++ public boolean hasNext()
++ {
++ if ( abortFlag )
++ throw new QueryCancelledException() ;
++ return iterator.hasNext() ;
++ }
++
++ @Override
++ public T next()
++ {
++ if ( abortFlag )
++ throw new QueryCancelledException() ;
++ return iterator.next() ;
++ }
++ }
++
++ public static Iterator<BindingNodeId> solve(NodeTupleTable nodeTupleTable,
++ Tuple<Node> tuple,
++ boolean anyGraph,
++ Iterator<BindingNodeId> chain, Predicate<Tuple<NodeId>> filter,
++ ExecutionContext execCxt)
++ {
++ return new StageMatchTuple(nodeTupleTable, chain, tuple, anyGraph, filter, execCxt) ;
++ }
++
++ public static Binding convToBinding(BindingNodeId bindingNodeIds, NodeTable nodeTable) {
++ if ( true )
++ return new BindingTDB(bindingNodeIds, nodeTable) ;
++ else {
++ // Makes nodes immediately. Causing unnecessary NodeTable accesses
++ // (e.g. project)
++ BindingMap b = BindingFactory.create() ;
++ for (Var v : bindingNodeIds) {
++ NodeId id = bindingNodeIds.get(v) ;
++ Node n = nodeTable.getNodeForNodeId(id) ;
++ b.add(v, n) ;
++ }
++ return b ;
++ }
++ }
++
++ // Transform : Binding ==> BindingNodeId
++ public static Function<Binding, BindingNodeId> convFromBinding(final NodeTable nodeTable)
++ {
++ return binding -> SolverLib.convert(binding, nodeTable);
++ }
++
++ /** Binding ==> BindingNodeId, given a NodeTable */
++ public static BindingNodeId convert(Binding binding, NodeTable nodeTable)
++ {
++ if ( binding instanceof BindingTDB )
++ return ((BindingTDB)binding).getBindingId() ;
++
++ BindingNodeId b = new BindingNodeId(binding) ;
++ // and copy over, getting NodeIds.
++ Iterator<Var> vars = binding.vars() ;
++
++ for ( ; vars.hasNext() ; )
++ {
++ Var v = vars.next() ;
++ Node n = binding.get(v) ;
++ if ( n == null )
++ // Variable mentioned in the binding but not actually defined.
++ // Can occur with BindingProject
++ continue ;
++
++ // Rely on the node table cache for efficency - we will likely be
++ // repeatedly looking up the same node in different bindings.
++ NodeId id = nodeTable.getNodeIdForNode(n) ;
++ // Even put in "does not exist" for a node now known not to be in the DB.
++ b.put(v, id) ;
++ }
++ return b ;
++ }
++
++ /** Find whether a specific graph name is in the quads table. */
++ public static QueryIterator testForGraphName(DatasetGraphTDB ds, Node graphNode, QueryIterator input,
++ Predicate<Tuple<NodeId>> filter, ExecutionContext execCxt) {
++ NodeId nid = TDBInternal.getNodeId(ds, graphNode) ;
++ boolean exists = !NodeId.isDoesNotExist(nid) ;
++ if ( exists ) {
++ // Node exists but is it used in the quad position?
++ NodeTupleTable ntt = ds.getQuadTable().getNodeTupleTable() ;
++ // Don't worry about abortable - this iterator should be fast
++ // (with normal indexing - at least one G???).
++ // Either it finds a starting point, or it doesn't. We are only
++ // interested in the first .hasNext.
++ Iterator<Tuple<NodeId>> iter1 = ntt.find(nid, NodeId.NodeIdAny, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++ if ( filter != null )
++ iter1 = Iter.filter(iter1, filter) ;
++ exists = iter1.hasNext() ;
++ }
++
++ if ( exists )
++ return input ;
++ else {
++ input.close() ;
++ return QueryIterNullIterator.create(execCxt) ;
++ }
++ }
++
++ /** Find all the graph names in the quads table. */
++ public static QueryIterator graphNames(DatasetGraphTDB ds, Node graphNode, QueryIterator input,
++ Predicate<Tuple<NodeId>> filter, ExecutionContext execCxt) {
++ List<Abortable> killList = new ArrayList<>() ;
++ Iterator<Tuple<NodeId>> iter1 = ds.getQuadTable().getNodeTupleTable().find(NodeId.NodeIdAny, NodeId.NodeIdAny,
++ NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++ if ( filter != null )
++ iter1 = Iter.filter(iter1, filter) ;
++
++ Iterator<NodeId> iter2 = Iter.map(iter1, t -> t.get(0)) ;
++ // Project is cheap - don't brother wrapping iter1
++ iter2 = makeAbortable(iter2, killList) ;
++
++ Iterator<NodeId> iter3 = Iter.distinct(iter2) ;
++ iter3 = makeAbortable(iter3, killList) ;
++
++ Iterator<Node> iter4 = NodeLib.nodes(ds.getQuadTable().getNodeTupleTable().getNodeTable(), iter3) ;
++
++ final Var var = Var.alloc(graphNode) ;
++ Iterator<Binding> iterBinding = Iter.map(iter4, node -> BindingFactory.binding(var, node)) ;
++ // Not abortable.
++ return new QueryIterTDB(iterBinding, killList, input, execCxt) ;
++ }
++
++ public static Set<NodeId> convertToNodeIds(Collection<Node> nodes, DatasetGraphTDB dataset)
++ {
++ Set<NodeId> graphIds = new HashSet<>() ;
++ NodeTable nt = dataset.getQuadTable().getNodeTupleTable().getNodeTable() ;
++ for ( Node n : nodes )
++ graphIds.add(nt.getNodeIdForNode(n)) ;
++ return graphIds ;
++ }
++
++ public static Iterator<Tuple<NodeId>> unionGraph(NodeTupleTable ntt)
++ {
++ Iterator<Tuple<NodeId>> iter = ntt.find((NodeId)null, null, null, null) ;
++ iter = Iter.map(iter, quadsToAnyTriples) ;
++ //iterMatches = Iter.distinct(iterMatches) ;
++
++ // This depends on the way indexes are choose and
++ // the indexing pattern. It assumes that the index
++ // chosen ends in G so same triples are adjacent
++ // in a union query.
++ /// See TupleTable.scanAllIndex that ensures this.
++ iter = Iter.distinctAdjacent(iter) ;
++ return iter ;
++ }
++
++ private static Function<Tuple<NodeId>, Tuple<NodeId>> quadsToAnyTriples = item -> {
++ return TupleFactory.create4(NodeId.NodeIdAny, item.get(1), item.get(2), item.get(3) ) ;
++ } ;
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/StageGeneratorDirectTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/StageGeneratorDirectTDB.java
index 0000000,0000000..5033f42
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/solver/StageGeneratorDirectTDB.java
@@@ -1,0 -1,0 +1,57 @@@
++/*
++ * 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.solver;
++
++import java.util.function.Predicate;
++
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.graph.Graph ;
++import org.apache.jena.sparql.core.BasicPattern ;
++import org.apache.jena.sparql.engine.ExecutionContext ;
++import org.apache.jena.sparql.engine.QueryIterator ;
++import org.apache.jena.sparql.engine.main.StageGenerator ;
++import org.seaborne.tdb2.store.GraphTDB ;
++import org.seaborne.tdb2.store.NodeId ;
++
++/** Execute TDB requests directly -- no reordering
++ * Using OpExecutor is preferred.
++ */
++public class StageGeneratorDirectTDB implements StageGenerator
++{
++ // Using OpExecutor is preferred.
++ StageGenerator above = null ;
++
++ public StageGeneratorDirectTDB(StageGenerator original)
++ {
++ above = original ;
++ }
++
++ @Override
++ public QueryIterator execute(BasicPattern pattern, QueryIterator input, ExecutionContext execCxt)
++ {
++ // --- In case this isn't for TDB
++ Graph g = execCxt.getActiveGraph() ;
++
++ if ( ! ( g instanceof GraphTDB ) )
++ // Not us - bounce up the StageGenerator chain
++ return above.execute(pattern, input, execCxt) ;
++ GraphTDB graph = (GraphTDB)g ;
++ Predicate<Tuple<NodeId>> filter = QC2.getFilter(execCxt.getContext()) ;
++ return SolverLib.execute(graph, pattern, input, filter, execCxt) ;
++ }
++}
[34/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/assembler/Vocab.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/assembler/Vocab.java
index 0000000,0000000..ae501bd
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/assembler/Vocab.java
@@@ -1,0 -1,0 +1,36 @@@
++/*
++ * 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.assembler ;
++
++import org.apache.jena.rdf.model.Property ;
++import org.apache.jena.rdf.model.Resource ;
++import org.apache.jena.rdf.model.ResourceFactory ;
++
++public class Vocab {
++ public static Resource type(String namespace, String localName) {
++ return ResourceFactory.createResource(namespace + localName) ;
++ }
++
++ public static Resource resource(String namespace, String localName) {
++ return ResourceFactory.createResource(namespace + localName) ;
++ }
++
++ public static Property property(String namespace, String localName) {
++ return ResourceFactory.createProperty(namespace + localName) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/assembler/VocabTDB2.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/assembler/VocabTDB2.java
index 0000000,0000000..a661368
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/assembler/VocabTDB2.java
@@@ -1,0 -1,0 +1,90 @@@
++/*
++ * 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.assembler;
++
++
++import org.apache.jena.assembler.Assembler ;
++import org.apache.jena.assembler.ConstAssembler ;
++import org.apache.jena.assembler.JA ;
++import org.apache.jena.assembler.assemblers.AssemblerGroup ;
++import org.apache.jena.rdf.model.Property ;
++import org.apache.jena.rdf.model.Resource ;
++import org.apache.jena.sparql.core.assembler.AssemblerUtils ;
++import org.seaborne.tdb2.TDB2 ;
++
++public class VocabTDB2
++{
++ private static final String NS = TDB2.namespace ;
++
++ public static String getURI() { return NS ; }
++
++ // Types
++ public static final Resource tDatasetTDB = Vocab.type(NS, "DatasetTDB2") ;
++ public static final Resource tDatasetTDB_alt = Vocab.type(NS, "DatasetTDB") ;
++ public static final Resource tGraphTDB = Vocab.type(NS, "GraphTDB2") ;
++ public static final Resource tGraphTDB_alt = Vocab.type(NS, "GraphTDB") ;
++// public static final Resource tTupleIndex = Vocab.type(NS, "TupleIndex") ;
++ public static final Resource tNodeTable = Vocab.type(NS, "NodeTable") ;
++
++ public static final Property pLocation = Vocab.property(NS, "location") ;
++ public static final Property pUnionDefaultGraph = Vocab.property(NS, "unionDefaultGraph") ;
++
++ public static final Property pIndex = Vocab.property(NS, "index") ;
++ public static final Property pGraphName1 = Vocab.property(NS, "graphName") ;
++ public static final Property pGraphName2 = Vocab.property(NS, "namedGraph") ;
++ public static final Property pDataset = Vocab.property(NS, "dataset") ;
++
++ public static final Property pNodes = Vocab.property(NS, "nodes") ;
++
++ // Indexes
++ public static final Property pDescription = Vocab.property(getURI(), "description") ;
++ public static final Property pFile = Vocab.property(getURI(), "file") ;
++
++ // Nodes
++ public static final Property pNodeIndex = Vocab.property(getURI(), "nodeIndex") ;
++ public static final Property pNodeData = Vocab.property(getURI(), "nodeData") ;
++
++ // Setting
++ public static final Property pSetting = Vocab.property(getURI(), "setting") ;
++ public static final Property pName = Vocab.property(getURI(), "name") ;
++ public static final Property pValue = Vocab.property(getURI(), "value") ;
++
++ private static boolean initialized = false ;
++
++ static { init() ; }
++
++ static synchronized public void init()
++ {
++ if ( initialized )
++ return ;
++ registerWith(Assembler.general) ;
++ initialized = true ;
++ }
++
++ static void registerWith(AssemblerGroup g)
++ {
++ // Wire in the extension assemblers (extensions relative to the Jena assembler framework)
++ // Domain and range for properties.
++ // Separated and use ja:imports
++ AssemblerUtils.registerDataset(tDatasetTDB, new DatasetAssemblerTDB());
++ AssemblerUtils.registerDataset(tDatasetTDB_alt, new DatasetAssemblerTDB());
++ AssemblerUtils.register(ConstAssembler.general(), tGraphTDB, new TDBGraphAssembler(), JA.Model);
++ AssemblerUtils.register(ConstAssembler.general(), tGraphTDB_alt, new TDBGraphAssembler(), JA.Model);
++
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/graph/TransactionHandlerTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/graph/TransactionHandlerTDB.java
index 0000000,0000000..664b005
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/graph/TransactionHandlerTDB.java
@@@ -1,0 -1,0 +1,60 @@@
++/*
++ * 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.graph;
++
++import org.apache.jena.graph.impl.TransactionHandlerBase ;
++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 ;
++
++public class TransactionHandlerTDB extends TransactionHandlerBase //implements TransactionHandler
++{
++ private final GraphTDB graph ;
++ private final DatasetGraphTDB dsg;
++
++ public TransactionHandlerTDB(GraphTDB graph) {
++ this.graph = graph;
++ this.dsg = graph.getDSG();
++ }
++
++ @Override
++ public void abort() {
++ graph.getDSG().abort();
++ graph.getDSG().end();
++ }
++
++ @Override
++ public void begin() {
++ if ( TransactionCoordinator.promotion )
++ dsg.begin(ReadWrite.READ);
++ else
++ dsg.begin(ReadWrite.WRITE);
++ }
++
++ @Override
++ public void commit() {
++ dsg.commit();
++ dsg.end();
++ }
++
++ @Override
++ public boolean transactionsSupported() {
++ return true;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/lib/Async.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/lib/Async.java
index 0000000,0000000..2a0bf52
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/lib/Async.java
@@@ -1,0 -1,0 +1,84 @@@
++/*
++ * 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.lib;
++
++import java.util.concurrent.* ;
++
++import org.seaborne.tdb2.TDBException ;
++
++/** Asyncrhonous operations support
++ * This class provides a simple framework for asynchronous operations.
++ * There is a thread pool and a pending queue.
++ * <p>
++ * Default settings are thread pool of one and at most two pending operations.
++ * When a new async operation is added, the pending queue is checked, and the
++ * call blocks until the pending queue is below the threashold.
++ * <p>
++ * With the default setting of a thread pool of one, operations are
++ * executed in the order submitted.
++ * <p>
++ * If the far end is the bottleneck, a longer queeue is no help.
++ */
++public final class Async {
++ // Currently specific to ThriftRunnable
++ private static final int THREAD_POOL_SIZE = 1 ;
++ private static final int PENDING_MAX = 2 ;
++ private static final int BlockingQueueSize = PENDING_MAX+2 ;
++
++ private final int pendingQueueLimit ;
++ private final int blockingQueueSize ;
++ private final ExecutorService executorService;
++ private final BlockingQueue<Future<Void>> outstanding ;
++
++ public Async() {
++ this(THREAD_POOL_SIZE, PENDING_MAX) ;
++ }
++
++ public Async(int threadPoolSize, int pendingQueueLimit) {
++ this.pendingQueueLimit = pendingQueueLimit ;
++ this.blockingQueueSize = this.pendingQueueLimit+1 ;
++ this.executorService = Executors.newFixedThreadPool(threadPoolSize) ;
++ this.outstanding = new ArrayBlockingQueue<>(BlockingQueueSize) ;
++ }
++
++ /** Block until all pending oeprations has been completed */
++ public void completeAsyncOperations() {
++ reduceAsyncQueue(0) ;
++ }
++
++ /** Block until the pending operations queue is below the given size. */
++ public void reduceAsyncQueue(int reduceSize) {
++ System.out.println("Reduce: "+outstanding.size()) ;
++ while ( outstanding.size() > reduceSize ) {
++ try { outstanding.take().get() ; }
++ catch (Exception ex) {
++ throw new TDBException("Exception taking from async queue", ex) ;
++ }
++ }
++ }
++
++ public void execAsync(Object lock, Runnable action) {
++ reduceAsyncQueue(pendingQueueLimit) ;
++ Future<Void> task = executorService.submit(()-> {
++ try { action.run() ; }
++ catch (Exception ex) { throw new TDBException("Unexpected exception: "+ex.getMessage(), ex) ; }
++ return null ;
++ }) ;
++ outstanding.add(task) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/lib/NodeLib.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/lib/NodeLib.java
index 0000000,0000000..97951d6
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/lib/NodeLib.java
@@@ -1,0 -1,0 +1,141 @@@
++/*
++ * 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.lib;
++
++import static org.seaborne.tdb2.sys.SystemTDB.LenNodeHash;
++
++import java.security.DigestException;
++import java.security.MessageDigest;
++import java.security.NoSuchAlgorithmException;
++import java.util.Iterator;
++
++import org.apache.jena.atlas.iterator.Iter;
++import org.apache.jena.atlas.lib.Bytes;
++import org.apache.jena.atlas.lib.Pool;
++import org.apache.jena.atlas.lib.PoolBase;
++import org.apache.jena.atlas.lib.PoolSync;
++import org.apache.jena.atlas.logging.Log;
++import org.apache.jena.graph.Node;
++import org.apache.jena.sparql.util.NodeUtils;
++import org.seaborne.dboe.base.record.Record;
++import org.seaborne.tdb2.TDBException;
++import org.seaborne.tdb2.store.Hash;
++import org.seaborne.tdb2.store.NodeId;
++import org.seaborne.tdb2.store.NodeIdFactory;
++import org.seaborne.tdb2.store.nodetable.NodeTable;
++
++public class NodeLib {
++ public static Hash hash(Node n) {
++ Hash h = new Hash(LenNodeHash);
++ setHash(h, n);
++ return h;
++ }
++
++ private static String BNODE = "bnode";
++ private static String URI = "uri";
++ private static String LITERAL = "literal";
++
++ public static void setHash(Hash h, Node n) {
++ if ( n.isURI() )
++ hash(h, n.getURI(), null, null, URI);
++ else if ( n.isBlank() )
++ hash(h, n.getBlankNodeLabel(), null, null, BNODE);
++ else if ( n.isLiteral() ) {
++ String dt = n.getLiteralDatatypeURI();
++ if ( NodeUtils.isSimpleString(n) || NodeUtils.isLangString(n) ) {
++ // RDF 1.1 : No datatype for:
++ // xsd:String as simple literals
++ // rdf:langString and @
++ dt = null;
++ }
++ hash(h, n.getLiteralLexicalForm(), n.getLiteralLanguage(), dt, LITERAL);
++ } else
++ throw new TDBException("Attempt to hash something strange: " + n);
++ }
++
++ private static int InitialPoolSize = 5;
++ private static Pool<MessageDigest> digesters = PoolSync.create(new PoolBase<MessageDigest>());
++ static {
++ try {
++ for ( int i = 0 ; i < InitialPoolSize ; i++ )
++ digesters.put(MessageDigest.getInstance("MD5"));
++ }
++ catch (NoSuchAlgorithmException e) {
++ Log.warn(NodeLib.class, "NoSuchAlgorithmException", e);
++ throw new RuntimeException(e);
++ }
++ }
++
++ private static MessageDigest allocDigest() {
++ try {
++ MessageDigest disgest = digesters.get();
++ if ( disgest == null )
++ disgest = MessageDigest.getInstance("MD5");
++ return disgest;
++ }
++ catch (NoSuchAlgorithmException e) {
++ e.printStackTrace();
++ return null;
++ }
++ }
++
++ private static void deallocDigest(MessageDigest digest) {
++ digest.reset();
++ digesters.put(digest);
++ }
++
++ private static void hash(Hash h, String lex, String lang, String datatype, String nodeName) {
++ if ( datatype == null )
++ datatype = "";
++ if ( lang == null )
++ lang = "";
++ String toHash = lex + "|" + lang + "|" + datatype + "|" + nodeName;
++ MessageDigest digest;
++ try {
++ // MessageDigest.getInstance("MD5");
++ digest = allocDigest();
++ digest.update(Bytes.string2bytes(toHash));
++ if ( h.getLen() == 16 ) {
++ // MD5 is 16 bytes.
++ digest.digest(h.getBytes(), 0, 16);
++ } else {
++ byte b[] = digest.digest(); // 16 bytes.
++ System.arraycopy(b, 0, h.getBytes(), 0, h.getLen());
++ }
++ deallocDigest(digest);
++ return;
++ }
++ catch (DigestException ex) {
++ Log.error(NodeLib.class, "DigestException", ex);
++ }
++ }
++
++ public static NodeId getNodeId(Record r, int idx) {
++ return NodeIdFactory.get(r.getKey(), idx);
++ }
++
++ public static Node termOrAny(Node node) {
++ if ( node == null || node.isVariable() )
++ return Node.ANY;
++ return node;
++ }
++
++ public static Iterator<Node> nodes(final NodeTable nodeTable, Iterator<NodeId> iter) {
++ return Iter.map(iter, nodeTable::getNodeForNodeId);
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/lib/TupleLib.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/lib/TupleLib.java
index 0000000,0000000..7f554f9
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/lib/TupleLib.java
@@@ -1,0 -1,0 +1,154 @@@
++/*
++ * 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.lib;
++
++import java.util.Iterator ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import org.apache.jena.atlas.lib.InternalErrorException ;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.atlas.lib.tuple.TupleFactory ;
++import org.apache.jena.atlas.lib.tuple.TupleMap ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.graph.Triple ;
++import org.apache.jena.sparql.core.Quad ;
++import org.seaborne.dboe.base.record.Record ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.store.NodeIdFactory;
++import org.seaborne.tdb2.store.nodetable.NodeTable ;
++
++public class TupleLib
++{
++ public static Iterator<Tuple<Node>> convertToNodes(final NodeTable nodeTable, Iterator<Tuple<NodeId>> iter) {
++ return Iter.map(iter, item -> tupleNodes(nodeTable, item));
++ }
++
++ public static Iterator<Tuple<NodeId>> convertToNodeId(final NodeTable nodeTable, Iterator<Tuple<Node>> iter) {
++ return Iter.map(iter, item -> tupleNodeIds(nodeTable, item));
++ }
++
++ // Leave - bypasses extract step in Tuple<NodeId> -> Tuple<Node> -> Triple
++ public static Iterator<Triple> convertToTriples(final NodeTable nodeTable, Iterator<Tuple<NodeId>> iter) {
++ return Iter.map(iter, item -> triple(nodeTable, item));
++ }
++
++ public static Iterator<Quad> convertToQuads(final NodeTable nodeTable, Iterator<Tuple<NodeId>> iter) {
++ return Iter.map(iter, item -> quad(nodeTable, item));
++ }
++
++ public static Tuple<Node> tupleNodes(NodeTable nodeTable, Tuple<NodeId> ids) {
++ int N = ids.len();
++ Node[] n = new Node[N];
++ for ( int i = 0 ; i < N ; i++ )
++ n[i] = nodeTable.getNodeForNodeId(ids.get(i));
++ return TupleFactory.create(n);
++ }
++
++ public static Tuple<NodeId> tupleNodeIds(NodeTable nodeTable, Tuple<Node> nodes) {
++ int N = nodes.len();
++ NodeId[] n = new NodeId[N];
++ for ( int i = 0 ; i < N ; i++ )
++ n[i] = nodeTable.getNodeIdForNode(nodes.get(i));
++ return TupleFactory.create(n);
++ }
++
++ private static Triple triple(NodeTable nodeTable, Tuple<NodeId> tuple) {
++ if ( tuple.len() != 3 )
++ throw new TDBException("Tuple is not of length 3: " + tuple);
++ return triple(nodeTable, tuple.get(0), tuple.get(1), tuple.get(2));
++ }
++
++ private static Triple triple(NodeTable nodeTable, NodeId s, NodeId p, NodeId o) {
++ if ( ! NodeId.isConcrete(s) )
++ throw new InternalErrorException("Invalid id for subject: "+fmt(s,p,o)) ;
++ if ( ! NodeId.isConcrete(p) )
++ throw new InternalErrorException("Invalid id for predicate: "+fmt(s,p,o)) ;
++ if ( ! NodeId.isConcrete(o) )
++ throw new InternalErrorException("Invalid id for object: "+fmt(s,p,o)) ;
++
++ Node sNode = nodeTable.getNodeForNodeId(s) ;
++ if ( sNode == null )
++ throw new InternalErrorException("Invalid id node for subject (null node): "+fmt(s,p,o)) ;
++
++ Node pNode = nodeTable.getNodeForNodeId(p) ;
++ if ( pNode == null )
++ {
++ nodeTable.getNodeForNodeId(p) ;
++ throw new InternalErrorException("Invalid id node for predicate (null node): "+fmt(s,p,o)) ;
++ }
++
++ Node oNode = nodeTable.getNodeForNodeId(o) ;
++ if ( oNode == null )
++ throw new InternalErrorException("Invalid id node for object (null node): "+fmt(s,p,o)) ;
++
++ return new Triple(sNode, pNode, oNode) ;
++ }
++
++ private static String fmt(NodeId s, NodeId p, NodeId o)
++ {
++ return "("+s+", "+p+", "+o+")" ;
++ }
++
++ private static Quad quad(NodeTable nodeTable, Tuple<NodeId> tuple)
++ {
++ if ( tuple.len() != 4 )
++ throw new TDBException("Tuple is not of length 4: "+tuple) ;
++ return quad(nodeTable, tuple.get(0), tuple.get(1), tuple.get(2), tuple.get(3)) ;
++ }
++
++ private static Quad quad(NodeTable nodeTable, NodeId g, NodeId s, NodeId p, NodeId o)
++ {
++ Node gNode = nodeTable.getNodeForNodeId(g) ;
++ Node sNode = nodeTable.getNodeForNodeId(s) ;
++ Node pNode = nodeTable.getNodeForNodeId(p) ;
++ Node oNode = nodeTable.getNodeForNodeId(o) ;
++ return new Quad(gNode, sNode, pNode, oNode) ;
++ }
++
++ // ---- Tuples and Records
++ public static Tuple<NodeId> tuple(Record r, TupleMap tMap) {
++ // Unmapping.
++ int N = r.getKey().length/NodeId.SIZE;
++ NodeId[] nodeIds = new NodeId[N] ;
++ for ( int i = 0 ; i < N ; i++ )
++ {
++ int j = i ;
++ if ( tMap != null )
++ j = tMap.unmapIdx(i) ;
++ NodeId id = NodeIdFactory.get(r.getKey(), j*NodeId.SIZE) ;
++ nodeIds[i] = id ;
++ }
++ return TupleFactory.create(nodeIds) ;
++ }
++
++
++ public static Record record(RecordFactory factory, Tuple<NodeId> tuple, TupleMap tMap) {
++ // Mapping.
++ byte[] b = new byte[tuple.len()*NodeId.SIZE] ;
++ for ( int i = 0 ; i < tuple.len() ; i++ )
++ {
++ int j = tMap.getSlotIdx(i) ;
++ // i'th Nodeid goes to j'th bytes slot.
++ NodeIdFactory.set(tuple.get(j), b, i*NodeId.SIZE) ;
++ }
++
++ return factory.create(b) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/loader/Loader.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/loader/Loader.java
index 0000000,0000000..8555088f
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/loader/Loader.java
@@@ -1,0 -1,0 +1,78 @@@
++/*
++ * 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.loader;
++
++import org.apache.jena.atlas.lib.ProgressMonitor ;
++import org.apache.jena.atlas.logging.FmtLog ;
++import org.apache.jena.query.Dataset ;
++import org.apache.jena.riot.RDFDataMgr ;
++import org.apache.jena.riot.system.ProgressStreamRDF ;
++import org.apache.jena.riot.system.StreamRDF ;
++import org.apache.jena.riot.system.StreamRDFLib ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.tdb2.store.DatasetGraphTDB ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++public class Loader {
++
++ private static final int BATCH_SIZE = 100 ;
++
++ // XXX StreamRDFBatchSplit and parallel index update.
++ private static Logger LOG = LoggerFactory.getLogger("Loader") ;
++
++ public static void bulkLoad(Dataset ds, String ... files) {
++ DatasetGraphTDB dsg = (DatasetGraphTDB)ds.asDatasetGraph() ;
++ StreamRDF s1 = StreamRDFLib.dataset(dsg) ;
++ ProgressMonitor plog = ProgressMonitor.create(LOG, "Triples", 100000, 10) ;
++ ProgressStreamRDF sMonitor = new ProgressStreamRDF(s1, plog) ;
++ StreamRDF s3 = sMonitor ;
++
++ plog.start();
++ Txn.executeWrite(ds, () -> {
++ for ( String fn : files ) {
++ if ( files.length > 1 )
++ FmtLog.info(LOG, "File: %s",fn);
++ RDFDataMgr.parse(s3, fn) ;
++ }
++ }) ;
++ plog.finish();
++ plog.finishMessage();
++ }
++
++ public static void bulkLoadBatching(Dataset ds, String ... files) {
++ DatasetGraphTDB dsg = (DatasetGraphTDB)ds.asDatasetGraph() ;
++
++ StreamRDFBatchSplit s1 = new StreamRDFBatchSplit(dsg, 10) ;
++ ProgressMonitor plog = ProgressMonitor.create(LOG, "Triples", 100000, BATCH_SIZE) ;
++ // Want the monitor on the outside to capture transaction wrapper costs.
++ StreamRDF s3 = new ProgressStreamRDF(s1, plog) ;
++
++ plog.start();
++ Txn.executeWrite(ds, () -> {
++ for ( String fn : files ) {
++ if ( files.length > 1 )
++ FmtLog.info(LOG, "File: %s",fn);
++ RDFDataMgr.parse(s3, fn) ;
++ }
++ }) ;
++ plog.finish();
++ plog.finishMessage();
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/loader/StreamRDFBatchSplit.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/loader/StreamRDFBatchSplit.java
index 0000000,0000000..fb7e25c
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/loader/StreamRDFBatchSplit.java
@@@ -1,0 -1,0 +1,224 @@@
++/*
++ * 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.loader;
++
++import java.util.* ;
++import java.util.stream.Collectors ;
++
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.atlas.lib.tuple.TupleFactory ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.graph.Triple ;
++import org.apache.jena.riot.other.BatchedStreamRDF ;
++import org.apache.jena.riot.system.StreamRDF ;
++import org.apache.jena.sparql.core.Quad ;
++import org.seaborne.dboe.transaction.txn.Transaction ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.setup.TDBDatasetDetails ;
++import org.seaborne.tdb2.store.DatasetGraphTDB ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.store.NodeIdFactory;
++import org.seaborne.tdb2.store.nodetable.NodeTable ;
++import org.seaborne.tdb2.store.tupletable.TupleTable ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++/**
++ * @see BatchedStreamRDF BatchedStreamRDF, which batches by subject
++ */
++public class StreamRDFBatchSplit implements StreamRDF {
++ // Need to handle transactions?
++ // Lizard des (TxnClient)
++
++ private static Logger log = LoggerFactory.getLogger(StreamRDFBatchSplit.class) ;
++ protected static NodeId placeholder = NodeIdFactory.genUnique();
++ protected final List<Triple> triples ;
++ protected final List<Tuple<NodeId>> tuples ;
++ protected final Map<Node, NodeId> mapping ;
++
++ private final int batchSize ;
++ private final TDBDatasetDetails details ;
++ private final DatasetGraphTDB dsg ;
++ private Transaction txn = null ;
++
++ public StreamRDFBatchSplit(DatasetGraphTDB dsg, int batchSize) {
++ this.dsg = dsg ;
++ this.batchSize = batchSize ;
++ this.triples = new ArrayList<>(batchSize) ;
++ this.tuples = new ArrayList<>(triples.size()) ;
++ this.mapping = new HashMap<>(2*batchSize) ;
++ this.details = new TDBDatasetDetails(dsg) ;
++ }
++
++ @Override
++ public void start() {
++ log.info("Batch size: "+batchSize);
++ // Multiple starts in one trnasaciton are possible.
++ if ( txn == null )
++ txn = dsg.getTxnSystem().getThreadTransaction() ;
++ if ( txn == null )
++ throw new TDBException("Not in a transaction") ;
++ }
++
++ @Override
++ public void triple(Triple triple) {
++ //Find nodes.
++ //log.info("Triple: "+triple) ;
++ processNode(triple.getSubject()) ;
++ processNode(triple.getPredicate()) ;
++ processNode(triple.getObject()) ;
++ triples.add(triple) ;
++ if ( triples.size() >= batchSize )
++ processBatch() ;
++ }
++
++ int batchNumber = 0 ;
++
++ protected void processBatch() {
++ //if ( batchNumber < 10 )
++ batchNumber++ ;
++ //FmtLog.info(log, ">>processBatch: [%d]->%d", batchNumber, triples.size()) ;
++
++ Set<Node> requiredNodes = mapping.keySet() ;
++
++ boolean executeBatchNodesPhase = true ;
++ boolean executeIndexPhase = true ;
++ // Derived control.
++ boolean batchUpdateIndexes = true ;
++
++ if ( executeBatchNodesPhase )
++ // Check this is a cache node table.
++ batchUpdateNodes(requiredNodes, details) ;
++
++ if ( executeIndexPhase ) {
++ if ( batchUpdateIndexes )
++ batchUpdateIndexes(dsg, details, triples, /*tuples*/null) ;
++ else
++ incrementalUpdateIndexes(triples, dsg) ;
++ }
++ triples.clear();
++ tuples.clear() ;
++ //FmtLog.info(log, "<<processBatch") ;
++ mapping.clear();
++// if ( batchSize < 10 )
++// System.exit(0) ;
++ }
++
++ private static void incrementalUpdateIndexes(List<Triple> triples, DatasetGraphTDB dsg) {
++ for ( Triple triple : triples ) {
++ dsg.getTripleTable().add(triple);
++ }
++ }
++
++ /** This files the cache so that the tuples adds are faster */
++ private static void batchUpdateNodes(Set<Node> required, TDBDatasetDetails details) {
++ List<Node> nodes = new ArrayList<>() ;
++ // Resolve NodeIds
++
++ // ** Move this into cache - code.
++
++ for ( Node n : required ) {
++ //
++ if ( details.ntCache.getNodeIdForNodeCache(n) == null /* set input - no need :: && ! nodes.contains(n) /* Not good?*/ )
++ nodes.add(n) ;
++ }
++ //log.info("Batch nodes: "+nodes.size()) ;
++ // This drops into the default method.
++ details.ntTop.bulkNodeToNodeId(nodes, true) ;
++
++ // Check
++ // Resolve NodeIds
++ for ( Node n : required ) {
++ if ( details.ntCache.getNodeIdForNodeCache(n) == null )
++ log.info("Not in cache: "+n) ;
++ }
++ //details.ntCluster.bulkNodeToNodeId(nodes, true) ;
++
++
++
++ }
++
++ private static void batchUpdateIndexes(DatasetGraphTDB dsg, TDBDatasetDetails details, List<Triple> batchTriples, List<Tuple<NodeId>> workspace) {
++ List<Tuple<NodeId>> tuples = workspace ;
++ if ( tuples == null )
++ tuples = new ArrayList<>(batchTriples.size()) ;
++
++ convert(batchTriples, tuples, details.ntTop) ;
++ //log.info("Batch triples: "+tuples.size()) ;
++
++ TupleTable tupleTable = dsg.getTripleTable().getNodeTupleTable().getTupleTable() ;
++ tupleTable.addAll(tuples);
++ }
++
++ // check for duplicate code
++ private static List<Tuple<NodeId>> convert(List<Triple> triples, NodeTable nodeTable) {
++ return triples.stream().map(t -> TupleFactory.tuple(nodeTable.getAllocateNodeId(t.getSubject()),
++ nodeTable.getAllocateNodeId(t.getPredicate()),
++ nodeTable.getAllocateNodeId(t.getObject())))
++ .collect(Collectors.toList());
++ }
++
++ private static void convert(List<Triple> triples, List<Tuple<NodeId>> tuples, NodeTable nodeTable) {
++ // Slightly faster. But larger batches?
++ for ( Triple t : triples ) {
++ NodeId nid_s = nodeTable.getAllocateNodeId(t.getSubject()) ;
++ NodeId nid_p = nodeTable.getAllocateNodeId(t.getPredicate()) ;
++ NodeId nid_o = nodeTable.getAllocateNodeId(t.getObject()) ;
++ Tuple<NodeId> x = TupleFactory.tuple(nid_s, nid_p, nid_o) ;
++ tuples.add(x) ;
++ }
++
++// triples.stream().map(t->
++// TupleFactory.tuple
++// (nodeTable.getAllocateNodeId(t.getSubject()),
++// nodeTable.getAllocateNodeId(t.getPredicate()),
++// nodeTable.getAllocateNodeId(t.getObject())))
++// .collect(Collectors.toCollection(()->tuples)) ;
++ }
++
++
++ private void processNode(Node node) {
++
++ if ( mapping.containsKey(node))
++ return ;
++
++ if ( NodeId.hasInlineDatatype(node) ) {
++ NodeId nodeId = NodeId.inline(node) ;
++ if ( nodeId != null )
++ return ;
++ }
++ mapping.put(node, placeholder) ;
++ }
++
++ @Override
++ public void quad(Quad quad) {}
++
++ @Override
++ public void base(String base) {}
++
++ @Override
++ public void prefix(String prefix, String iri) {}
++
++ @Override
++ public void finish() {
++ if ( ! triples.isEmpty() )
++ processBatch() ;
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/migrate/A2.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/migrate/A2.java
index 0000000,0000000..4dd1a90
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/migrate/A2.java
@@@ -1,0 -1,0 +1,37 @@@
++/*
++ * 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.migrate;
++
++import org.apache.jena.sparql.algebra.Op ;
++import org.apache.jena.sparql.algebra.Transform ;
++import org.apache.jena.sparql.algebra.Transformer ;
++import org.apache.jena.sparql.core.Quad ;
++
++public class A2
++{
++ /** Convert a pattern, assumed to be quad form,
++ * so that the default graph is the union of named graphs.
++ */
++ public static Op unionDefaultGraphQuads(Op op)
++ {
++ // Rewrite so that any explicitly named "default graph" is union graph.
++ Transform t = new TransformGraphRename(Quad.defaultGraphNodeGenerated, Quad.unionGraph) ;
++ op = Transformer.transform(t, op) ;
++ return op ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/migrate/TransformGraphRename.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/migrate/TransformGraphRename.java
index 0000000,0000000..4759bed
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/migrate/TransformGraphRename.java
@@@ -1,0 -1,0 +1,53 @@@
++/*
++ * 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.migrate;
++
++import org.apache.jena.graph.Node ;
++import org.apache.jena.sparql.algebra.Op ;
++import org.apache.jena.sparql.algebra.TransformCopy ;
++import org.apache.jena.sparql.algebra.op.OpGraph ;
++import org.apache.jena.sparql.algebra.op.OpQuadPattern ;
++
++public class TransformGraphRename extends TransformCopy
++{
++ private Node oldGraphName ;
++ private Node newGraphName ;
++
++ public TransformGraphRename(Node oldGraphName, Node newGraphName)
++ {
++ this.oldGraphName = oldGraphName ;
++ this.newGraphName = newGraphName ;
++ }
++
++ // Does not affect variables.
++ @Override
++ public Op transform(OpGraph opGraph, Op x)
++ {
++ if ( opGraph.getNode().equals(oldGraphName) )
++ opGraph = new OpGraph(newGraphName, x) ;
++ return super.transform(opGraph, x) ;
++ }
++
++ @Override
++ public Op transform(OpQuadPattern opQuadPattern)
++ {
++ if ( opQuadPattern.getGraphNode().equals(oldGraphName) )
++ opQuadPattern = new OpQuadPattern(newGraphName, opQuadPattern.getBasicPattern()) ;
++ return super.transform(opQuadPattern) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/modify/UpdateEngineTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/modify/UpdateEngineTDB.java
index 0000000,0000000..844f5a9
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/modify/UpdateEngineTDB.java
@@@ -1,0 -1,0 +1,52 @@@
++/*
++ * 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.modify;
++
++import org.apache.jena.sparql.core.DatasetGraph ;
++import org.apache.jena.sparql.engine.binding.Binding ;
++import org.apache.jena.sparql.modify.UpdateEngine ;
++import org.apache.jena.sparql.modify.UpdateEngineFactory ;
++import org.apache.jena.sparql.modify.UpdateEngineMain ;
++import org.apache.jena.sparql.modify.UpdateEngineRegistry ;
++import org.apache.jena.sparql.util.Context ;
++import org.seaborne.tdb2.store.DatasetGraphTxn ;
++
++public class UpdateEngineTDB extends UpdateEngineMain
++{
++ public UpdateEngineTDB(DatasetGraphTxn graphStore, Binding inputBinding, Context context)
++ { super(graphStore, inputBinding, context) ; }
++
++
++ // ---- Factory
++ public static UpdateEngineFactory getFactory() {
++ return new UpdateEngineFactory()
++ {
++ @Override
++ public boolean accept(DatasetGraph dataset, Context context) {
++ return (dataset instanceof DatasetGraphTxn) ;
++ }
++
++ @Override
++ public UpdateEngine create(DatasetGraph dataset, Binding inputBinding, Context context) {
++ return new UpdateEngineTDB((DatasetGraphTxn)dataset, inputBinding, context);
++ }
++ } ;
++ }
++
++ public static void register() { UpdateEngineRegistry.get().add(getFactory()) ; }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/ComponentIdMgr.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/ComponentIdMgr.java
index 0000000,0000000..7464a5a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/ComponentIdMgr.java
@@@ -1,0 -1,0 +1,101 @@@
++/*
++ * 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.setup;
++
++import java.util.HashMap ;
++import java.util.Map ;
++import java.util.UUID ;
++
++import org.seaborne.dboe.transaction.txn.ComponentId ;
++import org.slf4j.Logger ;
++import org.slf4j.LoggerFactory ;
++
++// Consistent name -> ComponentId
++
++public class ComponentIdMgr {
++ private static Logger log = LoggerFactory.getLogger(ComponentIdMgr.class) ;
++
++ private static Map<String, Integer> names = new HashMap<>() ;
++ static {
++ // Well know names.
++ setup(1, "SPO") ;
++ setup(2, "POS") ;
++ setup(3, "PSO") ;
++ setup(4, "OSP") ;
++
++ setup(11, "GSPO") ;
++ setup(12, "GPOS") ;
++ setup(13, "GPSO") ;
++ setup(14, "GOSP") ;
++
++ setup(21, "POSG") ;
++ setup(22, "PSOG") ;
++ setup(23, "OSPG") ;
++ setup(24, "SPOG") ;
++
++ setup(30, "GPU") ;
++
++ setup(40, "prefixes") ;
++ setup(41, "prefixes-data") ;
++
++ setup(50, "nodes") ;
++ setup(51, "nodes-data") ;
++ }
++
++ static void setup(int idx, String unitName) {
++ if ( names.containsKey(unitName) )
++ log.error("Name '"+unitName+"' is already registered") ;
++ names.put(unitName, idx) ;
++ }
++
++ private Map<String, ComponentId> allocated = new HashMap<>() ;
++
++ // Name to index mapping.
++ static Map<String, String> mapper = new HashMap<>() ;
++ private final UUID base ;
++
++ public ComponentIdMgr(UUID base) {
++ this.base = base ;
++ }
++
++ public static int getIndex(String name) {
++ Integer idx = names.get(name) ;
++ if ( idx == null ) {
++ log.error("Unregistered '"+name+"'") ;
++ return -1 ;
++ }
++ return idx ;
++ }
++
++ public ComponentId getComponentId(String name) {
++// // Trace duplicates
++// final String tracename = "SPO" ;
++// if ( tracename.equals(name) )
++// log.info("Name '"+name+"'") ;
++ if ( ! names.containsKey(name))
++ log.error("Name '"+name+"' is not registered") ;
++ if ( allocated.containsKey(name) ) {
++ log.error("ComponentId for '"+name+"' has already been allocated") ;
++ return allocated.get(name) ;
++ }
++ ComponentId cid = ComponentId.alloc(name, base, names.get(name)) ;
++ allocated.put(name, cid) ;
++ return cid ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParams.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParams.java
index 0000000,0000000..2c59757
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParams.java
@@@ -1,0 -1,0 +1,441 @@@
++/*
++ * 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.setup;
++
++import java.util.Objects ;
++
++import org.seaborne.dboe.base.block.FileMode ;
++import org.seaborne.dboe.index.IndexParams ;
++import org.seaborne.tdb2.setup.StoreParamsBuilder.Item ;
++
++/** System parameters for a TDB database instance.
++ * <p>
++ * Some parameters can be changed from run to run
++ * and some parameters can only be changed at the point the database is
++ * created.
++ * <p>
++ * Getting paramters settings wrong can destroy a databse.
++ * Alternating the block size is not encouraged and should only be
++ * done if necessary. It can silently destroy a database if set
++ * to a different value than thatused to create the database. The
++ * default value of 8Kbytes is good for almost use.
++ *
++ * @see StoreParamsBuilder for constructing StoreParams
++ * @see StoreParamsConst for default values.
++ */
++public class StoreParams implements IndexParams, StoreParamsDynamic
++{
++ /* These are items you can change JVM to JVM */
++
++ /*package*/ final Item<FileMode> fileMode ;
++ /*package*/ final Item<Integer> blockSize ;
++ /*package*/ final Item<Integer> blockReadCacheSize ;
++ /*package*/ final Item<Integer> blockWriteCacheSize ;
++ /*package*/ final Item<Integer> Node2NodeIdCacheSize ;
++ /*package*/ final Item<Integer> NodeId2NodeCacheSize ;
++ /*package*/ final Item<Integer> NodeMissCacheSize ;
++
++ /* These are items affect database layout and
++ * only can be applied when a database is created.
++ * They do not affect existing databases.
++ * If you want to, say, change the index structure,
++ * you'll need to use the index tools.
++ */
++
++ /*package*/ final Item<String> nodeTableBaseName ;
++
++ /*package*/ final Item<String> primaryIndexTriples ;
++ /*package*/ final Item<String[]> tripleIndexes ;
++
++ /*package*/ final Item<String> primaryIndexQuads ;
++ /*package*/ final Item<String[]> quadIndexes ;
++
++ /*package*/ final Item<String> prefixTableBaseName ;
++ /*package*/ final Item<String> primaryIndexPrefix ;
++ /*package*/ final Item<String[]> prefixIndexes ;
++
++ /** Build StoreParams, starting from system defaults.
++ *
++ * @return StoreParamsBuilder
++ */
++ public static StoreParamsBuilder builder() { return StoreParamsBuilder.create() ; }
++
++ /** Build StoreParams, starting from given default values.
++ *
++ * @return StoreParamsBuilder
++ */
++ public static StoreParamsBuilder builder(StoreParams params) { return StoreParamsBuilder.create(params) ; }
++
++ /*package*/ StoreParams(Item<FileMode> fileMode, Item<Integer> blockSize,
++ Item<Integer> blockReadCacheSize, Item<Integer> blockWriteCacheSize,
++ Item<Integer> node2NodeIdCacheSize, Item<Integer> nodeId2NodeCacheSize,
++ Item<Integer> nodeMissCacheSize,
++
++ Item<String> nodeTableBaseName,
++ Item<String> primaryIndexTriples, Item<String[]> tripleIndexes,
++ Item<String> primaryIndexQuads, Item<String[]> quadIndexes,
++
++ Item<String> prefixTableBasename,
++ Item<String> primaryIndexPrefix, Item<String[]> prefixIndexes) {
++ this.fileMode = fileMode ;
++ this.blockSize = blockSize ;
++ this.blockReadCacheSize = blockReadCacheSize ;
++ this.blockWriteCacheSize = blockWriteCacheSize ;
++ this.Node2NodeIdCacheSize = node2NodeIdCacheSize ;
++ this.NodeId2NodeCacheSize = nodeId2NodeCacheSize ;
++ this.NodeMissCacheSize = nodeMissCacheSize ;
++
++ this.nodeTableBaseName = nodeTableBaseName ;
++
++ this.primaryIndexTriples = primaryIndexTriples ;
++ this.tripleIndexes = tripleIndexes ;
++ this.primaryIndexQuads = primaryIndexQuads ;
++ this.quadIndexes = quadIndexes ;
++ this.primaryIndexPrefix = primaryIndexPrefix ;
++ this.prefixIndexes = prefixIndexes ;
++
++ this.prefixTableBaseName = prefixTableBasename ;
++ }
++
++ /** The system default settings. This is the normal set to use.
++ * It is the set of values used when no StoreParams is provided,
++ * which is the normal usage.
++ */
++ public static StoreParams getDftStoreParams() {
++ return StoreParamsConst.dftStoreParams ;
++ }
++
++ /** A {@code StoreParams} that provides a smaller
++ * in-JVM foot print. This is compatible with
++ * any database but it it is wise to use this consistently,
++ * that is, use when created and when opened later.
++ * It reduces cache sizes and runs the database in "direct"
++ * file mode so as not to use memory mapped files
++ * in addition to the JVM space.
++ */
++ public static StoreParams getSmallStoreParams() {
++ return StoreParamsConst.smallStoreParams ;
++ }
++
++ @Override
++ public FileMode getFileMode() {
++ return fileMode.value ;
++ }
++
++ @Override
++ public boolean isSetFileMode() {
++ return fileMode.isSet ;
++ }
++
++ @Override
++ public Integer getBlockSize() {
++ return blockSize.value ;
++ }
++
++ @Override
++ public Integer getBlockReadCacheSize() {
++ return blockReadCacheSize.value ;
++ }
++
++ @Override
++ public boolean isSetBlockReadCacheSize() {
++ return blockReadCacheSize.isSet ;
++ }
++
++ @Override
++ public Integer getBlockWriteCacheSize() {
++ return blockWriteCacheSize.value ;
++ }
++
++ @Override
++ public boolean isSetBlockWriteCacheSize() {
++ return blockWriteCacheSize.isSet ;
++ }
++
++ @Override
++ public Integer getNode2NodeIdCacheSize() {
++ return Node2NodeIdCacheSize.value ;
++ }
++
++ @Override
++ public boolean isSetNodeId2NodeCacheSize() {
++ return NodeId2NodeCacheSize.isSet ;
++ }
++
++ @Override
++ public boolean isSetNode2NodeIdCacheSize() {
++ return Node2NodeIdCacheSize.isSet ;
++ }
++
++ @Override
++ public Integer getNodeId2NodeCacheSize() {
++ return NodeId2NodeCacheSize.value ;
++ }
++
++ @Override
++ public Integer getNodeMissCacheSize() {
++ return NodeMissCacheSize.value ;
++ }
++
++ @Override
++ public boolean isSetNodeMissCacheSize() {
++ return NodeMissCacheSize.isSet ;
++ }
++
++ public String getNodeTableBaseName() {
++ return nodeTableBaseName.value ;
++ }
++
++ public boolean isSetNodeTableBaseName() {
++ return nodeTableBaseName.isSet ;
++ }
++
++ public String getPrimaryIndexTriples() {
++ return primaryIndexTriples.value ;
++ }
++
++ public String[] getTripleIndexes() {
++ return tripleIndexes.value ;
++ }
++
++ public String getPrimaryIndexQuads() {
++ return primaryIndexQuads.value ;
++ }
++
++ public String[] getQuadIndexes() {
++ return quadIndexes.value ;
++ }
++
++ public String getPrefixTableBaseName() {
++ return prefixTableBaseName.value ;
++ }
++
++ public boolean isSetPrefixBaseName() {
++ return prefixTableBaseName.isSet ;
++ }
++
++
++
++ public String getPrimaryIndexPrefix() {
++ return primaryIndexPrefix.value ;
++ }
++
++ public String[] getPrefixIndexes() {
++ return prefixIndexes.value ;
++ }
++
++ @Override
++ public String toString() {
++ StringBuilder buff = new StringBuilder() ;
++ fmt(buff, "fileMode", getFileMode().toString(), fileMode.isSet) ;
++ fmt(buff, "blockSize", getBlockSize(), blockSize.isSet) ;
++ fmt(buff, "readCacheSize", getBlockReadCacheSize(), blockReadCacheSize.isSet) ;
++ fmt(buff, "writeCacheSize", getBlockWriteCacheSize(), blockWriteCacheSize.isSet) ;
++ fmt(buff, "Node2NodeIdCacheSize", getNode2NodeIdCacheSize(), Node2NodeIdCacheSize.isSet) ;
++ fmt(buff, "NodeId2NodeCacheSize", getNodeId2NodeCacheSize(), NodeId2NodeCacheSize.isSet) ;
++ fmt(buff, "NodeMissCacheSize", getNodeMissCacheSize(), NodeMissCacheSize.isSet) ;
++
++ fmt(buff, "nodeTableBaseName", getNodeTableBaseName(), nodeTableBaseName.isSet) ;
++ fmt(buff, "primaryIndexTriples", getPrimaryIndexTriples(), primaryIndexTriples.isSet) ;
++ fmt(buff, "tripleIndexes", getTripleIndexes(), tripleIndexes.isSet) ;
++ fmt(buff, "primaryIndexQuads", getPrimaryIndexQuads(), primaryIndexQuads.isSet) ;
++ fmt(buff, "quadIndexes", getQuadIndexes(), quadIndexes.isSet) ;
++
++ fmt(buff, "prefixTableBaseName", getPrefixTableBaseName(), prefixTableBaseName.isSet) ;
++ fmt(buff, "primaryIndexPrefix", getPrimaryIndexPrefix(), primaryIndexPrefix.isSet) ;
++ fmt(buff, "prefixIndexes", getPrefixIndexes(), prefixIndexes.isSet) ;
++
++ return buff.toString() ;
++ }
++
++ private void fmt(StringBuilder buff, String name, String[] strings, boolean isSet) {
++ String dftStr = "" ;
++ if ( ! isSet )
++ dftStr = "dft:" ;
++ buff.append(String.format("%-20s %s[%s]\n", name, dftStr, String.join(", ", strings))) ;
++ }
++
++ private void fmt(StringBuilder buff, String name, String value, boolean isSet) {
++ String dftStr = "" ;
++ if ( ! isSet )
++ dftStr = "dft:" ;
++ buff.append(String.format("%-20s %s%s\n", name, dftStr, value)) ;
++ }
++
++ private void fmt(StringBuilder buff, String name, int value, boolean isSet) {
++ String dftStr = "" ;
++ if ( ! isSet )
++ dftStr = "dft:" ;
++ buff.append(String.format("%-20s %s%s\n", name, dftStr, value)) ;
++ }
++
++ /** Equality but ignore "isSet" */
++ public static boolean sameValues(StoreParams params1, StoreParams params2) {
++ if ( params1 == null && params2 == null )
++ return true ;
++ if ( params1 == null )
++ return false ;
++ if ( params2 == null )
++ return false ;
++ if ( !sameValues(params1.fileMode, params2.fileMode) )
++ return false ;
++ if ( !sameValues(params1.blockSize, params2.blockSize) )
++ return false ;
++ if ( !sameValues(params1.blockReadCacheSize, params2.blockReadCacheSize) )
++ return false ;
++ if ( !sameValues(params1.blockWriteCacheSize, params2.blockWriteCacheSize) )
++ return false ;
++ if ( !sameValues(params1.Node2NodeIdCacheSize, params2.Node2NodeIdCacheSize) )
++ return false ;
++ if ( !sameValues(params1.NodeId2NodeCacheSize, params2.NodeId2NodeCacheSize) )
++ return false ;
++ if ( !sameValues(params1.NodeMissCacheSize, params2.NodeMissCacheSize) )
++ return false ;
++ if ( !sameValues(params1.nodeTableBaseName, params2.nodeTableBaseName) )
++ return false ;
++ if ( !sameValues(params1.primaryIndexTriples, params2.primaryIndexTriples) )
++ return false ;
++ if ( !sameValues(params1.tripleIndexes, params2.tripleIndexes) )
++ return false ;
++ if ( !sameValues(params1.primaryIndexQuads, params2.primaryIndexQuads) )
++ return false ;
++ if ( !sameValues(params1.quadIndexes, params2.quadIndexes) )
++ return false ;
++ if ( !sameValues(params1.prefixTableBaseName, params2.prefixTableBaseName) )
++ return false ;
++ if ( !sameValues(params1.primaryIndexPrefix, params2.primaryIndexPrefix) )
++ return false ;
++ if ( !sameValues(params1.prefixIndexes, params2.prefixIndexes) )
++ return false ;
++ return true ;
++ }
++
++ private static <X> boolean sameValues(Item<X> item1, Item<X> item2) {
++ return Objects.deepEquals(item1.value, item2.value) ;
++ }
++
++ @Override
++ public int hashCode() {
++ final int prime = 31 ;
++ int result = 1 ;
++ result = prime * result + ((Node2NodeIdCacheSize == null) ? 0 : Node2NodeIdCacheSize.hashCode()) ;
++ result = prime * result + ((NodeId2NodeCacheSize == null) ? 0 : NodeId2NodeCacheSize.hashCode()) ;
++ result = prime * result + ((NodeMissCacheSize == null) ? 0 : NodeMissCacheSize.hashCode()) ;
++ result = prime * result + ((blockReadCacheSize == null) ? 0 : blockReadCacheSize.hashCode()) ;
++ result = prime * result + ((blockSize == null) ? 0 : blockSize.hashCode()) ;
++ result = prime * result + ((blockWriteCacheSize == null) ? 0 : blockWriteCacheSize.hashCode()) ;
++ result = prime * result + ((fileMode == null) ? 0 : fileMode.hashCode()) ;
++ result = prime * result + ((nodeTableBaseName == null) ? 0 : nodeTableBaseName.hashCode()) ;
++ result = prime * result + ((prefixTableBaseName == null) ? 0 : prefixTableBaseName.hashCode()) ;
++ result = prime * result + ((prefixIndexes == null) ? 0 : prefixIndexes.hashCode()) ;
++ result = prime * result + ((primaryIndexPrefix == null) ? 0 : primaryIndexPrefix.hashCode()) ;
++ result = prime * result + ((primaryIndexQuads == null) ? 0 : primaryIndexQuads.hashCode()) ;
++ result = prime * result + ((primaryIndexTriples == null) ? 0 : primaryIndexTriples.hashCode()) ;
++ result = prime * result + ((quadIndexes == null) ? 0 : quadIndexes.hashCode()) ;
++ result = prime * result + ((tripleIndexes == null) ? 0 : tripleIndexes.hashCode()) ;
++ return result ;
++ }
++
++ @Override
++ public boolean equals(Object obj) {
++ if ( this == obj )
++ return true ;
++ if ( obj == null )
++ return false ;
++ if ( getClass() != obj.getClass() )
++ return false ;
++ StoreParams other = (StoreParams)obj ;
++ if ( Node2NodeIdCacheSize == null ) {
++ if ( other.Node2NodeIdCacheSize != null )
++ return false ;
++ } else if ( !Node2NodeIdCacheSize.equals(other.Node2NodeIdCacheSize) )
++ return false ;
++ if ( NodeId2NodeCacheSize == null ) {
++ if ( other.NodeId2NodeCacheSize != null )
++ return false ;
++ } else if ( !NodeId2NodeCacheSize.equals(other.NodeId2NodeCacheSize) )
++ return false ;
++ if ( NodeMissCacheSize == null ) {
++ if ( other.NodeMissCacheSize != null )
++ return false ;
++ } else if ( !NodeMissCacheSize.equals(other.NodeMissCacheSize) )
++ return false ;
++ if ( blockReadCacheSize == null ) {
++ if ( other.blockReadCacheSize != null )
++ return false ;
++ } else if ( !blockReadCacheSize.equals(other.blockReadCacheSize) )
++ return false ;
++ if ( blockSize == null ) {
++ if ( other.blockSize != null )
++ return false ;
++ } else if ( !blockSize.equals(other.blockSize) )
++ return false ;
++ if ( blockWriteCacheSize == null ) {
++ if ( other.blockWriteCacheSize != null )
++ return false ;
++ } else if ( !blockWriteCacheSize.equals(other.blockWriteCacheSize) )
++ return false ;
++ if ( fileMode == null ) {
++ if ( other.fileMode != null )
++ return false ;
++ } else if ( !fileMode.equals(other.fileMode) )
++ return false ;
++ if ( nodeTableBaseName == null ) {
++ if ( other.nodeTableBaseName != null )
++ return false ;
++ } else if ( !nodeTableBaseName.equals(other.nodeTableBaseName) )
++ return false ;
++ if ( prefixTableBaseName == null ) {
++ if ( other.prefixTableBaseName != null )
++ return false ;
++ } else if ( !prefixTableBaseName.equals(other.prefixTableBaseName) )
++ return false ;
++ if ( prefixIndexes == null ) {
++ if ( other.prefixIndexes != null )
++ return false ;
++ } else if ( !prefixIndexes.equals(other.prefixIndexes) )
++ return false ;
++ if ( primaryIndexPrefix == null ) {
++ if ( other.primaryIndexPrefix != null )
++ return false ;
++ } else if ( !primaryIndexPrefix.equals(other.primaryIndexPrefix) )
++ return false ;
++ if ( primaryIndexQuads == null ) {
++ if ( other.primaryIndexQuads != null )
++ return false ;
++ } else if ( !primaryIndexQuads.equals(other.primaryIndexQuads) )
++ return false ;
++ if ( primaryIndexTriples == null ) {
++ if ( other.primaryIndexTriples != null )
++ return false ;
++ } else if ( !primaryIndexTriples.equals(other.primaryIndexTriples) )
++ return false ;
++ if ( quadIndexes == null ) {
++ if ( other.quadIndexes != null )
++ return false ;
++ } else if ( !quadIndexes.equals(other.quadIndexes) )
++ return false ;
++ if ( tripleIndexes == null ) {
++ if ( other.tripleIndexes != null )
++ return false ;
++ } else if ( !tripleIndexes.equals(other.tripleIndexes) )
++ return false ;
++ return true ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParamsBuilder.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParamsBuilder.java
index 0000000,0000000..3fb2f36
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParamsBuilder.java
@@@ -1,0 -1,0 +1,308 @@@
++/*
++ * 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.setup;
++
++import org.seaborne.dboe.base.block.FileMode ;
++
++public class StoreParamsBuilder {
++ // Immutable.
++ static class Item<X> {
++ final X value ;
++ final boolean isSet ;
++
++ Item(X value, boolean isSet) {
++ this.value = value ;
++ this.isSet = isSet ;
++ }
++ @Override
++ public int hashCode() {
++ final int prime = 31 ;
++ int result = 1 ;
++ result = prime * result + (isSet ? 1231 : 1237) ;
++ result = prime * result + ((value == null) ? 0 : value.hashCode()) ;
++ return result ;
++ }
++ @Override
++ public boolean equals(Object obj) {
++ if ( this == obj )
++ return true ;
++ if ( obj == null )
++ return false ;
++ if ( getClass() != obj.getClass() )
++ return false ;
++ Item<?> other = (Item<?>)obj ;
++ if ( isSet != other.isSet )
++ return false ;
++ if ( value == null ) {
++ if ( other.value != null )
++ return false ;
++ } else if ( !value.equals(other.value) )
++ return false ;
++ return true ;
++ }
++ }
++
++ // See also StoreParamsConst.
++ /** Database and query configuration */
++ // Key names are the base name - encode/decode may add a prefix.
++
++ private Item<FileMode> fileMode = new Item<>(StoreParamsConst.fileMode, false) ;
++
++ private Item<Integer> blockReadCacheSize = new Item<>(StoreParamsConst.blockReadCacheSize, false) ;
++
++ private Item<Integer> blockWriteCacheSize = new Item<>(StoreParamsConst.blockWriteCacheSize, false) ;
++
++ private Item<Integer> Node2NodeIdCacheSize = new Item<>(StoreParamsConst.Node2NodeIdCacheSize, false) ;
++
++ private Item<Integer> NodeId2NodeCacheSize = new Item<>(StoreParamsConst.NodeId2NodeCacheSize, false) ;
++
++ private Item<Integer> NodeMissCacheSize = new Item<>(StoreParamsConst.NodeMissCacheSize, false) ;
++
++ /** Database layout - ignored after a database is created */
++
++ private Item<Integer> blockSize = new Item<>(StoreParamsConst.blockSize, false) ;
++
++ private Item<String> nodeTableBaseName = new Item<>(StoreParamsConst.nodeTableBaseName, false) ;
++
++ private Item<String> primaryIndexTriples = new Item<>(StoreParamsConst.primaryIndexTriples, false) ;
++
++ private Item<String[]> tripleIndexes = new Item<>(StoreParamsConst.tripleIndexes, false) ;
++
++ private Item<String> primaryIndexQuads = new Item<>(StoreParamsConst.primaryIndexQuads, false) ;
++
++ private Item<String[]> quadIndexes = new Item<>(StoreParamsConst.quadIndexes, false) ;
++
++ private Item<String> prefixTableBaseName = new Item<>(StoreParamsConst.prefixTableBaseName, false) ;
++
++ private Item<String> primaryIndexPrefix = new Item<>(StoreParamsConst.primaryIndexPrefix, false) ;
++
++ private Item<String[]> prefixIndexes = new Item<>(StoreParamsConst.prefixIndexes, false) ;
++
++ public static StoreParamsBuilder create() {
++ return new StoreParamsBuilder() ;
++ }
++
++ public static StoreParamsBuilder create(StoreParams params) {
++ return new StoreParamsBuilder(params) ;
++ }
++
++ /** Using a base set of {@link StoreParams}, and update with dynamic parameters.
++ *
++ * @param baseParams
++ * @param additionalParams
++ * @return StoreParams
++ */
++
++ public static StoreParams modify(StoreParams baseParams, StoreParamsDynamic additionalParams) {
++ StoreParamsBuilder b = new StoreParamsBuilder(baseParams) ;
++ // Merge explicitly set params
++ if ( additionalParams.isSetFileMode() )
++ b.fileMode(additionalParams.getFileMode()) ;
++
++ if ( additionalParams.isSetBlockReadCacheSize() )
++ b.blockReadCacheSize(additionalParams.getBlockReadCacheSize()) ;
++
++ if ( additionalParams.isSetBlockWriteCacheSize() )
++ b.blockWriteCacheSize(additionalParams.getBlockWriteCacheSize()) ;
++
++ if ( additionalParams.isSetNode2NodeIdCacheSize() )
++ b.node2NodeIdCacheSize(additionalParams.getNode2NodeIdCacheSize()) ;
++
++ if ( additionalParams.isSetNodeId2NodeCacheSize() )
++ b.nodeId2NodeCacheSize(additionalParams.getNodeId2NodeCacheSize()) ;
++
++ if ( additionalParams.isSetNodeMissCacheSize() )
++ b.nodeMissCacheSize(additionalParams.getNodeMissCacheSize()) ;
++
++ return b.build();
++ }
++
++
++ private StoreParamsBuilder() {}
++
++ /** Initial with a StoreParams as default values */
++ private StoreParamsBuilder(StoreParams other) {
++ this.fileMode = other.fileMode ;
++ this.blockSize = other.blockSize ;
++ this.blockReadCacheSize = other.blockReadCacheSize ;
++ this.blockWriteCacheSize = other.blockWriteCacheSize ;
++ this.Node2NodeIdCacheSize = other.Node2NodeIdCacheSize ;
++ this.NodeId2NodeCacheSize = other.NodeId2NodeCacheSize ;
++ this.NodeMissCacheSize = other.NodeMissCacheSize ;
++
++ this.nodeTableBaseName = other.nodeTableBaseName ;
++
++ this.primaryIndexTriples = other.primaryIndexTriples ;
++ this.tripleIndexes = other.tripleIndexes ;
++
++ this.primaryIndexQuads = other.primaryIndexQuads ;
++ this.quadIndexes = other.quadIndexes ;
++
++ this.prefixTableBaseName = other.prefixTableBaseName ;
++ this.primaryIndexPrefix = other.primaryIndexPrefix ;
++ this.prefixIndexes = other.prefixIndexes ;
++ }
++
++ public StoreParams build() {
++ return new StoreParams(
++ fileMode, blockSize, blockReadCacheSize, blockWriteCacheSize,
++ Node2NodeIdCacheSize, NodeId2NodeCacheSize, NodeMissCacheSize,
++ nodeTableBaseName,
++ primaryIndexTriples, tripleIndexes,
++ primaryIndexQuads, quadIndexes,
++ prefixTableBaseName, primaryIndexPrefix,
++ prefixIndexes) ;
++ }
++
++ public FileMode getFileMode() {
++ return fileMode.value ;
++ }
++
++ public StoreParamsBuilder fileMode(FileMode fileMode) {
++ this.fileMode = new Item<>(fileMode, true) ;
++ return this ;
++ }
++
++ public int getBlockSize() {
++ return blockSize.value ;
++ }
++
++ public StoreParamsBuilder blockSize(int blockSize) {
++ this.blockSize = new Item<>(blockSize, true) ;
++ return this ;
++ }
++
++ public int getBlockReadCacheSize() {
++ return blockReadCacheSize.value ;
++ }
++
++ public StoreParamsBuilder blockReadCacheSize(int blockReadCacheSize) {
++ this.blockReadCacheSize = new Item<>(blockReadCacheSize, true) ;
++ return this ;
++ }
++
++ public int getBlockWriteCacheSize() {
++ return blockWriteCacheSize.value ;
++ }
++
++ public StoreParamsBuilder blockWriteCacheSize(int blockWriteCacheSize) {
++ this.blockWriteCacheSize = new Item<>(blockWriteCacheSize, true) ;
++ return this ;
++ }
++
++ public int getNode2NodeIdCacheSize() {
++ return Node2NodeIdCacheSize.value ;
++ }
++
++ public StoreParamsBuilder node2NodeIdCacheSize(int node2NodeIdCacheSize) {
++ Node2NodeIdCacheSize = new Item<>(node2NodeIdCacheSize, true) ;
++ return this ;
++ }
++
++ public int getNodeId2NodeCacheSize() {
++ return NodeId2NodeCacheSize.value ;
++ }
++
++ public StoreParamsBuilder nodeId2NodeCacheSize(int nodeId2NodeCacheSize) {
++ NodeId2NodeCacheSize = new Item<>(nodeId2NodeCacheSize, true) ;
++ return this ;
++ }
++
++ public int getNodeMissCacheSize() {
++ return NodeMissCacheSize.value ;
++ }
++
++ public StoreParamsBuilder nodeMissCacheSize(int nodeMissCacheSize) {
++ NodeMissCacheSize = new Item<>(nodeMissCacheSize, true) ;
++ return this ;
++ }
++
++ public String getNodeTableBaseName() {
++ return nodeTableBaseName.value ;
++ }
++
++ public StoreParamsBuilder nodeTableBaseName(String nodeTableBaseName) {
++ this.nodeTableBaseName = new Item<>(nodeTableBaseName, true);
++ return this ;
++ }
++
++ public String getPrimaryIndexTriples() {
++ return primaryIndexTriples.value ;
++ }
++
++ public StoreParamsBuilder primaryIndexTriples(String primaryIndexTriples) {
++ this.primaryIndexTriples = new Item<>(primaryIndexTriples, true) ;
++ return this ;
++ }
++
++ public String[] getTripleIndexes() {
++ return tripleIndexes.value ;
++ }
++
++ public StoreParamsBuilder tripleIndexes(String[] tripleIndexes) {
++ this.tripleIndexes = new Item<>(tripleIndexes, true) ;
++ return this ;
++ }
++
++ public String getPrimaryIndexQuads() {
++ return primaryIndexQuads.value ;
++ }
++
++ public StoreParamsBuilder primaryIndexQuads(String primaryIndexQuads) {
++ this.primaryIndexQuads = new Item<>(primaryIndexQuads, true) ;
++ return this ;
++ }
++
++ public String[] getQuadIndexes() {
++ return quadIndexes.value ;
++ }
++
++ public StoreParamsBuilder quadIndexes(String[] quadIndexes) {
++ this.quadIndexes = new Item<>(quadIndexes, true) ;
++ return this ;
++ }
++
++
++ public String getPreifixTableBaseName() {
++ return prefixTableBaseName.value ;
++ }
++
++ public StoreParamsBuilder prefixTableBaseName(String prefixTableBaseName) {
++ this.prefixTableBaseName = new Item<>(prefixTableBaseName, true) ;
++ return this ;
++ }
++
++ public String getPrimaryIndexPrefix() {
++ return primaryIndexPrefix.value ;
++ }
++
++ public StoreParamsBuilder primaryIndexPrefix(String primaryIndexPrefix) {
++ this.primaryIndexPrefix = new Item<>(primaryIndexPrefix, true) ;
++ return this ;
++ }
++
++ public String[] getPrefixIndexes() {
++ return prefixIndexes.value ;
++ }
++
++ public StoreParamsBuilder prefixIndexes(String[] prefixIndexes) {
++ this.prefixIndexes = new Item<>(prefixIndexes, true) ;
++ return this ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParamsCodec.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParamsCodec.java
index 0000000,0000000..87653f9
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/main/java/org/seaborne/tdb2/setup/StoreParamsCodec.java
@@@ -1,0 -1,0 +1,189 @@@
++/*
++ * 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.setup;
++
++import static org.seaborne.tdb2.setup.StoreParamsConst.* ;
++
++import java.io.BufferedOutputStream ;
++import java.io.FileOutputStream ;
++import java.io.IOException ;
++import java.io.OutputStream ;
++
++import org.apache.jena.atlas.AtlasException ;
++import org.apache.jena.atlas.io.IO ;
++import org.apache.jena.atlas.json.* ;
++import org.apache.jena.atlas.lib.Lib ;
++import org.seaborne.dboe.base.block.FileMode ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.sys.Names;
++import org.seaborne.tdb2.TDBException ;
++
++/** Encode and decode {@link StoreParams} */
++public class StoreParamsCodec {
++
++ /** Write to a file */
++ public static void write(Location location, StoreParams params) {
++ write(location.getPath(Names.TDB_CONFIG_FILE) ,params) ;
++ }
++
++ /** Write to a file */
++ public static void write(String filename, StoreParams params) {
++ try (OutputStream out = new FileOutputStream(filename);
++ OutputStream out2 = new BufferedOutputStream(out); ) {
++ JsonObject object = encodeToJson(params) ;
++ JSON.write(out2, object) ;
++ out2.write('\n') ;
++ }
++ catch (IOException ex) { IO.exception(ex); }
++ }
++
++ /** Read from a file */
++ public static StoreParams read(Location location) {
++ return read(location.getPath(Names.TDB_CONFIG_FILE)) ;
++ }
++
++ /** Read from a file, if possible. */
++ public static StoreParams read(String filename) {
++ try {
++ JsonObject obj = JSON.read(filename) ;
++ return StoreParamsCodec.decode(obj) ;
++ }
++ catch (JsonParseException ex) { return null ; }
++ catch (AtlasException ex) { return null ; }
++ }
++
++ public static JsonObject encodeToJson(StoreParams params) {
++ JsonBuilder builder = new JsonBuilder() ;
++ builder.startObject("StoreParams") ; // "StoreParams" is an internal alignment marker - not in the JSON.
++
++ encode(builder, key(fFileMode), params.getFileMode().name()) ;
++ encode(builder, key(fBlockSize), params.getBlockSize()) ;
++ encode(builder, key(fBlockReadCacheSize), params.getBlockReadCacheSize()) ;
++ encode(builder, key(fBlockWriteCacheSize), params.getBlockWriteCacheSize()) ;
++ encode(builder, key(fNode2NodeIdCacheSize), params.getNode2NodeIdCacheSize()) ;
++ encode(builder, key(fNodeId2NodeCacheSize), params.getNodeId2NodeCacheSize()) ;
++ encode(builder, key(fNodeMissCacheSize), params.getNodeMissCacheSize()) ;
++ encode(builder, key(fNodeTableBaseName), params.getNodeTableBaseName()) ;
++ encode(builder, key(fPrimaryIndexTriples), params.getPrimaryIndexTriples()) ;
++ encode(builder, key(fTripleIndexes), params.getTripleIndexes()) ;
++ encode(builder, key(fPrimaryIndexQuads), params.getPrimaryIndexQuads()) ;
++ encode(builder, key(fQuadIndexes), params.getQuadIndexes()) ;
++ encode(builder, key(fPrefixTableBaseName), params.getPrefixTableBaseName()) ;
++ encode(builder, key(fPrimaryIndexPrefix), params.getPrimaryIndexPrefix()) ;
++ encode(builder, key(fPrefixIndexes), params.getPrefixIndexes()) ;
++
++ builder.finishObject("StoreParams") ;
++ return (JsonObject)builder.build() ;
++ }
++
++ private static final String jsonKeyPrefix= "tdb." ;
++
++ private static String key(String string) {
++ if ( string.startsWith(jsonKeyPrefix))
++ throw new TDBException("Key name already starts with '"+jsonKeyPrefix+"'") ;
++ return jsonKeyPrefix+string ;
++ }
++
++ private static String unkey(String string) {
++ if ( ! string.startsWith(jsonKeyPrefix) )
++ throw new TDBException("JSON key name does not start with '"+jsonKeyPrefix+"'") ;
++ return string.substring(jsonKeyPrefix.length()) ;
++ }
++
++ public static StoreParams decode(JsonObject json) {
++ StoreParamsBuilder builder = StoreParams.builder() ;
++
++ for ( String key : json.keys() ) {
++ String short_key = unkey(key) ;
++ switch(short_key) {
++ case fFileMode : builder.fileMode(FileMode.valueOf(getString(json, key))) ; break ;
++ case fBlockSize: builder.blockSize(getInt(json, key)) ; break ;
++ case fBlockReadCacheSize: builder.blockReadCacheSize(getInt(json, key)) ; break ;
++ case fBlockWriteCacheSize: builder.blockWriteCacheSize(getInt(json, key)) ; break ;
++ case fNode2NodeIdCacheSize: builder.node2NodeIdCacheSize(getInt(json, key)) ; break ;
++ case fNodeId2NodeCacheSize: builder.nodeId2NodeCacheSize(getInt(json, key)) ; break ;
++ case fNodeMissCacheSize: builder.nodeMissCacheSize(getInt(json, key)) ; break ;
++
++ case fNodeTableBaseName: builder.nodeTableBaseName(getString(json, key)) ; break ;
++ case fPrimaryIndexTriples: builder.primaryIndexTriples(getString(json, key)) ; break ;
++ case fTripleIndexes: builder.tripleIndexes(getStringArray(json, key)) ; break ;
++ case fPrimaryIndexQuads: builder.primaryIndexQuads(getString(json, key)) ; break ;
++ case fQuadIndexes: builder.quadIndexes(getStringArray(json, key)) ; break ;
++
++ case fPrefixTableBaseName: builder.prefixTableBaseName(getString(json, key)) ; break ;
++ case fPrimaryIndexPrefix: builder.primaryIndexPrefix(getString(json, key)) ; break ;
++ case fPrefixIndexes: builder.prefixIndexes(getStringArray(json, key)) ; break ;
++
++ default:
++ throw new TDBException("StoreParams key no recognized: "+key) ;
++ }
++ }
++ return builder.build() ;
++ }
++
++ // "Get or error" operations.
++
++ private static String getString(JsonObject json, String key) {
++ if ( ! json.hasKey(key) )
++ throw new TDBException("StoreParamsCodec.getString: no such key: "+key) ;
++ String x = json.get(key).getAsString().value() ;
++ return x ;
++ }
++
++ private static Integer getInt(JsonObject json, String key) {
++ if ( ! json.hasKey(key) )
++ throw new TDBException("StoreParamsCodec.getInt: no such key: "+key) ;
++ Integer x = json.get(key).getAsNumber().value().intValue() ;
++ return x ;
++ }
++
++ private static String[] getStringArray(JsonObject json, String key) {
++ if ( ! json.hasKey(key) )
++ throw new TDBException("StoreParamsCodec.getStringArray: no such key: "+key) ;
++ JsonArray a = json.get(key).getAsArray() ;
++ String[] x = new String[a.size()] ;
++ for ( int i = 0 ; i < a.size() ; i++ ) {
++ x[i] = a.get(i).getAsString().value() ;
++ }
++ return x ;
++ }
++
++ // Encode helper.
++ private static void encode(JsonBuilder builder, String name, Object value) {
++ if ( value instanceof Number ) {
++ long x = ((Number)value).longValue() ;
++ builder.key(name).value(x) ;
++ return ;
++ }
++ if ( value instanceof String ) {
++ builder.key(name).value(value.toString()) ;
++ return ;
++ }
++ if ( value instanceof String[] ) {
++ String[] x = (String[])value ;
++ builder.key(name) ;
++ builder.startArray() ;
++ for ( String s : x ) {
++ builder.value(s) ;
++ }
++ builder.finishArray() ;
++ return ;
++ }
++ throw new TDBException("Class of value not recognized: "+Lib.classShortName(value.getClass())) ;
++ }
++}
[21/50] [abbrv] jena git commit: Remove ObjectFile (unused).
Posted by an...@apache.org.
Remove ObjectFile (unused).
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/67b69b5e
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/67b69b5e
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/67b69b5e
Branch: refs/heads/jena-tdb2
Commit: 67b69b5e2258da02451be2064e5980647908d709
Parents: 9b987b0
Author: Andy Seaborne <an...@seaborne.org>
Authored: Wed Sep 13 14:48:24 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Wed Sep 13 14:48:24 2017 +0100
----------------------------------------------------------------------
.../seaborne/dboe/base/file/BinaryDataFile.java | 14 +-
.../seaborne/dboe/base/file/FileFactory.java | 25 -
.../dboe/base/objectfile/ObjectFile.java | 95 ----
.../dboe/base/objectfile/ObjectFileBuilder.java | 24 -
.../dboe/base/objectfile/ObjectFileLogger.java | 143 ------
.../dboe/base/objectfile/ObjectFileStorage.java | 476 -------------------
.../base/objectfile/ObjectFileSwitcher.java | 45 --
.../dboe/base/objectfile/ObjectFileWrapper.java | 78 ---
.../dboe/base/objectfile/StringFile.java | 145 ------
.../test/java/org/seaborne/dboe/TC_DBOE_IO.java | 4 +-
.../java/org/seaborne/dboe/base/TC_Base.java | 41 --
.../base/objectfile/AbstractTestObjectFile.java | 140 ------
.../base/objectfile/AbstractTestStringFile.java | 145 ------
.../dboe/base/objectfile/TS_ObjectFile.java | 33 --
.../objectfile/TestObjectFileBuffering.java | 101 ----
.../base/objectfile/TestObjectFileDisk.java | 49 --
.../dboe/base/objectfile/TestObjectFileMem.java | 39 --
.../base/objectfile/TestStringFileDisk.java | 48 --
.../dboe/base/objectfile/TestStringFileMem.java | 40 --
.../dboe/trans/data/TransBinaryDataFile.java | 3 +-
.../dboe/trans/data/TransObjectFile.java | 276 -----------
.../seaborne/dboe/trans/data/TS_TransData.java | 3 +-
.../dboe/trans/data/TestTransObjectFile.java | 133 ------
23 files changed, 8 insertions(+), 2092 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFile.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFile.java b/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFile.java
index f840fb9..3d9772c 100644
--- a/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFile.java
+++ b/dboe-base/src/main/java/org/seaborne/dboe/base/file/BinaryDataFile.java
@@ -21,16 +21,11 @@ import java.io.RandomAccessFile ;
import org.apache.jena.atlas.lib.Closeable ;
import org.apache.jena.atlas.lib.Sync ;
-import org.seaborne.dboe.base.objectfile.ObjectFile ;
-/** An append-only, read anywhere, binary file.
- *
+/** An append-only, read-anywhere, binary file.
+ * A {@code BinaryDataFile} does not record the length and assumes the
+ * entries are self-defining.
*
- * An {@link ObjectFile} is a series of length+binary records.
- * A {@link BinaryDataFile} does not record the length and assumes the
- * entires are self-defining.
- *
- * @see ObjectFile
* @see RandomAccessFile
*/
public interface BinaryDataFile extends Closeable, Sync {
@@ -39,11 +34,10 @@ public interface BinaryDataFile extends Closeable, Sync {
//
// The choice seems to come down to ByteBuffers vs byte[]
// which in turn is a small/large data (scattered data)
- // issue. We are currently expecting small I/O so byte[]
+ // issue. We are currently expecting small(er) I/O so byte[]
// and being like Thrift is better.
// byte[] vs ByteBuffer
- // Merge with BufferChannel?
/** Open the file */
public void open() ;
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/main/java/org/seaborne/dboe/base/file/FileFactory.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/main/java/org/seaborne/dboe/base/file/FileFactory.java b/dboe-base/src/main/java/org/seaborne/dboe/base/file/FileFactory.java
index 390ba3b..ebdc1e4 100644
--- a/dboe-base/src/main/java/org/seaborne/dboe/base/file/FileFactory.java
+++ b/dboe-base/src/main/java/org/seaborne/dboe/base/file/FileFactory.java
@@ -17,10 +17,6 @@
package org.seaborne.dboe.base.file ;
-import org.seaborne.dboe.base.objectfile.ObjectFile ;
-import org.seaborne.dboe.base.objectfile.ObjectFileStorage ;
-import org.seaborne.dboe.base.objectfile.StringFile ;
-
public class FileFactory {
public static BinaryDataFile createBinaryDataFile(FileSet fileset, String ext) {
@@ -38,27 +34,6 @@ public class FileFactory {
return new BinaryDataFileMem() ;
}
- // TODO More use of fileset.
- // Prune use elsewhere e.g BlockMgrFactory.
-
- public static StringFile createStringFileDisk(String filename) {
- return new StringFile(createObjectFileDisk(filename)) ;
- }
-
- public static StringFile createStringFileMem(String filename) {
- return new StringFile(createObjectFileMem(filename)) ;
- }
-
- public static ObjectFile createObjectFileDisk(String filename) {
- BufferChannel file = BufferChannelFile.create(filename) ;
- return new ObjectFileStorage(file) ;
- }
-
- public static ObjectFile createObjectFileMem(String filename) {
- BufferChannel file = BufferChannelMem.create(filename) ;
- return new ObjectFileStorage(file) ;
- }
-
public static BufferChannel createBufferChannel(FileSet fileset, String ext) {
String x = fileset.filename(ext) ;
if ( fileset.isMem() )
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFile.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFile.java b/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFile.java
deleted file mode 100644
index a210d55..0000000
--- a/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFile.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.dboe.base.objectfile;
-
-import java.nio.ByteBuffer ;
-import java.util.Iterator ;
-
-import org.apache.jena.atlas.lib.Closeable ;
-import org.apache.jena.atlas.lib.Pair ;
-import org.apache.jena.atlas.lib.Sync ;
-import org.seaborne.dboe.base.block.Block ;
-
-/**
- * An ObjectFile is an append-read file, that is you can append data
- * to the stream or read any block.
- */
-
-public interface ObjectFile extends Sync, Closeable
-{
- public static final String type = "object" ;
-
- /** A label to identify this ObjectFile */
- public String getLabel() ;
-
- /** Allocate space for a write - pass this buffer to completeWrite .
- * The data to be written can be smaller than that requested but
- * the data must be in position 0 -> limit.
- */
- public Block allocWrite(int bytesSpace) ;
-
- /** Announce that a write is complete (buffer must come from allocWrite)
- */
- public void completeWrite(Block buffer) ;
-
- /** Decide not to perform the write */
- public void abortWrite(Block buffer) ;
-
- /** Write out the buffer - return the accessor number */
- public long write(ByteBuffer buffer) ;
-
- /** Read a buffer at the accessor number. */
- public ByteBuffer read(long id) ;
-
- /** Length, in bytes
- * @see #truncate
- */
- public long length() ;
-
- /** The append point. The length, in units used by read/write for ids.
- * @see #reposition
- */
- public long position() ;
-
- /** Any objects in this file? */
- public boolean isEmpty() ;
-
- /** Reset the "append" point; may only be moved earlier.
- * All data after the new point is lost.
- * The new position must correspond to a position returned by
- * {@link #write(ByteBuffer)} or an id in a {@link Block Block} from {@link #completeWrite(Block)}
- * <p>
- * {@link #truncate} is in bytes;
- * {@link #reposition} is in units returned {@link #write}
- * @see #position
- */
- public void reposition(long id) ;
-
- /** Truncate the file.
- * The new file point should correspond to a position used by {@link #write}, otherwise the
- * data written from the last valid position to this point is corrupted.
- * <p>
- * {@link #truncate} is in bytes;
- * {@link #reposition} is in units returned {@link #write}
- * @see #length
- */
- public void truncate(long size) ;
-
- /** All the bytebuffers - debugging aid */
- public Iterator<Pair<Long, ByteBuffer>> all() ;
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileBuilder.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileBuilder.java b/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileBuilder.java
deleted file mode 100644
index c8082af..0000000
--- a/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileBuilder.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.dboe.base.objectfile;
-
-import org.seaborne.dboe.base.file.FileSet ;
-
-public interface ObjectFileBuilder {
- ObjectFile buildObjectFile(FileSet fileSet, String ext) ;
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileLogger.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileLogger.java b/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileLogger.java
deleted file mode 100644
index 25d5316..0000000
--- a/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileLogger.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * 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.dboe.base.objectfile;
-
-import java.nio.ByteBuffer ;
-import java.util.Iterator ;
-
-import org.apache.jena.atlas.lib.Pair ;
-import org.seaborne.dboe.base.block.Block ;
-import org.slf4j.Logger ;
-import org.slf4j.LoggerFactory ;
-
-public class ObjectFileLogger implements ObjectFile
-{
- protected final ObjectFile other ;
- private static Logger defaultLogger = LoggerFactory.getLogger(ObjectFile.class) ;
- private final Logger log ;
- private final String label ;
-
- public ObjectFileLogger(String label, ObjectFile other)
- {
- this.other = other ;
- this.label = label ;
- log = defaultLogger ;
- }
-
- @Override
- public Block allocWrite(int maxBytes)
- {
- Block blk = other.allocWrite(maxBytes) ;
- info("allocWrite("+maxBytes+") -> "+blk.getId()) ;
- return blk ;
- }
-
- @Override
- public void completeWrite(Block buffer)
- {
- info("completeWrite("+buffer.getId()+")") ;
- other.completeWrite(buffer) ;
- }
-
- @Override
- public void abortWrite(Block buffer)
- {
- info("abortWrite("+buffer.getId()+")") ;
- other.abortWrite(buffer) ;
- }
-
- @Override
- public long write(ByteBuffer buffer)
- {
- info("write"+buffer) ;
- return other.write(buffer) ;
- }
-
- @Override
- public void reposition(long id)
- {
- info("reposition("+id+")") ;
- other.reposition(id) ;
- }
-
- @Override
- public ByteBuffer read(long id)
- {
- info("read("+id+")") ;
- return other.read(id) ;
- }
-
- @Override
- public Iterator<Pair<Long, ByteBuffer>> all()
- {
- info("all()") ;
- return other.all() ;
- }
-
- @Override
- public void truncate(long size)
- {
- info("truncate("+size+")") ;
- other.truncate(size) ;
- }
-
- @Override
- public void sync()
- {
- info("sync") ;
- other.sync() ;
- }
-
- @Override
- public void close()
- {
- info("close") ;
- other.close() ;
- }
-
- @Override
- public String getLabel()
- {
- return other.getLabel() ;
- }
-
- @Override
- public long length()
- {
- return position() ;
- }
-
- @Override
- public long position()
- {
- return other.position() ;
- }
-
- @Override
- public boolean isEmpty()
- {
- return other.isEmpty() ;
- }
-
- private void info(String string)
- {
- if ( label != null )
- string = label+": "+string ;
- log.info(string) ;
- }
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileStorage.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileStorage.java b/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileStorage.java
deleted file mode 100644
index fc34c22..0000000
--- a/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileStorage.java
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
- * 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.dboe.base.objectfile;
-
-import static org.seaborne.dboe.sys.Sys.SizeOfInt ;
-
-import java.nio.ByteBuffer ;
-import java.util.Iterator ;
-
-import org.apache.jena.atlas.iterator.Iter ;
-import org.apache.jena.atlas.iterator.IteratorSlotted ;
-import org.apache.jena.atlas.lib.Pair ;
-import org.apache.jena.atlas.logging.Log ;
-import org.seaborne.dboe.base.block.Block ;
-import org.seaborne.dboe.base.file.BufferChannel ;
-import org.seaborne.dboe.base.file.FileException ;
-import org.seaborne.dboe.sys.Sys ;
-import org.seaborne.dboe.sys.SystemFile ;
-import org.slf4j.Logger ;
-import org.slf4j.LoggerFactory ;
-
-/** Variable length ByteBuffer file on disk.
- * Buffering for delayed writes.
- */
-
-public class ObjectFileStorage implements ObjectFile
-{
- private static Logger log = LoggerFactory.getLogger(ObjectFileStorage.class) ;
- public static boolean logging = false ;
-
- private void log(String fmt, Object... args) {
- if ( !logging )
- return ;
- log.debug(state() + " " + String.format(fmt, args)) ;
- }
-
- /*
- * No synchronization - assumes that the caller has some appropriate lock
- * because the combination of file and cache operations needs to be thread safe.
- *
- * The position of the channel is assumed to be the end of the file always.
- * Read operations are done with absolute channel calls,
- * which do not reset the position.
- *
- * Writing is buffered.
- */
-
- // The object length slot.
- private ByteBuffer lengthBuffer = ByteBuffer.allocate(SizeOfInt) ;
-
- // Delayed write buffer.
- private final ByteBuffer writeBuffer ;
-
- private final BufferChannel file ;
- private long filesize ;
-
- // Two-step write - alloc, write
- private boolean inAllocWrite = false ;
- private Block allocBlock = null ;
- private long allocLocation = -1 ;
-
- // Old values for aborting a allocate-write
- int oldBufferPosn = -1 ;
- int oldBufferLimit = -1 ;
-
- public ObjectFileStorage(BufferChannel file) {
- this(file, SystemFile.ObjectFileWriteBufferSize) ;
- }
-
- public ObjectFileStorage(BufferChannel file, int bufferSize) {
- this.file = file ;
- filesize = file.size() ;
- this.file.position(filesize) ; // End of file.
- log("File size: 0x%X, posn: 0x%X", filesize, file.position()) ;
- writeBuffer = (bufferSize >= 0) ? ByteBuffer.allocate(bufferSize) : null ;
- }
-
- @Override
- public long write(ByteBuffer bb) {
- log("W") ;
-
- if ( inAllocWrite )
- Log.error(this, "In the middle of an alloc-write") ;
- inAllocWrite = false ;
- if ( writeBuffer == null ) {
- long x = rawWrite(bb) ;
- log("W -> 0x%X", x) ;
- return x ;
- }
-
- int len = bb.limit() - bb.position() ;
- int spaceNeeded = len + SizeOfInt ;
-
- if ( writeBuffer.position() + spaceNeeded > writeBuffer.capacity() )
- // No room - flush.
- flushOutputBuffer() ;
- if ( writeBuffer.position() + spaceNeeded > writeBuffer.capacity() ) {
- long x = rawWrite(bb) ;
- if ( logging )
- log("W -> 0x%X", x) ;
- return x ;
- }
-
- long loc = writeBuffer.position() + filesize ;
- writeBuffer.putInt(len) ;
- writeBuffer.put(bb) ;
- if ( logging )
- log("W -> 0x%X", loc) ;
- return loc ;
- }
-
- private long rawWrite(ByteBuffer bb) {
- if ( logging )
- log("RW %s", bb) ;
- int len = bb.limit() - bb.position() ;
- lengthBuffer.rewind() ;
- lengthBuffer.putInt(len) ;
- lengthBuffer.flip() ;
- long location = file.position() ;
- file.write(lengthBuffer) ;
- int x = file.write(bb) ;
- if ( x != len )
- throw new FileException() ;
- filesize = filesize + x + SizeOfInt ;
-
- if ( logging ) {
- log("Posn: %d", file.position()) ;
- log("RW ->0x%X", location) ;
- }
- return location ;
- }
-
- @Override
- public Block allocWrite(int bytesSpace) {
- // log.info("AW("+bytesSpace+"):"+state()) ;
- if ( inAllocWrite )
- Log.error(this, "In the middle of an alloc-write") ;
-
- // Include space for length.
- int spaceRequired = bytesSpace + SizeOfInt ;
-
- // Find space.
- if ( writeBuffer != null && spaceRequired > writeBuffer.remaining() )
- flushOutputBuffer() ;
-
- if ( writeBuffer == null || spaceRequired > writeBuffer.remaining() ) {
- // Too big. Have flushed buffering if buffering.
- inAllocWrite = true ;
- ByteBuffer bb = ByteBuffer.allocate(bytesSpace) ;
- allocBlock = new Block(filesize, bb) ;
- allocLocation = -1 ;
- // log.info("AW:"+state()+"-> ----") ;
- return allocBlock ;
- }
-
- // Will fit.
- inAllocWrite = true ;
- int start = writeBuffer.position() ;
- // Old values for restoration
- oldBufferPosn = start ;
- oldBufferLimit = writeBuffer.limit() ;
-
- // id (but don't tell the caller yet).
- allocLocation = filesize + start ;
-
- // Slice it.
- writeBuffer.putInt(bytesSpace) ;
- writeBuffer.position(start + SizeOfInt) ;
- writeBuffer.limit(start + spaceRequired) ;
- ByteBuffer bb = writeBuffer.slice() ;
-
- allocBlock = new Block(allocLocation, bb) ;
-
- if ( logging )
- log("AW: %s->0x%X", state(), allocLocation) ;
- return allocBlock ;
- }
-
- @Override
- public void completeWrite(Block block) {
- if ( logging )
- log("CW: %s @0x%X", block, allocLocation) ;
- if ( !inAllocWrite )
- throw new FileException("Not in the process of an allocated write operation pair") ;
- if ( allocBlock != null && (allocBlock.getByteBuffer() != block.getByteBuffer()) )
- throw new FileException("Wrong byte buffer in an allocated write operation pair") ;
-
- inAllocWrite = false ;
-
- ByteBuffer buffer = block.getByteBuffer() ;
-
- if ( allocLocation == -1 ) {
- // It was too big to use the buffering.
- rawWrite(buffer) ;
- return ;
- }
- // Write area is 0 -> limit
- if ( 0 != buffer.position() )
- log.warn("ObjectFleStorage: position != 0") ;
- buffer.position(0) ;
- int actualLength = buffer.limit() - buffer.position() ;
- // Insert object length
- int idx = (int)(allocLocation - filesize) ;
- writeBuffer.putInt(idx, actualLength) ;
- // And bytes to idx+actualLength+4 are used
- allocBlock = null ;
- int newLen = idx + actualLength + 4 ;
- writeBuffer.position(newLen) ;
- writeBuffer.limit(writeBuffer.capacity()) ;
- allocLocation = -1 ;
- oldBufferPosn = -1 ;
- oldBufferLimit = -1 ;
- }
-
- @Override
- public void abortWrite(Block block) {
- if ( ! inAllocWrite )
- return ;
- allocBlock = null ;
- int oldstart = (int)(allocLocation - filesize) ;
- if ( oldstart != oldBufferPosn )
- throw new FileException("Wrong reset point: calc=" + oldstart + " : expected=" + oldBufferPosn) ;
-
- writeBuffer.position(oldstart) ;
- writeBuffer.limit(oldBufferLimit) ;
- allocLocation = -1 ;
- oldBufferPosn = -1 ;
- oldBufferLimit = -1 ;
- inAllocWrite = false ;
- }
-
- private void flushOutputBuffer() {
- if ( logging )
- log("Flush") ;
-
- if ( writeBuffer == null )
- return ;
- if ( writeBuffer.position() == 0 )
- return ;
-
- if ( false ) {
- String x = getLabel() ;
- if ( x.contains("nodes") ) {
- long x1 = filesize ;
- long x2 = writeBuffer.position() ;
- long x3 = x1 + x2 ;
- System.out.printf("Flush(%s) : %d/0x%04X (%d/0x%04X) %d/0x%04X\n", getLabel(), x1, x1, x2, x2, x3, x3) ;
- }
- }
-
- long location = filesize ;
- writeBuffer.flip() ;
- int x = file.write(writeBuffer) ;
- filesize += x ;
- writeBuffer.clear() ;
- }
-
- @Override
- public void reposition(long posn) {
- if ( inAllocWrite )
- throw new FileException("In the middle of an alloc-write") ;
- if ( posn < 0 || posn > position() )
- throw new IllegalArgumentException("reposition: Bad location: " + posn) ;
- flushOutputBuffer() ;
- file.truncate(posn) ;
- filesize = posn ;
- }
-
- @Override
- public void truncate(long size) {
- // System.out.println("truncate: "+size+" ("+filesize+","+writeBuffer.position()+")")
- // ;
- reposition(size) ;
- }
-
- @Override
- public ByteBuffer read(long loc) {
- if ( logging )
- log("R(0x%X)", loc) ;
-
- if ( inAllocWrite )
- throw new FileException("In the middle of an alloc-write") ;
- if ( loc < 0 )
- throw new IllegalArgumentException("ObjectFile.read[" + file.getLabel() + "]: Bad read: " + loc) ;
-
- // Maybe it's in the in the write buffer.
- // Maybe the write buffer should keep more structure?
- if ( loc >= filesize ) {
- if ( loc >= filesize + writeBuffer.position() )
- throw new IllegalArgumentException("ObjectFileStorage.read[" + file.getLabel() + "]: Bad read: location=" + loc
- + " >= max=" + (filesize + writeBuffer.position())) ;
-
- int x = writeBuffer.position() ;
- int y = writeBuffer.limit() ;
-
- int offset = (int)(loc - filesize) ;
- int len = writeBuffer.getInt(offset) ;
- int posn = offset + SizeOfInt ;
- // Slice the data bytes,
- writeBuffer.position(posn) ;
- writeBuffer.limit(posn + len) ;
- ByteBuffer bb = writeBuffer.slice() ;
- writeBuffer.limit(y) ;
- writeBuffer.position(x) ;
- return bb ;
- }
-
- // No - it's in the underlying file storage.
- lengthBuffer.clear() ;
- int x = file.read(lengthBuffer, loc) ;
- if ( x != 4 )
- throw new FileException("ObjectFileStorage.read[" + file.getLabel() + "](" + loc + ")[filesize=" + filesize + "][file.size()="
- + file.size() + "]: Failed to read the length : got " + x + " bytes") ;
- int len = lengthBuffer.getInt(0) ;
- // Sanity check.
- if ( len > filesize - (loc + SizeOfInt) ) {
- String msg = "ObjectFileStorage.read[" + file.getLabel() + "](" + loc + ")[filesize=" + filesize + "][file.size()="
- + file.size() + "]: Impossibly large object : " + len + " bytes > filesize-(loc+SizeOfInt)="
- + (filesize - (loc + SizeOfInt)) ;
- Sys.errlog.error(msg) ;
- throw new FileException(msg) ;
- }
-
- ByteBuffer bb = ByteBuffer.allocate(len) ;
- if ( len == 0 )
- // Zero bytes.
- return bb ;
- x = file.read(bb, loc + SizeOfInt) ;
- bb.flip() ;
- if ( x != len )
- throw new FileException("ObjectFileStorage.read: Failed to read the object (" + len + " bytes) : got " + x + " bytes") ;
- return bb ;
- }
-
- @Override
- public long length() {
- return position() ;
- }
-
- @Override
- public long position() {
- if ( writeBuffer == null )
- return filesize ;
- return filesize + writeBuffer.position() ;
- }
-
- @Override
- public boolean isEmpty() {
- if ( writeBuffer == null )
- return filesize == 0 ;
- return writeBuffer.position() == 0 && filesize == 0 ;
- }
-
- @Override
- public void close() {
- flushOutputBuffer() ;
- file.close() ;
- }
-
- @Override
- public void sync() {
- flushOutputBuffer() ;
- file.sync() ;
- }
-
- @Override
- public String getLabel() {
- return file.getLabel() ;
- }
-
- @Override
- public String toString() {
- return file.getLabel() ;
- }
-
- @Override
- public Iterator<Pair<Long, ByteBuffer>> all() {
- flushOutputBuffer() ;
- // file.position(0) ;
- ObjectIterator iter = new ObjectIterator(0, filesize) ;
- // return iter ;
-
- if ( writeBuffer == null || writeBuffer.position() == 0 )
- return iter ;
- return Iter.concat(iter, new BufferIterator(writeBuffer)) ;
- }
-
- private String state() {
- if ( writeBuffer == null )
- return String.format(getLabel() + ": filesize=0x%X, file=(0x%X, 0x%X)", filesize, file.position(), file.size()) ;
- else
- return String.format(getLabel() + ": filesize=0x%X, file=(0x%X, 0x%X), writeBuffer=(0x%X,0x%X)", filesize, file.position(),
- file.size(), writeBuffer.position(), writeBuffer.limit()) ;
-
- }
-
- private class BufferIterator extends IteratorSlotted<Pair<Long, ByteBuffer>> implements Iterator<Pair<Long, ByteBuffer>> {
- private ByteBuffer buffer ;
- private int posn ;
-
- public BufferIterator(ByteBuffer buffer) {
- this.buffer = buffer ;
- this.posn = 0 ;
- }
-
- @Override
- protected Pair<Long, ByteBuffer> moveToNext() {
- if ( posn >= buffer.limit() )
- return null ;
-
- int x = buffer.getInt(posn) ;
- posn += Sys.SizeOfInt ;
- ByteBuffer bb = ByteBuffer.allocate(x) ;
- int p = buffer.position() ;
- buffer.position(posn) ;
- buffer.get(bb.array()) ;
- buffer.position(p) ;
- posn += x ;
- return new Pair<>((long)x, bb) ;
- }
-
- @Override
- protected boolean hasMore() {
- return posn < buffer.limit() ;
- }
-
- }
-
- private class ObjectIterator implements Iterator<Pair<Long, ByteBuffer>> {
- final private long start ;
- final private long finish ;
- private long current ;
-
- public ObjectIterator(long start, long finish) {
- this.start = start ;
- this.finish = finish ;
- this.current = start ;
- }
-
- @Override
- public boolean hasNext() {
- return (current < finish) ;
- }
-
- @Override
- public Pair<Long, ByteBuffer> next() {
- // read, but reserving the file position.
- long x = current ;
- long filePosn = file.position() ;
- ByteBuffer bb = read(current) ;
- file.position(filePosn) ;
- current = current + bb.limit() + 4 ;
- return new Pair<>(x, bb) ;
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException() ;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileSwitcher.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileSwitcher.java b/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileSwitcher.java
deleted file mode 100644
index b3fe36a..0000000
--- a/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileSwitcher.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.dboe.base.objectfile;
-
-
-/**
- * An ObjectFile is an append-read file, that is you can append data
- * to the stream or read any block.
- */
-
-public class ObjectFileSwitcher extends ObjectFileWrapper
-{
- protected final ObjectFile objFile1 ;
- protected final ObjectFile objFile2 ;
-
- public ObjectFileSwitcher(ObjectFile objFile1, ObjectFile objFile2)
- {
- super(objFile1) ;
- this.objFile1 = objFile1 ;
- this.objFile2 = objFile2 ;
- }
-
- public final void switchover()
- {
- if ( super.other == objFile1 )
- super.other = objFile2 ;
- else
- super.other = objFile1 ;
- }
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileWrapper.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileWrapper.java b/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileWrapper.java
deleted file mode 100644
index 413b7e4..0000000
--- a/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/ObjectFileWrapper.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.dboe.base.objectfile;
-
-import java.nio.ByteBuffer ;
-import java.util.Iterator ;
-
-import org.apache.jena.atlas.lib.Pair ;
-import org.seaborne.dboe.base.block.Block ;
-
-/**
- * An ObjectFile is an append-read file, that is you can append data
- * to the stream or read any block.
- */
-
-public class ObjectFileWrapper implements ObjectFile
-{
- protected ObjectFile other ;
-
- public ObjectFileWrapper(ObjectFile other) { this.other = other ; }
-
- @Override
- public Block allocWrite(int maxBytes) { return other.allocWrite(maxBytes) ; }
-
- @Override
- public void completeWrite(Block buffer) { other.completeWrite(buffer) ; }
-
- @Override
- public void abortWrite(Block buffer) { other.abortWrite(buffer) ; }
-
- @Override
- public long write(ByteBuffer buffer) { return other.write(buffer) ; }
-
- @Override
- public void reposition(long id) { other.reposition(id) ; }
-
- @Override
- public void truncate(long size) { other.truncate(size) ; }
-
- @Override
- public ByteBuffer read(long id) { return other.read(id) ; }
-
- @Override
- public String getLabel() { return other.getLabel() ; }
-
- @Override
- public Iterator<Pair<Long, ByteBuffer>> all() { return other.all() ; }
-
- @Override
- public void sync() { other.sync() ; }
-
- @Override
- public void close() { other.close() ; }
-
- @Override
- public long length() { return other.length() ; }
-
- @Override
- public long position() { return other.position() ; }
-
- @Override
- public boolean isEmpty() { return other.isEmpty() ; }
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/StringFile.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/StringFile.java b/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/StringFile.java
deleted file mode 100644
index d7f8b60..0000000
--- a/dboe-base/src/main/java/org/seaborne/dboe/base/objectfile/StringFile.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * 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.dboe.base.objectfile;
-
-import java.nio.ByteBuffer ;
-
-import org.apache.jena.atlas.lib.Bytes ;
-import org.apache.jena.atlas.lib.Closeable ;
-import org.apache.jena.atlas.lib.Sync ;
-import org.seaborne.dboe.base.block.Block ;
-
-/** Wrap a {@link ObjectFile} with a string encoder/decoder.
- * Controls the UTF encoder/decoder and is not limited to 64K byte encoded forms.
- */
-
-public class StringFile implements Sync, Closeable
-{
- // TODO :
-
- protected final ObjectFile file ;
- /*
- * Encoding: Simple for now:
- * length (4 bytes)
- * UTF-8 bytes.
- */
-
- public StringFile(ObjectFile file)
- {
- this.file = file ;
- }
-
- public long write(String str)
- {
- str = compress(str) ;
- Block block = file.allocWrite(4*str.length()) ;
- int len = Bytes.toByteBuffer(str, block.getByteBuffer()) ;
- block.getByteBuffer().flip() ;
- file.completeWrite(block) ;
- return block.getId() ;
- }
-
- public String read(long id)
- {
- ByteBuffer bb = file.read(id) ;
- String x = Bytes.fromByteBuffer(bb) ;
- x = decompress(x) ;
- return x ;
- }
-
- @Override
- public void close()
- { file.close() ; }
-
- @Override
- public void sync() { file.sync() ; }
-
- public void flush() { sync() ; }
-
- public ObjectFile getByteBufferFile()
- {
- return file ;
- }
-
- // ---- Dump
- public void dump() { dump(handler) ; }
-
- public interface DumpHandler { void handle(long fileIdx, String str) ; }
-
- public void dump(DumpHandler handler)
- {
- long fileIdx = 0 ;
- while ( true )
- {
- ByteBuffer bb = file.read(fileIdx) ;
- String str = Bytes.fromByteBuffer(bb) ;
- handler.handle(fileIdx, str) ;
- fileIdx = fileIdx + bb.limit() + 4 ;
- if ( fileIdx >= file.position() )
- break ;
- }
- }
-
- static StringFile.DumpHandler handler = new StringFile.DumpHandler() {
- @Override
- public void handle(long fileIdx, String str)
- {
- System.out.printf("0x%08X : %s\n", fileIdx, str) ;
- }
- } ;
-
- // Shodul be String -> Bytes.
- private String compress(String str) { return str ; }
- private String decompress(String x) { return x ; }
- // ----
-
-
-// // URI compression can be effective but literals are more of a problem. More variety.
-// public final static boolean compression = false ;
-// private static StringAbbrev abbreviations = new StringAbbrev() ;
-// static {
-// abbreviations.add( "rdf", "<http://www.w3.org/1999/02/22-rdf-syntax-ns#") ;
-// abbreviations.add( "rdfs", "<http://www.w3.org/2000/01/rdf-schema#") ;
-// abbreviations.add( "xsd", "<http://www.w3.org/2001/XMLSchema#") ;
-//
-// // MusicBrainz
-// abbreviations.add( "mal", "<http://musicbrainz.org/mm-2.1/album/") ;
-// abbreviations.add( "mt", "<http://musicbrainz.org/mm-2.1/track/") ;
-// abbreviations.add( "mar", "<http://musicbrainz.org/mm-2.1/artist/") ;
-// abbreviations.add( "mtr", "<http://musicbrainz.org/mm-2.1/trmid/") ;
-// abbreviations.add( "mc", "<http://musicbrainz.org/mm-2.1/cdindex/") ;
-//
-// abbreviations.add( "m21", "<http://musicbrainz.org/mm/mm-2.1#") ;
-// abbreviations.add( "dc", "<http://purl.org/dc/elements/1.1/") ;
-// // DBPedia
-// abbreviations.add( "r", "<http://dbpedia/resource/") ;
-// abbreviations.add( "p", "<http://dbpedia/property/") ;
-// }
-// private String compress(String str)
-// {
-// if ( !compression || abbreviations == null ) return str ;
-// return abbreviations.abbreviate(str) ;
-// }
-//
-// private String decompress(String x)
-// {
-// if ( !compression || abbreviations == null ) return x ;
-// return abbreviations.expand(x) ;
-// }
-
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/test/java/org/seaborne/dboe/TC_DBOE_IO.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/test/java/org/seaborne/dboe/TC_DBOE_IO.java b/dboe-base/src/test/java/org/seaborne/dboe/TC_DBOE_IO.java
index 6eae773..35a697d 100644
--- a/dboe-base/src/test/java/org/seaborne/dboe/TC_DBOE_IO.java
+++ b/dboe-base/src/test/java/org/seaborne/dboe/TC_DBOE_IO.java
@@ -25,8 +25,8 @@ import org.junit.runner.RunWith ;
import org.junit.runners.Suite ;
import org.seaborne.dboe.base.block.FileMode ;
import org.seaborne.dboe.base.block.TS_Block ;
+import org.seaborne.dboe.base.buffer.TS_Buffer ;
import org.seaborne.dboe.base.file.TS_File ;
-import org.seaborne.dboe.base.objectfile.TS_ObjectFile ;
import org.seaborne.dboe.base.record.TS_Record ;
import org.seaborne.dboe.base.recordfile.TS_RecordFile ;
import org.seaborne.dboe.sys.SystemIndex ;
@@ -35,9 +35,9 @@ import org.seaborne.dboe.sys.SystemIndex ;
@Suite.SuiteClasses( {
TS_Block.class
, TS_File.class
+ , TS_Buffer.class
, TS_Record.class
, TS_RecordFile.class
- , TS_ObjectFile.class
} )
public class TC_DBOE_IO {
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/test/java/org/seaborne/dboe/base/TC_Base.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/test/java/org/seaborne/dboe/base/TC_Base.java b/dboe-base/src/test/java/org/seaborne/dboe/base/TC_Base.java
deleted file mode 100644
index c02f079..0000000
--- a/dboe-base/src/test/java/org/seaborne/dboe/base/TC_Base.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.dboe.base;
-
-import org.junit.runner.RunWith ;
-import org.junit.runners.Suite ;
-import org.seaborne.dboe.base.block.TS_Block ;
-import org.seaborne.dboe.base.buffer.TS_Buffer ;
-import org.seaborne.dboe.base.file.TS_File ;
-import org.seaborne.dboe.base.objectfile.TS_ObjectFile ;
-import org.seaborne.dboe.base.record.TS_Record ;
-import org.seaborne.dboe.base.recordfile.TS_RecordFile ;
-
-@RunWith(Suite.class)
-@Suite.SuiteClasses( {
- TS_Block.class
- , TS_File.class
- , TS_Buffer.class
- , TS_Record.class
- , TS_RecordFile.class
- , TS_ObjectFile.class
-})
-
-
-public class TC_Base
-{}
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/AbstractTestObjectFile.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/AbstractTestObjectFile.java b/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/AbstractTestObjectFile.java
deleted file mode 100644
index 475a9cc..0000000
--- a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/AbstractTestObjectFile.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * 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.dboe.base.objectfile;
-
-import static org.seaborne.dboe.test.BufferTestLib.sameValue ;
-
-import java.nio.ByteBuffer ;
-
-import org.junit.Assert ;
-import org.junit.After ;
-import org.junit.Before ;
-import org.junit.Test ;
-import org.seaborne.dboe.base.block.Block ;
-import org.seaborne.dboe.base.objectfile.ObjectFile ;
-
-public abstract class AbstractTestObjectFile extends Assert
-{
- ObjectFile file ;
-
- @Before public void before() { file = make() ; }
- @After public void after() { release(file); }
-
- @Test public void objectfile_01()
- {
-
- assertEquals(0, file.position()) ;
- }
-
- @Test public void objectfile_02()
- {
- Block block = file.allocWrite(10) ;
- fill(block.getByteBuffer()) ;
- file.completeWrite(block) ;
- long x1 = block.getId() ;
- assertEquals(0, x1) ;
-
- ByteBuffer bb = file.read(x1) ;
-
- // position
-
- assertTrue(sameValue(block.getByteBuffer(), bb)) ;
- }
-
- @Test public void objectfile_03()
- {
- ByteBuffer bb = ByteBuffer.allocate(10) ;
- fill(bb) ;
- long x1 = file.write(bb) ;
- assertEquals(0, x1) ;
- }
-
- @Test public void objectfile_04()
- {
- Block block1 = file.allocWrite(10) ;
- fill(block1.getByteBuffer()) ;
- file.completeWrite(block1) ;
-
- Block block2 = file.allocWrite(20) ;
- fill(block2.getByteBuffer()) ;
- file.completeWrite(block2) ;
-
- long x1 = block1.getId() ;
- long x2 = block2.getId() ;
-
- assertFalse(x1 == x2) ;
- }
-
- @Test public void objectfile_05()
- {
- ByteBuffer bb1 = ByteBuffer.allocate(10) ;
- fill(bb1) ;
-
- ByteBuffer bb2 = ByteBuffer.allocate(20) ;
- fill(bb2) ;
- long x1 = file.write(bb1) ;
- long x2 = file.write(bb2) ;
-
- assertFalse(x1 == x2) ;
- }
-
- @Test public void objectfile_06()
- {
- ByteBuffer bb1 = ByteBuffer.allocate(10) ;
- fill(bb1) ;
-
- ByteBuffer bb2 = ByteBuffer.allocate(20) ;
- fill(bb2) ;
-
- long x1 = file.write(bb1) ;
- long x2 = file.write(bb2) ;
-
- ByteBuffer bb1a = file.read(x1) ;
- ByteBuffer bb2a = file.read(x2) ;
- assertNotSame(bb1a, bb2a) ;
- assertTrue(sameValue(bb1, bb1a)) ;
- assertTrue(sameValue(bb2, bb2a)) ;
- }
-
-// // Oversized writes.
-//
-// @Test public void objectfile_07()
-// {
-//
-// }
-//
-// @Test public void objectfile_08()
-// {}
-//
-// @Test public void objectfile_09()
-// {}
-//
-// @Test public void objectfile_10()
-// {}
-
- public static void fill(ByteBuffer byteBuffer)
- {
- int len = byteBuffer.remaining() ;
- for ( int i = 0 ; i < len ; i++ )
- byteBuffer.put((byte)(i&0xFF)) ;
- byteBuffer.rewind() ;
- }
-
- protected abstract ObjectFile make() ;
- protected abstract void release(ObjectFile file) ;
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/AbstractTestStringFile.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/AbstractTestStringFile.java b/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/AbstractTestStringFile.java
deleted file mode 100644
index 6475833..0000000
--- a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/AbstractTestStringFile.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * 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.dboe.base.objectfile;
-
-import org.junit.Assert ;
-import org.junit.After ;
-import org.junit.Before ;
-import org.junit.Test ;
-import org.seaborne.dboe.base.objectfile.StringFile ;
-
-public abstract class AbstractTestStringFile extends Assert
-{
- StringFile f = null ;
-
- @Before public void setup() { f = createStringFile() ; }
- @After public void teardown() { removeStringFile(f) ; }
-
- protected abstract StringFile createStringFile() ;
- protected abstract void removeStringFile(StringFile f) ;
-
- @Test public void object_file_01()
- {
- String x1 = "abc" ;
- long id1 = f.write(x1) ;
- test(id1, x1) ;
- test(0, x1) ;
- }
-
- @Test public void object_file_02()
- {
- String x1 = "" ;
-
- long id1 = f.write(x1) ;
- test(id1, x1) ;
- test(0, x1) ;
- }
-
- @Test public void object_file_03()
- {
- String x1 = "abbbbbbc" ;
- String x2 = "deeeef" ;
-
- long id1 = f.write(x1) ;
- long id2 = f.write(x2) ;
-
- assertNotEquals("Node Ids", id1, id2) ;
-
- test(id1, x1) ;
- test(id2, x2) ;
- test(0, x1) ;
- }
-
- @Test public void object_file_04()
- {
- String x1 = "abbbbbbc" ;
- String x2 = "deeeef" ;
-
- long id1 = f.write(x1) ;
- long id2 = f.write(x2) ;
- // Read in opposite order
- test(id2, x2) ;
- test(id1, x1) ;
- }
-
- @Test public void object_file_05()
- {
- String x = "孫子兵法" ;
-
- long id = f.write(x) ;
- test(0, x) ;
- }
-
- @Test public void object_file_06()
- {
- String x1 = "abbbbbbc" ;
- String x2 = "孫子兵法" ;
-
- long id1 = f.write(x1) ;
- f.flush() ;
- long id2 = f.write(x2) ;
- // No flush.
-
- assertNotEquals("Node Ids", id1, id2) ;
-
- String z = f.read(id2) ;
-
- test(id2, x2) ;
- test(id1, x1) ;
- test(0, x1) ;
- }
-
- @Test public void object_file_07()
- {
- String x1 = "abbbbbbc" ;
- String x2 = "孫子兵法" ;
-
- long id1 = f.write(x1) ;
- long id2 = f.write(x2) ;
- f.flush() ;
-
- assertNotEquals("Node Ids", id1, id2) ;
-
- test(id2, x2) ;
- test(id1, x1) ;
- test(0, x1) ;
- }
-
- @Test public void object_file_08()
- {
- String x1 = "abbbbbbc" ;
- String x2 = "孫子兵法" ;
-
- long id1 = f.write(x1) ;
- f.flush() ;
- long id2 = f.write(x2) ;
- f.flush() ;
-
- assertNotEquals("Node Ids", id1, id2) ;
-
- test(id2, x2) ;
- test(id1, x1) ;
- test(0, x1) ;
- }
-
- private void test(long id, String x)
- {
- String y = f.read(id) ;
- assertEquals(x, y) ;
- }
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TS_ObjectFile.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TS_ObjectFile.java b/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TS_ObjectFile.java
deleted file mode 100644
index d3b8704..0000000
--- a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TS_ObjectFile.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.dboe.base.objectfile;
-
-import org.junit.runner.RunWith ;
-import org.junit.runners.Suite ;
-
-@RunWith(Suite.class)
-@Suite.SuiteClasses( {
- TestObjectFileMem.class
- //, TestObjectFileDisk.class
- //, TestObjectFileBuffering.class
- , TestStringFileMem.class
- //, TestStringFileDisk.class
-})
-
-public class TS_ObjectFile
-{ }
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestObjectFileBuffering.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestObjectFileBuffering.java b/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestObjectFileBuffering.java
deleted file mode 100644
index 40ba9b3..0000000
--- a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestObjectFileBuffering.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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.dboe.base.objectfile;
-
-import static org.seaborne.dboe.base.objectfile.AbstractTestObjectFile.fill ;
-import static org.seaborne.dboe.test.BufferTestLib.sameValue ;
-
-import java.nio.ByteBuffer ;
-
-import org.junit.Assert ;
-import org.junit.Test ;
-import org.seaborne.dboe.base.block.Block ;
-import org.seaborne.dboe.base.file.BufferChannel ;
-import org.seaborne.dboe.base.file.BufferChannelMem ;
-import org.seaborne.dboe.base.objectfile.ObjectFile ;
-import org.seaborne.dboe.base.objectfile.ObjectFileStorage ;
-
-public class TestObjectFileBuffering extends Assert
-{
- protected ObjectFile make(int bufferSize)
- {
- BufferChannel chan = BufferChannelMem.create() ;
- return new ObjectFileStorage(chan, bufferSize) ;
- }
-
- private void write(int sizeOfBuffer, int... sizes)
- {
- ObjectFile file = make(sizeOfBuffer) ;
- int N = sizes.length ;
- ByteBuffer bb[] = new ByteBuffer[N] ;
- long loc[] = new long[N] ;
- ByteBuffer read[] = new ByteBuffer[N] ;
-
- for ( int i = 0 ; i < N ; i++ )
- {
- bb[i] = ByteBuffer.allocate(sizes[i]) ;
- fill(bb[i]) ;
- loc[i] = file.write(bb[i]) ;
- }
- //file.sync() ;
- for ( int i = 0 ; i < N ; i++ )
- {
- read[i] = file.read(loc[i]) ;
- assertNotSame(bb[i], read[i]) ;
- sameValue(bb[i], read[i]) ;
- }
- }
-
- private void writePrealloc(int sizeOfBuffer, int... sizes)
- {
- ObjectFile file = make(sizeOfBuffer) ;
- int N = sizes.length ;
- Block blocks[] = new Block[N] ;
- ByteBuffer read[] = new ByteBuffer[N] ;
-
- for ( int i = 0 ; i < N ; i++ )
- {
- blocks[i] = file.allocWrite(sizes[i]) ;
- fill(blocks[i].getByteBuffer()) ;
- file.completeWrite(blocks[i]) ;
- }
-
- for ( int i = 0 ; i < N ; i++ )
- {
- read[i] = file.read(blocks[i].getId()) ;
- assertNotSame(blocks[i].getByteBuffer(), read[i]) ;
- sameValue(blocks[i].getByteBuffer(), read[i]) ;
- }
- }
-
-
- @Test public void objectfile_50() { write(5, 10) ; }
- @Test public void objectfile_51() { writePrealloc(5, 10) ; }
- @Test public void objectfile_52() { write(12, 10) ; }
- @Test public void objectfile_53() { writePrealloc(12, 10) ; }
- @Test public void objectfile_54() { write(12, 10, 8) ; } // 10 is too big
- @Test public void objectfile_55() { writePrealloc(12, 10, 8) ; } // 10 is too big
- @Test public void objectfile_56() { write(12, 6, 10) ; }
- @Test public void objectfile_57() { writePrealloc(12, 6, 10) ; }
- @Test public void objectfile_58() { write(20, 6, 10, 5) ; }
- @Test public void objectfile_59() { writePrealloc(20, 6, 10, 5) ; }
-
- @Test public void objectfile_60() { write(20, 4, 4, 8) ; }
- @Test public void objectfile_61() { writePrealloc(20, 4, 4, 8) ; }
-
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestObjectFileDisk.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestObjectFileDisk.java b/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestObjectFileDisk.java
deleted file mode 100644
index 0639d83..0000000
--- a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestObjectFileDisk.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.dboe.base.objectfile;
-
-import org.apache.jena.atlas.lib.FileOps ;
-import org.junit.AfterClass ;
-import org.seaborne.dboe.ConfigTestDBOE ;
-import org.seaborne.dboe.base.file.BufferChannel ;
-import org.seaborne.dboe.base.file.BufferChannelFile ;
-import org.seaborne.dboe.base.objectfile.ObjectFile ;
-import org.seaborne.dboe.base.objectfile.ObjectFileStorage ;
-
-public class TestObjectFileDisk extends AbstractTestObjectFile
-{
- static String filename = ConfigTestDBOE.getTestingDir()+"/test-objectfile" ;
-
- @AfterClass public static void cleanup() { FileOps.deleteSilent(filename) ; }
-
- @Override
- protected ObjectFile make()
- {
- FileOps.deleteSilent(filename) ;
- BufferChannel chan = BufferChannelFile.create(filename) ;
- // No buffering.
- return new ObjectFileStorage(chan, -1) ;
- }
-
- @Override
- protected void release(ObjectFile file)
- {
- file.truncate(0) ;
- file.close() ;
- }
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestObjectFileMem.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestObjectFileMem.java b/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestObjectFileMem.java
deleted file mode 100644
index 0e9e8e0..0000000
--- a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestObjectFileMem.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.dboe.base.objectfile;
-
-import org.seaborne.dboe.base.file.FileFactory ;
-import org.seaborne.dboe.base.objectfile.ObjectFile ;
-
-public class TestObjectFileMem extends AbstractTestObjectFile
-{
-
- @Override
- protected ObjectFile make()
- {
- return FileFactory.createObjectFileMem("test") ;
- }
-
- @Override
- protected void release(ObjectFile file)
- {
- file.truncate(0) ;
- file.close() ;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestStringFileDisk.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestStringFileDisk.java b/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestStringFileDisk.java
deleted file mode 100644
index 9e6ef71..0000000
--- a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestStringFileDisk.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.dboe.base.objectfile;
-
-import static org.apache.jena.atlas.lib.FileOps.clearDirectory ;
-import org.apache.jena.atlas.lib.FileOps ;
-import org.seaborne.dboe.ConfigTestDBOE ;
-import org.seaborne.dboe.base.file.FileFactory ;
-import org.seaborne.dboe.base.file.Location ;
-import org.seaborne.dboe.base.objectfile.StringFile ;
-
-public class TestStringFileDisk extends AbstractTestStringFile
-{
- String fn = null ;
-
- @Override
- protected StringFile createStringFile()
- {
- String dir = ConfigTestDBOE.getTestingDir() ;
- clearDirectory(dir) ;
- Location loc = Location.create(dir) ;
- fn = loc.getPath("xyz", "node") ;
- FileOps.delete(fn) ;
- return FileFactory.createStringFileDisk(fn) ;
- }
-
- @Override
- protected void removeStringFile(StringFile f)
- {
- f.close() ;
- FileOps.delete(fn) ;
- }
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestStringFileMem.java
----------------------------------------------------------------------
diff --git a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestStringFileMem.java b/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestStringFileMem.java
deleted file mode 100644
index 0098fad..0000000
--- a/dboe-base/src/test/java/org/seaborne/dboe/base/objectfile/TestStringFileMem.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.dboe.base.objectfile;
-
-import org.seaborne.dboe.base.file.FileFactory ;
-import org.seaborne.dboe.base.objectfile.StringFile ;
-
-public class TestStringFileMem extends AbstractTestStringFile
-{
-
- @Override
- protected StringFile createStringFile()
- {
- // OLD
- //return new StringFile(new ObjectFileMem(("mem-test"))) ;
- // NEW
- return FileFactory.createStringFileMem("mem-test") ;
- }
-
- @Override
- protected void removeStringFile(StringFile f)
- {
- f.close() ;
- }
-}
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransBinaryDataFile.java
----------------------------------------------------------------------
diff --git a/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransBinaryDataFile.java b/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransBinaryDataFile.java
index b3c1ed0..569db33 100644
--- a/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransBinaryDataFile.java
+++ b/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransBinaryDataFile.java
@@ -25,10 +25,9 @@ import org.apache.jena.atlas.io.IO ;
import org.apache.jena.query.ReadWrite ;
import org.seaborne.dboe.base.file.BinaryDataFile ;
import org.seaborne.dboe.base.file.BufferChannel ;
-import org.seaborne.dboe.base.objectfile.ObjectFile ;
import org.seaborne.dboe.transaction.txn.* ;
-/** Transactional {@link ObjectFile}.
+/** Transactional {@link BinaryDataFile}.
* An binary file that is append-only and allows only one writer at a time.
* All readers see the file up to the last commit point at the time
* they started. The sole writer sees more of the file.
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransObjectFile.java
----------------------------------------------------------------------
diff --git a/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransObjectFile.java b/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransObjectFile.java
deleted file mode 100644
index ce2c678..0000000
--- a/dboe-trans-data/src/main/java/org/seaborne/dboe/trans/data/TransObjectFile.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * 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.dboe.trans.data;
-
-import java.nio.ByteBuffer ;
-import java.util.Iterator ;
-import java.util.concurrent.atomic.AtomicLong ;
-
-import org.apache.jena.atlas.lib.Pair ;
-import org.apache.jena.query.ReadWrite ;
-import org.seaborne.dboe.base.block.Block ;
-import org.seaborne.dboe.base.file.BufferChannel ;
-import org.seaborne.dboe.base.objectfile.ObjectFile ;
-import org.seaborne.dboe.transaction.txn.ComponentId ;
-import org.seaborne.dboe.transaction.txn.StateMgrData ;
-import org.seaborne.dboe.transaction.txn.TransactionalComponentLifecycle ;
-import org.seaborne.dboe.transaction.txn.TxnId ;
-
-/** Transactional {@link ObjectFile}.
- * An object file is append-only and allows only one writer at a time.
- * As a result, all readers see the file up to the last commit point at the time
- * they started. The sole writer sees more of the file.
- */
-
-public class TransObjectFile extends TransactionalComponentLifecycle<TransObjectFile.TxnObjectFile>
- implements ObjectFile {
-
- /*
- * The file is written to as we go along so abort requires some action. We
- * can't recover from just the file, without any redo or undo recovery
- * action. The length/position of the file may be duff, there is a possible
- * abandoned section of the file.
- *
- * But even if a partial entry, we don't corrupt data. Assumes no references
- * to the abandoned area of the file.
- */
-
- private final ObjectFileState stateMgr ;
-
- // The current committed position.
- // This is also the abort point.
- // And the limit as seen by readers.
-
- // Recovery record: (length, position)
- private final AtomicLong length ;
- private final AtomicLong position ;
-
- static class TxnObjectFile {
- final long length ;
- final long position ;
-
- TxnObjectFile(long length, long position) {
- this.length = length ;
- this.position = position ;
- }
- }
-
- static class ObjectFileState extends StateMgrData {
- ObjectFileState(BufferChannel bufferChannel, long length, long position) {
- super(bufferChannel, length, position) ;
- }
- private static int idxLength = 0 ;
- private static int idxPosition = 1 ;
- long length() { return get(idxLength) ; }
- long position() { return get(idxPosition) ; }
- void length(long len) { set(idxLength, len) ; }
- void position(long posn) { set(idxPosition, posn) ; }
- }
-
- private final ObjectFile objFile ;
-
- public TransObjectFile(ObjectFile objFile, ComponentId cid, BufferChannel bufferChannel) {
- super(cid) ;
- stateMgr = new ObjectFileState(bufferChannel, 0L, 0L) ;
- this.objFile = objFile ;
-
- // These may be updated by recovery. Start by setting to the
- // "clean start" settings.
-
- length = new AtomicLong(objFile.length()) ;
- position = new AtomicLong(objFile.position()) ;
- }
-
- private boolean recoveryAction = false ;
-
- @Override
- public void startRecovery() {
- recoveryAction = false ;
- }
-
- @Override
- public void recover(ByteBuffer ref) {
- stateMgr.setState(ref);
- length.set(stateMgr.length()) ;
- position.set(stateMgr.position()) ;
- recoveryAction = true ;
- }
-
- @Override
- public void finishRecovery() {
- // If we did a truncate.
-// if ( recoveryAction )
-// objFile.sync();
- }
-
- @Override
- public void cleanStart() { }
-
- @Override
- protected TxnObjectFile _begin(ReadWrite readWrite, TxnId txnId) {
- return createState();
- }
-
- private TxnObjectFile createState() {
- // Atomic read across the two because it's called from within
- // TransactionCoordinator.begin$ or promote$ where there is a lock.
- long xLength = length.get() ;
- long xPosition = position.get() ;
- return new TxnObjectFile(xLength, xPosition) ;
- }
-
- @Override
- protected TxnObjectFile _promote(TxnId txnId, TxnObjectFile state) {
- // Our write state is the read state.
- return createState();
- }
-
- @Override
- protected ByteBuffer _commitPrepare(TxnId txnId, TxnObjectFile state) {
- stateMgr.length(objFile.length()) ;
- stateMgr.position(objFile.position());
- return stateMgr.getState() ;
- }
-
- @Override
- protected void _commit(TxnId txnId, TxnObjectFile state) {
- if ( isWriteTxn() ) {
- // Force to disk.
- objFile.sync();
- stateMgr.writeState();
- // Move visible commit point forward.
- length.set(objFile.length()) ;
- position.set(objFile.position()) ;
- }
- }
-
- @Override
- protected void _commitEnd(TxnId txnId, TxnObjectFile state) {
- }
-
- @Override
- protected void _abort(TxnId txnId, TxnObjectFile state) {
- if ( isWriteTxn() ) {
- // One will imply the other.
- objFile.truncate(state.length) ;
- //objFile.reposition(state.position) ;
- // sync to make sure the file looses the unwanted part.
- // Neater, no abandoned sections (outside crashes).
- objFile.sync() ;
- }
- }
-
- @Override
- protected void _complete(TxnId txnId, TxnObjectFile state) {}
-
- @Override
- protected void _shutdown() {}
-
- private void checkBoundsReader(long requestedPoint, TxnObjectFile state) { }
-
- // The Object file part, with transaction testing.
- @Override
- public Block allocWrite(int maxBytes) {
- checkWriteTxn();
- return objFile.allocWrite(maxBytes) ;
- }
-
- @Override
- public void completeWrite(Block buffer) {
- checkWriteTxn();
- objFile.completeWrite(buffer) ;
- }
-
- @Override
- public void abortWrite(Block buffer) {
- checkWriteTxn();
- objFile.abortWrite(buffer) ;
- }
-
- @Override
- public long write(ByteBuffer buffer) {
- checkWriteTxn();
- return objFile.write(buffer) ;
- }
-
- @Override
- public void reposition(long id) {
- checkWriteTxn();
- objFile.reposition(id) ;
- }
-
- @Override
- public void truncate(long size) {
- checkWriteTxn();
- objFile.truncate(size) ;
- }
-
- @Override
- public ByteBuffer read(long id) {
- super.checkTxn();
- if ( isReadTxn() )
- // Reader. Check bounds.
- checkBoundsReader(id, super.getDataState()) ;
- return objFile.read(id) ;
- }
-
- @Override
- public String getLabel() {
- return objFile.getLabel() ;
- }
-
- @Override
- public Iterator<Pair<Long, ByteBuffer>> all() {
- super.checkTxn();
- return objFile.all() ;
- }
-
- @Override
- public void sync() {
- super.checkTxn();
- objFile.sync() ;
- }
-
- @Override
- public void close() {
- super.checkTxn();
- objFile.close() ;
- }
-
- @Override
- public long length() {
- super.checkTxn();
- if ( isReadTxn() )
- return getDataState().length ;
- // Reader. Check bounds.
- return objFile.length() ;
- }
-
- @Override
- public long position() {
- super.checkTxn();
- return objFile.position() ;
- }
-
- @Override
- public boolean isEmpty() {
- super.checkTxn();
- return objFile.isEmpty() ;
- }
-}
-
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TS_TransData.java
----------------------------------------------------------------------
diff --git a/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TS_TransData.java b/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TS_TransData.java
index 0d4c092..d310e6b 100644
--- a/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TS_TransData.java
+++ b/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TS_TransData.java
@@ -23,8 +23,7 @@ import org.junit.runners.Suite.SuiteClasses ;
@RunWith(Suite.class)
@SuiteClasses( {
- TestTransObjectFile.class
- , TestTransIndexMem.class
+ TestTransIndexMem.class
, TestTransBlob.class
, TestTransBlobPersistent.class
, TestTransBinaryDataFileGeneral.class
http://git-wip-us.apache.org/repos/asf/jena/blob/67b69b5e/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransObjectFile.java
----------------------------------------------------------------------
diff --git a/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransObjectFile.java b/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransObjectFile.java
deleted file mode 100644
index c2d0330..0000000
--- a/dboe-trans-data/src/test/java/org/seaborne/dboe/trans/data/TestTransObjectFile.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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.dboe.trans.data;
-
-import java.nio.ByteBuffer ;
-
-import org.apache.jena.atlas.lib.Bytes ;
-import org.apache.jena.atlas.lib.StrUtils ;
-import org.junit.After ;
-import org.junit.Assert ;
-import org.junit.Before ;
-import org.junit.Test ;
-import org.seaborne.dboe.base.file.BufferChannel ;
-import org.seaborne.dboe.base.file.FileFactory ;
-import org.seaborne.dboe.base.file.Location ;
-import org.seaborne.dboe.base.objectfile.ObjectFile ;
-import org.seaborne.dboe.jenax.Txn ;
-import org.seaborne.dboe.transaction.Transactional ;
-import org.seaborne.dboe.transaction.TransactionalFactory ;
-import org.seaborne.dboe.transaction.txn.ComponentId ;
-import org.seaborne.dboe.transaction.txn.TransactionalBase ;
-import org.seaborne.dboe.transaction.txn.journal.Journal ;
-import org.seaborne.dboe.transaction.txn.journal.JournalEntry ;
-import org.seaborne.dboe.transaction.txn.journal.JournalEntryType ;
-
-public class TestTransObjectFile extends Assert {
- private Journal journal ;
- private ObjectFile baseObjectFile ;
- private TransObjectFile transObjectFile ;
- private Transactional transactional ;
-
- @Before public void before() {
- journal = Journal.create(Location.mem()) ;
- baseObjectFile = FileFactory.createObjectFileMem("ObjectFile") ;
- BufferChannel chan = FileFactory.createBufferChannelMem() ;
- ComponentId cid = ComponentId.allocLocal() ;
- transObjectFile = new TransObjectFile(baseObjectFile, cid, chan) ;
- transactional = TransactionalFactory.createTransactional(journal, transObjectFile) ;
- }
-
- @After public void after() { }
-
- private static ByteBuffer str2bb(String x) {
- byte[] d = StrUtils.asUTF8bytes(x) ;
- ByteBuffer bb = ByteBuffer.wrap(d) ;
- return bb ;
- }
-
- private static long writeOne(Transactional transactional, TransObjectFile transObjectFile, String data) {
- return
- Txn.calculateWrite(transactional, ()->{
- ByteBuffer bb = str2bb(data) ;
- return transObjectFile.write(bb) ;
- }) ;
- }
-
- private static String readOne(Transactional transactional, TransObjectFile transObjectFile, long posn) {
- return Txn.calculateRead(transactional, ()->{
- ByteBuffer bb = transObjectFile.read(posn) ;
- return Bytes.fromByteBuffer(bb) ;
- }) ;
- }
-
- @Test public void transObjectFile_1() {
- String str = "Hello World" ;
- long x = writeOne(transactional, transObjectFile, str) ;
- String str2 = readOne(transactional, transObjectFile, x) ;
- assertEquals(str, str2) ;
- }
-
- @Test public void transObjectFile_2() {
- String str1 = "" ;
- String str2 = "$" ;
- long x1 = writeOne(transactional, transObjectFile, str1) ;
- long x2 = writeOne(transactional, transObjectFile, str2) ;
- assertNotEquals(x1, x2) ;
-
- String out2 = readOne(transactional, transObjectFile, x2) ;
- String out1 = readOne(transactional, transObjectFile, x1) ;
- assertEquals(str1, out1) ;
- assertEquals(str2, out2) ;
- }
-
- @Test public void transObjectFile_3() {
- String str = "Hello World" ;
- long x = writeOne(transactional, transObjectFile, str) ;
- // Assume journal not truncated.
- }
-
- @Test public void transObjectFile_4() {
- String str1 = "Test4" ;
- String str2 = "TheNext" ;
- long x1 = writeOne(transactional, transObjectFile, str1) ;
- ByteBuffer bb = str2bb(str2) ;
- long x2 = baseObjectFile.write(bb) ;
- baseObjectFile.sync();
- long x3 = Txn.calculateRead(transactional, ()->transObjectFile.length()) ;
- assertEquals(x2, x3);
- assertNotEquals(x3, baseObjectFile.length());
-
- // Fake recovery.
- ByteBuffer bbj = ByteBuffer.allocate(2*Long.BYTES) ;
- bbj.putLong(x3) ;
- bbj.putLong(0) ;
- bbj.rewind() ;
- journal.write(JournalEntryType.REDO, transObjectFile.getComponentId(), bbj) ;
- journal.writeJournal(JournalEntry.COMMIT) ;
- // Recovery.
- //transObjectFile.recover(bb);
- TransactionalBase transBase = (TransactionalBase)TransactionalFactory.createTransactional(journal, transObjectFile) ;
- ByteBuffer bb1 = Txn.calculateRead(transBase, ()->transObjectFile.read(x3)) ;
- String s1 = Bytes.fromByteBuffer(bb1) ;
- assertEquals(str2, s1);
- // Woot!
- transBase.getTxnMgr().shutdown();
- }
-}
-
[27/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis
as subdirectory jena-db/
Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/lib/TS_LibTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/lib/TS_LibTDB.java
index 0000000,0000000..df245fb
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/lib/TS_LibTDB.java
@@@ -1,0 -1,0 +1,33 @@@
++/*
++ * 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.lib;
++
++import org.junit.runner.RunWith;
++import org.junit.runners.Suite;
++import org.seaborne.tdb2.lib.TestNodeLib ;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestNodeLib.class
++})
++
++
++public class TS_LibTDB
++{
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/lib/TestNodeLib.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/lib/TestNodeLib.java
index 0000000,0000000..3e85f41
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/lib/TestNodeLib.java
@@@ -1,0 -1,0 +1,69 @@@
++/*
++ * 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.lib;
++
++import static org.seaborne.tdb2.lib.NodeLib.hash ;
++import static org.junit.Assert.*;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.sparql.util.NodeFactoryExtra ;
++import org.junit.Test ;
++
++public class TestNodeLib
++{
++ // Tests of TDBs NodeLib
++ @Test public void hash1()
++ {
++ Node x1 = NodeFactoryExtra.parseNode("<http://example/x>") ;
++ Node x2 = NodeFactoryExtra.parseNode("<http://example/x>") ;
++ assertEquals(hash(x1), hash(x2)) ;
++ }
++
++ @Test public void hash2()
++ {
++ Node x1 = NodeFactoryExtra.parseNode("<http://example/x1>") ;
++ Node x2 = NodeFactoryExtra.parseNode("<http://example/x2>") ;
++ assertNotEquals(hash(x1), hash(x2)) ;
++ }
++
++ @Test public void hash3()
++ {
++ Node x1 = NodeFactoryExtra.parseNode("<lex>") ;
++ Node x2 = NodeFactoryExtra.parseNode("'lex'") ;
++ Node x3 = NodeFactoryExtra.parseNode("_:lex") ;
++ assertNotEquals(hash(x1), hash(x2)) ;
++ assertNotEquals(hash(x2), hash(x3)) ;
++ assertNotEquals(hash(x3), hash(x1)) ;
++ }
++
++ @Test public void hash4()
++ {
++ Node x1 = NodeFactoryExtra.parseNode("123") ;
++ Node x2 = NodeFactoryExtra.parseNode("'123'") ;
++ assertNotEquals(hash(x1), hash(x2)) ;
++ }
++
++ @Test public void hash5()
++ {
++ Node x1 = NodeFactoryExtra.parseNode("123") ;
++ Node x2 = NodeFactoryExtra.parseNode("123.0") ;
++ Node x3 = NodeFactoryExtra.parseNode("123e0") ;
++ assertNotEquals(hash(x1), hash(x2)) ;
++ assertNotEquals(hash(x2), hash(x3)) ;
++ assertNotEquals(hash(x3), hash(x1)) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/setup/TS_TDBSetup.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/setup/TS_TDBSetup.java
index 0000000,0000000..8f99097
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/setup/TS_TDBSetup.java
@@@ -1,0 -1,0 +1,32 @@@
++/*
++ * 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.setup;
++
++import org.junit.runner.RunWith ;
++import org.junit.runners.Suite ;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestStoreParams.class
++ , TestStoreParamsChoose.class
++ , TestStoreParamsCreate.class
++})
++public class TS_TDBSetup {
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParams.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParams.java
index 0000000,0000000..0d8468c
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParams.java
@@@ -1,0 -1,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.setup;
++
++import org.apache.jena.atlas.json.JSON ;
++import org.apache.jena.atlas.json.JsonObject ;
++import static org.junit.Assert.*;
++import org.junit.Test ;
++import org.seaborne.dboe.base.block.FileMode ;
++import org.seaborne.tdb2.TDBException ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.setup.StoreParamsBuilder ;
++import org.seaborne.tdb2.setup.StoreParamsCodec ;
++
++public class TestStoreParams {
++
++ @Test public void store_params_01() {
++ assertEqualsStoreParams(StoreParams.getDftStoreParams(), StoreParams.getDftStoreParams()) ;
++ }
++
++ @Test public void store_params_02() {
++ StoreParams input = StoreParams.getDftStoreParams() ;
++ StoreParams sp = StoreParams.builder(input).build() ;
++ assertEqualsStoreParams(StoreParams.getDftStoreParams(), sp) ;
++ }
++
++ @Test public void store_params_03() {
++ StoreParams sp = StoreParams.builder().build() ;
++ assertEqualsStoreParams(StoreParams.getDftStoreParams(), sp) ;
++ }
++
++ @Test public void store_params_04() {
++ StoreParams params = StoreParams.builder().build() ;
++ StoreParams params2 = roundTrip(params) ;
++ assertEqualsStoreParams(params,params2) ;
++ }
++
++ // ----
++
++ @Test public void store_params_10() {
++ StoreParams params = StoreParams.builder().fileMode(FileMode.direct).blockSize(1024).build() ;
++ StoreParams params2 = roundTrip(params) ;
++ assertEqualsStoreParams(params,params2) ;
++ assertEquals(params.getFileMode(), params2.getFileMode()) ;
++ assertEquals(params.getBlockSize(), params2.getBlockSize()) ;
++ }
++
++ @Test public void store_params_11() {
++ String xs = "{ \"tdb.block_size\": 2048 }" ;
++ JsonObject x = JSON.parse(xs) ;
++ StoreParams paramsExpected = StoreParams.builder().blockSize(2048).build() ;
++ StoreParams paramsActual = StoreParamsCodec.decode(x) ;
++ assertEqualsStoreParams(paramsExpected,paramsActual) ;
++ }
++
++ @Test public void store_params_12() {
++ String xs = "{ \"tdb.file_mode\": \"direct\" , \"tdb.block_size\": 2048 }" ;
++ JsonObject x = JSON.parse(xs) ;
++ StoreParams paramsExpected = StoreParams.builder().blockSize(2048).fileMode(FileMode.direct).build() ;
++ StoreParams paramsActual = StoreParamsCodec.decode(x) ;
++ assertEqualsStoreParams(paramsExpected,paramsActual) ;
++ }
++
++ @Test public void store_params_13() {
++ String xs = "{ \"tdb.triple_indexes\" : [ \"POS\" , \"PSO\"] } " ;
++ JsonObject x = JSON.parse(xs) ;
++ StoreParams params = StoreParamsCodec.decode(x) ;
++ String[] expected = { "POS" , "PSO" } ;
++ assertArrayEquals(expected, params.getTripleIndexes()) ;
++ }
++
++ @Test(expected=TDBException.class)
++ public void store_params_14() {
++ String xs = "{ \"tdb.triples_indexes\" : [ \"POS\" , \"PSO\"] } " ; // Misspelt.
++ JsonObject x = JSON.parse(xs) ;
++ StoreParams params = StoreParamsCodec.decode(x) ;
++ String[] expected = { "POS" , "PSO" } ;
++ assertArrayEquals(expected, params.getTripleIndexes()) ;
++ }
++
++ // Check that setting gets recorded and propagated.
++
++ @Test public void store_params_20() {
++ StoreParams params = StoreParams.builder().blockReadCacheSize(0).build();
++ assertTrue(params.isSetBlockReadCacheSize()) ;
++ assertFalse(params.isSetBlockWriteCacheSize()) ;
++ }
++
++ @Test public void store_params_21() {
++ StoreParams params1 = StoreParams.builder().blockReadCacheSize(0).build();
++ assertTrue(params1.isSetBlockReadCacheSize()) ;
++ assertFalse(params1.isSetBlockWriteCacheSize()) ;
++ StoreParams params2 = StoreParams.builder(params1).blockWriteCacheSize(0).build();
++ assertTrue(params2.isSetBlockReadCacheSize()) ;
++ assertTrue(params2.isSetBlockWriteCacheSize()) ;
++ assertFalse(params2.isSetNodeMissCacheSize()) ;
++ }
++
++ // Modify
++ @Test public void store_params_22() {
++ StoreParams params1 = StoreParams.builder()
++ .blockReadCacheSize(0)
++ .blockWriteCacheSize(1)
++ .build();
++ StoreParams params2 = StoreParams.builder()
++ .blockReadCacheSize(5)
++ .build();
++ StoreParams params3 = StoreParamsBuilder.modify(params1, params2) ;
++ assertFalse(params2.isSetBlockWriteCacheSize()) ;
++ assertTrue(params3.isSetBlockReadCacheSize()) ;
++ assertTrue(params3.isSetBlockWriteCacheSize()) ;
++ assertEquals(5, params3.getBlockReadCacheSize().intValue()) ; // From params2
++ assertEquals(1, params3.getBlockWriteCacheSize().intValue()) ; // From params1, not params2(unset)
++
++ }
++
++
++ // --------
++
++ private static StoreParams roundTrip(StoreParams params) {
++ JsonObject obj = StoreParamsCodec.encodeToJson(params) ;
++ StoreParams params2 = StoreParamsCodec.decode(obj) ;
++ return params2 ;
++ }
++
++ private static void assertEqualsStoreParams(StoreParams params1, StoreParams params2) {
++ assertTrue(StoreParams.sameValues(params1, params2)) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsChoose.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsChoose.java
index 0000000,0000000..2b20d54
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsChoose.java
@@@ -1,0 -1,0 +1,157 @@@
++/*
++ * 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.setup;
++
++import static org.junit.Assert.*;
++import org.apache.jena.atlas.lib.FileOps ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.sys.Names;
++import org.seaborne.tdb2.ConfigTest ;
++
++//TestParamsCreate
++/** This test suite uses on-disk structures and can be slow */
++public class TestStoreParamsChoose {
++ private String DIR = ConfigTest.getCleanDir() ;
++
++ static final StoreParams pApp = StoreParams.builder()
++ .blockSize(12) // Not dynamic
++ .nodeMissCacheSize(12) // Dynamic
++ .build();
++ static final StoreParams pLoc = StoreParams.builder()
++ .blockSize(0)
++ .nodeMissCacheSize(0).build();
++
++ static final StoreParams pDft = StoreParams.getDftStoreParams() ;
++
++ @Test public void params_choose_new_1() {
++ StoreParams p = StoreParamsFactory.decideStoreParams(Location.mem(), true, null, null, pDft) ;
++ // New store, no pLoc, no pApp so pDft.
++ assertTrue(StoreParams.sameValues(p, pDft)) ;
++ }
++
++ @Test public void params_choose_new_2() {
++ StoreParams p = StoreParamsFactory.decideStoreParams(Location.mem(), true, pApp, null, pDft) ;
++ // New store, no pLoc, so pApp is the enire settings.
++ assertEquals(12, p.getBlockSize().intValue()) ;
++ assertTrue(StoreParams.sameValues(p, pApp)) ;
++ }
++
++ @Test public void params_choose_new_3() {
++ StoreParams p = StoreParamsFactory.decideStoreParams(Location.mem(), true, null, pLoc, pDft) ;
++ // New store, pLoc, no pApp, so pLoc is the entire settings.
++ assertEquals(0, p.getBlockSize().intValue()) ;
++ assertTrue(StoreParams.sameValues(p, pLoc)) ;
++ }
++
++ @Test public void params_choose_new_4() {
++ StoreParams p = StoreParamsFactory.decideStoreParams(Location.mem(), true, pApp, pLoc, pDft) ;
++ // New store, pLoc, no pApp, so pLoc is the entire settings.
++
++ assertFalse(StoreParams.sameValues(p, pApp)) ;
++ assertFalse(StoreParams.sameValues(p, pLoc)) ;
++ assertFalse(StoreParams.sameValues(p, pDft)) ;
++
++ assertEquals(0, p.getBlockSize().intValue()) ;
++ assertEquals(12, p.getNodeMissCacheSize().intValue()) ;
++ }
++
++ @Test public void params_choose_existing_1() {
++ StoreParams p = StoreParamsFactory.decideStoreParams(Location.mem(), false, null, null, pDft) ;
++ // p is pDft.
++ assertTrue(StoreParams.sameValues(p, pDft)) ;
++ }
++
++ @Test public void params_choose_existing_2() {
++ StoreParams p = StoreParamsFactory.decideStoreParams(Location.mem(), false, pApp, null, pDft) ;
++ // p is pLoc modified by pApp
++ assertFalse(StoreParams.sameValues(p, pApp)) ;
++ assertFalse(StoreParams.sameValues(p, pDft)) ;
++ // Existing store, no pLoc, so pDft is implicit pLoc and fixed the block size.
++ assertEquals(pDft.getBlockSize(), p.getBlockSize()) ;
++ assertEquals(12, p.getNodeMissCacheSize().intValue()) ;
++ }
++
++ @Test public void params_choose_existing_3() {
++ StoreParams p = StoreParamsFactory.decideStoreParams(Location.mem(), false, null, pLoc, pDft) ;
++ // p is pLoc
++ assertTrue(StoreParams.sameValues(p, pLoc)) ;
++
++ }
++
++ @Test public void params_choose_existing_4() {
++ StoreParams p = StoreParamsFactory.decideStoreParams(Location.mem(), false, pApp, pLoc, pDft) ;
++ // p is pLoc modifed by pApp.
++ assertFalse(StoreParams.sameValues(p, pApp)) ;
++ assertFalse(StoreParams.sameValues(p, pLoc)) ;
++ assertFalse(StoreParams.sameValues(p, pDft)) ;
++
++ assertEquals(0, p.getBlockSize().intValue()) ;
++ assertEquals(12, p.getNodeMissCacheSize().intValue()) ;
++ }
++
++ @Test public void params_choose_new_persist_1() {
++ // new database, app defined.
++ Location loc = Location.create(DIR) ;
++ FileOps.clearAll(loc.getDirectoryPath());
++ // Clear.
++ StoreParams p = StoreParamsFactory.decideStoreParams(loc, true, pApp, null, pDft) ;
++ // Check location now has a pLoc.
++ String fn = loc.getPath(Names.TDB_CONFIG_FILE) ;
++ assertTrue(FileOps.exists(fn)) ;
++
++ StoreParams pLoc2 = StoreParamsCodec.read(loc) ;
++ assertTrue(StoreParams.sameValues(pLoc2, p)) ;
++ }
++
++ @Test public void params_choose_new_persist_2() {
++ // new database, location defined.
++ Location loc = Location.create(DIR) ;
++ FileOps.clearAll(loc.getDirectoryPath());
++ StoreParamsCodec.write(loc, pLoc);
++
++ // Clear.
++ StoreParams p = StoreParamsFactory.decideStoreParams(loc, true, null, pLoc, pDft) ;
++ // Check location still has a pLoc.
++ String fn = loc.getPath(Names.TDB_CONFIG_FILE) ;
++ assertTrue(FileOps.exists(fn)) ;
++
++ StoreParams pLoc2 = StoreParamsCodec.read(loc) ;
++ assertTrue(StoreParams.sameValues(pLoc, p)) ;
++ }
++
++ @Test public void params_choose_new_persist_3() {
++ // new database, location defined, application modified.
++ Location loc = Location.create(DIR) ;
++ FileOps.clearAll(loc.getDirectoryPath());
++ StoreParamsCodec.write(loc, pLoc);
++
++ // Clear.
++ StoreParams p = StoreParamsFactory.decideStoreParams(loc, true, pApp, pLoc, pDft) ;
++ // Check location still has a pLoc.
++ String fn = loc.getPath(Names.TDB_CONFIG_FILE) ;
++ assertTrue(FileOps.exists(fn)) ;
++
++ StoreParams pLoc2 = StoreParamsCodec.read(loc) ;
++ assertFalse(StoreParams.sameValues(pLoc, p)) ;
++ assertEquals(0, p.getBlockSize().intValue()) ; // Location
++ assertEquals(12, p.getNodeMissCacheSize().intValue()) ; // Application
++ }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java
index 0000000,0000000..071b135
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java
@@@ -1,0 -1,0 +1,180 @@@
++/*
++ * 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.setup;
++
++import static org.junit.Assert.assertEquals ;
++import static org.junit.Assert.assertFalse ;
++import static org.junit.Assert.assertNotEquals ;
++import static org.junit.Assert.assertNotNull ;
++import static org.junit.Assert.assertNull ;
++import static org.junit.Assert.assertTrue ;
++
++import java.nio.file.Files ;
++import java.nio.file.Path ;
++import java.nio.file.Paths ;
++
++import org.apache.jena.atlas.json.JSON ;
++import org.apache.jena.atlas.json.JsonObject ;
++import org.apache.jena.atlas.lib.FileOps ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.sys.Names;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.sys.StoreConnection ;
++import org.seaborne.tdb2.sys.TDBInternal ;
++
++/**
++ * This test suite uses on-disk structures, does a lot of clean/create/sync
++ * calls and can be noticably slow.
++ */
++public class TestStoreParamsCreate {
++ // Thse tests work on storage locations.
++ private final String DB_DIR = ConfigTest.getCleanDir() ;
++ private final Path db = Paths.get(DB_DIR) ;
++ private final Path cfg = Paths.get(DB_DIR, Names.TDB_CONFIG_FILE) ;
++ private final Location loc = Location.create(DB_DIR) ;
++
++ static final StoreParams pApp = StoreParams.getSmallStoreParams() ;
++ static final StoreParams pDft = StoreParams.getDftStoreParams() ;
++ static final StoreParams pSpecial = StoreParams.builder(pApp)
++ .blockSize(1024)
++ .blockReadCacheSize(4)
++ .build();
++
++ private void expel() {
++ StoreConnection.internalExpel(loc, true);
++ }
++
++ @Before public void clearupTest() {
++ // Flush and clean.
++ TDBInternal.reset();
++ FileOps.clearAll(loc.getDirectoryPath());
++ }
++
++ @After public void expelDatabase() {
++ expel();
++ }
++
++ @Test public void params_create_01() {
++ StoreConnection.connectCreate(loc) ;
++ // Check. Default setup, no params.
++ assertTrue("DB directory", Files.exists(db)) ;
++ assertFalse("Config file unexpectedly found", Files.exists(cfg)) ;
++ }
++
++ @Test public void params_create_02() {
++ StoreConnection.connectCreate(loc, pApp) ;
++ // Check. Custom setup.
++ assertTrue("DB directory", Files.exists(db)) ;
++ assertTrue("Config file not found", Files.exists(cfg)) ;
++ StoreParams pLoc = StoreParamsCodec.read(loc) ;
++ assertTrue(StoreParams.sameValues(pLoc, pApp)) ;
++ }
++
++ // Defaults
++ @Test public void params_reconnect_01() {
++ // Create.
++ StoreConnection.connectCreate(loc) ;
++ // Drop.
++ expel();
++ // Reconnect
++ StoreConnection.connectCreate(loc, null) ;
++ StoreParams pLoc = StoreParamsCodec.read(loc) ;
++ assertNull(pLoc) ;
++
++ StoreParams pDB = StoreConnection.connectExisting(loc).getDatasetGraphTDB().getStoreParams() ;
++ assertNotNull(pDB) ;
++ // Should be the default setup.
++ assertTrue(StoreParams.sameValues(pDft, pDB)) ;
++ }
++
++ // Defaults, then reconnect with app modified.
++ @Test public void params_reconnect_02() {
++ // Create.
++ StoreConnection.connectCreate(loc, null) ;
++ // Drop.
++ expel();
++ // Reconnect
++ StoreConnection.connectCreate(loc, pSpecial) ;
++ //StoreParams pLoc = StoreParamsCodec.read(loc) ;
++ //assertNotNull(pLoc) ;
++
++ StoreParams pDB = StoreConnection.connectExisting(loc).getDatasetGraphTDB().getStoreParams() ;
++ assertNotNull(pDB) ;
++ // Should be the default setup, modified by pApp for cache sizes.
++ assertFalse(StoreParams.sameValues(pDft, pDB)) ;
++ assertFalse(StoreParams.sameValues(pSpecial, pDB)) ;
++
++ // Check it's default-modified-by-special.
++ assertEquals(pSpecial.getBlockReadCacheSize(), pDB.getBlockReadCacheSize()) ;
++ assertNotEquals(pDft.getBlockReadCacheSize(), pDB.getBlockReadCacheSize()) ;
++
++ assertNotEquals(pSpecial.getBlockSize(), pDB.getBlockSize()) ;
++ assertEquals(pDft.getBlockSize(), pDB.getBlockSize()) ;
++ }
++
++ // Custom, then reconnect with some special settings.
++ @Test public void params_reconnect_03() {
++ // Create.
++ StoreConnection.connectCreate(loc, pApp) ;
++ // Drop.
++ expel();
++ // Reconnect
++ StoreConnection.connectCreate(loc, pSpecial) ;
++ //StoreParams pLoc = StoreParamsCodec.read(loc) ;
++ //assertNotNull(pLoc) ;
++
++ StoreParams pDB = StoreConnection.connectExisting(loc).getDatasetGraphTDB().getStoreParams() ;
++ assertNotNull(pDB) ;
++ // Should be the default setup, modified by pApp for cache sizes.
++ assertFalse(StoreParams.sameValues(pApp, pDB)) ;
++ assertFalse(StoreParams.sameValues(pSpecial, pDB)) ;
++
++ // Check it's default-modified-by-special.
++ assertEquals(pSpecial.getBlockReadCacheSize(), pDB.getBlockReadCacheSize()) ;
++ assertNotEquals(pApp.getBlockReadCacheSize(), pDB.getBlockReadCacheSize()) ;
++
++ assertNotEquals(pSpecial.getBlockSize(), pDB.getBlockSize()) ;
++ assertEquals(pApp.getBlockSize(), pDB.getBlockSize()) ;
++ }
++
++
++// // Custom then modified.
++// @Test public void params_reconnect_03() {
++// // Create.
++// StoreConnection.connectCreate(loc, pLoc) ;
++// // Drop.
++// StoreConnection.expel(loc, true) ;
++// // Reconnect
++// StoreConnection.connectCreate(loc, pApp) ;
++// StoreParams pLoc = StoreParamsCodec.read(loc) ;
++// assertFalse(StoreParams.sameValues(pApp, pLoc)) ;
++// assertFalse(StoreParams.sameValues(pApp, pLoc)) ;
++// }
++
++ // Dataset tests
++
++ static StoreParams read(Location location) {
++ String fn = location.getPath(Names.TDB_CONFIG_FILE) ;
++ JsonObject obj = JSON.read(fn) ;
++ return StoreParamsCodec.decode(obj) ;
++ }
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/solver/TS_SolverTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/solver/TS_SolverTDB.java
index 0000000,0000000..f52d8ad
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/solver/TS_SolverTDB.java
@@@ -1,0 -1,0 +1,30 @@@
++/*
++ * 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.solver;
++
++import org.junit.runner.RunWith ;
++import org.junit.runners.Suite ;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestSolverTDB.class // Tests the TDB connectivity
++ , TestStats.class
++})
++
++public class TS_SolverTDB
++{}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/solver/TestSolverTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/solver/TestSolverTDB.java
index 0000000,0000000..43ef56d
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/solver/TestSolverTDB.java
@@@ -1,0 -1,0 +1,171 @@@
++/*
++ * 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.solver;
++
++
++import java.util.ArrayList ;
++import java.util.Iterator ;
++import java.util.List ;
++
++import static org.junit.Assert.*;
++import org.apache.jena.graph.Graph ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.graph.Triple ;
++import org.apache.jena.query.* ;
++import org.apache.jena.riot.RDFDataMgr ;
++import org.apache.jena.shared.PrefixMapping ;
++import org.apache.jena.shared.impl.PrefixMappingImpl ;
++import org.apache.jena.sparql.algebra.Algebra ;
++import org.apache.jena.sparql.algebra.Op ;
++import org.apache.jena.sparql.algebra.OpVars ;
++import org.apache.jena.sparql.core.Var ;
++import org.apache.jena.sparql.engine.QueryIterator ;
++import org.apache.jena.sparql.engine.binding.Binding ;
++import org.apache.jena.sparql.resultset.ResultSetCompare ;
++import org.apache.jena.sparql.sse.SSE ;
++import org.junit.AfterClass ;
++import org.junit.BeforeClass ;
++import org.junit.Test ;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.junit.TL ;
++
++public class TestSolverTDB
++{
++ static String graphData = null ;
++ static Graph graph = null ;
++ static Dataset dataset = null ;
++ static PrefixMapping pmap = null ;
++
++ @BeforeClass static public void beforeClass()
++ {
++ dataset = TL.createTestDatasetMem() ;
++ dataset.begin(ReadWrite.WRITE);
++ graphData = ConfigTest.getTestingDataRoot()+"/Data/solver-data.ttl" ;
++ RDFDataMgr.read(dataset, graphData) ;
++ graph = dataset.asDatasetGraph().getDefaultGraph() ;
++ pmap = new PrefixMappingImpl() ;
++ pmap.setNsPrefix("", "http://example/") ;
++ }
++
++
++ @AfterClass static public void afterClass() {
++ dataset.abort();
++ TL.expel(dataset);
++ }
++
++ static private void addAll(Graph srcGraph, Graph dstGraph)
++ {
++ Iterator<Triple> triples = srcGraph.find(Node.ANY, Node.ANY, Node.ANY) ;
++ triples.forEachRemaining(dstGraph::add) ;
++ }
++
++
++ @Test public void solve_01()
++ {
++ ResultSet rs1 = exec("(bgp (:s :p :o))", graph) ;
++ ResultSet rs2 = results("unit") ;
++ equals(rs1, rs2) ;
++ }
++
++ @Test public void solve_02()
++ {
++ ResultSet rs1 = exec("(bgp (:s :p :o2))", graph) ;
++ ResultSet rs2 = results("empty") ;
++ equals(rs1, rs2) ;
++ }
++
++ @Test public void solve_03()
++ {
++ // Above everything.
++ ResultSet rs1 = exec("(bgp (:zzzz :p 999999))", graph) ;
++ ResultSet rs2 = results("empty") ;
++ equals(rs1, rs2) ;
++ }
++
++ @Test public void solve_04()
++ {
++ // Below everything.
++ ResultSet rs1 = exec("(bgp (:a :p :a))", graph) ;
++ ResultSet rs2 = results("empty") ;
++ equals(rs1, rs2) ;
++ }
++
++ @Test public void solve_05()
++ {
++ ResultSet rs1 = exec("(project (?s ?y) (bgp (?s :p ?z) (?z :q ?y)))", graph) ;
++ ResultSet rs2 = results("(row (?s :s) (?y :y))") ;
++ equals(rs1, rs2) ;
++ }
++
++ @Test public void solve_06()
++ {
++ ResultSet rs1 = exec("(bgp (:s ?p ?o))", graph) ;
++ ResultSet rs2 = results("(row (?p :p) (?o :o))",
++ "(row (?p :p) (?o 10))",
++ "(row (?p :p) (?o :x))"
++ ) ;
++ equals(rs1, rs2) ;
++ }
++
++ // ------
++
++ private static void equals(ResultSet rs1, ResultSet rs2)
++ { same(rs1, rs2, true) ; }
++
++ private static void same(ResultSet rs1, ResultSet rs2, boolean result)
++ {
++ ResultSetRewindable rsw1 = ResultSetFactory.makeRewindable(rs1) ;
++ ResultSetRewindable rsw2 = ResultSetFactory.makeRewindable(rs2) ;
++ boolean b = ResultSetCompare.equalsByValue(rsw1, rsw2) ;
++ if ( b != result)
++ {
++ System.out.println("Different: ") ;
++ rsw1.reset() ;
++ rsw2.reset() ;
++ ResultSetFormatter.out(rsw1) ;
++ ResultSetFormatter.out(rsw2) ;
++ System.out.println() ;
++ }
++
++ assertTrue(b == result) ;
++ }
++
++ private static ResultSet results(String... rows)
++ {
++ String str = "(table "+String.join("", rows)+")" ;
++ return SSE.parseTable(str).toResultSet() ;
++ }
++
++
++ private static ResultSet exec(String pattern, Graph graph)
++ {
++ Op op = SSE.parseOp(pattern, pmap) ;
++ List<Var> vars = new ArrayList<>() ;
++ vars.addAll(OpVars.visibleVars(op)) ;
++ QueryIterator qIter = Algebra.exec(op, graph) ;
++ return ResultSetFactory.create(qIter, Var.varNames(vars)) ;
++ }
++
++ private static List<Binding> toList(QueryIterator qIter)
++ {
++ List<Binding> x = new ArrayList<>() ;
++ for ( ; qIter.hasNext() ; )
++ x.add(qIter.nextBinding()) ;
++ return x ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java
index 0000000,0000000..a9dfe92
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java
@@@ -1,0 -1,0 +1,117 @@@
++/*
++ * 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.solver;
++
++import static org.junit.Assert.assertEquals ;
++
++import java.util.Iterator ;
++
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.graph.NodeFactory ;
++import org.apache.jena.sparql.core.Quad ;
++import org.apache.jena.sparql.sse.SSE ;
++import org.junit.Test ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.tdb2.junit.TL ;
++import org.seaborne.tdb2.solver.stats.StatsCollectorNodeId ;
++import org.seaborne.tdb2.solver.stats.StatsResults ;
++import org.seaborne.tdb2.store.DatasetGraphTDB ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.store.nodetable.NodeTable ;
++import org.seaborne.tdb2.store.nodetupletable.NodeTupleTable ;
++import org.seaborne.tdb2.sys.TDBInternal ;
++
++public class TestStats
++{
++ static DatasetGraphTDB dsg = TDBInternal.getDatasetGraphTDB(TL.createTestDatasetGraphMem()) ;
++ static NodeTupleTable quads = dsg.getQuadTable().getNodeTupleTable() ;
++ static NodeTupleTable triples = dsg.getTripleTable().getNodeTupleTable() ;
++ static NodeTable nt = quads.getNodeTable() ;
++
++ static Quad q1 = SSE.parseQuad("(<g1> <s> <p> 1)") ;
++ static Quad q2 = SSE.parseQuad("(<g2> <s> <p> 2)") ;
++ static Quad q3 = SSE.parseQuad("(<g2> <s> <p> 9)") ;
++ static Quad q4 = SSE.parseQuad("(_ <s> <p> 1)") ;
++ static {
++ Txn.executeWrite(dsg, ()->{
++ dsg.add(q1) ;
++ dsg.add(q2) ;
++ dsg.add(q3) ;
++ dsg.add(q4) ;
++ });
++ }
++
++ private StatsResults statsForGraph(NodeId gid) {
++ // StatsCollectorNodeId writes nodes for rdf:type (this is not good).
++ return Txn.calculateWrite(dsg, ()-> {
++ Iterator<Tuple<NodeId>> iter = quads.find(gid, null, null, null) ;
++
++ StatsCollectorNodeId stats = new StatsCollectorNodeId(nt) ;
++ for ( ; iter.hasNext() ; ) {
++ Tuple<NodeId> t = iter.next() ;
++ stats.record(t.get(0), t.get(1), t.get(2), t.get(3)) ;
++ }
++
++ return stats.results() ;
++ }) ;
++ }
++
++ private StatsResults statsForDftGraph() {
++ // StatsCollectorNodeId writes nodes for rdf:type (this is not good).
++ return Txn.calculateWrite(dsg, ()-> {
++ Iterator<Tuple<NodeId>> iter = triples.findAll() ;
++
++ StatsCollectorNodeId stats = new StatsCollectorNodeId(nt) ;
++ for ( ; iter.hasNext() ; ) {
++ Tuple<NodeId> t = iter.next() ;
++ stats.record(null, t.get(0), t.get(1), t.get(2)) ;
++ }
++
++ return stats.results() ;
++ }) ;
++ }
++
++ @Test public void stats_01() {
++ StatsResults r = statsForDftGraph() ;
++ assertEquals(1, r.getCount()) ;
++ assertEquals(1, r.getPredicates().keySet().size()) ;
++ }
++
++ @Test public void stats_02() {
++ NodeId gid = nt.getNodeIdForNode(NodeFactory.createURI("g1")) ;
++ StatsResults r = statsForGraph(gid) ;
++ assertEquals(1, r.getCount()) ;
++ assertEquals(1, r.getPredicates().keySet().size()) ;
++ }
++
++ @Test public void stats_03() {
++ NodeId gid = nt.getNodeIdForNode(NodeFactory.createURI("g2")) ;
++ StatsResults r = statsForGraph(gid) ;
++ assertEquals(2, r.getCount()) ;
++ assertEquals(1, r.getPredicates().keySet().size()) ;
++ }
++
++ @Test public void stats_04() {
++ StatsResults r = statsForGraph(null) ;
++ assertEquals(3, r.getCount()) ;
++ assertEquals(1, r.getPredicates().keySet().size()) ;
++ }
++
++}
++
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java
index 0000000,0000000..792fef4
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java
@@@ -1,0 -1,0 +1,185 @@@
++/*
++ * 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 org.junit.Assert.*;
++import org.apache.jena.query.ReadWrite ;
++import org.apache.jena.sparql.core.Quad ;
++import org.apache.jena.sparql.sse.SSE ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.tdb2.sys.StoreConnection ;
++import org.seaborne.tdb2.sys.TDBInternal ;
++
++/** StoreConnection and transactions - basic wiring.
++ * These tests are slow on rotational disk.
++ * Complet cleaning of file areas is done.
++ */
++public abstract class AbstractTestStoreConnectionBasics
++{
++ // Subclass to give direct and mapped versions.
++
++ // Per-test unique-ish.
++ static int count = 0 ;
++ long x = System.currentTimeMillis()+(count++) ;
++
++ Quad q = SSE.parseQuad("(<g> <s> <p> '000-"+x+"') ") ;
++ Quad q1 = SSE.parseQuad("(<g> <s> <p> '111-"+x+"')") ;
++ Quad q2 = SSE.parseQuad("(<g> <s> <p> '222-"+x+"')") ;
++ Quad q3 = SSE.parseQuad("(<g> <s> <p> '333-"+x+"')") ;
++ Quad q4 = SSE.parseQuad("(<g> <s> <p> '444-"+x+"')") ;
++
++ Location location = null ;
++
++ protected abstract Location getLocation() ;
++
++ @Before public void before()
++ {
++ TDBInternal.reset() ;
++ location = getLocation() ;
++ }
++
++ @After public void after() { TDBInternal.reset() ; }
++
++ @Test
++ public void store_01()
++ {
++ StoreConnection sConn = StoreConnection.connectCreate(location) ;
++ assertNotNull(sConn);
++ StoreConnection.release(location) ;
++ StoreConnection sConn2 = StoreConnection.connectExisting(location) ;
++ assertNull(sConn2);
++ StoreConnection sConn3 = StoreConnection.connectCreate(location) ;
++ assertNotNull(sConn3);
++ }
++
++ @Test
++ public void store_02()
++ {
++ StoreConnection sConn = StoreConnection.connectCreate(location) ;
++
++ { // Isolate to stop mix ups on variables.
++ DatasetGraphTDB dsg = sConn.getDatasetGraphTDB() ;
++ Txn.executeWrite(dsg, ()->{
++ dsg.add(q1) ;
++ }) ;
++
++ Txn.executeWrite(dsg, ()->{
++ assertTrue(dsg.contains(q1)) ;
++ }) ;
++
++ Txn.executeRead(dsg, ()->{
++ assertTrue(dsg.contains(q1)) ;
++ }) ;
++ }
++
++ {
++ StoreConnection sConn2 = StoreConnection.connectCreate(location) ;
++ DatasetGraphTDB dsg2 = sConn.getDatasetGraphTDB() ;
++ Txn.executeRead(dsg2, ()->{
++ assertTrue(dsg2.contains(q1)) ;
++ }) ;
++ }
++
++ StoreConnection.release(sConn.getLocation()) ;
++ sConn = null ;
++
++ {
++ if ( ! location.isMem() ) {
++ StoreConnection sConn2 = StoreConnection.connectCreate(location) ;
++ DatasetGraphTDB dsg3 = sConn2.getDatasetGraphTDB() ;
++ Txn.executeRead(dsg3, ()->{
++ assertTrue(dsg3.contains(q1)) ;
++ }) ;
++ }
++ }
++ }
++
++ @Test
++ public void store_03()
++ {
++ StoreConnection sConn = StoreConnection.connectCreate(location) ;
++
++ DatasetGraphTDB dsg = sConn.getDatasetGraphTDB() ;
++ Txn.executeWrite(dsg, ()->{
++ dsg.add(q1) ;
++ }) ;
++
++ Txn.executeWrite(dsg, ()->{
++ assertTrue(dsg.contains(q1)) ;
++ }) ;
++
++ try {
++ Txn.executeWrite(dsg, ()->{
++ dsg.add(q2) ;
++ throw new RuntimeException() ;
++ }) ;
++ fail("Should not get to here!") ;
++ } catch (RuntimeException ex) {}
++
++ Txn.executeRead(dsg, ()->{
++ assertTrue(dsg.contains(q1)) ;
++ assertFalse(dsg.contains(q2)) ;
++ }) ;
++ }
++
++ @Test
++ public void store_04()
++ {
++ StoreConnection sConn = StoreConnection.connectCreate(location) ;
++
++ DatasetGraphTDB dsg = sConn.getDatasetGraphTDB() ;
++ Txn.executeWrite(dsg, ()->{
++ dsg.add(q1) ;
++ }) ;
++
++ Txn.executeWrite(dsg, ()->{
++ assertTrue(dsg.contains(q1)) ;
++ }) ;
++
++ dsg.begin(ReadWrite.WRITE);
++ dsg.add(q2) ;
++ dsg.abort() ;
++ dsg.end() ;
++
++ Txn.executeRead(dsg, ()->{
++ assertTrue(dsg.contains(q1)) ;
++ assertFalse(dsg.contains(q2)) ;
++ }) ;
++ }
++
++ @Test
++ public void store_05()
++ {
++ StoreConnection sConn = StoreConnection.connectCreate(location) ;
++
++ DatasetGraphTDB dsg = sConn.getDatasetGraphTDB() ;
++ Txn.executeWrite(dsg, ()->{
++ dsg.add(q3) ;
++ }) ;
++
++ Txn.executeWrite(dsg, ()->{
++ assertTrue(dsg.contains(q3)) ;
++ }) ;
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestTransPromoteTDB2.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestTransPromoteTDB2.java
index 0000000,0000000..7441a56
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestTransPromoteTDB2.java
@@@ -1,0 -1,0 +1,71 @@@
++/*
++ * 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.
++ */
++
++// **** COPIED from Jena 3.4.0 development.
++// After Mantis moves to 3.4.0 or later, this can be removed.
++
++//package org.apache.jena.sparql.transaction ;
++package org.seaborne.tdb2.store;
++
++import static org.junit.Assert.fail ;
++
++import org.apache.jena.query.ReadWrite ;
++import org.apache.jena.sparql.JenaTransactionException;
++import org.apache.jena.sparql.core.DatasetGraph ;
++import org.apache.jena.sparql.transaction.AbstractTestTransPromote;
++import org.apache.log4j.Logger ;
++import org.junit.Ignore;
++import org.junit.Test ;
++
++/** Tests for transactions that start read and then promote to write */
++public abstract class AbstractTestTransPromoteTDB2 extends AbstractTestTransPromote {
++
++ protected AbstractTestTransPromoteTDB2(Logger[] loggers) {
++ super(loggers);
++ }
++
++ // Copy in Jena 3.4.0 development
++ // write-end becomes an exception.
++
++ @Override
++ @Ignore
++ @Test public void promote_snapshot_05() { }
++ @Test public void promote_snapshot_05_x() { run_05_X(false) ; }
++
++ @Override
++ @Ignore
++ @Test public void promote_readCommitted_05() { }
++
++ @Test public void promote_readCommitted_05_x() { run_05_X(true) ; }
++
++ private void run_05_X(boolean readCommitted) {
++ //Assume.assumeTrue( ! readCommitted || supportsReadCommitted());
++
++ setReadCommitted(readCommitted);
++ DatasetGraph dsg = create() ;
++ dsg.begin(ReadWrite.READ) ;
++ dsg.add(q1) ;
++
++ try {
++ dsg.end() ;
++ fail("begin(W);end() did not throw an exception");
++ } catch ( JenaTransactionException ex) {}
++
++ assertCount(0, dsg) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TS_Store.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TS_Store.java
index 0000000,0000000..580b301
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TS_Store.java
@@@ -1,0 -1,0 +1,71 @@@
++/*
++ * 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 org.junit.AfterClass ;
++import org.junit.BeforeClass ;
++import org.junit.runner.RunWith ;
++import org.junit.runners.Suite ;
++import org.seaborne.dboe.base.block.FileMode ;
++import org.seaborne.tdb2.store.value.TestDoubleNode62;
++import org.seaborne.tdb2.store.value.TestNodeIdInline;
++import org.seaborne.tdb2.sys.SystemTDB ;
++import org.seaborne.tdb2.sys.TestOps ;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++ TestNodeId.class
++ , TestNodeIdInline.class
++ , TestDoubleNode62.class
++ , TestTripleTable.class
++ , TestGraphTDB.class
++ , TestGraphNamedTDB.class
++ , TestDatasetTDB.class
++ , TestDatasetTDBPersist.class
++ //, TestBulkLoader.class
++ // The script suite
++ , TestSuiteGraphTDB.class
++
++ , Test_SPARQL_TDB.class
++ , TestDynamicDatasetTDB.class
++ , TestStoreConnectionMem.class
++ , TestStoreConnectionDirect.class
++ , TestStoreConnectionMapped.class
++ , TestStoreConnectionLock.class
++ , TestTransactions.class
++ , TestTransactionLifecycleTDB.class
++ , TestTransPromoteTDB.class
++ , TestQuadFilter.class
++} )
++public class TS_Store
++{
++ static FileMode mode ;
++
++ @BeforeClass
++ public static void beforeClass()
++ {
++ mode = SystemTDB.fileMode() ;
++ }
++
++ @AfterClass
++ public static void afterClass()
++ {
++ if ( ! SystemTDB.fileMode().equals(mode) )
++ TestOps.setFileMode(mode) ;
++ }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDB.java
index 0000000,0000000..1ff5387
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDB.java
@@@ -1,0 -1,0 +1,323 @@@
++/*
++ * 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 org.junit.Assert.*;
++import org.apache.jena.query.* ;
++import org.apache.jena.rdf.model.Model ;
++import org.apache.jena.rdf.model.ModelFactory ;
++import org.apache.jena.rdf.model.Property ;
++import org.apache.jena.rdf.model.Resource ;
++import org.apache.jena.riot.Lang ;
++import org.apache.jena.riot.RDFDataMgr ;
++import org.apache.jena.sparql.core.Quad ;
++import org.apache.jena.sparql.sse.SSE ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.tdb2.TDB2 ;
++import org.seaborne.tdb2.junit.TL ;
++
++/** Tests of datasets, prefixes, special URIs etc (see also {@link org.apache.jena.sparql.graph.GraphsTests} */
++public class TestDatasetTDB
++{
++ private Dataset dataset ;
++
++ @Before public void before() {
++ dataset = TL.createTestDatasetMem() ;
++ dataset.begin(ReadWrite.WRITE);
++ }
++
++ @After public void after() {
++ dataset.abort();
++ dataset.end();
++ TL.expel(dataset);
++
++ }
++
++ private Dataset dataset() {
++ return dataset ;
++ }
++
++ private static void load(Model model, String file)
++ {
++ RDFDataMgr.read(model, file) ;
++ }
++
++ private static String base1 = "http://example/" ;
++ private static String baseNS = "http://example/ns#" ;
++
++ private static void load1(Model model)
++ {
++ model.setNsPrefix("", base1) ;
++ Resource r1 = model.createResource(base1+"r1") ;
++ Property p1 = model.createProperty(baseNS+"p1") ;
++ model.add(r1, p1, "x1") ;
++ model.add(r1, p1, "x2") ;
++ }
++
++ private static void load2(Model model)
++ {
++ Resource r2 = model.createResource(base1+"r2") ;
++ Property p1 = model.createProperty(baseNS+"p1") ;
++ model.add(r2, p1, "x1") ;
++ model.add(r2, p1, "x2") ;
++ }
++
++ private static void load3(Model model)
++ {
++ Resource r3 = model.createResource(base1+"r3") ;
++ Property p1 = model.createProperty(baseNS+"p2") ;
++ model.add(r3, p1, "x1") ;
++ model.add(r3, p1, "x2") ;
++ }
++
++ @Test public void prefix1()
++ {
++ Dataset ds = dataset() ;
++ Model m = ds.getDefaultModel() ;
++ load1(m) ;
++ String x = m.expandPrefix(":x") ;
++ assertEquals(x, base1+"x") ;
++ }
++
++ @Test public void prefix2()
++ {
++ Dataset ds = dataset() ;
++ Model m = ds.getDefaultModel() ;
++ load1(m) ;
++ Model m2 = ds.getNamedModel("http://example/graph/") ;
++ String x = m2.expandPrefix(":x") ;
++ assertEquals(x, ":x") ;
++ }
++
++ @Test public void query1()
++ {
++ Dataset ds = dataset() ;
++ Model m = ds.getDefaultModel() ;
++ load1(m) ;
++
++ String qs = "CONSTRUCT {?s ?p ?o } WHERE {?s ?p ?o}" ;
++ Query q = QueryFactory.create(qs) ;
++ QueryExecution qExec = QueryExecutionFactory.create(q, ds) ;
++ Model m2 = qExec.execConstruct() ;
++ assertTrue(m.isIsomorphicWith(m2)) ;
++ }
++
++ @Test public void query2()
++ {
++ Dataset ds = dataset() ;
++ Model m = ds.getDefaultModel() ;
++ load1(m) ;
++
++ String qs = "CONSTRUCT {?s ?p ?o } WHERE { GRAPH <http://example/graph/> {?s ?p ?o}}" ;
++ Query q = QueryFactory.create(qs) ;
++ QueryExecution qExec = QueryExecutionFactory.create(q, ds) ;
++ Model m2 = qExec.execConstruct() ;
++ assertTrue(m2.isEmpty()) ;
++ }
++
++ static String defaultGraph = Quad.defaultGraphIRI.getURI() ;
++ static String unionGraph = Quad.unionGraph.getURI() ;
++
++ @Test public void special1()
++ {
++ Dataset ds = dataset() ;
++ Model m = ds.getDefaultModel() ;
++ load1(m) ;
++
++ String qs = "CONSTRUCT {?s ?p ?o } WHERE { GRAPH <"+defaultGraph+"> {?s ?p ?o}}" ;
++ Query q = QueryFactory.create(qs) ;
++ QueryExecution qExec = QueryExecutionFactory.create(q, ds) ;
++ Model m2 = qExec.execConstruct() ;
++ assertTrue(m.isIsomorphicWith(m2)) ;
++ }
++
++ @Test public void special2()
++ {
++ Dataset ds = dataset() ;
++
++ load1(ds.getDefaultModel()) ;
++ load2(ds.getNamedModel("http://example/graph1")) ;
++ load3(ds.getNamedModel("http://example/graph2")) ;
++
++ Model m = ModelFactory.createDefaultModel() ;
++ load2(m) ;
++ load3(m) ;
++
++ String qs = "CONSTRUCT {?s ?p ?o } WHERE { GRAPH <"+unionGraph+"> {?s ?p ?o}}" ;
++ Query q = QueryFactory.create(qs) ;
++ QueryExecution qExec = QueryExecutionFactory.create(q, ds) ;
++ Model m2 = qExec.execConstruct() ;
++ assertTrue(m.isIsomorphicWith(m2)) ;
++ }
++
++ @Test public void special3()
++ {
++ Dataset ds = dataset() ;
++
++ load1(ds.getDefaultModel()) ;
++ load2(ds.getNamedModel("http://example/graph1")) ;
++ load3(ds.getNamedModel("http://example/graph2")) ;
++
++ Model m = ModelFactory.createDefaultModel() ;
++ load2(m) ;
++ load3(m) ;
++
++ String qs = "CONSTRUCT {?s ?p ?o } WHERE { ?s ?p ?o }" ;
++ Query q = QueryFactory.create(qs) ;
++ QueryExecution qExec = QueryExecutionFactory.create(q, ds) ;
++ qExec.getContext().set(TDB2.symUnionDefaultGraph, true) ;
++ Model m2 = qExec.execConstruct() ;
++ if ( ! m.isIsomorphicWith(m2) )
++ {
++ System.out.println("---- ----") ;
++ SSE.write(ds.asDatasetGraph()) ;
++ System.out.println("-- Expected") ;
++ m.write(System.out, "TTL") ;
++ System.out.println("-- Actual") ;
++ m2.write(System.out, "TTL") ;
++ System.out.println("---- ----") ;
++
++ }
++ assertTrue(m.isIsomorphicWith(m2)) ;
++ }
++
++ @Test public void special4()
++ {
++ Dataset ds = dataset() ;
++
++ load1(ds.getDefaultModel()) ;
++ load2(ds.getNamedModel("http://example/graph1")) ;
++ load3(ds.getNamedModel("http://example/graph2")) ;
++
++ Model m = ModelFactory.createDefaultModel() ;
++ load2(m) ;
++ load3(m) ;
++
++ String qs = "PREFIX : <"+baseNS+"> SELECT (COUNT(?x) as ?c) WHERE { ?x (:p1|:p2) 'x1' }" ;
++ Query q = QueryFactory.create(qs) ;
++
++ long c_m ;
++ // Model
++ try (QueryExecution qExec = QueryExecutionFactory.create(q, m)) {
++ c_m = qExec.execSelect().next().getLiteral("c").getLong() ;
++ }
++
++ // dataset
++ long c_ds ;
++ try (QueryExecution qExec = QueryExecutionFactory.create(q, ds)) {
++ qExec.getContext().set(TDB2.symUnionDefaultGraph, true) ;
++ c_ds = qExec.execSelect().next().getLiteral("c").getLong() ;
++ }
++
++// String qs2 = "PREFIX : <"+baseNS+"> SELECT * WHERE { ?x (:p1|:p2) 'x1' }" ;
++// Query q2 = QueryFactory.create(qs2) ;
++// qExec = QueryExecutionFactory.create(q2, ds) ;
++// qExec.getContext().set(TDB.symUnionDefaultGraph, true) ;
++// ResultSetFormatter.out(qExec.execSelect()) ;
++//
++// qExec = QueryExecutionFactory.create(q2, m) ;
++// ResultSetFormatter.out(qExec.execSelect()) ;
++ // --------
++
++ assertEquals(c_m, c_ds) ;
++ }
++
++ @Test public void special5()
++ {
++ Dataset ds = dataset() ;
++
++ //load1(ds.getDefaultModel()) ;
++ load1(ds.getNamedModel("http://example/graph1")) ; // Same triples, different graph
++ load1(ds.getNamedModel("http://example/graph2")) ;
++
++ Model m = ds.getNamedModel(unionGraph) ;
++ assertEquals(2, m.size()) ;
++ }
++
++ // Put a model into a general dataset and use it.
++ @Test public void generalDataset1()
++ {
++ Dataset ds = dataset() ;
++ load1(ds.getDefaultModel()) ;
++ load2(ds.getNamedModel("http://example/graph1")) ;
++ load3(ds.getNamedModel("http://example/graph2")) ;
++ Model m = ds.getNamedModel("http://example/graph2") ;
++
++ // Use graph2 as default model.
++ Dataset ds2 = DatasetFactory.create() ;
++ ds2.setDefaultModel(ds.getNamedModel("http://example/graph2")) ;
++
++ String qs = "CONSTRUCT {?s ?p ?o } WHERE { ?s ?p ?o}" ;
++ Query q = QueryFactory.create(qs) ;
++ QueryExecution qExec = QueryExecutionFactory.create(q, ds2) ;
++ Model m2 = qExec.execConstruct() ;
++ assertTrue(m.isIsomorphicWith(m2)) ;
++ }
++
++ @Test public void generalDataset2()
++ {
++ Dataset ds = dataset() ;
++ load1(ds.getDefaultModel()) ;
++ load2(ds.getNamedModel("http://example/graph1")) ;
++ load3(ds.getNamedModel("http://example/graph2")) ;
++ Model m = ds.getNamedModel("http://example/graph2") ;
++
++ // Use graph1 as a differently named model.
++ Dataset ds2 = DatasetFactory.create() ;
++ ds2.addNamedModel("http://example/graphOther", m) ;
++
++ String qs = "CONSTRUCT {?s ?p ?o } WHERE { {?s ?p ?o} UNION { GRAPH <http://example/graphOther> {?s ?p ?o} } }" ;
++ Query q = QueryFactory.create(qs) ;
++ QueryExecution qExec = QueryExecutionFactory.create(q, ds2) ;
++ Model m2 = qExec.execConstruct() ;
++ if ( ! m.isIsomorphicWith(m2) )
++ {
++ System.out.println(m.getGraph().getClass().getSimpleName()+"/"+m.size()+" : "+m2.getGraph().getClass().getSimpleName()+"/"+m2.size()) ;
++ System.out.println("---- Different:" ) ;
++ RDFDataMgr.write(System.out, m, Lang.TTL) ;
++ System.out.println("---- ----" ) ;
++ RDFDataMgr.write(System.out, m2, Lang.TTL) ;
++ System.out.println("---- ----") ;
++ }
++
++ assertTrue(m.isIsomorphicWith(m2)) ;
++ }
++
++ @Test public void generalDataset3()
++ {
++ Dataset ds = dataset() ;
++ load1(ds.getDefaultModel()) ;
++ load2(ds.getNamedModel("http://example/graph1")) ;
++ load3(ds.getNamedModel("http://example/graph2")) ;
++ Model m = ds.getDefaultModel() ;
++
++ // Use the default model in one dataset as a named model in another.
++ Dataset ds2 = DatasetFactory.create() ;
++ ds2.addNamedModel("http://example/graphOther", m) ;
++
++ String qs = "CONSTRUCT {?s ?p ?o } WHERE { {?s ?p ?o} UNION { GRAPH <http://example/graphOther> {?s ?p ?o} } }" ;
++ Query q = QueryFactory.create(qs) ;
++ QueryExecution qExec = QueryExecutionFactory.create(q, ds2) ;
++ Model m2 = qExec.execConstruct() ;
++ assertTrue(m.isIsomorphicWith(m2)) ;
++ }
++
++ // removeAll
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDBPersist.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDBPersist.java
index 0000000,0000000..81a5dd5
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDBPersist.java
@@@ -1,0 -1,0 +1,111 @@@
++/*
++ * 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 org.junit.Assert.assertFalse ;
++import static org.junit.Assert.assertTrue ;
++
++import org.apache.jena.graph.Graph ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.graph.Triple ;
++import org.apache.jena.sparql.util.NodeFactoryExtra ;
++import org.junit.Test ;
++import org.seaborne.tdb2.junit.TL ;
++
++/** Testing persistence */
++public class TestDatasetTDBPersist
++{
++ static Node n0 = NodeFactoryExtra.parseNode("<http://example/n0>") ;
++ static Node n1 = NodeFactoryExtra.parseNode("<http://example/n1>") ;
++ static Node n2 = NodeFactoryExtra.parseNode("<http://example/n2>") ;
++
++ @Test
++ public void dataset1() {
++ TL.exec((ds) -> {
++ assertTrue(ds.getDefaultModel().getGraph() instanceof GraphViewSwitchable) ;
++ assertTrue(ds.getNamedModel("http://example/").getGraph() instanceof GraphViewSwitchable) ;
++ }) ;
++ }
++
++ @Test
++ public void dataset2() {
++ TL.exec((ds) -> {
++ Graph g1 = ds.getDefaultModel().getGraph() ;
++ Graph g2 = ds.getNamedModel("http://example/").getGraph() ;
++
++ g1.add(new Triple(n0, n1, n2)) ;
++ assertTrue(g1.contains(n0, n1, n2)) ;
++ assertFalse(g2.contains(n0, n1, n2)) ;
++ }) ;
++ }
++
++// @Test
++// public void dataset3() {
++// TL.exec((ds) -> {
++// Graph g1 = ds.getDefaultModel().getGraph() ;
++// // Sometimes, under windows, deleting the files by
++// // clearDirectory does not work.
++// // Needed for safe tests on windows.
++// g1.clear() ;
++//
++// Graph g2 = ds.getNamedModel("http://example/").getGraph() ;
++// g2.add(new Triple(n0, n1, n2)) ;
++// assertTrue(g2.contains(n0, n1, n2)) ;
++// assertFalse(g1.contains(n0, n1, n2)) ;
++// }) ;
++// }
++//
++// @Test
++// public void dataset4() {
++// String graphName = "http://example/" ;
++// Triple triple = SSE.parseTriple("(<x> <y> <z>)") ;
++// Node gn = org.apache.jena.graph.NodeFactory.createURI(graphName) ;
++//
++// TL.exec((ds) -> {
++// // ?? See TupleLib.
++// ds.asDatasetGraph().deleteAny(gn, null, null, null) ;
++//
++// Graph g2 = ds.asDatasetGraph().getGraph(gn) ;
++//
++// // Graphs only exists if they have a triple in them
++// assertFalse(ds.containsNamedModel(graphName)) ;
++//
++// List<String> names = Iter.toList(ds.listNames()) ;
++// assertEquals(0, names.size()) ;
++// assertEquals(0, ds.asDatasetGraph().size()) ;
++// }) ;
++// }
++//
++// @Test
++// public void dataset5() {
++// String graphName = "http://example/" ;
++// Triple triple = SSE.parseTriple("(<x> <y> <z>)") ;
++// TL.exec((ds) -> {
++// Graph g2 = ds.asDatasetGraph().getGraph(org.apache.jena.graph.NodeFactory.createURI(graphName)) ;
++// // Graphs only exists if they have a triple in them
++// g2.add(triple) ;
++//
++// assertTrue(ds.containsNamedModel(graphName)) ;
++// List<String> x = Iter.toList(ds.listNames()) ;
++// List<String> y = Arrays.asList(graphName) ;
++// assertEquals(x, y) ;
++//
++// assertEquals(1, ds.asDatasetGraph().size()) ;
++// }) ;
++// }
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestDynamicDatasetTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestDynamicDatasetTDB.java
index 0000000,0000000..d0376e9
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestDynamicDatasetTDB.java
@@@ -1,0 -1,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 org.apache.jena.query.Dataset ;
++import org.apache.jena.query.ReadWrite ;
++import org.apache.jena.sparql.core.AbstractTestDynamicDataset ;
++import org.seaborne.tdb2.TDB2 ;
++import org.seaborne.tdb2.junit.TL ;
++
++public class TestDynamicDatasetTDB extends AbstractTestDynamicDataset
++{
++ @Override
++ protected Dataset createDataset()
++ {
++ Dataset ds = TL.createTestDatasetMem() ;
++ ds.begin(ReadWrite.WRITE);
++ return ds;
++ }
++
++ @Override
++ protected void releaseDataset(Dataset ds) { ds.abort(); TL.expel(ds); }
++
++ protected void startDynamicAndUnionTest() { TDB2.getContext().setTrue(TDB2.symUnionDefaultGraph) ; }
++
++ protected void finishDynamicAndUnionTest() { TDB2.getContext().unset(TDB2.symUnionDefaultGraph) ; }
++
++}
++
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphNamedTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphNamedTDB.java
index 0000000,0000000..d844c5a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphNamedTDB.java
@@@ -1,0 -1,0 +1,60 @@@
++/*
++ * 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 org.apache.jena.graph.Graph ;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.query.Dataset ;
++import org.apache.jena.query.ReadWrite ;
++import org.apache.jena.sparql.graph.AbstractTestGraph2 ;
++import org.apache.jena.sparql.util.NodeFactoryExtra ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.seaborne.tdb2.junit.TL ;
++
++/** Programmatic tests on persistent graph */
++public class TestGraphNamedTDB extends AbstractTestGraph2
++{
++ static Node graphNode = NodeFactoryExtra.parseNode("<http://example/namedGraph>") ;
++ private Dataset dataset ;
++ private Graph graph ;
++
++ @Before
++ public void before() {
++ dataset = TL.createTestDatasetMem() ;
++ dataset.begin(ReadWrite.WRITE);
++ graph = dataset.asDatasetGraph().getGraph(graphNode) ;
++ }
++
++ @After
++ public void after() {
++ dataset.abort();
++ dataset.end();
++ TL.expel(dataset) ;
++ }
++
++ @Override
++ protected Graph emptyGraph() {
++ graph.clear() ;
++ return graph ;
++ }
++
++ @Override
++ protected void returnGraph(Graph g)
++ {}
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphTDB.java
index 0000000,0000000..7f941eb
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestGraphTDB.java
@@@ -1,0 -1,0 +1,57 @@@
++/*
++ * 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 org.apache.jena.graph.Graph ;
++import org.apache.jena.query.Dataset ;
++import org.apache.jena.query.ReadWrite ;
++import org.apache.jena.sparql.graph.AbstractTestGraph2 ;
++import org.junit.After ;
++import org.junit.Before ;
++import org.seaborne.tdb2.junit.TL ;
++
++/** Programmatic tests on graphs */
++public class TestGraphTDB extends AbstractTestGraph2
++{
++ private Dataset dataset ;
++ private Graph graph ;
++
++ @Before
++ public void before() {
++ dataset = TL.createTestDatasetMem() ;
++ dataset.begin(ReadWrite.WRITE);
++ graph = dataset.getDefaultModel().getGraph() ;
++ }
++
++ @After
++ public void after() {
++ dataset.abort();
++ dataset.end();
++ TL.expel(dataset) ;
++ }
++
++ @Override
++ protected Graph emptyGraph() {
++ graph.clear() ;
++ return graph ;
++ }
++
++ @Override
++ protected void returnGraph(Graph g)
++ {}
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestNodeId.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestNodeId.java
index 0000000,0000000..56cf166
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestNodeId.java
@@@ -1,0 -1,0 +1,127 @@@
++/*
++ * 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 org.junit.Assert.assertEquals;
++import static org.junit.Assert.assertFalse;
++
++import java.nio.ByteBuffer;
++
++import org.apache.jena.atlas.lib.BitsLong;
++import org.apache.jena.graph.Node;
++import org.apache.jena.sparql.util.NodeFactoryExtra;
++import org.junit.Test ;
++
++public class TestNodeId
++{
++ // Pointers.
++ @Test public void nodeId_ptr_01() {
++ NodeId nodeId = NodeIdFactory.createPtrLong(17, 37);
++ assertEquals(NodeIdType.PTR, nodeId.type());
++// assertEquals(37L, nodeId.getPtrLo());
++// assertEquals(17, nodeId.getPtrHi());
++ assertEquals(37L, nodeId.getValue2());
++ assertEquals(17, nodeId.getValue1());
++ }
++
++ @Test public void nodeId_ptr_02() {
++ NodeId nodeId = NodeIdFactory.createPtr(37);
++ assertEquals(NodeIdType.PTR, nodeId.type());
++// assertEquals(37L, nodeId.getPtrLo());
++// assertEquals(0, nodeId.getPtrHi());
++ assertEquals(37L, nodeId.getPtrLocation());
++ }
++
++ @Test public void nodeId_ptr_03() {
++ NodeId nodeId = NodeIdFactory.createPtr(39);
++ // 64 bit
++ long x = nodeId.getValue2();
++ long t = BitsLong.unpack(x, 56, 64);
++ assertEquals(0, t);
++ assertEquals(NodeIdType.PTR.type(), t);
++ }
++
++ // Specials.
++ @Test public void nodeId_special_01() {
++ assertFalse(NodeId.isConcrete(NodeId.NodeDoesNotExist));
++ assertEquals(NodeIdType.SPECIAL, NodeId.NodeDoesNotExist.type());
++ }
++
++ @Test public void nodeId_special_02() {
++ assertFalse(NodeId.isConcrete(NodeId.NodeIdAny));
++ assertEquals(NodeIdType.SPECIAL, NodeId.NodeIdAny.type());
++ }
++
++ // Storage
++
++ @Test public void nodeId_codec_01() { testCodecArray(NodeIdFactory.createPtr(37)); }
++
++ @Test public void nodeId_codec_02() { testCodecArray(NodeId.createRaw(NodeIdType.XSD_INTEGER, 1)); }
++
++ // 56 bit -1.
++ @Test public void nodeId_codec_03() { testCodecArray(NodeId.createRaw(NodeIdType.XSD_INTEGER, BitsLong.clear(-1L, 56,64))); }
++
++ @Test public void nodeId_codec_04() { testCodecArray("12.34"); }
++
++ @Test public void nodeId_codec_05() { testCodecArray("'2.2'^^xsd:float"); }
++
++ private static void testCodecArray(String str) {
++ Node n = NodeFactoryExtra.parseNode(str);
++ NodeId nid = NodeIdInline.inline(n);
++ testCodecArray(nid);
++ }
++
++ private static void testCodecArray(NodeId nid) {
++ testCodecArray(nid, nid);
++ }
++
++ private static void testCodecArray(NodeId testNid,NodeId expected) {
++ byte[] b = new byte[8];
++ NodeIdFactory.set(testNid, b);
++ NodeId nid1 = NodeIdFactory.get(b);
++ assertEquals(expected, nid1);
++ }
++
++ @Test public void nodeId_codec_11() { testCodecBuffer(NodeIdFactory.createPtr(37)); }
++
++ @Test public void nodeId_codec_12() { testCodecBuffer(NodeId.createRaw(NodeIdType.XSD_INTEGER, 1)); }
++
++ @Test public void nodeId_codec_13() { testCodecBuffer(NodeId.createRaw(NodeIdType.XSD_INTEGER, BitsLong.clear(-1L, 56,64))); }
++
++ @Test public void nodeId_codec_14() { testCodecBuffer("12.34"); }
++
++ @Test public void nodeId_codec_15() { testCodecBuffer("'2.2'^^xsd:float"); }
++
++ private static void testCodecBuffer(String str) {
++ Node n = NodeFactoryExtra.parseNode(str);
++ NodeId nid = NodeIdInline.inline(n);
++ testCodecArray(nid);
++ }
++
++ private static void testCodecBuffer(NodeId nid) {
++ testCodecArray(nid, nid);
++ }
++
++ private static void testCodecBuffer(NodeId testNid,NodeId expected) {
++ ByteBuffer b = ByteBuffer.allocate(8);
++ NodeIdFactory.set(testNid, b);
++ NodeId nid1 = NodeIdFactory.get(b);
++ assertEquals(expected, nid1);
++ }
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestQuadFilter.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestQuadFilter.java
index 0000000,0000000..78ee4c4
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestQuadFilter.java
@@@ -1,0 -1,0 +1,110 @@@
++/*
++ * 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.function.Predicate ;
++
++import static org.junit.Assert.*;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.graph.NodeFactory ;
++import org.apache.jena.query.* ;
++import org.apache.jena.sparql.core.Quad ;
++import org.apache.jena.sparql.sse.SSE ;
++import org.apache.jena.system.Txn;
++import org.junit.AfterClass ;
++import org.junit.BeforeClass ;
++import org.junit.Ignore;
++import org.junit.Test ;
++import org.seaborne.tdb2.TDB2 ;
++import org.seaborne.tdb2.TDB2Factory ;
++import org.seaborne.tdb2.store.nodetable.NodeTable ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++
++@Ignore("Quad filter tests not ready (transactions)")
++public class TestQuadFilter
++{
++ private static String graphToHide = "http://example/g2" ;
++ private static Dataset ds = setup() ;
++
++
++ @BeforeClass public static void beforeClass()
++ {
++
++ }
++
++ @AfterClass public static void afterClass() {}
++
++ /** Example setup - in-memory dataset with two graphs, one triple in each */
++ private static Dataset setup()
++ {
++ Dataset ds = TDB2Factory.createDataset() ;
++ DatasetGraphTDB dsg = (DatasetGraphTDB)(ds.asDatasetGraph()) ;
++ Txn.executeWrite(dsg, ()->{
++ Quad q1 = SSE.parseQuad("(<http://example/g1> <http://example/s> <http://example/p> <http://example/o1>)") ;
++ Quad q2 = SSE.parseQuad("(<http://example/g2> <http://example/s> <http://example/p> <http://example/o2>)") ;
++ dsg.add(q1) ;
++ dsg.add(q2) ;
++ });
++ return ds ;
++ }
++
++ /** Create a filter to exclude the graph http://example/g2 */
++ private static Predicate<Tuple<NodeId>> createFilter(Dataset ds)
++ {
++ DatasetGraphTDB dsg = (DatasetGraphTDB)(ds.asDatasetGraph()) ;
++ final NodeTable nodeTable = dsg.getQuadTable().getNodeTupleTable().getNodeTable() ;
++ final NodeId target = nodeTable.getNodeIdForNode(NodeFactory.createURI(graphToHide)) ;
++ return item -> !( item.len() == 4 && item.get(0).equals(target) );
++ }
++
++ @Test public void quad_filter_1() { test("SELECT * { GRAPH ?g { ?s ?p ?o } }", 1, 2) ; }
++ @Test public void quad_filter_2() { test("SELECT * { ?s ?p ?o }", 1, 2) ; }
++ @Test public void quad_filter_3() { test("SELECT * { GRAPH ?g { } }", 1, 2) ; }
++
++ private void test(String qs, int withFilter, int withoutFilter)
++ {
++ Predicate<Tuple<NodeId>> filter = createFilter(ds) ;
++
++// private static void example(Dataset ds, Filter<Tuple<NodeId>> filter)
++// {
++// String[] x = {
++// "SELECT * { GRAPH ?g { ?s ?p ?o } }",
++// "SELECT * { ?s ?p ?o }",
++// // THis filter does not hide the graph itself, just the quads associated with the graph.
++// "SELECT * { GRAPH ?g {} }"
++// } ;
++ Query query = QueryFactory.create(qs) ;
++
++ try(QueryExecution qExec = QueryExecutionFactory.create(query, ds)) {
++ // Install filter for this query only.
++ qExec.getContext().set(SystemTDB.symTupleFilter, filter) ;
++ qExec.getContext().setTrue(TDB2.symUnionDefaultGraph) ;
++ long x1 = ResultSetFormatter.consume(qExec.execSelect()) ;
++ assertEquals(withFilter, x1) ;
++ }
++ // No filter.
++ try(QueryExecution qExec = QueryExecutionFactory.create(query, ds)) {
++ qExec.getContext().setTrue(TDB2.symUnionDefaultGraph) ;
++ long x2 = ResultSetFormatter.consume(qExec.execSelect()) ;
++ assertEquals(withoutFilter, x2) ;
++ }
++
++ }
++
++
++}
http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionDirect.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionDirect.java
index 0000000,0000000..ccf1b41
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionDirect.java
@@@ -1,0 -1,0 +1,47 @@@
++/*
++ * 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 org.junit.AfterClass ;
++import org.junit.BeforeClass ;
++import org.seaborne.dboe.base.block.FileMode ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++import org.seaborne.tdb2.sys.TestOps ;
++
++/** Slow tests - complete cleaning of disk areas each time */
++public class TestStoreConnectionDirect extends AbstractTestStoreConnectionBasics {
++ static FileMode mode ;
++
++ @BeforeClass
++ public static void beforeClassFileMode() {
++ mode = SystemTDB.fileMode() ;
++ TestOps.setFileMode(FileMode.direct) ;
++ }
++
++ @AfterClass
++ public static void afterClassFileMode() {
++ TestOps.setFileMode(mode) ;
++ }
++
++ @Override
++ protected Location getLocation() {
++ return Location.create(ConfigTest.getCleanDir()) ;
++ }
++}
[12/50] [abbrv] jena git commit: Switch off DatasetControl
Posted by an...@apache.org.
Switch off DatasetControl
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/4e8fc3b3
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/4e8fc3b3
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/4e8fc3b3
Branch: refs/heads/jena-tdb2
Commit: 4e8fc3b3a00016c68c2af5c5a887dc1e34f82d76
Parents: eee1a6a
Author: Andy Seaborne <an...@seaborne.org>
Authored: Sun Sep 3 22:08:23 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Sun Sep 3 22:08:23 2017 +0100
----------------------------------------------------------------------
tdb2/src/main/java/org/seaborne/tdb2/setup/TDBBuilder.java | 2 +-
.../main/java/org/seaborne/tdb2/store/nodetable/NodeTableSSE.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/4e8fc3b3/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 66c5c89..67ee708 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/setup/TDBBuilder.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/setup/TDBBuilder.java
@@ -143,7 +143,7 @@ public class TDBBuilder {
return new TDBBuilder(txnCoord, location, params, new ComponentIdMgr(UUID.randomUUID())) ;
}
- private DatasetControl createPolicy() { return new DatasetControlMRSW() ; }
+ private DatasetControl createPolicy() { return new DatasetControlNone() ; }
/** Look at a directory and see if it is a new area */
private static boolean isNewDatabaseArea(Location location) {
http://git-wip-us.apache.org/repos/asf/jena/blob/4e8fc3b3/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableSSE.java
----------------------------------------------------------------------
diff --git a/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableSSE.java b/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableSSE.java
index 336ac09..ed4577f 100644
--- a/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableSSE.java
+++ b/tdb2/src/main/java/org/seaborne/tdb2/store/nodetable/NodeTableSSE.java
@@ -50,7 +50,7 @@ public class NodeTableSSE extends NodeTableNative {
private ObjectFile objects ;
//private final Index nodeToId ;
- public NodeTableSSE(Index nodeToId, String filename)
+ private /*public*/ NodeTableSSE(Index nodeToId, String filename)
{
super(nodeToId);
BufferChannel file = BufferChannelFile.create(filename) ;
[08/50] [abbrv] jena git commit: Remove use of BaseTest
Posted by an...@apache.org.
Remove use of BaseTest
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/7624f540
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/7624f540
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/7624f540
Branch: refs/heads/jena-tdb2
Commit: 7624f54062ebda6ab9672b572e1a96a20cb01c78
Parents: 0d5a468
Author: Andy Seaborne <an...@seaborne.org>
Authored: Sat Sep 2 18:48:01 2017 +0100
Committer: Andy Seaborne <an...@seaborne.org>
Committed: Sat Sep 2 18:48:01 2017 +0100
----------------------------------------------------------------------
tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java | 4 ++--
tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java | 4 ++--
.../java/org/seaborne/tdb2/assembler/TestTDBAssembler.java | 4 ++--
tdb2/src/test/java/org/seaborne/tdb2/lib/TestNodeLib.java | 4 ++--
.../test/java/org/seaborne/tdb2/setup/TestStoreParams.java | 4 ++--
.../java/org/seaborne/tdb2/setup/TestStoreParamsChoose.java | 4 ++--
.../java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java | 4 ++--
.../src/test/java/org/seaborne/tdb2/solver/TestSolverTDB.java | 4 ++--
tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java | 4 ++--
.../tdb2/store/AbstractTestStoreConnectionBasics.java | 5 +++--
.../src/test/java/org/seaborne/tdb2/store/TestDatasetTDB.java | 4 ++--
.../src/test/java/org/seaborne/tdb2/store/TestQuadFilter.java | 4 ++--
.../test/java/org/seaborne/tdb2/store/TestTransactions.java | 4 ++--
.../test/java/org/seaborne/tdb2/store/TestTripleTable.java | 4 ++--
.../test/java/org/seaborne/tdb2/store/Test_SPARQL_TDB.java | 4 ++--
.../seaborne/tdb2/store/nodetable/AbstractTestNodeTable.java | 7 +++++--
.../tdb2/store/tupletable/AbstractTestTupleIndex.java | 4 ++--
.../tdb2/store/tupletable/TestTupleIndexRecordDirect.java | 4 ++--
.../org/seaborne/tdb2/store/tupletable/TestTupleTable.java | 4 ++--
tdb2/src/test/java/org/seaborne/tdb2/sys/TestSys.java | 4 ++--
20 files changed, 44 insertions(+), 40 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java b/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java
index 552aa56..da75494 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/TestDatabaseMgr.java
@@ -17,7 +17,7 @@
package org.seaborne.tdb2;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.atlas.lib.FileOps ;
import org.apache.jena.sparql.core.DatasetGraph ;
import org.apache.jena.sparql.core.Quad ;
@@ -28,7 +28,7 @@ import org.seaborne.dboe.jenax.Txn ;
import org.seaborne.tdb2.sys.TDBInternal ;
/** Test of DatabaseMgr - the DatasetGraph level API to TDB2 **/
-public class TestDatabaseMgr extends BaseTest
+public class TestDatabaseMgr
{
// String DIRx = ConfigTest.getCleanDir() ;
// Location DIR = Location.create(DIRx);
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java b/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
index 795c871..752a95c 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/TestTDBFactory.java
@@ -17,7 +17,7 @@
package org.seaborne.tdb2;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.atlas.lib.FileOps ;
import org.apache.jena.datatypes.xsd.XSDDatatype ;
import org.apache.jena.query.Dataset ;
@@ -31,7 +31,7 @@ import org.seaborne.dboe.jenax.Txn ;
import org.seaborne.tdb2.sys.TDBInternal ;
/** Test of TDB2Factory - the Dataset level API to TDB2 **/
-public class TestTDBFactory extends BaseTest
+public class TestTDBFactory
{
static Resource s1 = ResourceFactory.createResource("http://example/s2");
static Resource s2 = ResourceFactory.createResource();
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/assembler/TestTDBAssembler.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/assembler/TestTDBAssembler.java b/tdb2/src/test/java/org/seaborne/tdb2/assembler/TestTDBAssembler.java
index 581af56..f1e13e2 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/assembler/TestTDBAssembler.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/assembler/TestTDBAssembler.java
@@ -19,7 +19,7 @@ package org.seaborne.tdb2.assembler;
import org.apache.jena.assembler.JA ;
import org.apache.jena.assembler.exceptions.AssemblerException ;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.atlas.lib.FileOps ;
import org.apache.jena.graph.Graph ;
import org.apache.jena.query.Dataset ;
@@ -36,7 +36,7 @@ import org.seaborne.tdb2.store.DatasetGraphSwitchable ;
import org.seaborne.tdb2.store.GraphViewSwitchable ;
import org.seaborne.tdb2.sys.TDBInternal ;
-public class TestTDBAssembler extends BaseTest
+public class TestTDBAssembler
{
// Can be slow - explicitly closes the dataset.
static String dirAssem = null ;
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/lib/TestNodeLib.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/lib/TestNodeLib.java b/tdb2/src/test/java/org/seaborne/tdb2/lib/TestNodeLib.java
index ee69570..3e85f41 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/lib/TestNodeLib.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/lib/TestNodeLib.java
@@ -18,12 +18,12 @@
package org.seaborne.tdb2.lib;
import static org.seaborne.tdb2.lib.NodeLib.hash ;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.graph.Node ;
import org.apache.jena.sparql.util.NodeFactoryExtra ;
import org.junit.Test ;
-public class TestNodeLib extends BaseTest
+public class TestNodeLib
{
// Tests of TDBs NodeLib
@Test public void hash1()
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParams.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParams.java b/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParams.java
index 5396733..0d8468c 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParams.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParams.java
@@ -19,7 +19,7 @@ package org.seaborne.tdb2.setup;
import org.apache.jena.atlas.json.JSON ;
import org.apache.jena.atlas.json.JsonObject ;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.junit.Test ;
import org.seaborne.dboe.base.block.FileMode ;
import org.seaborne.tdb2.TDBException ;
@@ -27,7 +27,7 @@ import org.seaborne.tdb2.setup.StoreParams ;
import org.seaborne.tdb2.setup.StoreParamsBuilder ;
import org.seaborne.tdb2.setup.StoreParamsCodec ;
-public class TestStoreParams extends BaseTest {
+public class TestStoreParams {
@Test public void store_params_01() {
assertEqualsStoreParams(StoreParams.getDftStoreParams(), StoreParams.getDftStoreParams()) ;
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsChoose.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsChoose.java b/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsChoose.java
index 5bbf3c3..2b20d54 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsChoose.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsChoose.java
@@ -17,7 +17,7 @@
package org.seaborne.tdb2.setup;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.atlas.lib.FileOps ;
import org.junit.Test ;
import org.seaborne.dboe.base.file.Location ;
@@ -26,7 +26,7 @@ import org.seaborne.tdb2.ConfigTest ;
//TestParamsCreate
/** This test suite uses on-disk structures and can be slow */
-public class TestStoreParamsChoose extends BaseTest {
+public class TestStoreParamsChoose {
private String DIR = ConfigTest.getCleanDir() ;
static final StoreParams pApp = StoreParams.builder()
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java b/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java
index fbac48e..44aacfb 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/setup/TestStoreParamsCreate.java
@@ -23,7 +23,7 @@ import java.nio.file.Paths ;
import org.apache.jena.atlas.json.JSON ;
import org.apache.jena.atlas.json.JsonObject ;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.atlas.lib.FileOps ;
import org.junit.After ;
import org.junit.Before ;
@@ -39,7 +39,7 @@ import org.seaborne.tdb2.sys.TDBInternal ;
* This test suite uses on-disk structures, does a lot of clean/create/sync
* calls and can be noticably slow.
*/
-public class TestStoreParamsCreate extends BaseTest {
+public class TestStoreParamsCreate {
private final String DB_DIR = ConfigTest.getCleanDir() ;
private final Path db = Paths.get(DB_DIR) ;
private final Path cfg = Paths.get(DB_DIR, Names.TDB_CONFIG_FILE) ;
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/solver/TestSolverTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/solver/TestSolverTDB.java b/tdb2/src/test/java/org/seaborne/tdb2/solver/TestSolverTDB.java
index dcaa71e..d94252e 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/solver/TestSolverTDB.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/solver/TestSolverTDB.java
@@ -22,7 +22,7 @@ import java.util.ArrayList ;
import java.util.Iterator ;
import java.util.List ;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.graph.Graph ;
import org.apache.jena.graph.Node ;
import org.apache.jena.graph.Triple ;
@@ -44,7 +44,7 @@ import org.junit.Test ;
import org.seaborne.tdb2.ConfigTest ;
import org.seaborne.tdb2.junit.TL ;
-public class TestSolverTDB extends BaseTest
+public class TestSolverTDB
{
static String graphData = null ;
static Graph graph = null ;
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java b/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java
index e31263b..8bb3ae7 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/solver/TestStats.java
@@ -19,7 +19,7 @@ package org.seaborne.tdb2.solver;
import java.util.Iterator ;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.atlas.lib.tuple.Tuple ;
import org.apache.jena.graph.NodeFactory ;
import org.apache.jena.sparql.core.Quad ;
@@ -34,7 +34,7 @@ import org.seaborne.tdb2.store.nodetable.NodeTable ;
import org.seaborne.tdb2.store.nodetupletable.NodeTupleTable ;
import org.seaborne.tdb2.sys.TDBInternal ;
-public class TestStats extends BaseTest
+public class TestStats
{
static DatasetGraphTDB dsg = TDBInternal.getDatasetGraphTDB(TL.createTestDatasetGraphMem()) ;
static NodeTupleTable quads = dsg.getQuadTable().getNodeTupleTable() ;
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java b/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java
index c23dc0e..792fef4 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/AbstractTestStoreConnectionBasics.java
@@ -17,7 +17,8 @@
package org.seaborne.tdb2.store;
-import org.apache.jena.atlas.junit.BaseTest ;
+
+import static org.junit.Assert.*;
import org.apache.jena.query.ReadWrite ;
import org.apache.jena.sparql.core.Quad ;
import org.apache.jena.sparql.sse.SSE ;
@@ -33,7 +34,7 @@ import org.seaborne.tdb2.sys.TDBInternal ;
* These tests are slow on rotational disk.
* Complet cleaning of file areas is done.
*/
-public abstract class AbstractTestStoreConnectionBasics extends BaseTest
+public abstract class AbstractTestStoreConnectionBasics
{
// Subclass to give direct and mapped versions.
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDB.java b/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDB.java
index 9bc74bb..48fd7fb 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDB.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/TestDatasetTDB.java
@@ -17,7 +17,7 @@
package org.seaborne.tdb2.store;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.query.* ;
import org.apache.jena.rdf.model.Model ;
import org.apache.jena.rdf.model.ModelFactory ;
@@ -34,7 +34,7 @@ import org.seaborne.tdb2.TDB2 ;
import org.seaborne.tdb2.junit.TL ;
/** Tests of datasets, prefixes, special URIs etc (see also {@link org.apache.jena.sparql.graph.GraphsTests} */
-public class TestDatasetTDB extends BaseTest
+public class TestDatasetTDB
{
private Dataset dataset ;
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/store/TestQuadFilter.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/TestQuadFilter.java b/tdb2/src/test/java/org/seaborne/tdb2/store/TestQuadFilter.java
index a08b263..78ee4c4 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/TestQuadFilter.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/TestQuadFilter.java
@@ -19,7 +19,7 @@ package org.seaborne.tdb2.store;
import java.util.function.Predicate ;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.atlas.lib.tuple.Tuple ;
import org.apache.jena.graph.NodeFactory ;
import org.apache.jena.query.* ;
@@ -36,7 +36,7 @@ import org.seaborne.tdb2.store.nodetable.NodeTable ;
import org.seaborne.tdb2.sys.SystemTDB ;
@Ignore("Quad filter tests not ready (transactions)")
-public class TestQuadFilter extends BaseTest
+public class TestQuadFilter
{
private static String graphToHide = "http://example/g2" ;
private static Dataset ds = setup() ;
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java b/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
index 5442c79..47bc3e5 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
@@ -21,7 +21,7 @@ import java.io.StringReader ;
import java.util.Iterator;
import org.apache.jena.atlas.iterator.Iter ;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.atlas.lib.StrUtils ;
import org.apache.jena.query.Dataset ;
import org.apache.jena.query.ReadWrite;
@@ -48,7 +48,7 @@ import org.seaborne.tdb2.sys.TDBInternal;
* @see TestStoreConnectionMapped
* @see TestStoreConnectionMem
*/
-public class TestTransactions extends BaseTest
+public class TestTransactions
{
// Per-test unique-ish.
static int count = 0 ;
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/store/TestTripleTable.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/TestTripleTable.java b/tdb2/src/test/java/org/seaborne/tdb2/store/TestTripleTable.java
index 5908498..98e48d1 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/TestTripleTable.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/TestTripleTable.java
@@ -19,7 +19,7 @@ package org.seaborne.tdb2.store;
import java.util.Iterator ;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.graph.Node ;
import org.apache.jena.graph.Triple ;
import org.apache.jena.query.ReadWrite ;
@@ -30,7 +30,7 @@ import org.junit.Test ;
import org.seaborne.dboe.base.file.Location ;
import org.seaborne.tdb2.setup.TDBBuilder ;
-public class TestTripleTable extends BaseTest
+public class TestTripleTable
{
static {
Logger.getLogger("org.apache.jena.tdb.info").setLevel(Level.WARN) ;
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/store/Test_SPARQL_TDB.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/Test_SPARQL_TDB.java b/tdb2/src/test/java/org/seaborne/tdb2/store/Test_SPARQL_TDB.java
index e23875b..0ab4cb4 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/Test_SPARQL_TDB.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/Test_SPARQL_TDB.java
@@ -17,7 +17,7 @@
package org.seaborne.tdb2.store;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.atlas.lib.StrUtils ;
import org.apache.jena.graph.Graph ;
import org.apache.jena.graph.NodeFactory ;
@@ -35,7 +35,7 @@ import org.seaborne.tdb2.TDB2Factory ;
/**
* Test SPARQL
*/
-public class Test_SPARQL_TDB extends BaseTest
+public class Test_SPARQL_TDB
{
private static Dataset create() {
return TDB2Factory.createDataset() ;
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/AbstractTestNodeTable.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/AbstractTestNodeTable.java b/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/AbstractTestNodeTable.java
index 8f0c279..158e2ff 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/AbstractTestNodeTable.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/AbstractTestNodeTable.java
@@ -17,13 +17,16 @@
package org.seaborne.tdb2.store.nodetable;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.assertEquals ;
+import static org.junit.Assert.assertNotEquals ;
+import static org.junit.Assert.assertNotNull ;
+
import org.apache.jena.graph.Node ;
import org.apache.jena.sparql.util.NodeFactoryExtra ;
import org.junit.Test ;
import org.seaborne.tdb2.store.NodeId ;
-public abstract class AbstractTestNodeTable extends BaseTest
+public abstract class AbstractTestNodeTable
{
protected abstract NodeTable createEmptyNodeTable() ;
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/AbstractTestTupleIndex.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/AbstractTestTupleIndex.java b/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/AbstractTestTupleIndex.java
index 42651ad..6a2e138 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/AbstractTestTupleIndex.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/AbstractTestTupleIndex.java
@@ -23,7 +23,7 @@ import java.util.Iterator ;
import java.util.Set ;
import org.apache.jena.atlas.iterator.Iter ;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.atlas.lib.tuple.Tuple ;
import org.junit.Test ;
import org.seaborne.tdb2.store.NodeId ;
@@ -31,7 +31,7 @@ import org.seaborne.tdb2.store.tupletable.TupleIndex ;
import static org.seaborne.tdb2.store.tupletable.NData.*;
/** Test TupleIndexes (general) */
-public abstract class AbstractTestTupleIndex extends BaseTest
+public abstract class AbstractTestTupleIndex
{
protected abstract TupleIndex create(String description) ;
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecordDirect.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecordDirect.java b/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecordDirect.java
index b6b9119..a48c87b 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecordDirect.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecordDirect.java
@@ -24,7 +24,7 @@ import java.util.Iterator ;
import java.util.Set ;
import org.apache.jena.atlas.iterator.Iter ;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.atlas.lib.tuple.Tuple ;
import org.apache.jena.atlas.lib.tuple.TupleMap ;
import org.junit.Test ;
@@ -37,7 +37,7 @@ import org.seaborne.tdb2.setup.StoreParams ;
import org.seaborne.tdb2.store.NodeId ;
import org.seaborne.tdb2.sys.SystemTDB ;
-public class TestTupleIndexRecordDirect extends BaseTest
+public class TestTupleIndexRecordDirect
{
static RecordFactory factory = new RecordFactory(3*SystemTDB.SizeOfNodeId, 0) ;
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleTable.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleTable.java b/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleTable.java
index f82b52d..4d27266 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleTable.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleTable.java
@@ -23,7 +23,7 @@ import java.util.Iterator ;
import java.util.List ;
import org.apache.jena.atlas.iterator.Iter ;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.apache.jena.atlas.lib.tuple.Tuple ;
import org.junit.Test ;
import org.seaborne.dboe.base.record.RecordFactory ;
@@ -31,7 +31,7 @@ import org.seaborne.tdb2.store.NodeId ;
import org.seaborne.tdb2.sys.SystemTDB ;
import static org.seaborne.tdb2.store.tupletable.NData.*;
-public class TestTupleTable extends BaseTest
+public class TestTupleTable
{
static RecordFactory factory = new RecordFactory(3*SystemTDB.SizeOfNodeId, 0) ;
http://git-wip-us.apache.org/repos/asf/jena/blob/7624f540/tdb2/src/test/java/org/seaborne/tdb2/sys/TestSys.java
----------------------------------------------------------------------
diff --git a/tdb2/src/test/java/org/seaborne/tdb2/sys/TestSys.java b/tdb2/src/test/java/org/seaborne/tdb2/sys/TestSys.java
index 0a98d8d..b537655 100644
--- a/tdb2/src/test/java/org/seaborne/tdb2/sys/TestSys.java
+++ b/tdb2/src/test/java/org/seaborne/tdb2/sys/TestSys.java
@@ -18,11 +18,11 @@
package org.seaborne.tdb2.sys;
-import org.apache.jena.atlas.junit.BaseTest ;
+import static org.junit.Assert.*;
import org.junit.Test ;
import org.seaborne.tdb2.TDB2 ;
-public class TestSys extends BaseTest
+public class TestSys
{
@Test public void sys1()
{