-
Marko Mäkelä authored
Bug#14774779 CRASH RECOVERY FAILED, UNABLE TO COMPRESS A PAGE Whenever we successfully reorganize or compress a compressed secondary index page, ensure that the IBUF_BITMAP_FREE bits will be updated accordingly. Also, slightly change the definition of IBUF_BITMAP_FREE in compressed pages. Instead of considering the free space on the uncompressed page *after* reorganize, use the *before* value, so that a buffered insert can be merged without reorganizing or even recompressing the page. btr_page_reorganize_low(), btr_page_reorganize(), btr_cur_update_alloc_zip_func(), btr_cur_insert_if_possible(), page_cur_tuple_insert(), page_cur_rec_insert(), page_cur_insert_rec_zip(), page_copy_rec_list_end_to_created_page(), page_copy_rec_list_end_no_locks(), page_copy_rec_list_end(), page_copy_rec_list_start(), page_move_rec_list_end(), page_move_rec_list_start(): Note that the caller should keep IBUF_BITMAP_FREE up to date. btr_page_split_and_insert(): On failure, reset the IBUF_BITMAP_FREE bits on both pages. btr_cur_optimistic_delete_func(): Do not update the IBUF_BITMAP_FREE on compressed pages any more, because according to the updated definition, it will not increase by purging records without reorganizing the page. btr_cur_optimistic_insert(), btr_cur_update_in_place(), btr_cur_optimistic_update(), btr_cur_pessimistic_update(): After a failed attempt to modify a compressed page, reset the IBUF_BITMAP_FREE bits, because we may already have reorganized the page. btr_cur_update_in_place(), btr_cur_optimistic_update(): Implement the flag BTR_KEEP_IBUF_BITMAP for suppressing the IBUF_BITMAP_FREE updates, so that btr_cur_pessimistic_update() can invoke btr_cur_compress_if_useful() without violating the latching order (further pages cannot be latched after latching a change buffer bitmap page). ibuf_index_page_calc_free_zip(): Consider the maximum insert size on the uncompressed page without reorganizing the page, so that ibuf_insert_to_index_page_low() will succeed without reorganizing or recompressing the page. Fix a recovery problem in innodb_log_compressed_pages=OFF and reintroduce the parameter innodb_log_compressed_pages=OFF (ON by default). Also, whenever a page becomes empty, create the page from the scratch. This should hopefully generate less redo log, and it will reduce the cases where we are compressing garbage. This is also necessary in order to avoid an infinite page split with the rest of this patch. page_compression_level: Renamed to page_zip_level. page_log_compressed_pages: Renamed to page_zip_log_pages. innodb_compression_level_update(): Remove. Declare page_zip_level directly with a compatible data type. page_is_empty(): A new predicate, similar to page_is_leaf(), for checking PAGE_N_RECS == 0 without adjusting the endianness. page_has_garbage(): New predicate for checking if PAGE_GARBAGE is nonzero. page_create_empty(): New function, to replace a B-tree page with an empty page. page_create_zip(): Add a parameter for PAGE_MAX_TRX_ID, so that we can recreate a page without zeroing out the field. This field only needs to be nonzero on nonempty secondary index leaf pages. page_cur_insert_rec_zip_reorg(): Remove (merge to the only caller). page_cur_insert_rec_zip(): Take 'cursor' as a parameter. When not in crash recovery (applying redo log), modify the behaviour if there is not enough room in the page modification log (that is, page_zip_available() fails). If the page is logically empty, invoke page_create_zip() to physically empty the page. Otherwise, if the page contains no garbage and no modification log, give up. Otherwise, if innodb_log_compressed_pages=OFF, first do btr_page_reorganize_low() and only then attempt an insert followed by compressing the whole page. If innodb_log_compressed_pages=ON, insert into the uncompressed page only, and then invoke page_zip_reorganize(). In this way, whenever we have to recompress, we will always end up with a reorganized page with 1 or 0 record in the page modification log. page_cur_delete_rec(), page_delete_rec_list_end(), page_delete_rec_list_start(): If the page would become logically empty, invoke page_create_empty() to physically empty it. btr_page_reorganize_low(): Replace the 'block' parameter with 'page_cur', and position the cursor on the same record, so that the caller will avoid the repositioning. Do not write a redo log record unless the operation succeeds. btr_cur_insert_if_possible(): Pass the cursor to btr_page_reorganize(), avoiding the costly page_cur_search() call. btr_cur_optimistic_insert(): After a failed page_cur_tuple_insert(), do not attempt page reorganize on a compressed page. The page_cur_tuple_insert() will already have attempted it, in vain. On uncompressed pages, pass the cursor to btr_page_reorganize() to avoid the page_cur_search() call. btr_cur_update_alloc_zip_func(): Renmed from btr_cur_update_alloc_zip(). Make offsets a debug-only parameter. Replace 'block' with 'cursor'. If there is not enough place, reorganize the page (to get rid of garbage in the PAGE_FREE list) rather than just recompress it. Give up if there is neither garbage in the PAGE_FREE list nor any modification log. btr_cur_update_in_place(): Make 'offsets' non-const, because btr_cur_update_alloc_zip() can now change the rec_offs_validate() information when it is reorganizing the page. NOTE: If we were free to change the redo log format, we could do the following when there is not enough place in the modification log to log an insert or update: * Reorganize the uncompressed page only. * Make the modification on the uncompressed page only. (These would need new redo log entry types.) * Compress the entire page. Redo logged as MLOG_ZIP_PAGE_COMPRESS_NO_DATA. If the compress operation fails, none of the redo log must be written, and we will have to restore the uncompressed page from the compressed page and refuse the operation. rb#1761 approved by Inaam Rana
Marko Mäkelä authoredBug#14774779 CRASH RECOVERY FAILED, UNABLE TO COMPRESS A PAGE Whenever we successfully reorganize or compress a compressed secondary index page, ensure that the IBUF_BITMAP_FREE bits will be updated accordingly. Also, slightly change the definition of IBUF_BITMAP_FREE in compressed pages. Instead of considering the free space on the uncompressed page *after* reorganize, use the *before* value, so that a buffered insert can be merged without reorganizing or even recompressing the page. btr_page_reorganize_low(), btr_page_reorganize(), btr_cur_update_alloc_zip_func(), btr_cur_insert_if_possible(), page_cur_tuple_insert(), page_cur_rec_insert(), page_cur_insert_rec_zip(), page_copy_rec_list_end_to_created_page(), page_copy_rec_list_end_no_locks(), page_copy_rec_list_end(), page_copy_rec_list_start(), page_move_rec_list_end(), page_move_rec_list_start(): Note that the caller should keep IBUF_BITMAP_FREE up to date. btr_page_split_and_insert(): On failure, reset the IBUF_BITMAP_FREE bits on both pages. btr_cur_optimistic_delete_func(): Do not update the IBUF_BITMAP_FREE on compressed pages any more, because according to the updated definition, it will not increase by purging records without reorganizing the page. btr_cur_optimistic_insert(), btr_cur_update_in_place(), btr_cur_optimistic_update(), btr_cur_pessimistic_update(): After a failed attempt to modify a compressed page, reset the IBUF_BITMAP_FREE bits, because we may already have reorganized the page. btr_cur_update_in_place(), btr_cur_optimistic_update(): Implement the flag BTR_KEEP_IBUF_BITMAP for suppressing the IBUF_BITMAP_FREE updates, so that btr_cur_pessimistic_update() can invoke btr_cur_compress_if_useful() without violating the latching order (further pages cannot be latched after latching a change buffer bitmap page). ibuf_index_page_calc_free_zip(): Consider the maximum insert size on the uncompressed page without reorganizing the page, so that ibuf_insert_to_index_page_low() will succeed without reorganizing or recompressing the page. Fix a recovery problem in innodb_log_compressed_pages=OFF and reintroduce the parameter innodb_log_compressed_pages=OFF (ON by default). Also, whenever a page becomes empty, create the page from the scratch. This should hopefully generate less redo log, and it will reduce the cases where we are compressing garbage. This is also necessary in order to avoid an infinite page split with the rest of this patch. page_compression_level: Renamed to page_zip_level. page_log_compressed_pages: Renamed to page_zip_log_pages. innodb_compression_level_update(): Remove. Declare page_zip_level directly with a compatible data type. page_is_empty(): A new predicate, similar to page_is_leaf(), for checking PAGE_N_RECS == 0 without adjusting the endianness. page_has_garbage(): New predicate for checking if PAGE_GARBAGE is nonzero. page_create_empty(): New function, to replace a B-tree page with an empty page. page_create_zip(): Add a parameter for PAGE_MAX_TRX_ID, so that we can recreate a page without zeroing out the field. This field only needs to be nonzero on nonempty secondary index leaf pages. page_cur_insert_rec_zip_reorg(): Remove (merge to the only caller). page_cur_insert_rec_zip(): Take 'cursor' as a parameter. When not in crash recovery (applying redo log), modify the behaviour if there is not enough room in the page modification log (that is, page_zip_available() fails). If the page is logically empty, invoke page_create_zip() to physically empty the page. Otherwise, if the page contains no garbage and no modification log, give up. Otherwise, if innodb_log_compressed_pages=OFF, first do btr_page_reorganize_low() and only then attempt an insert followed by compressing the whole page. If innodb_log_compressed_pages=ON, insert into the uncompressed page only, and then invoke page_zip_reorganize(). In this way, whenever we have to recompress, we will always end up with a reorganized page with 1 or 0 record in the page modification log. page_cur_delete_rec(), page_delete_rec_list_end(), page_delete_rec_list_start(): If the page would become logically empty, invoke page_create_empty() to physically empty it. btr_page_reorganize_low(): Replace the 'block' parameter with 'page_cur', and position the cursor on the same record, so that the caller will avoid the repositioning. Do not write a redo log record unless the operation succeeds. btr_cur_insert_if_possible(): Pass the cursor to btr_page_reorganize(), avoiding the costly page_cur_search() call. btr_cur_optimistic_insert(): After a failed page_cur_tuple_insert(), do not attempt page reorganize on a compressed page. The page_cur_tuple_insert() will already have attempted it, in vain. On uncompressed pages, pass the cursor to btr_page_reorganize() to avoid the page_cur_search() call. btr_cur_update_alloc_zip_func(): Renmed from btr_cur_update_alloc_zip(). Make offsets a debug-only parameter. Replace 'block' with 'cursor'. If there is not enough place, reorganize the page (to get rid of garbage in the PAGE_FREE list) rather than just recompress it. Give up if there is neither garbage in the PAGE_FREE list nor any modification log. btr_cur_update_in_place(): Make 'offsets' non-const, because btr_cur_update_alloc_zip() can now change the rec_offs_validate() information when it is reorganizing the page. NOTE: If we were free to change the redo log format, we could do the following when there is not enough place in the modification log to log an insert or update: * Reorganize the uncompressed page only. * Make the modification on the uncompressed page only. (These would need new redo log entry types.) * Compress the entire page. Redo logged as MLOG_ZIP_PAGE_COMPRESS_NO_DATA. If the compress operation fails, none of the redo log must be written, and we will have to restore the uncompressed page from the compressed page and refuse the operation. rb#1761 approved by Inaam Rana
Loading