Bug #64715 buf_LRU_free_block() calls page_zip_calc_checksum() unnecessarily.
Submitted: 21 Mar 2012 4:24 Modified: 21 Mar 2012 20:00
Reporter: Nizameddin Ordulu Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: InnoDB Plugin storage engine Severity:S5 (Performance)
Version:5.1.52, 5.1.63 OS:Any
Assigned to: CPU Architecture:Any
Tags: Contribution

[21 Mar 2012 4:24] Nizameddin Ordulu
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
[21 Mar 2012 9:33] Valeriy Kravchuk
Thank you for the problem report and patch contributed. In current mysql-5.1 related code is still the same (just different line numbers).
[21 Mar 2012 20:00] Nizameddin Ordulu
it's not fixed in 5.6 either.