quota-clone-plugin.c revision bcb4e51a409d94ae670de96afb8483a4f7855294
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen/* If mailbox is kept open for this many milliseconds after quota update,
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen flush quota-clone. */
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#define QUOTA_CLONE_FLUSH_DELAY_MSECS (10*1000)
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#define DICT_QUOTA_CLONE_PATH DICT_PATH_PRIVATE"quota/"
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen#define DICT_QUOTA_CLONE_BYTES_PATH DICT_QUOTA_CLONE_PATH"storage"
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen#define DICT_QUOTA_CLONE_COUNT_PATH DICT_QUOTA_CLONE_PATH"messages"
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen MODULE_CONTEXT(obj, quota_clone_storage_module)
a272994d43de80a306a8ed1f2983960d1f3102d0Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(quota_clone_user_module,
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(quota_clone_storage_module,
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainenstatic void quota_clone_flush_real(struct mailbox *box)
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen /* we'll clone the first quota root */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen /* no quota roots defined for this mailbox - ignore */
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen /* get new values first */
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen bytes_res = quota_get_resource(root, "", QUOTA_NAME_STORAGE_BYTES,
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen if (bytes_res == QUOTA_GET_RESULT_INTERNAL_ERROR) {
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen "Failed to get quota resource "QUOTA_NAME_STORAGE_BYTES": %s",
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen count_res = quota_get_resource(root, "", QUOTA_NAME_MESSAGES,
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen if (count_res == QUOTA_GET_RESULT_INTERNAL_ERROR) {
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen "Failed to get quota resource "QUOTA_NAME_MESSAGES": %s",
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen if (bytes_res == QUOTA_GET_RESULT_UNKNOWN_RESOURCE &&
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen count_res == QUOTA_GET_RESULT_UNKNOWN_RESOURCE) {
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen /* quota resources don't exist - no point in updating it */
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen if (bytes_res == QUOTA_GET_RESULT_BACKGROUND_CALC &&
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen count_res == QUOTA_GET_RESULT_BACKGROUND_CALC) {
419baa2c17c63ae516b2df6cc5695f15aaccbff8Timo Sirainen /* Blocked by an ongoing quota calculation - try again later */
d1414c09cf0d58ac983054e2f4e1a1f329272dcfTimo Sirainen /* Then update the resources that exist. The resources' existence can't
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen change unless the quota backend is changed, so we don't worry about
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen the special case of lookup changing from
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen RESULT_LIMITED/RESULT_UNLIMITED to RESULT_UNKNOWN_RESOURCE, which
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen leaves the old value unchanged. */
419baa2c17c63ae516b2df6cc5695f15aaccbff8Timo Sirainen if (dict_transaction_commit(&trans, &error) < 0)
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen i_error("quota_clone_plugin: Failed to commit dict update: %s", error);
e2ae85924b0ef1a7c97e021a3b901b498f599c18Timo Sirainenstatic void quota_clone_flush(struct mailbox *box)
419baa2c17c63ae516b2df6cc5695f15aaccbff8Timo Sirainen struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
73bfdbe28c2ce6d143eadf0bab8ccfbe4cab0faeTimo Sirainen /* recursing back from quota recalculation */
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainenstatic void quota_clone_changed(struct mailbox *box)
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen qbox->to_quota_flush = timeout_add(QUOTA_CLONE_FLUSH_DELAY_MSECS,
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainenstatic int quota_clone_save_finish(struct mail_save_context *ctx)
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen return qbox->module_ctx.super.save_finish(ctx);
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainenquota_clone_copy(struct mail_save_context *ctx, struct mail *mail)
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen return qbox->module_ctx.super.copy(ctx, mail);
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainenquota_clone_mailbox_sync_notify(struct mailbox *box, uint32_t uid,
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen if (qbox->module_ctx.super.sync_notify != NULL)
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen qbox->module_ctx.super.sync_notify(box, uid, sync_type);
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainenstatic void quota_clone_mailbox_close(struct mailbox *box)
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainenstatic void quota_clone_mailbox_allocated(struct mailbox *box)
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen qbox = p_new(box->pool, struct quota_clone_mailbox, 1);
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen v->sync_notify = quota_clone_mailbox_sync_notify;
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen MODULE_CONTEXT_SET(box, quota_clone_storage_module, qbox);
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainenstatic void quota_clone_mail_user_deinit(struct mail_user *user)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk struct quota_clone_user *quser = QUOTA_CLONE_USER_CONTEXT(user);
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainenstatic void quota_clone_mail_user_created(struct mail_user *user)
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen uri = mail_user_plugin_getenv(user, "quota_clone_dict");
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen i_debug("The quota_clone_dict setting is missing from configuration");
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen (void)mail_user_get_home(user, &dict_set.home_dir);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen if (dict_init(uri, &dict_set, &dict, &error) < 0) {
b6e1d85292485a7fb4cfa5f40dd1ec131ab07cc1Timo Sirainen i_error("quota_clone_dict: Failed to initialize '%s': %s",
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen quser = p_new(user->pool, struct quota_clone_user, 1);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainen MODULE_CONTEXT_SET(user, quota_clone_user_module, quser);
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenstatic struct mail_storage_hooks quota_clone_mail_storage_hooks = {
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen .mailbox_allocated = quota_clone_mailbox_allocated,
9137c55411aa39d41c1e705ddc34d5bd26c65021Timo Sirainen .mail_user_created = quota_clone_mail_user_created
2a90d8a14b0e7cc1508814bc87d3dfa598ef46a8Timo Sirainenvoid quota_clone_plugin_init(struct module *module ATTR_UNUSED)
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen mail_storage_hooks_add(module, "a_clone_mail_storage_hooks);
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainen mail_storage_hooks_remove("a_clone_mail_storage_hooks);
b0df0e9a8ed8889ad4bf032043ab245ce8851fdeTimo Sirainenconst char *quota_clone_plugin_dependencies[] = { "quota", NULL };