summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@oracle.com>2013-08-21 08:22:05 +0300
committerMarko Mäkelä <marko.makela@oracle.com>2013-08-21 08:22:05 +0300
commit6a3bb3c07c9a8c0d9c664bbba688b739368bbb84 (patch)
tree0bac4fefb1967b43a3ea83a405a3b9bdbd279e4e /storage
parent55129f676accff001fcd7b60b049cdd0932442e8 (diff)
downloadmariadb-git-6a3bb3c07c9a8c0d9c664bbba688b739368bbb84.tar.gz
Bug#12560151 61132: infinite loop in buf_page_get_gen() when handling
compressed pages After loading a compressed-only page in buf_page_get_gen() we allocate a new block for decompression. The problem is that the compressed page is neither buffer-fixed nor I/O-fixed by the time we call buf_LRU_get_free_block(), so it may end up being evicted and returned back as a new block. buf_page_get_gen(): Temporarily buffer-fix the compressed-only block while allocating memory for an uncompressed page frame. This should prevent this form of the infinite loop, which is more likely with a small innodb_buffer_pool_size. rb#2511 approved by Jimmy Yang, Sunny Bains
Diffstat (limited to 'storage')
-rw-r--r--storage/innodb_plugin/ChangeLog6
-rw-r--r--storage/innodb_plugin/buf/buf0buf.c43
2 files changed, 22 insertions, 27 deletions
diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog
index 719bb89c865..4c3aa9460f9 100644
--- a/storage/innodb_plugin/ChangeLog
+++ b/storage/innodb_plugin/ChangeLog
@@ -1,3 +1,9 @@
+2013-08-21 The InnoDB Team
+
+ * buf/buf0buf.c:
+ Fix Bug#12560151 61132: infinite loop in buf_page_get_gen()
+ when handling compressed pages
+
2013-08-16 The InnoDB Team
* row/row0sel.c:
diff --git a/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c
index 2d85f389b21..d709a7c89ad 100644
--- a/storage/innodb_plugin/buf/buf0buf.c
+++ b/storage/innodb_plugin/buf/buf0buf.c
@@ -1615,7 +1615,6 @@ loop:
block = (buf_block_t*) buf_page_hash_get(space, offset);
}
-loop2:
if (block == NULL) {
/* Page not in buf_pool: needs to be read from file */
@@ -1706,6 +1705,11 @@ wait_until_unfixed:
goto loop;
}
+ /* Buffer-fix the block so that it cannot be evicted
+ or relocated while we are attempting to allocate an
+ uncompressed page. */
+ bpage->buf_fix_count++;
+
/* Allocate an uncompressed page. */
buf_pool_mutex_exit();
mutex_exit(&buf_pool_zip_mutex);
@@ -1715,32 +1719,19 @@ wait_until_unfixed:
buf_pool_mutex_enter();
mutex_enter(&block->mutex);
+ mutex_enter(&buf_pool_zip_mutex);
+ /* Buffer-fixing prevents the page_hash from changing. */
+ ut_ad(bpage == buf_page_hash_get(space, offset));
- {
- buf_page_t* hash_bpage
- = buf_page_hash_get(space, offset);
-
- if (UNIV_UNLIKELY(bpage != hash_bpage)) {
- /* The buf_pool->page_hash was modified
- while buf_pool_mutex was released.
- Free the block that was allocated. */
-
- buf_LRU_block_free_non_file_page(block);
- mutex_exit(&block->mutex);
-
- block = (buf_block_t*) hash_bpage;
- goto loop2;
- }
- }
-
- if (UNIV_UNLIKELY
- (bpage->buf_fix_count
- || buf_page_get_io_fix(bpage) != BUF_IO_NONE)) {
+ if (--bpage->buf_fix_count
+ || buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
- /* The block was buffer-fixed or I/O-fixed
- while buf_pool_mutex was not held by this thread.
- Free the block that was allocated and try again.
- This should be extremely unlikely. */
+ mutex_exit(&buf_pool_zip_mutex);
+ /* The block was buffer-fixed or I/O-fixed while
+ buf_pool_mutex was not held by this thread.
+ Free the block that was allocated and retry.
+ This should be extremely unlikely, for example,
+ if buf_page_get_zip() was invoked. */
buf_LRU_block_free_non_file_page(block);
mutex_exit(&block->mutex);
@@ -1751,8 +1742,6 @@ wait_until_unfixed:
/* Move the compressed page from bpage to block,
and uncompress it. */
- mutex_enter(&buf_pool_zip_mutex);
-
buf_relocate(bpage, &block->page);
buf_block_init_low(block);
block->lock_hash_val = lock_rec_hash(space, offset);