From 9c663a0c461e8518fadc697d9021135e5b668f2d Mon Sep 17 00:00:00 2001
From: marko <Unknown>
Date: Fri, 16 Feb 2007 09:22:50 +0000
Subject: [PATCH] branches/zip: buf_LRU_search_and_free_block(): Avoid freeing
 compressed-only pages when they do not occupy too much of the buffer pool.

buf0buddy.c, buf0buddy.h: Export buf_buddy_n_frames and buf_buddy_min_n_frames.
---
 buf/buf0buddy.c     | 15 +++++---
 buf/buf0lru.c       | 90 ++++++++++++++++++++++++++++++++++++++-------
 include/buf0buddy.h |  9 +++++
 3 files changed, 94 insertions(+), 20 deletions(-)

diff --git a/buf/buf0buddy.c b/buf/buf0buddy.c
index 69c344a52f8..efe55af8ff9 100644
--- a/buf/buf0buddy.c
+++ b/buf/buf0buddy.c
@@ -17,20 +17,23 @@ Created December 2006 by Marko Makela
 #include "buf0flu.h"
 #include "page0zip.h"
 
-/* Statistic counters, protected by buf_pool->mutex */
+/* Statistic counters */
 
-/** Number of frames allocated from the buffer pool to the buddy system */
-static ulint buf_buddy_n_frames;
-/** Counts of blocks allocated from the buddy system */
+/** Number of frames allocated from the buffer pool to the buddy system.
+Protected by buf_pool->mutex. */
+ulint buf_buddy_n_frames;
+/** Counts of blocks allocated from the buddy system.
+Protected by buf_pool->mutex. */
 static ulint buf_buddy_used[BUF_BUDDY_SIZES + 1];
-/** Counts of blocks relocated by the buddy system */
+/** Counts of blocks relocated by the buddy system.
+Protected by buf_pool->mutex. */
 static ib_uint64_t buf_buddy_relocated[BUF_BUDDY_SIZES + 1];
 
 /** Preferred minimum number of frames allocated from the buffer pool
 to the buddy system.  When this number is exceeded, the buddy allocator
 will not try to free clean compressed-only pages in order to satisfy
 an allocation request.  Protected by buf_pool->mutex. */
-static ulint buf_buddy_min_n_frames = ULINT_UNDEFINED;
+ulint buf_buddy_min_n_frames = ULINT_UNDEFINED;
 
 /**************************************************************************
 Get the offset of the buddy of a compressed page frame. */
diff --git a/buf/buf0lru.c b/buf/buf0lru.c
index b4967da257b..ba4918fede0 100644
--- a/buf/buf0lru.c
+++ b/buf/buf0lru.c
@@ -264,7 +264,6 @@ buf_LRU_search_and_free_block(
 				of the LRU list */
 {
 	buf_page_t*	bpage;
-	ulint		distance = 0;
 	ibool		freed;
 
 	mutex_enter(&(buf_pool->mutex));
@@ -272,25 +271,88 @@ buf_LRU_search_and_free_block(
 	freed = FALSE;
 	bpage = UT_LIST_GET_LAST(buf_pool->LRU);
 
-	while (bpage != NULL) {
-		mutex_t*	block_mutex = buf_page_get_mutex(bpage);
+	if (UNIV_UNLIKELY(n_iterations > 10)) {
+		/* The buffer pool is scarce.  Search the whole
+		LRU list, and also free any compressed pages. */
+
+		while (bpage != NULL) {
+			mutex_t*	block_mutex
+				= buf_page_get_mutex(bpage);
+
+			mutex_enter(block_mutex);
+			/* Discard also the compressed page. */
+			freed = buf_LRU_free_block(bpage, TRUE);
+			if (!freed && bpage->zip.data) {
+				/* Could not free the compressed page;
+				try freeing the uncompressed page then. */
+				freed = buf_LRU_free_block(bpage, FALSE);
+			}
+			mutex_exit(block_mutex);
 
-		mutex_enter(block_mutex);
-		freed = buf_LRU_free_block(bpage, n_iterations > 10);
-		mutex_exit(block_mutex);
+			if (freed) {
+
+				break;
+			}
+
+			bpage = UT_LIST_GET_PREV(LRU, bpage);
+		}
+	} else if (buf_buddy_n_frames > buf_buddy_min_n_frames) {
+		/* There are enough compressed blocks.  Free the
+		least recently used block, whether or not it
+		comprises an uncompressed page. */
 
-		if (freed) {
+		ulint	distance = 100
+			+ (n_iterations * buf_pool->curr_size) / 10;
 
-			break;
+		while (bpage != NULL) {
+			mutex_t*	block_mutex
+				= buf_page_get_mutex(bpage);
+
+			mutex_enter(block_mutex);
+			/* Preserve any compressed page. */
+			freed = buf_LRU_free_block(bpage, FALSE);
+			mutex_exit(block_mutex);
+
+			if (freed) {
+
+				break;
+			}
+
+			bpage = UT_LIST_GET_PREV(LRU, bpage);
+
+			if (!--distance) {
+				goto func_exit;
+			}
 		}
+	} else {
+		/* There are few compressed blocks.  Skip compressed-only
+		blocks in the search for the least recently used block
+		that can be freed.  Preserve any compressed page. */
+
+		ulint	distance = 100
+			+ (n_iterations * buf_pool->curr_size) / 10;
 
-		bpage = UT_LIST_GET_PREV(LRU, bpage);
-		distance++;
+		while (bpage != NULL) {
+			if (buf_page_get_state(bpage)
+			    == BUF_BLOCK_FILE_PAGE) {
 
-		if (n_iterations <= 10
-		    && distance > 100 + (n_iterations * buf_pool->curr_size)
-		    / 10) {
-			goto func_exit;
+				buf_block_t*	block = (buf_block_t*) bpage;
+				mutex_enter(&block->mutex);
+				/* Preserve any compressed page. */
+				freed = buf_LRU_free_block(bpage, FALSE);
+				mutex_exit(&block->mutex);
+
+				if (freed) {
+
+					break;
+				}
+			}
+
+			bpage = UT_LIST_GET_PREV(LRU, bpage);
+
+			if (!--distance) {
+				goto func_exit;
+			}
 		}
 	}
 
diff --git a/include/buf0buddy.h b/include/buf0buddy.h
index 5bd2dbc779f..2e8cc694558 100644
--- a/include/buf0buddy.h
+++ b/include/buf0buddy.h
@@ -46,6 +46,15 @@ buf_buddy_free(
 	ulint	size)	/* in: block size, up to UNIV_PAGE_SIZE */
 	__attribute__((nonnull));
 
+/** Number of frames allocated from the buffer pool to the buddy system.
+Protected by buf_pool->mutex. */
+extern ulint buf_buddy_n_frames;
+/** Preferred minimum number of frames allocated from the buffer pool
+to the buddy system.  When this number is exceeded, the buddy allocator
+will not try to free clean compressed-only pages in order to satisfy
+an allocation request.  Protected by buf_pool->mutex. */
+extern ulint buf_buddy_min_n_frames;
+
 #ifndef UNIV_NONINL
 # include "buf0buddy.ic"
 #endif
-- 
2.30.9