@@ -243,17 +243,16 @@ def begin_transaction(mutable: false, graph_name: nil)
243243 #
244244 # @see RDF::Repository
245245 module Implementation
246- require 'hamster'
247246 DEFAULT_GRAPH = false
248247
249248 ##
250249 # @private
251250 def self . extend_object ( obj )
252251 obj . instance_variable_set ( :@data , obj . options . delete ( :data ) ||
253- Hamster :: Hash . new )
252+ Hash . new )
254253 obj . instance_variable_set ( :@tx_class ,
255254 obj . options . delete ( :transaction_class ) ||
256- SerializedTransaction )
255+ DEFAULT_TX_CLASS )
257256 super
258257 end
259258
@@ -263,7 +262,6 @@ def self.extend_object(obj)
263262 def supports? ( feature )
264263 case feature . to_sym
265264 when :graph_name then @options [ :with_graph_name ]
266- when :inference then false # forward-chaining inference
267265 when :validity then @options . fetch ( :with_validity , true )
268266 when :literal_equality then true
269267 when :atomic_write then true
@@ -381,7 +379,7 @@ def apply_changeset(changeset)
381379 ##
382380 # @see RDF::Dataset#isolation_level
383381 def isolation_level
384- :serializable
382+ :snapshot
385383 end
386384
387385 ##
@@ -471,7 +469,7 @@ def delete_statement(statement)
471469 # @private
472470 # @see RDF::Mutable#clear
473471 def clear_statements
474- @data = @data . clear
472+ @data = @data . class . new
475473 end
476474
477475 ##
@@ -513,14 +511,11 @@ def insert_to(data, statement)
513511 unless statement_in? ( data , statement )
514512 s , p , o , c = statement . to_quad
515513 c ||= DEFAULT_GRAPH
516-
517- return data . put ( c ) do |subs |
518- ( subs || Hamster ::Hash . new ) . put ( s ) do |preds |
519- ( preds || Hamster ::Hash . new ) . put ( p ) do |objs |
520- ( objs || Hamster ::Hash . new ) . put ( o , statement . options )
521- end
522- end
523- end
514+
515+ data = data . has_key? ( c ) ? data . dup : data . merge ( c => { } )
516+ data [ c ] = data [ c ] . has_key? ( s ) ? data [ c ] . dup : data [ c ] . merge ( s => { } )
517+ data [ c ] [ s ] = data [ c ] [ s ] . has_key? ( p ) ? data [ c ] [ s ] . dup : data [ c ] [ s ] . merge ( p => { } )
518+ data [ c ] [ s ] [ p ] = data [ c ] [ s ] [ p ] . merge ( o => statement . options )
524519 end
525520 data
526521 end
@@ -529,93 +524,18 @@ def insert_to(data, statement)
529524 # @private
530525 # @return [Hamster::Hash] a new, updated hamster hash
531526 def delete_from ( data , statement )
532- if statement_in ?( data , statement )
527+ if has_statement_in ?( data , statement )
533528 s , p , o , g = statement . to_quad
534529 g = DEFAULT_GRAPH unless supports? ( :graph_name )
535530 g ||= DEFAULT_GRAPH
536531
537- os = data [ g ] [ s ] [ p ] . delete ( o )
538- ps = os . empty? ? data [ g ] [ s ] . delete ( p ) : data [ g ] [ s ] . put ( p , os )
539- ss = ps . empty? ? data [ g ] . delete ( s ) : data [ g ] . put ( s , ps )
540- return ss . empty? ? data . delete ( g ) : data . put ( g , ss )
532+ os = data [ g ] [ s ] [ p ] . dup . delete_if { | k , v | k == o }
533+ ps = os . empty? ? data [ g ] [ s ] . dup . delete_if { | k , v | k == p } : data [ g ] [ s ] . merge ( p => os )
534+ ss = ps . empty? ? data [ g ] . dup . delete_if { | k , v | k == s } : data [ g ] . merge ( s => ps )
535+ return ss . empty? ? data . dup . delete_if { | k , v | k == g } : data . merge ( g => ss )
541536 end
542537 data
543538 end
544-
545- ##
546- # A transaction for the Hamster-based `RDF::Repository::Implementation`
547- # with full serializability.
548- #
549- # @todo refactor me!
550- # @see RDF::Transaction
551- class SerializedTransaction < Transaction
552- ##
553- # @see Transaction#initialize
554- def initialize ( *args , **options , &block )
555- super ( *args , **options , &block )
556- @base_snapshot = @snapshot
557- end
558-
559- ##
560- # Inserts the statement to the transaction's working snapshot.
561- #
562- # @see Transaction#insert_statement
563- def insert_statement ( statement )
564- @snapshot = @snapshot . class
565- . new ( data : @snapshot . send ( :insert_to ,
566- @snapshot . send ( :data ) ,
567- process_statement ( statement ) ) )
568- end
569-
570- ##
571- # Deletes the statement from the transaction's working snapshot.
572- #
573- # @see Transaction#insert_statement
574- def delete_statement ( statement )
575- @snapshot = @snapshot . class
576- . new ( data : @snapshot . send ( :delete_from ,
577- @snapshot . send ( :data ) ,
578- process_statement ( statement ) ) )
579- end
580-
581- ##
582- # @see RDF::Dataset#isolation_level
583- def isolation_level
584- :serializable
585- end
586-
587- ##
588- # @note this is a simple object equality check.
589- #
590- # @see RDF::Transaction#mutated?
591- def mutated?
592- !@snapshot . send ( :data ) . equal? ( repository . send ( :data ) )
593- end
594-
595- ##
596- # Replaces repository data with the transaction's snapshot in a safely
597- # serializable fashion.
598- #
599- # @note this transaction uses a pessimistic merge strategy which
600- # fails the transaction if any data has changed in the repository
601- # since transaction start time. However, the specific guarantee is
602- # softer: multiple concurrent conflicting transactions will not
603- # succeed. We may choose to implement a less pessimistic merge
604- # strategy as a non-breaking change.
605- #
606- # @raise [TransactionError] when the transaction can't be merged.
607- # @see Transaction#execute
608- def execute
609- raise TransactionError , 'Cannot execute a rolled back transaction. ' \
610- 'Open a new one instead.' if instance_variable_defined? ( :@rolledback ) && @rolledback
611-
612- raise TransactionError , 'Error merging transaction. Repository' \
613- 'has changed during transaction time.' unless
614- repository . send ( :data ) . equal? @base_snapshot . send ( :data )
615-
616- repository . send ( :data= , @snapshot . send ( :data ) )
617- end
618- end
619539 end # Implementation
620540 end # Repository
621541end # RDF
0 commit comments