Software /
code /
prosody
Comparison
plugins/mod_blocklist.lua @ 13345:a74251a790ed
mod_blocklist: Remove weak cache (and increase default LRU cache size)
Weak tables are said to have suboptimal performance, so we might as well
get replace it with an increased default LRU cache size.
Sorry about the 'and'
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sun, 26 Nov 2023 17:41:38 +0100 |
parent | 13213:50324f66ca2a |
child | 13481:1c87c0a7ece6 |
comparison
equal
deleted
inserted
replaced
13344:958c759d3897 | 13345:a74251a790ed |
---|---|
22 | 22 |
23 local storage = module:open_store(); | 23 local storage = module:open_store(); |
24 local sessions = prosody.hosts[module.host].sessions; | 24 local sessions = prosody.hosts[module.host].sessions; |
25 local full_sessions = prosody.full_sessions; | 25 local full_sessions = prosody.full_sessions; |
26 | 26 |
27 -- First level cache of blocklists by username. | 27 -- Cache of blocklists, keeps a fixed number of items. |
28 -- Weak table so may randomly expire at any time. | |
29 local cache = setmetatable({}, { __mode = "v" }); | |
30 | |
31 -- Second level of caching, keeps a fixed number of items, also anchors | |
32 -- items in the above cache. | |
33 -- | 28 -- |
34 -- The size of this affects how often we will need to load a blocklist from | 29 -- The size of this affects how often we will need to load a blocklist from |
35 -- disk, which we want to avoid during routing. On the other hand, we don't | 30 -- disk, which we want to avoid during routing. On the other hand, we don't |
36 -- want to use too much memory either, so this can be tuned by advanced | 31 -- want to use too much memory either, so this can be tuned by advanced |
37 -- users. TODO use science to figure out a better default, 64 is just a guess. | 32 -- users. TODO use science to figure out a better default, 64 is just a guess. |
38 local cache_size = module:get_option_integer("blocklist_cache_size", 64, 1); | 33 local cache_size = module:get_option_integer("blocklist_cache_size", 256, 1); |
39 local cache2 = require"prosody.util.cache".new(cache_size); | 34 local blocklist_cache = require"prosody.util.cache".new(cache_size); |
40 | 35 |
41 local null_blocklist = {}; | 36 local null_blocklist = {}; |
42 | 37 |
43 module:add_feature("urn:xmpp:blocking"); | 38 module:add_feature("urn:xmpp:blocking"); |
44 | 39 |
46 local ok, err = storage:set(username, blocklist); | 41 local ok, err = storage:set(username, blocklist); |
47 if not ok then | 42 if not ok then |
48 return ok, err; | 43 return ok, err; |
49 end | 44 end |
50 -- Successful save, update the cache | 45 -- Successful save, update the cache |
51 cache2:set(username, blocklist); | 46 blocklist_cache:set(username, blocklist); |
52 cache[username] = blocklist; | |
53 return true; | 47 return true; |
54 end | 48 end |
55 | 49 |
56 -- Migrates from the old mod_privacy storage | 50 -- Migrates from the old mod_privacy storage |
57 -- TODO mod_privacy was removed in 0.10.0, this should be phased out | 51 -- TODO mod_privacy was removed in 0.10.0, this should be phased out |
84 return nil; | 78 return nil; |
85 end | 79 end |
86 end | 80 end |
87 | 81 |
88 local function get_blocklist(username) | 82 local function get_blocklist(username) |
89 local blocklist = cache2:get(username); | 83 local blocklist = blocklist_cache:get(username); |
90 if not blocklist then | 84 if not blocklist then |
91 if not user_exists(username, module.host) then | 85 if not user_exists(username, module.host) then |
92 return null_blocklist; | 86 return null_blocklist; |
93 end | 87 end |
94 blocklist = storage:get(username); | 88 blocklist = storage:get(username); |
96 blocklist = migrate_privacy_list(username); | 90 blocklist = migrate_privacy_list(username); |
97 end | 91 end |
98 if not blocklist then | 92 if not blocklist then |
99 blocklist = { [false] = { created = os.time(); }; }; | 93 blocklist = { [false] = { created = os.time(); }; }; |
100 end | 94 end |
101 cache2:set(username, blocklist); | 95 blocklist_cache:set(username, blocklist); |
102 end | 96 end |
103 cache[username] = blocklist; | |
104 return blocklist; | 97 return blocklist; |
105 end | 98 end |
106 | 99 |
107 module:hook("iq-get/self/urn:xmpp:blocking:blocklist", function (event) | 100 module:hook("iq-get/self/urn:xmpp:blocking:blocklist", function (event) |
108 local origin, stanza = event.origin, event.stanza; | 101 local origin, stanza = event.origin, event.stanza; |
109 local username = origin.username; | 102 local username = origin.username; |
110 local reply = st.reply(stanza):tag("blocklist", { xmlns = "urn:xmpp:blocking" }); | 103 local reply = st.reply(stanza):tag("blocklist", { xmlns = "urn:xmpp:blocking" }); |
111 local blocklist = cache[username] or get_blocklist(username); | 104 local blocklist = get_blocklist(username); |
112 for jid in pairs(blocklist) do | 105 for jid in pairs(blocklist) do |
113 if jid then | 106 if jid then |
114 reply:tag("item", { jid = jid }):up(); | 107 reply:tag("item", { jid = jid }):up(); |
115 end | 108 end |
116 end | 109 end |
165 -- <block/> element does not contain at least one <item/> child element | 158 -- <block/> element does not contain at least one <item/> child element |
166 origin.send(st_error_reply(stanza, "modify", "bad-request")); | 159 origin.send(st_error_reply(stanza, "modify", "bad-request")); |
167 return true; | 160 return true; |
168 end | 161 end |
169 | 162 |
170 local blocklist = cache[username] or get_blocklist(username); | 163 local blocklist = get_blocklist(username); |
171 | 164 |
172 local new_blocklist = { | 165 local new_blocklist = { |
173 -- We set the [false] key to something as a signal not to migrate privacy lists | 166 -- We set the [false] key to something as a signal not to migrate privacy lists |
174 [false] = blocklist[false] or { created = now; }; | 167 [false] = blocklist[false] or { created = now; }; |
175 }; | 168 }; |
239 module:hook("iq-set/self/urn:xmpp:blocking:unblock", edit_blocklist, -1); | 232 module:hook("iq-set/self/urn:xmpp:blocking:unblock", edit_blocklist, -1); |
240 | 233 |
241 -- Cache invalidation, solved! | 234 -- Cache invalidation, solved! |
242 module:hook_global("user-deleted", function (event) | 235 module:hook_global("user-deleted", function (event) |
243 if event.host == module.host then | 236 if event.host == module.host then |
244 cache2:set(event.username, nil); | 237 blocklist_cache:set(event.username, nil); |
245 cache[event.username] = nil; | |
246 end | 238 end |
247 end); | 239 end); |
248 | 240 |
249 -- Buggy clients | 241 -- Buggy clients |
250 module:hook("iq-error/self/blocklist-push", function (event) | 242 module:hook("iq-error/self/blocklist-push", function (event) |
255 module.name, condition, text and ": " or "", text or ""); | 247 module.name, condition, text and ": " or "", text or ""); |
256 return true; | 248 return true; |
257 end); | 249 end); |
258 | 250 |
259 local function is_blocked(user, jid) | 251 local function is_blocked(user, jid) |
260 local blocklist = cache[user] or get_blocklist(user); | 252 local blocklist = get_blocklist(user); |
261 if blocklist[jid] then return true; end | 253 if blocklist[jid] then return true; end |
262 local node, host = jid_split(jid); | 254 local node, host = jid_split(jid); |
263 return blocklist[host] or node and blocklist[node..'@'..host]; | 255 return blocklist[host] or node and blocklist[node..'@'..host]; |
264 end | 256 end |
265 | 257 |