[dovecot-cvs] dovecot/src/lib-index mail-index-sync.c, 1.25,
1.26 mail-index.h, 1.122, 1.123 mail-transaction-util.c, 1.14, 1.15
cras at procontrol.fi
cras at procontrol.fi
Sat Jul 3 20:21:29 EEST 2004
Update of /home/cvs/dovecot/src/lib-index
In directory talvi:/tmp/cvs-serv26178/lib-index
Modified Files:
mail-index-sync.c mail-index.h mail-transaction-util.c
Log Message:
mail_index_sync_sort_flags() now merges flag changes so mail storage
backends don't need to do it (and maildir didn't before). Dirty flags will
be synced now too.
Index: mail-index-sync.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-index/mail-index-sync.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- mail-index-sync.c 28 Jun 2004 17:35:27 -0000 1.25
+++ mail-index-sync.c 3 Jul 2004 17:21:26 -0000 1.26
@@ -10,51 +10,106 @@
#include <stdlib.h>
-static void mail_index_sync_sort_flags(struct mail_index_sync_ctx *ctx)
+static void
+mail_index_sync_sort_flags(buffer_t *dest_buf,
+ const struct mail_transaction_flag_update *src,
+ size_t src_size)
{
- const struct mail_transaction_flag_update *src, *src_end;
- const struct mail_transaction_flag_update *dest;
- struct mail_transaction_flag_update new_update;
- uint32_t last;
+ const struct mail_transaction_flag_update *src_end;
+ struct mail_transaction_flag_update *dest;
+ struct mail_transaction_flag_update new_update, tmp_update;
size_t i, dest_count;
+ int j;
- src = ctx->data;
- src_end = PTR_OFFSET(src, ctx->hdr->size);
- if (src == src_end)
- return;
-
- dest = buffer_get_data(ctx->updates_buf, &dest_count);
+ dest = buffer_get_modifyable_data(dest_buf, &dest_count);
dest_count /= sizeof(*dest);
+ if (dest_count == 0) {
+ buffer_append(dest_buf, src, src_size);
+ return;
+ }
+
+ src_end = PTR_OFFSET(src, src_size);
for (i = 0; src != src_end; src++) {
new_update = *src;
- /* insert it into buffer, split it in multiple parts if needed
- to make sure the ordering stays the same */
+ /* insert it into buffer, split and merge it with existing
+ updates if needed. */
for (; i < dest_count; i++) {
- if (dest[i].uid1 <= new_update.uid1)
+ if (new_update.uid1 > dest[i].uid2)
continue;
- if (dest[i].uid1 > new_update.uid2)
+ if (new_update.uid2 < dest[i].uid1)
break;
- /* partial */
- last = new_update.uid2;
- new_update.uid2 = dest[i].uid1-1;
+ /* at least partially overlapping */
- buffer_insert(ctx->updates_buf, i * sizeof(new_update),
- &new_update, sizeof(new_update));
- dest = buffer_get_data(ctx->updates_buf, NULL);
- dest_count++;
+ if (new_update.uid1 < dest[i].uid1) {
+ /* { 5..6 } + { 1..5 } -> { 1..4 } + { 5..6 } */
+ tmp_update = new_update;
+ tmp_update.uid2 = dest[i].uid1-1;
+ new_update.uid1 = dest[i].uid1;
+ buffer_insert(dest_buf, i * sizeof(tmp_update),
+ &tmp_update, sizeof(tmp_update));
+ dest = buffer_get_modifyable_data(dest_buf,
+ NULL);
+ dest_count++; i++;
+ } else if (new_update.uid1 > dest[i].uid1) {
+ /* { 5..7 } + { 6..6 } ->
+ split old to { 5..5 } + { 6..7 } */
+ tmp_update = dest[i];
+ tmp_update.uid2 = new_update.uid1-1;
+ dest[i].uid1 = new_update.uid1;
+ buffer_insert(dest_buf, i * sizeof(tmp_update),
+ &tmp_update, sizeof(tmp_update));
+ dest = buffer_get_modifyable_data(dest_buf,
+ NULL);
+ dest_count++; i++;
+ }
+ i_assert(new_update.uid1 == dest[i].uid1);
- new_update.uid1 = new_update.uid2+1;
- new_update.uid2 = last;
+ if (new_update.uid2 < dest[i].uid2) {
+ /* { 5..7 } + { 5..6 } -> { 5..6 } + { 7..7 } */
+ tmp_update = dest[i];
+ tmp_update.uid1 = new_update.uid2+1;
+ dest[i].uid2 = new_update.uid2;
+ buffer_insert(dest_buf,
+ (i+1) * sizeof(tmp_update),
+ &tmp_update, sizeof(tmp_update));
+ dest = buffer_get_modifyable_data(dest_buf,
+ NULL);
+ dest_count++;
+ new_update.uid2 = 0;
+ } else {
+ /* full match, or continues. */
+ new_update.uid1 = dest[i].uid2+1;
+ }
+
+ /* dest[i] now contains the overlapping area.
+ merge them - new_update overrides old changes. */
+ dest[i].add_flags |= new_update.add_flags;
+ dest[i].add_flags &= ~new_update.remove_flags;
+ dest[i].remove_flags |= new_update.remove_flags;
+ dest[i].remove_flags &= ~new_update.add_flags;
+
+ for (j = 0; j < INDEX_KEYWORDS_BYTE_COUNT; j++) {
+ dest[i].add_keywords[j] |=
+ new_update.add_keywords[j];
+ dest[i].add_keywords[j] &=
+ ~new_update.remove_keywords[j];
+ dest[i].remove_keywords[j] |=
+ new_update.remove_keywords[j];
+ dest[i].remove_keywords[j] &=
+ ~new_update.add_keywords[j];
+ }
}
- buffer_insert(ctx->updates_buf, i * sizeof(new_update),
- &new_update, sizeof(new_update));
- dest = buffer_get_data(ctx->updates_buf, NULL);
- dest_count++;
+ if (new_update.uid1 <= new_update.uid2) {
+ buffer_insert(dest_buf, i * sizeof(new_update),
+ &new_update, sizeof(new_update));
+ dest = buffer_get_modifyable_data(dest_buf, NULL);
+ dest_count++;
+ }
}
}
@@ -62,23 +117,12 @@
{
switch (ctx->hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
case MAIL_TRANSACTION_EXPUNGE:
- if (buffer_get_used_size(ctx->expunges_buf) == 0) {
- buffer_append(ctx->expunges_buf, ctx->data,
- ctx->hdr->size);
- } else {
- mail_transaction_log_sort_expunges(ctx->expunges_buf,
- ctx->data,
- ctx->hdr->size);
- }
+ mail_transaction_log_sort_expunges(ctx->expunges_buf,
+ ctx->data, ctx->hdr->size);
break;
case MAIL_TRANSACTION_FLAG_UPDATE:
- if (buffer_get_used_size(ctx->expunges_buf) == 0 &&
- buffer_get_used_size(ctx->updates_buf) == 0) {
- buffer_append(ctx->updates_buf, ctx->data,
- ctx->hdr->size);
- } else {
- mail_index_sync_sort_flags(ctx);
- }
+ mail_index_sync_sort_flags(ctx->updates_buf, ctx->data,
+ ctx->hdr->size);
break;
case MAIL_TRANSACTION_APPEND: {
const struct mail_transaction_append_header *hdr = ctx->data;
@@ -99,11 +143,48 @@
}
}
+static int mail_index_sync_add_dirty_updates(struct mail_index_sync_ctx *ctx)
+{
+ struct mail_transaction_flag_update update;
+ const struct mail_index_record *rec;
+ uint32_t seq, messages_count;
+ int i;
+
+ memset(&update, 0, sizeof(update));
+
+ messages_count = mail_index_view_get_message_count(ctx->view);
+ for (seq = 1; seq <= messages_count; seq++) {
+ if (mail_index_lookup(ctx->view, seq, &rec) < 0)
+ return -1;
+
+ if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) == 0)
+ continue;
+
+ update.uid1 = update.uid2 = rec->uid;
+ update.add_flags = rec->flags;
+ update.remove_flags = ~update.add_flags;
+ memcpy(update.add_keywords, rec->keywords,
+ INDEX_KEYWORDS_BYTE_COUNT);
+ for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++)
+ update.remove_keywords[i] = ~update.add_keywords[i];
+
+ mail_index_sync_sort_flags(ctx->updates_buf,
+ &update, sizeof(update));
+ }
+ return 0;
+}
+
static int mail_index_sync_read_and_sort(struct mail_index_sync_ctx *ctx)
{
size_t size;
int ret;
+ if (ctx->view->map->hdr->flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) {
+ /* show dirty flags as flag updates */
+ if (mail_index_sync_add_dirty_updates(ctx) < 0)
+ return -1;
+ }
+
while ((ret = mail_transaction_log_view_next(ctx->view->log_view,
&ctx->hdr,
&ctx->data, NULL)) > 0) {
@@ -260,42 +341,22 @@
next_update = ctx->update_idx == ctx->updates_count ? NULL :
&ctx->updates[ctx->update_idx];
- // FIXME: return dirty flagged records as flag updates
-
- /* the ugliness here is to avoid returning overlapping expunge
- and update areas. For example:
-
- updates[] = A { 1, 7 }, B { 1, 3 }
- expunges[] = { 5, 6 }
-
- will make us return
-
- update A: 1, 4
- update B: 1, 3
- expunge : 5, 6
- update A: 7, 7
- */
- while (next_update != NULL &&
- (next_exp == NULL || next_update->uid1 < next_exp->uid1)) {
- if (next_update->uid2 >= ctx->next_uid) {
- mail_index_sync_get_update(sync_rec, next_update);
- if (next_exp != NULL &&
- next_exp->uid1 <= next_update->uid2) {
- /* it's overlapping.. */
- sync_rec->uid2 = next_exp->uid1-1;
- }
-
- if (sync_rec->uid1 < ctx->next_uid)
- sync_rec->uid1 = ctx->next_uid;
+ if (next_update != NULL &&
+ (next_exp == NULL || next_update->uid1 < next_exp->uid1)) {
+ mail_index_sync_get_update(sync_rec, next_update);
+ if (next_exp != NULL && next_exp->uid1 <= next_update->uid2) {
+ /* it's overlapping with next expunge */
+ sync_rec->uid2 = next_exp->uid1-1;
+ }
- i_assert(sync_rec->uid1 <= sync_rec->uid2);
- ctx->update_idx++;
- return mail_index_sync_rec_check(ctx->view, sync_rec);
+ if (sync_rec->uid1 < ctx->next_uid) {
+ /* overlapping with previous expunge */
+ sync_rec->uid1 = ctx->next_uid;
}
- if (++ctx->update_idx == ctx->updates_count)
- break;
- next_update++;
+ i_assert(sync_rec->uid1 <= sync_rec->uid2);
+ ctx->update_idx++;
+ return mail_index_sync_rec_check(ctx->view, sync_rec);
}
if (next_exp != NULL) {
@@ -304,9 +365,6 @@
return -1;
ctx->expunge_idx++;
-
- /* scan updates again from the beginning */
- ctx->update_idx = 0;
ctx->next_uid = next_exp->uid2+1;
return 1;
}
Index: mail-index.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-index/mail-index.h,v
retrieving revision 1.122
retrieving revision 1.123
diff -u -d -r1.122 -r1.123
--- mail-index.h 3 Jul 2004 10:57:53 -0000 1.122
+++ mail-index.h 3 Jul 2004 17:21:26 -0000 1.123
@@ -194,14 +194,13 @@
mail_index_sync_next() returns all changes from previously committed
transactions which haven't yet been committed to the actual mailbox.
- They're returned in ascending order. You must go through all of them and
- update the mailbox accordingly.
+ They're returned in ascending order and they never overlap (if we add more
+ sync types, then they might). You must go through all of them and update
+ the mailbox accordingly.
None of the changes actually show up in index until at
mail_index_sync_end().
- Note that there may be multiple overlapping flag changes. They're returned
- sorted by their beginning sequence. They never overlap expunges however.
Returned sequence numbers describe the mailbox state at the beginning of
synchronization, ie. expunges don't affect them.
Index: mail-transaction-util.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-index/mail-transaction-util.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- mail-transaction-util.c 24 Jun 2004 11:10:41 -0000 1.14
+++ mail-transaction-util.c 3 Jul 2004 17:21:26 -0000 1.15
@@ -189,12 +189,17 @@
size_t first, i, dest_count;
i_assert(src_buf_size % sizeof(*src) == 0);
- src_end = CONST_PTR_OFFSET(src, src_buf_size);
/* @UNSAFE */
dest = buffer_get_modifyable_data(expunges_buf, &dest_count);
dest_count /= sizeof(*dest);
+ if (dest_count == 0) {
+ buffer_append(expunges_buf, src, src_buf_size);
+ return;
+ }
+
+ src_end = CONST_PTR_OFFSET(src, src_buf_size);
for (i = 0; src != src_end; src++) {
/* src[] must be sorted. */
i_assert(src+1 == src_end || src->uid1 < src[1].uid1);
More information about the dovecot-cvs
mailing list