]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-index: Remember reason for delayed cache file purges
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Mon, 31 Aug 2020 14:25:54 +0000 (17:25 +0300)
committerTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 3 Sep 2020 15:31:01 +0000 (18:31 +0300)
src/lib-index/mail-cache-fields.c
src/lib-index/mail-cache-private.h
src/lib-index/mail-cache-purge.c
src/lib-index/mail-cache.c
src/lib-index/mail-cache.h

index 17f26d64cf978933a14fe0e7061757237d3e63ea..7638eea6882cd8efd4782b062a428acdcad01f3f 100644 (file)
@@ -287,8 +287,10 @@ mail_cache_header_fields_get_offset(struct mail_cache *cache,
        }
        cache->last_field_header_offset = offset;
 
-       if (next_count > cache->index->optimization_set.cache.purge_header_continue_count)
-               cache->need_purge_file_seq = cache->hdr->file_seq;
+       if (next_count > cache->index->optimization_set.cache.purge_header_continue_count) {
+               mail_cache_purge_later(cache, t_strdup_printf(
+                       "Too many continued headers (%u)", next_count));
+       }
 
        if (field_hdr_r != NULL) {
                /* detect corrupted size later */
@@ -450,7 +452,10 @@ int mail_cache_header_fields_read(struct mail_cache *cache)
                    dec != MAIL_CACHE_DECISION_NO) {
                        /* time to drop this field. don't bother dropping
                           fields that have never been used. */
-                       cache->need_purge_file_seq = cache->hdr->file_seq;
+                       mail_cache_purge_later(cache, t_strdup_printf(
+                               "Drop old field %s (last_used=%"PRIdTIME_T")",
+                               cache->fields[fidx].field.name,
+                               cache->fields[fidx].field.last_used));
                }
 
                 names = p + 1;
index 54d3fb8bfe2165eee23b1befa7a63cfa729f7291..8dfc97f59ae467e57bb67ac40a75ba0185f4aebb 100644 (file)
@@ -134,6 +134,7 @@ struct mail_cache {
        /* 0 is no need for purging, otherwise the file sequence number
           which we want purged. */
        uint32_t need_purge_file_seq;
+       char *need_purge_reason;
 
        unsigned int *file_field_map;
        unsigned int file_fields_count;
index f2d1b14a0b767c1bfcb60835df5118e2d5bb5746..a56e2d842bc2bf9a8dcf766aad0fd6148bc45a19 100644 (file)
@@ -499,7 +499,7 @@ static int mail_cache_purge_locked(struct mail_cache *cache,
                        return -1;
 
                /* was just purged, forget this */
-               cache->need_purge_file_seq = 0;
+               mail_cache_purge_later_reset(cache);
 
                if (*unlock) {
                        (void)mail_cache_unlock(cache);
@@ -531,7 +531,7 @@ static int mail_cache_purge_locked(struct mail_cache *cache,
        if (mail_cache_header_fields_read(cache) < 0)
                return -1;
 
-       cache->need_purge_file_seq = 0;
+       mail_cache_purge_later_reset(cache);
        return 0;
 }
 
@@ -642,3 +642,18 @@ bool mail_cache_need_purge(struct mail_cache *cache)
                (cache->index->flags & MAIL_INDEX_OPEN_FLAG_SAVEONLY) == 0 &&
                !cache->index->readonly;
 }
+
+void mail_cache_purge_later(struct mail_cache *cache, const char *reason)
+{
+       i_assert(cache->hdr != NULL);
+
+       cache->need_purge_file_seq = cache->hdr->file_seq;
+       i_free(cache->need_purge_reason);
+       cache->need_purge_reason = i_strdup(reason);
+}
+
+void mail_cache_purge_later_reset(struct mail_cache *cache)
+{
+       cache->need_purge_file_seq = 0;
+       i_free(cache->need_purge_reason);
+}
index f5422b8f01a27519b7060dee76bc886a6cd3bbb5..9cb4ae60b814c6ac9b3e1ba4a8111b50d5e757df 100644 (file)
@@ -146,7 +146,7 @@ static int mail_cache_try_open(struct mail_cache *cache)
        if (cache->fd == -1) {
                mail_cache_file_close(cache);
                if (errno == ENOENT) {
-                       cache->need_purge_file_seq = 0;
+                       mail_cache_purge_later_reset(cache);
                        return 0;
                }
 
@@ -223,11 +223,11 @@ static void mail_cache_update_need_purge(struct mail_cache *cache)
        struct stat st;
        unsigned int msg_count;
        unsigned int records_count, cont_percentage, delete_percentage;
-       bool want_purge = FALSE;
+       const char *want_purge_reason = NULL;
 
        if (hdr->minor_version == 0) {
                /* purge to get ourself into the new header version */
-               cache->need_purge_file_seq = hdr->file_seq;
+               mail_cache_purge_later(cache, "Minor version too old");
                return;
        }
 
@@ -248,24 +248,28 @@ static void mail_cache_update_need_purge(struct mail_cache *cache)
        cont_percentage = hdr->continued_record_count * 100 / records_count;
        if (cont_percentage >= set->purge_continued_percentage) {
                /* too many continued rows, purge */
-               want_purge = TRUE;
+               want_purge_reason = t_strdup_printf(
+                       "Too many continued records (%u/%u)",
+                       hdr->continued_record_count, records_count);
        }
 
        delete_percentage = hdr->deleted_record_count * 100 /
                (records_count + hdr->deleted_record_count);
        if (delete_percentage >= set->purge_delete_percentage) {
                /* too many deleted records, purge */
-               want_purge = TRUE;
+               want_purge_reason = t_strdup_printf(
+                       "Too many deleted records (%u/%u)",
+                       hdr->deleted_record_count, records_count);
        }
 
-       if (want_purge) {
+       if (want_purge_reason != NULL) {
                if (fstat(cache->fd, &st) < 0) {
                        if (!ESTALE_FSTAT(errno))
                                mail_cache_set_syscall_error(cache, "fstat()");
                        return;
                }
                if ((uoff_t)st.st_size >= set->purge_min_size)
-                       cache->need_purge_file_seq = hdr->file_seq;
+                       mail_cache_purge_later(cache, want_purge_reason);
        }
 
 }
@@ -316,10 +320,9 @@ mail_cache_map_finish(struct mail_cache *cache, uoff_t offset, size_t size,
                /* verify the header validity only with offset=0. this way
                   we won't waste time re-verifying it all the time */
                if (!mail_cache_verify_header(cache, hdr)) {
-                       cache->need_purge_file_seq =
-                               !MAIL_CACHE_IS_UNUSABLE(cache) &&
-                               cache->hdr->file_seq != 0 ?
-                               cache->hdr->file_seq : 0;
+                       if (!MAIL_CACHE_IS_UNUSABLE(cache) &&
+                           cache->hdr->file_seq != 0)
+                               mail_cache_purge_later(cache, "Invalid header");
                        *corrupted_r = TRUE;
                        return -1;
                }
@@ -617,6 +620,7 @@ void mail_cache_free(struct mail_cache **_cache)
        hash_table_destroy(&cache->field_name_hash);
        pool_unref(&cache->field_pool);
        event_unref(&cache->event);
+       i_free(cache->need_purge_reason);
        i_free(cache->field_file_map);
        i_free(cache->file_field_map);
        i_free(cache->fields);
index 3f6803e60ad0ebb77bc8b5f799da3cf65676869b..0c3abee94ef7c7dba5028cb57bb5ceb6e4b4ba4d 100644 (file)
@@ -66,6 +66,10 @@ mail_cache_register_get_list(struct mail_cache *cache, pool_t pool,
 
 /* Returns TRUE if cache should be purged. */
 bool mail_cache_need_purge(struct mail_cache *cache);
+/* Set cache file to be purged later. */
+void mail_cache_purge_later(struct mail_cache *cache, const char *reason);
+/* Don't try to purge the cache file later after all. */
+void mail_cache_purge_later_reset(struct mail_cache *cache);
 /* Purge cache file. Offsets are updated to given transaction.
    The transaction log must already be exclusively locked.