dovecot-1.2: Maildir/dbox: Try harder to assign unique UIDVALIDI...

dovecot at dovecot.org dovecot at dovecot.org
Sat Oct 11 13:26:51 EEST 2008


details:   http://hg.dovecot.org/dovecot-1.2/rev/110afc84fbb1
changeset: 8260:110afc84fbb1
user:      Timo Sirainen <tss at iki.fi>
date:      Sat Oct 11 13:26:46 2008 +0300
description:
Maildir/dbox: Try harder to assign unique UIDVALIDITY values to mailboxes.

diffstat:

9 files changed, 243 insertions(+), 10 deletions(-)
src/lib-storage/Makefile.am                        |    6 
src/lib-storage/index/dbox/dbox-index.c            |   17 +
src/lib-storage/index/dbox/dbox-storage.h          |    1 
src/lib-storage/index/maildir/maildir-storage.c    |   11 +
src/lib-storage/index/maildir/maildir-storage.h    |    2 
src/lib-storage/index/maildir/maildir-sync-index.c |    4 
src/lib-storage/index/maildir/maildir-uidlist.c    |   10 -
src/lib-storage/mailbox-uidvalidity.c              |  196 ++++++++++++++++++++
src/lib-storage/mailbox-uidvalidity.h              |    6 

diffs (truncated from 394 to 300 lines):

diff -r 4dc07239ddfa -r 110afc84fbb1 src/lib-storage/Makefile.am
--- a/src/lib-storage/Makefile.am	Fri Oct 10 21:21:52 2008 +0300
+++ b/src/lib-storage/Makefile.am	Sat Oct 11 13:26:46 2008 +0300
@@ -19,7 +19,8 @@ libstorage_a_SOURCES = \
 	mail-user.c \
 	mailbox-list.c \
 	mailbox-search-result.c \
-	mailbox-tree.c
+	mailbox-tree.c \
+	mailbox-uidvalidity.c
 
 headers = \
 	mail-copy.h \
@@ -34,7 +35,8 @@ headers = \
 	mailbox-list.h \
 	mailbox-list-private.h \
 	mailbox-search-result-private.h \
-	mailbox-tree.h
+	mailbox-tree.h \
+	mailbox-uidvalidity.h
 
 if INSTALL_HEADERS
   pkginc_libdir=$(pkgincludedir)/src/lib-storage
diff -r 4dc07239ddfa -r 110afc84fbb1 src/lib-storage/index/dbox/dbox-index.c
--- a/src/lib-storage/index/dbox/dbox-index.c	Fri Oct 10 21:21:52 2008 +0300
+++ b/src/lib-storage/index/dbox/dbox-index.c	Sat Oct 11 13:26:46 2008 +0300
@@ -9,6 +9,7 @@
 #include "write-full.h"
 #include "nfs-workarounds.h"
 #include "safe-mkstemp.h"
+#include "mailbox-uidvalidity.h"
 #include "dbox-storage.h"
 #include "dbox-file.h"
 #include "dbox-index.h"
@@ -151,15 +152,27 @@ dbox_index_set_corrupted(struct dbox_ind
 	return -1;
 }
 
+static uint32_t dbox_get_uidvalidity_next(struct mail_storage *storage)
+{
+	const char *path;
+
+	path = mailbox_list_get_path(storage->list, NULL,
+				     MAILBOX_LIST_PATH_TYPE_CONTROL);
+	path = t_strconcat(path, "/"DBOX_UIDVALIDITY_FILE_NAME, NULL);
+	return mailbox_uidvalidity_next(path);
+}
+
 static void dbox_index_header_init(struct dbox_index *index,
 				   struct dbox_index_file_header *hdr)
 {
 	if (index->uid_validity == 0) {
+		struct index_mailbox *ibox = &index->mbox->ibox;
 		const struct mail_index_header *idx_hdr;
 
-		idx_hdr = mail_index_get_header(index->mbox->ibox.view);
+		idx_hdr = mail_index_get_header(ibox->view);
 		index->uid_validity = idx_hdr->uid_validity != 0 ?
-			idx_hdr->uid_validity : (uint32_t)ioloop_time;
+			idx_hdr->uid_validity :
+			dbox_get_uidvalidity_next(ibox->box.storage);
 	}
 
 	memset(hdr, ' ', sizeof(*hdr));
diff -r 4dc07239ddfa -r 110afc84fbb1 src/lib-storage/index/dbox/dbox-storage.h
--- a/src/lib-storage/index/dbox/dbox-storage.h	Fri Oct 10 21:21:52 2008 +0300
+++ b/src/lib-storage/index/dbox/dbox-storage.h	Sat Oct 11 13:26:46 2008 +0300
@@ -6,6 +6,7 @@
 
 #define DBOX_STORAGE_NAME "dbox"
 #define DBOX_SUBSCRIPTION_FILE_NAME ".dbox-subscriptions"
+#define DBOX_UIDVALIDITY_FILE_NAME ".dbox-uidvalidity"
 #define DBOX_INDEX_PREFIX "dovecot.index"
 
 #define DBOX_MAILDIR_NAME "dbox-Mails"
diff -r 4dc07239ddfa -r 110afc84fbb1 src/lib-storage/index/maildir/maildir-storage.c
--- a/src/lib-storage/index/maildir/maildir-storage.c	Fri Oct 10 21:21:52 2008 +0300
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Sat Oct 11 13:26:46 2008 +0300
@@ -8,6 +8,7 @@
 #include "mkdir-parents.h"
 #include "unlink-directory.h"
 #include "unlink-old-files.h"
+#include "mailbox-uidvalidity.h"
 #include "maildir-storage.h"
 #include "maildir-uidlist.h"
 #include "maildir-keywords.h"
@@ -996,6 +997,16 @@ maildirplusplus_iter_is_mailbox(struct m
 		ret = 1;
 	}
 	return ret;
+}
+
+uint32_t maildir_get_uidvalidity_next(struct mail_storage *storage)
+{
+	const char *path;
+
+	path = mailbox_list_get_path(storage->list, NULL,
+				     MAILBOX_LIST_PATH_TYPE_CONTROL);
+	path = t_strconcat(path, "/"MAILDIR_UIDVALIDITY_FNAME, NULL);
+	return mailbox_uidvalidity_next(path);
 }
 
 static void maildir_class_init(void)
diff -r 4dc07239ddfa -r 110afc84fbb1 src/lib-storage/index/maildir/maildir-storage.h
--- a/src/lib-storage/index/maildir/maildir-storage.h	Fri Oct 10 21:21:52 2008 +0300
+++ b/src/lib-storage/index/maildir/maildir-storage.h	Sat Oct 11 13:26:46 2008 +0300
@@ -5,6 +5,7 @@
 #define MAILDIR_SUBSCRIPTION_FILE_NAME "subscriptions"
 #define MAILDIR_INDEX_PREFIX "dovecot.index"
 #define MAILDIR_UNLINK_DIRNAME "DOVECOT-TRASHED"
+#define MAILDIR_UIDVALIDITY_FNAME "dovecot-uidvalidity"
 
 /* "base,S=123:2," means:
    <base> [<extra sep> <extra data> [..]] <info sep> 2 <flags sep> */
@@ -122,6 +123,7 @@ int maildir_file_do(struct maildir_mailb
 #endif
 
 bool maildir_set_deleted(struct maildir_mailbox *mbox);
+uint32_t maildir_get_uidvalidity_next(struct mail_storage *storage);
 
 void maildir_transaction_class_init(void);
 void maildir_transaction_class_deinit(void);
diff -r 4dc07239ddfa -r 110afc84fbb1 src/lib-storage/index/maildir/maildir-sync-index.c
--- a/src/lib-storage/index/maildir/maildir-sync-index.c	Fri Oct 10 21:21:52 2008 +0300
+++ b/src/lib-storage/index/maildir/maildir-sync-index.c	Sat Oct 11 13:26:46 2008 +0300
@@ -465,8 +465,8 @@ int maildir_sync_index(struct maildir_in
 		mbox->maildir_hdr.cur_mtime = time(NULL);
 
 	if (uid_validity == 0) {
-		uid_validity = hdr->uid_validity != 0 ?
-			hdr->uid_validity : (uint32_t)ioloop_time;
+		uid_validity = hdr->uid_validity != 0 ? hdr->uid_validity :
+			maildir_get_uidvalidity_next(mbox->ibox.box.storage);
 		maildir_uidlist_set_uid_validity(mbox->uidlist, uid_validity);
 	}
 	maildir_uidlist_set_next_uid(mbox->uidlist, hdr_next_uid, FALSE);
diff -r 4dc07239ddfa -r 110afc84fbb1 src/lib-storage/index/maildir/maildir-uidlist.c
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Fri Oct 10 21:21:52 2008 +0300
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Sat Oct 11 13:26:46 2008 +0300
@@ -1189,6 +1189,7 @@ static int maildir_uidlist_sync_update(s
 static int maildir_uidlist_sync_update(struct maildir_uidlist_sync_ctx *ctx)
 {
 	struct maildir_uidlist *uidlist = ctx->uidlist;
+	struct mail_storage *storage = uidlist->ibox->box.storage;
 	struct stat st;
 	uoff_t file_size;
 
@@ -1198,7 +1199,8 @@ static int maildir_uidlist_sync_update(s
 
 		hdr = mail_index_get_header(uidlist->ibox->view);
 		uidlist->uid_validity = hdr->uid_validity != 0 ?
-			hdr->uid_validity : (uint32_t)ioloop_time;
+			hdr->uid_validity :
+			maildir_get_uidvalidity_next(storage);
 	}
 
 
@@ -1211,7 +1213,7 @@ static int maildir_uidlist_sync_update(s
 
 		uidlist->fd = nfs_safe_open(uidlist->path, O_RDWR);
 		if (uidlist->fd == -1) {
-			mail_storage_set_critical(uidlist->ibox->box.storage,
+			mail_storage_set_critical(storage,
 				"open(%s) failed: %m", uidlist->path);
 			return -1;
 		}
@@ -1220,7 +1222,7 @@ static int maildir_uidlist_sync_update(s
 	i_assert(ctx->first_unwritten_pos != (unsigned int)-1);
 
 	if (lseek(uidlist->fd, 0, SEEK_END) < 0) {
-		mail_storage_set_critical(uidlist->ibox->box.storage,
+		mail_storage_set_critical(storage,
 			"lseek(%s) failed: %m", uidlist->path);
 		return -1;
 	}
@@ -1230,7 +1232,7 @@ static int maildir_uidlist_sync_update(s
 		return -1;
 
 	if (fstat(uidlist->fd, &st) < 0) {
-		mail_storage_set_critical(uidlist->ibox->box.storage,
+		mail_storage_set_critical(storage,
 			"fstat(%s) failed: %m", uidlist->path);
 		return -1;
 	}
diff -r 4dc07239ddfa -r 110afc84fbb1 src/lib-storage/mailbox-uidvalidity.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/mailbox-uidvalidity.c	Sat Oct 11 13:26:46 2008 +0300
@@ -0,0 +1,196 @@
+/* Copyright (c) 2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "str.h"
+#include "read-full.h"
+#include "write-full.h"
+#include "mailbox-uidvalidity.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#define RETRY_COUNT 10
+
+static uint32_t mailbox_uidvalidity_next_fallback(void)
+{
+	static uint32_t uid_validity = 0;
+
+	/* we failed to use the uidvalidity file. don't fail the mailbox
+	   creation because of it though, most of the time it's safe enough
+	   to use the current time as the uidvalidity value. */
+	if (uid_validity < ioloop_time)
+		uid_validity = ioloop_time;
+	else
+		uid_validity++;
+	return uid_validity;
+}
+
+static void mailbox_uidvalidity_write(const char *path, uint32_t uid_validity)
+{
+	char buf[8+1];
+	int fd;
+
+	fd = open(path, O_RDWR | O_CREAT, 0666);
+	if (fd == -1) {
+		i_error("open(%s) failed: %m", path);
+		return;
+	}
+	i_snprintf(buf, sizeof(buf), "%08x", uid_validity);
+	if (pwrite_full(fd, buf, strlen(buf), 0) < 0)
+		i_error("write(%s) failed: %m", path);
+	if (close(fd) < 0)
+		i_error("close(%s) failed: %m", path);
+}
+
+static int mailbox_uidvalidity_rename(const char *path, uint32_t *uid_validity)
+{
+	string_t *src, *dest;
+	unsigned int i, prefix_len;
+	int ret;
+
+	src = t_str_new(256);
+	str_append(src, path);
+	dest = t_str_new(256);
+	str_append(dest, path);
+	prefix_len = str_len(src);
+
+	for (i = 0; i < RETRY_COUNT; i++) {
+		str_printfa(src, ".%08x", *uid_validity);
+		*uid_validity += 1;
+		str_printfa(dest, ".%08x", *uid_validity);
+
+		if ((ret = rename(str_c(src), str_c(dest))) == 0 ||
+		    errno != ENOENT)
+			break;
+
+		/* possibly a race condition. try the next value. */
+		str_truncate(src, prefix_len);
+		str_truncate(dest, prefix_len);
+	}
+	if (ret < 0)
+		i_error("rename(%s, %s) failed: %m", str_c(src), str_c(dest));
+	return ret;
+}
+
+static uint32_t mailbox_uidvalidity_next_rescan(const char *path)
+{
+	DIR *d;
+	struct dirent *dp;
+	const char *fname, *dir, *prefix, *tmp;
+	char *endp;
+	unsigned int i, prefix_len;
+	uint32_t cur_value, min_value, max_value;
+	int fd;
+
+	fname = strrchr(path, '/');
+	if (fname == NULL) {
+		dir = ".";
+		fname = path;
+	} else {
+		dir = t_strdup_until(path, fname);
+		fname++;
+	}
+
+	d = opendir(dir);
+	if (d == NULL) {
+		i_error("opendir(%s) failed: %m", dir);
+		return mailbox_uidvalidity_next_fallback();
+	}
+	prefix = t_strconcat(fname, ".", NULL);
+	prefix_len = strlen(prefix);
+
+	/* just in case there happens to be multiple matching uidvalidity
+	   files, track the min/max values. use the max value and delete the
+	   min value file. */
+	max_value = 0; min_value = (uint32_t)-1;
+	while ((dp = readdir(d)) != NULL) {
+		if (strncmp(dp->d_name, prefix, prefix_len) == 0) {
+			cur_value = strtoul(dp->d_name + prefix_len, &endp, 16);


More information about the dovecot-cvs mailing list