From 8c626a9d96cf2106822648d5b38d11a352a822cf Mon Sep 17 00:00:00 2001 From: "chengjie.zhou" Date: Wed, 3 Jun 2020 17:27:42 +0800 Subject: [PATCH 1/6] add evict call back func in lrucache --- lib/resty/lrucache.lua | 6 +++++- lib/resty/lrucache/pureffi.lua | 6 +++++- t/009-evict-call-back.t | 31 +++++++++++++++++++++++++++++ t/100-pureffi/009-evict-call-back.t | 31 +++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 t/009-evict-call-back.t create mode 100644 t/100-pureffi/009-evict-call-back.t diff --git a/lib/resty/lrucache.lua b/lib/resty/lrucache.lua index 147842a..2eed0bc 100644 --- a/lib/resty/lrucache.lua +++ b/lib/resty/lrucache.lua @@ -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 @@ -164,6 +164,7 @@ function _M.new(size) node2key = {}, num_items = 0, max_items = size, + evict_cb = evict_cb, } return setmetatable(self, mt) end @@ -241,6 +242,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 + self.evict_cb(oldkey, hasht[oldkey]) + end hasht[oldkey] = nil key2node[oldkey] = nil end diff --git a/lib/resty/lrucache/pureffi.lua b/lib/resty/lrucache/pureffi.lua index fc1103e..5beacca 100644 --- a/lib/resty/lrucache/pureffi.lua +++ b/lib/resty/lrucache/pureffi.lua @@ -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 @@ -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". @@ -526,6 +527,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 + 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 diff --git a/t/009-evict-call-back.t b/t/009-evict-call-back.t new file mode 100644 index 0000000..2a82bb0 --- /dev/null +++ b/t/009-evict-call-back.t @@ -0,0 +1,31 @@ +# 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 ' + 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 diff --git a/t/100-pureffi/009-evict-call-back.t b/t/100-pureffi/009-evict-call-back.t new file mode 100644 index 0000000..6813593 --- /dev/null +++ b/t/100-pureffi/009-evict-call-back.t @@ -0,0 +1,31 @@ +# 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 ' + 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 From 9e42cfd68d7df15471fa63ee7ba88ebd976940c4 Mon Sep 17 00:00:00 2001 From: "chengjie.zhou" Date: Tue, 9 Jun 2020 01:27:40 +0800 Subject: [PATCH 2/6] add usage; use content_by_lua_block; use pcall wrap call evict func; add call evict_cb at get with ttl item --- README.markdown | 67 ++++++++++++++++++----------- lib/resty/lrucache.lua | 5 ++- lib/resty/lrucache/pureffi.lua | 5 ++- t/009-evict-call-back.t | 26 ++++++++++- t/100-pureffi/009-evict-call-back.t | 26 ++++++++++- 5 files changed, 99 insertions(+), 30 deletions(-) diff --git a/README.markdown b/README.markdown index c4da2f8..f7ca19b 100644 --- a/README.markdown +++ b/README.markdown @@ -6,28 +6,29 @@ lua-resty-lrucache - Lua-land LRU cache based on the LuaJIT FFI. Table of Contents ================= -* [Name](#name) -* [Status](#status) -* [Synopsis](#synopsis) -* [Description](#description) -* [Methods](#methods) - * [new](#new) - * [set](#set) - * [get](#get) - * [delete](#delete) - * [count](#count) - * [capacity](#capacity) - * [get_keys](#get_keys) - * [flush_all](#flush_all) -* [Prerequisites](#prerequisites) -* [Installation](#installation) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Bugs and Patches](#bugs-and-patches) -* [Author](#author) -* [Copyright and License](#copyright-and-license) -* [See Also](#see-also) +1. [Name](#name) +2. [Table of Contents](#table-of-contents) +3. [Status](#status) +4. [Synopsis](#synopsis) +5. [Description](#description) +6. [Methods](#methods) + 1. [new](#new) + 2. [set](#set) + 3. [get](#get) + 4. [delete](#delete) + 5. [count](#count) + 6. [capacity](#capacity) + 7. [get_keys](#get_keys) + 8. [flush_all](#flush_all) +7. [Prerequisites](#prerequisites) +8. [Installation](#installation) +9. [Community](#community) + 1. [English Mailing List](#english-mailing-list) + 2. [Chinese Mailing List](#chinese-mailing-list) +10. [Bugs and Patches](#bugs-and-patches) +11. [Author](#author) +12. [Copyright and License](#copyright-and-license) +13. [See Also](#see-also) Status ====== @@ -45,9 +46,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 @@ -61,6 +67,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 @@ -151,7 +163,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. @@ -167,6 +181,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 diff --git a/lib/resty/lrucache.lua b/lib/resty/lrucache.lua index 2eed0bc..71782fd 100644 --- a/lib/resty/lrucache.lua +++ b/lib/resty/lrucache.lua @@ -196,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) + end return nil, val, node.user_flags end @@ -243,7 +246,7 @@ function _M.set(self, key, value, ttl, flags) -- tostring(node)) if oldkey then if self.evict_cb then - self.evict_cb(oldkey, hasht[oldkey]) + pcall(self.evict_cb, oldkey, hasht[oldkey]) end hasht[oldkey] = nil key2node[oldkey] = nil diff --git a/lib/resty/lrucache/pureffi.lua b/lib/resty/lrucache/pureffi.lua index 5beacca..857e722 100644 --- a/lib/resty/lrucache/pureffi.lua +++ b/lib/resty/lrucache/pureffi.lua @@ -490,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 @@ -528,7 +531,7 @@ function _M.set(self, key, value, ttl, flags) -- assert(not queue_is_empty(self.cache_queue)) node = queue_last(self.cache_queue) if self.evict_cb then - self.evict_cb(self.key_v[node.id], self.val_v[node.id]) + pcall(self.evict_cb, self.key_v[node.id], self.val_v[node.id]) end remove_key(self, self.key_v[node.id]) else diff --git a/t/009-evict-call-back.t b/t/009-evict-call-back.t index 2a82bb0..fabfa57 100644 --- a/t/009-evict-call-back.t +++ b/t/009-evict-call-back.t @@ -14,7 +14,7 @@ __DATA__ === TEST 1: evict with call back --- config location = /t { - content_by_lua ' + content_by_lua_block { local function evict_cb(k,v) ngx.say(k, v) end @@ -25,7 +25,29 @@ __DATA__ 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 diff --git a/t/100-pureffi/009-evict-call-back.t b/t/100-pureffi/009-evict-call-back.t index 6813593..252969d 100644 --- a/t/100-pureffi/009-evict-call-back.t +++ b/t/100-pureffi/009-evict-call-back.t @@ -14,7 +14,7 @@ __DATA__ === TEST 1: evict with call back --- config location = /t { - content_by_lua ' + content_by_lua_block { local function evict_cb(k,v) ngx.say(k, v) end @@ -25,7 +25,29 @@ __DATA__ 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 From 74cb21e9ab752925e8369328be1051952856a46e Mon Sep 17 00:00:00 2001 From: "chengjie.zhou" Date: Tue, 23 Jun 2020 11:30:08 +0800 Subject: [PATCH 3/6] revert toc filed --- README.markdown | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/README.markdown b/README.markdown index f7ca19b..a520a3b 100644 --- a/README.markdown +++ b/README.markdown @@ -6,29 +6,28 @@ lua-resty-lrucache - Lua-land LRU cache based on the LuaJIT FFI. Table of Contents ================= -1. [Name](#name) -2. [Table of Contents](#table-of-contents) -3. [Status](#status) -4. [Synopsis](#synopsis) -5. [Description](#description) -6. [Methods](#methods) - 1. [new](#new) - 2. [set](#set) - 3. [get](#get) - 4. [delete](#delete) - 5. [count](#count) - 6. [capacity](#capacity) - 7. [get_keys](#get_keys) - 8. [flush_all](#flush_all) -7. [Prerequisites](#prerequisites) -8. [Installation](#installation) -9. [Community](#community) - 1. [English Mailing List](#english-mailing-list) - 2. [Chinese Mailing List](#chinese-mailing-list) -10. [Bugs and Patches](#bugs-and-patches) -11. [Author](#author) -12. [Copyright and License](#copyright-and-license) -13. [See Also](#see-also) +* [Name](#name) +* [Status](#status) +* [Synopsis](#synopsis) +* [Description](#description) +* [Methods](#methods) + * [new](#new) + * [set](#set) + * [get](#get) + * [delete](#delete) + * [count](#count) + * [capacity](#capacity) + * [get_keys](#get_keys) + * [flush_all](#flush_all) +* [Prerequisites](#prerequisites) +* [Installation](#installation) +* [Community](#community) + * [English Mailing List](#english-mailing-list) + * [Chinese Mailing List](#chinese-mailing-list) +* [Bugs and Patches](#bugs-and-patches) +* [Author](#author) +* [Copyright and License](#copyright-and-license) +* [See Also](#see-also) Status ====== From 16bf4313c0f107159788d83953d58e7b21323730 Mon Sep 17 00:00:00 2001 From: "chengjie.zhou" Date: Tue, 30 Jun 2020 19:57:42 +0800 Subject: [PATCH 4/6] add pcall error check --- lib/resty/lrucache.lua | 10 ++++++++-- lib/resty/lrucache/pureffi.lua | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/resty/lrucache.lua b/lib/resty/lrucache.lua index 71782fd..c17085a 100644 --- a/lib/resty/lrucache.lua +++ b/lib/resty/lrucache.lua @@ -197,7 +197,10 @@ 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) + local ok, err = pcall(self.evict_cb, key, val) + if not ok then + ngx.log(ngx.ERR, "evict expire key:", key, " fail:", err) + end end return nil, val, node.user_flags end @@ -246,7 +249,10 @@ function _M.set(self, key, value, ttl, flags) -- tostring(node)) if oldkey then if self.evict_cb then - pcall(self.evict_cb, oldkey, hasht[oldkey]) + local ok, err = pcall(self.evict_cb, oldkey, hasht[oldkey]) + if not ok then + ngx.log(ngx.ERR, "evict old key:", oldkey, " fail:", err) + end end hasht[oldkey] = nil key2node[oldkey] = nil diff --git a/lib/resty/lrucache/pureffi.lua b/lib/resty/lrucache/pureffi.lua index 857e722..f14f062 100644 --- a/lib/resty/lrucache/pureffi.lua +++ b/lib/resty/lrucache/pureffi.lua @@ -491,7 +491,10 @@ function _M.get(self, key) 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]) + local ok, err = pcall(self.evict_cb, key, self.val_v[node_id]) + if not ok then + ngx.log(ngx.ERR, "evict expire key:", key, " fail:", err) + end end return nil, self.val_v[node_id], node.user_flags end @@ -531,7 +534,10 @@ function _M.set(self, key, value, ttl, flags) -- 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]) + local ok, err = pcall(self.evict_cb, self.key_v[node.id], self.val_v[node.id]) + if not ok then + ngx.log(ngx.ERR, "evict old key:", self.key_v[node.id], " fail:", err) + end end remove_key(self, self.key_v[node.id]) else From 35f40f9578ba71bf761343b62c6645be74b50f7d Mon Sep 17 00:00:00 2001 From: "chengjie.zhou" Date: Sun, 5 Jul 2020 10:48:40 +0800 Subject: [PATCH 5/6] add evict_cb type check --- lib/resty/lrucache.lua | 4 ++++ lib/resty/lrucache/pureffi.lua | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/lib/resty/lrucache.lua b/lib/resty/lrucache.lua index c17085a..5677cce 100644 --- a/lib/resty/lrucache.lua +++ b/lib/resty/lrucache.lua @@ -156,6 +156,10 @@ function _M.new(size, evict_cb) return nil, "size too small" end + if type(evict_cb) ~= "function" then + return nil, "evict_cb type error" + end + local self = { hasht = {}, free_queue = queue_init(size), diff --git a/lib/resty/lrucache/pureffi.lua b/lib/resty/lrucache/pureffi.lua index f14f062..f7307fa 100644 --- a/lib/resty/lrucache/pureffi.lua +++ b/lib/resty/lrucache/pureffi.lua @@ -323,6 +323,10 @@ function _M.new(size, load_factor, evict_cb) return nil, "size too small" end + if type(evict_cb) ~= "function" then + return nil, "evict_cb type error" + end + -- Determine bucket size, which must be power of two. local load_f = load_factor if not load_factor then From e2b6d6e9a123ad7208587268235ef0922e53bc44 Mon Sep 17 00:00:00 2001 From: "chengjie.zhou" Date: Sun, 5 Jul 2020 11:00:57 +0800 Subject: [PATCH 6/6] evict_cb exist then do type check --- lib/resty/lrucache.lua | 2 +- lib/resty/lrucache/pureffi.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/resty/lrucache.lua b/lib/resty/lrucache.lua index 5677cce..7bc46d4 100644 --- a/lib/resty/lrucache.lua +++ b/lib/resty/lrucache.lua @@ -156,7 +156,7 @@ function _M.new(size, evict_cb) return nil, "size too small" end - if type(evict_cb) ~= "function" then + if evict_cb and type(evict_cb) ~= "function" then return nil, "evict_cb type error" end diff --git a/lib/resty/lrucache/pureffi.lua b/lib/resty/lrucache/pureffi.lua index f7307fa..070fbb7 100644 --- a/lib/resty/lrucache/pureffi.lua +++ b/lib/resty/lrucache/pureffi.lua @@ -323,7 +323,7 @@ function _M.new(size, load_factor, evict_cb) return nil, "size too small" end - if type(evict_cb) ~= "function" then + if evict_cb and type(evict_cb) ~= "function" then return nil, "evict_cb type error" end