(t->view->index->fsync_mask & change_mask) != 0 ||
(t->flags & MAIL_INDEX_TRANSACTION_FLAG_FSYNC) != 0;
}
+
+static unsigned int
+count_modseq_incs_with(struct mail_index_transaction *t,
+ ARRAY_TYPE(seq_range) *tmp_seqs,
+ const ARRAY_TYPE(seq_range) *orig_seqs)
+{
+ if (!array_is_created(orig_seqs))
+ return 0;
+
+ array_clear(tmp_seqs);
+ array_append_array(tmp_seqs, orig_seqs);
+ mail_index_transaction_seq_range_to_uid(t, tmp_seqs);
+ return array_count(tmp_seqs) > 0 ? 1 : 0;
+}
+
+static unsigned int
+mail_index_transaction_keywords_count_modseq_incs(struct mail_index_transaction *t)
+{
+ const struct mail_index_transaction_keyword_update *update;
+ ARRAY_TYPE(seq_range) tmp_seqs;
+ unsigned int count = 0;
+
+ i_array_init(&tmp_seqs, 64);
+ array_foreach_modifiable(&t->keyword_updates, update) {
+ count += count_modseq_incs_with(t, &tmp_seqs, &update->add_seq);
+ count += count_modseq_incs_with(t, &tmp_seqs, &update->remove_seq);
+ }
+ array_free(&tmp_seqs);
+ return count;
+}
+
+uint64_t mail_index_transaction_get_highest_modseq(struct mail_index_transaction *t)
+{
+ struct mail_transaction_log_file *file = t->view->index->log->head;
+ uint64_t new_highest_modseq = file->sync_highest_modseq;
+
+ i_assert(file->locked);
+
+ if (new_highest_modseq == 0) {
+ /* highest-modseq tracking isn't enabled in this transaction
+ log file. This shouldn't happen with logs created since
+ v2.2.26+, because initial_modseq is always set. We don't
+ also bother checking if this transaction itself enables the
+ highest-modseq tracking, because it's always done as a
+ standalone transaction in mail_index_modseq_enable(),
+ which doesn't care about this function. */
+ i_warning("%s: Requested highest-modseq for transaction, "
+ "but modseq tracking isn't enabled for the file "
+ "(this shouldn't happen)", file->filepath);
+ return 0;
+ }
+
+ /* finish everything that can affect highest-modseq */
+ mail_index_transaction_finish_so_far(t);
+
+ /* NOTE: keep in sync with mail_transaction_update_modseq() */
+ if (array_is_created(&t->appends) && array_count(&t->appends) > 0) {
+ /* sorting may change the order of keyword_updates, */
+ new_highest_modseq++;
+ }
+ if (array_is_created(&t->updates) && array_count(&t->updates) > 0)
+ new_highest_modseq++;
+ if (array_is_created(&t->keyword_updates)) {
+ new_highest_modseq +=
+ mail_index_transaction_keywords_count_modseq_incs(t);
+ }
+ if (t->attribute_updates != NULL)
+ new_highest_modseq++;
+ /* NOTE: the order of modseq_updates and everything following it
+ must match mail_index_transaction_export(). */
+ if (array_is_created(&t->modseq_updates)) {
+ const struct mail_transaction_modseq_update *mu;
+
+ /* mail_index_update_highest_modseq() is handled here also,
+ as a special case of uid==0. */
+ array_foreach(&t->modseq_updates, mu) {
+ uint64_t modseq = ((uint64_t)mu->modseq_high32 << 32) |
+ mu->modseq_low32;
+ if (new_highest_modseq < modseq)
+ new_highest_modseq = modseq;
+ }
+ }
+ if (array_is_created(&t->expunges) && array_count(&t->expunges) > 0 &&
+ (t->flags & MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL) != 0)
+ new_highest_modseq++;
+ return new_highest_modseq;
+}
return uid1;
}
-static void
-mail_index_convert_to_uid_ranges(struct mail_index_transaction *t,
- ARRAY_TYPE(seq_range) *array)
+void mail_index_transaction_seq_range_to_uid(struct mail_index_transaction *t,
+ ARRAY_TYPE(seq_range) *array)
{
struct seq_range *range, *new_range;
unsigned int i, count;
return;
array_foreach_modifiable(&t->keyword_updates, update) {
- mail_index_convert_to_uid_ranges(t, &update->add_seq);
- mail_index_convert_to_uid_ranges(t, &update->remove_seq);
+ mail_index_transaction_seq_range_to_uid(t, &update->add_seq);
+ mail_index_transaction_seq_range_to_uid(t, &update->remove_seq);
}
}
keyword_updates_convert_to_uids(t);
expunges_convert_to_uids(t);
mail_index_convert_to_uids(t, (void *)&t->modseq_updates);
- mail_index_convert_to_uid_ranges(t, (void *)&t->updates);
+ mail_index_transaction_seq_range_to_uid(t, (void *)&t->updates);
}
void mail_index_transaction_finish_so_far(struct mail_index_transaction *t)
bool mail_index_cancel_keyword_updates(struct mail_index_transaction *t,
uint32_t seq);
+/* As input the array's each element starts with struct seq_range where
+ uid1..uid2 are actually sequences within the transaction view. This function
+ changes the sequences into UIDs. If the transaction has any appends, they
+ must have already been assigned UIDs. */
+void mail_index_transaction_seq_range_to_uid(struct mail_index_transaction *t,
+ ARRAY_TYPE(seq_range) *array);
void mail_index_transaction_finish_so_far(struct mail_index_transaction *t);
void mail_index_transaction_finish(struct mail_index_transaction *t);
void mail_index_transaction_export(struct mail_index_transaction *t,
if (mail_transaction_log_append_begin(log->index, trans_flags, &ctx) < 0)
return -1;
ret = mail_transaction_log_file_refresh(t, ctx);
+#ifdef DEBUG
+ uint64_t expected_highest_modseq =
+ mail_index_transaction_get_highest_modseq(t);
+#endif
if (ret > 0) T_BEGIN {
mail_index_transaction_finish(t);
mail_index_transaction_export(t, ctx);
mail_transaction_log_get_head(log, &log_seq2, &log_offset2);
i_assert(log_seq1 == log_seq2);
+#ifdef DEBUG
+ i_assert(expected_highest_modseq == log->head->sync_highest_modseq);
+#endif
+
if (t->reset) {
/* get rid of the old index. it might just confuse readers,
especially if it's broken. */