feat: Several module optimizations to avoid constant parsing of jids. (#12594)

* feat: Several module optimizations to avoid constant parsing of jids.

Caches the parsed values in a rotating table with limited size.
Skips constant creating of a stanza with never changing values - create it once and then just clone it.

* squash: Fixes extract_subdomain multiple values.

* squash: Fix table values when there is a nil element.

* squash: Fix skipping the roomless IQs.

* squash: Fix comments.
This commit is contained in:
Дамян Минков 2022-11-28 14:18:59 -06:00 committed by GitHub
parent 76471a0ea9
commit 744960bb1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 34 deletions

View File

@ -22,21 +22,30 @@ if release_number_config then
module:add_identity("server", "release", release_number_config);
end
-- we cache the query as server identities will not change dynamically, amd use its clone every time
local query_cache;
-- this is after xmpp-bind, the moment a client has resource and can be contacted
module:hook("resource-bind", function (event)
local session = event.session;
-- disco info data / all identity and features
local query = st.stanza("query", { xmlns = "http://jabber.org/protocol/disco#info" });
local done = {};
for _,identity in ipairs(module:get_host_items("identity")) do
local identity_s = identity.category.."\0"..identity.type;
if not done[identity_s] then
query:tag("identity", identity):up();
done[identity_s] = true;
if query_cache == nil then
-- disco info data / all identity and features
local query = st.stanza("query", { xmlns = "http://jabber.org/protocol/disco#info" });
local done = {};
for _,identity in ipairs(module:get_host_items("identity")) do
local identity_s = identity.category.."\0"..identity.type;
if not done[identity_s] then
query:tag("identity", identity):up();
done[identity_s] = true;
end
end
query_cache = query;
end
local query = st.clone(query_cache);
-- check whether room has lobby enabled and display name is required for those trying to join
local lobby_muc_component_config = module:get_option_string('lobby_muc');
module:context(lobby_muc_component_config):fire_event('host-disco-info-node',

View File

@ -273,9 +273,7 @@ end
-- and was not successful
function Util:verify_room(session, room_address)
if self.allowEmptyToken and session.auth_token == nil then
module:log(
"debug",
"Skipped room token verification - empty tokens are allowed");
--module:log("debug", "Skipped room token verification - empty tokens are allowed");
return true;
end

View File

@ -1,6 +1,7 @@
local jid = require "util.jid";
local timer = require "util.timer";
local http = require "net.http";
local cache = require "util.cache";
local http_timeout = 30;
local have_async, async = pcall(require, "util.async");
@ -25,18 +26,24 @@ local target_subdomain_pattern = "^"..escaped_muc_domain_prefix..".([^%.]+)%."..
-- table to store all incoming iqs without roomname in it, like discoinfo to the muc component
local roomless_iqs = {};
local split_subdomain_cache = cache.new(1000);
local extract_subdomain_cache = cache.new(1000);
local internal_room_jid_cache = cache.new(1000);
-- Utility function to split room JID to include room name and subdomain
-- (e.g. from room1@conference.foo.example.com/res returns (room1, example.com, res, foo))
local function room_jid_split_subdomain(room_jid)
local node, host, resource = jid.split(room_jid);
-- optimization, skip matching if there is no subdomain or it is not the muc component address at all
if host == muc_domain or not starts_with(host, muc_domain_prefix) then
return node, host, resource;
local ret = split_subdomain_cache:get(room_jid);
if ret then
return ret.node, ret.host, ret.resource, ret.subdomain;
end
local node, host, resource = jid.split(room_jid);
local target_subdomain = host and host:match(target_subdomain_pattern);
return node, host, resource, target_subdomain
local cache_value = {node=node, host=host, resource=resource, subdomain=target_subdomain};
split_subdomain_cache:set(room_jid, cache_value);
return node, host, resource, target_subdomain;
end
--- Utility function to check and convert a room JID from
@ -69,27 +76,36 @@ end
-- Utility function to check and convert a room JID from real [foo]room1@muc.example.com to virtual room1@muc.foo.example.com
local function internal_room_jid_match_rewrite(room_jid, stanza)
-- first check for roomless_iqs
if (stanza and stanza.attr and stanza.attr.id and roomless_iqs[stanza.attr.id]) then
local result = roomless_iqs[stanza.attr.id];
roomless_iqs[stanza.attr.id] = nil;
return result;
end
local ret = internal_room_jid_cache:get(room_jid);
if ret then
return ret;
end
local node, host, resource = jid.split(room_jid);
if host ~= muc_domain or not node then
-- module:log("debug", "No need to rewrite %s (not from the MUC host)", room_jid);
if (stanza and stanza.attr and stanza.attr.id and roomless_iqs[stanza.attr.id]) then
local result = roomless_iqs[stanza.attr.id];
roomless_iqs[stanza.attr.id] = nil;
return result;
end
internal_room_jid_cache:set(room_jid, room_jid);
return room_jid;
end
local target_subdomain, target_node = extract_subdomain(node);
if not (target_node and target_subdomain) then
-- module:log("debug", "Not rewriting... unexpected node format: %s", node);
internal_room_jid_cache:set(room_jid, room_jid);
return room_jid;
end
-- Ok, rewrite room_jid address to pretty format
return jid.join(target_node, muc_domain_prefix..".".. target_subdomain.."."..muc_domain_base, resource);
ret = jid.join(target_node, muc_domain_prefix..".".. target_subdomain.."."..muc_domain_base, resource);
internal_room_jid_cache:set(room_jid, ret);
return ret;
end
--- Finds and returns room by its jid
@ -242,12 +258,15 @@ end
--- Extracts the subdomain and room name from internal jid node [foo]room1
-- @return subdomain(optional, if extracted or nil), the room name
function extract_subdomain(room_node)
-- optimization, skip matching if there is no subdomain, no [subdomain] part in the beginning of the node
if not starts_with(room_node, '[') then
return nil,room_node;
local ret = extract_subdomain_cache:get(room_node);
if ret then
return ret.subdomain, ret.room;
end
return room_node:match("^%[([^%]]+)%](.+)$");
local subdomain, room_name = room_node:match("^%[([^%]]+)%](.+)$");
local cache_value = {subdomain=subdomain, room=room_name};
extract_subdomain_cache:set(room_node, cache_value);
return subdomain, room_name;
end
function starts_with(str, start)
@ -260,11 +279,7 @@ end
-- healthcheck rooms in jicofo starts with a string '__jicofo-health-check'
function is_healthcheck_room(room_jid)
if starts_with(room_jid, "__jicofo-health-check") then
return true;
end
return false;
return starts_with(room_jid, "__jicofo-health-check");
end
--- Utility function to make an http get request and