def lock
raise StackingLockError, "<#{ @path }> is locked!" if @locked
sweep unless @dont_sweep
ret = nil
attempt do
begin
@sleep_cycle.reset
create_tmplock do |f|
begin
Timeout.timeout(@timeout) do
tmp_path = f.path
tmp_stat = f.lstat
n_retries = 0
trace{ "attempting to lock <#{ @path }>..." }
begin
i = 0
begin
trace{ "polling attempt <#{ i }>..." }
begin
File.link tmp_path, @path
rescue Errno::ENOENT
try_again!
end
lock_stat = File.lstat @path
raise StatLockError, "stat's do not agree" unless
tmp_stat.rdev == lock_stat.rdev and tmp_stat.ino == lock_stat.ino
trace{ "aquired lock <#{ @path }>" }
@locked = true
rescue => e
i += 1
unless i >= @poll_retries
t = [rand(@poll_max_sleep), @poll_max_sleep].min
trace{ "poll sleep <#{ t }>..." }
sleep t
retry
end
raise
end
rescue => e
n_retries += 1
trace{ "n_retries <#{ n_retries }>" }
case validlock?
when true
raise MaxTriesLockError, "surpased retries <#{ @retries }>" if
@retries and n_retries >= @retries
trace{ "found valid lock" }
sleeptime = @sleep_cycle.next
trace{ "sleep <#{ sleeptime }>..." }
sleep sleeptime
when false
trace{ "found invalid lock and removing" }
begin
File.unlink @path
@thief = true
warn "<#{ @path }> stolen by <#{ Process.pid }> at <#{ timestamp }>"
trace{ "i am a thief!" }
rescue Errno::ENOENT
end
trace{ "suspending <#{ @suspend }>" }
sleep @suspend
when nil
raise MaxTriesLockError, "surpased retries <#{ @retries }>" if
@retries and n_retries >= @retries
end
retry
end
end
rescue Timeout::Error
raise TimeoutLockError, "surpassed timeout <#{ @timeout }>"
end
end
if block_given?
stolen = false
@refresher = (@refresh ? new_refresher : nil)
begin
begin
ret = yield @path
rescue StolenLockError
stolen = true
raise
end
ensure
begin
@refresher.kill if @refresher and @refresher.status
@refresher = nil
ensure
unlock unless stolen
end
end
else
@refresher = (@refresh ? new_refresher : nil)
ObjectSpace.define_finalizer self, @clean if @clean
ret = self
end
rescue Errno::ESTALE, Errno::EIO => e
raise(NFSLockError, errmsg(e))
end
end
return ret
end