# name : innodb_fast_checksum.patch # introduced : 11 or before # maintainer : Yasufumi # #!!! notice !!! # Any small change to this file in the main branch # should be done or reviewed by the maintainer! diff -ruN a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c --- a/storage/innobase/buf/buf0buf.c 2010-12-04 15:52:23.391514910 +0900 +++ b/storage/innobase/buf/buf0buf.c 2010-12-04 15:53:45.013513772 +0900 @@ -511,6 +511,27 @@ return(checksum); } +UNIV_INTERN +ulint +buf_calc_page_new_checksum_32( +/*==========================*/ + const byte* page) /*!< in: buffer page */ +{ + ulint checksum; + + checksum = ut_fold_binary(page + FIL_PAGE_OFFSET, + FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET) + + ut_fold_binary(page + FIL_PAGE_DATA, + FIL_PAGE_DATA_ALIGN_32 - FIL_PAGE_DATA) + + ut_fold_binary_32(page + FIL_PAGE_DATA_ALIGN_32, + UNIV_PAGE_SIZE - FIL_PAGE_DATA_ALIGN_32 + - FIL_PAGE_END_LSN_OLD_CHKSUM); + + checksum = checksum & 0xFFFFFFFFUL; + + return(checksum); +} + /********************************************************************//** In versions < 4.0.14 and < 4.1.1 there was a bug that the checksum only looked at the first few bytes of the page. This calculates that old @@ -627,9 +648,21 @@ /* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id (always equal to 0), to FIL_PAGE_SPACE_OR_CHKSUM */ - if (checksum_field != 0 + if (!srv_fast_checksum + && checksum_field != 0 + && checksum_field != BUF_NO_CHECKSUM_MAGIC + && checksum_field + != buf_calc_page_new_checksum(read_buf)) { + + return(TRUE); + } + + if (srv_fast_checksum + && checksum_field != 0 && checksum_field != BUF_NO_CHECKSUM_MAGIC && checksum_field + != buf_calc_page_new_checksum_32(read_buf) + && checksum_field != buf_calc_page_new_checksum(read_buf)) { return(TRUE); @@ -653,6 +686,7 @@ dict_index_t* index; #endif /* !UNIV_HOTBACKUP */ ulint checksum; + ulint checksum_32; ulint old_checksum; ulint size = zip_size; @@ -739,12 +773,14 @@ checksum = srv_use_checksums ? buf_calc_page_new_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC; + checksum_32 = srv_use_checksums + ? buf_calc_page_new_checksum_32(read_buf) : BUF_NO_CHECKSUM_MAGIC; old_checksum = srv_use_checksums ? buf_calc_page_old_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC; ut_print_timestamp(stderr); fprintf(stderr, - " InnoDB: Page checksum %lu, prior-to-4.0.14-form" + " InnoDB: Page checksum %lu (32bit_calc: %lu), prior-to-4.0.14-form" " checksum %lu\n" "InnoDB: stored checksum %lu, prior-to-4.0.14-form" " stored checksum %lu\n" @@ -753,7 +789,7 @@ "InnoDB: Page number (if stored to page already) %lu,\n" "InnoDB: space id (if created with >= MySQL-4.1.1" " and stored already) %lu\n", - (ulong) checksum, (ulong) old_checksum, + (ulong) checksum, (ulong) checksum_32, (ulong) old_checksum, (ulong) mach_read_from_4(read_buf + FIL_PAGE_SPACE_OR_CHKSUM), (ulong) mach_read_from_4(read_buf + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM), diff -ruN a/storage/innobase/buf/buf0flu.c b/storage/innobase/buf/buf0flu.c --- a/storage/innobase/buf/buf0flu.c 2010-12-04 15:37:50.555568346 +0900 +++ b/storage/innobase/buf/buf0flu.c 2010-12-04 15:53:45.015513917 +0900 @@ -1055,7 +1055,9 @@ mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, srv_use_checksums - ? buf_calc_page_new_checksum(page) + ? (!srv_fast_checksum + ? buf_calc_page_new_checksum(page) + : buf_calc_page_new_checksum_32(page)) : BUF_NO_CHECKSUM_MAGIC); /* We overwrite the first 4 bytes of the end lsn field to store diff -ruN a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c --- a/storage/innobase/fil/fil0fil.c 2010-12-04 15:52:23.406513743 +0900 +++ b/storage/innobase/fil/fil0fil.c 2010-12-04 15:53:45.020513800 +0900 @@ -3199,7 +3199,9 @@ mach_write_to_8(page + FIL_PAGE_FILE_FLUSH_LSN, current_lsn); mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, srv_use_checksums - ? buf_calc_page_new_checksum(page) + ? (!srv_fast_checksum + ? buf_calc_page_new_checksum(page) + : buf_calc_page_new_checksum_32(page)) : BUF_NO_CHECKSUM_MAGIC); mach_write_to_4(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, srv_use_checksums @@ -3331,7 +3333,8 @@ page_is_corrupt = TRUE; } - if (checksum_field != 0 + if (!srv_fast_checksum + && checksum_field != 0 && checksum_field != BUF_NO_CHECKSUM_MAGIC && checksum_field != buf_calc_page_new_checksum(page)) { @@ -3339,6 +3342,17 @@ page_is_corrupt = TRUE; } + if (srv_fast_checksum + && checksum_field != 0 + && checksum_field != BUF_NO_CHECKSUM_MAGIC + && checksum_field + != buf_calc_page_new_checksum_32(page) + && checksum_field + != buf_calc_page_new_checksum(page)) { + + page_is_corrupt = TRUE; + } + /* if it is free page, inconsistency is acceptable */ if (!offset) { /* header page*/ @@ -3484,7 +3498,9 @@ mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, srv_use_checksums - ? buf_calc_page_new_checksum(page) + ? (!srv_fast_checksum + ? buf_calc_page_new_checksum(page) + : buf_calc_page_new_checksum_32(page)) : BUF_NO_CHECKSUM_MAGIC); mach_write_to_4(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, srv_use_checksums diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc --- a/storage/innobase/handler/ha_innodb.cc 2010-12-04 15:52:23.420480329 +0900 +++ b/storage/innobase/handler/ha_innodb.cc 2010-12-04 15:53:45.029551892 +0900 @@ -183,6 +183,7 @@ #endif /* UNIV_LOG_ARCHIVE */ static my_bool innobase_use_doublewrite = TRUE; static my_bool innobase_use_checksums = TRUE; +static my_bool innobase_fast_checksum = FALSE; static my_bool innobase_recovery_stats = TRUE; static my_bool innobase_locks_unsafe_for_binlog = FALSE; static my_bool innobase_overwrite_relay_log_info = FALSE; @@ -2593,6 +2594,7 @@ srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite; srv_use_checksums = (ibool) innobase_use_checksums; + srv_fast_checksum = (ibool) innobase_fast_checksum; #ifdef HAVE_LARGE_PAGES if ((os_use_large_pages = (ibool) my_use_large_pages)) @@ -11397,6 +11399,15 @@ "Disable with --skip-innodb-checksums.", NULL, NULL, TRUE); +static MYSQL_SYSVAR_BOOL(fast_checksum, innobase_fast_checksum, + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, + "Change the algorithm of checksum for the whole of datapage to 4-bytes word based. " + "The original checksum is checked after the new one. It may be slow for reading page" + " which has orginal checksum. Overwrite the page or recreate the InnoDB database, " + "if you want the entire benefit for performance at once. " + "#### Attention: The checksum is not compatible for normal or disabled version! ####", + NULL, NULL, FALSE); + static MYSQL_SYSVAR_STR(data_home_dir, innobase_data_home_dir, PLUGIN_VAR_READONLY, "The common part for InnoDB table spaces.", @@ -11903,6 +11914,7 @@ MYSQL_SYSVAR(buffer_pool_size), MYSQL_SYSVAR(buffer_pool_instances), MYSQL_SYSVAR(checksums), + MYSQL_SYSVAR(fast_checksum), MYSQL_SYSVAR(commit_concurrency), MYSQL_SYSVAR(concurrency_tickets), MYSQL_SYSVAR(data_file_path), diff -ruN a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h --- a/storage/innobase/include/buf0buf.h 2010-12-04 15:52:23.458514045 +0900 +++ b/storage/innobase/include/buf0buf.h 2010-12-04 15:53:45.044514150 +0900 @@ -602,6 +602,11 @@ buf_calc_page_new_checksum( /*=======================*/ const byte* page); /*!< in: buffer page */ +UNIV_INTERN +ulint +buf_calc_page_new_checksum_32( +/*==========================*/ + const byte* page); /*!< in: buffer page */ /********************************************************************//** In versions < 4.0.14 and < 4.1.1 there was a bug that the checksum only looked at the first few bytes of the page. This calculates that old diff -ruN a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h --- a/storage/innobase/include/fil0fil.h 2010-12-04 15:52:23.466513796 +0900 +++ b/storage/innobase/include/fil0fil.h 2010-12-04 15:53:45.046513558 +0900 @@ -118,6 +118,7 @@ #define FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID 34 /*!< starting from 4.1.x this contains the space id of the page */ #define FIL_PAGE_DATA 38 /*!< start of the data on the page */ +#define FIL_PAGE_DATA_ALIGN_32 40 /* @} */ /** File page trailer @{ */ #define FIL_PAGE_END_LSN_OLD_CHKSUM 8 /*!< the low 4 bytes of this are used diff -ruN a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h --- a/storage/innobase/include/srv0srv.h 2010-12-04 15:52:23.474482590 +0900 +++ b/storage/innobase/include/srv0srv.h 2010-12-04 15:53:45.048512100 +0900 @@ -227,6 +227,7 @@ extern ibool srv_use_doublewrite_buf; extern ibool srv_use_checksums; +extern ibool srv_fast_checksum; extern ulong srv_max_buf_pool_modified_pct; extern ulong srv_max_purge_lag; diff -ruN a/storage/innobase/include/ut0rnd.h b/storage/innobase/include/ut0rnd.h --- a/storage/innobase/include/ut0rnd.h 2010-11-03 07:01:13.000000000 +0900 +++ b/storage/innobase/include/ut0rnd.h 2010-12-04 15:53:45.049510146 +0900 @@ -124,6 +124,13 @@ const byte* str, /*!< in: string of bytes */ ulint len) /*!< in: length */ __attribute__((pure)); +UNIV_INLINE +ulint +ut_fold_binary_32( +/*==============*/ + const byte* str, /*!< in: string of bytes */ + ulint len) /*!< in: length */ + __attribute__((pure)); /***********************************************************//** Looks for a prime number slightly greater than the given argument. The prime is chosen so that it is not near any power of 2. diff -ruN a/storage/innobase/include/ut0rnd.ic b/storage/innobase/include/ut0rnd.ic --- a/storage/innobase/include/ut0rnd.ic 2010-11-03 07:01:13.000000000 +0900 +++ b/storage/innobase/include/ut0rnd.ic 2010-12-04 15:53:45.050565975 +0900 @@ -226,3 +226,28 @@ return(fold); } + +UNIV_INLINE +ulint +ut_fold_binary_32( +/*==============*/ + const byte* str, /*!< in: string of bytes */ + ulint len) /*!< in: length */ +{ + const ib_uint32_t* str_end = (const ib_uint32_t*) (str + len); + const ib_uint32_t* str_32 = (const ib_uint32_t*) str; + ulint fold = 0; + + ut_ad(str); + /* This function is only for word-aligned data */ + ut_ad(len % 4 == 0); + ut_ad((ulint)str % 4 == 0); + + while (str_32 < str_end) { + fold = ut_fold_ulint_pair(fold, (ulint)(*str_32)); + + str_32++; + } + + return(fold); +} diff -ruN a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c --- a/storage/innobase/srv/srv0srv.c 2010-12-04 15:52:23.498513634 +0900 +++ b/storage/innobase/srv/srv0srv.c 2010-12-04 15:53:45.053550283 +0900 @@ -418,6 +418,7 @@ UNIV_INTERN ibool srv_use_doublewrite_buf = TRUE; UNIV_INTERN ibool srv_use_checksums = TRUE; +UNIV_INTERN ibool srv_fast_checksum = FALSE; UNIV_INTERN ulong srv_replication_delay = 0;