]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
quota: Skip reading mail sizes when quota backend doesn't need it.
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 2 May 2016 15:16:00 +0000 (18:16 +0300)
committerGitLab <gitlab@git.dovecot.net>
Mon, 6 Jun 2016 11:28:38 +0000 (14:28 +0300)
If quota backend is updating the quota internally, it's just going to ignore
the looked up size. The only reason for looking up the sizes is to check
with quota_try_alloc() whether user is going over quota.

src/plugins/quota/quota-count.c
src/plugins/quota/quota-dirsize.c
src/plugins/quota/quota-fs.c
src/plugins/quota/quota-private.h
src/plugins/quota/quota-storage.c
src/plugins/quota/quota.c

index 5db0525bf09c2693d23c26939f6168ae83f8bdf8..76072eaa56630d5d451a7947d5c75129cdab2cf6 100644 (file)
@@ -206,6 +206,7 @@ static int count_quota_init(struct quota_root *root, const char *args,
                *error_r = "quota count backend requires quota_vsizes=yes";
                return -1;
        }
+       root->auto_updating = TRUE;
        return quota_root_default_init(root, args, error_r);
 }
 
index 1d2140617645c4cfbc84a52a89d49154ac467a10..17fe6e5def302410de381e1b606507cc679ceddd 100644 (file)
@@ -25,6 +25,13 @@ static struct quota_root *dirsize_quota_alloc(void)
        return i_new(struct quota_root, 1);
 }
 
+static int dirsize_quota_init(struct quota_root *root, const char *args,
+                             const char **error_r)
+{
+       root->auto_updating = TRUE;
+       return quota_root_default_init(root, args, error_r);
+}
+
 static void dirsize_quota_deinit(struct quota_root *_root)
 {
        i_free(_root);
@@ -210,7 +217,7 @@ struct quota_backend quota_backend_dirsize = {
 
        {
                dirsize_quota_alloc,
-               NULL,
+               dirsize_quota_init,
                dirsize_quota_deinit,
                NULL,
                NULL,
index 5b3431a5a86e08d1d62992c83f175a65d92c7acd..b3c15be3a8827f352fe918b45952b747712607b1 100644 (file)
@@ -122,6 +122,7 @@ static int fs_quota_init(struct quota_root *_root, const char *args,
                        return -1;
                }
        }
+       _root->auto_updating = TRUE;
        return 0;
 }
 
index 60683f7d89d597a1211c8a1b1e3b62574c6baf2d..3341c646a75163462173eb310dc6fce15c86c6a6 100644 (file)
@@ -137,6 +137,9 @@ struct quota_root {
 
        /* don't enforce quota when saving */
        unsigned int no_enforcing:1;
+       /* quota is automatically updated. update() should be called but the
+          bytes/count won't be used. */
+       unsigned int auto_updating:1;
        /* If user has unlimited quota, disable quota tracking */
        unsigned int disable_unlimited_tracking:1;
        /* Set while quota is being recalculated to avoid recursion. */
@@ -177,6 +180,8 @@ struct quota_transaction_context {
        unsigned int failed:1;
        unsigned int recalculate:1;
        unsigned int sync_transaction:1;
+       /* TRUE if all roots have auto_updating=TRUE */
+       unsigned int auto_updating:1;
 };
 
 /* Register storage to all user's quota roots. */
index 4d75a319437c3e504042b02ba534d452df7d5d43..1b47bb8f71756d197487fe130374ff3954970d21 100644 (file)
@@ -52,9 +52,15 @@ static void quota_mail_expunge(struct mail *_mail)
        struct quota_mailbox *qbox = QUOTA_CONTEXT(_mail->box);
        struct quota_user *quser = QUOTA_USER_CONTEXT(_mail->box->storage->user);
        union mail_module_context *qmail = QUOTA_MAIL_CONTEXT(mail);
+       struct quota_transaction_context *qt = QUOTA_CONTEXT(_mail->transaction);
        uoff_t size;
        int ret;
 
+       if (qt->auto_updating) {
+               qmail->super.expunge(_mail);
+               return;
+       }
+
        /* We need to handle the situation where multiple transactions expunged
           the mail at the same time. In here we'll just save the message's
           physical size and do the quota freeing later when the message was
@@ -338,6 +344,14 @@ static void quota_mailbox_sync_notify(struct mailbox *box, uint32_t uid,
                return;
        }
 
+       if (qbox->expunge_qt == NULL) {
+               qbox->expunge_qt = quota_transaction_begin(box);
+               qbox->expunge_qt->sync_transaction =
+                       qbox->sync_transaction_expunge;
+       }
+       if (qbox->expunge_qt->auto_updating)
+               return;
+
        /* we're in the middle of syncing the mailbox, so it's a bad idea to
           try and get the message sizes at this point. Rely on sizes that
           we saved earlier, or recalculate the whole quota if we don't know
@@ -362,12 +376,6 @@ static void quota_mailbox_sync_notify(struct mailbox *box, uint32_t uid,
                qbox->prev_idx = i;
        }
 
-       if (qbox->expunge_qt == NULL) {
-               qbox->expunge_qt = quota_transaction_begin(box);
-               qbox->expunge_qt->sync_transaction =
-                       qbox->sync_transaction_expunge;
-       }
-
        if (i != count) {
                /* we already know the size */
                sizep = array_idx(&qbox->expunge_sizes, i);
index 23782690a79c05508c18cef0a36398aab2ffe63e..c178bec2c56568c86fd36ff8ef76a1e1c9009142 100644 (file)
@@ -753,6 +753,7 @@ int quota_set_resource(struct quota_root *root, const char *name,
 struct quota_transaction_context *quota_transaction_begin(struct mailbox *box)
 {
        struct quota_transaction_context *ctx;
+       struct quota_root *const *rootp;
 
        ctx = i_new(struct quota_transaction_context, 1);
        ctx->quota = box->list->ns->owner != NULL ?
@@ -765,6 +766,12 @@ struct quota_transaction_context *quota_transaction_begin(struct mailbox *box)
        ctx->bytes_ceil2 = (uint64_t)-1;
        ctx->count_ceil = (uint64_t)-1;
 
+       ctx->auto_updating = TRUE;
+       array_foreach(&ctx->quota->roots, rootp) {
+               if (!(*rootp)->auto_updating)
+                       ctx->auto_updating = FALSE;
+       }
+
        if (box->storage->user->dsyncing) {
                /* ignore quota for dsync */
                ctx->limits_set = TRUE;
@@ -1093,7 +1100,12 @@ int quota_try_alloc(struct quota_transaction_context *ctx,
        ret = quota_test_alloc(ctx, size, too_large_r);
        if (ret <= 0)
                return ret;
-
+       /* with quota_try_alloc() we want to keep track of how many bytes
+          we've been adding/removing, so disable auto_updating=TRUE
+          optimization. this of course doesn't work perfectly if
+          quota_alloc() or quota_free*() was already used within the same
+          transaction, but that doesn't normally happen. */
+       ctx->auto_updating = FALSE;
        quota_alloc(ctx, mail);
        return 1;
 }
@@ -1153,6 +1165,8 @@ void quota_alloc(struct quota_transaction_context *ctx, struct mail *mail)
 {
        uoff_t size;
 
+       if (ctx->auto_updating)
+               return;
        if (mail_get_physical_size(mail, &size) == 0)
                ctx->bytes_used += size;
 
@@ -1164,6 +1178,8 @@ void quota_free(struct quota_transaction_context *ctx, struct mail *mail)
 {
        uoff_t size;
 
+       if (ctx->auto_updating)
+               return;
        if (mail_get_physical_size(mail, &size) < 0)
                quota_recalculate(ctx);
        else