/* * 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.tdb.store.nodetupletable ; import static java.lang.String.format ; import java.util.Iterator ; import org.apache.jena.atlas.iterator.Iter ; import org.apache.jena.atlas.iterator.NullIterator ; 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.tdb.TDBException ; import org.apache.jena.tdb.lib.TupleLib ; import org.apache.jena.tdb.store.NodeId ; import org.apache.jena.tdb.store.nodetable.NodeTable ; import org.apache.jena.tdb.store.tupletable.TupleIndex ; import org.apache.jena.tdb.store.tupletable.TupleTable ; import org.apache.jena.tdb.sys.DatasetControl ; /** 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 ; private final DatasetControl dsPolicy ; /* * Concurrency checking: Everything goes through one of * addRow, deleteRow or find* */ public NodeTupleTableConcrete(int N, TupleIndex[] indexes, NodeTable nodeTable, DatasetControl dsControl) { 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.getMapping(), index.getTupleLength())) ; } this.dsPolicy = dsControl ; this.tupleTable = new TupleTable(N, indexes) ; this.nodeTable = nodeTable ; } private void startWrite() { dsPolicy.startUpdate() ; } private void finishWrite() { dsPolicy.finishUpdate() ; } private void startRead() { dsPolicy.startRead() ; } private void finishRead() { dsPolicy.finishRead() ; } @Override public DatasetControl getPolicy() { return dsPolicy ; } @Override public boolean 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.tuple(n) ; return tupleTable.add(t) ; } finally { finishWrite() ; } } @Override public boolean 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 false ; n[i] = id ; } Tuple<NodeId> t = TupleFactory.tuple(n) ; return 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 new 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.tuple(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() ; } } private <T> Iterator<T> iteratorControl(Iterator<T> iter) { return dsPolicy.iteratorControl(iter) ; } }