From e2c305f32b39ee4dc9cf003f2e078366ce7a70f3 Mon Sep 17 00:00:00 2001
From: marko <Unknown>
Date: Wed, 15 Nov 2006 21:49:14 +0000
Subject: [PATCH] branches/zip: Improve the shrinking of the buffer pool.

buf_LRU_block_free_non_file_page(): Deallocate block->page_zip.data
to avoid ut_a(!block->page_zip.data) in buf_chunk_free().

buf_chunk_free(): Add the assertion ut_a(!block->in_LRU_list).

buf_pool_resize(): When shrinking the buffer pool and there are
non-free blocks in the candidate chunk, free the clean blocks
and move the dirty blocks to the end of the LRU list and request a flush.
Proceed if the chunk becomes free, and retry otherwise.
---
 buf/buf0buf.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++-----
 buf/buf0lru.c |  8 ++++-
 2 files changed, 80 insertions(+), 9 deletions(-)

diff --git a/buf/buf0buf.c b/buf/buf0buf.c
index 25ad81505e4..cf68b9156c0 100644
--- a/buf/buf0buf.c
+++ b/buf/buf0buf.c
@@ -798,6 +798,7 @@ buf_chunk_free(
 		ut_a(block->state == BUF_BLOCK_NOT_USED);
 		ut_a(!block->page_zip.data);
 
+		ut_a(!block->in_LRU_list);
 		/* Remove the block from the free list. */
 		ut_a(block->in_free_list);
 		UT_LIST_REMOVE(free, buf_pool->free, block);
@@ -904,6 +905,7 @@ buf_pool_resize(void)
 	buf_chunk_t*	chunks;
 	buf_chunk_t*	chunk;
 
+try_again:
 	mutex_enter(&buf_pool->mutex);
 
 	if (srv_buf_pool_old_size == srv_buf_pool_size) {
@@ -919,7 +921,9 @@ buf_pool_resize(void)
 			= (srv_buf_pool_curr_size - srv_buf_pool_size) 
 			/ UNIV_PAGE_SIZE;
 		ulint		max_size;
+		ulint		max_free_size;
 		buf_chunk_t*	max_chunk;
+		buf_chunk_t*	max_free_chunk;
 
 shrink_again:
 		if (buf_pool->n_chunks <= 1) {
@@ -932,25 +936,86 @@ buf_pool_resize(void)
 		not larger than the size difference */
 		chunks = buf_pool->chunks;
 		chunk = chunks + buf_pool->n_chunks;
-		max_size = 0;
-		max_chunk = NULL;
+		max_size = max_free_size = 0;
+		max_chunk = max_free_chunk = NULL;
 
 		while (--chunk >= chunks) {
 			if (chunk->size <= chunk_size
-			    && chunk->size > max_size
-			    && buf_chunk_all_free(chunk)) {
-				max_size = chunk->size;
-				max_chunk = chunk;
+			    && chunk->size > max_free_size) {
+				if (chunk->size > max_size) {
+					max_size = chunk->size;
+					max_chunk = chunk;
+				}
+
+				if (buf_chunk_all_free(chunk)) {
+					max_free_size = chunk->size;
+					max_free_chunk = chunk;
+				}
 			}
 		}
 
-		if (!max_size) {
+		if (!max_free_size) {
+
+			ulint		dirty	= 0;
+			ulint		nonfree	= 0;
+			buf_block_t*	block;
+			buf_block_t*	bend;
 
 			/* Cannot shrink: try again later
 			(do not assign srv_buf_pool_old_size) */
-			goto func_exit;
+			if (!max_chunk) {
+
+				goto func_exit;
+			}
+
+			block = max_chunk->blocks;
+			bend = block + max_chunk->size;
+
+			/* Move the blocks of chunk to the end of the
+			LRU list and try to flush them. */
+			for (; block < bend; block++) {
+				if (block->state != BUF_BLOCK_FILE_PAGE) {
+
+					continue;
+				}
+
+				mutex_enter(&block->mutex);
+
+				if (!buf_flush_ready_for_replace(block)) {
+
+					buf_LRU_make_block_old(block);
+					dirty++;
+				} else if (!buf_LRU_free_block(block)) {
+					nonfree++;
+				}
+
+				mutex_exit(&block->mutex);
+			}
+
+			/* See if the chunk was in fact free. */
+			if (!dirty && !nonfree) {
+
+				goto is_free;
+			}
+
+			mutex_exit(&buf_pool->mutex);
+
+			/* Request for a flush of the chunk. */
+			if (buf_flush_batch(BUF_FLUSH_LRU, dirty,
+					    ut_dulint_zero)
+			    == ULINT_UNDEFINED) {
+
+				buf_flush_wait_batch_end(BUF_FLUSH_LRU);
+			}
+
+			/* Retry after flushing. */
+			goto try_again;
 		}
 
+		max_size = max_free_size;
+		max_chunk = max_free_chunk;
+
+is_free:
 		srv_buf_pool_old_size = srv_buf_pool_size;
 
 		/* Rewrite buf_pool->chunks.  Copy everything but max_chunk. */
diff --git a/buf/buf0lru.c b/buf/buf0lru.c
index 461dd752c3c..a5db248f585 100644
--- a/buf/buf0lru.c
+++ b/buf/buf0lru.c
@@ -868,12 +868,18 @@ buf_LRU_block_free_non_file_page(
 #ifdef UNIV_DEBUG
 	/* Wipe contents of page to reveal possible stale pointers to it */
 	memset(block->frame, '\0', UNIV_PAGE_SIZE);
-	memset(block->page_zip.data, 0xff, block->page_zip.size);
 #else
 	/* Wipe page_no and space_id */
 	memset(block->frame + FIL_PAGE_OFFSET, 0xfe, 4);
 	memset(block->frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xfe, 4);
 #endif
+	if (block->page_zip.data) {
+		/* TODO: return zip to an aligned pool */
+		ut_free(block->page_zip.data);
+		block->page_zip.data = NULL;
+		block->page_zip.size = 0;
+	}
+
 	UT_LIST_ADD_FIRST(free, buf_pool->free, block);
 	block->in_free_list = TRUE;
 
-- 
2.30.9