]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-index: Add cache to mail_cache_get_missing_reason()
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 5 Jun 2017 18:53:18 +0000 (21:53 +0300)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Fri, 9 Jun 2017 07:26:30 +0000 (10:26 +0300)
This avoids excessive CPU usage when it's called in a loop for many mails.

src/lib-index/mail-cache-lookup.c
src/lib-index/mail-cache-private.h

index 31b20e36fd66e59ede13b6e472a2e7410042e099..f1490212fecc056ffe96c05bc1d95211881b84b8 100644 (file)
@@ -616,14 +616,31 @@ static uint32_t
 mail_cache_get_highest_seq_with_cache(struct mail_cache_view *view,
                                      uint32_t below_seq, uint32_t *reset_id_r)
 {
-       uint32_t seq;
+       struct mail_cache_missing_reason_cache *rc = &view->reason_cache;
+       uint32_t seq = below_seq-1, highest_checked_seq = 0;
 
        /* find the newest mail that has anything in cache */
-       for (seq = below_seq-1; seq > 0; seq--) {
-               if (mail_cache_lookup_cur_offset(view->view, seq, reset_id_r) != 0)
+       if (rc->log_file_head_offset == view->view->log_file_head_offset &&
+           rc->log_file_head_seq == view->view->log_file_head_seq) {
+               /* reason_cache matches the current view - we can use it */
+               highest_checked_seq = rc->highest_checked_seq;
+       } else {
+               rc->log_file_head_offset = view->view->log_file_head_offset;
+               rc->log_file_head_seq = view->view->log_file_head_seq;
+       }
+       rc->highest_checked_seq = below_seq;
+
+       /* first check anything not already in reason_cache */
+       for (; seq > highest_checked_seq; seq--) {
+               if (mail_cache_lookup_cur_offset(view->view, seq, reset_id_r) != 0) {
+                       rc->highest_seq_with_cache = seq;
                        return seq;
+               }
        }
-       return 0;
+       if (seq == 0)
+               return 0;
+       /* then return the result from cache */
+       return rc->highest_seq_with_cache;
 }
 
 const char *
index 1fb8b3ad6c69e4309a6f96aaaa3923470e53d70c..ff748cca31877f9f6ed2915f32265a9f0645f5e7 100644 (file)
@@ -169,6 +169,14 @@ struct mail_cache_loop_track {
        uoff_t size_sum;
 };
 
+struct mail_cache_missing_reason_cache {
+       uint32_t highest_checked_seq;
+       uint32_t highest_seq_with_cache;
+
+       uint32_t log_file_head_seq;
+       uoff_t log_file_head_offset;
+};
+
 struct mail_cache_view {
        struct mail_cache *cache;
        struct mail_index_view *view, *trans_view;
@@ -177,6 +185,7 @@ struct mail_cache_view {
        uint32_t trans_seq1, trans_seq2;
 
        struct mail_cache_loop_track loop_track;
+       struct mail_cache_missing_reason_cache reason_cache;
 
        /* if cached_exists_buf[field] == cached_exists_value, it's cached.
           this allows us to avoid constantly clearing the whole buffer.