Description:
Inside buf_LRU_free_block() we have the following code:
1559 if (b && (buf_page_get_state(b) == BUF_BLOCK_ZIP_DIRTY)) {
1560 /* Compute and stamp the compressed page
1561 checksum while not holding any mutex. The
1562 block is already half-freed
1563 (BUF_BLOCK_REMOVE_HASH) and removed from
1564 buf_pool->page_hash, thus inaccessible by any
1565 other thread. */
1566
1567 mach_write_to_4(
1568 b->zip.data + FIL_PAGE_SPACE_OR_CHKSUM,
1569 UNIV_LIKELY(srv_use_checksums)
1570 ? page_zip_calc_checksum(
1571 b->zip.data,
1572 page_zip_get_size(&b->zip))
1573 : BUF_NO_CHECKSUM_MAGIC);
1574 }
This code computes the checksum for a compressed page. I believe this is an optimization to not compute the checksum during flush (look at this code from buf_flush_write_block_low():
1007 switch (buf_page_get_state(bpage)) {
1008 case BUF_BLOCK_ZIP_FREE:
1009 case BUF_BLOCK_ZIP_PAGE: /* The page should be dirty. */
1010 case BUF_BLOCK_NOT_USED:
1011 case BUF_BLOCK_READY_FOR_USE:
1012 case BUF_BLOCK_MEMORY:
1013 case BUF_BLOCK_REMOVE_HASH:
1014 ut_error;
1015 break;
1016 case BUF_BLOCK_ZIP_DIRTY:
1017 frame = bpage->zip.data;
1018 if (UNIV_UNLIKELY(srv_use_checksums && srv_extra_checksums)) {
1019 ut_a(mach_read_from_4(frame + FIL_PAGE_SPACE_OR_CHKSUM)
1020 == page_zip_calc_checksum(frame, zip_size));
1021 }
1022 mach_write_ull(frame + FIL_PAGE_LSN,
1023 bpage->newest_modification);
1024 memset(frame + FIL_PAGE_FILE_FLUSH_LSN, 0, 8);
1025 break;
1026 case BUF_BLOCK_FILE_PAGE:
1027 frame = bpage->zip.data;
1028 if (!frame) {
1029 frame = ((buf_block_t*) bpage)->frame;
1030 }
1031
1032 buf_flush_init_for_writing(((buf_block_t*) bpage)->frame,
1033 bpage->zip.data
1034 ? &bpage->zip : NULL,
1035 bpage->newest_modification);
1036 break;
1037 }
) It's wasting cycles because it doesn't need to calculate the checksum if the page is not always dirty.
How to repeat:
Read code.
Suggested fix:
diff --git a/storage/innodb_plugin/buf/buf0lru.c b/storage/innodb_plugin/buf/buf0lru.c
index b5a74b3..831d257 100644
--- a/storage/innodb_plugin/buf/buf0lru.c
+++ b/storage/innodb_plugin/buf/buf0lru.c
@@ -1556,7 +1556,7 @@ alloc:
UNIV_MEM_INVALID(((buf_block_t*) bpage)->frame,
UNIV_PAGE_SIZE);
- if (b) {
+ if (b && (buf_page_get_state(b) == BUF_BLOCK_ZIP_DIRTY)) {
/* Compute and stamp the compressed page
checksum while not holding any mutex. The
block is already half-freed