From 744960bb1a1a5bfd4931126634b4a904d038c8b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=8F=D0=BD=20=D0=9C=D0=B8=D0=BD=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 28 Nov 2022 14:18:59 -0600 Subject: [PATCH] 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. --- resources/prosody-plugins/mod_jiconop.lua | 25 +++++--- resources/prosody-plugins/token/util.lib.lua | 4 +- resources/prosody-plugins/util.lib.lua | 61 ++++++++++++-------- 3 files changed, 56 insertions(+), 34 deletions(-) diff --git a/resources/prosody-plugins/mod_jiconop.lua b/resources/prosody-plugins/mod_jiconop.lua index 1f6d811a9..7c3fb49cc 100644 --- a/resources/prosody-plugins/mod_jiconop.lua +++ b/resources/prosody-plugins/mod_jiconop.lua @@ -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', diff --git a/resources/prosody-plugins/token/util.lib.lua b/resources/prosody-plugins/token/util.lib.lua index 816c26b40..d8832d59a 100644 --- a/resources/prosody-plugins/token/util.lib.lua +++ b/resources/prosody-plugins/token/util.lib.lua @@ -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 diff --git a/resources/prosody-plugins/util.lib.lua b/resources/prosody-plugins/util.lib.lua index fb876410a..5609a7cd5 100644 --- a/resources/prosody-plugins/util.lib.lua +++ b/resources/prosody-plugins/util.lib.lua @@ -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