Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Table of Contents
* [new](#new)
* [set](#set)
* [get](#get)
* [ttl](#ttl)
* [delete](#delete)
* [count](#count)
* [capacity](#capacity)
Expand Down Expand Up @@ -206,6 +207,22 @@ item, its default flags will be `0`.

[Back to TOC](#table-of-contents)

ttl
---
`syntax: ttl = cache:ttl(key, update_queue?)`

Retrieves the remaining TTL (time-to-live in seconds) of a key. If the key does
not exist in the cache or has already expired, `nil` will be returned. If the
key does not have a TTL, `-1` will be returned.

The optional boolean `update_queue` argument specifies if the cache entry will
be put on top of the internal LRU queue (like when calling [cache:set](#set) or
[cache:get](#get)) as part of the `cache:ttl` call.

This feature was first introduced in the v0.16 release.

[Back to TOC](#table-of-contents)

delete
------
`syntax: cache:delete(key)`
Expand Down
31 changes: 31 additions & 0 deletions lib/resty/lrucache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,37 @@ function _M.get(self, key)
end


function _M.ttl(self, key, update_queue)
local hasht = self.hasht
local val = hasht[key]
if val == nil then
return nil
end

local node = self.key2node[key]

if update_queue then
-- print(key, ": moving node ", tostring(node), " to cache queue head")
local cache_queue = self.cache_queue
queue_remove(node)
queue_insert_head(cache_queue, node)
end

local now = ngx_now()
local expire = node.expire
if expire >= 0 then
if expire < now then
-- print("expired: ", expire, " > ", ngx_now())
return nil
else
return expire - now
end
end

return -1
end


function _M.delete(self, key)
self.hasht[key] = nil

Expand Down
33 changes: 33 additions & 0 deletions lib/resty/lrucache/pureffi.lua
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,39 @@ function _M.get(self, key)
end


function _M.ttl(self, key, update_queue)
if type(key) ~= "string" then
key = tostring(key)
end

local node_id = find_key(self, key)
if not node_id then
return nil
end

local node = self.node_v + node_id
if update_queue then
-- print(key, ": moving node ", tostring(node), " to cache queue head")
local cache_queue = self.cache_queue
queue_remove(node)
queue_insert_head(cache_queue, node)
end

local now = ngx_now()
local expire = node.expire
if expire >= 0 then
if expire < now then
-- print("expired: ", expire, " > ", ngx_now())
return nil
else
return expire - now
end
end

return -1
end


function _M.delete(self, key)
if type(key) ~= "string" then
key = tostring(key)
Expand Down
133 changes: 133 additions & 0 deletions t/009-ttl.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# vim:set ft= ts=4 sw=4 et fdm=marker:
use lib '.';
use t::TestLRUCache;

repeat_each(2);

plan tests => repeat_each() * (blocks() * 3);

no_long_string();
run_tests();

__DATA__

=== TEST 1: no ttl
--- config
location = /t {
content_by_lua '
local lrucache = require "resty.lrucache"
local c = lrucache.new(2)
if not c then
ngx.say("failed to init lrucache: ", err)
return
end

c:set("dog", 32)

ngx.say("ttl: ", (c:ttl("dog")))
';
}
--- response_body
ttl: -1



=== TEST 2: ttl defined
--- config
location = /t {
content_by_lua '
local lrucache = require "resty.lrucache"
local c = lrucache.new(2)
if not c then
ngx.say("failed to init lrucache: ", err)
return
end

c:set("dog", 32, 0.2)
ngx.say("ttl: ", ((c:ttl("dog") or 0) > 0))

ngx.sleep(0.3)

ngx.say("ttl: ", ((c:ttl("dog") or 0) > 0))
';
}
--- response_body
ttl: true
ttl: false



=== TEST 3: update_queue is false
--- config
location = /t {
content_by_lua '
local lrucache = require "resty.lrucache"
local c = lrucache.new(2)
if not c then
ngx.say("failed to init lrucache: ", err)
return
end

c:set("dog", 32)
c:set("cat", 33)

ngx.say("dog: ", (c:get("dog")))
ngx.say("cat: ", (c:get("cat")))

ngx.say("ttl cat: ", (c:ttl("cat")))
ngx.say("ttl dog: ", (c:ttl("dog")))

c:set("bird", 76)

ngx.say("dog: ", (c:get("dog")))
ngx.say("cat: ", (c:get("cat")))
ngx.say("bird: ", (c:get("bird")))
';
}
--- response_body
dog: 32
cat: 33
ttl cat: -1
ttl dog: -1
dog: nil
cat: 33
bird: 76



=== TEST 4: update_queue is true
--- config
location = /t {
content_by_lua '
local lrucache = require "resty.lrucache"
local c = lrucache.new(2)
if not c then
ngx.say("failed to init lrucache: ", err)
return
end

c:set("dog", 32)
c:set("cat", 33)

ngx.say("dog: ", (c:get("dog")))
ngx.say("cat: ", (c:get("cat")))

ngx.say("ttl cat: ", (c:ttl("cat", true)))
ngx.say("ttl dog: ", (c:ttl("dog", true)))

c:set("bird", 76)

ngx.say("dog: ", (c:get("dog")))
ngx.say("cat: ", (c:get("cat")))
ngx.say("bird: ", (c:get("bird")))
';
}
--- response_body
dog: 32
cat: 33
ttl cat: -1
ttl dog: -1
dog: 32
cat: nil
bird: 76

133 changes: 133 additions & 0 deletions t/100-pureffi/009-ttl.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# vim:set ft= ts=4 sw=4 et fdm=marker:
use lib '.';
use t::TestLRUCache;

repeat_each(2);

plan tests => repeat_each() * (blocks() * 3);

no_long_string();
run_tests();

__DATA__

=== TEST 1: no ttl
--- config
location = /t {
content_by_lua '
local lrucache = require "resty.lrucache.pureffi"
local c = lrucache.new(2)
if not c then
ngx.say("failed to init lrucache: ", err)
return
end

c:set("dog", 32)

ngx.say("ttl: ", (c:ttl("dog")))
';
}
--- response_body
ttl: -1



=== TEST 2: ttl defined
--- config
location = /t {
content_by_lua '
local lrucache = require "resty.lrucache.pureffi"
local c = lrucache.new(2)
if not c then
ngx.say("failed to init lrucache: ", err)
return
end

c:set("dog", 32, 0.2)
ngx.say("ttl: ", ((c:ttl("dog") or 0) > 0))

ngx.sleep(0.3)

ngx.say("ttl: ", ((c:ttl("dog") or 0) > 0))
';
}
--- response_body
ttl: true
ttl: false



=== TEST 3: update_queue is false
--- config
location = /t {
content_by_lua '
local lrucache = require "resty.lrucache.pureffi"
local c = lrucache.new(2)
if not c then
ngx.say("failed to init lrucache: ", err)
return
end

c:set("dog", 32)
c:set("cat", 33)

ngx.say("dog: ", (c:get("dog")))
ngx.say("cat: ", (c:get("cat")))

ngx.say("ttl cat: ", (c:ttl("cat")))
ngx.say("ttl dog: ", (c:ttl("dog")))

c:set("bird", 76)

ngx.say("dog: ", (c:get("dog")))
ngx.say("cat: ", (c:get("cat")))
ngx.say("bird: ", (c:get("bird")))
';
}
--- response_body
dog: 32
cat: 33
ttl cat: -1
ttl dog: -1
dog: nil
cat: 33
bird: 76



=== TEST 4: update_queue is true
--- config
location = /t {
content_by_lua '
local lrucache = require "resty.lrucache.pureffi"
local c = lrucache.new(2)
if not c then
ngx.say("failed to init lrucache: ", err)
return
end

c:set("dog", 32)
c:set("cat", 33)

ngx.say("dog: ", (c:get("dog")))
ngx.say("cat: ", (c:get("cat")))

ngx.say("ttl cat: ", (c:ttl("cat", true)))
ngx.say("ttl dog: ", (c:ttl("dog", true)))

c:set("bird", 76)

ngx.say("dog: ", (c:get("dog")))
ngx.say("cat: ", (c:get("cat")))
ngx.say("bird: ", (c:get("bird")))
';
}
--- response_body
dog: 32
cat: 33
ttl cat: -1
ttl dog: -1
dog: 32
cat: nil
bird: 76