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/10/03 19:34:02 UTC
[16/65] [abbrv] jena git commit: JENA-1397: Rename java packages
http://git-wip-us.apache.org/repos/asf/jena/blob/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/NodeTableOps.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/NodeTableOps.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/NodeTableOps.java
new file mode 100644
index 0000000..0fcc559
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/NodeTableOps.java
@@ -0,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 org.apache.jena.tdb2.store.nodetable;
+
+import java.util.ArrayList ;
+import java.util.List ;
+
+import org.apache.jena.graph.Node ;
+import org.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/NodeTableTRDF.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/NodeTableTRDF.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/NodeTableTRDF.java
new file mode 100644
index 0000000..6dec310
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/NodeTableTRDF.java
@@ -0,0 +1,109 @@
+/*
+ * 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.apache.jena.tdb2.store.nodetable ;
+
+import org.apache.jena.atlas.logging.Log ;
+import org.apache.jena.dboe.base.file.BinaryDataFile;
+import org.apache.jena.dboe.index.Index;
+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.jena.tdb2.TDBException;
+import org.apache.jena.tdb2.store.NodeId;
+import org.apache.jena.tdb2.store.NodeIdFactory;
+import org.apache.thrift.TException ;
+import org.apache.thrift.protocol.TProtocol ;
+
+/** 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 ; }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/jena/blob/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/NodeTableWrapper.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/NodeTableWrapper.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/NodeTableWrapper.java
new file mode 100644
index 0000000..c847135
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/NodeTableWrapper.java
@@ -0,0 +1,94 @@
+/*
+ * 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.apache.jena.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.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/TReadAppendFileTransport.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/TReadAppendFileTransport.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/TReadAppendFileTransport.java
new file mode 100644
index 0000000..ba9e001
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetable/TReadAppendFileTransport.java
@@ -0,0 +1,86 @@
+/*
+ * 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.apache.jena.tdb2.store.nodetable;
+
+import java.util.Objects ;
+
+import org.apache.jena.dboe.base.file.BinaryDataFile;
+import org.apache.thrift.transport.TTransport ;
+
+/** 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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTable.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTable.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTable.java
new file mode 100644
index 0000000..ef610a1
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTable.java
@@ -0,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.apache.jena.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.apache.jena.tdb2.store.NodeId;
+import org.apache.jena.tdb2.store.nodetable.NodeTable;
+import org.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTableConcrete.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTableConcrete.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTableConcrete.java
new file mode 100644
index 0000000..55671f7
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTableConcrete.java
@@ -0,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.apache.jena.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.apache.jena.tdb2.TDBException;
+import org.apache.jena.tdb2.lib.TupleLib;
+import org.apache.jena.tdb2.store.NodeId;
+import org.apache.jena.tdb2.store.nodetable.NodeTable;
+import org.apache.jena.tdb2.store.tupletable.TupleIndex;
+import org.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTableView.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTableView.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTableView.java
new file mode 100644
index 0000000..7f65221
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTableView.java
@@ -0,0 +1,113 @@
+/*
+ * 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.apache.jena.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.apache.jena.tdb2.store.NodeId;
+import org.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTableWrapper.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTableWrapper.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTableWrapper.java
new file mode 100644
index 0000000..8fc88a9
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/nodetupletable/NodeTupleTableWrapper.java
@@ -0,0 +1,98 @@
+/*
+ * 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.apache.jena.tdb2.store.nodetupletable;
+
+import java.util.Iterator ;
+
+import org.apache.jena.atlas.lib.tuple.Tuple ;
+import org.apache.jena.graph.Node ;
+import org.apache.jena.tdb2.store.NodeId;
+import org.apache.jena.tdb2.store.nodetable.NodeTable;
+import org.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndex.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndex.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndex.java
new file mode 100644
index 0000000..ffb3d86
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndex.java
@@ -0,0 +1,88 @@
+/*
+ * 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.apache.jena.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.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexBase.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexBase.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexBase.java
new file mode 100644
index 0000000..7784a36
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexBase.java
@@ -0,0 +1,124 @@
+/*
+ * 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.apache.jena.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.apache.jena.tdb2.TDBException;
+import org.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexRecord.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexRecord.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexRecord.java
new file mode 100644
index 0000000..15d1c40
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexRecord.java
@@ -0,0 +1,238 @@
+/*
+ * 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.apache.jena.tdb2.store.tupletable;
+
+import static java.lang.String.format ;
+import static org.apache.jena.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.apache.jena.dboe.base.record.Record;
+import org.apache.jena.dboe.base.record.RecordFactory;
+import org.apache.jena.dboe.index.RangeIndex;
+import org.apache.jena.tdb2.TDBException;
+import org.apache.jena.tdb2.lib.TupleLib;
+import org.apache.jena.tdb2.store.NodeId;
+import org.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexRecordAsyncBulkAdd.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexRecordAsyncBulkAdd.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexRecordAsyncBulkAdd.java
new file mode 100644
index 0000000..536c935
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexRecordAsyncBulkAdd.java
@@ -0,0 +1,263 @@
+/*
+ * 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.apache.jena.tdb2.store.tupletable;
+
+import static java.lang.String.format ;
+import static org.apache.jena.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.apache.jena.dboe.base.record.Record;
+import org.apache.jena.dboe.base.record.RecordFactory;
+import org.apache.jena.dboe.index.RangeIndex;
+import org.apache.jena.dboe.transaction.txn.Transaction;
+import org.apache.jena.tdb2.TDBException;
+import org.apache.jena.tdb2.lib.Async;
+import org.apache.jena.tdb2.lib.TupleLib;
+import org.apache.jena.tdb2.store.NodeId;
+import org.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexWrapper.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexWrapper.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexWrapper.java
new file mode 100644
index 0000000..fad06a3
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleIndexWrapper.java
@@ -0,0 +1,118 @@
+/*
+ * 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.apache.jena.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.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleTable.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleTable.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleTable.java
new file mode 100644
index 0000000..42658fa
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/tupletable/TupleTable.java
@@ -0,0 +1,219 @@
+/*
+ * 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.apache.jena.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.apache.jena.tdb2.TDBException;
+import org.apache.jena.tdb2.store.NodeId;
+import org.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DateTimeNode.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DateTimeNode.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DateTimeNode.java
new file mode 100644
index 0000000..9989414
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DateTimeNode.java
@@ -0,0 +1,254 @@
+/*
+ * 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.apache.jena.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.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DecimalNode.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DecimalNode.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DecimalNode.java
new file mode 100644
index 0000000..acb99de
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DecimalNode.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.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DecimalNode56.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DecimalNode56.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DecimalNode56.java
new file mode 100644
index 0000000..7515588
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/value/DecimalNode56.java
@@ -0,0 +1,141 @@
+/*
+ * 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.apache.jena.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;
+ }
+}