*error_r = "quota count backend requires quota_vsizes=yes";
return -1;
}
+ root->auto_updating = TRUE;
return quota_root_default_init(root, args, error_r);
}
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);
{
dirsize_quota_alloc,
- NULL,
+ dirsize_quota_init,
dirsize_quota_deinit,
NULL,
NULL,
return -1;
}
}
+ _root->auto_updating = TRUE;
return 0;
}
/* 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. */
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. */
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
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
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);
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 ?
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;
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;
}
{
uoff_t size;
+ if (ctx->auto_updating)
+ return;
if (mail_get_physical_size(mail, &size) == 0)
ctx->bytes_used += size;
{
uoff_t size;
+ if (ctx->auto_updating)
+ return;
if (mail_get_physical_size(mail, &size) < 0)
quota_recalculate(ctx);
else