Skip to content

Commit 1c7b189

Browse files
committed
Finish 3.2.1
2 parents 9a7adc2 + 0f69e30 commit 1c7b189

File tree

5 files changed

+100
-3
lines changed

5 files changed

+100
-3
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.2.0
1+
3.2.1

lib/rdf/repository.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ def self.extend_object(obj)
252252
Hash.new)
253253
obj.instance_variable_set(:@tx_class,
254254
obj.options.delete(:transaction_class) ||
255-
DEFAULT_TX_CLASS)
255+
RDF::Transaction::SerializedTransaction)
256256
super
257257
end
258258

lib/rdf/transaction.rb

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,81 @@ def read_target
322322
end
323323

324324
public
325-
325+
326+
##
327+
# A transaction with full serializability.
328+
#
329+
# @todo refactor me!
330+
# @see RDF::Transaction
331+
class SerializedTransaction < Transaction
332+
##
333+
# @see Transaction#initialize
334+
def initialize(*args, **options, &block)
335+
super(*args, **options, &block)
336+
@base_snapshot = @snapshot
337+
end
338+
339+
##
340+
# Inserts the statement to the transaction's working snapshot.
341+
#
342+
# @see Transaction#insert_statement
343+
def insert_statement(statement)
344+
@snapshot = @snapshot.class
345+
.new(data: @snapshot.send(:insert_to,
346+
@snapshot.send(:data),
347+
process_statement(statement)))
348+
end
349+
350+
##
351+
# Deletes the statement from the transaction's working snapshot.
352+
#
353+
# @see Transaction#insert_statement
354+
def delete_statement(statement)
355+
@snapshot = @snapshot.class
356+
.new(data: @snapshot.send(:delete_from,
357+
@snapshot.send(:data),
358+
process_statement(statement)))
359+
end
360+
361+
##
362+
# @see RDF::Dataset#isolation_level
363+
def isolation_level
364+
:serializable
365+
end
366+
367+
##
368+
# @note this is a simple object equality check.
369+
#
370+
# @see RDF::Transaction#mutated?
371+
def mutated?
372+
!@snapshot.send(:data).equal?(repository.send(:data))
373+
end
374+
375+
##
376+
# Replaces repository data with the transaction's snapshot in a safely
377+
# serializable fashion.
378+
#
379+
# @note this transaction uses a pessimistic merge strategy which
380+
# fails the transaction if any data has changed in the repository
381+
# since transaction start time. However, the specific guarantee is
382+
# softer: multiple concurrent conflicting transactions will not
383+
# succeed. We may choose to implement a less pessimistic merge
384+
# strategy as a non-breaking change.
385+
#
386+
# @raise [TransactionError] when the transaction can't be merged.
387+
# @see Transaction#execute
388+
def execute
389+
raise TransactionError, 'Cannot execute a rolled back transaction. ' \
390+
'Open a new one instead.' if instance_variable_defined?(:@rolledback) && @rolledback
391+
392+
raise TransactionError, 'Error merging transaction. Repository' \
393+
'has changed during transaction time.' unless
394+
repository.send(:data).equal? @base_snapshot.send(:data)
395+
396+
repository.send(:data=, @snapshot.send(:data))
397+
end
398+
end # SerializedTransaction
399+
326400
##
327401
# An error class for transaction failures.
328402
#

spec/repository_spec.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,20 @@
6262
expect(subject.statements.first).to eq existing_statement
6363
expect(subject.statements.first).to be_inferred
6464
end
65+
66+
it "performs coherent list updates" do
67+
# List updates require reading from the repository mid-transaction, which requires a SerializedTransaction
68+
repo = RDF::Repository.new
69+
lh = RDF::Node.new("o")
70+
repo << RDF::Statement.new(RDF::URI('s'), RDF::URI('p'), lh)
71+
expect(repo.count).to eq 1
72+
repo.transaction(mutable: true) do |tx|
73+
list = RDF::List.new(subject: lh, graph: tx, values: %w(a b c))
74+
expect(tx.count).to eq 7
75+
list[0, 2] = %(d)
76+
expect(tx.count).to eq 5
77+
end
78+
expect(repo.count).to eq 5
79+
80+
end
6581
end

spec/transaction_spec.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,10 @@ class MyTx < described_class; end
7676
end
7777
end
7878
end
79+
80+
describe RDF::Transaction::SerializedTransaction do
81+
let(:repository) { RDF::Repository.new }
82+
83+
# @see lib/rdf/spec/transaction.rb in rdf-spec
84+
it_behaves_like "an RDF::Transaction", RDF::Transaction::SerializedTransaction
85+
end

0 commit comments

Comments
 (0)