class Concurrent::Transaction
def self.current
def self.current CURRENT_TRANSACTION.value end
def self.current=(transaction)
def self.current=(transaction) CURRENT_TRANSACTION.value = transaction end
def abort
def abort @undo_log.each do |entry| entry.tvar.unsafe_value = entry.value end unlock end
def commit
def commit return false unless valid? @write_set.each do |tvar| tvar.unsafe_increment_version end unlock true end
def initialize
def initialize @write_set = Set.new @read_log = [] @undo_log = [] end
def read(tvar)
def read(tvar) Concurrent::abort_transaction unless valid? @read_log.push(ReadLogEntry.new(tvar, tvar.unsafe_version)) tvar.unsafe_value end
def unlock
def unlock @write_set.each do |tvar| tvar.unsafe_lock.unlock end end
def valid?
def valid? @read_log.each do |log_entry| unless @write_set.include? log_entry.tvar if log_entry.tvar.unsafe_version > log_entry.version return false end end end true end
def write(tvar, value)
def write(tvar, value) # Have we already written to this TVar? unless @write_set.include? tvar # Try to lock the TVar unless tvar.unsafe_lock.try_lock # Someone else is writing to this TVar - abort Concurrent::abort_transaction end # We've locked it - add it to the write set @write_set.add(tvar) # If we previously wrote to it, check the version hasn't changed @read_log.each do |log_entry| if log_entry.tvar == tvar and tvar.unsafe_version > log_entry.version Concurrent::abort_transaction end end end # Record the current value of the TVar so we can undo it later @undo_log.push(UndoLogEntry.new(tvar, tvar.unsafe_value)) # Write the new value to the TVar tvar.unsafe_value = value end