1 package eu.fbk.knowledgestore.triplestore; 2 3 import java.io.IOException; 4 5 import javax.annotation.Nullable; 6 7 import org.openrdf.model.Resource; 8 import org.openrdf.model.Statement; 9 import org.openrdf.model.URI; 10 import org.openrdf.model.Value; 11 import org.openrdf.query.BindingSet; 12 import org.openrdf.query.QueryEvaluationException; 13 14 import info.aduna.iteration.CloseableIteration; 15 16 import eu.fbk.knowledgestore.data.Handler; 17 import eu.fbk.knowledgestore.runtime.DataCorruptedException; 18 19 /** 20 * A triple store transaction. 21 * <p> 22 * A {@code TripleTransaction} is a unit of work over the contents of a {@link TripleStore} that 23 * provides atomicity (i.e., changes are either completely stored or discarded), isolation (i.e., 24 * other transaction do not see the modifications of this transaction) and durability (i.e., 25 * changes are persisted across different program runs) guarantees. 26 * </p> 27 * <p> 28 * A {@code TripleTransaction} supports the following four main features: 29 * </p> 30 * <ul> 31 * <li><b>Statement retrieval</b>, via method {@link #get(Resource, URI, Value, Resource)};</li> 32 * <li><b>SPARQL querying</b>, via method {@link #query(SelectQuery, BindingSet)};</li> 33 * <li><b>Inference materialization</b>, via method {@link #infer(Handler)}</li> 34 * <li><b>Triple modification</b>, via bulk methods {@link #add(Iterable)} and 35 * {@link #remove(Iterable)}.</li> 36 * </ul> 37 * <p> 38 * Note that the latter two functionalities are not available for read-only transactions (an 39 * {@link IllegalStateException} is thrown in that case). 40 * </p> 41 * <p> 42 * Transactions are terminated via {@link #end(boolean)}, whose parameter specifies whether 43 * changes should be committed. Method {@code end()} always tries to terminate the transaction: if 44 * it throws an {@code IOException} exception a rollback must be assumed, even if a commit was 45 * asked; if it throws a {@code DataCorruptedException}, then neither commit or rollback were 46 * possible and the {@code TripleStore} is left in some unpredictable state with no possibility of 47 * automatic recovery. In that case, external code may resort to the {@link TripleStore#reset()} 48 * and re-population procedure to recover the situation. In case the JVM is abruptly shutdown 49 * during a transaction, the effects of the transaction should be the same as if a rollback was 50 * performed. 51 * </p> 52 * <p> 53 * {@code TripleTransaction} objects are not required to be thread safe. Access by at most one 54 * thread at a time can be assumed and must be guaranteed externally, with the only exception of 55 * method {@link #end(boolean)} that can be called at any moment by any thread in case the 56 * transaction need to be rolled back. Note also that it must be allowed for operations to be 57 * issued while streams from previous operations are still open; if a stream is open and a write 58 * operations is performed that affects one of the statements/query solutions still to be returned 59 * by the stream (or made a statement/query solution returnable/not returnable by the stream), 60 * then the behaviour of the stream is undefined. 61 * </p> 62 */ 63 public interface TripleTransaction { 64 65 /** 66 * Returns a Sesame {@code CloseableIteration} over all the RDF statements matching the 67 * (optional) subject, predicate, object, context supplied. Null values are used as wildcard. 68 * Implementations are designed to perform high throughput statement extraction (likely more 69 * efficient than doing a SPARQL query). 70 * 71 * @param subject 72 * the subject to match, null to match any subject 73 * @param predicate 74 * the predicate to match, null to match any predicate 75 * @param object 76 * the object to match, null to match any object 77 * @param context 78 * the context to match, null to match any context 79 * @return an iteration over matching RDF statements 80 * @throws IOException 81 * in case some IO error occurs 82 * @throws IllegalStateException 83 * if the {@code TripleTransaction} has been already ended 84 */ 85 CloseableIteration<? extends Statement, ? extends Exception> get(@Nullable Resource subject, 86 @Nullable URI predicate, @Nullable Value object, @Nullable Resource context) 87 throws IOException, IllegalStateException; 88 89 /** 90 * Evaluates the supplied SPARQL SELECT query, returning a Sesame {@code CloseableIteration} 91 * over its solutions. The method accepts an optional <tt>BindingSet</tt> object, providing 92 * bindings for variables in the query; it can be used to instantiate parametric queries, 93 * similarly to <tt>PreparedStatements</tt> in JDBC. 94 * 95 * @param query 96 * the SPARQL SELECT query to evaluate 97 * @param bindings 98 * optional bindings for variables in the query; 99 * @param timeout 100 * optional timeout in milliseconds for the query 101 * @return an iteration over the results of the query 102 * @throws IOException 103 * in case some IO error occurs 104 * @throws UnsupportedOperationException 105 * in case the query, while being valid according to SPARQL, uses a construct, 106 * function or feature that is not supported by the triple store implementation 107 * (refer to the implementation documentation for unsupported features) 108 * @throws IllegalStateException 109 * if the {@code TripleTransaction} has been already ended 110 */ 111 CloseableIteration<BindingSet, QueryEvaluationException> query(SelectQuery query, 112 @Nullable BindingSet bindings, @Nullable Long timeout) throws IOException, 113 UnsupportedOperationException, IllegalStateException; 114 115 /** 116 * Performs inference, materializing the logical closure of the RDF statements contained in 117 * the triple store. The method accepts an optional {@code Handler} inferred statements can be 118 * notified to, allowing for their additional processing by external code. 119 * 120 * @param handler 121 * an optional handler inferred RDF statements can be notified to 122 * @throws IOException 123 * in case some IO error occurs, with no guarantee that the {@code TripleStore} is 124 * left in the same state if was when the method was called; note that this 125 * exception may trigger a rollback on the caller side 126 * @throws IllegalStateException 127 * if the {@code TripleTransaction} has been already ended, or if it is read-only 128 */ 129 void infer(@Nullable Handler<? super Statement> handler) throws IOException, 130 IllegalStateException; 131 132 /** 133 * Adds all the RDF statements in the {@code Iterable} specified to the triple store. 134 * Implementations are designed to perform high throughput insertion. They are also allowed to 135 * buffer part or all of the operation, successfully returning before specified triples have 136 * been completely modified; in this case, it must be however guaranteed that subsequent calls 137 * to {@link #query(SelectQuery, BindingSet)} will 'see' all the triples added. 138 * 139 * @param statements 140 * the statements to add 141 * @throws IOException 142 * in case some IO error occurs, with no guarantee that the {@code TripleStore} is 143 * left in the same state if was when the method was called; note that this 144 * exception may trigger a rollback on the caller side 145 * @throws IllegalStateException 146 * if the {@code TripleTransaction} has been already ended, or if it is read-only 147 */ 148 void add(Iterable<? extends Statement> statements) throws IOException, IllegalStateException; 149 150 /** 151 * Removes all the RDF statements in the {@code Iterable} specified from the triple store. 152 * Implementations are designed to perform high throughput deletion. They are also allowed to 153 * return before specified triples have been completely removed; in this case, it must be 154 * however guaranteed that subsequent calls to {@link #query(SelectQuery, BindingSet)} will 155 * not 'see' any of the triples removed. 156 * 157 * @param statements 158 * the statements to remove 159 * @throws IOException 160 * in case some IO error occurs, with no guarantee that the {@code TripleStore} is 161 * left in the same state if was when the method was called; note that this 162 * exception may trigger a rollback on the caller side 163 * @throws IllegalStateException 164 * if the {@code TripleTransaction} has been already ended, or if it is read-only 165 */ 166 void remove(Iterable<? extends Statement> statements) throws IOException, 167 IllegalStateException; 168 169 /** 170 * Ends the transaction, either committing or rolling back its changes (if any). This method 171 * always tries to terminate the transaction: if commit is requested but fails, a rollback is 172 * forced by the method and an {@code IOException} is thrown. If it is not possible either to 173 * commit or rollback, then the {@code TripleStore} is possibly left in an unknown state and a 174 * {@code DataCorruptedException} is thrown to signal a data corruption situation that cannot 175 * be automatically recovered (apart from calling {@link TripleStore#reset()} and repopulating 176 * the {@code TripleStore}). 177 * 178 * @param commit 179 * true in case changes made by the transaction should be committed 180 * @throws IOException 181 * in case some IO error occurs or the commit request cannot be satisfied for any 182 * reason; it is however guaranteed that a forced rollback has been performed 183 * @throws DataCorruptedException 184 * in case it was not possible either to commit or rollback, which implies the 185 * state of the {@code TripleStore} is unknown and automatic recovery is not 186 * possible (hence, data is corrupted) 187 * @throws IllegalStateException 188 * if the {@code TripleTransaction} has been already ended 189 */ 190 void end(boolean commit) throws DataCorruptedException, IOException, IllegalStateException; 191 192 } 193 194 // IMPLEMENTATION NOTES 195 // 196 // - ask, construct and describe queries can be implemented on top of select; a limit clause 197 // should be generated for ask queries for efficiency; a stream wrapper based on 198 // MultiProjectionIterator and the code of SailGraphQuery can be used for construct and describe. 199 // - during query execution, QueryEvaluationException is thrown in case of IO errors or if a 200 // malformed query is detected after execution began: in the first case an IOException seems more 201 // appropriate, while in the second case an UnsupportedOperationException seems appropriate 202 // (it's the client fault, not something expected to be recoverable) 203 // 204 // Corruption may result from 205 // - internal failure of the triple store (e.g. due to bug) 206 // - bug in the Java code or unsupported rollback that leaves partial modifications in the store