Class: Locksy::Memory

Inherits:
BaseLock show all
Defined in:
lib/locksy/memory.rb

Class Attribute Summary collapse

Attributes inherited from BaseLock

#_clock, #default_expiry, #default_extension, #lock_name, #owner

Attributes inherited from LockInterface

#default_expiry, #default_extension, #lock_name, #owner

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from BaseLock

#initialize, shutting_down?, #with_lock

Methods inherited from LockInterface

#initialize, #with_lock

Constructor Details

This class inherits a constructor from Locksy::BaseLock

Class Attribute Details

._data_change=(value) ⇒ Object (writeonly)

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



52
53
54
# File 'lib/locksy/memory.rb', line 52

def _data_change=(value)
  @_data_change = value
end

._datastoreObject (readonly)

Returns the value of attribute _datastore.



49
50
51
# File 'lib/locksy/memory.rb', line 49

def _datastore
  @_datastore
end

Class Method Details

._notify_data_changeObject

THIS IS DANGEROUS… CALL ONLY WHEN SYNCHRONIZED IN THE MUTEX



68
69
70
# File 'lib/locksy/memory.rb', line 68

def _notify_data_change
  @_data_change.broadcast
end

._synchronize(&blk) ⇒ Object



58
59
60
# File 'lib/locksy/memory.rb', line 58

def _synchronize(&blk)
  @_singleton_mutex.synchronize(&blk)
end

._wait_for_data_change(timeout = nil) ⇒ Object

THIS IS DANGEROUS… CALL ONLY WHEN SYNCHRONIZED IN THE MUTEX



63
64
65
# File 'lib/locksy/memory.rb', line 63

def _wait_for_data_change(timeout = nil)
  @_data_change.wait(@_singleton_mutex, timeout)
end

.release_all!Object



54
55
56
# File 'lib/locksy/memory.rb', line 54

def release_all!
  _synchronize { @_datastore = {} }
end

Instance Method Details

#obtain_lock(expire_after: default_expiry, wait_for: nil, **_args) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 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) ⇒ Object



44
45
46
# File 'lib/locksy/memory.rb', line 44

def refresh_lock(expire_after: default_extension, **_args)
  obtain_lock expire_after: expire_after
end

#release_lockObject



36
37
38
39
40
41
42
# 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