class Locksy::Memory

Attributes

_data_change[W]

This is needed to allow tests to inject and control the condition variable

_datastore[R]

Public Class Methods

_notify_data_change() click to toggle source

THIS IS DANGEROUS… CALL ONLY WHEN SYNCHRONIZED IN THE MUTEX

# File lib/locksy/memory.rb, line 68
def _notify_data_change
  @_data_change.broadcast
end
_synchronize(&blk) click to toggle source
# File lib/locksy/memory.rb, line 58
def _synchronize(&blk)
  @_singleton_mutex.synchronize(&blk)
end
_wait_for_data_change(timeout = nil) click to toggle source

THIS IS DANGEROUS… CALL ONLY WHEN SYNCHRONIZED IN THE MUTEX

# File lib/locksy/memory.rb, line 63
def _wait_for_data_change(timeout = nil)
  @_data_change.wait(@_singleton_mutex, timeout)
end
release_all!() click to toggle source
# File lib/locksy/memory.rb, line 54
def release_all!
  _synchronize { @_datastore = {} }
end

Public Instance Methods

obtain_lock(expire_after: default_expiry, wait_for: nil, **_args) click to toggle source
# File lib/locksy/memory.rb, line 9
def obtain_lock(expire_after: default_expiry, wait_for: nil, **_args)
  stop_waiting_at = wait_for ? now + wait_for : nil
  begin
    current = nil
    self.class._synchronize do
      current = _in_mutex_retrieve_lock
      self.class._datastore[lock_name] = [owner, expiry(expire_after)]
      self.class._notify_data_change
    end
  rescue LockNotOwnedError => ex
    if stop_waiting_at && stop_waiting_at > now
      # Maximum wait time for the condition variable before retrying
      # Because it is possible that a condition variable will not be
      # triggered, or may be triggered by something that is not what
      # was expected.
      # Retry at a maximum of 1/2 of the remaining time until the
      # current lock expires or the remaining time from the what the
      # caller was willing to wait, subject to a minimum of 0.1s to
      # prevent busy looping.
      cv_timeout = [stop_waiting_at - now, [(ex.current_expiry - now) / 2, 0.1].max].min
      self.class._synchronize { self.class._wait_for_data_change(cv_timeout) }
      retry unless self.class.shutting_down?
    end
    raise ex
  end
end
refresh_lock(expire_after: default_extension, **_args) click to toggle source
# File lib/locksy/memory.rb, line 44
def refresh_lock(expire_after: default_extension, **_args)
  obtain_lock expire_after: expire_after
end
release_lock() click to toggle source
# File lib/locksy/memory.rb, line 36
def release_lock
  self.class._synchronize do
    _in_mutex_retrieve_lock
    self.class._datastore.delete lock_name
    self.class._notify_data_change
  end
end

Private Instance Methods

_in_mutex_retrieve_lock() click to toggle source
# File lib/locksy/memory.rb, line 79
def _in_mutex_retrieve_lock
  current = self.class._datastore[lock_name]
  if current && current[0] != owner && current[1] > now
    raise LockNotOwnedError.new(lock: self, current_owner: current[0],
                                current_expiry: current[1])
  end
  current
end