142 lines
3.1 KiB
Lua
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
|