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:04 UTC
[18/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/solver/StageGeneratorDirectTDB.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/StageGeneratorDirectTDB.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/StageGeneratorDirectTDB.java
new file mode 100644
index 0000000..1e081f3
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/StageGeneratorDirectTDB.java
@@ -0,0 +1,58 @@
+/*
+ * 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.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.apache.jena.tdb2.store.GraphTDB;
+import org.apache.jena.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) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/StageMatchTuple.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/StageMatchTuple.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/StageMatchTuple.java
new file mode 100644
index 0000000..99d3d06
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/StageMatchTuple.java
@@ -0,0 +1,196 @@
+/*
+ * 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.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.apache.jena.tdb2.store.NodeId;
+import org.apache.jena.tdb2.store.nodetable.NodeTable;
+import org.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/Stats.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/Stats.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/Stats.java
new file mode 100644
index 0000000..6897847
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/Stats.java
@@ -0,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 org.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsCollector.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsCollector.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsCollector.java
new file mode 100644
index 0000000..a751bb8
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsCollector.java
@@ -0,0 +1,36 @@
+/*
+ * 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.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsCollectorBase.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsCollectorBase.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsCollectorBase.java
new file mode 100644
index 0000000..3de508e
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsCollectorBase.java
@@ -0,0 +1,54 @@
+/*
+ * 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.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsCollectorNodeId.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsCollectorNodeId.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsCollectorNodeId.java
new file mode 100644
index 0000000..c4b1b9c
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsCollectorNodeId.java
@@ -0,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 org.apache.jena.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.apache.jena.tdb2.store.NodeId;
+import org.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsResults.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsResults.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsResults.java
new file mode 100644
index 0000000..d386dbe
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/solver/stats/StatsResults.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.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetGraphSwitchable.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetGraphSwitchable.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetGraphSwitchable.java
new file mode 100644
index 0000000..a9a2fc0
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetGraphSwitchable.java
@@ -0,0 +1,204 @@
+/*
+ * 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;
+
+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.dboe.base.file.Location;
+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 ;
+
+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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetGraphTDB.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetGraphTDB.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetGraphTDB.java
new file mode 100644
index 0000000..fa2cd47
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetGraphTDB.java
@@ -0,0 +1,481 @@
+/*
+ * 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;
+
+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.dboe.base.file.Location;
+import org.apache.jena.dboe.transaction.TransactionalMonitor;
+import org.apache.jena.dboe.transaction.txn.Transaction;
+import org.apache.jena.dboe.transaction.txn.TransactionException;
+import org.apache.jena.dboe.transaction.txn.TransactionalSystem;
+import org.apache.jena.dboe.transaction.txn.TxnId;
+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.apache.jena.tdb2.TDBException;
+import org.apache.jena.tdb2.lib.NodeLib;
+import org.apache.jena.tdb2.setup.StoreParams;
+import org.apache.jena.tdb2.store.nodetupletable.NodeTupleTable;
+import org.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetGraphTxn.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetGraphTxn.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetGraphTxn.java
new file mode 100644
index 0000000..a1354ea
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetGraphTxn.java
@@ -0,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.
+ */
+
+package org.apache.jena.tdb2.store;
+
+import org.apache.jena.dboe.transaction.Transactional;
+import org.apache.jena.sparql.core.DatasetGraph ;
+
+/** Transaction representation of a DatasetGraph */
+public interface DatasetGraphTxn extends DatasetGraph, Transactional {
+ // Combines org.apache.jena.dboe.transaction.Transactional and org.apache.jena.sparql.core.Transactional.
+ // o.a.j.dboe.transaction.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetGraphWrapperTxn.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetGraphWrapperTxn.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetGraphWrapperTxn.java
new file mode 100644
index 0000000..8022165
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/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.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetPrefixesTDB.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetPrefixesTDB.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetPrefixesTDB.java
new file mode 100644
index 0000000..e1b7e7b
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/DatasetPrefixesTDB.java
@@ -0,0 +1,174 @@
+/*
+ * 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;
+
+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.dboe.base.record.RecordFactory;
+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.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/GraphPrefixesProjectionTDB.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/GraphPrefixesProjectionTDB.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/GraphPrefixesProjectionTDB.java
new file mode 100644
index 0000000..fc805b0
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/GraphPrefixesProjectionTDB.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.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/GraphTDB.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/GraphTDB.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/GraphTDB.java
new file mode 100644
index 0000000..15d2508
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/GraphTDB.java
@@ -0,0 +1,181 @@
+/*
+ * 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 ;
+
+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.tdb2.TDBException;
+import org.apache.jena.tdb2.graph.TransactionHandlerTDB;
+import org.apache.jena.tdb2.store.nodetupletable.NodeTupleTable;
+import org.apache.jena.util.iterator.ExtendedIterator ;
+import org.apache.jena.util.iterator.WrappedIterator ;
+
+/**
+ * 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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/GraphViewSwitchable.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/GraphViewSwitchable.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/GraphViewSwitchable.java
new file mode 100644
index 0000000..de4c2c0
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/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.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/Hash.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/Hash.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/Hash.java
new file mode 100644
index 0000000..ff06594
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/Hash.java
@@ -0,0 +1,57 @@
+/*
+ * 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;
+
+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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/IteratorCheckNotConcurrent.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/IteratorCheckNotConcurrent.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/IteratorCheckNotConcurrent.java
new file mode 100644
index 0000000..1b4d727
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/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.apache.jena.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/3d456654/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/IteratorTxnTracker.java
----------------------------------------------------------------------
diff --git a/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/IteratorTxnTracker.java b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/IteratorTxnTracker.java
new file mode 100644
index 0000000..59e58c8
--- /dev/null
+++ b/jena-db/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/IteratorTxnTracker.java
@@ -0,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.apache.jena.tdb2.store;
+
+import java.util.Iterator;
+import java.util.Objects;
+
+import org.apache.jena.atlas.iterator.IteratorWrapper;
+import org.apache.jena.dboe.transaction.txn.Transaction;
+import org.apache.jena.dboe.transaction.txn.TransactionException;
+import org.apache.jena.dboe.transaction.txn.TransactionalSystem;
+import org.apache.jena.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");
+ }
+}
\ No newline at end of file