dovecot-2.2: quota: Added quota_last_extra setting, which defaul...
dovecot at dovecot.org
dovecot at dovecot.org
Mon Feb 11 03:03:22 EET 2013
details: http://hg.dovecot.org/dovecot-2.2/rev/e866b9e64f09
changeset: 15758:e866b9e64f09
user: Timo Sirainen <tss at iki.fi>
date: Mon Feb 11 03:02:49 2013 +0200
description:
quota: Added quota_last_extra setting, which defaults to 10%
This can be used to save the last message when user is almost over quota.
So by default the last message can bring the quota over 10% of the total
quota limit. The setting allows also explicit values. Setting it to 0 brings
it back to previous behavior.
diffstat:
src/plugins/quota/quota-private.h | 13 ++-
src/plugins/quota/quota-storage.c | 2 +-
src/plugins/quota/quota.c | 140 ++++++++++++++++++++++++++++---------
3 files changed, 116 insertions(+), 39 deletions(-)
diffs (292 lines):
diff -r d4080bea7286 -r e866b9e64f09 src/plugins/quota/quota-private.h
--- a/src/plugins/quota/quota-private.h Mon Feb 11 02:03:43 2013 +0200
+++ b/src/plugins/quota/quota-private.h Mon Feb 11 03:02:49 2013 +0200
@@ -87,6 +87,10 @@
ARRAY(struct quota_rule) rules;
ARRAY(struct quota_warning_rule) warning_rules;
+ /* If user is under quota before saving a mail, allow the last mail to
+ bring the user over quota by this many bytes. */
+ uint64_t last_mail_max_extra_bytes;
+
/* Limits in default_rule override backend's quota limits */
unsigned int force_default_rule:1;
};
@@ -134,8 +138,13 @@
int64_t bytes_used, count_used;
/* how many bytes/mails can be saved until limit is reached.
- (set once, not updated by bytes_used/count_used) */
- uint64_t bytes_ceil, count_ceil;
+ (set once, not updated by bytes_used/count_used).
+
+ if last_mail_max_extra_bytes>0, the bytes_ceil is initially
+ increased by that much, while bytes_ceil2 contains the real ceiling.
+ after the first allocation is done, bytes_ceil is set to
+ bytes_ceil2. */
+ uint64_t bytes_ceil, bytes_ceil2, count_ceil;
/* how many bytes/mails we are over quota (either *_ceil or *_over
is always zero) */
uint64_t bytes_over, count_over;
diff -r d4080bea7286 -r e866b9e64f09 src/plugins/quota/quota-storage.c
--- a/src/plugins/quota/quota-storage.c Mon Feb 11 02:03:43 2013 +0200
+++ b/src/plugins/quota/quota-storage.c Mon Feb 11 03:02:49 2013 +0200
@@ -77,7 +77,7 @@
if ((items & STATUS_CHECK_OVER_QUOTA) != 0) {
qt = quota_transaction_begin(box);
- if ((ret = quota_test_alloc(qt, 1, &too_large)) == 0) {
+ if ((ret = quota_test_alloc(qt, 0, &too_large)) == 0) {
mail_storage_set_error(box->storage, MAIL_ERROR_NOSPACE,
qt->quota->set->quota_exceeded_msg);
ret = -1;
diff -r d4080bea7286 -r e866b9e64f09 src/plugins/quota/quota.c
--- a/src/plugins/quota/quota.c Mon Feb 11 02:03:43 2013 +0200
+++ b/src/plugins/quota/quota.c Mon Feb 11 03:02:49 2013 +0200
@@ -15,6 +15,7 @@
#include <stdlib.h>
#include <sys/wait.h>
+#define QUOTA_DEFAULT_LAST_EXTRA "10%"
#define DEFAULT_QUOTA_EXCEEDED_MSG \
"Quota exceeded (mailbox for user is full)"
#define RULE_NAME_DEFAULT_FORCE "*"
@@ -45,6 +46,10 @@
static int quota_default_test_alloc(struct quota_transaction_context *ctx,
uoff_t size, bool *too_large_r);
+static int
+quota_root_parse_last_extra(struct mail_user *user, const char *root_name,
+ struct quota_root_settings *root_set,
+ const char **error_r);
static const struct quota_backend *quota_backend_find(const char *name)
{
@@ -175,6 +180,8 @@
return -1;
if (quota_root_add_warning_rules(user, root_name, root_set, error_r) < 0)
return -1;
+ if (quota_root_parse_last_extra(user, root_name, root_set, error_r) < 0)
+ return -1;
return 0;
}
@@ -362,8 +369,7 @@
int64_t percentage = *limit;
if (percentage <= -100 || percentage >= -1U) {
- *error_r = p_strdup_printf(root_set->set->pool,
- "Invalid rule percentage: %lld", (long long)percentage);
+ *error_r = "Invalid percentage";
return -1;
}
@@ -381,6 +387,44 @@
return 0;
}
+static int quota_limit_parse(struct quota_root_settings *root_set,
+ struct quota_rule *rule, const char *unit,
+ uint64_t multiply, int64_t *limit,
+ const char **error_r)
+{
+ switch (i_toupper(*unit)) {
+ case '\0':
+ /* default */
+ break;
+ case 'B':
+ multiply = 1;
+ break;
+ case 'K':
+ multiply = 1024;
+ break;
+ case 'M':
+ multiply = 1024*1024;
+ break;
+ case 'G':
+ multiply = 1024*1024*1024;
+ break;
+ case 'T':
+ multiply = 1024ULL*1024*1024*1024;
+ break;
+ case '%':
+ multiply = 0;
+ if (quota_rule_parse_percentage(root_set, rule, limit,
+ error_r) < 0)
+ return -1;
+ break;
+ default:
+ *error_r = t_strdup_printf("Unknown unit: %s", unit);
+ return -1;
+ }
+ *limit *= multiply;
+ return 0;
+}
+
static void
quota_rule_recalculate_relative_rules(struct quota_rule *rule,
int64_t bytes_limit, int64_t count_limit)
@@ -415,7 +459,7 @@
const char *full_rule_def,
bool relative_rule, const char **error_r)
{
- const char **args, *key, *value;
+ const char **args, *key, *value, *error;
char *p;
uint64_t multiply;
int64_t *limit;
@@ -462,37 +506,13 @@
return -1;
}
- switch (i_toupper(*p)) {
- case '\0':
- /* default */
- break;
- case 'B':
- multiply = 1;
- break;
- case 'K':
- multiply = 1024;
- break;
- case 'M':
- multiply = 1024*1024;
- break;
- case 'G':
- multiply = 1024*1024*1024;
- break;
- case 'T':
- multiply = 1024ULL*1024*1024*1024;
- break;
- case '%':
- multiply = 0;
- if (quota_rule_parse_percentage(root_set, rule, limit,
- error_r) < 0)
- return -1;
- break;
- default:
+ if (quota_limit_parse(root_set, rule, p, multiply,
+ limit, &error) < 0) {
*error_r = p_strdup_printf(root_set->set->pool,
- "Invalid rule limit value: %s", *args);
+ "Invalid rule limit value '%s': %s",
+ *args, error);
return -1;
}
- *limit *= multiply;
}
if (!relative_rule) {
if (rule->bytes_limit < 0) {
@@ -583,6 +603,37 @@
return ret;
}
+static int
+quota_root_parse_last_extra(struct mail_user *user, const char *root_name,
+ struct quota_root_settings *root_set,
+ const char **error_r)
+{
+ const char *set_name, *value, *error;
+ char *p;
+ struct quota_rule rule;
+
+ set_name = t_strconcat(root_name, "_last_extra", NULL);
+ value = mail_user_plugin_getenv(user, set_name);
+ if (value == NULL) {
+ /* default */
+ value = QUOTA_DEFAULT_LAST_EXTRA;
+ }
+
+ memset(&rule, 0, sizeof(rule));
+ rule.bytes_limit = strtoll(value, &p, 10);
+
+ if (quota_limit_parse(root_set, &rule, p, 1,
+ &rule.bytes_limit, &error) < 0) {
+ *error_r = p_strdup_printf(root_set->set->pool,
+ "Invalid %s value '%s': %s", set_name, value, error);
+ return -1;
+ }
+ quota_rule_recalculate_relative_rules(&rule,
+ root_set->default_rule.bytes_limit, 0);
+ root_set->last_mail_max_extra_bytes = rule.bytes_limit;
+ return 0;
+}
+
static int quota_root_get_rule_limits(struct quota_root *root,
const char *mailbox_name,
uint64_t *bytes_limit_r,
@@ -927,6 +978,7 @@
ctx->box = box;
ctx->bytes_ceil = (uint64_t)-1;
+ ctx->bytes_ceil2 = (uint64_t)-1;
ctx->count_ceil = (uint64_t)-1;
if (box->storage->user->admin) {
@@ -965,13 +1017,18 @@
QUOTA_NAME_STORAGE_BYTES,
¤t, &limit);
if (ret > 0) {
- if (limit < current) {
+ if (limit <= current) {
+ /* over quota */
ctx->bytes_ceil = 0;
+ ctx->bytes_ceil2 = 0;
diff = current - limit;
if (ctx->bytes_over < diff)
ctx->bytes_over = diff;
} else {
diff = limit - current;
+ if (ctx->bytes_ceil2 > diff)
+ ctx->bytes_ceil2 = diff;
+ diff += roots[i]->set->last_mail_max_extra_bytes;
if (ctx->bytes_ceil > diff)
ctx->bytes_ceil = diff;
}
@@ -1155,6 +1212,17 @@
i_free(ctx);
}
+static bool quota_is_over(struct quota_transaction_context *ctx, uoff_t size)
+{
+ if ((ctx->count_used < 0 ||
+ (uint64_t)ctx->count_used + 1 <= ctx->count_ceil) &&
+ ((ctx->bytes_used < 0 && size <= ctx->bytes_ceil) ||
+ (uint64_t)ctx->bytes_used + size <= ctx->bytes_ceil))
+ return FALSE;
+ else
+ return TRUE;
+}
+
int quota_try_alloc(struct quota_transaction_context *ctx,
struct mail *mail, bool *too_large_r)
{
@@ -1182,6 +1250,8 @@
if (quota_transaction_set_limits(ctx) < 0)
return -1;
}
+ /* this is a virtual function mainly for trash plugin and similar,
+ which may automatically delete mails to stay under quota. */
return ctx->quota->set->test_alloc(ctx, size, too_large_r);
}
@@ -1194,10 +1264,7 @@
*too_large_r = FALSE;
- if ((ctx->count_used < 0 ||
- (uint64_t)ctx->count_used + 1 <= ctx->count_ceil) &&
- ((ctx->bytes_used < 0 && size <= ctx->bytes_ceil) ||
- (uint64_t)ctx->bytes_used + size <= ctx->bytes_ceil))
+ if (!quota_is_over(ctx, size))
return 1;
/* limit reached. only thing left to do now is to set too_large_r. */
@@ -1233,6 +1300,7 @@
if (mail_get_physical_size(mail, &size) == 0)
ctx->bytes_used += size;
+ ctx->bytes_ceil = ctx->bytes_ceil2;
ctx->count_used++;
}
More information about the dovecot-cvs
mailing list