dovecot-2.0: virtual: Fixed crashes when simultaneous connection...
dovecot at dovecot.org
dovecot at dovecot.org
Tue May 26 08:37:10 EEST 2009
details: http://hg.dovecot.org/dovecot-2.0/rev/17a2415fdab9
changeset: 9377:17a2415fdab9
user: Timo Sirainen <tss at iki.fi>
date: Tue May 26 01:36:51 2009 -0400
description:
virtual: Fixed crashes when simultaneous connections accessed the same virtual mailbox.
diffstat:
3 files changed, 217 insertions(+), 17 deletions(-)
src/plugins/virtual/virtual-storage.c | 2
src/plugins/virtual/virtual-storage.h | 5
src/plugins/virtual/virtual-sync.c | 227 ++++++++++++++++++++++++++++++---
diffs (truncated from 372 to 300 lines):
diff -r 446ba4e8d37d -r 17a2415fdab9 src/plugins/virtual/virtual-storage.c
--- a/src/plugins/virtual/virtual-storage.c Tue May 26 00:39:25 2009 -0400
+++ b/src/plugins/virtual/virtual-storage.c Tue May 26 01:36:51 2009 -0400
@@ -362,6 +362,8 @@ static int virtual_storage_mailbox_close
virtual_copy_error(box->storage, storage);
ret = -1;
}
+ if (array_is_created(&bboxes[i]->sync_outside_expunges))
+ array_free(&bboxes[i]->sync_outside_expunges);
array_free(&bboxes[i]->sync_pending_removes);
array_free(&bboxes[i]->uids);
}
diff -r 446ba4e8d37d -r 17a2415fdab9 src/plugins/virtual/virtual-storage.h
--- a/src/plugins/virtual/virtual-storage.h Tue May 26 00:39:25 2009 -0400
+++ b/src/plugins/virtual/virtual-storage.h Tue May 26 01:36:51 2009 -0400
@@ -84,6 +84,9 @@ struct virtual_backend_box {
struct mail *sync_mail;
/* pending removed UIDs */
ARRAY_TYPE(seq_range) sync_pending_removes;
+ /* another process expunged these UIDs. they need to be removed on
+ next sync. */
+ ARRAY_TYPE(seq_range) sync_outside_expunges;
/* name contains a wildcard, this is a glob for it */
struct imap_match_glob *glob;
@@ -91,6 +94,7 @@ struct virtual_backend_box {
unsigned int sync_seen:1;
unsigned int wildcard:1;
+ unsigned int uids_nonsorted:1;
};
ARRAY_DEFINE_TYPE(virtual_backend_box, struct virtual_backend_box *);
@@ -108,6 +112,7 @@ struct virtual_mailbox {
char *vseq_lookup_prev_mailbox;
struct virtual_backend_box *vseq_lookup_prev_bbox;
+ uint32_t sync_virtual_next_uid;
/* Mailboxes this virtual mailbox consists of, sorted by mailbox_id */
ARRAY_TYPE(virtual_backend_box) backend_boxes;
diff -r 446ba4e8d37d -r 17a2415fdab9 src/plugins/virtual/virtual-sync.c
--- a/src/plugins/virtual/virtual-sync.c Tue May 26 00:39:25 2009 -0400
+++ b/src/plugins/virtual/virtual-sync.c Tue May 26 01:36:51 2009 -0400
@@ -8,6 +8,7 @@
#include "mail-index-modseq.h"
#include "mail-search-build.h"
#include "mailbox-search-result-private.h"
+#include "index-sync-private.h"
#include "index-search-result.h"
#include "virtual-storage.h"
@@ -518,11 +519,10 @@ virtual_sync_mailbox_box_remove(struct v
for (; uid <= uids[i].seq2; uid++, src++) {
i_assert(src < rec_count);
i_assert(uidmap[src].real_uid == uid);
- if (!mail_index_lookup_seq(ctx->sync_view,
- uidmap[src].virtual_uid,
- &vseq))
- i_unreached();
- mail_index_expunge(ctx->trans, vseq);
+ if (mail_index_lookup_seq(ctx->sync_view,
+ uidmap[src].virtual_uid,
+ &vseq))
+ mail_index_expunge(ctx->trans, vseq);
}
}
array_delete(&bbox->uids, dest, src - dest);
@@ -600,17 +600,39 @@ static int virtual_backend_uidmap_cmp(co
return 0;
}
+static void virtual_sync_bbox_uids_sort(struct virtual_backend_box *bbox)
+{
+ struct virtual_backend_uidmap *uids;
+ unsigned int uid_count;
+
+ /* the uidmap must be sorted by real_uids */
+ uids = array_get_modifiable(&bbox->uids, &uid_count);
+ qsort(uids, uid_count, sizeof(*uids), virtual_backend_uidmap_cmp);
+ bbox->uids_nonsorted = FALSE;
+}
+
+static void virtual_sync_backend_boxes_sort_uids(struct virtual_mailbox *mbox)
+{
+ struct virtual_backend_box *const *bboxes;
+ unsigned int i, count;
+
+ bboxes = array_get(&mbox->backend_boxes, &count);
+ for (i = 0; i < count; i++) {
+ if (bboxes[i]->uids_nonsorted)
+ virtual_sync_bbox_uids_sort(bboxes[i]);
+ }
+}
+
static void
virtual_sync_backend_handle_old_vmsgs(struct virtual_sync_context *ctx,
struct virtual_backend_box *bbox,
struct mail_search_result *result)
{
struct index_mailbox *ibox = (struct index_mailbox *)bbox->box;
- struct virtual_backend_uidmap uidmap, *uids;
const struct virtual_mail_index_record *vrec;
+ struct virtual_backend_uidmap uidmap;
const void *data;
uint32_t seq, vseq, vuid, messages;
- unsigned int uid_count;
bool expunged;
/* add the currently existing UIDs to uidmap. remember the messages
@@ -641,9 +663,7 @@ virtual_sync_backend_handle_old_vmsgs(st
}
}
- /* the uidmap must be sorted by real_uids */
- uids = array_get_modifiable(&bbox->uids, &uid_count);
- qsort(uids, uid_count, sizeof(*uids), virtual_backend_uidmap_cmp);
+ virtual_sync_bbox_uids_sort(bbox);
}
static int virtual_sync_backend_box_continue(struct virtual_sync_context *ctx,
@@ -697,6 +717,76 @@ static int virtual_sync_backend_box_cont
return 0;
}
+static void virtual_sync_drop_existing(struct virtual_backend_box *bbox,
+ ARRAY_TYPE(seq_range) *added_uids)
+{
+ ARRAY_TYPE(seq_range) drop_uids;
+ const struct virtual_backend_uidmap *uidmap;
+ struct seq_range_iter iter;
+ unsigned int i, n = 0, count;
+ uint32_t add_uid;
+
+ seq_range_array_iter_init(&iter, added_uids);
+ if (!seq_range_array_iter_nth(&iter, n++, &add_uid))
+ return;
+
+ uidmap = array_get_modifiable(&bbox->uids, &count);
+ (void)bsearch_insert_pos(&add_uid, uidmap, count, sizeof(*uidmap),
+ virtual_backend_uidmap_bsearch_cmp, &i);
+ if (i == count)
+ return;
+
+ t_array_init(&drop_uids, array_count(added_uids));
+ for (; i < count; ) {
+ if (uidmap[i].real_uid < add_uid) {
+ i++;
+ continue;
+ }
+ if (uidmap[i].real_uid == add_uid) {
+ seq_range_array_add(&drop_uids, 0, add_uid);
+ i++;
+ }
+ if (!seq_range_array_iter_nth(&iter, n++, &add_uid))
+ break;
+ }
+ seq_range_array_remove_seq_range(added_uids, &drop_uids);
+}
+
+static void virtual_sync_drop_nonexisting(struct virtual_backend_box *bbox,
+ ARRAY_TYPE(seq_range) *removed_uids)
+{
+ ARRAY_TYPE(seq_range) drop_uids;
+ const struct virtual_backend_uidmap *uidmap;
+ struct seq_range_iter iter;
+ unsigned int i, n = 0, count;
+ uint32_t remove_uid;
+
+ seq_range_array_iter_init(&iter, removed_uids);
+ if (!seq_range_array_iter_nth(&iter, n++, &remove_uid))
+ return;
+
+ uidmap = array_get_modifiable(&bbox->uids, &count);
+ (void)bsearch_insert_pos(&remove_uid, uidmap, count, sizeof(*uidmap),
+ virtual_backend_uidmap_bsearch_cmp, &i);
+ if (i == count)
+ return;
+
+ t_array_init(&drop_uids, array_count(removed_uids));
+ for (; i < count; ) {
+ if (uidmap[i].real_uid < remove_uid) {
+ i++;
+ continue;
+ }
+ if (uidmap[i].real_uid != remove_uid) {
+ seq_range_array_add(&drop_uids, 0, remove_uid);
+ i++;
+ }
+ if (!seq_range_array_iter_nth(&iter, n++, &remove_uid))
+ break;
+ }
+ seq_range_array_remove_seq_range(removed_uids, &drop_uids);
+}
+
static void virtual_sync_mailbox_box_update(struct virtual_sync_context *ctx,
struct virtual_backend_box *bbox)
{
@@ -708,6 +798,16 @@ static void virtual_sync_mailbox_box_upd
mailbox_search_result_sync(bbox->search_result,
&removed_uids, &added_uids);
+ if (array_is_created(&bbox->sync_outside_expunges)) {
+ seq_range_array_remove_seq_range(&bbox->sync_outside_expunges,
+ &added_uids);
+ seq_range_array_merge(&removed_uids,
+ &bbox->sync_outside_expunges);
+ array_clear(&bbox->sync_outside_expunges);
+ }
+
+ virtual_sync_drop_existing(bbox, &added_uids);
+ virtual_sync_drop_nonexisting(bbox, &removed_uids);
/* if any of the pending removes came back, we don't want to expunge
them anymore. also since they already exist, remove them from
@@ -827,8 +927,12 @@ static int virtual_sync_backend_box_sync
for (; idx1 <= idx2; idx1++) {
vuid = uidmap[idx1].virtual_uid;
if (!mail_index_lookup_seq(ctx->sync_view,
- vuid, &vseq))
- i_unreached();
+ vuid, &vseq)) {
+ /* expunged by another session,
+ but we haven't yet updated
+ bbox->uids. */
+ continue;
+ }
virtual_sync_external_flags(ctx, bbox, vseq,
uidmap[idx1].real_uid);
}
@@ -1089,13 +1193,17 @@ static void virtual_sync_backend_add_new
struct virtual_add_record *adds;
struct virtual_backend_box *bbox;
struct virtual_backend_uidmap *uidmap;
+ const struct mail_index_header *hdr;
const struct virtual_mail_index_record *vrec;
unsigned int i, count, idx, uid_count;
uint32_t vseq, first_uid, next_uid;
+ hdr = mail_index_get_header(ctx->sync_view);
adds = array_get_modifiable(&ctx->all_adds, &count);
- if (count == 0)
- return;
+ if (count == 0) {
+ ctx->mbox->sync_virtual_next_uid = hdr->next_uid;
+ return;
+ }
if (adds[0].rec.mailbox_id == adds[count-1].rec.mailbox_id) {
/* all messages are from a single mailbox. add them in
@@ -1119,7 +1227,7 @@ static void virtual_sync_backend_add_new
}
/* assign UIDs to new messages */
- first_uid = mail_index_get_header(ctx->sync_view)->next_uid;
+ first_uid = hdr->next_uid;
mail_index_append_assign_uids(ctx->trans, first_uid, &next_uid);
/* update virtual UIDs in uidmap */
@@ -1139,12 +1247,94 @@ static void virtual_sync_backend_add_new
i_assert(uidmap[idx].virtual_uid == 0);
uidmap[idx].virtual_uid = first_uid + i;
}
+ ctx->mbox->sync_virtual_next_uid = first_uid + i;
+}
+
+static void
+virtual_sync_apply_existing_appends(struct virtual_sync_context *ctx)
+{
+ uint32_t virtual_ext_id = ctx->mbox->virtual_ext_id;
+ struct virtual_backend_box *bbox = NULL;
+ const struct mail_index_header *hdr;
+ const struct virtual_mail_index_record *vrec;
+ struct virtual_backend_uidmap uidmap;
+ const void *data;
+ bool expunged;
+ uint32_t seq, seq2;
+
+ if (!ctx->mbox->uids_mapped)
+ return;
+
+ hdr = mail_index_get_header(ctx->sync_view);
+ if (ctx->mbox->sync_virtual_next_uid >= hdr->next_uid)
+ return;
+
+ /* another process added messages to virtual index. get backend boxes'
+ uid lists up-to-date by adding the new messages there. */
+ if (!mail_index_lookup_seq_range(ctx->sync_view,
+ ctx->mbox->sync_virtual_next_uid,
+ (uint32_t)-1, &seq, &seq2))
+ return;
+
+ memset(&uidmap, 0, sizeof(uidmap));
+ for (; seq <= seq2; seq++) {
+ mail_index_lookup_ext(ctx->sync_view, seq, virtual_ext_id,
+ &data, &expunged);
+ vrec = data;
+ uidmap.real_uid = vrec->real_uid;
+ mail_index_lookup_uid(ctx->sync_view, seq, &uidmap.virtual_uid);
+
More information about the dovecot-cvs
mailing list