From 319472b6e73af6925fbe958dcb99801fe48c1759 Mon Sep 17 00:00:00 2001 From: thefosk Date: Wed, 21 Sep 2016 17:34:48 -0700 Subject: [PATCH] feat(lock) exptime can be set per key --- README.markdown | 4 +++- lib/resty/lock.lua | 7 +++++-- t/sanity.t | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/README.markdown b/README.markdown index 5286671..013f945 100644 --- a/README.markdown +++ b/README.markdown @@ -118,12 +118,14 @@ Specifies the maximal step size (i.e., sleep interval, in seconds) allowed. See lock ---- -`syntax: elapsed, err = obj:lock(key)` +`syntax: elapsed, err = obj:lock(key, exptime)` Tries to lock a key across all the Nginx worker processes in the current Nginx server instance. Different keys are different locks. The length of the key string must not be larger than 65535 bytes. +The optional `exptime` argument allows to set an expiration time (in seconds) for the key. + Returns the waiting time (in seconds) if the lock is successfully acquired. Otherwise returns `nil` and a string describing the error. The waiting time is not from the wallclock, but rather is from simply adding up all the waiting "steps". A nonzero `elapsed` return value indicates that someone else has just hold this lock. But a zero return value cannot gurantee that no one else has just acquired and released the lock. diff --git a/lib/resty/lock.lua b/lib/resty/lock.lua index cf305cb..353843b 100644 --- a/lib/resty/lock.lua +++ b/lib/resty/lock.lua @@ -117,7 +117,7 @@ function _M.new(_, dict_name, opts) end -function _M.lock(self, key) +function _M.lock(self, key, exptime) if not key then return nil, "nil key" end @@ -127,7 +127,7 @@ function _M.lock(self, key) if cdata.key_id > 0 then return nil, "locked" end - local exptime = self.exptime + local exptime = exptime or self.exptime local ok, err = dict:add(key, true, exptime) if ok then cdata.key_id = ref_obj(key) @@ -143,6 +143,9 @@ function _M.lock(self, key) local step = self.step local ratio = self.ratio local timeout = self.timeout + if timeout and timeout > exptime then + timeout = exptime + end local max_step = self.max_step local elapsed = 0 while timeout > 0 do diff --git a/t/sanity.t b/t/sanity.t index b04497c..9450399 100644 --- a/t/sanity.t +++ b/t/sanity.t @@ -468,3 +468,37 @@ lock 2: unlock: nil, unlocked --- no_error_log [error] + + +=== TEST 14: lock expired by itself when set per key +--- http_config eval: $::HttpConfig +--- config + location = /t { + content_by_lua ' + local resty_lock = require "resty.lock" + local key = "blah" + local t, err = ngx.thread.spawn(function () + local lock = resty_lock:new("cache_locks") + local elapsed, err = lock:lock(key, 0.1) + ngx.say("sub thread: lock: ", elapsed, " ", err) + ngx.sleep(0.1) + -- ngx.say("sub thread: unlock: ", lock:unlock(key)) + end) + + local lock = resty_lock:new("cache_locks", { max_step = 0.05 }) + local elapsed, err = lock:lock(key) + ngx.say("main thread: lock: ", elapsed, " ", err) + ngx.say("main thread: unlock: ", lock:unlock()) + '; + } +--- request +GET /t +--- response_body_like chop +^sub thread: lock: 0 nil +main thread: lock: 0.11[2-4]\d* nil +main thread: unlock: 1 +$ +--- no_error_log +[error] + +