dovecot-2.2: lib-index: Index cache could have kept too many ind...

dovecot at dovecot.org dovecot at dovecot.org
Thu Jul 3 14:31:39 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/8944983786cc
changeset: 17578:8944983786cc
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Jul 03 17:29:58 2014 +0300
description:
lib-index: Index cache could have kept too many indexes open.
If a lot of indexes were allocated and then later on they were opened and
closed, the alloc-cache simply kept all the indexes open even after they
should have been closed.

diffstat:

 src/lib-index/mail-index-alloc-cache.c |  64 +++++++++++++++++++++++++++------
 src/lib-index/mail-index-alloc-cache.h |   1 +
 src/lib-index/mail-index.c             |   2 +
 3 files changed, 55 insertions(+), 12 deletions(-)

diffs (156 lines):

diff -r 46e47e4082d8 -r 8944983786cc src/lib-index/mail-index-alloc-cache.c
--- a/src/lib-index/mail-index-alloc-cache.c	Thu Jul 03 16:07:09 2014 +0300
+++ b/src/lib-index/mail-index-alloc-cache.c	Thu Jul 03 17:29:58 2014 +0300
@@ -33,6 +33,7 @@
 static MODULE_CONTEXT_DEFINE_INIT(mail_index_alloc_cache_index_module,
 				  &mail_index_module_register);
 static struct mail_index_alloc_cache_list *indexes = NULL;
+static unsigned int indexes_cache_references_count = 0;
 static struct timeout *to_index = NULL;
 
 static struct mail_index_alloc_cache_list *
@@ -57,10 +58,23 @@
 }
 
 static void
+mail_index_alloc_cache_list_unref(struct mail_index_alloc_cache_list *list)
+{
+	i_assert(list->referenced);
+	i_assert(indexes_cache_references_count > 0);
+
+	indexes_cache_references_count--;
+	mail_index_close(list->index);
+	list->referenced = FALSE;
+}
+
+static void
 mail_index_alloc_cache_list_free(struct mail_index_alloc_cache_list *list)
 {
+	i_assert(list->refcount == 0);
+
 	if (list->referenced)
-		mail_index_close(list->index);
+		mail_index_alloc_cache_list_unref(list);
 	mail_index_free(&list->index);
 	i_free(list->mailbox_path);
 	i_free(list);
@@ -153,29 +167,34 @@
 	return match->index;
 }
 
-static void destroy_unrefed(bool all)
+static bool destroy_unrefed(unsigned int min_destroy_count)
 {
 	struct mail_index_alloc_cache_list **list, *rec;
+	bool destroyed = FALSE;
 	bool seen_ref0 = FALSE;
 
 	for (list = &indexes; *list != NULL;) {
 		rec = *list;
 
 		if (rec->refcount == 0 &&
-		    (all || rec->destroy_time <= ioloop_time)) {
+		    (min_destroy_count > 0 || rec->destroy_time <= ioloop_time)) {
 			*list = rec->next;
+			destroyed = TRUE;
 			mail_index_alloc_cache_list_free(rec);
+			if (min_destroy_count > 0)
+				min_destroy_count--;
 		} else {
 			if (rec->refcount == 0)
 				seen_ref0 = TRUE;
-			if (all && rec->index->open_count == 1 &&
+			if (min_destroy_count > 0 &&
+			    rec->index->open_count == 1 &&
 			    rec->referenced) {
 				/* we're the only one keeping this index open.
 				   we might be here, because the caller is
 				   deleting this mailbox and wants its indexes
 				   to be closed. so close it. */
-				rec->referenced = FALSE;
-				mail_index_close(rec->index);
+				destroyed = TRUE;
+				mail_index_alloc_cache_list_unref(rec);
 			}
 			list = &(*list)->next;
 		}
@@ -183,12 +202,13 @@
 
 	if (!seen_ref0 && to_index != NULL)
 		timeout_remove(&to_index);
+	return destroyed;
 }
 
 static void ATTR_NULL(1)
 index_removal_timeout(void *context ATTR_UNUSED)
 {
-	destroy_unrefed(FALSE);
+	destroy_unrefed(0);
 }
 
 void mail_index_alloc_cache_unref(struct mail_index **_index)
@@ -223,7 +243,7 @@
 
 void mail_index_alloc_cache_destroy_unrefed(void)
 {
-	destroy_unrefed(TRUE);
+	destroy_unrefed(UINT_MAX);
 }
 
 void mail_index_alloc_cache_index_opened(struct mail_index *index)
@@ -240,9 +260,29 @@
 			list->index_dir_dev = st.st_dev;
 		}
 	}
-	if (list != NULL && !list->referenced) {
-		/* keep it referenced for ourself */
-		list->referenced = TRUE;
-		index->open_count++;
+}
+
+void mail_index_alloc_cache_index_closing(struct mail_index *index)
+{
+	struct mail_index_alloc_cache_list *list =
+		MAIL_INDEX_ALLOC_CACHE_CONTEXT(index);
+
+	i_assert(index->open_count > 0);
+	if (index->open_count > 1 || list == NULL)
+		return;
+
+	if (list->referenced) {
+		/* we're closing our referenced index */
+		return;
 	}
+	while (indexes_cache_references_count > INDEX_CACHE_MAX) {
+		if (!destroy_unrefed(1)) {
+			/* our cache is full already, don't keep more */
+			return;
+		}
+	}
+	/* keep the index referenced for caching */
+	indexes_cache_references_count++;
+	list->referenced = TRUE;
+	index->open_count++;
 }
diff -r 46e47e4082d8 -r 8944983786cc src/lib-index/mail-index-alloc-cache.h
--- a/src/lib-index/mail-index-alloc-cache.h	Thu Jul 03 16:07:09 2014 +0300
+++ b/src/lib-index/mail-index-alloc-cache.h	Thu Jul 03 17:29:58 2014 +0300
@@ -11,5 +11,6 @@
 
 /* internal: */
 void mail_index_alloc_cache_index_opened(struct mail_index *index);
+void mail_index_alloc_cache_index_closing(struct mail_index *index);
 
 #endif
diff -r 46e47e4082d8 -r 8944983786cc src/lib-index/mail-index.c
--- a/src/lib-index/mail-index.c	Thu Jul 03 16:07:09 2014 +0300
+++ b/src/lib-index/mail-index.c	Thu Jul 03 17:29:58 2014 +0300
@@ -631,6 +631,8 @@
 void mail_index_close(struct mail_index *index)
 {
 	i_assert(index->open_count > 0);
+
+	mail_index_alloc_cache_index_closing(index);
 	if (--index->open_count > 0)
 		return;
 


More information about the dovecot-cvs mailing list