Files
2026-07-13 12:32:21 +08:00

142 lines
3.1 KiB
Lua

local cjson = require "cjson.safe"
local ngx = ngx
local type = type
local time = ngx.time
local shared = ngx.shared
local setmetatable = setmetatable
local _M = {}
--- Create new memory strategy object
-- @table opts Strategy options: contains 'dictionary_name' and 'ttl' fields
function _M.new(opts)
local dict = shared[opts.dictionary_name]
local self = {
dict = dict,
opts = opts,
}
return setmetatable(self, {
__index = _M,
})
end
--- Store a new request entity in the shared memory
-- @string key The request key
-- @table req_obj The request object, represented as a table containing
-- everything that needs to be cached
-- @int[opt] ttl The TTL for the request; if nil, use default TTL specified
-- at strategy instantiation time
function _M:store(key, req_obj, req_ttl)
local ttl = req_ttl or self.opts.ttl
if type(key) ~= "string" then
return nil, "key must be a string"
end
-- encode request table representation as JSON
local req_json = cjson.encode(req_obj)
if not req_json then
return nil, "could not encode request object"
end
local succ, err = self.dict:set(key, req_json, ttl)
return succ and req_json or nil, err
end
--- Fetch a cached request
-- @string key The request key
-- @return Table representing the request
function _M:fetch(key)
if type(key) ~= "string" then
return nil, "key must be a string"
end
-- retrieve object from shared dict
local req_json, err = self.dict:get(key)
if not req_json then
if not err then
return nil, "request object not in cache"
else
return nil, err
end
end
-- decode object from JSON to table
local req_obj = cjson.decode(req_json)
if not req_obj then
return nil, "could not decode request object"
end
return req_obj
end
--- Purge an entry from the request cache
-- @return true on success, nil plus error message otherwise
function _M:purge(key)
if type(key) ~= "string" then
return nil, "key must be a string"
end
self.dict:delete(key)
return true
end
--- Reset TTL for a cached request
function _M:touch(key, req_ttl, timestamp)
if type(key) ~= "string" then
return nil, "key must be a string"
end
-- check if entry actually exists
local req_json, err = self.dict:get(key)
if not req_json then
if not err then
return nil, "request object not in cache"
else
return nil, err
end
end
-- decode object from JSON to table
local req_obj = cjson.decode(req_json)
if not req_obj then
return nil, "could not decode request object"
end
-- refresh timestamp field
req_obj.timestamp = timestamp or time()
-- store it again to reset the TTL
return _M:store(key, req_obj, req_ttl)
end
--- Marks all entries as expired and remove them from the memory
-- @param free_mem Boolean indicating whether to free the memory; if false,
-- entries will only be marked as expired
-- @return true on success, nil plus error message otherwise
function _M:flush(free_mem)
-- mark all items as expired
self.dict:flush_all()
-- flush items from memory
if free_mem then
self.dict:flush_expired()
end
return true
end
return _M