From 4dd52e0499459dc2c9cef206dc994a3a00313077 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Mon, 31 Aug 2020 17:25:54 +0300 Subject: [PATCH] lib-index: Remember reason for delayed cache file purges --- src/lib-index/mail-cache-fields.c | 11 ++++++++--- src/lib-index/mail-cache-private.h | 1 + src/lib-index/mail-cache-purge.c | 19 +++++++++++++++++-- src/lib-index/mail-cache.c | 26 +++++++++++++++----------- src/lib-index/mail-cache.h | 4 ++++ 5 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/lib-index/mail-cache-fields.c b/src/lib-index/mail-cache-fields.c index 17f26d64cf..7638eea688 100644 --- a/src/lib-index/mail-cache-fields.c +++ b/src/lib-index/mail-cache-fields.c @@ -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; diff --git a/src/lib-index/mail-cache-private.h b/src/lib-index/mail-cache-private.h index 54d3fb8bfe..8dfc97f59a 100644 --- a/src/lib-index/mail-cache-private.h +++ b/src/lib-index/mail-cache-private.h @@ -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; diff --git a/src/lib-index/mail-cache-purge.c b/src/lib-index/mail-cache-purge.c index f2d1b14a0b..a56e2d842b 100644 --- a/src/lib-index/mail-cache-purge.c +++ b/src/lib-index/mail-cache-purge.c @@ -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); +} diff --git a/src/lib-index/mail-cache.c b/src/lib-index/mail-cache.c index f5422b8f01..9cb4ae60b8 100644 --- a/src/lib-index/mail-cache.c +++ b/src/lib-index/mail-cache.c @@ -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); diff --git a/src/lib-index/mail-cache.h b/src/lib-index/mail-cache.h index 3f6803e60a..0c3abee94e 100644 --- a/src/lib-index/mail-cache.h +++ b/src/lib-index/mail-cache.h @@ -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. -- 2.47.3