dovecot-2.2: Added mailbox { autoexpunge } setting.
dovecot at dovecot.org
dovecot at dovecot.org
Fri Nov 27 11:59:31 UTC 2015
details: http://hg.dovecot.org/dovecot-2.2/rev/82e6a3baa001
changeset: 19421:82e6a3baa001
user: Timo Sirainen <tss at iki.fi>
date: Fri Nov 27 13:59:22 2015 +0200
description:
Added mailbox { autoexpunge } setting.
This can be used to automatically expunge mails from specified mailboxes
after they're old enough. The expunges are done when the user is being
deinitialized. mailbox_list_index=yes should be enabled to have the best
performance with this setting.
Example:
namespace inbox {
mailbox Spam {
auto = create
special_use = \Junk
autoexpunge = 30d
}
}
diffstat:
src/lib-storage/Makefile.am | 1 +
src/lib-storage/list/mailbox-list-index-status.c | 117 ++++++++++++++++++++++-
src/lib-storage/list/mailbox-list-index.h | 2 +-
src/lib-storage/mail-autoexpunge.c | 93 ++++++++++++++++++
src/lib-storage/mail-autoexpunge.h | 6 +
src/lib-storage/mail-storage-private.h | 5 +
src/lib-storage/mail-storage-settings.c | 4 +-
src/lib-storage/mail-storage-settings.h | 1 +
src/lib-storage/mail-storage.h | 11 +-
src/lib-storage/mail-user.c | 3 +
10 files changed, 237 insertions(+), 6 deletions(-)
diffs (truncated from 415 to 300 lines):
diff -r db90e76f44dc -r 82e6a3baa001 src/lib-storage/Makefile.am
--- a/src/lib-storage/Makefile.am Fri Nov 27 13:06:01 2015 +0200
+++ b/src/lib-storage/Makefile.am Fri Nov 27 13:59:22 2015 +0200
@@ -24,6 +24,7 @@
fail-mailbox.c \
fail-mail.c \
mail.c \
+ mail-autoexpunge.c \
mail-copy.c \
mail-error.c \
mail-namespace.c \
diff -r db90e76f44dc -r 82e6a3baa001 src/lib-storage/list/mailbox-list-index-status.c
--- a/src/lib-storage/list/mailbox-list-index-status.c Fri Nov 27 13:06:01 2015 +0200
+++ b/src/lib-storage/list/mailbox-list-index-status.c Fri Nov 27 13:59:22 2015 +0200
@@ -15,11 +15,13 @@
guid_128_t guid;
uint32_t seq;
struct mailbox_index_vsize vsize;
+ uint32_t first_uid;
bool rec_changed;
bool msgs_changed;
bool hmodseq_changed;
bool vsize_changed;
+ bool first_saved_changed;
};
struct index_list_storage_module index_list_storage_module =
@@ -268,6 +270,30 @@
}
static int
+index_list_get_cached_first_saved(struct mailbox *box,
+ struct mailbox_index_first_saved *first_saved_r)
+{
+ struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(box->list);
+ struct mail_index_view *view;
+ const void *data;
+ bool expunged;
+ uint32_t seq;
+ int ret;
+
+ memset(first_saved_r, 0, sizeof(*first_saved_r));
+
+ if ((ret = index_list_open_view(box, &view, &seq)) <= 0)
+ return ret;
+
+ mail_index_lookup_ext(view, seq, ilist->first_saved_ext_id,
+ &data, &expunged);
+ if (data != NULL)
+ memcpy(first_saved_r, data, sizeof(*first_saved_r));
+ mail_index_view_close(&view);
+ return first_saved_r->timestamp != 0 ? 1 : 0;
+}
+
+static int
index_list_try_get_metadata(struct mailbox *box,
enum mailbox_metadata_items items,
struct mailbox_metadata *metadata_r)
@@ -286,7 +312,8 @@
/* see if we have a chance of fulfilling this without opening
the mailbox. */
noncached_items = items & ~(MAILBOX_METADATA_GUID |
- MAILBOX_METADATA_VIRTUAL_SIZE);
+ MAILBOX_METADATA_VIRTUAL_SIZE |
+ MAILBOX_METADATA_FIRST_SAVE_DATE);
if ((noncached_items & MAILBOX_METADATA_PHYSICAL_SIZE) != 0 &&
box->mail_vfuncs->get_physical_size ==
box->mail_vfuncs->get_virtual_size)
@@ -306,6 +333,15 @@
if ((items & MAILBOX_METADATA_PHYSICAL_SIZE) != 0)
metadata_r->physical_size = metadata_r->virtual_size;
}
+ if ((items & MAILBOX_METADATA_FIRST_SAVE_DATE) != 0) {
+ struct mailbox_index_first_saved first_saved;
+
+ if ((ret = index_list_get_cached_first_saved(box, &first_saved)) <= 0)
+ return ret;
+ metadata_r->first_save_date =
+ first_saved.timestamp == (uint32_t)-1 ? (time_t)-1 :
+ first_saved.timestamp;
+ }
return 1;
}
@@ -386,6 +422,33 @@
return TRUE;
}
+static void
+index_list_first_saved_update_changes(struct mailbox *box,
+ struct mail_index_view *list_view,
+ struct index_list_changes *changes)
+{
+ struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(box->list);
+ struct mailbox_index_first_saved first_saved;
+ const void *data;
+ bool expunged;
+
+ mail_index_lookup_ext(list_view, changes->seq,
+ ilist->first_saved_ext_id, &data, &expunged);
+ if (data == NULL)
+ memset(&first_saved, 0, sizeof(first_saved));
+ else
+ memcpy(&first_saved, data, sizeof(first_saved));
+ if (mail_index_view_get_messages_count(box->view) > 0)
+ mail_index_lookup_uid(box->view, 1, &changes->first_uid);
+ if (first_saved.uid == 0 && first_saved.timestamp == 0) {
+ /* first time setting this */
+ changes->first_saved_changed = TRUE;
+ } else {
+ changes->first_saved_changed =
+ changes->first_uid != first_saved.uid;
+ }
+}
+
static bool
index_list_has_changed(struct mailbox *box, struct mail_index_view *list_view,
struct index_list_changes *changes)
@@ -428,12 +491,57 @@
}
if (memcmp(&old_vsize, &changes->vsize, sizeof(old_vsize)) != 0)
changes->vsize_changed = TRUE;
+ index_list_first_saved_update_changes(box, list_view, changes);
return changes->rec_changed || changes->msgs_changed ||
- changes->hmodseq_changed || changes->vsize_changed;
+ changes->hmodseq_changed || changes->vsize_changed ||
+ changes->first_saved_changed;
}
static void
+index_list_update_first_saved(struct mailbox *box,
+ struct mail_index_transaction *list_trans,
+ const struct index_list_changes *changes)
+{
+ struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(box->list);
+ struct mailbox_transaction_context *t;
+ struct mail *mail;
+ struct mailbox_index_first_saved first_saved;
+ uint32_t seq, messages_count;
+ time_t save_date;
+ int ret = 0;
+
+ memset(&first_saved, 0, sizeof(first_saved));
+ first_saved.uid = changes->first_uid;
+ first_saved.timestamp = (uint32_t)-1;
+
+ if (changes->first_uid != 0) {
+ t = mailbox_transaction_begin(box, 0);
+ mail = mail_alloc(t, MAIL_FETCH_SAVE_DATE, NULL);
+ messages_count = mail_index_view_get_messages_count(box->view);
+ for (seq = 1; seq <= messages_count; seq++) {
+ mail_set_seq(mail, seq);
+ if (mail_get_save_date(mail, &save_date) == 0) {
+ first_saved.timestamp = save_date;
+ break;
+ }
+ if (mailbox_get_last_mail_error(box) != MAIL_ERROR_EXPUNGED) {
+ ret = -1;
+ break;
+ }
+ }
+ mail_free(&mail);
+ (void)mailbox_transaction_commit(&t);
+ }
+ if (ret == 0) {
+ mail_index_update_ext(list_trans, changes->seq,
+ ilist->first_saved_ext_id,
+ &first_saved, NULL);
+ }
+}
+
+
+static void
index_list_update(struct mailbox *box, struct mail_index_view *list_view,
struct mail_index_transaction *list_trans,
const struct index_list_changes *changes)
@@ -480,6 +588,8 @@
ilist->vsize_ext_id,
&changes->vsize, NULL);
}
+ if (changes->first_saved_changed)
+ index_list_update_first_saved(box, list_trans, changes);
}
static int index_list_update_mailbox(struct mailbox *box)
@@ -705,4 +815,7 @@
ilist->vsize_ext_id =
mail_index_ext_register(ilist->index, "vsize", 0,
sizeof(struct mailbox_index_vsize), sizeof(uint64_t));
+ ilist->first_saved_ext_id =
+ mail_index_ext_register(ilist->index, "1saved", 0,
+ sizeof(struct mailbox_index_first_saved), sizeof(uint32_t));
}
diff -r db90e76f44dc -r 82e6a3baa001 src/lib-storage/list/mailbox-list-index.h
--- a/src/lib-storage/list/mailbox-list-index.h Fri Nov 27 13:06:01 2015 +0200
+++ b/src/lib-storage/list/mailbox-list-index.h Fri Nov 27 13:59:22 2015 +0200
@@ -89,7 +89,7 @@
const char *path;
struct mail_index *index;
uint32_t ext_id, msgs_ext_id, hmodseq_ext_id, subs_hdr_ext_id;
- uint32_t vsize_ext_id;
+ uint32_t vsize_ext_id, first_saved_ext_id;
struct timeval last_refresh_timeval;
pool_t mailbox_pool;
diff -r db90e76f44dc -r 82e6a3baa001 src/lib-storage/mail-autoexpunge.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/mail-autoexpunge.c Fri Nov 27 13:59:22 2015 +0200
@@ -0,0 +1,93 @@
+/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "mail-storage-private.h"
+#include "mail-namespace.h"
+#include "mail-user.h"
+#include "mail-autoexpunge.h"
+
+static int mailbox_autoexpunge(struct mailbox *box, time_t expire_time)
+{
+ struct mailbox_transaction_context *t;
+ struct mail *mail;
+ struct mailbox_metadata metadata;
+ const struct mail_index_header *hdr;
+ uint32_t seq;
+ time_t timestamp;
+ int ret = 0;
+
+ /* first try to check quickly from mailbox list index if we should
+ bother opening this mailbox. */
+ if (mailbox_get_metadata(box, MAILBOX_METADATA_FIRST_SAVE_DATE,
+ &metadata) == 0) {
+ if (metadata.first_save_date == (time_t)-1 ||
+ metadata.first_save_date > expire_time)
+ return 0;
+ }
+
+ if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FAST) < 0) {
+ if (mailbox_get_last_mail_error(box) == MAIL_ERROR_NOTFOUND) {
+ /* autocreated mailbox doesn't exist yet */
+ return 0;
+ }
+ return -1;
+ }
+
+ t = mailbox_transaction_begin(box, 0);
+ mail = mail_alloc(t, 0, NULL);
+
+ hdr = mail_index_get_header(box->view);
+ for (seq = 1; seq <= hdr->messages_count; seq++) {
+ mail_set_seq(mail, seq);
+ if (mail_get_save_date(mail, ×tamp) == 0) {
+ if (timestamp > expire_time)
+ break;
+ mail_expunge(mail);
+ } else if (mailbox_get_last_mail_error(box) == MAIL_ERROR_EXPUNGED) {
+ /* already expunged */
+ } else {
+ /* failed */
+ ret = -1;
+ break;
+ }
+ }
+ mail_free(&mail);
+ if (mailbox_transaction_commit(&t) < 0)
+ ret = -1;
+ return ret;
+}
+
+static void mail_namespace_autoexpunge(struct mail_namespace *ns)
+{
+ struct mailbox_settings *const *box_set;
+ struct mailbox *box;
+ time_t expire_time;
+
+ if (!array_is_created(&ns->set->mailboxes))
+ return;
+
+ array_foreach(&ns->set->mailboxes, box_set) {
+ if ((*box_set)->autoexpunge == 0 ||
+ ioloop_time < (*box_set)->autoexpunge)
+ continue;
+ expire_time = ioloop_time - (*box_set)->autoexpunge;
+ box = mailbox_alloc(ns->list, (*box_set)->name, 0);
+ if (mailbox_autoexpunge(box, expire_time) < 0) {
+ i_error("Failed to autoexpunge mailbox '%s': %s",
+ mailbox_get_vname(box),
+ mailbox_get_last_error(box, NULL));
+ }
+ mailbox_free(&box);
+ }
+}
+
+void mail_user_autoexpunge(struct mail_user *user)
+{
+ struct mail_namespace *ns;
+
+ for (ns = user->namespaces; ns != NULL; ns = ns->next) {
More information about the dovecot-cvs
mailing list