Skip to content

Commit

Permalink
quota: Skip reading mail sizes when quota backend doesn't need it.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sirainen committed Jun 14, 2016
1 parent 3eb7503 commit 6ab59f3
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/plugins/quota/quota-count.c
Expand Up @@ -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);
}

Expand Down
9 changes: 8 additions & 1 deletion src/plugins/quota/quota-dirsize.c
Expand Up @@ -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);
Expand Down Expand Up @@ -210,7 +217,7 @@ struct quota_backend quota_backend_dirsize = {

{
dirsize_quota_alloc,
NULL,
dirsize_quota_init,
dirsize_quota_deinit,
NULL,
NULL,
Expand Down
1 change: 1 addition & 0 deletions src/plugins/quota/quota-fs.c
Expand Up @@ -122,6 +122,7 @@ static int fs_quota_init(struct quota_root *_root, const char *args,
return -1;
}
}
_root->auto_updating = TRUE;
return 0;
}

Expand Down
5 changes: 5 additions & 0 deletions src/plugins/quota/quota-private.h
Expand Up @@ -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. */
Expand Down Expand Up @@ -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. */
Expand Down
20 changes: 14 additions & 6 deletions src/plugins/quota/quota-storage.c
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down
18 changes: 17 additions & 1 deletion src/plugins/quota/quota.c
Expand Up @@ -752,6 +752,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 ?
Expand All @@ -764,6 +765,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;
Expand Down Expand Up @@ -1092,7 +1099,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;
}
Expand Down Expand Up @@ -1152,6 +1164,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;

Expand All @@ -1163,6 +1177,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
Expand Down

0 comments on commit 6ab59f3

Please sign in to comment.