-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
refactor(clustering) dpcp config clean #8880
Changes from all commits
31152d1
283a966
2595d8e
3179b83
dd506af
cb924a0
a1f148d
8fa4a6a
63b3edd
0f1e9f0
65a3f9a
c122969
2284eb2
8c4fb09
6a48b69
68925f9
3ec4be2
8709d5d
486c70f
b8ed36f
61075ae
c060981
66abd81
21f79b9
3b04364
16dee27
4da6404
0a8bf89
de66e7a
c5be4cf
d5436d7
e4b74d7
9d4169a
ea83d84
5eba885
bd244b6
329688e
4b8895d
69e1204
66d10d7
7affc3e
07fd555
79a275d
9a2bc91
031c18e
310a3b5
18f7fb5
36e6540
69a003d
7c98016
e4c3543
4f0adb1
a615cbb
0f8a2eb
436cb82
5a25d4d
e9cb7d1
0155ea8
fe2d337
de945de
288e667
6d5aa75
cddc8e2
4ea4949
092ad86
6ea52d0
c5bb0cd
7287710
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
local constants = require("kong.constants") | ||
kikito marked this conversation as resolved.
Show resolved
Hide resolved
|
||
local declarative = require("kong.db.declarative") | ||
|
||
local tostring = tostring | ||
local assert = assert | ||
local type = type | ||
local error = error | ||
local pairs = pairs | ||
local ipairs = ipairs | ||
local concat = table.concat | ||
local sort = table.sort | ||
|
||
local isempty = require("table.isempty") | ||
local isarray = require("table.isarray") | ||
local nkeys = require("table.nkeys") | ||
local new_tab = require("table.new") | ||
|
||
local yield = require("kong.tools.utils").yield | ||
|
||
local ngx_log = ngx.log | ||
local ngx_null = ngx.null | ||
local ngx_md5 = ngx.md5 | ||
local ngx_md5_bin = ngx.md5_bin | ||
|
||
local ngx_DEBUG = ngx.DEBUG | ||
|
||
local DECLARATIVE_EMPTY_CONFIG_HASH = constants.DECLARATIVE_EMPTY_CONFIG_HASH | ||
local _log_prefix = "[clustering] " | ||
|
||
|
||
local _M = {} | ||
|
||
|
||
local function to_sorted_string(value) | ||
yield(true) | ||
|
||
if value == ngx_null then | ||
return "/null/" | ||
end | ||
|
||
local t = type(value) | ||
if t == "string" or t == "number" then | ||
return value | ||
end | ||
|
||
if t == "boolean" then | ||
return tostring(value) | ||
end | ||
|
||
if t == "table" then | ||
if isempty(value) then | ||
return "{}" | ||
end | ||
|
||
if isarray(value) then | ||
local count = #value | ||
if count == 1 then | ||
return to_sorted_string(value[1]) | ||
end | ||
|
||
if count == 2 then | ||
return to_sorted_string(value[1]) .. ";" .. | ||
to_sorted_string(value[2]) | ||
end | ||
|
||
if count == 3 then | ||
return to_sorted_string(value[1]) .. ";" .. | ||
to_sorted_string(value[2]) .. ";" .. | ||
to_sorted_string(value[3]) | ||
end | ||
|
||
if count == 4 then | ||
return to_sorted_string(value[1]) .. ";" .. | ||
to_sorted_string(value[2]) .. ";" .. | ||
to_sorted_string(value[3]) .. ";" .. | ||
to_sorted_string(value[4]) | ||
end | ||
|
||
if count == 5 then | ||
return to_sorted_string(value[1]) .. ";" .. | ||
to_sorted_string(value[2]) .. ";" .. | ||
to_sorted_string(value[3]) .. ";" .. | ||
to_sorted_string(value[4]) .. ";" .. | ||
to_sorted_string(value[5]) | ||
end | ||
|
||
local i = 0 | ||
local o = new_tab(count < 100 and count or 100, 0) | ||
for j = 1, count do | ||
i = i + 1 | ||
o[i] = to_sorted_string(value[j]) | ||
|
||
if j % 100 == 0 then | ||
i = 1 | ||
o[i] = ngx_md5_bin(concat(o, ";", 1, 100)) | ||
end | ||
Comment on lines
+93
to
+96
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are there plans to fix this off-by-one error? on every There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems true. Shall we fix it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe we can use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don't know. mentioned it just that it can be discussed. probably in a separate PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think perhaps we can not change it because of the compatibility of old version. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the hash method has changed several times already. there's no compatibility issue There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's fix the off-by-one error on this PR then then. Another PR will make everything take even longer. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It will force us to modify all the hashes on the test, which is a pain. New directive: Do it only if it can be done quickly on this PR. We have lived with the problem so far. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can do it later, now we should finish refactoring first. |
||
end | ||
|
||
return ngx_md5_bin(concat(o, ";", 1, i)) | ||
|
||
else | ||
local count = nkeys(value) | ||
local keys = new_tab(count, 0) | ||
local i = 0 | ||
for k in pairs(value) do | ||
i = i + 1 | ||
keys[i] = k | ||
end | ||
|
||
sort(keys) | ||
|
||
local o = new_tab(count, 0) | ||
for i = 1, count do | ||
o[i] = keys[i] .. ":" .. to_sorted_string(value[keys[i]]) | ||
end | ||
|
||
value = concat(o, ";", 1, count) | ||
|
||
return #value > 512 and ngx_md5_bin(value) or value | ||
end -- isarray | ||
|
||
end -- table | ||
|
||
error("invalid type to be sorted (JSON types are supported)") | ||
end | ||
|
||
local function calculate_config_hash(config_table) | ||
if type(config_table) ~= "table" then | ||
local config_hash = ngx_md5(to_sorted_string(config_table)) | ||
return config_hash, { config = config_hash, } | ||
end | ||
|
||
local routes = config_table.routes | ||
local services = config_table.services | ||
local plugins = config_table.plugins | ||
local upstreams = config_table.upstreams | ||
local targets = config_table.targets | ||
|
||
local routes_hash = routes and ngx_md5(to_sorted_string(routes)) or DECLARATIVE_EMPTY_CONFIG_HASH | ||
local services_hash = services and ngx_md5(to_sorted_string(services)) or DECLARATIVE_EMPTY_CONFIG_HASH | ||
local plugins_hash = plugins and ngx_md5(to_sorted_string(plugins)) or DECLARATIVE_EMPTY_CONFIG_HASH | ||
local upstreams_hash = upstreams and ngx_md5(to_sorted_string(upstreams)) or DECLARATIVE_EMPTY_CONFIG_HASH | ||
local targets_hash = targets and ngx_md5(to_sorted_string(targets)) or DECLARATIVE_EMPTY_CONFIG_HASH | ||
|
||
config_table.routes = nil | ||
config_table.services = nil | ||
config_table.plugins = nil | ||
config_table.upstreams = nil | ||
config_table.targets = nil | ||
|
||
local config_hash = ngx_md5(to_sorted_string(config_table) .. routes_hash | ||
.. services_hash | ||
.. plugins_hash | ||
.. upstreams_hash | ||
.. targets_hash) | ||
|
||
config_table.routes = routes | ||
config_table.services = services | ||
config_table.plugins = plugins | ||
config_table.upstreams = upstreams | ||
config_table.targets = targets | ||
|
||
return config_hash, { | ||
config = config_hash, | ||
routes = routes_hash, | ||
services = services_hash, | ||
plugins = plugins_hash, | ||
upstreams = upstreams_hash, | ||
targets = targets_hash, | ||
} | ||
end | ||
|
||
local hash_fields = { | ||
"config", | ||
"routes", | ||
"services", | ||
"plugins", | ||
"upstreams", | ||
"targets", | ||
} | ||
|
||
local function fill_empty_hashes(hashes) | ||
for _, field_name in ipairs(hash_fields) do | ||
hashes[field_name] = hashes[field_name] or DECLARATIVE_EMPTY_CONFIG_HASH | ||
end | ||
end | ||
|
||
function _M.update(declarative_config, config_table, config_hash, hashes) | ||
assert(type(config_table) == "table") | ||
|
||
if not config_hash then | ||
config_hash, hashes = calculate_config_hash(config_table) | ||
end | ||
|
||
if hashes then | ||
fill_empty_hashes(hashes) | ||
end | ||
|
||
local current_hash = declarative.get_current_hash() | ||
if current_hash == config_hash then | ||
ngx_log(ngx_DEBUG, _log_prefix, "same config received from control plane, ", | ||
"no need to reload") | ||
return true | ||
end | ||
|
||
local entities, err, _, meta, new_hash = | ||
declarative_config:parse_table(config_table, config_hash) | ||
if not entities then | ||
return nil, "bad config received from control plane " .. err | ||
end | ||
|
||
if current_hash == new_hash then | ||
ngx_log(ngx_DEBUG, _log_prefix, "same config received from control plane, ", | ||
"no need to reload") | ||
return true | ||
end | ||
|
||
-- NOTE: no worker mutex needed as this code can only be | ||
-- executed by worker 0 | ||
|
||
local res | ||
res, err = declarative.load_into_cache_with_events(entities, meta, new_hash, hashes) | ||
if not res then | ||
return nil, err | ||
end | ||
|
||
return true | ||
end | ||
|
||
|
||
_M.calculate_config_hash = calculate_config_hash | ||
|
||
|
||
return _M |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when is this coming back?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without these, this PR is doing more than a refactor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After this PR, we will try another method to implement similar feature.