dovecot: Fixes to handling appends and unexpunges.
dovecot at dovecot.org
dovecot at dovecot.org
Mon Jul 16 03:15:28 EEST 2007
details: http://hg.dovecot.org/dovecot/rev/dcaa8d5296a9
changeset: 6034:dcaa8d5296a9
user: Timo Sirainen <tss at iki.fi>
date: Mon Jul 16 03:15:24 2007 +0300
description:
Fixes to handling appends and unexpunges.
diffstat:
1 file changed, 64 insertions(+), 39 deletions(-)
src/lib-storage/index/maildir/maildir-uidlist.c | 103 ++++++++++++++---------
diffs (219 lines):
diff -r 61bf911dad91 -r dcaa8d5296a9 src/lib-storage/index/maildir/maildir-uidlist.c
--- a/src/lib-storage/index/maildir/maildir-uidlist.c Mon Jul 16 03:14:51 2007 +0300
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c Mon Jul 16 03:15:24 2007 +0300
@@ -101,7 +101,7 @@ struct maildir_uidlist_sync_ctx {
ARRAY_TYPE(maildir_uidlist_rec_p) records;
struct hash_table *files;
- unsigned int first_new_pos;
+ unsigned int first_unwritten_pos, first_nouid_pos;
unsigned int new_files_count;
unsigned int partial:1;
@@ -255,6 +255,28 @@ maildir_uidlist_mark_recent(struct maild
uidlist->first_recent_uid = uid;
}
+static int maildir_uid_cmp(const void *p1, const void *p2)
+{
+ const struct maildir_uidlist_rec *const *rec1 = p1, *const *rec2 = p2;
+
+ return (*rec1)->uid < (*rec2)->uid ? -1 :
+ (*rec1)->uid > (*rec2)->uid ? 1 : 0;
+}
+
+static void
+maildir_uidlist_records_array_delete(struct maildir_uidlist *uidlist,
+ struct maildir_uidlist_rec *rec)
+{
+ struct maildir_uidlist_rec *const *recs, *const *pos;
+ unsigned int count;
+
+ recs = array_get(&uidlist->records, &count);
+ pos = bsearch(&rec, recs, count, sizeof(*recs), maildir_uid_cmp);
+ i_assert(pos != NULL);
+
+ array_delete(&uidlist->records, pos - recs, 1);
+}
+
static bool
maildir_uidlist_read_extended(struct maildir_uidlist *uidlist,
const char **line_p,
@@ -295,7 +317,7 @@ static int maildir_uidlist_next(struct m
const char *line)
{
struct mail_storage *storage = &uidlist->mbox->storage->storage;
- struct maildir_uidlist_rec *rec;
+ struct maildir_uidlist_rec *rec, *old_rec;
uint32_t uid;
uid = 0;
@@ -346,11 +368,17 @@ static int maildir_uidlist_next(struct m
}
}
- if (hash_lookup_full(uidlist->files, line, NULL, NULL)) {
- mail_storage_set_critical(&uidlist->mbox->storage->storage,
- "Duplicate file in uidlist file %s: %s",
- uidlist->path, line);
- return 0;
+ old_rec = hash_lookup(uidlist->files, line);
+ if (old_rec != NULL) {
+ /* This can happen if expunged file is moved back and the file
+ was appended to uidlist. */
+ i_warning("%s: Duplicate file entry: %s", uidlist->path, line);
+ /* Delete the old UID */
+ maildir_uidlist_records_array_delete(uidlist, old_rec);
+ /* Replace the old record with this new one */
+ *old_rec = *rec;
+ rec = old_rec;
+ uidlist->recreate = TRUE;
}
rec->filename = p_strdup(uidlist->record_pool, line);
@@ -944,6 +972,7 @@ static int maildir_uidlist_recreate(stru
uidlist->fd_ino = st.st_ino;
uidlist->fd_size = st.st_size;
uidlist->last_read_offset = st.st_size;
+ uidlist->recreate = FALSE;
}
return ret;
}
@@ -982,7 +1011,7 @@ static int maildir_uidlist_sync_update(s
UIDLIST_COMPRESS_PERCENTAGE / 100 >= array_count(&uidlist->records))
return maildir_uidlist_recreate(uidlist);
- i_assert(ctx->first_new_pos != (unsigned int)-1);
+ i_assert(ctx->first_unwritten_pos != (unsigned int)-1);
if (lseek(uidlist->fd, 0, SEEK_END) < 0) {
mail_storage_set_critical(&uidlist->mbox->storage->storage,
@@ -991,7 +1020,7 @@ static int maildir_uidlist_sync_update(s
}
if (maildir_uidlist_write_fd(uidlist, uidlist->fd, uidlist->path,
- ctx->first_new_pos, &file_size) < 0)
+ ctx->first_unwritten_pos, &file_size) < 0)
return -1;
uidlist->last_read_offset = file_size;
@@ -1028,7 +1057,8 @@ int maildir_uidlist_sync_init(struct mai
ctx->uidlist = uidlist;
ctx->sync_flags = sync_flags;
ctx->partial = (sync_flags & MAILDIR_UIDLIST_SYNC_PARTIAL) != 0;
- ctx->first_new_pos = (unsigned int)-1;
+ ctx->first_unwritten_pos = (unsigned int)-1;
+ ctx->first_nouid_pos = (unsigned int)-1;
if (ctx->partial) {
if ((sync_flags & MAILDIR_UIDLIST_SYNC_KEEP_STATE) == 0) {
@@ -1061,8 +1091,8 @@ maildir_uidlist_sync_next_partial(struct
i_assert(rec != NULL || UIDLIST_IS_LOCKED(uidlist));
if (rec == NULL) {
- if (ctx->new_files_count == 0)
- ctx->first_new_pos = array_count(&uidlist->records);
+ if (ctx->first_nouid_pos == (unsigned int)-1)
+ ctx->first_nouid_pos = array_count(&uidlist->records);
ctx->new_files_count++;
ctx->changed = TRUE;
@@ -1164,36 +1194,28 @@ int maildir_uidlist_sync_next(struct mai
return 1;
}
-static int maildir_uid_cmp(const void *p1, const void *p2)
-{
- const struct maildir_uidlist_rec *const *rec1 = p1, *const *rec2 = p2;
-
- return (*rec1)->uid < (*rec2)->uid ? -1 :
- (*rec1)->uid > (*rec2)->uid ? 1 : 0;
-}
-
void maildir_uidlist_sync_remove(struct maildir_uidlist_sync_ctx *ctx,
const char *filename)
{
- struct maildir_uidlist_rec *const *recs, *const *pos, *rec;
- unsigned int count;
+ struct maildir_uidlist_rec *rec;
i_assert(ctx->partial);
- if (ctx->first_new_pos != (unsigned int)-1)
- ctx->first_new_pos--;
+ if (ctx->first_unwritten_pos != (unsigned int)-1) {
+ i_assert(ctx->first_unwritten_pos > 0);
+ ctx->first_unwritten_pos--;
+ }
+ if (ctx->first_nouid_pos != (unsigned int)-1) {
+ i_assert(ctx->first_nouid_pos > 0);
+ ctx->first_nouid_pos--;
+ }
rec = hash_lookup(ctx->uidlist->files, filename);
i_assert(rec != NULL);
i_assert(rec->uid != (uint32_t)-1);
hash_remove(ctx->uidlist->files, filename);
-
- recs = array_get(&ctx->uidlist->records, &count);
- pos = bsearch(&rec, recs, count, sizeof(*recs), maildir_uid_cmp);
- i_assert(pos != NULL);
-
- array_delete(&ctx->uidlist->records, pos - recs, 1);
+ maildir_uidlist_records_array_delete(ctx->uidlist, rec);
ctx->changed = TRUE;
ctx->uidlist->recreate = TRUE;
@@ -1232,14 +1254,17 @@ static void maildir_uidlist_assign_uids(
unsigned int dest, count;
i_assert(UIDLIST_IS_LOCKED(ctx->uidlist));
- i_assert(ctx->first_new_pos != (unsigned int)-1);
-
+ i_assert(ctx->first_nouid_pos != (unsigned int)-1);
+
+ if (ctx->first_unwritten_pos == (unsigned int)-1)
+ ctx->first_unwritten_pos = ctx->first_nouid_pos;
+
+ /* sort new files and assign UIDs for them */
recs = array_get_modifiable(&ctx->uidlist->records, &count);
-
- /* sort new files and assign UIDs for them */
- qsort(recs + ctx->first_new_pos, count - ctx->first_new_pos,
+ qsort(recs + ctx->first_nouid_pos, count - ctx->first_nouid_pos,
sizeof(*recs), maildir_time_cmp);
- for (dest = ctx->first_new_pos; dest < count; dest++) {
+
+ for (dest = ctx->first_nouid_pos; dest < count; dest++) {
i_assert(recs[dest]->uid == (uint32_t)-1);
recs[dest]->uid = ctx->uidlist->next_uid++;
recs[dest]->flags &= ~MAILDIR_UIDLIST_REC_FLAG_MOVED;
@@ -1251,8 +1276,8 @@ static void maildir_uidlist_assign_uids(
}
}
- ctx->first_new_pos = (unsigned int)-1;
ctx->new_files_count = 0;
+ ctx->first_nouid_pos = (unsigned int)-1;
ctx->uidlist->last_seen_uid = ctx->uidlist->next_uid-1;
ctx->uidlist->change_counter++;
@@ -1282,7 +1307,7 @@ static void maildir_uidlist_swap(struct
ctx->record_pool = NULL;
if (ctx->new_files_count != 0) {
- ctx->first_new_pos = count - ctx->new_files_count;
+ ctx->first_nouid_pos = count - ctx->new_files_count;
maildir_uidlist_assign_uids(ctx);
}
@@ -1295,7 +1320,7 @@ void maildir_uidlist_sync_finish(struct
if (!ctx->failed)
maildir_uidlist_swap(ctx);
} else {
- if (ctx->changed)
+ if (ctx->new_files_count != 0)
maildir_uidlist_assign_uids(ctx);
}
More information about the dovecot-cvs
mailing list