Comparison

plugins/mod_storage_internal.lua @ 9883:f76bd399267c

mod_storage_internal,_sql: Add limit to number of items in an archive store (fixes #733)
author Matthew Wild <mwild1@gmail.com>
date Fri, 20 Oct 2017 12:53:53 +0200
parent 9105:e735c9865f42
child 9884:9751c17f5281
comparison
equal deleted inserted replaced
9882:18f025b3987d 9883:f76bd399267c
1 local cache = require "util.cache";
1 local datamanager = require "core.storagemanager".olddm; 2 local datamanager = require "core.storagemanager".olddm;
2 local array = require "util.array"; 3 local array = require "util.array";
3 local datetime = require "util.datetime"; 4 local datetime = require "util.datetime";
4 local st = require "util.stanza"; 5 local st = require "util.stanza";
5 local now = require "util.time".now; 6 local now = require "util.time".now;
6 local id = require "util.id".medium; 7 local id = require "util.id".medium;
7 8
8 local host = module.host; 9 local host = module.host;
9 10
11 local archive_item_limit = module:get_option_number("storage_archive_item_limit", 1000);
12 local archive_item_count_cache = cache.new(module:get_option("storage_archive_item_limit_cache_size", 1000));
13
10 local driver = {}; 14 local driver = {};
11 15
12 function driver:open(store, typ) 16 function driver:open(store, typ)
13 local mt = self[typ or "keyval"] 17 local mt = self[typ or "keyval"]
14 if not mt then 18 if not mt then
52 value.when = when; 56 value.when = when;
53 value.with = with; 57 value.with = with;
54 value.attr.stamp = datetime.datetime(when); 58 value.attr.stamp = datetime.datetime(when);
55 value.attr.stamp_legacy = datetime.legacy(when); 59 value.attr.stamp_legacy = datetime.legacy(when);
56 60
61 local item_count = archive_item_count_cache:get(username);
62
57 if key then 63 if key then
58 local items, err = datamanager.list_load(username, host, self.store); 64 local items, err = datamanager.list_load(username, host, self.store);
59 if not items and err then return items, err; end 65 if not items and err then return items, err; end
66
67 -- Check the quota
68 item_count = items and #items or 0;
69 archive_item_count_cache:set(username, item_count);
70 if item_count >= archive_item_limit then
71 module:log("debug", "%s reached or over quota, not adding to store", username);
72 return nil, "quota-limit";
73 end
74
60 if items then 75 if items then
76 -- Filter out any item with the same key as the one being added
61 items = array(items); 77 items = array(items);
62 items:filter(function (item) 78 items:filter(function (item)
63 return item.key ~= key; 79 return item.key ~= key;
64 end); 80 end);
81
65 value.key = key; 82 value.key = key;
66 items:push(value); 83 items:push(value);
67 local ok, err = datamanager.list_store(username, host, self.store, items); 84 local ok, err = datamanager.list_store(username, host, self.store, items);
68 if not ok then return ok, err; end 85 if not ok then return ok, err; end
86 archive_item_count_cache:set(username, #items);
69 return key; 87 return key;
70 end 88 end
71 else 89 else
90 if not item_count then -- Item count not cached?
91 -- We need to load the list to get the number of items currently stored
92 local items, err = datamanager.list_load(username, host, self.store);
93 if not items and err then return items, err; end
94 item_count = items and #items or 0;
95 archive_item_count_cache:set(username, item_count);
96 end
97 if item_count >= archive_item_limit then
98 module:log("debug", "%s reached or over quota, not adding to store", username);
99 return nil, "quota-limit";
100 end
72 key = id(); 101 key = id();
73 end 102 end
103
104 module:log("debug", "%s has %d items out of %d limit", username, item_count, archive_item_limit);
74 105
75 value.key = key; 106 value.key = key;
76 107
77 local ok, err = datamanager.list_append(username, host, self.store, value); 108 local ok, err = datamanager.list_append(username, host, self.store, value);
78 if not ok then return ok, err; end 109 if not ok then return ok, err; end
110 archive_item_count_cache:set(username, item_count+1);
79 return key; 111 return key;
80 end 112 end
81 113
82 function archive:find(username, query) 114 function archive:find(username, query)
83 local items, err = datamanager.list_load(username, host, self.store); 115 local items, err = datamanager.list_load(username, host, self.store);
156 return array(items):pluck("when"):map(datetime.date):unique(); 188 return array(items):pluck("when"):map(datetime.date):unique();
157 end 189 end
158 190
159 function archive:delete(username, query) 191 function archive:delete(username, query)
160 if not query or next(query) == nil then 192 if not query or next(query) == nil then
193 archive_item_count_cache:set(username, nil);
161 return datamanager.list_store(username, host, self.store, nil); 194 return datamanager.list_store(username, host, self.store, nil);
162 end 195 end
163 local items, err = datamanager.list_load(username, host, self.store); 196 local items, err = datamanager.list_load(username, host, self.store);
164 if not items then 197 if not items then
165 if err then 198 if err then
166 return items, err; 199 return items, err;
167 end 200 end
201 archive_item_count_cache:set(username, 0);
168 -- Store is empty 202 -- Store is empty
169 return 0; 203 return 0;
170 end 204 end
171 items = array(items); 205 items = array(items);
172 local count_before = #items; 206 local count_before = #items;
212 if count == 0 then 246 if count == 0 then
213 return 0; -- No changes, skip write 247 return 0; -- No changes, skip write
214 end 248 end
215 local ok, err = datamanager.list_store(username, host, self.store, items); 249 local ok, err = datamanager.list_store(username, host, self.store, items);
216 if not ok then return ok, err; end 250 if not ok then return ok, err; end
251 archive_item_count_cache:set(username, #items);
217 return count; 252 return count;
218 end 253 end
219 254
220 module:provides("storage", driver); 255 module:provides("storage", driver);