static void index_mailbox_expunge_unseen_recent(struct index_mailbox_sync_context *ctx) { struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(ctx->ctx.box); struct mail_index_view *view = ctx->ctx.box->view; const struct mail_index_header *hdr; uint32_t seq, start_uid, uid; if (!array_is_created(&ibox->recent_flags)) return; /* expunges array contained expunges for the messages that were already visible in this view, but append+expunge would be invisible. recent_flags may however contain the append UID, so we'll have to remove it separately */ hdr = mail_index_get_header(view); if (ctx->messages_count == 0) uid = 0; else if (ctx->messages_count <= hdr->messages_count) mail_index_lookup_uid(view, ctx->messages_count, &uid); else { i_assert(mail_index_view_is_inconsistent(view)); return; } for (seq = ctx->messages_count + 1; seq <= hdr->messages_count; seq++) { start_uid = uid; mail_index_lookup_uid(view, seq, &uid); if (start_uid + 1 > uid - 1) continue; ibox->recent_flags_count -= seq_range_array_remove_range(&ibox->recent_flags, start_uid + 1, uid - 1); } if (uid + 1 < hdr->next_uid) { ibox->recent_flags_count -= seq_range_array_remove_range(&ibox->recent_flags, uid + 1, hdr->next_uid - 1); } #ifdef DEBUG if (!mail_index_view_is_inconsistent(view)) { const struct seq_range *range; unsigned int i, count; range = array_get(&ibox->recent_flags, &count); for (i = 0; i < count; i++) { for (uid = range[i].seq1; uid <= range[i].seq2; uid++) { if (uid >= hdr->next_uid) break; (void)mail_index_lookup_seq(view, uid, &seq); i_assert(seq != 0); } } } #endif }
static void test_seq_range_array_random(void) { #define SEQ_RANGE_TEST_BUFSIZE 20 #define SEQ_RANGE_TEST_COUNT 10000 unsigned char shadowbuf[SEQ_RANGE_TEST_BUFSIZE]; ARRAY_TYPE(seq_range) range; const struct seq_range *seqs; uint32_t seq1, seq2; unsigned int i, j, ret, ret2, count; int test = -1; ret = ret2 = 0; i_array_init(&range, 1); memset(shadowbuf, 0, sizeof(shadowbuf)); for (i = 0; i < SEQ_RANGE_TEST_COUNT; i++) { seq1 = rand() % SEQ_RANGE_TEST_BUFSIZE; seq2 = seq1 + rand() % (SEQ_RANGE_TEST_BUFSIZE - seq1); test = rand() % 4; switch (test) { case 0: seq_range_array_add(&range, seq1); shadowbuf[seq1] = 1; break; case 1: seq_range_array_add_range(&range, seq1, seq2); memset(shadowbuf + seq1, 1, seq2 - seq1 + 1); break; case 2: ret = seq_range_array_remove(&range, seq1) ? 1 : 0; ret2 = shadowbuf[seq1] != 0 ? 1 : 0; shadowbuf[seq1] = 0; break; case 3: ret = seq_range_array_remove_range(&range, seq1, seq2); for (ret2 = 0; seq1 <= seq2; seq1++) { if (shadowbuf[seq1] != 0) { ret2++; shadowbuf[seq1] = 0; } } break; } if (ret != ret2) break; seqs = array_get(&range, &count); for (j = 0, seq1 = 0; j < count; j++) { if (j > 0 && seqs[j-1].seq2+1 >= seqs[j].seq1) goto fail; for (; seq1 < seqs[j].seq1; seq1++) { if (shadowbuf[seq1] != 0) goto fail; } for (; seq1 <= seqs[j].seq2; seq1++) { if (shadowbuf[seq1] == 0) goto fail; } } i_assert(seq1 <= SEQ_RANGE_TEST_BUFSIZE); for (; seq1 < SEQ_RANGE_TEST_BUFSIZE; seq1++) { if (shadowbuf[seq1] != 0) goto fail; } } fail: if (i == SEQ_RANGE_TEST_COUNT) test_out("seq_range_array random", TRUE); else { test_out_reason("seq_range_array random", FALSE, t_strdup_printf("round %u test %d failed", i, test)); } }