Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
22 changes: 20 additions & 2 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,14 @@ local _M = {}
-- alternatively: local lrucache = require "resty.lrucache.pureffi"
local lrucache = require "resty.lrucache"

local function call_back(key, value)
ngx.log(ngx.ERR, "evict:", key, ":", value)
end

-- we need to initialize the cache on the lua module level so that
-- it can be shared by all the requests served by each nginx worker process:
local c, err = lrucache.new(200) -- allow up to 200 items in the cache
local c, err = lrucache.new(2, call_back) -- allow up to 2 items in the cache
-- local c, err = lrucache.new(2, nil, call_back) -- for `resty.lrucache.pureffi`
if not c then
error("failed to create the cache: " .. (err or "unknown"))
end
Expand All @@ -61,6 +66,12 @@ function _M.go()
c:set("dog", { age = 10 }, 0.1) -- expire in 0.1 sec
c:delete("dog")

c:set("dog", 32)
c:set("parrto", 12) -- in log "evict:cat:56"
c:set("cat", 56, 0.1) -- in log "evict:dog:32"
ngx.sleep(1)
ngx.say("cat:", c:get("cat")) -- in log "evict:cat:56"

c:flush_all() -- flush all the cached data
end

Expand Down Expand Up @@ -151,7 +162,9 @@ local lrucache = require "resty.lrucache.pureffi"

new
---
`syntax: cache, err = lrucache.new(max_items [, load_factor])`
`syntax: cache, err = lrucache.new(max_items [, evict_cb])`

`syntax: cache, err = lrucache.new(max_items [, load_factor, evict_cb])`

Creates a new cache instance. Upon failure, returns `nil` and a string
describing the error.
Expand All @@ -167,6 +180,11 @@ saturated to 1; likewise, if load-factor is smaller than `0.1`, it will be
clamped to `0.1`). This argument is only meaningful for
`resty.lrucache.pureffi`.

The `evict_cb` argument specifies the item's destory call back. When use `set`
add new item or `get`(item with ttl), may trigger remove old item, with this
call back you can do some clean up job. The `evict_cb` will receive two param:
key and value.

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

set
Expand Down
9 changes: 8 additions & 1 deletion lib/resty/lrucache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ local function ptr2num(ptr)
end


function _M.new(size)
function _M.new(size, evict_cb)
if size < 1 then
return nil, "size too small"
end
Expand All @@ -164,6 +164,7 @@ function _M.new(size)
node2key = {},
num_items = 0,
max_items = size,
evict_cb = evict_cb,
}
return setmetatable(self, mt)
end
Expand Down Expand Up @@ -195,6 +196,9 @@ function _M.get(self, key)

if node.expire >= 0 and node.expire < ngx_now() then
-- print("expired: ", node.expire, " > ", ngx_now())
if self.evict_cb then
pcall(self.evict_cb, key, val)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we have a error log while running pcall failed? otherwise use will be confuse why their callback did not run.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea, i will add an errlog out put.

end
return nil, val, node.user_flags
end

Expand Down Expand Up @@ -241,6 +245,9 @@ function _M.set(self, key, value, ttl, flags)
-- print(key, ": evicting oldkey: ", oldkey, ", oldnode: ",
-- tostring(node))
if oldkey then
if self.evict_cb then
pcall(self.evict_cb, oldkey, hasht[oldkey])
end
hasht[oldkey] = nil
key2node[oldkey] = nil
end
Expand Down
9 changes: 8 additions & 1 deletion lib/resty/lrucache/pureffi.lua
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ local mt = { __index = _M }
-- load-factor is specified, it will be clamped to the range of [0.1, 1](i.e.
-- if load-factor is greater than 1, it will be saturated to 1, likewise,
-- if load-factor is smaller than 0.1, it will be clamped to 0.1).
function _M.new(size, load_factor)
function _M.new(size, load_factor, evict_cb)
if size < 1 then
return nil, "size too small"
end
Expand Down Expand Up @@ -350,6 +350,7 @@ function _M.new(size, load_factor)
val_v = new_tab(size, 0),
bucket_v = ffi_new(int_array_t, bucket_sz),
num_items = 0,
evict_cb = evict_cb,
}
-- "note_v" is an array of all the nodes used in the LRU queue. Exprpession
-- node_v[i] evaluates to the element of ID "i".
Expand Down Expand Up @@ -489,6 +490,9 @@ function _M.get(self, key)
local expire = node.expire
if expire >= 0 and expire < ngx_now() then
-- print("expired: ", node.expire, " > ", ngx_now())
if self.evict_cb then
pcall(self.evict_cb, key, self.val_v[node_id])
end
return nil, self.val_v[node_id], node.user_flags
end

Expand Down Expand Up @@ -526,6 +530,9 @@ function _M.set(self, key, value, ttl, flags)
-- evict the least recently used key
-- assert(not queue_is_empty(self.cache_queue))
node = queue_last(self.cache_queue)
if self.evict_cb then
pcall(self.evict_cb, self.key_v[node.id], self.val_v[node.id])
end
remove_key(self, self.key_v[node.id])
else
-- take a free queue node
Expand Down
53 changes: 53 additions & 0 deletions t/009-evict-call-back.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# 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: evict with call back
--- config
location = /t {
content_by_lua_block {
local function evict_cb(k,v)
ngx.say(k, v)
end
local lrucache = require "resty.lrucache"
local c = lrucache.new(1, evict_cb)

collectgarbage()

c:set("dog", 12)
c:set("cat", 14)
}
}
--- response_body
dog12



=== TEST 2: evict with call back, ttl
--- config
location = /t {
content_by_lua_block {
local function evict_cb(k,v)
ngx.say(k, v)
end
local lrucache = require "resty.lrucache"
local c = lrucache.new(1, evict_cb)

collectgarbage()

c:set("dog", 12, 0.1)
ngx.sleep(1)
c:get("dog")
}
}
--- response_body
dog12
53 changes: 53 additions & 0 deletions t/100-pureffi/009-evict-call-back.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# 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: evict with call back
--- config
location = /t {
content_by_lua_block {
local function evict_cb(k,v)
ngx.say(k, v)
end
local lrucache = require "resty.lrucache.pureffi"
local c = lrucache.new(1, nil, evict_cb)

collectgarbage()

c:set("dog", 12)
c:set("cat", 14)
}
}
--- response_body
dog12



=== TEST 2: evict with call back, ttl
--- config
location = /t {
content_by_lua_block {
local function evict_cb(k,v)
ngx.say(k, v)
end
local lrucache = require "resty.lrucache.pureffi"
local c = lrucache.new(1, nil, evict_cb)

collectgarbage()

c:set("dog", 12, 1)
ngx.sleep(1)
c:get("dog")
}
}
--- response_body
dog12