Module: Redis::EM::Mutex::ScriptHandlerMixin
- Includes:
- Errors
- Defined in:
- lib/redis/em-mutex/script_handler.rb
Defined Under Namespace
Modules: Scripts
Class Method Summary collapse
Instance Method Summary collapse
-
#expiration_timestamp ⇒ Object
Returns timestamp at which the semaphore will expire or have expired.
-
#expired? ⇒ Boolean
Returns ‘true` when the semaphore is being held and have already expired.
-
#expires_at ⇒ Object
Returns local time at which the semaphore will expire or have expired.
-
#expires_in ⇒ Object
Returns the number of seconds left until the semaphore expires.
-
#lock(block_timeout = nil) ⇒ Object
Attempts to grab the lock and waits if it isn’t available.
-
#locked? ⇒ Boolean
Returns ‘true` if this semaphore (at least one of locked `names`) is currently being held by some owner.
-
#owned? ⇒ Boolean
Returns ‘true` if this semaphore (all the locked `names`) is currently being held by calling owner.
- #owner_ident ⇒ Object
-
#refresh(expire_timeout = nil) ⇒ Object
Refreshes lock expiration timeout.
-
#try_lock ⇒ Object
Attempts to obtain the lock and returns immediately.
-
#unlock! ⇒ Object
Releases the lock.
Class Method Details
.can_refresh_expired? ⇒ Boolean
8 |
# File 'lib/redis/em-mutex/script_handler.rb', line 8 def self.can_refresh_expired?; false end |
Instance Method Details
#expiration_timestamp ⇒ Object
Returns timestamp at which the semaphore will expire or have expired. Returns ‘nil` if the semaphore wasn’t locked by current owner.
The check is performed only on the Mutex object instance and should only be used as a hint. For reliable lock status information use #refresh or #owned? instead.
103 104 105 |
# File 'lib/redis/em-mutex/script_handler.rb', line 103 def @lock_expire if @lock_expire && owner_ident == @locked_owner_id end |
#expired? ⇒ Boolean
Returns ‘true` when the semaphore is being held and have already expired. Returns `false` when the semaphore is still locked and valid or `nil` if the semaphore wasn’t locked by current owner.
The check is performed only on the Mutex object instance and should only be used as a hint. For reliable lock status information use #refresh or #owned? instead.
74 75 76 |
# File 'lib/redis/em-mutex/script_handler.rb', line 74 def expired? Time.now.to_f > @lock_expire if @lock_expire && owner_ident == @locked_owner_id end |
#expires_at ⇒ Object
Returns local time at which the semaphore will expire or have expired. Returns ‘nil` if the semaphore wasn’t locked by current owner.
The check is performed only on the Mutex object instance and should only be used as a hint. For reliable lock status information use #refresh or #owned? instead.
94 95 96 |
# File 'lib/redis/em-mutex/script_handler.rb', line 94 def expires_at Time.at(@lock_expire) if @lock_expire && owner_ident == @locked_owner_id end |
#expires_in ⇒ Object
Returns the number of seconds left until the semaphore expires. The number of seconds less than 0 means that the semaphore expired and could be grabbed by some other owner. Returns ‘nil` if the semaphore wasn’t locked by current owner.
The check is performed only on the Mutex object instance and should only be used as a hint. For reliable lock status information use #refresh or #owned? instead.
85 86 87 |
# File 'lib/redis/em-mutex/script_handler.rb', line 85 def expires_in @lock_expire.to_f - Time.now.to_f if @lock_expire && owner_ident == @locked_owner_id end |
#lock(block_timeout = nil) ⇒ Object
Attempts to grab the lock and waits if it isn’t available. Raises MutexError if mutex was locked by the current owner. Returns ‘true` if lock was successfully obtained. Returns `false` if lock wasn’t available within ‘block_timeout` seconds.
If ‘block_timeout` is `nil` or omited this method uses Mutex#block_timeout. If also Mutex#block_timeout is nil this method returns only after lock has been granted.
Use Mutex#expire_timeout= to set lock expiration timeout. Otherwise global Mutex.default_expire is used.
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/redis/em-mutex/script_handler.rb', line 162 def lock(block_timeout = nil) block_timeout||= self.block_timeout names = @ns_names timer = fiber = nil try_again = false sig_proc = proc do try_again = true ::EM.next_tick { fiber.resume if fiber } if fiber end begin Mutex.start_watcher unless watching? queues = names.map {|n| signal_queue[n] << sig_proc } ident_match = owner_ident loop do start_time = Time.now.to_f case timeout = eval_safe(@eval_lock, names, [ident_match, ((lock_expire = (Time.now + expire_timeout).to_f)*1000.0).to_i]) when 'OK' @locked_owner_id = ident_match @lock_expire = lock_expire break when 'DD' raise MutexError, "deadlock; recursive locking #{ident_match}" else expire_time = start_time + (timeout/=1000.0) timeout = block_timeout if block_timeout && block_timeout < timeout if !try_again && timeout > 0 timer = ::EM::Timer.new(timeout) do timer = nil ::EM.next_tick { fiber.resume if fiber } if fiber end fiber = Fiber.current Fiber.yield fiber = nil end finish_time = Time.now.to_f if try_again || finish_time > expire_time block_timeout-= finish_time - start_time if block_timeout try_again = false else return false end end end true ensure timer.cancel if timer timer = nil queues.each {|q| q.delete sig_proc } names.each {|n| signal_queue.delete(n) if signal_queue[n].empty? } end end |
#locked? ⇒ Boolean
Returns ‘true` if this semaphore (at least one of locked `names`) is currently being held by some owner.
52 53 54 55 56 57 58 |
# File 'lib/redis/em-mutex/script_handler.rb', line 52 def locked? if sha1 = @eval_is_locked 1 == eval_safe(sha1, @ns_names) else redis_pool.exists @ns_names.first end end |
#owned? ⇒ Boolean
Returns ‘true` if this semaphore (all the locked `names`) is currently being held by calling owner. This is the method you should use to check if lock is still held and valid.
62 63 64 65 66 |
# File 'lib/redis/em-mutex/script_handler.rb', line 62 def owned? !!if owner_ident == (lock_full_ident = @locked_owner_id) redis_pool.mget(*@ns_names).all? {|v| v == lock_full_ident} end end |
#owner_ident ⇒ Object
47 48 49 |
# File 'lib/redis/em-mutex/script_handler.rb', line 47 def owner_ident "#{uuid}$#$$@#{Fiber.current.__id__}" end |
#refresh(expire_timeout = nil) ⇒ Object
Refreshes lock expiration timeout. Returns ‘true` if refresh was successfull. Returns `false` if the semaphore wasn’t locked or when it was locked but it has expired.
127 128 129 130 131 132 133 134 135 136 |
# File 'lib/redis/em-mutex/script_handler.rb', line 127 def refresh(expire_timeout=nil) if @lock_expire && owner_ident == (lock_full_ident = @locked_owner_id) lock_expire = (Time.now + (expire_timeout.to_f.nonzero? || self.expire_timeout)).to_f !!if 1 == eval_safe(@eval_refresh, @ns_names, [lock_full_ident, (lock_expire*1000.0).to_i]) @lock_expire = lock_expire end else false end end |
#try_lock ⇒ Object
Attempts to obtain the lock and returns immediately. Returns ‘true` if the lock was granted. Use Mutex#expire_timeout= to set lock expiration time in secods. Otherwise global Mutex.default_expire is used.
This method captures expired semaphores only in “script” implementation and therefore it should NEVER be used under normal circumstances. Use Mutex#lock with block_timeout = 0 to obtain expired lock without blocking.
115 116 117 118 119 120 121 122 |
# File 'lib/redis/em-mutex/script_handler.rb', line 115 def try_lock lock_expire = (Time.now + expire_timeout).to_f lock_full_ident = owner_ident !!if 1 == eval_safe(@eval_try_lock, @ns_names, [lock_full_ident, (lock_expire*1000.0).to_i]) @lock_expire = lock_expire @locked_owner_id = lock_full_ident end end |
#unlock! ⇒ Object
Releases the lock. Returns self on success. Returns ‘false` if the semaphore wasn’t locked or when it was locked but it has expired and now it’s got a new owner. In case of unlocking multiple name semaphore this method returns self only when all of the names have been unlocked successfully.
143 144 145 146 147 148 149 |
# File 'lib/redis/em-mutex/script_handler.rb', line 143 def unlock! if (lock_expire = @lock_expire) && owner_ident == (lock_full_ident = @locked_owner_id) @locked_owner_id = @lock_expire = nil removed = eval_safe(@eval_unlock, @ns_names, [lock_full_ident, SIGNAL_QUEUE_CHANNEL, @marsh_names]) end return removed == @ns_names.length && self end |