dovecot-2.2: lib-storage: Added mailbox-list-notify API for trac...

dovecot at dovecot.org dovecot at dovecot.org
Mon Aug 13 15:23:46 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/a16d77a075bb
changeset: 14898:a16d77a075bb
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Aug 13 15:20:33 2012 +0300
description:
lib-storage: Added mailbox-list-notify API for tracking changes in all mailboxes.
Requires mailbox_list_index=yes to work.

diffstat:

 src/lib-storage/Makefile.am                      |    2 +
 src/lib-storage/index/imapc/imapc-list.c         |    3 +-
 src/lib-storage/index/shared/shared-list.c       |    3 +-
 src/lib-storage/list/Makefile.am                 |    3 +
 src/lib-storage/list/mailbox-list-fs.c           |    3 +-
 src/lib-storage/list/mailbox-list-index-notify.c |  699 +++++++++++++++++++++++
 src/lib-storage/list/mailbox-list-index-status.c |   52 +-
 src/lib-storage/list/mailbox-list-index-sync.c   |   32 +
 src/lib-storage/list/mailbox-list-index.c        |   49 +-
 src/lib-storage/list/mailbox-list-index.h        |   25 +-
 src/lib-storage/list/mailbox-list-maildir.c      |    6 +-
 src/lib-storage/list/mailbox-list-none.c         |    3 +-
 src/lib-storage/list/mailbox-list-notify-tree.c  |  129 ++++
 src/lib-storage/list/mailbox-list-notify-tree.h  |   27 +
 src/lib-storage/mailbox-list-notify.c            |   35 +
 src/lib-storage/mailbox-list-notify.h            |   58 +
 src/lib-storage/mailbox-list-private.h           |   12 +
 17 files changed, 1111 insertions(+), 30 deletions(-)

diffs (truncated from 1506 to 300 lines):

diff -r 026b688b379f -r a16d77a075bb src/lib-storage/Makefile.am
--- a/src/lib-storage/Makefile.am	Mon Aug 13 15:15:07 2012 +0300
+++ b/src/lib-storage/Makefile.am	Mon Aug 13 15:20:33 2012 +0300
@@ -43,6 +43,7 @@
 	mailbox-keywords.c \
 	mailbox-list.c \
 	mailbox-list-iter.c \
+	mailbox-list-notify.c \
 	mailbox-search-result.c \
 	mailbox-tree.c \
 	mailbox-uidvalidity.c
@@ -70,6 +71,7 @@
 	mailbox-guid-cache.h \
 	mailbox-list.h \
 	mailbox-list-private.h \
+	mailbox-list-notify.h \
 	mailbox-search-result-private.h \
 	mailbox-tree.h \
 	mailbox-uidvalidity.h
diff -r 026b688b379f -r a16d77a075bb src/lib-storage/index/imapc/imapc-list.c
--- a/src/lib-storage/index/imapc/imapc-list.c	Mon Aug 13 15:15:07 2012 +0300
+++ b/src/lib-storage/index/imapc/imapc-list.c	Mon Aug 13 15:20:33 2012 +0300
@@ -720,6 +720,7 @@
 		imapc_list_delete_mailbox,
 		imapc_list_delete_dir,
 		imapc_list_delete_symlink,
-		imapc_list_rename_mailbox
+		imapc_list_rename_mailbox,
+		NULL, NULL, NULL, NULL
 	}
 };
diff -r 026b688b379f -r a16d77a075bb src/lib-storage/index/shared/shared-list.c
--- a/src/lib-storage/index/shared/shared-list.c	Mon Aug 13 15:15:07 2012 +0300
+++ b/src/lib-storage/index/shared/shared-list.c	Mon Aug 13 15:20:33 2012 +0300
@@ -359,6 +359,7 @@
 		shared_list_delete_mailbox,
 		shared_list_delete_dir,
 		shared_list_delete_symlink,
-		shared_list_rename_mailbox
+		shared_list_rename_mailbox,
+		NULL, NULL, NULL, NULL
 	}
 };
diff -r 026b688b379f -r a16d77a075bb src/lib-storage/list/Makefile.am
--- a/src/lib-storage/list/Makefile.am	Mon Aug 13 15:15:07 2012 +0300
+++ b/src/lib-storage/list/Makefile.am	Mon Aug 13 15:20:33 2012 +0300
@@ -15,11 +15,13 @@
 	mailbox-list-fs-iter.c \
 	mailbox-list-index.c \
 	mailbox-list-index-iter.c \
+	mailbox-list-index-notify.c \
 	mailbox-list-index-status.c \
 	mailbox-list-index-sync.c \
 	mailbox-list-maildir.c \
 	mailbox-list-maildir-iter.c \
 	mailbox-list-none.c \
+	mailbox-list-notify-tree.c \
 	mailbox-list-subscriptions.c \
 	subscription-file.c
 
@@ -28,6 +30,7 @@
 	mailbox-list-fs.h \
 	mailbox-list-index.h \
 	mailbox-list-maildir.h \
+	mailbox-list-notify-tree.h \
 	mailbox-list-subscriptions.h \
 	subscription-file.h
 
diff -r 026b688b379f -r a16d77a075bb src/lib-storage/list/mailbox-list-fs.c
--- a/src/lib-storage/list/mailbox-list-fs.c	Mon Aug 13 15:15:07 2012 +0300
+++ b/src/lib-storage/list/mailbox-list-fs.c	Mon Aug 13 15:20:33 2012 +0300
@@ -651,6 +651,7 @@
 		fs_list_delete_mailbox,
 		fs_list_delete_dir,
 		mailbox_list_delete_symlink_default,
-		fs_list_rename_mailbox
+		fs_list_rename_mailbox,
+		NULL, NULL, NULL, NULL
 	}
 };
diff -r 026b688b379f -r a16d77a075bb src/lib-storage/list/mailbox-list-index-notify.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/list/mailbox-list-index-notify.c	Mon Aug 13 15:20:33 2012 +0300
@@ -0,0 +1,699 @@
+/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "str.h"
+#include "mail-index-private.h"
+#include "mail-transaction-log-private.h"
+#include "mail-storage.h"
+#include "mailbox-list-notify.h"
+#include "mailbox-list-notify-tree.h"
+#include "mailbox-list-index.h"
+
+#include <sys/stat.h>
+
+#define NOTIFY_DELAY_MSECS 500
+
+enum ilist_ext_type {
+	ILIST_EXT_NONE,
+	ILIST_EXT_BASE,
+	ILIST_EXT_MSGS,
+	ILIST_EXT_HIGHESTMODSEQ,
+	ILIST_EXT_UNKNOWN
+};
+
+struct mailbox_list_notify_rename {
+	uint32_t old_uid, new_uid;
+};
+
+struct mailbox_list_inotify_entry {
+	uint32_t uid;
+	guid_128_t guid;
+	bool expunge;
+};
+
+struct mailbox_list_notify_index {
+	struct mailbox_list_notify notify;
+
+	struct mailbox_list_notify_tree *tree;
+	struct mail_index_view *view, *old_view;
+	struct mail_index_view_sync_ctx *sync_ctx;
+	enum ilist_ext_type cur_ext;
+	uint32_t cur_ext_id;
+
+	void (*wait_callback)(void *context);
+	void *wait_context;
+	struct io *io_wait;
+	struct timeout *to_wait, *to_notify;
+
+	ARRAY_TYPE(seq_range) new_uids, expunged_uids, changed_uids;
+	ARRAY_DEFINE(renames, struct mailbox_list_notify_rename);
+	struct seq_range_iter new_uids_iter, expunged_uids_iter;
+	struct seq_range_iter changed_uids_iter;
+	unsigned int new_uids_n, expunged_uids_n, changed_uids_n;
+	unsigned int rename_idx;
+
+	struct mailbox_list_notify_rec notify_rec;
+	string_t *rec_name;
+
+	struct stat last_st;
+
+	unsigned int initialized:1;
+	unsigned int read_failed:1;
+};
+
+int mailbox_list_index_notify_init(struct mailbox_list *list,
+				   enum mailbox_list_notify_event mask,
+				   struct mailbox_list_notify **notify_r)
+{
+	struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list);
+	struct mailbox_list_notify_index *inotify;
+
+	if (ilist == NULL) {
+		/* can't do this without mailbox list indexes */
+		return -1;
+	}
+
+	(void)mailbox_list_index_refresh(list);
+
+	inotify = i_new(struct mailbox_list_notify_index, 1);
+	inotify->notify.list = list;
+	inotify->notify.mask = mask;
+	inotify->view = mail_index_view_open(ilist->index);
+	inotify->old_view = mail_index_view_dup_private(inotify->view);
+	inotify->tree = mailbox_list_notify_tree_init(list);
+	i_array_init(&inotify->new_uids, 8);
+	i_array_init(&inotify->expunged_uids, 8);
+	i_array_init(&inotify->changed_uids, 16);
+	i_array_init(&inotify->renames, 16);
+	inotify->rec_name = str_new(default_pool, 64);
+
+	*notify_r = &inotify->notify;
+	return 1;
+}
+
+void mailbox_list_index_notify_deinit(struct mailbox_list_notify *notify)
+{
+	struct mailbox_list_notify_index *inotify =
+		(struct mailbox_list_notify_index *)notify;
+	bool b;
+
+	if (inotify->io_wait != NULL)
+		io_remove(&inotify->io_wait);
+	if (inotify->to_wait != NULL)
+		timeout_remove(&inotify->to_wait);
+	if (inotify->to_notify != NULL)
+		timeout_remove(&inotify->to_notify);
+	if (inotify->sync_ctx != NULL)
+		(void)mail_index_view_sync_commit(&inotify->sync_ctx, &b);
+	mail_index_view_close(&inotify->view);
+	mail_index_view_close(&inotify->old_view);
+	mailbox_list_notify_tree_deinit(&inotify->tree);
+	array_free(&inotify->new_uids);
+	array_free(&inotify->expunged_uids);
+	array_free(&inotify->changed_uids);
+	array_free(&inotify->renames);
+	str_free(&inotify->rec_name);
+	i_free(inotify);
+}
+
+static struct mailbox_list_index_node *
+notify_lookup_guid(struct mailbox_list_notify_index *inotify,
+		   struct mail_index_view *view,
+		   uint32_t uid, enum mailbox_status_items items,
+		   struct mailbox_status *status_r, guid_128_t guid_r)
+{
+	struct mailbox_list_index *ilist =
+		INDEX_LIST_CONTEXT(inotify->notify.list);
+	struct mailbox_list_index_node *index_node;
+	uint32_t seq;
+
+	if (!mail_index_lookup_seq(view, uid, &seq))
+		return NULL;
+
+	index_node = mailbox_list_index_lookup_uid(ilist, uid);
+	if (index_node == NULL) {
+		/* re-parse the index list using the given view. we could be
+		   jumping here between old and new view. */
+		(void)mailbox_list_index_parse(ilist, view, FALSE);
+		index_node = mailbox_list_index_lookup_uid(ilist, uid);
+		if (index_node == NULL)
+			return NULL;
+	}
+
+	/* get GUID */
+	memset(status_r, 0, sizeof(*status_r));
+	memset(guid_r, 0, GUID_128_SIZE);
+	(void)mailbox_list_index_status(inotify->notify.list, view, seq,
+					items, status_r, guid_r);
+	return index_node;
+}
+
+static void notify_update_stat(struct mailbox_list_notify_index *inotify)
+{
+	struct mailbox_list_index *ilist =
+		INDEX_LIST_CONTEXT(inotify->notify.list);
+	const char *path = ilist->index->log->filepath;
+
+	if (stat(path, &inotify->last_st) < 0 && errno != ENOENT) {
+		i_error("stat(%s) failed: %m", path);
+		mailbox_list_index_notify_wait(&inotify->notify, NULL, NULL);
+	}
+}
+
+static void
+mailbox_list_index_notify_sync_init(struct mailbox_list_notify_index *inotify)
+{
+	struct mail_index_view_sync_rec sync_rec;
+
+	notify_update_stat(inotify);
+	(void)mail_index_refresh(inotify->view->index);
+
+	/* sync the view so that map extensions gets updated */
+	inotify->sync_ctx = mail_index_view_sync_begin(inotify->view, 0);
+	mail_transaction_log_view_mark(inotify->view->log_view);
+	while (mail_index_view_sync_next(inotify->sync_ctx, &sync_rec)) ;
+	mail_transaction_log_view_rewind(inotify->view->log_view);
+
+	inotify->cur_ext = ILIST_EXT_NONE;
+	inotify->cur_ext_id = (uint32_t)-1;
+}
+
+static bool notify_ext_rec(struct mailbox_list_notify_index *inotify,
+			   uint32_t uid)
+{
+	struct mailbox_list_notify *notify = &inotify->notify;
+
+	switch (inotify->cur_ext) {
+	case ILIST_EXT_NONE:
+		i_unreached();
+	case ILIST_EXT_BASE:
+		/* UIDVALIDITY changed */
+		if ((notify->mask & MAILBOX_LIST_NOTIFY_UIDVALIDITY) == 0)
+			return FALSE;
+		break;
+	case ILIST_EXT_MSGS:
+		/* APPEND, EXPUNGE, \Seen or \Recent flag change */
+		if ((notify->mask & MAILBOX_LIST_NOTIFY_STATUS) == 0)
+			return FALSE;
+		break;
+	case ILIST_EXT_HIGHESTMODSEQ:
+		/* when this doesn't come with EXT_MSGS update,
+		   it can only be a flag change or an explicit
+		   modseq change */
+		if ((notify->mask & MAILBOX_LIST_NOTIFY_MODSEQ_CHANGES) == 0)
+			return FALSE;
+		break;
+	case ILIST_EXT_UNKNOWN:
+		return FALSE;
+	}
+	seq_range_array_add(&inotify->changed_uids, uid);
+	return TRUE;
+}
+
+static int
+mailbox_list_index_notify_read_next(struct mailbox_list_notify_index *inotify)
+{


More information about the dovecot-cvs mailing list