changeset 22130:39df47bebbe7

lib-index: Add cache to mail_cache_get_missing_reason() This avoids excessive CPU usage when it's called in a loop for many mails.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Mon, 05 Jun 2017 21:53:18 +0300
parents 5d18e2c27efe
children d1ad3d43a3d2
files src/lib-index/mail-cache-lookup.c src/lib-index/mail-cache-private.h
diffstat 2 files changed, 30 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-index/mail-cache-lookup.c	Mon Jun 05 21:44:45 2017 +0300
+++ b/src/lib-index/mail-cache-lookup.c	Mon Jun 05 21:53:18 2017 +0300
@@ -616,14 +616,31 @@
 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 *
--- a/src/lib-index/mail-cache-private.h	Mon Jun 05 21:44:45 2017 +0300
+++ b/src/lib-index/mail-cache-private.h	Mon Jun 05 21:53:18 2017 +0300
@@ -169,6 +169,14 @@
 	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 @@
 	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.