Class: RubyReactor::Lock

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_reactor/lock.rb

Defined Under Namespace

Classes: AcquisitionError, ContextLockContention

Constant Summary collapse

MIN_EXTEND_INTERVAL =

Minimum interval between auto-extend pings; protects very small TTLs.

1.0

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key, owner:, ttl: 60, wait: 0, auto_extend: true) ⇒ Lock

Returns a new instance of Lock.



25
26
27
28
29
30
31
32
33
# File 'lib/ruby_reactor/lock.rb', line 25

def initialize(key, owner:, ttl: 60, wait: 0, auto_extend: true)
  @key = "lock:#{key}"
  @owner = owner
  @ttl = ttl
  @wait = wait
  @auto_extend = auto_extend
  @extender = nil
  @extender_running = false
end

Instance Attribute Details

#auto_extendObject (readonly)

Returns the value of attribute auto_extend.



23
24
25
# File 'lib/ruby_reactor/lock.rb', line 23

def auto_extend
  @auto_extend
end

#keyObject (readonly)

Returns the value of attribute key.



23
24
25
# File 'lib/ruby_reactor/lock.rb', line 23

def key
  @key
end

#ownerObject (readonly)

Returns the value of attribute owner.



23
24
25
# File 'lib/ruby_reactor/lock.rb', line 23

def owner
  @owner
end

#ttlObject (readonly)

Returns the value of attribute ttl.



23
24
25
# File 'lib/ruby_reactor/lock.rb', line 23

def ttl
  @ttl
end

#waitObject (readonly)

Returns the value of attribute wait.



23
24
25
# File 'lib/ruby_reactor/lock.rb', line 23

def wait
  @wait
end

Instance Method Details

#acquireObject



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/ruby_reactor/lock.rb', line 35

def acquire
  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)

  loop do
    if adapter.lock_acquire(@key, @owner, @ttl)
      start_extender if @auto_extend
      return true
    end

    if @wait.zero? || (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time) >= @wait
      raise AcquisitionError, "Could not acquire lock '#{@key}' for owner '#{@owner}'"
    end

    sleep 0.1
  end
end

#detachObject

Park support: stop refreshing the TTL but LEAVE the key held — the parked execution keeps ownership through the gap, bounded by the TTL.



59
60
61
# File 'lib/ruby_reactor/lock.rb', line 59

def detach
  stop_extender
end

#reattachObject

Resume ownership after a parked gap: verify we are still the owner and refresh the TTL — WITHOUT incrementing the reentrancy count. The count was never decremented at park, so a plain acquire here would bump it to 2 and the final release would leave the key behind until TTL. Returns false when ownership lapsed (TTL expired mid-park); the caller falls back to a fresh acquire.



69
70
71
72
73
74
# File 'lib/ruby_reactor/lock.rb', line 69

def reattach # rubocop:disable Naming/PredicateMethod
  return false unless adapter.lock_extend(@key, @owner, @ttl)

  start_extender if @auto_extend
  true
end

#releaseObject



52
53
54
55
# File 'lib/ruby_reactor/lock.rb', line 52

def release
  stop_extender
  adapter.lock_release(@key, @owner)
end

#synchronizeObject



76
77
78
79
80
81
# File 'lib/ruby_reactor/lock.rb', line 76

def synchronize
  acquire
  yield
ensure
  release
end