Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(pdk) ensure 'kong.ctx.plugin' and 'kong.log' are light-threads safe #5873

Merged
merged 4 commits into from
May 14, 2020
Merged
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
198 changes: 113 additions & 85 deletions kong/global.lua
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,36 @@ function _GLOBAL.set_named_ctx(self, name, key)
error("name cannot be an empty string", 2)
end

if key == nil then
error("key cannot be nil", 2)
end

if not self.ctx then
error("ctx PDK module not initialized", 2)
end

self.ctx.keys[name] = key
self.ctx.__set_namespace(name, key)
end


function _GLOBAL.del_named_ctx(self, name)
if not self then
error("arg #1 cannot be nil", 2)
end

if type(name) ~= "string" then
error("name must be a string", 2)
end

if #name == 0 then
error("name cannot be an empty string", 2)
end

if not self.ctx then
error("ctx PDK module not initialized", 2)
end

self.ctx.__del_namespace(name)
end


Expand All @@ -66,18 +91,15 @@ function _GLOBAL.set_phase(self, phase)

local kctx = self.ctx
if not kctx then
error("ctx SDK module not initialized", 2)
error("ctx PDK module not initialized", 2)
end

kctx.core.phase = phase
end


do
local log_facilities = {
core = nil,
namespaced = setmetatable({}, { __index = "k" }),
}
local log_facilities = setmetatable({}, { __index = "k" })


function _GLOBAL.set_namespaced_log(self, namespace)
Expand All @@ -89,13 +111,17 @@ do
error("namespace (arg #2) must be a string", 2)
end

local log = log_facilities.namespaced[namespace]
if not self.ctx then
error("ctx PDK module not initialized", 2)
end

local log = log_facilities[namespace]
if not log then
log = self.log.new(namespace) -- use default namespaced format
log_facilities.namespaced[namespace] = log
log = self.core_log.new(namespace) -- use default namespaced format
log_facilities[namespace] = log
end

self.log = log
self.ctx.core.log = log
end


Expand All @@ -104,98 +130,100 @@ do
error("arg #1 cannot be nil", 2)
end

self.log = log_facilities.core
end


function _GLOBAL.init_pdk(self, kong_config, pdk_major_version)
if not self then
error("arg #1 cannot be nil", 2)
if not self.ctx then
error("ctx PDK module not initialized", 2)
end

PDK.new(kong_config, pdk_major_version, self)
self.ctx.core.log = self.core_log
end
end

log_facilities.core = self.log

function _GLOBAL.init_pdk(self, kong_config, pdk_major_version)
if not self then
error("arg #1 cannot be nil", 2)
end

PDK.new(kong_config, pdk_major_version, self)
end

function _GLOBAL.init_worker_events()
-- Note: worker_events will not work correctly if required at the top of the file.
-- It must be required right here, inside the init function
local worker_events = require "resty.worker.events"

local ok, err = worker_events.configure {
shm = "kong_process_events", -- defined by "lua_shared_dict"
timeout = 5, -- life time of event data in shm
interval = 1, -- poll interval (seconds)
function _GLOBAL.init_worker_events()
-- Note: worker_events will not work correctly if required at the top of the file.
-- It must be required right here, inside the init function
local worker_events = require "resty.worker.events"

wait_interval = 0.010, -- wait before retry fetching event data
wait_max = 0.5, -- max wait time before discarding event
}
if not ok then
return nil, err
end
local ok, err = worker_events.configure {
shm = "kong_process_events", -- defined by "lua_shared_dict"
timeout = 5, -- life time of event data in shm
interval = 1, -- poll interval (seconds)

return worker_events
wait_interval = 0.010, -- wait before retry fetching event data
wait_max = 0.5, -- max wait time before discarding event
}
if not ok then
return nil, err
end

return worker_events
end

function _GLOBAL.init_cluster_events(kong_config, db)
return kong_cluster_events.new({
db = db,
poll_interval = kong_config.db_update_frequency,
poll_offset = kong_config.db_update_propagation,
poll_delay = kong_config.db_update_propagation,
})
end

function _GLOBAL.init_cluster_events(kong_config, db)
return kong_cluster_events.new({
db = db,
poll_interval = kong_config.db_update_frequency,
poll_offset = kong_config.db_update_propagation,
poll_delay = kong_config.db_update_propagation,
})
end

function _GLOBAL.init_cache(kong_config, cluster_events, worker_events)
local db_cache_ttl = kong_config.db_cache_ttl
local cache_pages = 1
if kong_config.database == "off" then
db_cache_ttl = 0
cache_pages = 2
end

return kong_cache.new {
shm_name = "kong_db_cache",
cluster_events = cluster_events,
worker_events = worker_events,
ttl = db_cache_ttl,
neg_ttl = db_cache_ttl,
resurrect_ttl = kong_config.resurrect_ttl,
cache_pages = cache_pages,
resty_lock_opts = {
exptime = 10,
timeout = 5,
},
}
end


function _GLOBAL.init_core_cache(kong_config, cluster_events, worker_events)
local db_cache_ttl = kong_config.db_cache_ttl
local cache_pages = 1
if kong_config.database == "off" then
db_cache_ttl = 0
cache_pages = 2
end
function _GLOBAL.init_cache(kong_config, cluster_events, worker_events)
local db_cache_ttl = kong_config.db_cache_ttl
local cache_pages = 1
if kong_config.database == "off" then
db_cache_ttl = 0
cache_pages = 2
end

return kong_cache.new {
shm_name = "kong_core_db_cache",
cluster_events = cluster_events,
worker_events = worker_events,
ttl = db_cache_ttl,
neg_ttl = db_cache_ttl,
resurrect_ttl = kong_config.resurrect_ttl,
cache_pages = cache_pages,
resty_lock_opts = {
exptime = 10,
timeout = 5,
},
}
return kong_cache.new {
shm_name = "kong_db_cache",
cluster_events = cluster_events,
worker_events = worker_events,
ttl = db_cache_ttl,
neg_ttl = db_cache_ttl,
resurrect_ttl = kong_config.resurrect_ttl,
cache_pages = cache_pages,
resty_lock_opts = {
exptime = 10,
timeout = 5,
},
}
end


function _GLOBAL.init_core_cache(kong_config, cluster_events, worker_events)
local db_cache_ttl = kong_config.db_cache_ttl
local cache_pages = 1
if kong_config.database == "off" then
db_cache_ttl = 0
cache_pages = 2
end

return kong_cache.new {
shm_name = "kong_core_db_cache",
cluster_events = cluster_events,
worker_events = worker_events,
ttl = db_cache_ttl,
neg_ttl = db_cache_ttl,
resurrect_ttl = kong_config.resurrect_ttl,
cache_pages = cache_pages,
resty_lock_opts = {
exptime = 10,
timeout = 5,
},
}
end


Expand Down
61 changes: 53 additions & 8 deletions kong/pdk/ctx.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@


local ngx = ngx
local ngx_get_phase = ngx.get_phase


-- shared between all global instances
local _CTX_SHARED_KEY = {}
local _CTX_CORE_KEY = {}


-- dynamic namespaces, also shared between global instances
local _CTX_NAMESPACES_KEY = {}


---
-- A table that has the lifetime of the current request and is shared between
-- all plugins. It can be used to share data between several plugins in a given
Expand Down Expand Up @@ -86,19 +91,58 @@ local _CTX_CORE_KEY = {}
--
-- kong.log(value) -- "hello world"
-- end
local function new(self)
local _CTX = {
-- those would be visible on the *.ctx namespace for now
-- TODO: hide them in a private table shared between this
-- module and the global.lua one
keys = setmetatable({}, { __mode = "v" }),
}


local function new(self)
local _CTX = {}
local _ctx_mt = {}
local _ns_mt = { __mode = "v" }


local function get_namespaces(nctx)
local namespaces = nctx[_CTX_NAMESPACES_KEY]
if not namespaces then
-- 4 namespaces for request, i.e. ~4 plugins
namespaces = self.table.new(0, 4)
nctx[_CTX_NAMESPACES_KEY] = setmetatable(namespaces, _ns_mt)
end

return namespaces
end


local function set_namespace(namespace, namespace_key)
local nctx = ngx.ctx
local namespaces = get_namespaces(nctx)

local ns = namespaces[namespace]
if ns and ns == namespace_key then
thibaultcha marked this conversation as resolved.
Show resolved Hide resolved
return
end

namespaces[namespace] = namespace_key
end


local function del_namespace(namespace)
local nctx = ngx.ctx
local namespaces = get_namespaces(nctx)
namespaces[namespace] = nil
thibaultcha marked this conversation as resolved.
Show resolved Hide resolved
end


function _ctx_mt.__index(t, k)
if k == "__set_namespace" then
return set_namespace

elseif k == "__del_namespace" then
return del_namespace
end

if ngx_get_phase() == "init" then
return
end

local nctx = ngx.ctx
local key

Expand All @@ -109,7 +153,8 @@ local function new(self)
key = _CTX_SHARED_KEY

else
key = t.keys[k]
local namespaces = get_namespaces(nctx)
key = namespaces[k]
thibaultcha marked this conversation as resolved.
Show resolved Hide resolved
end

if key then
Expand Down
21 changes: 19 additions & 2 deletions kong/pdk/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ assert(package.loaded["resty.core"])

local MAJOR_VERSIONS = {
[1] = {
version = "1.3.0",
version = "1.3.1",
modules = {
"table",
"node",
Expand Down Expand Up @@ -294,7 +294,24 @@ function _PDK.new(kong_config, major_version, self)
parent[child] = mod.new(self)
end

return self
self._log = self.log
self.log = nil

return setmetatable(self, {
__index = function(t, k)
if k == "core_log" then
return rawget(t, "_log")
end

if k == "log" then
if t.ctx.core and t.ctx.core.log then
return t.ctx.core.log
end

return rawget(t, "_log")
end
end
})
end


Expand Down
2 changes: 2 additions & 0 deletions kong/pdk/log.lua
Original file line number Diff line number Diff line change
Expand Up @@ -442,8 +442,10 @@ do
self.print = nop
end


self.on()


return setmetatable(self, _inspect_mt)
end
end
Expand Down
Loading