dovecot-2.2: lazy-expunge: If lazy_expunge_only_last_instance is...
dovecot at dovecot.org
dovecot at dovecot.org
Sun Feb 24 16:43:34 EET 2013
details: http://hg.dovecot.org/dovecot-2.2/rev/5c31615ce111
changeset: 15918:5c31615ce111
user: Timo Sirainen <tss at iki.fi>
date: Sun Feb 24 16:43:28 2013 +0200
description:
lazy-expunge: If lazy_expunge_only_last_instance is set, copy only last instances of mails.
Requires storage backend to support refcounts.
diffstat:
src/plugins/lazy-expunge/lazy-expunge-plugin.c | 98 ++++++++++++++++++++++++++
1 files changed, 98 insertions(+), 0 deletions(-)
diffs (171 lines):
diff -r 5e0c1ecad4a5 -r 5c31615ce111 src/plugins/lazy-expunge/lazy-expunge-plugin.c
--- a/src/plugins/lazy-expunge/lazy-expunge-plugin.c Sun Feb 24 16:33:24 2013 +0200
+++ b/src/plugins/lazy-expunge/lazy-expunge-plugin.c Sun Feb 24 16:43:28 2013 +0200
@@ -4,6 +4,7 @@
#include "ioloop.h"
#include "array.h"
#include "str.h"
+#include "hash.h"
#include "seq-range-array.h"
#include "mkdir-parents.h"
#include "mail-storage-private.h"
@@ -32,6 +33,7 @@
struct mail_namespace *lazy_ns;
const char *env;
+ bool copy_only_last_instance;
};
struct lazy_expunge_mailbox_list {
@@ -47,7 +49,11 @@
struct mailbox *dest_box;
struct mailbox_transaction_context *dest_trans;
+ pool_t pool;
+ HASH_TABLE(const char *, void *) guids;
+
bool failed;
+ bool copy_only_last_instance;
};
const char *lazy_expunge_plugin_version = DOVECOT_ABI_VERSION;
@@ -112,6 +118,74 @@
return box;
}
+static unsigned int
+lazy_expunge_count_in_transaction(struct lazy_expunge_transaction *lt,
+ const char *guid)
+{
+ void *refcountp;
+ unsigned int refcount;
+
+ if (lt->pool == NULL) {
+ lt->pool = pool_alloconly_create("lazy expunge transaction",
+ 1024);
+ hash_table_create(<->guids, lt->pool, 0, str_hash, strcmp);
+ }
+
+ refcountp = hash_table_lookup(lt->guids, guid);
+ refcount = POINTER_CAST_TO(refcountp, unsigned int) + 1;
+ refcountp = POINTER_CAST(refcount);
+ if (refcount == 1) {
+ guid = p_strdup(lt->pool, guid);
+ hash_table_insert(lt->guids, guid, refcountp);
+ } else {
+ hash_table_update(lt->guids, guid, refcountp);
+ }
+ return refcount-1;
+}
+
+static int lazy_expunge_mail_is_last_instace(struct mail *_mail)
+{
+ struct lazy_expunge_transaction *lt =
+ LAZY_EXPUNGE_CONTEXT(_mail->transaction);
+ const char *value;
+ unsigned long refcount;
+
+ if (mail_get_special(_mail, MAIL_FETCH_REFCOUNT, &value) < 0) {
+ mail_storage_set_critical(_mail->box->storage,
+ "lazy_expunge: Couldn't lookup message's refcount");
+ return -1;
+ }
+ if (*value == '\0') {
+ /* refcounts not supported by backend. assume all mails are
+ the last instance. */
+ return 1;
+ }
+ if (str_to_ulong(value, &refcount) < 0)
+ i_panic("Invalid mail refcount number: %s", value);
+ if (refcount > 1) {
+ /* this probably isn't the last instance of the mail, but
+ it's possible that the same mail was copied to this mailbox
+ multiple times and we're deleting more than one instance
+ within this transaction. in those cases each expunge will
+ see the same refcount, so we need to adjust the refcount
+ by tracking the expunged message GUIDs. */
+ if (mail_get_special(_mail, MAIL_FETCH_GUID, &value) < 0) {
+ mail_storage_set_critical(_mail->box->storage,
+ "lazy_expunge: Couldn't lookup message's GUID");
+ return -1;
+ }
+ if (*value == '\0') {
+ /* GUIDs not supported by backend, but refcounts are?
+ not with our current backends. */
+ mail_storage_set_critical(_mail->box->storage,
+ "lazy_expunge: Message unexpectedly has no GUID");
+ return -1;
+ }
+ refcount -= lazy_expunge_count_in_transaction(lt, value);
+ }
+ return refcount <= 1 ? 1 : 0;
+}
+
static void lazy_expunge_mail_expunge(struct mail *_mail)
{
struct mail_namespace *ns = _mail->box->list->ns;
@@ -125,6 +199,7 @@
struct mailbox *real_box;
struct mail_save_context *save_ctx;
const char *error;
+ int ret;
/* don't copy the mail if we're expunging from lazy_expunge
namespace (even if it's via a virtual mailbox) */
@@ -135,6 +210,20 @@
return;
}
+ if (lt->copy_only_last_instance) {
+ /* we want to copy only the last instance of the mail to
+ lazy_expunge namespace. other instances will be expunged
+ immediately. */
+ if ((ret = lazy_expunge_mail_is_last_instace(_mail)) < 0) {
+ lt->failed = TRUE;
+ return;
+ }
+ if (ret == 0) {
+ mmail->super.expunge(_mail);
+ return;
+ }
+ }
+
if (lt->dest_box == NULL) {
lt->dest_box = mailbox_open_or_create(luser->lazy_ns->list,
_mail->box, &error);
@@ -169,12 +258,15 @@
lazy_expunge_transaction_begin(struct mailbox *box,
enum mailbox_transaction_flags flags)
{
+ struct lazy_expunge_mail_user *luser =
+ LAZY_EXPUNGE_USER_CONTEXT(box->list->ns->user);
union mailbox_module_context *mbox = LAZY_EXPUNGE_CONTEXT(box);
struct mailbox_transaction_context *t;
struct lazy_expunge_transaction *lt;
t = mbox->super.transaction_begin(box, flags);
lt = i_new(struct lazy_expunge_transaction, 1);
+ lt->copy_only_last_instance = luser->copy_only_last_instance;
MODULE_CONTEXT_SET(t, lazy_expunge_mail_storage_module, lt);
return t;
@@ -186,6 +278,10 @@
mailbox_transaction_rollback(<->dest_trans);
if (lt->dest_box != NULL)
mailbox_free(<->dest_box);
+ if (hash_table_is_created(lt->guids))
+ hash_table_destroy(<->guids);
+ if (lt->pool != NULL)
+ pool_unref(<->pool);
i_free(lt);
}
@@ -349,6 +445,8 @@
user->vlast = &luser->module_ctx.super;
v->deinit = lazy_expunge_user_deinit;
luser->env = env;
+ luser->copy_only_last_instance =
+ mail_user_plugin_getenv(user, "lazy_expunge_only_last_instance") != NULL;
MODULE_CONTEXT_SET(user, lazy_expunge_mail_user_module, luser);
} else if (user->mail_debug) {
More information about the dovecot-cvs
mailing list