Comparison

plugins/mod_storage_sql.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 9691:e11e076f0eb8
child 9884:9751c17f5281
comparison
equal deleted inserted replaced
9882:18f025b3987d 9883:f76bd399267c
1 1
2 -- luacheck: ignore 212/self 2 -- luacheck: ignore 212/self
3 3
4 local cache = require "util.cache";
4 local json = require "util.json"; 5 local json = require "util.json";
5 local sql = require "util.sql"; 6 local sql = require "util.sql";
6 local xml_parse = require "util.xml".parse; 7 local xml_parse = require "util.xml".parse;
7 local uuid = require "util.uuid"; 8 local uuid = require "util.uuid";
8 local resolve_relative_path = require "util.paths".resolve_relative_path; 9 local resolve_relative_path = require "util.paths".resolve_relative_path;
146 return iterator(result); 147 return iterator(result);
147 end 148 end
148 149
149 --- Archive store API 150 --- Archive store API
150 151
152 local archive_item_limit = module:get_option_number("storage_archive_item_limit", 1000);
153 local archive_item_count_cache = cache.new(module:get_option("storage_archive_item_limit_cache_size", 1000));
154
151 -- luacheck: ignore 512 431/user 431/store 155 -- luacheck: ignore 512 431/user 431/store
152 local map_store = {}; 156 local map_store = {};
153 map_store.__index = map_store; 157 map_store.__index = map_store;
154 map_store.remove = {}; 158 map_store.remove = {};
155 function map_store:get(username, key) 159 function map_store:get(username, key)
229 archive_store.caps = { 233 archive_store.caps = {
230 total = true; 234 total = true;
231 }; 235 };
232 archive_store.__index = archive_store 236 archive_store.__index = archive_store
233 function archive_store:append(username, key, value, when, with) 237 function archive_store:append(username, key, value, when, with)
238 local item_count = archive_item_count_cache:get(username);
239 if not item_count then
240 local ok, ret = engine:transaction(function()
241 local count_sql = [[
242 SELECT COUNT(*) FROM "prosodyarchive"
243 WHERE "host"=? AND "user"=? AND "store"=?;
244 ]];
245 local result = engine:select(count_sql, host, user, store);
246 if result then
247 for row in result do
248 item_count = row[1];
249 end
250 end
251 end);
252 if not ok or not item_count then
253 module:log("error", "Failed while checking quota for %s: %s", username, ret);
254 return nil, "Failure while checking quota";
255 end
256 archive_item_count_cache:set(username, item_count);
257 end
258
259 module:log("debug", "%s has %d items out of %d limit", username, item_count, archive_item_limit);
260 if item_count >= archive_item_limit then
261 return nil, "quota-limit";
262 end
263
234 local user,store = username,self.store; 264 local user,store = username,self.store;
235 when = when or os.time(); 265 when = when or os.time();
236 with = with or ""; 266 with = with or "";
237 local ok, ret = engine:transaction(function() 267 local ok, ret = engine:transaction(function()
238 local delete_sql = [[ 268 local delete_sql = [[
243 INSERT INTO "prosodyarchive" 273 INSERT INTO "prosodyarchive"
244 ("host", "user", "store", "when", "with", "key", "type", "value") 274 ("host", "user", "store", "when", "with", "key", "type", "value")
245 VALUES (?,?,?,?,?,?,?,?); 275 VALUES (?,?,?,?,?,?,?,?);
246 ]]; 276 ]];
247 if key then 277 if key then
248 engine:delete(delete_sql, host, user or "", store, key); 278 local result, err = engine:delete(delete_sql, host, user or "", store, key);
279 if result then
280 item_count = item_count - result:affected();
281 archive_item_count_cache:set(username, item_count);
282 end
249 else 283 else
284 item_count = item_count + 1;
250 key = uuid.generate(); 285 key = uuid.generate();
251 end 286 end
252 local t, encoded_value = assert(serialize(value)); 287 local t, encoded_value = assert(serialize(value));
253 engine:insert(insert_sql, host, user or "", store, when, with, key, t, encoded_value); 288 engine:insert(insert_sql, host, user or "", store, when, with, key, t, encoded_value);
289 archive_item_count_cache:set(username, item_count+1);
254 return key; 290 return key;
255 end); 291 end);
256 if not ok then return ok, ret; end 292 if not ok then return ok, ret; end
257 return ret; -- the key 293 return ret; -- the key
258 end 294 end
420 sql_query = string.format(sql_query, t_concat(where, " AND "), 456 sql_query = string.format(sql_query, t_concat(where, " AND "),
421 query.reverse and "ASC" or "DESC", unlimited); 457 query.reverse and "ASC" or "DESC", unlimited);
422 end 458 end
423 return engine:delete(sql_query, unpack(args)); 459 return engine:delete(sql_query, unpack(args));
424 end); 460 end);
461 archive_item_count_cache:set(username, nil);
425 return ok and stmt:affected(), stmt; 462 return ok and stmt:affected(), stmt;
426 end 463 end
427 464
428 local stores = { 465 local stores = {
429 keyval = keyval_store; 466 keyval = keyval_store;