]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
quota: Add support for recording quota resource usage reduction from sub-transactions
authorStephan Bosch <stephan.bosch@dovecot.fi>
Fri, 16 Nov 2018 11:08:47 +0000 (12:08 +0100)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Wed, 26 Feb 2025 10:45:00 +0000 (10:45 +0000)
Such transactions apply their own quota modifications, so modifying the usage
fields for the present transaction would cause such modifications to be
counted several times. However, their effect must be applied in the quota limit
calculations, so the amount of resources expunged in sub-transactions is
recorded in separate fields.

src/plugins/quota/quota-private.h
src/plugins/quota/quota-util.c

index f532e8334063a4a422c2924bca33c7e379c93d88..72fdbc6e214ca56dcb82e19f67335a89bb4163cc 100644 (file)
@@ -109,6 +109,14 @@ struct quota_transaction_root_context {
           only once and not updated by bytes_used/count_used. (Either *_ceil
           or *_over is always zero.) */
        uint64_t bytes_over, count_over;
+
+       /* Quota resource usage reduction performed in separate transactions.
+          Hence, these changes are already committed and must not be counted
+          a second time in this transaction. These values are used in the
+          limit calculations though, since the limits were recorded at the
+          start of the transaction and these reductions were performed some
+          time later. */
+       uint64_t bytes_expunged, count_expunged;
 };
 
 struct quota_transaction_context {
@@ -121,7 +129,17 @@ struct quota_transaction_context {
 
        struct quota_transaction_root_context *roots;
 
+       /* Quota resource usage changes relative to the start of the
+          transaction. */
        int64_t bytes_used, count_used;
+       /* Quota resource usage reduction performed in separate transactions.
+          Hence, these changes are already committed and must not be counted
+          a second time in this transaction. These values are used in the
+          limit calculations though, since the limits were recorded at the
+          start of the transaction and these reductions were performed some
+          time later. */
+       uint64_t bytes_expunged, count_expunged;
+
        /* how many bytes/mails can be saved until limit is reached.
           (set once, not updated by bytes_used/count_used).
 
index 4435f9417f6b68ae7852e91ab2fb14f322905465..feb8ac87de4d859d4a347bcfa88f7beffdc9e63f 100644 (file)
@@ -145,10 +145,16 @@ void quota_used_apply_expunged(int64_t *used, uint64_t expunged)
 bool quota_transaction_is_over(struct quota_transaction_context *ctx,
                               uoff_t size)
 {
-       if (quota_is_over(1, ctx->count_used, ctx->count_ceil,
+       int64_t count_used = ctx->count_used;
+       int64_t bytes_used = ctx->bytes_used;
+
+       quota_used_apply_expunged(&count_used, ctx->count_expunged);
+       quota_used_apply_expunged(&bytes_used, ctx->bytes_expunged);
+
+       if (quota_is_over(1, count_used, ctx->count_ceil,
                          ctx->count_over, NULL))
                return TRUE;
-       if (quota_is_over(size, ctx->bytes_used, ctx->bytes_ceil,
+       if (quota_is_over(size, bytes_used, ctx->bytes_ceil,
                          ctx->bytes_over, NULL))
                return TRUE;
        return FALSE;
@@ -159,13 +165,19 @@ bool quota_root_is_over(struct quota_transaction_context *ctx,
                        uoff_t count_alloc, uoff_t bytes_alloc,
                        uoff_t *count_overrun_r, uoff_t *bytes_overrun_r)
 {
+       int64_t count_used = ctx->count_used;
+       int64_t bytes_used = ctx->bytes_used;
+
        *count_overrun_r = 0;
        *bytes_overrun_r = 0;
 
-       return (quota_is_over(count_alloc, ctx->count_used,
+       quota_used_apply_expunged(&count_used, root->count_expunged);
+       quota_used_apply_expunged(&bytes_used, root->bytes_expunged);
+
+       return (quota_is_over(count_alloc, count_used,
                              root->count_ceil, root->count_over,
                              count_overrun_r) ||
-               quota_is_over(bytes_alloc, ctx->bytes_used,
+               quota_is_over(bytes_alloc, bytes_used,
                              root->bytes_ceil, root->bytes_over,
                              bytes_overrun_r));
 }