bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "lib.h"
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainen#include "ioloop.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "str.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "dict.h"
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen#include "mail-user.h"
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen#include "mail-namespace.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "quota-private.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
51dbc2d559815da774f8ee5faf0e28df3c8d40c0Timo Sirainen#define DICT_QUOTA_CURRENT_PATH DICT_PATH_PRIVATE"quota/"
51dbc2d559815da774f8ee5faf0e28df3c8d40c0Timo Sirainen#define DICT_QUOTA_CURRENT_BYTES_PATH DICT_QUOTA_CURRENT_PATH"storage"
51dbc2d559815da774f8ee5faf0e28df3c8d40c0Timo Sirainen#define DICT_QUOTA_CURRENT_COUNT_PATH DICT_QUOTA_CURRENT_PATH"messages"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstruct dict_quota_root {
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct quota_root root;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen struct dict *dict;
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainen struct timeout *to_update;
6b0e35b29f65a95fe8ae22ed8b5f0f36720c9f45Timo Sirainen bool disable_unset;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen};
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenextern struct quota_backend quota_backend_dict;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic struct quota_root *dict_quota_alloc(void)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen struct dict_quota_root *root;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen root = i_new(struct dict_quota_root, 1);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return &root->root;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1f166c4a7498b4b6bdf6f072edeaebb388cc53ebSergey Kitovstatic void handle_nounset_param(struct quota_root *_root, const char *param_value ATTR_UNUSED)
1f166c4a7498b4b6bdf6f072edeaebb388cc53ebSergey Kitov{
1f166c4a7498b4b6bdf6f072edeaebb388cc53ebSergey Kitov ((struct dict_quota_root *)_root)->disable_unset = TRUE;
1f166c4a7498b4b6bdf6f072edeaebb388cc53ebSergey Kitov}
1f166c4a7498b4b6bdf6f072edeaebb388cc53ebSergey Kitov
9b61a6db87c026656f8d2ae214e4486b98a069c0Timo Sirainenstatic int dict_quota_init(struct quota_root *_root, const char *args,
9b61a6db87c026656f8d2ae214e4486b98a069c0Timo Sirainen const char **error_r)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen struct dict_quota_root *root = (struct dict_quota_root *)_root;
9346506a9f4dd9a6285fe8595588e73161849235Timo Sirainen struct dict_settings set;
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen const char *username, *p, *error;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1f166c4a7498b4b6bdf6f072edeaebb388cc53ebSergey Kitov const struct quota_param_parser dict_params[] = {
1f166c4a7498b4b6bdf6f072edeaebb388cc53ebSergey Kitov {.param_name = "no-unset", .param_handler = handle_nounset_param},
1f166c4a7498b4b6bdf6f072edeaebb388cc53ebSergey Kitov quota_param_hidden, quota_param_ignoreunlimited, quota_param_noenforcing, quota_param_ns,
1f166c4a7498b4b6bdf6f072edeaebb388cc53ebSergey Kitov {.param_name = NULL}
1f166c4a7498b4b6bdf6f072edeaebb388cc53ebSergey Kitov };
1f166c4a7498b4b6bdf6f072edeaebb388cc53ebSergey Kitov
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen p = args == NULL ? NULL : strchr(args, ':');
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (p == NULL) {
9b61a6db87c026656f8d2ae214e4486b98a069c0Timo Sirainen *error_r = "URI missing from parameters";
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen username = t_strdup_until(args, p);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen args = p+1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
fde14422caabc3c4ac4a6c5e3e5cf176cedd90a6Timo Sirainen if (quota_parse_parameters(_root, &args, error_r, dict_params, FALSE) < 0)
fde14422caabc3c4ac4a6c5e3e5cf176cedd90a6Timo Sirainen i_unreached();
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (*username == '\0')
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen username = _root->quota->user->username;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (_root->quota->set->debug) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("dict quota: user=%s, uri=%s, noenforcing=%d",
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen username, args, _root->no_enforcing ? 1 : 0);
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen /* FIXME: we should use 64bit integer as datatype instead but before
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen it can actually be used don't bother */
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&set);
9346506a9f4dd9a6285fe8595588e73161849235Timo Sirainen set.username = username;
9346506a9f4dd9a6285fe8595588e73161849235Timo Sirainen set.base_dir = _root->quota->user->set->base_dir;
9346506a9f4dd9a6285fe8595588e73161849235Timo Sirainen if (mail_user_get_home(_root->quota->user, &set.home_dir) <= 0)
9346506a9f4dd9a6285fe8595588e73161849235Timo Sirainen set.home_dir = NULL;
20e04227229970d148801c507946666e2a9bd838Timo Sirainen if (dict_init(args, &set, &root->dict, &error) < 0) {
9b61a6db87c026656f8d2ae214e4486b98a069c0Timo Sirainen *error_r = t_strdup_printf("dict_init(%s) failed: %s", args, error);
10399559650f552a23949772be79eb6a80198c5aTimo Sirainen return -1;
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen }
10399559650f552a23949772be79eb6a80198c5aTimo Sirainen return 0;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic void dict_quota_deinit(struct quota_root *_root)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct dict_quota_root *root = (struct dict_quota_root *)_root;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainen i_assert(root->to_update == NULL);
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainen
3764f786a6d13b23c49c9990b816be1e23a1adccAki Tuomi if (root->dict != NULL) {
3764f786a6d13b23c49c9990b816be1e23a1adccAki Tuomi dict_wait(root->dict);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen dict_deinit(&root->dict);
3764f786a6d13b23c49c9990b816be1e23a1adccAki Tuomi }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_free(root);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic const char *const *
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainendict_quota_root_get_resources(struct quota_root *root ATTR_UNUSED)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen static const char *resources[] = {
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen QUOTA_NAME_STORAGE_KILOBYTES, QUOTA_NAME_MESSAGES, NULL
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen };
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return resources;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvistatic enum quota_get_result
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainendict_quota_count(struct dict_quota_root *root,
2b4e421b76d997e2ad18c74200d9d8521bed165cMartti Rannanjärvi bool want_bytes, uint64_t *value_r,
2b4e421b76d997e2ad18c74200d9d8521bed165cMartti Rannanjärvi const char **error_r)
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen{
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen struct dict_transaction_context *dt;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen uint64_t bytes, count;
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi enum quota_get_result error_res;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi if (quota_count(&root->root, &bytes, &count, &error_res, error_r) < 0)
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi return error_res;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi dt = dict_transaction_begin(root->dict);
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi /* these unsets are mainly necessary for pgsql, because its
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi trigger otherwise increases quota without deleting it.
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi but some people with other databases want to store the
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi quota usage among other data in the same row, which
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi shouldn't be deleted. */
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi if (!root->disable_unset) {
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi dict_unset(dt, DICT_QUOTA_CURRENT_BYTES_PATH);
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi dict_unset(dt, DICT_QUOTA_CURRENT_COUNT_PATH);
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi }
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi dict_set(dt, DICT_QUOTA_CURRENT_BYTES_PATH, dec2str(bytes));
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi dict_set(dt, DICT_QUOTA_CURRENT_COUNT_PATH, dec2str(count));
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen
1bb7fb04a0583f0d5160706f24b2df08d31ada46Timo Sirainen if (root->root.quota->set->debug) {
1bb7fb04a0583f0d5160706f24b2df08d31ada46Timo Sirainen i_debug("dict quota: Quota recalculated: "
1bb7fb04a0583f0d5160706f24b2df08d31ada46Timo Sirainen "count=%"PRIu64" bytes=%"PRIu64, count, bytes);
1bb7fb04a0583f0d5160706f24b2df08d31ada46Timo Sirainen }
1bb7fb04a0583f0d5160706f24b2df08d31ada46Timo Sirainen
02d91785bcf42ced46080db91c29bb534fbe2d1cTimo Sirainen dict_transaction_commit_async(&dt, NULL, NULL);
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen *value_r = want_bytes ? bytes : count;
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi return QUOTA_GET_RESULT_LIMITED;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen}
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvistatic enum quota_get_result
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainendict_quota_get_resource(struct quota_root *_root,
a525be16a69367f43765d20c873b5f168c5b7ea3Martti Rannanjärvi const char *name, uint64_t *value_r,
a525be16a69367f43765d20c873b5f168c5b7ea3Martti Rannanjärvi const char **error_r)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen struct dict_quota_root *root = (struct dict_quota_root *)_root;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen bool want_bytes;
f8ead0942a9b7c8fcf91414ed1b534d5807ca555Timo Sirainen int ret;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen if (strcmp(name, QUOTA_NAME_STORAGE_BYTES) == 0)
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen want_bytes = TRUE;
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0)
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen want_bytes = FALSE;
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi else {
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi *error_r = QUOTA_UNKNOWN_RESOURCE_ERROR_STRING;
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi return QUOTA_GET_RESULT_UNKNOWN_RESOURCE;
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi const char *key, *value, *error;
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi key = want_bytes ? DICT_QUOTA_CURRENT_BYTES_PATH :
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi DICT_QUOTA_CURRENT_COUNT_PATH;
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi ret = dict_lookup(root->dict, unsafe_data_stack_pool,
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi key, &value, &error);
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi if (ret < 0) {
2b4e421b76d997e2ad18c74200d9d8521bed165cMartti Rannanjärvi *error_r = t_strdup_printf(
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi "dict_lookup(%s) failed: %s", key, error);
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi *value_r = 0;
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi return QUOTA_GET_RESULT_INTERNAL_ERROR;
5729882717902b5f3f5d62f71ddf2894b67fc7a6Martti Rannanjärvi }
995c0a88e9a32e0ec1460567ce5f2ce6e7ba1f13Martti Rannanjärvi
995c0a88e9a32e0ec1460567ce5f2ce6e7ba1f13Martti Rannanjärvi intmax_t tmp;
995c0a88e9a32e0ec1460567ce5f2ce6e7ba1f13Martti Rannanjärvi /* recalculate quota if it's negative or if it wasn't found */
995c0a88e9a32e0ec1460567ce5f2ce6e7ba1f13Martti Rannanjärvi if (ret == 0 || str_to_intmax(value, &tmp) < 0)
995c0a88e9a32e0ec1460567ce5f2ce6e7ba1f13Martti Rannanjärvi tmp = -1;
995c0a88e9a32e0ec1460567ce5f2ce6e7ba1f13Martti Rannanjärvi if (tmp >= 0)
995c0a88e9a32e0ec1460567ce5f2ce6e7ba1f13Martti Rannanjärvi *value_r = tmp;
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi else
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi return dict_quota_count(root, want_bytes, value_r, error_r);
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi return QUOTA_GET_RESULT_LIMITED;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainenstatic void dict_quota_recalc_timeout(struct dict_quota_root *root)
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainen{
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainen uint64_t value;
2b4e421b76d997e2ad18c74200d9d8521bed165cMartti Rannanjärvi const char *error;
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainen
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainen timeout_remove(&root->to_update);
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi if (dict_quota_count(root, TRUE, &value, &error)
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi <= QUOTA_GET_RESULT_INTERNAL_ERROR)
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi i_error("quota-dict: Recalculation failed: %s", error);
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainen}
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenstatic void dict_quota_update_callback(const struct dict_commit_result *result,
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen void *context)
02d91785bcf42ced46080db91c29bb534fbe2d1cTimo Sirainen{
02d91785bcf42ced46080db91c29bb534fbe2d1cTimo Sirainen struct dict_quota_root *root = context;
02d91785bcf42ced46080db91c29bb534fbe2d1cTimo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen if (result->ret == 0) {
02d91785bcf42ced46080db91c29bb534fbe2d1cTimo Sirainen /* row doesn't exist, need to recalculate it */
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainen if (root->to_update == NULL)
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainen root->to_update = timeout_add_short(0, dict_quota_recalc_timeout, root);
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen } else if (result->ret < 0) {
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen i_error("dict quota: Quota update failed: %s "
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen "- Quota is now desynced", result->error);
02d91785bcf42ced46080db91c29bb534fbe2d1cTimo Sirainen }
02d91785bcf42ced46080db91c29bb534fbe2d1cTimo Sirainen}
02d91785bcf42ced46080db91c29bb534fbe2d1cTimo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenstatic int
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainendict_quota_update(struct quota_root *_root,
7b3b617e946d5b32078baa821f5fc05f775e1dfeMartti Rannanjärvi struct quota_transaction_context *ctx,
7b3b617e946d5b32078baa821f5fc05f775e1dfeMartti Rannanjärvi const char **error_r)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct dict_quota_root *root = (struct dict_quota_root *) _root;
51dbc2d559815da774f8ee5faf0e28df3c8d40c0Timo Sirainen struct dict_transaction_context *dt;
02d91785bcf42ced46080db91c29bb534fbe2d1cTimo Sirainen uint64_t value;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
39dea5f2e78f6bfc3adc0655176f596ee211938fTimo Sirainen if (ctx->recalculate != QUOTA_RECALCULATE_DONT) {
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi if (dict_quota_count(root, TRUE, &value, error_r)
4f52de745cf26ee9dcbde7ca4500d442116226cfMartti Rannanjärvi <= QUOTA_GET_RESULT_INTERNAL_ERROR)
02d91785bcf42ced46080db91c29bb534fbe2d1cTimo Sirainen return -1;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen } else {
02d91785bcf42ced46080db91c29bb534fbe2d1cTimo Sirainen dt = dict_transaction_begin(root->dict);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (ctx->bytes_used != 0) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen dict_atomic_inc(dt, DICT_QUOTA_CURRENT_BYTES_PATH,
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen ctx->bytes_used);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen if (ctx->count_used != 0) {
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen dict_atomic_inc(dt, DICT_QUOTA_CURRENT_COUNT_PATH,
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen ctx->count_used);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen }
8f7e81b327b8b5bf34262f6755df6d4481760d23Timo Sirainen dict_transaction_no_slowness_warning(dt);
02d91785bcf42ced46080db91c29bb534fbe2d1cTimo Sirainen dict_transaction_commit_async(&dt, dict_quota_update_callback,
02d91785bcf42ced46080db91c29bb534fbe2d1cTimo Sirainen root);
62300a38f91227b9de043a9a8ec1d4f1978e1138Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen return 0;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
048e40f9364fa68482bc276dd4a5d595a3d742e9Timo Sirainenstatic void dict_quota_flush(struct quota_root *_root)
048e40f9364fa68482bc276dd4a5d595a3d742e9Timo Sirainen{
048e40f9364fa68482bc276dd4a5d595a3d742e9Timo Sirainen struct dict_quota_root *root = (struct dict_quota_root *)_root;
048e40f9364fa68482bc276dd4a5d595a3d742e9Timo Sirainen
c4478af52de63804efef2055580adf1dfc8679c6Timo Sirainen dict_wait(root->dict);
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainen if (root->to_update != NULL) {
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainen dict_quota_recalc_timeout(root);
c4478af52de63804efef2055580adf1dfc8679c6Timo Sirainen dict_wait(root->dict);
54a8bb6e9b852d9a96a8cdda1bb55a85ce0e10daTimo Sirainen }
048e40f9364fa68482bc276dd4a5d595a3d742e9Timo Sirainen}
048e40f9364fa68482bc276dd4a5d595a3d742e9Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstruct quota_backend quota_backend_dict = {
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .name = "dict",
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .v = {
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .alloc = dict_quota_alloc,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .init = dict_quota_init,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .deinit = dict_quota_deinit,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .get_resources = dict_quota_root_get_resources,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .get_resource = dict_quota_get_resource,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .update = dict_quota_update,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .flush = dict_quota_flush,
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen};