Software / code / prosody
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); |