diff options
author | Marko Mäkelä <marko.makela@oracle.com> | 2013-08-21 08:22:05 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@oracle.com> | 2013-08-21 08:22:05 +0300 |
commit | 6a3bb3c07c9a8c0d9c664bbba688b739368bbb84 (patch) | |
tree | 0bac4fefb1967b43a3ea83a405a3b9bdbd279e4e /storage | |
parent | 55129f676accff001fcd7b60b049cdd0932442e8 (diff) | |
download | mariadb-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/ChangeLog | 6 | ||||
-rw-r--r-- | storage/innodb_plugin/buf/buf0buf.c | 43 |
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); |