]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-index: Added mail_index_transaction_get_highest_modseq()
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 14 Nov 2016 16:41:23 +0000 (17:41 +0100)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Fri, 18 Nov 2016 11:55:48 +0000 (13:55 +0200)
src/lib-index/mail-index-transaction-export.c
src/lib-index/mail-index-transaction-finish.c
src/lib-index/mail-index-transaction-private.h
src/lib-index/mail-index-transaction.c
src/lib-index/mail-index.h
src/lib-index/mail-transaction-log-file.c

index f846c891f1c00c79cc291a3d0aeeecde43a63af9..fa690e1ec8f28de9bb24b078e172554f69fc8c19 100644 (file)
@@ -505,3 +505,90 @@ void mail_index_transaction_export(struct mail_index_transaction *t,
                (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;
+}
index 0e47c254d3c9a909e2b82c88e6b5cdbc05f565b4..e182afec3c00183ed8d38f660566fe6af1c3c6d1 100644 (file)
@@ -218,9 +218,8 @@ get_nonexpunged_uid2(struct mail_index_transaction *t,
        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;
@@ -268,8 +267,8 @@ static void keyword_updates_convert_to_uids(struct mail_index_transaction *t)
                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);
        }
 }
 
@@ -320,7 +319,7 @@ mail_index_transaction_convert_to_uids(struct mail_index_transaction *t)
         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)
index 44120f2c4323f0085707a87ad4a30538d70ea7ae..755480c0a09c41788e0efdceab9870a43359cea8 100644 (file)
@@ -137,6 +137,12 @@ bool mail_index_cancel_flag_updates(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,
index d401638cb27e7e86fc10261d0f437a9f24447a64..492615bbdde2b42abf96b3145f424aa8c2e16c3d 100644 (file)
@@ -161,6 +161,10 @@ mail_index_transaction_commit_real(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);
@@ -172,6 +176,10 @@ mail_index_transaction_commit_real(struct mail_index_transaction *t,
        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. */
index 2ead84827fc348b02324fd6232583ac17105f018..c519adae4f24ecb3c54b1c7420aa60f00bdbc77a 100644 (file)
@@ -309,6 +309,11 @@ void mail_index_transaction_reset(struct mail_index_transaction *t);
 void mail_index_transaction_set_max_modseq(struct mail_index_transaction *t,
                                           uint64_t max_modseq,
                                           ARRAY_TYPE(seq_range) *seqs);
+/* Returns the resulting highest-modseq after this commit. This can be called
+   only if transaction log is locked, which normally means only during mail
+   index syncing. If there are any appends, they all must have been assigned
+   UIDs before calling this. */
+uint64_t mail_index_transaction_get_highest_modseq(struct mail_index_transaction *t);
 
 /* Returns the view transaction was created for. */
 struct mail_index_view *
index 36d519b0bbb3e6a09dde64990e931591bade8897..ed073b5130f3618582225dbd2abb406e467810aa 100644 (file)
@@ -1021,6 +1021,7 @@ void mail_transaction_update_modseq(const struct mail_transaction_header *hdr,
                return;
        }
 
+       /* NOTE: keep in sync with mail_index_transaction_get_highest_modseq() */
        switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
        case MAIL_TRANSACTION_EXPUNGE | MAIL_TRANSACTION_EXPUNGE_PROT:
        case MAIL_TRANSACTION_EXPUNGE_GUID | MAIL_TRANSACTION_EXPUNGE_PROT: