class Synapse::IdentifierLockManager
Generic lock manager that can be used to lock identifiers for exclusive access
Public Class Methods
@api private @param [IdentifierLockManager] instance @return [undefined]
# File lib/synapse/common/concurrency/identifier_lock_manager.rb, line 19 def add(instance) @mutex.synchronize do @instances[instance] = true end end
@api private @return [Array]
# File lib/synapse/common/concurrency/identifier_lock_manager.rb, line 10 def instances @mutex.synchronize do @instances.keys end end
@return [undefined]
# File lib/synapse/common/concurrency/identifier_lock_manager.rb, line 69 def initialize @locks = Hash.new @mutex = Mutex.new IdentifierLockManager.add self end
@api private @param [Thread] thread @return [Set]
# File lib/synapse/common/concurrency/identifier_lock_manager.rb, line 28 def waiters_for_locks_owned_by(thread) stack = Array.new waiters = Set.new find_waiters thread, instances, waiters, stack waiters end
Private Class Methods
@param [Thread] thread @param [Array] managers @param [Set] waiters @param [Array] stack @return [undefined]
# File lib/synapse/common/concurrency/identifier_lock_manager.rb, line 44 def find_waiters(thread, managers, waiters, stack) stack.push thread for manager in managers for lock in manager.internal_locks next unless lock.owned_by? thread for waiter in lock.waiters # Avoid infinite recursion in the case of an imminent deadlock next if stack.include? waiter # Skip waiters that are already known next unless waiters.add? waiter # Recursively find waiters for locks find_waiters waiter, managers, waiters, stack end end end stack.pop end
Public Instance Methods
@api private @return [Array]
# File lib/synapse/common/concurrency/identifier_lock_manager.rb, line 116 def internal_locks @mutex.synchronize do @locks.values end end
Obtains a lock for the given identifier, blocking until the lock is obtained
@param [Object] identifier @return [undefined]
# File lib/synapse/common/concurrency/identifier_lock_manager.rb, line 89 def obtain_lock(identifier) loop do lock = lock_for identifier return if lock.lock remove_lock identifier, lock end end
Returns true if the calling thread holds the lock for the given identifier
@param [Object] identifier @return [Boolean]
# File lib/synapse/common/concurrency/identifier_lock_manager.rb, line 80 def owned?(identifier) lock_available?(identifier) && lock_for(identifier).owned? end
Releases a lock for the given identifier
@raise [RuntimeError] If no lock was ever obtained for the identifier @param [Object] identifier @return [undefined]
# File lib/synapse/common/concurrency/identifier_lock_manager.rb, line 103 def release_lock(identifier) unless lock_available? identifier raise RuntimeError end lock = lock_for identifier lock.unlock try_dispose identifier, lock end
Private Instance Methods
@param [Object] identifier @return [Boolean]
# File lib/synapse/common/concurrency/identifier_lock_manager.rb, line 158 def lock_available?(identifier) @mutex.synchronize do @locks.has_key? identifier end end
@param [Object] identifier @return [DisposableLock]
# File lib/synapse/common/concurrency/identifier_lock_manager.rb, line 146 def lock_for(identifier) @mutex.synchronize do if @locks.has_key? identifier @locks.fetch identifier else @locks.store identifier, DisposableLock.new end end end
@param [Object] identifier @param [DisposableLock] lock @return [undefined]
# File lib/synapse/common/concurrency/identifier_lock_manager.rb, line 136 def remove_lock(identifier, lock) @mutex.synchronize do @locks.delete_if do |i, l| i == identifier && l == lock end end end
@param [Object] identifier @param [DisposableLock] lock @return [undefined]
# File lib/synapse/common/concurrency/identifier_lock_manager.rb, line 127 def try_dispose(identifier, lock) if lock.try_close remove_lock identifier, lock end end