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 ‘RDF::Changeset` and using `Changeset#apply`. Custom `Repositories` can implement a minimial write-atomic transactions by overriding `#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 `RDF::Dataset` returned by `#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 `#snapshot`.
Direct Known Subclasses
Defined Under Namespace
Classes: 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| ... } ⇒ void
Executes a transaction against the given RDF repository.
Instance Method Summary collapse
- #each(*args, &block) ⇒ Object
-
#execute ⇒ Boolean
Executes the transaction.
- #has_statement?(statement) ⇒ Boolean
-
#initialize(repository, graph_name: nil, mutable: false, **options) {|tx| ... } ⇒ Transaction
constructor
Initializes this transaction.
-
#inspect ⇒ String
Returns a developer-friendly representation of this transaction.
-
#inspect! ⇒ void
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.
-
#readable? ⇒ Boolean
Returns ‘true` to indicate that this transaction is readable.
-
#rollback ⇒ Boolean
Rolls back the transaction.
-
#writable? ⇒ Boolean
Returns ‘true` if this is a read/write transaction, `false` otherwise.
Methods included from Queryable
#enum_for, #first, #first_literal, #first_object, #first_predicate, #first_subject, #first_value, #query
Methods included from Enumerable
#dump, #each_graph, #each_object, #each_predicate, #each_quad, #each_statement, #each_subject, #each_term, #each_triple, #enum_for, #enum_graph, #enum_object, #enum_predicate, #enum_quad, #enum_statement, #enum_subject, #enum_term, #enum_triple, #graph_names, #has_graph?, #has_object?, #has_predicate?, #has_quad?, #has_subject?, #has_term?, #has_triple?, #invalid?, #method_missing, #objects, #predicates, #project_graph, #quads, #respond_to_missing?, #statements, #subjects, #supports?, #terms, #to_a, #to_hash, #to_set, #triples, #valid?, #validate!
Methods included from Util::Aliasing::LateBound
Methods included from Countable
Methods included from Mutable
#<<, #apply_changeset, #clear, #delete, #delete_insert, #immutable?, #insert, #load, #method_missing, #respond_to_missing?, #snapshot, #update
Methods included from Writable
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 = .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 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| ... } ⇒ void
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, .merge(mutable: mutable), &block) end |
Instance Method Details
#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
215 216 217 218 219 |
# File 'lib/rdf/transaction.rb', line 215 def execute raise TransactionError, 'Cannot execute a rolled back transaction. ' \ 'Open a new one instead.' if @rolledback @changes.apply(@repository) end |
#has_statement?(statement) ⇒ Boolean
188 189 190 |
# File 'lib/rdf/transaction.rb', line 188 def has_statement?(statement) read_target.has_statement?(statement) end |
#inspect ⇒ String
Returns a developer-friendly representation of this transaction.
196 197 198 199 |
# File 'lib/rdf/transaction.rb', line 196 def inspect sprintf("#<%s:%#0x(changes: -%d/+%d)>", self.class.name, self.__id__, self.changes.deletes.count, self.changes.inserts.count) end |
#inspect! ⇒ void
This method returns an undefined value.
Outputs a developer-friendly representation of this transaction to ‘stderr`.
206 207 208 |
# File 'lib/rdf/transaction.rb', line 206 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.
173 174 175 |
# File 'lib/rdf/transaction.rb', line 173 def mutable? @mutable end |
#readable? ⇒ Boolean
Returns ‘true` to indicate that this transaction is readable.
182 183 184 |
# File 'lib/rdf/transaction.rb', line 182 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.
232 233 234 235 |
# File 'lib/rdf/transaction.rb', line 232 def rollback @changes = RDF::Changeset.new @rolledback = true end |
#writable? ⇒ Boolean
Returns ‘true` if this is a read/write transaction, `false` otherwise.
164 165 166 |
# File 'lib/rdf/transaction.rb', line 164 def writable? @mutable end |