why I didn't earlier.
--HG--
branch : HEAD
const struct mail_transaction_flag_update *src, *src_end;
const struct mail_transaction_flag_update *dest;
struct mail_transaction_flag_update new_update;
- struct mail_transaction_expunge_traverse_ctx *exp_ctx;
+ struct mail_transaction_expunge_iter_ctx *exp_ctx;
uint32_t last;
size_t i, dest_count;
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_count /= sizeof(*dest);
- exp_ctx = mail_transaction_expunge_traverse_init(ctx->expunges_buf);
+ exp_ctx = mail_transaction_expunge_iter_init(ctx->expunges_buf);
+ mail_transaction_expunge_iter_seek(exp_ctx, src->seq1, src->seq2);
- for (i = 0; src != src_end; src++) {
+ for (i = 0; src != src_end; ) {
new_update = *src;
- /* find seq1 */
- new_update.seq1 +=
- mail_transaction_expunge_traverse_to(exp_ctx,
- src->seq1);
-
- /* find seq2 */
- new_update.seq2 +=
- mail_transaction_expunge_traverse_to(exp_ctx,
- src->seq2);
+ if (!mail_transaction_expunge_iter_get(exp_ctx,
+ &new_update.seq1,
+ &new_update.seq2)) {
+ mail_transaction_expunge_iter_seek(exp_ctx, src->seq1,
+ src->seq2);
+ src++;
+ continue;
+ }
/* insert it into buffer, split it in multiple parts if needed
to make sure the ordering stays the same */
dest = buffer_get_data(ctx->updates_buf, NULL);
dest_count++;
}
- mail_transaction_expunge_traverse_deinit(exp_ctx);
+ mail_transaction_expunge_iter_deinit(exp_ctx);
}
static void mail_index_sync_sort_transaction(struct mail_index_sync_ctx *ctx)
enum mail_transaction_type type_mask;
buffer_t *expunges_buf, *data_buf;
- struct mail_transaction_expunge_traverse_ctx *exp_ctx;
+ struct mail_transaction_expunge_iter_ctx *exp_ctx;
struct mail_transaction_header tmp_hdr;
struct mail_transaction_log_file *file;
{
struct mail_transaction_log_view *view = context;
struct mail_transaction_expunge new_e;
- uint32_t expunges_before;
- expunges_before = mail_transaction_expunge_traverse_to(view->exp_ctx,
- e->seq2);
- if (expunges_before == 0) {
- buffer_append(view->data_buf, e, sizeof(*e));
- return 1;
+ if (!mail_transaction_expunge_iter_seek(view->exp_ctx,
+ e->seq1, e->seq2)) {
+ new_e = *e;
+ /*FIXME:buffer_append(view->data_buf, e, sizeof(*e));
+ return 1;*/
}
- /* FIXME: if there's expunges in the middle of the
- range, we'd have to split this to multiple records */
+ new_e.uid1 = new_e.uid2 = 0; // FIXME: this breaks anyway
- new_e = *e;
- new_e.seq2 += expunges_before;
- new_e.seq1 += mail_transaction_expunge_traverse_to(view->exp_ctx,
- new_e.seq1);
- buffer_append(view->data_buf, &new_e, sizeof(new_e));
+ while (mail_transaction_expunge_iter_get(view->exp_ctx,
+ &new_e.seq1, &new_e.seq2)) {
+ i_assert(new_e.seq1 != 0);
+ buffer_append(view->data_buf, &new_e, sizeof(new_e));
+ }
return 1;
}
{
struct mail_transaction_log_view *view = context;
struct mail_transaction_flag_update new_u;
- uint32_t expunges_before;
- expunges_before = mail_transaction_expunge_traverse_to(view->exp_ctx,
- u->seq2);
- if (expunges_before == 0) {
+ if (!mail_transaction_expunge_iter_seek(view->exp_ctx,
+ u->seq1, u->seq2)) {
buffer_append(view->data_buf, u, sizeof(*u));
return 1;
}
- /* FIXME: if there's expunges in the middle of the
- range, we'd have to split this to multiple records */
-
new_u = *u;
- new_u.seq2 += expunges_before;
- new_u.seq1 += mail_transaction_expunge_traverse_to(view->exp_ctx,
- new_u.seq1);
- buffer_append(view->data_buf, &new_u, sizeof(new_u));
+ while (mail_transaction_expunge_iter_get(view->exp_ctx,
+ &new_u.seq1, &new_u.seq2))
+ buffer_append(view->data_buf, &new_u, sizeof(new_u));
return 1;
}
{
struct mail_transaction_log_view *view = context;
struct mail_transaction_cache_update new_u;
- uint32_t expunges_before;
-
- expunges_before = mail_transaction_expunge_traverse_to(view->exp_ctx,
- u->seq);
- if (expunges_before != 0) {
- new_u = *u;
- new_u.seq += expunges_before;
- u = &new_u;
+
+ if (!mail_transaction_expunge_iter_seek(view->exp_ctx,
+ u->seq, u->seq)) {
+ buffer_append(view->data_buf, u, sizeof(*u));
+ return 1;
}
- buffer_append(view->data_buf, u, sizeof(*u));
+ new_u = *u;
+ if (mail_transaction_expunge_iter_get(view->exp_ctx,
+ &new_u.seq, &new_u.seq))
+ buffer_append(view->data_buf, &new_u, sizeof(new_u));
return 1;
}
buffer_set_used_size(view->data_buf, 0);
}
- view->exp_ctx = mail_transaction_expunge_traverse_init(
- view->expunges_buf);
+ view->exp_ctx =
+ mail_transaction_expunge_iter_init(view->expunges_buf);
ret = mail_transaction_map(hdr, data, &seqfix_funcs, view);
- mail_transaction_expunge_traverse_deinit(view->exp_ctx);
+ mail_transaction_expunge_iter_deinit(view->exp_ctx);
if (ret > 0) {
- /* modified */
- i_assert(buffer_get_used_size(view->data_buf) ==
- hdr->size);
+ /* modified - size may have changed, so update header */
+ view->tmp_hdr = *hdr;
+ view->tmp_hdr.size =
+ buffer_get_used_size(view->data_buf);
+ *hdr_r = &view->tmp_hdr;
+
*data_r = buffer_get_data(view->data_buf, NULL);
} else {
i_assert(buffer_get_used_size(view->data_buf) == 0);
data, hdr->size);
/* hide expunge protection */
- view->tmp_hdr = *hdr;
+ if (*hdr_r != &view->tmp_hdr) {
+ view->tmp_hdr = *hdr;
+ *hdr_r = &view->tmp_hdr;
+ }
view->tmp_hdr.type &= ~MAIL_TRANSACTION_EXPUNGE_PROT;
- *hdr_r = &view->tmp_hdr;
}
return 1;
#include "mail-transaction-log.h"
#include "mail-transaction-util.h"
-struct mail_transaction_expunge_traverse_ctx {
+struct mail_transaction_expunge_iter_ctx {
const struct mail_transaction_expunge *expunges;
- size_t expunges_count, cur_idx, old_idx;
- uint32_t cur_seq, expunges_before;
- uint32_t old_seq, old_expunges_before;
+ size_t expunges_count;
+ uint32_t cur_seq, cur_idx, expunges_before;
+ uint32_t iter_seq, iter_count, iter_idx;
};
const struct mail_transaction_type_map mail_transaction_type_map[] = {
if (src->seq1 + expunges_before < dest[i].seq1)
break;
- i_assert(src->uid2 > dest[i].uid1);
+ i_assert(src->uid2 == 0 || src->uid2 > dest[i].uid1);
expunges_before += dest[i].seq2 - dest[i].seq1 + 1;
}
new_exp.seq2 += count;
if (new_exp.seq2 == dest[i].seq2)
new_exp.uid2 = dest[i].uid2;
- i_assert(new_exp.uid2 >= dest[i].uid2);
+ i_assert(new_exp.uid2 == 0 ||
+ new_exp.uid2 >= dest[i].uid2);
i++;
}
}
}
-struct mail_transaction_expunge_traverse_ctx *
-mail_transaction_expunge_traverse_init(const buffer_t *expunges_buf)
+struct mail_transaction_expunge_iter_ctx *
+mail_transaction_expunge_iter_init(const buffer_t *expunges_buf)
{
- struct mail_transaction_expunge_traverse_ctx *ctx;
+ struct mail_transaction_expunge_iter_ctx *ctx;
- ctx = i_new(struct mail_transaction_expunge_traverse_ctx, 1);
+ ctx = i_new(struct mail_transaction_expunge_iter_ctx, 1);
ctx->cur_seq = 1;
- ctx->old_seq = 1;
if (expunges_buf != NULL) {
ctx->expunges =
return ctx;
}
-void mail_transaction_expunge_traverse_deinit(
- struct mail_transaction_expunge_traverse_ctx *ctx)
+void mail_transaction_expunge_iter_deinit(
+ struct mail_transaction_expunge_iter_ctx *ctx)
{
i_free(ctx);
}
-uint32_t mail_transaction_expunge_traverse_to(
- struct mail_transaction_expunge_traverse_ctx *ctx, uint32_t seq)
+int mail_transaction_expunge_iter_seek(
+ struct mail_transaction_expunge_iter_ctx *ctx,
+ uint32_t seq1, uint32_t seq2)
{
uint32_t idx, count, last_seq;
- if (seq < ctx->cur_seq) {
- /* allow seeking one back */
- ctx->cur_idx = ctx->old_idx;
- ctx->cur_seq = ctx->old_seq;
- ctx->expunges_before = ctx->old_expunges_before;
- } else {
- ctx->old_idx = ctx->cur_idx;
- ctx->old_seq = ctx->cur_seq;
- ctx->old_expunges_before = ctx->expunges_before;
- }
- i_assert(seq >= ctx->cur_seq);
+ i_assert(seq1 >= ctx->cur_seq);
idx = ctx->cur_idx;
last_seq = idx == 0 ? 1 : ctx->expunges[idx-1].seq2 + 1;
for (; idx < ctx->expunges_count; idx++) {
count = ctx->expunges[idx].seq1 - last_seq;
- if (ctx->cur_seq + count > seq)
+ if (ctx->cur_seq + count > seq1)
break;
ctx->cur_seq += count;
last_seq = ctx->expunges[idx].seq2+1;
}
+ ctx->iter_idx = idx;
+ ctx->iter_seq = seq1 + ctx->expunges_before;
+ ctx->iter_count = seq2 - seq1 + 1;
+
ctx->cur_idx = idx;
- return ctx->expunges_before;
+ return ctx->expunges_before != 0 ||
+ (idx != ctx->expunges_count && ctx->expunges[idx].seq1 <= seq2);
+}
+
+int mail_transaction_expunge_iter_get(
+ struct mail_transaction_expunge_iter_ctx *ctx,
+ uint32_t *seq1_r, uint32_t *seq2_r)
+{
+ if (ctx->iter_count == 0)
+ return 0;
+
+ *seq1_r = ctx->iter_seq;
+
+ if (ctx->iter_idx == ctx->expunges_count ||
+ ctx->expunges[ctx->iter_idx].seq1 >=
+ ctx->iter_seq + ctx->iter_count) {
+ /* last one */
+ *seq2_r = ctx->iter_seq + ctx->iter_count - 1;
+ ctx->iter_count = 0;
+ return 1;
+ }
+
+ ctx->iter_count -= ctx->expunges[ctx->iter_idx].seq1 - ctx->iter_seq;
+ i_assert(ctx->iter_count > 0);
+
+ /* have to split this one */
+ *seq2_r = ctx->expunges[ctx->iter_idx].seq1-1;
+ do {
+ ctx->iter_seq = ctx->expunges[ctx->iter_idx].seq2+1;
+ ctx->iter_idx++;
+ } while (ctx->iter_idx != ctx->expunges_count &&
+ ctx->expunges[ctx->iter_idx].seq1 == ctx->iter_seq);
+ return 1;
}
void
mail_transaction_log_sort_expunges(buffer_t *expunges_buf,
const struct mail_transaction_expunge *src,
- size_t src_buf_size);;
+ size_t src_buf_size);
-struct mail_transaction_expunge_traverse_ctx *
-mail_transaction_expunge_traverse_init(const buffer_t *expunges_buf);
-void mail_transaction_expunge_traverse_deinit(
- struct mail_transaction_expunge_traverse_ctx *ctx);
-uint32_t mail_transaction_expunge_traverse_to(
- struct mail_transaction_expunge_traverse_ctx *ctx, uint32_t seq);
+/* Iterate through expunges buffer. iter_seek()'s seq1/seq2 is assumed to be
+ in post-expunge view, iter_get() updates them to pre-expunge view. Some
+ post-expunge sequence arrays may go through expunges, we split them so it
+ won't be visible. */
+struct mail_transaction_expunge_iter_ctx *
+mail_transaction_expunge_iter_init(const buffer_t *expunges_buf);
+void mail_transaction_expunge_iter_deinit(
+ struct mail_transaction_expunge_iter_ctx *ctx);
+/* Returns TRUE if seq1 or seq2 will be modified by iter_get(). If FALSE is
+ returned calling iter_get() is a bit pointless. */
+int mail_transaction_expunge_iter_seek(
+ struct mail_transaction_expunge_iter_ctx *ctx,
+ uint32_t seq1, uint32_t seq2);
+/* Returns TRUE while sequences are returned. */
+int mail_transaction_expunge_iter_get(
+ struct mail_transaction_expunge_iter_ctx *ctx,
+ uint32_t *seq1_r, uint32_t *seq2_r);
#endif