[dovecot-cvs] dovecot/src/plugins/quota quota-dict.c, 1.20, 1.21 quota-maildir.c, 1.25, 1.26 quota-plugin.c, 1.7, 1.8 quota-private.h, 1.17, 1.18 quota-storage.c, 1.14, 1.15 quota.c, 1.20, 1.21 quota.h, 1.8, 1.9
tss at dovecot.org
tss at dovecot.org
Tue Apr 17 18:33:27 EEST 2007
- Previous message: [dovecot-cvs] dovecot/src/plugins/imap-quota imap-quota-plugin.c, 1.12, 1.13
- Next message: [dovecot-cvs] dovecot/src/lib-storage mail-namespace.c, 1.4, 1.5 mail-storage.c, 1.79, 1.80 mail-storage.h, 1.129, 1.130 mailbox-list-private.h, 1.6, 1.7 mailbox-list.h, 1.9, 1.10
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /var/lib/cvs/dovecot/src/plugins/quota
In directory talvi:/tmp/cvs-serv30048/quota
Modified Files:
quota-dict.c quota-maildir.c quota-plugin.c quota-private.h
quota-storage.c quota.c quota.h
Log Message:
Use sync_notify() callback to count expunges. This makes the calculation
much more reliable than the previous method. Also did some API cleanups.
Index: quota-dict.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/quota/quota-dict.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- quota-dict.c 3 Apr 2007 04:44:34 -0000 1.20
+++ quota-dict.c 17 Apr 2007 15:33:23 -0000 1.21
@@ -119,7 +119,7 @@
else {
long long tmp;
- /* recalculate quota if it's negative */
+ /* recalculate quota if it's negative or if it wasn't found */
tmp = ret == 0 ? -1 : strtoll(value, NULL, 10);
if (tmp < 0)
ret = dict_quota_count(root, want_bytes, value_r);
@@ -139,13 +139,19 @@
struct dict_transaction_context *dt;
dt = dict_transaction_begin(root->dict);
- if (ctx->bytes_used != 0) {
- dict_atomic_inc(dt, DICT_QUOTA_CURRENT_BYTES_PATH,
- ctx->bytes_used);
- }
- if (ctx->count_used != 0) {
- dict_atomic_inc(dt, DICT_QUOTA_CURRENT_COUNT_PATH,
- ctx->count_used);
+
+ if (ctx->recalculate) {
+ dict_unset(dt, DICT_QUOTA_CURRENT_BYTES_PATH);
+ dict_unset(dt, DICT_QUOTA_CURRENT_COUNT_PATH);
+ } else {
+ if (ctx->bytes_used != 0) {
+ dict_atomic_inc(dt, DICT_QUOTA_CURRENT_BYTES_PATH,
+ ctx->bytes_used);
+ }
+ if (ctx->count_used != 0) {
+ dict_atomic_inc(dt, DICT_QUOTA_CURRENT_COUNT_PATH,
+ ctx->count_used);
+ }
}
if (dict_transaction_commit(dt) < 0)
Index: quota-maildir.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/quota/quota-maildir.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- quota-maildir.c 12 Mar 2007 21:05:50 -0000 1.25
+++ quota-maildir.c 17 Apr 2007 15:33:23 -0000 1.26
@@ -290,6 +290,18 @@
return ret;
}
+static void maildirsize_rebuild_later(struct maildir_quota_root *root)
+{
+ if (!root->master_message_limits) {
+ /* FIXME: can't unlink(), because the limits would be lost. */
+ return;
+ }
+
+ if (unlink(root->maildirsize_path) < 0 &&
+ errno != ENOENT && errno != ESTALE)
+ i_error("unlink(%s) failed: %m", root->maildirsize_path);
+}
+
static int maildirsize_recalculate_finish(struct maildir_quota_root *root,
int ret)
{
@@ -297,14 +309,8 @@
/* maildir didn't change, we can write the maildirsize file */
ret = maildirsize_write(root, root->maildirsize_path);
}
- if (ret != 0) {
- /* make sure it gets rebuilt later */
- if (unlink(root->maildirsize_path) < 0 &&
- errno != ENOENT && errno != ESTALE) {
- i_error("unlink(%s) failed: %m",
- root->maildirsize_path);
- }
- }
+ if (ret != 0)
+ maildirsize_rebuild_later(root);
return ret;
}
@@ -655,11 +661,10 @@
struct maildir_quota_root *root =
(struct maildir_quota_root *) _root;
- if (root->fd != -1) {
- /* if writing fails, we don't care all that much */
- (void)maildirsize_update(root, ctx->count_used,
- ctx->bytes_used);
- }
+ if (root->fd == -1 || ctx->recalculate ||
+ maildirsize_update(root, ctx->count_used, ctx->bytes_used) < 0)
+ maildirsize_rebuild_later(root);
+
return 0;
}
Index: quota-plugin.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/quota/quota-plugin.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- quota-plugin.c 29 Mar 2007 07:59:14 -0000 1.7
+++ quota-plugin.c 17 Apr 2007 15:33:23 -0000 1.8
@@ -90,6 +90,6 @@
quota_next_hook_mail_storage_created;
hook_mailbox_list_created =
quota_next_hook_mailbox_list_created;
- quota_deinit(quota_set);
+ quota_deinit("a_set);
}
}
Index: quota-private.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/quota/quota-private.h,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- quota-private.h 29 Mar 2007 11:51:13 -0000 1.17
+++ quota-private.h 17 Apr 2007 15:33:23 -0000 1.18
@@ -79,6 +79,7 @@
struct mail *tmp_mail;
unsigned int failed:1;
+ unsigned int recalculate:1;
};
/* Register storage to all user's quota roots. */
Index: quota-storage.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/quota/quota-storage.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- quota-storage.c 29 Mar 2007 11:51:13 -0000 1.14
+++ quota-storage.c 17 Apr 2007 15:33:23 -0000 1.15
@@ -27,7 +27,13 @@
struct quota_mailbox {
union mailbox_module_context module_ctx;
+ struct mailbox_transaction_context *expunge_trans;
+ struct quota_transaction_context *expunge_qt;
+ ARRAY_DEFINE(expunge_uids, uint32_t);
+ ARRAY_DEFINE(expunge_sizes, uoff_t);
+
unsigned int save_hack:1;
+ unsigned int recalculate:1;
};
static MODULE_CONTEXT_DEFINE_INIT(quota_storage_module,
@@ -39,14 +45,27 @@
static int quota_mail_expunge(struct mail *_mail)
{
struct mail_private *mail = (struct mail_private *)_mail;
+ struct quota_mailbox *qbox = QUOTA_CONTEXT(_mail->box);
union mail_module_context *qmail = QUOTA_MAIL_CONTEXT(mail);
- struct quota_transaction_context *qt =
- QUOTA_CONTEXT(_mail->transaction);
+ uoff_t size;
if (qmail->super.expunge(_mail) < 0)
return -1;
- quota_free(qt, _mail);
+ /* 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
+ known to be expunged. */
+ size = mail_get_physical_size(_mail);
+ if (size != (uoff_t)-1) {
+ if (!array_is_created(&qbox->expunge_uids)) {
+ i_array_init(&qbox->expunge_uids, 64);
+ i_array_init(&qbox->expunge_sizes, 64);
+ }
+ array_append(&qbox->expunge_uids, &_mail->uid, 1);
+ array_append(&qbox->expunge_sizes, &size, 1);
+ }
+
return 0;
}
@@ -73,12 +92,12 @@
struct quota_transaction_context *qt = QUOTA_CONTEXT(ctx);
if (qbox->module_ctx.super.transaction_commit(ctx, flags) < 0) {
- quota_transaction_rollback(qt);
+ quota_transaction_rollback(&qt);
return -1;
} else {
- (void)quota_transaction_commit(qt);
if (qt->tmp_mail != NULL)
mail_free(&qt->tmp_mail);
+ (void)quota_transaction_commit(&qt);
return 0;
}
}
@@ -93,7 +112,7 @@
if (qt->tmp_mail != NULL)
mail_free(&qt->tmp_mail);
- quota_transaction_rollback(qt);
+ quota_transaction_rollback(&qt);
}
static struct mail *
@@ -229,6 +248,110 @@
ctx->dest_mail : qt->tmp_mail);
}
+static void quota_mailbox_sync_finish(struct quota_mailbox *qbox)
+{
+ if (array_is_created(&qbox->expunge_uids)) {
+ array_clear(&qbox->expunge_uids);
+ array_clear(&qbox->expunge_sizes);
+ }
+
+ if (qbox->expunge_qt != NULL) {
+ if (qbox->expunge_qt->tmp_mail != NULL) {
+ mail_free(&qbox->expunge_qt->tmp_mail);
+ mailbox_transaction_rollback(&qbox->expunge_trans);
+ }
+ (void)quota_transaction_commit(&qbox->expunge_qt);
+ }
+ qbox->recalculate = FALSE;
+}
+
+static void quota_mailbox_sync_notify(struct mailbox *box, uint32_t uid,
+ enum mailbox_sync_type sync_type)
+{
+ struct quota_mailbox *qbox = QUOTA_CONTEXT(box);
+ const uint32_t *uids;
+ const uoff_t *sizep;
+ unsigned int i, count;
+ uoff_t size;
+
+ if (qbox->module_ctx.super.sync_notify != NULL)
+ qbox->module_ctx.super.sync_notify(box, uid, sync_type);
+
+ if (sync_type != MAILBOX_SYNC_TYPE_EXPUNGE || qbox->recalculate) {
+ if (uid == 0)
+ quota_mailbox_sync_finish(qbox);
+ 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
+ the size. */
+ if (!array_is_created(&qbox->expunge_uids)) {
+ i = count = 0;
+ } else {
+ uids = array_get(&qbox->expunge_uids, &count);
+ for (i = 0; i < count; i++) {
+ if (uids[i] == uid)
+ break;
+ }
+ }
+
+ if (qbox->expunge_qt == NULL)
+ qbox->expunge_qt = quota_transaction_begin(quota_set, box);
+
+ if (i != count) {
+ /* we already know the size */
+ sizep = array_idx(&qbox->expunge_sizes, i);
+ quota_free_bytes(qbox->expunge_qt, *sizep);
+ return;
+ }
+
+ /* try to look up the size. this works only if it's cached. */
+ if (qbox->expunge_qt->tmp_mail == NULL) {
+ qbox->expunge_trans = mailbox_transaction_begin(box, 0);
+ qbox->expunge_qt->tmp_mail =
+ mail_alloc(qbox->expunge_trans,
+ MAIL_FETCH_PHYSICAL_SIZE, NULL);
+ }
+ mail_set_uid(qbox->expunge_qt->tmp_mail, uid);
+
+ size = mail_get_physical_size(qbox->expunge_qt->tmp_mail);
+ if (size != (uoff_t)-1)
+ quota_free_bytes(qbox->expunge_qt, size);
+ else {
+ /* there's no way to get the size. recalculate the quota. */
+ quota_recalculate(qbox->expunge_qt);
+ qbox->recalculate = TRUE;
+ }
+}
+
+static int quota_mailbox_sync_deinit(struct mailbox_sync_context *ctx,
+ enum mailbox_status_items status_items,
+ struct mailbox_status *status_r)
+{
+ struct quota_mailbox *qbox = QUOTA_CONTEXT(ctx->box);
+
+ /* just in case sync_notify() wasn't called with uid=0 */
+ quota_mailbox_sync_finish(qbox);
+
+ return qbox->module_ctx.super.sync_deinit(ctx, status_items, status_r);
+}
+
+static int quota_mailbox_close(struct mailbox *box)
+{
+ struct quota_mailbox *qbox = QUOTA_CONTEXT(box);
+
+ if (array_is_created(&qbox->expunge_uids)) {
+ array_free(&qbox->expunge_uids);
+ array_free(&qbox->expunge_sizes);
+ }
+ i_assert(qbox->expunge_qt == NULL ||
+ qbox->expunge_qt->tmp_mail == NULL);
+
+ return qbox->module_ctx.super.close(box);
+}
+
static struct mailbox *
quota_mailbox_open(struct mail_storage *storage, const char *name,
struct istream *input, enum mailbox_open_flags flags)
@@ -251,6 +374,9 @@
box->v.save_init = quota_save_init;
box->v.save_finish = quota_save_finish;
box->v.copy = quota_copy;
+ box->v.sync_notify = quota_mailbox_sync_notify;
+ box->v.sync_deinit = quota_mailbox_sync_deinit;
+ box->v.close = quota_mailbox_close;
MODULE_CONTEXT_SET(box, quota_storage_module, qbox);
return box;
}
@@ -305,7 +431,8 @@
quota_remove_user_storage(quota_set, storage);
- qstorage->super.destroy(storage);
+ if (qstorage->super.destroy != NULL)
+ qstorage->super.destroy(storage);
}
void quota_mail_storage_created(struct mail_storage *storage)
Index: quota.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/quota/quota.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- quota.c 29 Mar 2007 07:59:14 -0000 1.20
+++ quota.c 17 Apr 2007 15:33:23 -0000 1.21
@@ -50,13 +50,15 @@
return quota;
}
-void quota_deinit(struct quota *quota)
+void quota_deinit(struct quota **_quota)
{
+ struct quota *quota = *_quota;
struct quota_root **root;
+ *_quota = NULL;
while (array_count("a->roots) > 0) {
root = array_idx_modifiable("a->roots, 0);
- quota_root_deinit(*root);
+ quota_root_deinit(root);
}
array_free("a->roots);
@@ -127,15 +129,16 @@
if (backend->v.init != NULL) {
if (backend->v.init(root, args) < 0) {
- quota_root_deinit(root);
+ quota_root_deinit(&root);
return NULL;
}
}
return root;
}
-void quota_root_deinit(struct quota_root *root)
+void quota_root_deinit(struct quota_root **_root)
{
+ struct quota_root *root = *_root;
pool_t pool = root->pool;
struct quota_root *const *roots;
unsigned int i, count;
@@ -145,6 +148,7 @@
if (roots[i] == root)
array_delete(&root->quota->roots, i, 1);
}
+ *_root = NULL;
array_free(&root->rules);
array_free(&root->quota_module_contexts);
@@ -346,8 +350,11 @@
return root;
}
-void quota_root_iter_deinit(struct quota_root_iter *iter)
+void quota_root_iter_deinit(struct quota_root_iter **_iter)
{
+ struct quota_root_iter *iter = *_iter;
+
+ *_iter = NULL;
i_free(iter);
}
@@ -467,12 +474,15 @@
return ctx;
}
-int quota_transaction_commit(struct quota_transaction_context *ctx)
+int quota_transaction_commit(struct quota_transaction_context **_ctx)
{
+ struct quota_transaction_context *ctx = *_ctx;
struct quota_root *const *roots;
unsigned int i, count;
int ret = 0;
+ *_ctx = NULL;
+
if (ctx->failed)
ret = -1;
else {
@@ -487,8 +497,11 @@
return ret;
}
-void quota_transaction_rollback(struct quota_transaction_context *ctx)
+void quota_transaction_rollback(struct quota_transaction_context **_ctx)
{
+ struct quota_transaction_context *ctx = *_ctx;
+
+ *_ctx = NULL;
i_free(ctx);
}
@@ -560,8 +573,20 @@
uoff_t size;
size = mail_get_physical_size(mail);
- if (size != (uoff_t)-1)
- ctx->bytes_used -= size;
+ if (size == (uoff_t)-1)
+ quota_recalculate(ctx);
+ else
+ quota_free_bytes(ctx, size);
+}
+void quota_free_bytes(struct quota_transaction_context *ctx,
+ uoff_t physical_size)
+{
+ ctx->bytes_used -= physical_size;
ctx->count_used--;
}
+
+void quota_recalculate(struct quota_transaction_context *ctx)
+{
+ ctx->recalculate = TRUE;
+}
Index: quota.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/quota/quota.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- quota.h 22 Nov 2006 17:23:09 -0000 1.8
+++ quota.h 17 Apr 2007 15:33:23 -0000 1.9
@@ -17,11 +17,11 @@
struct quota_transaction_context;
struct quota *quota_init(void);
-void quota_deinit(struct quota *quota);
+void quota_deinit(struct quota **quota);
/* Create a new quota root. */
struct quota_root *quota_root_init(struct quota *quota, const char *root_def);
-void quota_root_deinit(struct quota_root *root);
+void quota_root_deinit(struct quota_root **root);
/* Add a new rule too the quota root. Returns 0 if ok, -1 if rule is invalid. */
int quota_root_add_rule(struct quota_root *root, const char *rule_def,
@@ -31,7 +31,7 @@
struct quota_root_iter *
quota_root_iter_init(struct quota *quota, struct mailbox *box);
struct quota_root *quota_root_iter_next(struct quota_root_iter *iter);
-void quota_root_iter_deinit(struct quota_root_iter *iter);
+void quota_root_iter_deinit(struct quota_root_iter **iter);
/* Return quota root or NULL. */
struct quota_root *quota_root_lookup(struct quota *quota, const char *name);
@@ -52,9 +52,9 @@
struct quota_transaction_context *quota_transaction_begin(struct quota *quota,
struct mailbox *box);
/* Commit quota transaction. Returns 0 if ok, -1 if failed. */
-int quota_transaction_commit(struct quota_transaction_context *ctx);
+int quota_transaction_commit(struct quota_transaction_context **ctx);
/* Rollback quota transaction changes. */
-void quota_transaction_rollback(struct quota_transaction_context *ctx);
+void quota_transaction_rollback(struct quota_transaction_context **ctx);
/* Allocate from quota if there's space. Returns 1 if updated, 0 if not,
-1 if error. If mail size is larger than even maximum allowed quota,
@@ -67,5 +67,9 @@
/* Update quota by allocating/freeing space used by mail. */
void quota_alloc(struct quota_transaction_context *ctx, struct mail *mail);
void quota_free(struct quota_transaction_context *ctx, struct mail *mail);
+void quota_free_bytes(struct quota_transaction_context *ctx,
+ uoff_t physical_size);
+/* Mark the quota to be recalculated */
+void quota_recalculate(struct quota_transaction_context *ctx);
#endif
- Previous message: [dovecot-cvs] dovecot/src/plugins/imap-quota imap-quota-plugin.c, 1.12, 1.13
- Next message: [dovecot-cvs] dovecot/src/lib-storage mail-namespace.c, 1.4, 1.5 mail-storage.c, 1.79, 1.80 mail-storage.h, 1.129, 1.130 mailbox-list-private.h, 1.6, 1.7 mailbox-list.h, 1.9, 1.10
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the dovecot-cvs
mailing list