Class: RDF::Transaction
- Inherits:
-
Object
- Object
- RDF::Transaction
- Includes:
- Enumerable, Mutable, Queryable
- Defined in:
- lib/rdf/transaction.rb
Overview
An RDF transaction.
Transactions provide an ACID scope for queries and mutations.
Repository implementations may provide support for transactional updates by providing an atomic implementation of Mutable#apply_changeset and responding to #supports?(:atomic_write)
with true
.
We carefully distinguish between read-only and read/write transactions, in order to enable repository implementations to take out the appropriate locks for concurrency control. Transactions are read-only by default; mutability must be explicitly requested on construction in order to obtain a read/write transaction.
Individual repositories may make their own sets of guarantees within the transaction’s scope. In case repository implementations should be unable to provide full ACID guarantees for transactions, that must be clearly indicated in their documentation. If update atomicity is not provided, #supports?(:atomic_write)
must respond false
.
The base class provides an atomic write implementation depending on Changeset and using Changeset#apply. Custom Repository classes can implement a minimial write-atomic transactions by overriding Mutable#apply_changeset.
Reads within a transaction run against the live repository by default (#isolation_level is :read_committed
). Repositories may provide support for snapshots by implementing Repository#snapshot and responding true
to #supports?(:snapshots)
. In this case, the transaction will use the Dataset returned by Mutable#snapshot for reads (:repeatable_read
).
For datastores that support transactions natively, implementation of a custom Transaction subclass is recommended. The Repository is responsible for specifying snapshot support and isolation level as appropriate. Note that repositories may provide the snapshot isolation level without implementing Mutable#snapshot.
Direct Known Subclasses
Defined Under Namespace
Classes: SerializedTransaction, TransactionError
Instance Attribute Summary collapse
-
#changes ⇒ RDF::Changeset
readonly
RDF statement mutations to apply when executed.
-
#graph_name ⇒ RDF::Resource?
readonly
The default graph name to apply to statements inserted or deleted by the transaction.
-
#options ⇒ Hash{Symbol => Object}
readonly
Any additional options for this transaction.
-
#repository ⇒ RDF::Repository
readonly
The repository being operated upon.
Class Method Summary collapse
-
.begin(repository, mutable: false, **options) {|tx| ... }
Executes a transaction against the given RDF repository.
Instance Method Summary collapse
-
#delete_statement(statement)
protected
Appends an RDF statement to the sequence to delete when executed.
- #each(*args, &block) ⇒ Object
-
#execute ⇒ Boolean
Executes the transaction.
-
#initialize(repository, graph_name: nil, mutable: false, **options) {|tx| ... } ⇒ Transaction
constructor
Initializes this transaction.
-
#insert_statement(statement)
protected
Appends an RDF statement to the sequence to insert when executed.
-
#inspect ⇒ String
Returns a developer-friendly representation of this transaction.
-
#inspect!
Outputs a developer-friendly representation of this transaction to
stderr
. - #isolation_level ⇒ Object
-
#mutable? ⇒ Boolean
Returns
true
if this is a read/write transaction,false
otherwise. -
#mutated? ⇒ Boolean
Indicates whether the transaction includes changes relative to the target repository’s state at transaction start time.
- #query_execute(*args, &block) ⇒ Object protected
- #query_pattern(*args, &block) ⇒ Object protected
-
#readable? ⇒ Boolean
Returns
true
to indicate that this transaction is readable. -
#rollback ⇒ Boolean
Rolls back the transaction.
- #statement?(*args) ⇒ Object (also: #has_statement?)
-
#writable? ⇒ Boolean
Returns
true
if this is a read/write transaction,false
otherwise.
Methods included from Queryable
#first, #first_literal, #first_object, #first_predicate, #first_subject, #first_value, #query
Methods included from Enumerable
#canonicalize, #canonicalize!, #dump, #each_graph, #each_object, #each_predicate, #each_quad, #each_statement, #each_subject, #each_term, #each_triple, #enum_graph, #enum_object, #enum_predicate, #enum_quad, #enum_statement, #enum_subject, #enum_term, #enum_triple, #graph?, #graph_names, #invalid?, #method_missing, #object?, #objects, #predicate?, #predicates, #project_graph, #quad?, #quads, #respond_to_missing?, #statements, #subject?, #subjects, #supports?, #term?, #terms, #to_a, #to_h, #to_set, #triple?, #triples, #valid?, #validate!
Methods included from Util::Aliasing::LateBound
Methods included from Countable
Methods included from Mutable
#<<, #apply_changeset, #clear, #delete, #delete_insert, #delete_statements, #immutable?, #insert, #load, #method_missing, #respond_to_missing?, #snapshot, #update
Methods included from Util::Coercions
Methods included from Writable
#<<, #insert, #insert_graph, #insert_reader, #insert_statements
Constructor Details
#initialize(repository, graph_name: nil, mutable: false, **options) {|tx| ... } ⇒ Transaction
Initializes this transaction.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/rdf/transaction.rb', line 130 def initialize(repository, graph_name: nil, mutable: false, **, &block) @repository = repository @snapshot = repository.supports?(:snapshots) ? repository.snapshot : repository @options = .dup @mutable = mutable @graph_name = graph_name raise TransactionError, 'Tried to open a mutable transaction on an immutable repository' if @mutable && !@repository.mutable? @changes = RDF::Changeset.new if block_given? case block.arity when 1 then block.call(self) else self.instance_eval(&block) end end end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class RDF::Enumerable
Instance Attribute Details
#changes ⇒ RDF::Changeset (readonly)
RDF statement mutations to apply when executed.
114 115 116 |
# File 'lib/rdf/transaction.rb', line 114 def changes @changes end |
#graph_name ⇒ RDF::Resource? (readonly)
The default graph name to apply to statements inserted or deleted by the transaction.
107 108 109 |
# File 'lib/rdf/transaction.rb', line 107 def graph_name @graph_name end |
#options ⇒ Hash{Symbol => Object} (readonly)
Any additional options for this transaction.
120 121 122 |
# File 'lib/rdf/transaction.rb', line 120 def @options end |
#repository ⇒ RDF::Repository (readonly)
The repository being operated upon.
99 100 101 |
# File 'lib/rdf/transaction.rb', line 99 def repository @repository end |
Class Method Details
.begin(repository, mutable: false, **options) {|tx| ... }
This method returns an undefined value.
Executes a transaction against the given RDF repository.
90 91 92 |
# File 'lib/rdf/transaction.rb', line 90 def self.begin(repository, mutable: false, **, &block) self.new(repository, mutable: mutable, **, &block) end |
Instance Method Details
#delete_statement(statement) (protected)
This method returns an undefined value.
Appends an RDF statement to the sequence to delete when executed.
288 289 290 |
# File 'lib/rdf/transaction.rb', line 288 def delete_statement(statement) @changes.delete(process_statement(statement)) end |
#each(*args, &block) ⇒ Object
76 77 78 |
# File 'lib/rdf/transaction.rb', line 76 def each(*args, &block) read_target.each(*args, &block) end |
#execute ⇒ Boolean
Executes the transaction
248 249 250 251 252 |
# File 'lib/rdf/transaction.rb', line 248 def execute raise TransactionError, 'Cannot execute a rolled back transaction. ' \ 'Open a new one instead.' if instance_variable_defined?(:@rolledback) && @rolledback @changes.apply(@repository) end |
#insert_statement(statement) (protected)
This method returns an undefined value.
Appends an RDF statement to the sequence to insert when executed.
278 279 280 |
# File 'lib/rdf/transaction.rb', line 278 def insert_statement(statement) @changes.insert(process_statement(statement)) end |
#inspect ⇒ String
Returns a developer-friendly representation of this transaction.
229 230 231 232 |
# File 'lib/rdf/transaction.rb', line 229 def inspect sprintf("#<%s:%#0x(changes: -%d/+%d)>", self.class.name, self.__id__, self.changes.deletes.count, self.changes.inserts.count) end |
#inspect!
This method returns an undefined value.
Outputs a developer-friendly representation of this transaction to stderr
.
239 240 241 |
# File 'lib/rdf/transaction.rb', line 239 def inspect! $stderr.puts(inspect) end |
#isolation_level ⇒ Object
154 155 156 157 |
# File 'lib/rdf/transaction.rb', line 154 def isolation_level return :repeatable_read if repository.supports?(:snapshots) :read_committed end |
#mutable? ⇒ Boolean
Returns true
if this is a read/write transaction, false
otherwise.
196 197 198 |
# File 'lib/rdf/transaction.rb', line 196 def mutable? @mutable end |
#mutated? ⇒ Boolean
Transaction
implementers may choose to NotImplementedError
if the transaction implementation cannot be implemented efficiently.
Indicates whether the transaction includes changes relative to the target repository’s state at transaction start time.
The response is guaranteed to be true
if executing the transaction against the original repository state would cause a change. It may also return true
in cases where the repository would not change (e.g. because the transaction would insert statements already present).
175 176 177 178 179 180 |
# File 'lib/rdf/transaction.rb', line 175 def mutated? return !changes.empty? if self.class == Transaction raise NotImplementedError, '#mutated? is not implemented for #{self.class}' end |
#query_execute(*args, &block) ⇒ Object (protected)
296 297 298 |
# File 'lib/rdf/transaction.rb', line 296 def query_execute(*args, &block) read_target.send(:query_execute, *args, &block) end |
#query_pattern(*args, &block) ⇒ Object (protected)
292 293 294 |
# File 'lib/rdf/transaction.rb', line 292 def query_pattern(*args, &block) read_target.send(:query_pattern, *args, &block) end |
#readable? ⇒ Boolean
Returns true
to indicate that this transaction is readable.
205 206 207 |
# File 'lib/rdf/transaction.rb', line 205 def readable? true end |
#rollback ⇒ Boolean
Rolls back the transaction
@note: the base class simply replaces its current Changeset
with a fresh one. Other implementations may need to explictly rollback at the supporting datastore.
@note: clients should not rely on using same transaction instance after rollback.
265 266 267 268 |
# File 'lib/rdf/transaction.rb', line 265 def rollback @changes = RDF::Changeset.new @rolledback = true end |
#statement? ⇒ Boolean #statement?(statement) ⇒ Object Also known as: has_statement?
216 217 218 219 220 221 222 |
# File 'lib/rdf/transaction.rb', line 216 def statement?(*args) case args.length when 0 then false when 1 then read_target.statement?(*args) else raise ArgumentError("wrong number of arguments (given #{args.length}, expected 0 or 1)") end end |
#writable? ⇒ Boolean
Returns true
if this is a read/write transaction, false
otherwise.
187 188 189 |
# File 'lib/rdf/transaction.rb', line 187 def writable? @mutable end |