class NoBrainer::Lock
Public Class Methods
find(key)
click to toggle source
Calls superclass method
# File lib/no_brainer/lock.rb, line 17 def self.find(key) super(Digest::SHA1.base64digest(key.to_s)) end
new(key, options={})
click to toggle source
Calls superclass method
# File lib/no_brainer/lock.rb, line 21 def initialize(key, options={}) if options[:from_db] super # We reset our instance_token to allow recoveries. self.instance_token = get_new_instance_token else @default_options = options.slice(:expire, :timeout) options.delete(:expire); options.delete(:timeout); key = key.to_s if key.is_a?(Symbol) super(options.merge(:key => key)) raise ArgumentError unless valid? end end
Public Instance Methods
delete(*)
click to toggle source
# File lib/no_brainer/lock.rb, line 116 def delete(*); raise NotImplementedError; end
get_new_instance_token()
click to toggle source
# File lib/no_brainer/lock.rb, line 36 def get_new_instance_token NoBrainer::Document::PrimaryKey::Generator.generate end
lock(options={})
click to toggle source
# File lib/no_brainer/lock.rb, line 49 def lock(options={}) options.assert_valid_keys(:expire, :timeout) timeout = get_option_value(options, :timeout) sleep_amount = 0.1 start_at = Time.now loop do return if try_lock(options.slice(:expire)) raise_lock_unavailable! if Time.now - start_at + sleep_amount > timeout sleep(sleep_amount) sleep_amount = [1, sleep_amount * 2].min end end
refresh(options={})
click to toggle source
# File lib/no_brainer/lock.rb, line 93 def refresh(options={}) options.assert_valid_keys(:expire) raise_unless_locked! set_expiration(options.merge(:use_previous_expire => true)) result = NoBrainer.run do |r| selector.update do |doc| r.branch(doc[:instance_token].eq(self.instance_token), { :expires_at => self.expires_at }, nil) end end # Note: If we are too quick, expires_at may not change, and the returned # 'replaced' won't be 1. We'll generate a spurious error. This is very # unlikely to happen and should not harmful. unless result['replaced'] == 1 @locked = false raise_lost_lock! end end
save?(*)
click to toggle source
# File lib/no_brainer/lock.rb, line 115 def save?(*); raise NotImplementedError; end
synchronize(options={}, &block)
click to toggle source
# File lib/no_brainer/lock.rb, line 40 def synchronize(options={}, &block) lock(options) begin block.call ensure unlock if @locked end end
try_lock(options={})
click to toggle source
# File lib/no_brainer/lock.rb, line 63 def try_lock(options={}) options.assert_valid_keys(:expire) raise_if_locked! set_expiration(options) result = NoBrainer.run do |r| selector.replace do |doc| r.branch(doc.eq(nil).or(doc[:expires_at] < r.now), self.attributes, doc) end end return @locked = (result['inserted'] + result['replaced']) == 1 end
unlock()
click to toggle source
# File lib/no_brainer/lock.rb, line 79 def unlock raise_unless_locked! result = NoBrainer.run do |r| selector.replace do |doc| r.branch(doc[:instance_token].default(nil).eq(self.instance_token), nil, doc) end end @locked = false raise_lost_lock! unless result['deleted'] == 1 end
Private Instance Methods
get_option_value(options, key)
click to toggle source
# File lib/no_brainer/lock.rb, line 127 def get_option_value(options, key) NoBrainer::Config.lock_options.merge(@default_options || {}).merge(options)[key] end
raise_if_locked!()
click to toggle source
# File lib/no_brainer/lock.rb, line 131 def raise_if_locked! raise NoBrainer::Error::LockInvalidOp.new("Lock instance `#{key}' already locked") if @locked end
raise_lost_lock!()
click to toggle source
# File lib/no_brainer/lock.rb, line 139 def raise_lost_lock! raise NoBrainer::Error::LostLock.new("Lost lock on `#{key}'") end
raise_unless_locked!()
click to toggle source
# File lib/no_brainer/lock.rb, line 135 def raise_unless_locked! raise NoBrainer::Error::LockInvalidOp.new("Lock instance `#{key}' not locked") unless @locked end
set_expiration(options)
click to toggle source
# File lib/no_brainer/lock.rb, line 120 def set_expiration(options) expire = @previous_expire if options[:use_previous_expire] && !options[:expire] expire ||= get_option_value(options, :expire) @previous_expire = expire self.expires_at = RethinkDB::RQL.new.now + expire end