List:Commits« Previous MessageNext Message »
From:vasil.dimov Date:August 22 2011 7:50am
Subject:bzr commit into mysql-trunk branch (vasil.dimov:3396) WL#5652
View as plain text  
#At file:///usr/local/devel/bzrroot/server/wl5652-crc32/ based on revid:andrei.elkin@stripped

 3396 Vasil Dimov	2011-08-22
      Implement WL#5652 InnoDB: Use HW CRC32
      
      + Introduce a new option innodb_checksum_algorithm that may have the
      following values:
      
      * crc32
      Write CRC32 to both checksum fields (calculated using CPU instructions
      if supported).
      When reading allow any of the valid checksums to match (flexible
      allowing old files to be read, but increases the possibility for
      announcing a corrupted page to be valid). Still if one of the two fields
      contains CRC32, the other one must contain CRC32 too.
      
      * strict_crc32
      Write CRC32 to both checksum fields
      When reading allow only CRC32 to match (will announce old files as
      corrupted, but minimizes the possibility to announce a corrupted page
      as valid).
      
      * innodb
      Write InnoDB calculated (custom algorithm) checksum to both checksum
      fields (different algo is used for each field).
      When reading allow any of the valid checksums to match.
      
      * strict_innodb
      Write InnoDB calculated (custom algorithm) checksum to both checksum
      fields (different algo is used for each field).
      When reading allow only InnoDB algorithm to match.
      
      * none
      Write a constant magic number to both fields
      When reading do not do any checks on the checksum fields
      (same as setting innodb_checksums=OFF)
      
      * strict_none
      Write a constant magic number to both fields
      When reading allow only the constant magic number to match.
      
      + Deprecate innodb_checksums (use innodb_checksum_algorithm=NONE instead)
      
      + Remove copy-pasted InnoDB source from extra/innochecksum.c and link
      the innochecksum executable with libinnobase.a
      
      + For the above to work extract the functions innochecksum needs in a
      dedicated files
      
      + Add the Facebook contributed CRC32 implementation into ut0crc32.c

    added:
      mysql-test/suite/sys_vars/r/innodb_checksum_algorithm_basic.result
      mysql-test/suite/sys_vars/t/innodb_checksum_algorithm_basic.test
      storage/innobase/buf/buf0checksum.c
      storage/innobase/include/buf0checksum.h
      storage/innobase/include/ut0crc32.h
      storage/innobase/ut/ut0crc32.c
    modified:
      extra/CMakeLists.txt
      extra/innochecksum.c
      storage/innobase/CMakeLists.txt
      storage/innobase/buf/buf0buf.c
      storage/innobase/buf/buf0flu.c
      storage/innobase/buf/buf0lru.c
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/include/buf0buf.h
      storage/innobase/include/page0zip.h
      storage/innobase/include/srv0srv.h
      storage/innobase/include/univ.i
      storage/innobase/page/page0zip.c
      storage/innobase/srv/srv0srv.c
=== modified file 'extra/CMakeLists.txt'
--- a/extra/CMakeLists.txt	revid:andrei.elkin@stripped
+++ b/extra/CMakeLists.txt	revid:vasil.dimov@stripped
@@ -70,7 +70,16 @@ ENDIF()
 MYSQL_ADD_EXECUTABLE(replace replace.c)
 TARGET_LINK_LIBRARIES(replace mysys)
 IF(UNIX)
-  MYSQL_ADD_EXECUTABLE(innochecksum innochecksum.c)
+  IF(WITH_INNOBASE_STORAGE_ENGINE)
+    # Add path to the InnoDB headers
+    INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/innobase/include)
+    MYSQL_ADD_EXECUTABLE(innochecksum innochecksum.c)
+    IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+      ADD_DEFINITIONS("-DINNOCHECKSUM_SOLARIS")
+    ELSE()
+      TARGET_LINK_LIBRARIES(innochecksum innobase)
+    ENDIF()
+  ENDIF()
 
   MYSQL_ADD_EXECUTABLE(resolve_stack_dump resolve_stack_dump.c)
   TARGET_LINK_LIBRARIES(resolve_stack_dump mysys)

=== modified file 'extra/innochecksum.c'
--- a/extra/innochecksum.c	revid:andrei.elkin@stripped
+++ b/extra/innochecksum.c	revid:vasil.dimov@stripped
@@ -25,127 +25,733 @@
   Published with a permission.
 */
 
-/* needed to have access to 64 bit file functions */
-#define _LARGEFILE_SOURCE
-#define _LARGEFILE64_SOURCE
+#ifndef INNOCHECKSUM_SOLARIS
 
-#define _XOPEN_SOURCE 500 /* needed to include getopt.h on some platforms. */
+/* On non-Solaris we can link with libinnobase.a and the linker does not
+complain about undefined symbols in libinnobase.a (the ones that are defined
+in mysql code). */
+
+#include "univ.i"
+#include "buf0checksum.h" /* buf_calc_page_*() */
+#include "fil0fil.h" /* FIL_* */
+#include "mach0data.h" /* mach_read_from_4() */
+#include "ut0crc32.h" /* ut_crc32_init() */
 
+#else /* INNOCHECKSUM_SOLARIS */
+
+/* Unfortunately on Solaris the linker seems to be too picky, requiring all
+symbols to be defined. Using "-z nodefs" and the innochecksum binary gets
+compiled but it cannot be executed later. */
+
+#include <assert.h>
 #include <stdio.h>
-#include <stdlib.h>
 #include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
 
-/* all of these ripped from InnoDB code from MySQL 4.0.22 */
-#define UT_HASH_RANDOM_MASK     1463735687
-#define UT_HASH_RANDOM_MASK2    1653893711
-#define FIL_PAGE_LSN          16 
-#define FIL_PAGE_FILE_FLUSH_LSN 26
-#define FIL_PAGE_OFFSET     4
-#define FIL_PAGE_DATA       38
-#define FIL_PAGE_END_LSN_OLD_CHKSUM 8
-#define FIL_PAGE_SPACE_OR_CHKSUM 0
-#define UNIV_PAGE_SIZE          (2 * 8192)
+#define ut_a		assert
+#define ut_ad		assert
+#define ut_error	assert(0)
+
+/* univ.i { */
+# ifndef __WIN__
+#  ifndef UNIV_HOTBACKUP
+#   include "config.h"
+#  endif /* UNIV_HOTBACKUP */
+# endif
+
+#if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(sun) || defined(__INTEL_COMPILER)
+# define UNIV_INTERN __attribute__((visibility ("hidden")))
+#else
+# define UNIV_INTERN
+#endif
+
+#ifdef __WIN__
+# define UNIV_INLINE	__inline
+#elif defined(__SUNPRO_CC) || defined(__SUNPRO_C)
+# define UNIV_INLINE static inline
+#else
+# define UNIV_INLINE static __inline__
+#endif
+
+/** The 2-logarithm of UNIV_PAGE_SIZE: */
+#define UNIV_PAGE_SIZE_SHIFT	14
+
+/** The universal page size of the database */
+#define UNIV_PAGE_SIZE		(1 << UNIV_PAGE_SIZE_SHIFT)
+
+/* Note that inside MySQL 'byte' is defined as char on Linux! */
+#define byte			unsigned char
+
+/* Define an unsigned integer type that is exactly 32 bits. */
+
+#if SIZEOF_INT == 4
+typedef unsigned int		ib_uint32_t;
+#define UINT32PF		"%u"
+#elif SIZEOF_LONG == 4
+typedef unsigned long		ib_uint32_t;
+#define UINT32PF		"%lu"
+#else
+#error "Neither int or long is 4 bytes"
+#endif
+
+/* Another basic type we use is unsigned long integer which should be equal to
+the word size of the machine, that is on a 32-bit platform 32 bits, and on a
+64-bit platform 64 bits. We also give the printf format for the type as a
+macro ULINTPF. */
+
+#ifdef _WIN64
+typedef unsigned __int64	ulint;
+#define ULINTPF			"%I64u"
+typedef __int64			lint;
+#else
+typedef unsigned long int	ulint;
+#define ULINTPF			"%lu"
+typedef long int		lint;
+#endif
+
+#ifdef __WIN__
+typedef __int64			ib_int64_t;
+typedef unsigned __int64	ib_uint64_t;
+#elif !defined(UNIV_HOTBACKUP)
+/** Note: longlong and ulonglong come from MySQL headers. */
+typedef long long		ib_int64_t;
+typedef unsigned long long	ib_uint64_t;
+#endif
+
+/** This 'ibool' type is used within Innobase. Remember that different included
+headers may define 'bool' differently. Do not assume that 'bool' is a ulint! */
+#define ibool			ulint
+
+#ifndef TRUE
+
+#define TRUE    1
+#define FALSE   0
+
+#endif
+/* } univ.i */
+
+/* fil0fil.h { */
+#define FIL_PAGE_SPACE_OR_CHKSUM 0	/*!< in < MySQL-4.0.14 space id the
+					page belongs to (== 0) but in later
+					versions the 'new' checksum of the
+					page */
+#define FIL_PAGE_OFFSET		4	/*!< page offset inside space */
+#define FIL_PAGE_LSN		16	/*!< lsn of the end of the newest
+					modification log record to the page */
+#define FIL_PAGE_FILE_FLUSH_LSN	26	/*!< this is only defined for the
+					first page in a system tablespace
+					data file (ibdata*, not *.ibd):
+					the file has been flushed to disk
+					at least up to this lsn */
+#define FIL_PAGE_DATA		38	/*!< start of the data on the page */
+#define FIL_PAGE_END_LSN_OLD_CHKSUM 8	/*!< the low 4 bytes of this are used
+					to store the page checksum, the
+					last 4 bytes should be identical
+					to the last 4 bytes of FIL_PAGE_LSN */
+/* } fil0fil.h */
+
+/* mach0data.ic { */
+/********************************************************//**
+The following function is used to fetch data from 4 consecutive
+bytes. The most significant byte is at the lowest address.
+@return	ulint integer */
+UNIV_INLINE
+ulint
+mach_read_from_4(
+/*=============*/
+	const byte*	b)	/*!< in: pointer to four bytes */
+{
+	ut_ad(b);
+	return( ((ulint)(b[0]) << 24)
+		| ((ulint)(b[1]) << 16)
+		| ((ulint)(b[2]) << 8)
+		| (ulint)(b[3])
+		);
+}
+/* } mach0data.ic */
 
-/* command line argument to do page checks (that's it) */
-/* another argument to specify page ranges... seek to right spot and go from there */
+/* ut0ut.c { */
+/**********************************************************//**
+Prints a timestamp to a file. */
+UNIV_INTERN
+void
+ut_print_timestamp(
+/*===============*/
+	FILE*  file) /*!< in: file where to print */
+{
+#ifdef __WIN__
+	SYSTEMTIME cal_tm;
+
+	GetLocalTime(&cal_tm);
+
+	fprintf(file,"%02d%02d%02d %2d:%02d:%02d",
+		(int)cal_tm.wYear % 100,
+		(int)cal_tm.wMonth,
+		(int)cal_tm.wDay,
+		(int)cal_tm.wHour,
+		(int)cal_tm.wMinute,
+		(int)cal_tm.wSecond);
+#else
+	struct tm* cal_tm_ptr;
+	time_t	   tm;
+
+#ifdef HAVE_LOCALTIME_R
+	struct tm  cal_tm;
+	time(&tm);
+	localtime_r(&tm, &cal_tm);
+	cal_tm_ptr = &cal_tm;
+#else
+	time(&tm);
+	cal_tm_ptr = localtime(&tm);
+#endif
+	fprintf(file,"%02d%02d%02d %2d:%02d:%02d",
+		cal_tm_ptr->tm_year % 100,
+		cal_tm_ptr->tm_mon + 1,
+		cal_tm_ptr->tm_mday,
+		cal_tm_ptr->tm_hour,
+		cal_tm_ptr->tm_min,
+		cal_tm_ptr->tm_sec);
+#endif
+}
+/* } ut0ut.c */
+
+/* ut0crc32.h { */
+/********************************************************************//**
+Calculates CRC32.
+@return CRC32 (CRC-32C, using the GF(2) primitive polynomial 0x11EDC6F41,
+or 0x1EDC6F41 without the high-order bit) */
+UNIV_INTERN
+ib_uint32_t
+(*ut_crc32)(
+/*========*/
+	const byte*	buf,	/*!< in: data over which to calculate CRC32 */
+	ulint		len);	/*!< in: data length */
+/* } ut0crc32.h */
+
+/* ut0crc32.c { */
+/*****************************************************************************
+
+Copyright (C) 2009, 2010 Facebook, Inc. All Rights Reserved.
+Copyright (c) 2011, 2011, Oracle and/or its affiliates. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
+
+*****************************************************************************/
+
+/***************************************************************//**
+@file ut/ut0crc32.c
+CRC32 implementation from Facebook, based on the zlib implementation.
+
+Created Aug 8, 2011, Vasil Dimov, based on mysys/my_crc32.c and
+mysys/my_perf.c, contributed by Facebook under the following license.
+********************************************************************/
+
+/* Copyright (C) 2009-2010 Facebook, Inc.  All Rights Reserved.
+
+   Dual licensed under BSD license and GPLv2.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+   1. Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY FACEBOOK, INC. ``AS IS'' AND ANY EXPRESS OR
+   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
+   EVENT SHALL FACEBOOK, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+   OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the Free
+   Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+
+   You should have received a copy of the GNU General Public License along with
+   this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+   Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/* The below CRC32 implementation is based on the implementation included with
+ * zlib with modifications to process 8 bytes at a time and using SSE 4.2
+ * extentions when available.  The polynomial constant has been changed to
+ * match the one used by SSE 4.2 and does not return the same value as the
+ * version used by zlib.  This implementation only supports 64-bit
+ * little-endian processors.  The original zlib copyright notice follows. */
+
+/* crc32.c -- compute the CRC-32 of a buf stream
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@stripped> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of buf at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors.  This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+#include <string.h> /* memcmp() */
+
+/* Precalculated table used to generate the CRC32 if the CPU does not
+have support for it */
+static ib_uint32_t	ut_crc32_slice8_table[8][256];
+static ibool		ut_crc32_slice8_table_initialized = FALSE;
+
+/* Flag that tells whether the CPU supports CRC32 or not */
+static ibool		ut_crc32_sse2_enabled = FALSE;
+
+/********************************************************************//**
+Initializes the table that is used to generate the CRC32 if the CPU does
+not have support for it. */
+static
+void
+ut_crc32_slice8_table_init()
+/*========================*/
+{
+	/* bit-reversed poly 0x1EDC6F41 (from SSE42 crc32 instruction) */
+	static const ib_uint32_t	poly = 0x82f63b78;
+	ib_uint32_t			n;
+	ib_uint32_t			k;
+	ib_uint32_t			c;
+
+	for (n = 0; n < 256; n++) {
+		c = n;
+		for (k = 0; k < 8; k++) {
+			c = (c & 1) ? (poly ^ (c >> 1)) : (c >> 1);
+		}
+		ut_crc32_slice8_table[0][n] = c;
+	}
+
+	for (n = 0; n < 256; n++) {
+		c = ut_crc32_slice8_table[0][n];
+		for (k = 1; k < 8; k++) {
+			c = ut_crc32_slice8_table[0][c & 0xFF] ^ (c >> 8);
+			ut_crc32_slice8_table[k][n] = c;
+		}
+	}
+
+	ut_crc32_slice8_table_initialized = TRUE;
+}
+
+#if defined(__GNUC__) && defined(__x86_64__)
+/********************************************************************//**
+Fetches CPU info */
+static
+void
+ut_cpuid(
+/*=====*/
+	ib_uint32_t	vend[3],	/*!< out: CPU vendor */
+	ib_uint32_t*	model,		/*!< out: CPU model */
+	ib_uint32_t*	family,		/*!< out: CPU family */
+	ib_uint32_t*	stepping,	/*!< out: CPU stepping */
+	ib_uint32_t*	features_ecx,	/*!< out: CPU features ecx */
+	ib_uint32_t*	features_edx)	/*!< out: CPU features edx */
+{
+	ib_uint32_t	sig;
+	asm("cpuid" : "=b" (vend[0]), "=c" (vend[2]), "=d" (vend[1]) : "a" (0));
+	asm("cpuid" : "=a" (sig), "=c" (*features_ecx), "=d" (*features_edx)
+	    : "a" (1)
+	    : "ebx");
+
+	*model = ((sig >> 4) & 0xF);
+	*family = ((sig >> 8) & 0xF);
+	*stepping = (sig & 0xF);
+
+	if (memcmp(vend, "GenuineIntel", 12) == 0 ||
+	    (memcmp(vend, "AuthenticAMD", 12) == 0 && *family == 0xF)) {
+
+		*model += (((sig >> 16) & 0xF) << 4);
+		*family += ((sig >> 20) & 0xFF);
+	}
+}
+
+/* opcodes taken from objdump of "crc32b (%%rdx), %%rcx"
+for RHEL4 support (GCC 3 doesn't support this instruction) */
+#define ut_crc32_sse42_byte \
+	asm(".byte 0xf2, 0x48, 0x0f, 0x38, 0xf0, 0x0a" \
+	    : "=c"(crc) : "c"(crc), "d"(buf)); \
+	len--, buf++
+
+/* opcodes taken from objdump of "crc32q (%%rdx), %%rcx"
+for RHEL4 support (GCC 3 doesn't support this instruction) */
+#define ut_crc32_sse42_quadword \
+	asm(".byte 0xf2, 0x48, 0x0f, 0x38, 0xf1, 0x0a" \
+	    : "=c"(crc) : "c"(crc), "d"(buf)); \
+	len -= 8, buf += 8
+#endif /* defined(__GNUC__) && defined(__x86_64__) */
+
+/********************************************************************//**
+Calculates CRC32 using CPU instructions.
+@return CRC-32C (polynomial 0x11EDC6F41) */
+UNIV_INLINE
+ib_uint32_t
+ut_crc32_sse42(
+/*===========*/
+	const byte*	buf,	/*!< in: data over which to calculate CRC32 */
+	ulint		len)	/*!< in: data length */
+{
+#if defined(__GNUC__) && defined(__x86_64__)
+	ib_uint64_t	crc = (ib_uint32_t) (-1);
+
+	ut_a(ut_crc32_sse2_enabled);
+
+	while (len && ((ulint) buf & 7)) {
+		ut_crc32_sse42_byte;
+	}
+
+	while (len >= 32) {
+		ut_crc32_sse42_quadword;
+		ut_crc32_sse42_quadword;
+		ut_crc32_sse42_quadword;
+		ut_crc32_sse42_quadword;
+	}
+
+	while (len >= 8) {
+		ut_crc32_sse42_quadword;
+	}
+
+	while (len) {
+		ut_crc32_sse42_byte;
+	}
+
+	return((ib_uint32_t) ((~crc) & 0xFFFFFFFF));
+#else
+	ut_error;
+	/* silence compiler warning about unused parameters */
+	return((ib_uint32_t) buf[len]);
+#endif /* defined(__GNUC__) && defined(__x86_64__) */
+}
+
+#define ut_crc32_slice8_byte \
+	crc = (crc >> 8) ^ ut_crc32_slice8_table[0][(crc ^ *buf++) & 0xFF]; \
+	len--
+
+#define ut_crc32_slice8_quadword \
+	crc ^= *(ib_uint64_t*) buf; \
+	crc = ut_crc32_slice8_table[7][(crc      ) & 0xFF] ^ \
+	      ut_crc32_slice8_table[6][(crc >>  8) & 0xFF] ^ \
+	      ut_crc32_slice8_table[5][(crc >> 16) & 0xFF] ^ \
+	      ut_crc32_slice8_table[4][(crc >> 24) & 0xFF] ^ \
+	      ut_crc32_slice8_table[3][(crc >> 32) & 0xFF] ^ \
+	      ut_crc32_slice8_table[2][(crc >> 40) & 0xFF] ^ \
+	      ut_crc32_slice8_table[1][(crc >> 48) & 0xFF] ^ \
+	      ut_crc32_slice8_table[0][(crc >> 56)]; \
+	len -= 8, buf += 8
+
+/********************************************************************//**
+Calculates CRC32 manually.
+@return CRC-32C (polynomial 0x11EDC6F41) */
+UNIV_INLINE
+ib_uint32_t
+ut_crc32_slice8(
+/*============*/
+	const byte*	buf,	/*!< in: data over which to calculate CRC32 */
+	ulint		len)	/*!< in: data length */
+{
+	ib_uint64_t	crc = (ib_uint32_t) (-1);
 
-typedef unsigned long int ulint;
-typedef unsigned char uchar;
+	ut_a(ut_crc32_slice8_table_initialized);
 
-/* innodb function in name; modified slightly to not have the ASM version (lots of #ifs that didn't apply) */
-ulint mach_read_from_4(uchar *b)
+	while (len && ((ulint) buf & 7)) {
+		ut_crc32_slice8_byte;
+	}
+
+	while (len >= 32) {
+		ut_crc32_slice8_quadword;
+		ut_crc32_slice8_quadword;
+		ut_crc32_slice8_quadword;
+		ut_crc32_slice8_quadword;
+	}
+
+	while (len >= 8) {
+		ut_crc32_slice8_quadword;
+	}
+
+	while (len) {
+		ut_crc32_slice8_byte;
+	}
+
+	return((ib_uint32_t) ((~crc) & 0xFFFFFFFF));
+}
+
+/********************************************************************//**
+Initializes the data structures used by ut_crc32(). Does not do any
+allocations, would not hurt if called twice, but would be pointless. */
+UNIV_INTERN
+void
+ut_crc32_init()
+/*===========*/
 {
-  return( ((ulint)(b[0]) << 24)
-          + ((ulint)(b[1]) << 16)
-          + ((ulint)(b[2]) << 8)
-          + (ulint)(b[3])
-          );
+#if defined(__GNUC__) && defined(__x86_64__)
+	ib_uint32_t	vend[3];
+	ib_uint32_t	model;
+	ib_uint32_t	family;
+	ib_uint32_t	stepping;
+	ib_uint32_t	features_ecx;
+	ib_uint32_t	features_edx;
+
+	ut_cpuid(vend, &model, &family, &stepping,
+		 &features_ecx, &features_edx);
+
+	/* Valgrind does not understand the CRC32 instructions:
+
+	vex amd64->IR: unhandled instruction bytes: 0xF2 0x48 0xF 0x38 0xF0 0xA
+	valgrind: Unrecognised instruction at address 0xad3db5.
+	Your program just tried to execute an instruction that Valgrind
+	did not recognise.  There are two possible reasons for this.
+	1. Your program has a bug and erroneously jumped to a non-code
+	   location.  If you are running Memcheck and you just saw a
+	   warning about a bad jump, it's probably your program's fault.
+	2. The instruction is legitimate but Valgrind doesn't handle it,
+	   i.e. it's Valgrind's fault.  If you think this is the case or
+	   you are not sure, please let us know and we'll try to fix it.
+	Either way, Valgrind will now raise a SIGILL signal which will
+	probably kill your program.
+
+	*/
+#ifndef UNIV_DEBUG_VALGRIND
+	ut_crc32_sse2_enabled = (features_ecx >> 20) & 1;
+#endif /* UNIV_DEBUG_VALGRIND */
+
+#endif /* defined(__GNUC__) && defined(__x86_64__) */
+
+	if (ut_crc32_sse2_enabled) {
+		ut_crc32 = ut_crc32_sse42;
+	} else {
+		ut_crc32_slice8_table_init();
+		ut_crc32 = ut_crc32_slice8;
+	}
+
+	ut_print_timestamp(stderr);
+	fprintf(stderr, " InnoDB: CPU %s crc32 instructions\n",
+		ut_crc32_sse2_enabled ? "supports" : "does not support");
 }
+/* } ut0crc32.c */
 
+/* ut0rnd.ic { */
+#define UT_HASH_RANDOM_MASK	1463735687
+#define UT_HASH_RANDOM_MASK2	1653893711
+/*************************************************************//**
+Folds a pair of ulints.
+@return	folded value */
+UNIV_INLINE
 ulint
 ut_fold_ulint_pair(
 /*===============*/
-            /* out: folded value */
-    ulint   n1, /* in: ulint */
-    ulint   n2) /* in: ulint */
+	ulint	n1,	/*!< in: ulint */
+	ulint	n2)	/*!< in: ulint */
 {
-    return(((((n1 ^ n2 ^ UT_HASH_RANDOM_MASK2) << 8) + n1)
-                        ^ UT_HASH_RANDOM_MASK) + n2);
+	return(((((n1 ^ n2 ^ UT_HASH_RANDOM_MASK2) << 8) + n1)
+		^ UT_HASH_RANDOM_MASK) + n2);
 }
 
+/*************************************************************//**
+Folds a binary string.
+@return	folded value */
+UNIV_INLINE
 ulint
 ut_fold_binary(
 /*===========*/
-            /* out: folded value */
-    uchar*   str,    /* in: string of bytes */
-    ulint   len)    /* in: length */
+	const byte*	str,	/*!< in: string of bytes */
+	ulint		len)	/*!< in: length */
 {
-    ulint   i;
-    ulint   fold= 0;
+	ulint		fold = 0;
+	const byte*	str_end	= str + (len & 0xFFFFFFF8);
 
-    for (i= 0; i < len; i++)
-    {
-      fold= ut_fold_ulint_pair(fold, (ulint)(*str));
+	ut_ad(str || !len);
 
-      str++;
-    }
+	while (str < str_end) {
+		fold = ut_fold_ulint_pair(fold, (ulint)(*str++));
+		fold = ut_fold_ulint_pair(fold, (ulint)(*str++));
+		fold = ut_fold_ulint_pair(fold, (ulint)(*str++));
+		fold = ut_fold_ulint_pair(fold, (ulint)(*str++));
+		fold = ut_fold_ulint_pair(fold, (ulint)(*str++));
+		fold = ut_fold_ulint_pair(fold, (ulint)(*str++));
+		fold = ut_fold_ulint_pair(fold, (ulint)(*str++));
+		fold = ut_fold_ulint_pair(fold, (ulint)(*str++));
+	}
+
+	switch (len & 0x7) {
+	case 7:
+		fold = ut_fold_ulint_pair(fold, (ulint)(*str++));
+	case 6:
+		fold = ut_fold_ulint_pair(fold, (ulint)(*str++));
+	case 5:
+		fold = ut_fold_ulint_pair(fold, (ulint)(*str++));
+	case 4:
+		fold = ut_fold_ulint_pair(fold, (ulint)(*str++));
+	case 3:
+		fold = ut_fold_ulint_pair(fold, (ulint)(*str++));
+	case 2:
+		fold = ut_fold_ulint_pair(fold, (ulint)(*str++));
+	case 1:
+		fold = ut_fold_ulint_pair(fold, (ulint)(*str++));
+	}
+
+	return(fold);
+}
+/* } ut0rnd.ic */
+
+/* buf0checksum.c { */
+/********************************************************************//**
+Calculates a page CRC32 which is stored to the page when it is written
+to a file. Note that we must be careful to calculate the same value on
+32-bit and 64-bit architectures.
+@return	checksum */
+UNIV_INTERN
+ib_uint32_t
+buf_calc_page_crc32(
+/*================*/
+	const byte*	page)	/*!< in: buffer page */
+{
+	ib_uint32_t	checksum;
+
+	/* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
+	FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, are written outside the buffer pool
+	to the first pages of data files, we have to skip them in the page
+	checksum calculation.
+	We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
+	checksum is stored, and also the last 8 bytes of page because
+	there we store the old formula checksum. */
+
+	checksum = ut_crc32(page + FIL_PAGE_OFFSET,
+			    FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
+		^ ut_crc32(page + FIL_PAGE_DATA,
+			   UNIV_PAGE_SIZE - FIL_PAGE_DATA
+			   - FIL_PAGE_END_LSN_OLD_CHKSUM);
 
-    return(fold);
+	return(checksum);
 }
 
+/********************************************************************//**
+Calculates a page checksum which is stored to the page when it is written
+to a file. Note that we must be careful to calculate the same value on
+32-bit and 64-bit architectures.
+@return	checksum */
+UNIV_INTERN
 ulint
 buf_calc_page_new_checksum(
 /*=======================*/
-               /* out: checksum */
-    uchar*    page) /* in: buffer page */
+	const byte*	page)	/*!< in: buffer page */
 {
-    ulint checksum;
+	ulint checksum;
 
-    /* Since the fields FIL_PAGE_FILE_FLUSH_LSN and ..._ARCH_LOG_NO
-    are written outside the buffer pool to the first pages of data
-    files, we have to skip them in the page checksum calculation.
-    We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
-    checksum is stored, and also the last 8 bytes of page because
-    there we store the old formula checksum. */
-
-    checksum= ut_fold_binary(page + FIL_PAGE_OFFSET,
-                             FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
-            + ut_fold_binary(page + FIL_PAGE_DATA,
-                             UNIV_PAGE_SIZE - FIL_PAGE_DATA
-                             - FIL_PAGE_END_LSN_OLD_CHKSUM);
-    checksum= checksum & 0xFFFFFFFF;
+	/* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
+	FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, are written outside the buffer pool
+	to the first pages of data files, we have to skip them in the page
+	checksum calculation.
+	We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
+	checksum is stored, and also the last 8 bytes of page because
+	there we store the old formula checksum. */
+
+	checksum = ut_fold_binary(page + FIL_PAGE_OFFSET,
+				  FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
+		+ ut_fold_binary(page + FIL_PAGE_DATA,
+				 UNIV_PAGE_SIZE - FIL_PAGE_DATA
+				 - FIL_PAGE_END_LSN_OLD_CHKSUM);
+	checksum = checksum & 0xFFFFFFFFUL;
 
-    return(checksum);
+	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
+checksum.
+NOTE: we must first store the new formula checksum to
+FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
+because this takes that field as an input!
+@return	checksum */
+UNIV_INTERN
 ulint
 buf_calc_page_old_checksum(
 /*=======================*/
-               /* out: checksum */
-    uchar*    page) /* in: buffer page */
+	const byte*	page)	/*!< in: buffer page */
 {
-    ulint checksum;
+	ulint checksum;
+
+	checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
+
+	checksum = checksum & 0xFFFFFFFFUL;
+
+	return(checksum);
+}
+/* } buf0checksum.c */
+
+#endif /* INNOCHECKSUM_SOLARIS */
+
+/* needed to have access to 64 bit file functions */
+#ifndef _LARGEFILE_SOURCE
+#define _LARGEFILE_SOURCE
+#endif /* _LARGEFILE_SOURCE */
+
+#ifndef _LARGEFILE64_SOURCE
+#define _LARGEFILE64_SOURCE
+#endif /* _LARGEFILE64_SOURCE */
+
+#ifdef _XOPEN_SOURCE
+#undef _XOPEN_SOURCE
+#endif /* _XOPEN_SOURCE */
+#define _XOPEN_SOURCE 500 /* needed to include getopt.h on some platforms. */
 
-    checksum= ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
-    checksum= checksum & 0xFFFFFFFF;
+/* command line argument to do page checks (that's it) */
+/* another argument to specify page ranges... seek to right spot and go from there */
 
-    return(checksum);
+#ifndef INNOCHECKSUM_SOLARIS
+void
+ut_dbg_assertion_failed(
+/*====================*/
+        const char* expr,       /*!< in: the failed assertion (optional) */
+        const char* file,       /*!< in: source file containing the assertion */
+        ulint line)             /*!< in: line number of the assertion */
+{
+	fprintf(stderr, "innochecksum(%s:%u): Assertion %s failed.\n",
+		file, (unsigned) line, expr ? expr : "");
 }
 
+void
+ut_print_timestamp(
+/*===============*/
+	FILE*	file __attribute__((unused)))	/*!< in: file where to print */
+{
+}
+#endif /* INNOCHECKSUM_SOLARIS */
 
 int main(int argc, char **argv)
 {
   FILE *f;                     /* our input file */
-  uchar *p;                     /* storage of pages read */
+  byte *p;                     /* storage of pages read */
   int bytes;                   /* bytes read count */
   ulint ct;                    /* current page number (0 based) */
   int now;                     /* current time */
   int lastt;                   /* last time */
-  ulint oldcsum, oldcsumfield, csum, csumfield, logseq, logseqfield; /* ulints for checksum storage */
+  ulint oldcsum, oldcsumfield, csum, csumfield, crc32, logseq, logseqfield; /* ulints for checksum storage */
   struct stat st;              /* for stat, if you couldn't guess */
   unsigned long long int size; /* size of file (has to be 64 bits) */
   ulint pages;                 /* number of pages in file */
@@ -157,6 +763,8 @@ int main(int argc, char **argv)
   int c;
   int fd;
 
+  ut_crc32_init();
+
   /* remove arguments */
   while ((c= getopt(argc, argv, "cvds:e:p:")) != -1)
   {
@@ -258,7 +866,7 @@ int main(int argc, char **argv)
   }
 
   /* allocate buffer for reading (so we don't realloc every time) */
-  p= (uchar *)malloc(UNIV_PAGE_SIZE);
+  p= (byte*)malloc(UNIV_PAGE_SIZE);
 
   /* main checksumming loop */
   ct= start_page;
@@ -297,12 +905,14 @@ int main(int argc, char **argv)
 
     /* now check the new method */
     csum= buf_calc_page_new_checksum(p);
+    crc32= buf_calc_page_crc32(p);
     csumfield= mach_read_from_4(p + FIL_PAGE_SPACE_OR_CHKSUM);
     if (debug)
-      printf("page %lu: new style: calculated = %lu; recorded = %lu\n", ct, csum, csumfield);
-    if (csumfield != 0 && csum != csumfield)
+      printf("page %lu: new style: calculated = %lu; crc32 = %lu; recorded = %lu\n",
+          ct, csum, crc32, csumfield);
+    if (csumfield != 0 && crc32 != csumfield && csum != csumfield)
     {
-      fprintf(stderr, "page %lu invalid (fails new style checksum)\n", ct);
+      fprintf(stderr, "page %lu invalid (fails innodb and crc32 checksum)\n", ct);
       return 1;
     }
 

=== added file 'mysql-test/suite/sys_vars/r/innodb_checksum_algorithm_basic.result'
--- a/mysql-test/suite/sys_vars/r/innodb_checksum_algorithm_basic.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/sys_vars/r/innodb_checksum_algorithm_basic.result	revid:vasil.dimov@stripped
@@ -0,0 +1,47 @@
+SET @orig = @@global.innodb_checksum_algorithm;
+SELECT @orig;
+@orig
+innodb
+SET GLOBAL innodb_checksum_algorithm = 'crc32';
+SELECT @@global.innodb_checksum_algorithm;
+@@global.innodb_checksum_algorithm
+crc32
+SET GLOBAL innodb_checksum_algorithm = 'strict_crc32';
+SELECT @@global.innodb_checksum_algorithm;
+@@global.innodb_checksum_algorithm
+strict_crc32
+SET GLOBAL innodb_checksum_algorithm = 'innodb';
+SELECT @@global.innodb_checksum_algorithm;
+@@global.innodb_checksum_algorithm
+innodb
+SET GLOBAL innodb_checksum_algorithm = 'strict_innodb';
+SELECT @@global.innodb_checksum_algorithm;
+@@global.innodb_checksum_algorithm
+strict_innodb
+SET GLOBAL innodb_checksum_algorithm = 'none';
+SELECT @@global.innodb_checksum_algorithm;
+@@global.innodb_checksum_algorithm
+none
+SET GLOBAL innodb_checksum_algorithm = 'strict_none';
+SELECT @@global.innodb_checksum_algorithm;
+@@global.innodb_checksum_algorithm
+strict_none
+SET GLOBAL innodb_checksum_algorithm = '';
+ERROR 42000: Variable 'innodb_checksum_algorithm' can't be set to the value of ''
+SELECT @@global.innodb_checksum_algorithm;
+@@global.innodb_checksum_algorithm
+strict_none
+SET GLOBAL innodb_checksum_algorithm = 'foobar';
+ERROR 42000: Variable 'innodb_checksum_algorithm' can't be set to the value of 'foobar'
+SELECT @@global.innodb_checksum_algorithm;
+@@global.innodb_checksum_algorithm
+strict_none
+SET GLOBAL innodb_checksum_algorithm = 123;
+ERROR 42000: Variable 'innodb_checksum_algorithm' can't be set to the value of '123'
+SELECT @@global.innodb_checksum_algorithm;
+@@global.innodb_checksum_algorithm
+strict_none
+SET GLOBAL innodb_checksum_algorithm = @orig;
+SELECT @@global.innodb_checksum_algorithm;
+@@global.innodb_checksum_algorithm
+innodb

=== added file 'mysql-test/suite/sys_vars/t/innodb_checksum_algorithm_basic.test'
--- a/mysql-test/suite/sys_vars/t/innodb_checksum_algorithm_basic.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/sys_vars/t/innodb_checksum_algorithm_basic.test	revid:vasil.dimov@stripped
@@ -0,0 +1,38 @@
+--source include/have_innodb.inc
+
+# Check the default value
+SET @orig = @@global.innodb_checksum_algorithm;
+SELECT @orig;
+
+SET GLOBAL innodb_checksum_algorithm = 'crc32';
+SELECT @@global.innodb_checksum_algorithm;
+
+SET GLOBAL innodb_checksum_algorithm = 'strict_crc32';
+SELECT @@global.innodb_checksum_algorithm;
+
+SET GLOBAL innodb_checksum_algorithm = 'innodb';
+SELECT @@global.innodb_checksum_algorithm;
+
+SET GLOBAL innodb_checksum_algorithm = 'strict_innodb';
+SELECT @@global.innodb_checksum_algorithm;
+
+SET GLOBAL innodb_checksum_algorithm = 'none';
+SELECT @@global.innodb_checksum_algorithm;
+
+SET GLOBAL innodb_checksum_algorithm = 'strict_none';
+SELECT @@global.innodb_checksum_algorithm;
+
+-- error ER_WRONG_VALUE_FOR_VAR
+SET GLOBAL innodb_checksum_algorithm = '';
+SELECT @@global.innodb_checksum_algorithm;
+
+-- error ER_WRONG_VALUE_FOR_VAR
+SET GLOBAL innodb_checksum_algorithm = 'foobar';
+SELECT @@global.innodb_checksum_algorithm;
+
+-- error ER_WRONG_VALUE_FOR_VAR
+SET GLOBAL innodb_checksum_algorithm = 123;
+SELECT @@global.innodb_checksum_algorithm;
+
+SET GLOBAL innodb_checksum_algorithm = @orig;
+SELECT @@global.innodb_checksum_algorithm;

=== modified file 'storage/innobase/CMakeLists.txt'
--- a/storage/innobase/CMakeLists.txt	revid:andrei.elkin@stripped
+++ b/storage/innobase/CMakeLists.txt	revid:vasil.dimov@stripped
@@ -227,6 +227,7 @@ SET(INNOBASE_SOURCES
 	btr/btr0sea.c
 	buf/buf0buddy.c
 	buf/buf0buf.c
+	buf/buf0checksum.c
 	buf/buf0dump.c
 	buf/buf0flu.c
 	buf/buf0lru.c
@@ -309,6 +310,7 @@ SET(INNOBASE_SOURCES
 	usr/usr0sess.c
 	ut/ut0bh.c
 	ut/ut0byte.c
+	ut/ut0crc32.c
 	ut/ut0dbg.c
 	ut/ut0list.c
 	ut/ut0mem.c

=== modified file 'storage/innobase/buf/buf0buf.c'
--- a/storage/innobase/buf/buf0buf.c	revid:andrei.elkin@stripped
+++ b/storage/innobase/buf/buf0buf.c	revid:vasil.dimov@stripped
@@ -41,6 +41,7 @@ Created 11/5/1995 Heikki Tuuri
 #include "fil0fil.h"
 #ifndef UNIV_HOTBACKUP
 #include "buf0buddy.h"
+#include "buf0checksum.h"
 #include "lock0lock.h"
 #include "btr0sea.h"
 #include "ibuf0ibuf.h"
@@ -448,60 +449,6 @@ buf_block_alloc(
 #endif /* !UNIV_HOTBACKUP */
 
 /********************************************************************//**
-Calculates a page checksum which is stored to the page when it is written
-to a file. Note that we must be careful to calculate the same value on
-32-bit and 64-bit architectures.
-@return	checksum */
-UNIV_INTERN
-ulint
-buf_calc_page_new_checksum(
-/*=======================*/
-	const byte*	page)	/*!< in: buffer page */
-{
-	ulint checksum;
-
-	/* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
-	..._ARCH_LOG_NO, are written outside the buffer pool to the first
-	pages of data files, we have to skip them in the page checksum
-	calculation.
-	We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
-	checksum is stored, and also the last 8 bytes of page because
-	there we store the old formula checksum. */
-
-	checksum = ut_fold_binary(page + FIL_PAGE_OFFSET,
-				  FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
-		+ ut_fold_binary(page + FIL_PAGE_DATA,
-				 UNIV_PAGE_SIZE - FIL_PAGE_DATA
-				 - 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
-checksum.
-NOTE: we must first store the new formula checksum to
-FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
-because this takes that field as an input!
-@return	checksum */
-UNIV_INTERN
-ulint
-buf_calc_page_old_checksum(
-/*=======================*/
-	const byte*	page)	/*!< in: buffer page */
-{
-	ulint checksum;
-
-	checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
-
-	checksum = checksum & 0xFFFFFFFFUL;
-
-	return(checksum);
-}
-
-/********************************************************************//**
 Checks if a page is corrupt.
 @return	TRUE if corrupted */
 UNIV_INTERN
@@ -512,8 +459,9 @@ buf_page_is_corrupted(
 	ulint		zip_size)	/*!< in: size of compressed page;
 					0 for uncompressed pages */
 {
-	ulint		checksum_field;
-	ulint		old_checksum_field;
+	ulint		checksum_field1;
+	ulint		checksum_field2;
+	ib_uint32_t	crc32;
 
 	if (UNIV_LIKELY(!zip_size)
 	    && memcmp(read_buf + FIL_PAGE_LSN + 4,
@@ -555,52 +503,118 @@ buf_page_is_corrupted(
 	}
 #endif
 
-	/* If we use checksums validation, make additional check before
-	returning TRUE to ensure that the checksum is not equal to
-	BUF_NO_CHECKSUM_MAGIC which might be stored by InnoDB with checksums
-	disabled. Otherwise, skip checksum calculation and return FALSE */
-
-	if (UNIV_LIKELY(srv_use_checksums)) {
-		checksum_field = mach_read_from_4(read_buf
-						  + FIL_PAGE_SPACE_OR_CHKSUM);
+	/* Check whether the checksum fields have correct values */
 
-		if (UNIV_UNLIKELY(zip_size)) {
-			return(checksum_field != BUF_NO_CHECKSUM_MAGIC
-			       && checksum_field
-			       != page_zip_calc_checksum(read_buf, zip_size));
-		}
+	if (srv_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_NONE) {
+		return(FALSE);
+	}
+
+	if (UNIV_UNLIKELY(zip_size)) {
+		return(!page_zip_verify_checksum(read_buf, zip_size));
+	}
+
+	checksum_field1 = mach_read_from_4(
+		read_buf + FIL_PAGE_SPACE_OR_CHKSUM);
+
+	checksum_field2 = mach_read_from_4(
+		read_buf + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM);
+
+	/* declare empty pages non-corrupted */
+	if (checksum_field1 == 0 && checksum_field2 == 0
+	    && mach_read_from_4(read_buf + FIL_PAGE_LSN) == 0) {
+		/* make sure that the page is really empty */
+		ut_d(ulint i; for (i = 0; i < UNIV_PAGE_SIZE; i++) {
+		     ut_a(read_buf[i] == 0); });
+
+		return(FALSE);
+	}
+
+	switch ((srv_checksum_algorithm_t) srv_checksum_algorithm) {
+	case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
 
-		old_checksum_field = mach_read_from_4(
-			read_buf + UNIV_PAGE_SIZE
-			- FIL_PAGE_END_LSN_OLD_CHKSUM);
+		crc32 = buf_calc_page_crc32(read_buf);
 
-		/* There are 2 valid formulas for old_checksum_field:
+		return(checksum_field1 != crc32 || checksum_field2 != crc32);
+
+	case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
+
+		return(checksum_field1
+		       != buf_calc_page_new_checksum(read_buf)
+		       || checksum_field2
+		       != buf_calc_page_old_checksum(read_buf));
+
+	case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
+
+		return(checksum_field1 != BUF_NO_CHECKSUM_MAGIC
+		       || checksum_field2 != BUF_NO_CHECKSUM_MAGIC);
+
+	case SRV_CHECKSUM_ALGORITHM_CRC32:
+	case SRV_CHECKSUM_ALGORITHM_INNODB:
+		/* There are 3 valid formulas for old_checksum_field:
 
 		1. Very old versions of InnoDB only stored 8 byte lsn to the
 		start and the end of the page.
 
-		2. Newer InnoDB versions store the old formula checksum
-		there. */
+		2. InnoDB versions before MySQL 5.6.3 store the old formula
+		checksum.
+
+		3. InnoDB versions 5.6.3 and newer with
+		innodb_checksum_algorithm=strict_crc32|crc32 store CRC32. */
+
+		crc32 = buf_calc_page_crc32(read_buf);
+
+		/* since innodb_checksum_algorithm is not strict_* allow
+		any of the algos to match for the old field */
+
+		if (checksum_field2
+		    != mach_read_from_4(read_buf + FIL_PAGE_LSN)
 
-		if (old_checksum_field != mach_read_from_4(read_buf
-							   + FIL_PAGE_LSN)
-		    && old_checksum_field != BUF_NO_CHECKSUM_MAGIC
-		    && old_checksum_field
+		    && checksum_field2
+		    != crc32
+
+		    && checksum_field2
+		    != BUF_NO_CHECKSUM_MAGIC
+
+		    && checksum_field2
 		    != buf_calc_page_old_checksum(read_buf)) {
 
 			return(TRUE);
 		}
 
+		/* old field is fine, check the new field */
+
 		/* 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
-		    && checksum_field != BUF_NO_CHECKSUM_MAGIC
-		    && checksum_field
+		if (checksum_field1
+		    != 0
+
+		    && checksum_field1
+		    != BUF_NO_CHECKSUM_MAGIC
+
+		    && checksum_field1
+		    != crc32
+
+		    && checksum_field1
 		    != buf_calc_page_new_checksum(read_buf)) {
 
 			return(TRUE);
 		}
+
+		/* If CRC32 is stored in at least one of the fields, then the
+		other field must also be CRC32 */
+		if ((checksum_field1 == crc32 && checksum_field2 != crc32)
+		    || (checksum_field1 != crc32 && checksum_field2 == crc32)) {
+
+			return(TRUE);
+		}
+
+		break;
+	case SRV_CHECKSUM_ALGORITHM_NONE:
+		/* should have returned FALSE earlier */
+		ut_error;
+	/* no default so the compiler will emit a warning if new enum
+	is added and not handled here */
 	}
 
 	return(FALSE);
@@ -619,118 +633,94 @@ buf_page_print(
 #ifndef UNIV_HOTBACKUP
 	dict_index_t*	index;
 #endif /* !UNIV_HOTBACKUP */
-	ulint		checksum;
-	ulint		old_checksum;
-	ulint		size	= zip_size;
+	ulint		size = zip_size;
 
 	if (!size) {
 		size = UNIV_PAGE_SIZE;
 	}
 
 	ut_print_timestamp(stderr);
-	fprintf(stderr, "  InnoDB: Page dump in ascii and hex (%lu bytes):\n",
+	fprintf(stderr, " InnoDB: Page dump in ascii and hex (%lu bytes):\n",
 		(ulong) size);
 	ut_print_buf(stderr, read_buf, size);
 	fputs("\nInnoDB: End of page dump\n", stderr);
 
 	if (zip_size) {
 		/* Print compressed page. */
+		ut_print_timestamp(stderr);
+		fprintf(stderr,
+			" InnoDB: Compressed page type (" ULINTPF "); "
+			"stored checksum in field1 " ULINTPF "; "
+			"calculated checksums for field1: "
+			"%s " ULINTPF ", "
+			"%s " ULINTPF ", "
+			"%s " ULINTPF "; "
+			"page LSN " LSN_PF "; "
+			"page number (if stored to page already) " ULINTPF "; "
+			"space id (if stored to page already) " ULINTPF "\n",
+			fil_page_get_type(read_buf),
+			mach_read_from_4(read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
+			buf_checksum_algorithm_name(
+				SRV_CHECKSUM_ALGORITHM_CRC32),
+			page_zip_calc_checksum(read_buf, zip_size,
+				SRV_CHECKSUM_ALGORITHM_CRC32),
+			buf_checksum_algorithm_name(
+				SRV_CHECKSUM_ALGORITHM_INNODB),
+			page_zip_calc_checksum(read_buf, zip_size,
+				SRV_CHECKSUM_ALGORITHM_INNODB),
+			buf_checksum_algorithm_name(
+				SRV_CHECKSUM_ALGORITHM_NONE),
+			page_zip_calc_checksum(read_buf, zip_size,
+				SRV_CHECKSUM_ALGORITHM_NONE),
+			mach_read_from_8(read_buf + FIL_PAGE_LSN),
+			mach_read_from_4(read_buf + FIL_PAGE_OFFSET),
+			mach_read_from_4(read_buf
+					 + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
+	} else {
+		ut_print_timestamp(stderr);
+		fprintf(stderr, " InnoDB: uncompressed page, "
+			"stored checksum in field1 " ULINTPF ", "
+			"calculated checksums for field1: "
+			"%s " UINT32PF ", "
+			"%s " ULINTPF ", "
+			"%s " ULINTPF ", "
+
+			"stored checksum in field2 " ULINTPF ", "
+			"calculated checksums for field2: "
+			"%s " UINT32PF ", "
+			"%s " ULINTPF ", "
+			"%s " ULINTPF ", "
+
+			"page LSN " ULINTPF " " ULINTPF ", "
+			"low 4 bytes of LSN at page end " ULINTPF ", "
+			"page number (if stored to page already) " ULINTPF ", "
+			"space id (if created with >= MySQL-4.1.1 "
+			"and stored already) %lu\n",
+			mach_read_from_4(read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
+			buf_checksum_algorithm_name(SRV_CHECKSUM_ALGORITHM_CRC32),
+			buf_calc_page_crc32(read_buf),
+			buf_checksum_algorithm_name(SRV_CHECKSUM_ALGORITHM_INNODB),
+			buf_calc_page_new_checksum(read_buf),
+			buf_checksum_algorithm_name(SRV_CHECKSUM_ALGORITHM_NONE),
+			BUF_NO_CHECKSUM_MAGIC,
 
-		switch (fil_page_get_type(read_buf)) {
-		case FIL_PAGE_TYPE_ZBLOB:
-		case FIL_PAGE_TYPE_ZBLOB2:
-			checksum = srv_use_checksums
-				? page_zip_calc_checksum(read_buf, zip_size)
-				: BUF_NO_CHECKSUM_MAGIC;
-			ut_print_timestamp(stderr);
-			fprintf(stderr,
-				"  InnoDB: Compressed BLOB page"
-				" checksum %lu, stored %lu\n"
-				"InnoDB: Page lsn %lu %lu\n"
-				"InnoDB: Page number (if stored"
-				" to page already) %lu,\n"
-				"InnoDB: space id (if stored"
-				" to page already) %lu\n",
-				(ulong) checksum,
-				(ulong) mach_read_from_4(
-					read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
-				(ulong) mach_read_from_4(
-					read_buf + FIL_PAGE_LSN),
-				(ulong) mach_read_from_4(
-					read_buf + (FIL_PAGE_LSN + 4)),
-				(ulong) mach_read_from_4(
-					read_buf + FIL_PAGE_OFFSET),
-				(ulong) mach_read_from_4(
-					read_buf
-					+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
-			return;
-		default:
-			ut_print_timestamp(stderr);
-			fprintf(stderr,
-				"  InnoDB: unknown page type %lu,"
-				" assuming FIL_PAGE_INDEX\n",
-				fil_page_get_type(read_buf));
-			/* fall through */
-		case FIL_PAGE_INDEX:
-			checksum = srv_use_checksums
-				? page_zip_calc_checksum(read_buf, zip_size)
-				: BUF_NO_CHECKSUM_MAGIC;
-
-			ut_print_timestamp(stderr);
-			fprintf(stderr,
-				"  InnoDB: Compressed page checksum %lu,"
-				" stored %lu\n"
-				"InnoDB: Page lsn %lu %lu\n"
-				"InnoDB: Page number (if stored"
-				" to page already) %lu,\n"
-				"InnoDB: space id (if stored"
-				" to page already) %lu\n",
-				(ulong) checksum,
-				(ulong) mach_read_from_4(
-					read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
-				(ulong) mach_read_from_4(
-					read_buf + FIL_PAGE_LSN),
-				(ulong) mach_read_from_4(
-					read_buf + (FIL_PAGE_LSN + 4)),
-				(ulong) mach_read_from_4(
-					read_buf + FIL_PAGE_OFFSET),
-				(ulong) mach_read_from_4(
-					read_buf
-					+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
-			return;
-		case FIL_PAGE_TYPE_XDES:
-			/* This is an uncompressed page. */
-			break;
-		}
-	}
-
-	checksum = srv_use_checksums
-		? buf_calc_page_new_checksum(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"
-		" checksum %lu\n"
-		"InnoDB: stored checksum %lu, prior-to-4.0.14-form"
-		" stored checksum %lu\n"
-		"InnoDB: Page lsn %lu %lu, low 4 bytes of lsn"
-		" at page end %lu\n"
-		"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) mach_read_from_4(read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
-		(ulong) mach_read_from_4(read_buf + UNIV_PAGE_SIZE
+			mach_read_from_4(read_buf + UNIV_PAGE_SIZE
 					 - FIL_PAGE_END_LSN_OLD_CHKSUM),
-		(ulong) mach_read_from_4(read_buf + FIL_PAGE_LSN),
-		(ulong) mach_read_from_4(read_buf + FIL_PAGE_LSN + 4),
-		(ulong) mach_read_from_4(read_buf + UNIV_PAGE_SIZE
+			buf_checksum_algorithm_name(SRV_CHECKSUM_ALGORITHM_CRC32),
+			buf_calc_page_crc32(read_buf),
+			buf_checksum_algorithm_name(SRV_CHECKSUM_ALGORITHM_INNODB),
+			buf_calc_page_old_checksum(read_buf),
+			buf_checksum_algorithm_name(SRV_CHECKSUM_ALGORITHM_NONE),
+			BUF_NO_CHECKSUM_MAGIC,
+
+			mach_read_from_4(read_buf + FIL_PAGE_LSN),
+			mach_read_from_4(read_buf + FIL_PAGE_LSN + 4),
+			mach_read_from_4(read_buf + UNIV_PAGE_SIZE
 					 - FIL_PAGE_END_LSN_OLD_CHKSUM + 4),
-		(ulong) mach_read_from_4(read_buf + FIL_PAGE_OFFSET),
-		(ulong) mach_read_from_4(read_buf
+			mach_read_from_4(read_buf + FIL_PAGE_OFFSET),
+			mach_read_from_4(read_buf
 					 + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
+	}
 
 #ifndef UNIV_HOTBACKUP
 	if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE)
@@ -2132,26 +2122,28 @@ buf_zip_decompress(
 	buf_block_t*	block,	/*!< in/out: block */
 	ibool		check)	/*!< in: TRUE=verify the page checksum */
 {
-	const byte*	frame		= block->page.zip.data;
-	ulint		stamp_checksum	= mach_read_from_4(
-		frame + FIL_PAGE_SPACE_OR_CHKSUM);
+	const byte*	frame = block->page.zip.data;
+	ulint		size = page_zip_get_size(&block->page.zip);
 
 	ut_ad(buf_block_get_zip_size(block));
 	ut_a(buf_block_get_space(block) != 0);
 
-	if (UNIV_LIKELY(check && stamp_checksum != BUF_NO_CHECKSUM_MAGIC)) {
-		ulint	calc_checksum	= page_zip_calc_checksum(
-			frame, page_zip_get_size(&block->page.zip));
+	if (UNIV_UNLIKELY(check && !page_zip_verify_checksum(frame, size))) {
 
-		if (UNIV_UNLIKELY(stamp_checksum != calc_checksum)) {
-			ut_print_timestamp(stderr);
-			fprintf(stderr,
-				"  InnoDB: compressed page checksum mismatch"
-				" (space %u page %u): %lu != %lu\n",
-				block->page.space, block->page.offset,
-				stamp_checksum, calc_checksum);
-			return(FALSE);
-		}
+		ut_print_timestamp(stderr);
+		fprintf(stderr,
+			"  InnoDB: compressed page checksum mismatch"
+			" (space %u page %u): stored: %lu, crc32: %lu "
+			"innodb: %lu, none: %lu\n",
+			block->page.space, block->page.offset,
+			mach_read_from_4(frame + FIL_PAGE_SPACE_OR_CHKSUM),
+			page_zip_calc_checksum(frame, size,
+					       SRV_CHECKSUM_ALGORITHM_CRC32),
+			page_zip_calc_checksum(frame, size,
+					       SRV_CHECKSUM_ALGORITHM_INNODB),
+			page_zip_calc_checksum(frame, size,
+					       SRV_CHECKSUM_ALGORITHM_NONE));
+		return(FALSE);
 	}
 
 	switch (fil_page_get_type(frame)) {
@@ -2568,7 +2560,6 @@ got_block:
 
 	switch (buf_block_get_state(block)) {
 		buf_page_t*	bpage;
-		ibool		success;
 
 	case BUF_BLOCK_FILE_PAGE:
 		break;
@@ -2690,8 +2681,8 @@ wait_until_unfixed:
 
 		/* Decompress the page and apply buffered operations
 		while not holding buf_pool->mutex or block->mutex. */
-		success = buf_zip_decompress(block, srv_use_checksums);
-		ut_a(success);
+
+		ut_a(buf_zip_decompress(block, TRUE));
 
 		if (UNIV_LIKELY(!recv_no_ibuf_operations)) {
 			ibuf_merge_or_delete_for_page(block, space, offset,

=== added file 'storage/innobase/buf/buf0checksum.c'
--- a/storage/innobase/buf/buf0checksum.c	1970-01-01 00:00:00 +0000
+++ b/storage/innobase/buf/buf0checksum.c	revid:vasil.dimov@stripped
@@ -0,0 +1,140 @@
+/*****************************************************************************
+
+Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file buf/buf0checksum.c
+Buffer pool checksum functions, also linked from /extra/innochecksum.c
+
+Created Aug 11, 2011 Vasil Dimov
+*******************************************************/
+
+#include "univ.i"
+
+#include "fil0fil.h" /* FIL_* */
+#include "srv0srv.h" /* SRV_CHECKSUM_* */
+#include "ut0crc32.h" /* ut_crc32() */
+#include "ut0rnd.h" /* ut_fold_binary() */
+
+/********************************************************************//**
+Calculates a page CRC32 which is stored to the page when it is written
+to a file. Note that we must be careful to calculate the same value on
+32-bit and 64-bit architectures.
+@return	checksum */
+UNIV_INTERN
+ib_uint32_t
+buf_calc_page_crc32(
+/*================*/
+	const byte*	page)	/*!< in: buffer page */
+{
+	ib_uint32_t	checksum;
+
+	/* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
+	FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, are written outside the buffer pool
+	to the first pages of data files, we have to skip them in the page
+	checksum calculation.
+	We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
+	checksum is stored, and also the last 8 bytes of page because
+	there we store the old formula checksum. */
+
+	checksum = ut_crc32(page + FIL_PAGE_OFFSET,
+			    FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
+		^ ut_crc32(page + FIL_PAGE_DATA,
+			   UNIV_PAGE_SIZE - FIL_PAGE_DATA
+			   - FIL_PAGE_END_LSN_OLD_CHKSUM);
+
+	return(checksum);
+}
+
+/********************************************************************//**
+Calculates a page checksum which is stored to the page when it is written
+to a file. Note that we must be careful to calculate the same value on
+32-bit and 64-bit architectures.
+@return	checksum */
+UNIV_INTERN
+ulint
+buf_calc_page_new_checksum(
+/*=======================*/
+	const byte*	page)	/*!< in: buffer page */
+{
+	ulint checksum;
+
+	/* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
+	FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, are written outside the buffer pool
+	to the first pages of data files, we have to skip them in the page
+	checksum calculation.
+	We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
+	checksum is stored, and also the last 8 bytes of page because
+	there we store the old formula checksum. */
+
+	checksum = ut_fold_binary(page + FIL_PAGE_OFFSET,
+				  FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
+		+ ut_fold_binary(page + FIL_PAGE_DATA,
+				 UNIV_PAGE_SIZE - FIL_PAGE_DATA
+				 - 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
+checksum.
+NOTE: we must first store the new formula checksum to
+FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
+because this takes that field as an input!
+@return	checksum */
+UNIV_INTERN
+ulint
+buf_calc_page_old_checksum(
+/*=======================*/
+	const byte*	page)	/*!< in: buffer page */
+{
+	ulint checksum;
+
+	checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
+
+	checksum = checksum & 0xFFFFFFFFUL;
+
+	return(checksum);
+}
+
+/********************************************************************//**
+Return a printable string describing the checksum algorithm.
+@return	algorithm name */
+UNIV_INTERN
+const char*
+buf_checksum_algorithm_name(
+/*========================*/
+	srv_checksum_algorithm_t	algo)	/*!< in: algorithm */
+{
+	switch (algo) {
+	case SRV_CHECKSUM_ALGORITHM_CRC32:
+	case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
+		return("crc32");
+	case SRV_CHECKSUM_ALGORITHM_INNODB:
+	case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
+		return("innodb");
+	case SRV_CHECKSUM_ALGORITHM_NONE:
+	case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
+		return("none");
+	}
+
+	ut_error;
+	return(NULL);
+}

=== modified file 'storage/innobase/buf/buf0flu.c'
--- a/storage/innobase/buf/buf0flu.c	revid:andrei.elkin@stripped
+++ b/storage/innobase/buf/buf0flu.c	revid:vasil.dimov@stripped
@@ -30,6 +30,7 @@ Created 11/11/1995 Heikki Tuuri
 #endif
 
 #include "buf0buf.h"
+#include "buf0checksum.h"
 #include "srv0start.h"
 #include "srv0srv.h"
 #include "page0zip.h"
@@ -735,10 +736,16 @@ buf_flush_doublewrite_check_page_lsn(
 
 		ut_print_timestamp(stderr);
 		fprintf(stderr,
-			"  InnoDB: ERROR: The page to be written"
+			" InnoDB: ERROR: The page to be written"
 			" seems corrupt!\n"
-			"InnoDB: The LSN fields do not match!"
-			" Noticed in the buffer pool\n");
+			"InnoDB: The low 4 bytes of LSN fields do not match "
+			"(" ULINTPF " != " ULINTPF ")!"
+			" Noticed in the buffer pool.\n",
+			mach_read_from_4(
+				page + FIL_PAGE_LSN + 4),
+			mach_read_from_4(
+				page + UNIV_PAGE_SIZE
+				- FIL_PAGE_END_LSN_OLD_CHKSUM + 4));
 	}
 }
 
@@ -1199,6 +1206,8 @@ buf_flush_init_for_writing(
 	lsn_t	newest_lsn)	/*!< in: newest modification lsn
 				to the page */
 {
+	ib_uint32_t	checksum = 0 /* silence bogus gcc warning */;
+
 	ut_ad(page);
 
 	if (page_zip_) {
@@ -1220,15 +1229,16 @@ buf_flush_init_for_writing(
 		case FIL_PAGE_TYPE_ZBLOB:
 		case FIL_PAGE_TYPE_ZBLOB2:
 		case FIL_PAGE_INDEX:
+			checksum = page_zip_calc_checksum(
+				page_zip->data, zip_size,
+				srv_checksum_algorithm);
+
 			mach_write_to_8(page_zip->data
 					+ FIL_PAGE_LSN, newest_lsn);
 			memset(page_zip->data + FIL_PAGE_FILE_FLUSH_LSN, 0, 8);
 			mach_write_to_4(page_zip->data
 					+ FIL_PAGE_SPACE_OR_CHKSUM,
-					srv_use_checksums
-					? page_zip_calc_checksum(
-						page_zip->data, zip_size)
-					: BUF_NO_CHECKSUM_MAGIC);
+					checksum);
 			return;
 		}
 
@@ -1250,20 +1260,46 @@ buf_flush_init_for_writing(
 
 	/* Store the new formula checksum */
 
-	mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM,
-			srv_use_checksums
-			? buf_calc_page_new_checksum(page)
-			: BUF_NO_CHECKSUM_MAGIC);
+	switch ((srv_checksum_algorithm_t) srv_checksum_algorithm) {
+	case SRV_CHECKSUM_ALGORITHM_CRC32:
+	case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
+		checksum = buf_calc_page_crc32(page);
+		break;
+	case SRV_CHECKSUM_ALGORITHM_INNODB:
+	case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
+		checksum = (ib_uint32_t) buf_calc_page_new_checksum(page);
+		break;
+	case SRV_CHECKSUM_ALGORITHM_NONE:
+	case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
+		checksum = BUF_NO_CHECKSUM_MAGIC;
+		break;
+	/* no default so the compiler will emit a warning if new enum
+	is added and not handled here */
+	}
+
+	mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM, checksum);
 
 	/* We overwrite the first 4 bytes of the end lsn field to store
 	the old formula checksum. Since it depends also on the field
 	FIL_PAGE_SPACE_OR_CHKSUM, it has to be calculated after storing the
 	new formula checksum. */
 
+	if (srv_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_STRICT_INNODB
+	    || srv_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_INNODB) {
+
+		checksum = (ib_uint32_t) buf_calc_page_old_checksum(page);
+
+		/* In other cases we use the value assigned from above.
+		If CRC32 is used then it is faster to use that checksum
+		(calculated above) instead of calculating another one.
+		We can afford to store something other than
+		buf_calc_page_old_checksum() or BUF_NO_CHECKSUM_MAGIC in
+		this field because the file will not be readable by old
+		versions of MySQL/InnoDB anyway (older than MySQL 5.6.3) */
+	}
+
 	mach_write_to_4(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM,
-			srv_use_checksums
-			? buf_calc_page_old_checksum(page)
-			: BUF_NO_CHECKSUM_MAGIC);
+			checksum);
 }
 
 #ifndef UNIV_HOTBACKUP
@@ -1331,10 +1367,9 @@ buf_flush_write_block_low(
 		break;
 	case BUF_BLOCK_ZIP_DIRTY:
 		frame = bpage->zip.data;
-		if (UNIV_LIKELY(srv_use_checksums)) {
-			ut_a(mach_read_from_4(frame + FIL_PAGE_SPACE_OR_CHKSUM)
-			     == page_zip_calc_checksum(frame, zip_size));
-		}
+
+		ut_a(page_zip_verify_checksum(frame, zip_size));
+
 		mach_write_to_8(frame + FIL_PAGE_LSN,
 				bpage->newest_modification);
 		memset(frame + FIL_PAGE_FILE_FLUSH_LSN, 0, 8);

=== modified file 'storage/innobase/buf/buf0lru.c'
--- a/storage/innobase/buf/buf0lru.c	revid:andrei.elkin@stripped
+++ b/storage/innobase/buf/buf0lru.c	revid:vasil.dimov@stripped
@@ -1623,6 +1623,7 @@ func_exit:
 			 UNIV_PAGE_SIZE);
 
 	if (b) {
+		ib_uint32_t	checksum;
 		/* Compute and stamp the compressed page
 		checksum while not holding any mutex.  The
 		block is already half-freed
@@ -1630,13 +1631,13 @@ func_exit:
 		buf_pool->page_hash, thus inaccessible by any
 		other thread. */
 
-		mach_write_to_4(
-			b->zip.data + FIL_PAGE_SPACE_OR_CHKSUM,
-			UNIV_LIKELY(srv_use_checksums)
-			? page_zip_calc_checksum(
-				b->zip.data,
-				page_zip_get_size(&b->zip))
-			: BUF_NO_CHECKSUM_MAGIC);
+		checksum = page_zip_calc_checksum(
+			b->zip.data,
+			page_zip_get_size(&b->zip),
+			srv_checksum_algorithm);
+
+		mach_write_to_4(b->zip.data + FIL_PAGE_SPACE_OR_CHKSUM,
+				checksum);
 	}
 
 	buf_pool_mutex_enter(buf_pool);

=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/handler/ha_innodb.cc	revid:vasil.dimov@stripped
@@ -197,6 +197,26 @@ static TYPELIB innodb_stats_method_typel
 	NULL
 };
 
+/** Possible values for system variable "innodb_checksum_algorithm". */
+static const char* innodb_checksum_algorithm_names[] = {
+	"crc32",
+	"strict_crc32",
+	"innodb",
+	"strict_innodb",
+	"none",
+	"strict_none",
+	NullS
+};
+
+/** Used to define an enumerate type of the system variable
+innodb_checksum_algorithm. */
+static TYPELIB innodb_checksum_algorithm_typelib = {
+	array_elements(innodb_checksum_algorithm_names) - 1,
+	"innodb_checksum_algorithm_typelib",
+	innodb_checksum_algorithm_names,
+	NULL
+};
+
 /* The following counter is used to convey information to InnoDB
 about server activity: in selects it is not sensible to call
 srv_active_wake_master_thread after each fetch or search, we only do
@@ -2715,7 +2735,16 @@ innobase_change_buffering_inited_ok:
 	srv_force_recovery = (ulint) innobase_force_recovery;
 
 	srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
-	srv_use_checksums = (ibool) innobase_use_checksums;
+	if (!innobase_use_checksums) {
+		ut_print_timestamp(stderr);
+		fprintf(stderr,
+			" InnoDB: Warning: Setting " 
+			"innodb_checksums to OFF is DEPRECATED. "
+			"This option may be removed in future releases. "
+			"You should set innodb_checksum_algorithm=NONE "
+			"instead.\n");
+		srv_checksum_algorithm = SRV_CHECKSUM_ALGORITHM_NONE;
+	}
 
 #ifdef HAVE_LARGE_PAGES
 	if ((os_use_large_pages = (ibool) my_use_large_pages)) {
@@ -12366,8 +12395,35 @@ static struct st_mysql_storage_engine in
 { MYSQL_HANDLERTON_INTERFACE_VERSION };
 
 /* plugin options */
+
+static MYSQL_SYSVAR_ENUM(checksum_algorithm, srv_checksum_algorithm,
+  PLUGIN_VAR_RQCMDARG,
+  "The algorithm InnoDB uses for page checksumming. Possible values are "
+  "CRC32 (hardware accelerated if the CPU supports it) "
+    "write crc32, allow any of the other checksums to match when reading; "
+  "STRICT_CRC32 "
+    "write crc32, do not allow other algorithms to match when reading; "
+  "INNODB "
+    "write a software calculated checksum, allow any other checksums "
+    "to match when reading; "
+  "STRICT_INNODB "
+    "write a software calculated checksum, do not allow other algorithms "
+    "to match when reading; "
+  "NONE "
+    "write a constant magic number, do not do any checksum verification "
+    "when reading (same as innodb_checksums=OFF); "
+  "STRICT_NONE "
+    "write a constant magic number, do not allow values other than that "
+    "magic number when reading; "
+  "Files updated when this option is set to crc32 or strict_crc32 will "
+  "not be readable by MySQL versions older than 5.6.3",
+  NULL, NULL, SRV_CHECKSUM_ALGORITHM_INNODB,
+  &innodb_checksum_algorithm_typelib);
+
 static MYSQL_SYSVAR_BOOL(checksums, innobase_use_checksums,
   PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
+  "DEPRECATED. Use innodb_checksum_algorithm=NONE instead of setting "
+  "this to OFF. "
   "Enable InnoDB checksums validation (enabled by default). "
   "Disable with --skip-innodb-checksums.",
   NULL, NULL, TRUE);
@@ -12876,6 +12932,7 @@ static struct st_mysql_sys_var* innobase
   MYSQL_SYSVAR(buffer_pool_load_at_startup),
   MYSQL_SYSVAR(lru_scan_depth),
   MYSQL_SYSVAR(flush_neighbors),
+  MYSQL_SYSVAR(checksum_algorithm),
   MYSQL_SYSVAR(checksums),
   MYSQL_SYSVAR(commit_concurrency),
   MYSQL_SYSVAR(concurrency_tickets),

=== modified file 'storage/innobase/include/buf0buf.h'
--- a/storage/innobase/include/buf0buf.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/buf0buf.h	revid:vasil.dimov@stripped
@@ -644,29 +644,6 @@ buf_block_buf_fix_inc_func(
 # define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b)
 #endif /* UNIV_SYNC_DEBUG */
 /********************************************************************//**
-Calculates a page checksum which is stored to the page when it is written
-to a file. Note that we must be careful to calculate the same value
-on 32-bit and 64-bit architectures.
-@return	checksum */
-UNIV_INTERN
-ulint
-buf_calc_page_new_checksum(
-/*=======================*/
-	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
-checksum.
-NOTE: we must first store the new formula checksum to
-FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
-because this takes that field as an input!
-@return	checksum */
-UNIV_INTERN
-ulint
-buf_calc_page_old_checksum(
-/*=======================*/
-	const byte*	 page);	/*!< in: buffer page */
-/********************************************************************//**
 Checks if a page is corrupt.
 @return	TRUE if corrupted */
 UNIV_INTERN

=== added file 'storage/innobase/include/buf0checksum.h'
--- a/storage/innobase/include/buf0checksum.h	1970-01-01 00:00:00 +0000
+++ b/storage/innobase/include/buf0checksum.h	revid:vasil.dimov@stripped
@@ -0,0 +1,78 @@
+/*****************************************************************************
+
+Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file buf/buf0checksum.c
+Buffer pool checksum functions, also linked from /extra/innochecksum.c
+
+Created Aug 11, 2011 Vasil Dimov
+*******************************************************/
+
+#ifndef buf0checksum_h
+#define buf0checksum_h
+
+#include "univ.i"
+
+#include "srv0srv.h" /* srv_checksum_algorithm_t */
+
+/********************************************************************//**
+Calculates a page CRC32 which is stored to the page when it is written
+to a file. Note that we must be careful to calculate the same value on
+32-bit and 64-bit architectures.
+@return	checksum */
+UNIV_INTERN
+ib_uint32_t
+buf_calc_page_crc32(
+/*================*/
+	const byte*	page);	/*!< in: buffer page */
+
+/********************************************************************//**
+Calculates a page checksum which is stored to the page when it is written
+to a file. Note that we must be careful to calculate the same value on
+32-bit and 64-bit architectures.
+@return	checksum */
+UNIV_INTERN
+ulint
+buf_calc_page_new_checksum(
+/*=======================*/
+	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
+checksum.
+NOTE: we must first store the new formula checksum to
+FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
+because this takes that field as an input!
+@return	checksum */
+UNIV_INTERN
+ulint
+buf_calc_page_old_checksum(
+/*=======================*/
+	const byte*	page);	/*!< in: buffer page */
+
+/********************************************************************//**
+Return a printable string describing the checksum algorithm.
+@return	algorithm name */
+UNIV_INTERN
+const char*
+buf_checksum_algorithm_name(
+/*========================*/
+	srv_checksum_algorithm_t	algo);	/*!< in: algorithm */
+
+#endif /* buf0checksum_h */

=== modified file 'storage/innobase/include/page0zip.h'
--- a/storage/innobase/include/page0zip.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/page0zip.h	revid:vasil.dimov@stripped
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2005, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 2005, 2011, Oracle and/or its affiliates. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -35,6 +35,7 @@ Created June 2005 by Marko Makela
 #include "page0types.h"
 #include "buf0types.h"
 #include "dict0types.h"
+#include "srv0srv.h"
 #include "trx0types.h"
 #include "mem0mem.h"
 
@@ -444,9 +445,21 @@ ulint
 page_zip_calc_checksum(
 /*===================*/
         const void*     data,   /*!< in: compressed page */
-        ulint           size)   /*!< in: size of compressed page */
+        ulint           size,   /*!< in: size of compressed page */
+	srv_checksum_algorithm_t algo) /*!< in: algorithm to use */
 	__attribute__((nonnull));
 
+/**********************************************************************//**
+Verify a compressed page's checksum.
+@return	TRUE if the stored checksum is valid according to the value of
+innodb_checksum_algorithm */
+UNIV_INTERN
+ibool
+page_zip_verify_checksum(
+/*=====================*/
+	const void*	data,	/*!< in: compressed page */
+	ulint		size);	/*!< in: size of compressed page */
+
 #ifndef UNIV_HOTBACKUP
 /** Check if a pointer to an uncompressed page matches a compressed page.
 @param ptr	pointer to an uncompressed page frame

=== modified file 'storage/innobase/include/srv0srv.h'
--- a/storage/innobase/include/srv0srv.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/srv0srv.h	revid:vasil.dimov@stripped
@@ -50,6 +50,25 @@ Created 10/10/1995 Heikki Tuuri
 #include "trx0types.h"
 #include "srv0conc.h"
 
+/** Alternatives for srv_checksum_algorithm, which can be changed by
+setting innodb_checksum_algorithm */
+enum srv_checksum_algorithm_enum {
+	SRV_CHECKSUM_ALGORITHM_CRC32,		/*!< Write crc32, allow crc32,
+						innodb or none when reading */
+	SRV_CHECKSUM_ALGORITHM_STRICT_CRC32,	/*!< Write crc32, allow crc32
+						when reading */
+	SRV_CHECKSUM_ALGORITHM_INNODB,		/*!< Write innodb, allow crc32,
+						innodb or none when reading */
+	SRV_CHECKSUM_ALGORITHM_STRICT_INNODB,	/*!< Write innodb, allow
+						innodb when reading */
+	SRV_CHECKSUM_ALGORITHM_NONE,		/*!< Write none, allow crc32,
+						innodb or none when reading */
+	SRV_CHECKSUM_ALGORITHM_STRICT_NONE,	/*!< Write none, allow none
+						when reading */
+};
+
+typedef enum srv_checksum_algorithm_enum	srv_checksum_algorithm_t;
+
 extern const char*	srv_main_thread_op_info;
 
 /** Prefix used by MySQL to indicate pre-5.1 table name encoding */
@@ -246,7 +265,7 @@ extern unsigned long long	srv_stats_pers
 
 extern ibool	srv_use_doublewrite_buf;
 extern ulong	srv_doublewrite_batch_size;
-extern ibool	srv_use_checksums;
+extern ulong	srv_checksum_algorithm;
 
 extern ulong	srv_max_buf_pool_modified_pct;
 extern ulong	srv_max_purge_lag;
@@ -810,7 +829,6 @@ struct srv_slot_struct{
 
 #else /* !UNIV_HOTBACKUP */
 # define srv_use_adaptive_hash_indexes		FALSE
-# define srv_use_checksums			TRUE
 # define srv_use_native_aio			FALSE
 # define srv_force_recovery			0UL
 # define srv_set_io_thread_op_info(t,info)	((void) 0)

=== modified file 'storage/innobase/include/univ.i'
--- a/storage/innobase/include/univ.i	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/univ.i	revid:vasil.dimov@stripped
@@ -391,8 +391,10 @@ database name and table name. In additio
 
 #if SIZEOF_INT == 4
 typedef unsigned int		ib_uint32_t;
+#define UINT32PF		"%u"
 #elif SIZEOF_LONG == 4
 typedef unsigned long		ib_uint32_t;
+#define UINT32PF		"%lu"
 #else
 #error "Neither int or long is 4 bytes"
 #endif

=== added file 'storage/innobase/include/ut0crc32.h'
--- a/storage/innobase/include/ut0crc32.h	1970-01-01 00:00:00 +0000
+++ b/storage/innobase/include/ut0crc32.h	revid:vasil.dimov@stripped
@@ -0,0 +1,50 @@
+/*****************************************************************************
+
+Copyright (c) 2011, 2011, Oracle and/or its affiliates. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file include/ut0crc32.h
+CRC32 implementation
+
+Created Aug 10, 2011 Vasil Dimov
+*******************************************************/
+
+#ifndef ut0crc32_h
+#define ut0crc32_h
+
+#include "univ.i"
+
+/********************************************************************//**
+Initializes the data structures used by ut_crc32(). Does not do any
+allocations, would not hurt if called twice, but would be pointless. */
+UNIV_INTERN
+void
+ut_crc32_init();
+/*===========*/
+
+/********************************************************************//**
+Calculates CRC32.
+@return CRC32 (CRC-32C, using the GF(2) primitive polynomial 0x11EDC6F41,
+or 0x1EDC6F41 without the high-order bit) */
+UNIV_INTERN
+ib_uint32_t
+(*ut_crc32)(
+/*========*/
+	const byte*	buf,	/*!< in: data over which to calculate CRC32 */
+	ulint		len);	/*!< in: data length */
+
+#endif /* ut0crc32_h */

=== modified file 'storage/innobase/page/page0zip.c'
--- a/storage/innobase/page/page0zip.c	revid:andrei.elkin@stripped
+++ b/storage/innobase/page/page0zip.c	revid:vasil.dimov@stripped
@@ -38,11 +38,14 @@ Created June 2005 by Marko Makela
 #include "log0recv.h"
 #include "zlib.h"
 #ifndef UNIV_HOTBACKUP
+# include "buf0buf.h"
 # include "buf0lru.h"
 # include "btr0sea.h"
 # include "dict0boot.h"
 # include "lock0lock.h"
 # include "srv0mon.h"
+# include "srv0srv.h"
+# include "ut0crc32.h"
 #else /* !UNIV_HOTBACKUP */
 # define lock_move_reorganize_page(block, temp_block)	((void) 0)
 # define buf_LRU_stat_inc_unzip()			((void) 0)
@@ -4675,21 +4678,111 @@ ulint
 page_zip_calc_checksum(
 /*===================*/
 	const void*	data,	/*!< in: compressed page */
-	ulint		size)	/*!< in: size of compressed page */
+	ulint		size,	/*!< in: size of compressed page */
+	srv_checksum_algorithm_t algo) /*!< in: algorithm to use */
 {
+	const Bytef*	s = data;
+	uLong		adler;
+	ib_uint32_t	crc32;
+
 	/* Exclude FIL_PAGE_SPACE_OR_CHKSUM, FIL_PAGE_LSN,
 	and FIL_PAGE_FILE_FLUSH_LSN from the checksum. */
 
-	const Bytef*	s	= data;
-	uLong		adler;
+	switch (algo) {
+	case SRV_CHECKSUM_ALGORITHM_CRC32:
+	case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
+
+		ut_ad(size > FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+
+		crc32 = ut_crc32(s + FIL_PAGE_OFFSET,
+				 FIL_PAGE_LSN - FIL_PAGE_OFFSET)
+			^ ut_crc32(s + FIL_PAGE_TYPE, 2)
+			^ ut_crc32(s + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
+				   size - FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+
+		return((ulint) crc32);
+	case SRV_CHECKSUM_ALGORITHM_INNODB:
+	case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
+		ut_ad(size > FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+
+		adler = adler32(0L, s + FIL_PAGE_OFFSET,
+				FIL_PAGE_LSN - FIL_PAGE_OFFSET);
+		adler = adler32(adler, s + FIL_PAGE_TYPE, 2);
+		adler = adler32(adler, s + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
+				size - FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+
+		return((ulint) adler);
+	case SRV_CHECKSUM_ALGORITHM_NONE:
+	case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
+		return(BUF_NO_CHECKSUM_MAGIC);
+	/* no default so the compiler will emit a warning if new enum
+	is added and not handled here */
+	}
+
+	ut_error;
+	return(0);
+}
+
+/**********************************************************************//**
+Verify a compressed page's checksum.
+@return	TRUE if the stored checksum is valid according to the value of
+innodb_checksum_algorithm */
+UNIV_INTERN
+ibool
+page_zip_verify_checksum(
+/*=====================*/
+	const void*	data,	/*!< in: compressed page */
+	ulint		size)	/*!< in: size of compressed page */
+{
+	ib_uint32_t	stored;
+	ib_uint32_t	calc;
+	ib_uint32_t	crc32 = 0 /* silence bogus warning */;
+	ib_uint32_t	innodb = 0 /* silence bogus warning */;
+
+	stored = mach_read_from_4(
+		(const unsigned char*) data + FIL_PAGE_SPACE_OR_CHKSUM);
+
+	/* declare empty pages non-corrupted */
+	if (stored == 0) {
+		/* make sure that the page is really empty */
+		ut_d(ulint i; for (i = 0; i < size; i++) {
+		     ut_a(*((const char*) data + i) == 0); });
+
+		return(TRUE);
+	}
+
+	calc = page_zip_calc_checksum(data, size, srv_checksum_algorithm);
 
-	ut_ad(size > FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+	if (stored == calc) {
+		return(TRUE);
+	}
 
-	adler = adler32(0L, s + FIL_PAGE_OFFSET,
-			FIL_PAGE_LSN - FIL_PAGE_OFFSET);
-	adler = adler32(adler, s + FIL_PAGE_TYPE, 2);
-	adler = adler32(adler, s + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
-			size - FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+	switch ((srv_checksum_algorithm_t) srv_checksum_algorithm) {
+	case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
+	case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
+	case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
+		return(stored == calc);
+	case SRV_CHECKSUM_ALGORITHM_CRC32:
+		if (stored == BUF_NO_CHECKSUM_MAGIC) {
+			return(TRUE);
+		}
+		crc32 = calc;
+		innodb = page_zip_calc_checksum(
+			data, size, SRV_CHECKSUM_ALGORITHM_INNODB);
+		break;
+	case SRV_CHECKSUM_ALGORITHM_INNODB:
+		if (stored == BUF_NO_CHECKSUM_MAGIC) {
+			return(TRUE);
+		}
+		crc32 = page_zip_calc_checksum(
+			data, size, SRV_CHECKSUM_ALGORITHM_CRC32);
+		innodb = calc;
+		break;
+	case SRV_CHECKSUM_ALGORITHM_NONE:
+		return(TRUE);
+	/* no default so the compiler will emit a warning if new enum
+	is added and not handled here */
+	}
 
-	return((ulint) adler);
+	return(stored == crc32 || stored == innodb);
 }

=== modified file 'storage/innobase/srv/srv0srv.c'
--- a/storage/innobase/srv/srv0srv.c	revid:andrei.elkin@stripped
+++ b/storage/innobase/srv/srv0srv.c	revid:vasil.dimov@stripped
@@ -65,6 +65,8 @@ Created 10/8/1995 Heikki Tuuri
 #include "trx0i_s.h"
 #include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */
 #include "srv0mon.h"
+#include "ut0crc32.h"
+
 #include "mysql/plugin.h"
 #include "mysql/service_thd_wait.h"
 
@@ -355,7 +357,12 @@ The following parameter is the size of t
 batch flushing i.e.: LRU flushing and flush_list flushing. The rest
 of the pages are used for single page flushing. */
 UNIV_INTERN ulong	srv_doublewrite_batch_size	= 120;
-UNIV_INTERN ibool	srv_use_checksums = TRUE;
+
+/** the macro MYSQL_SYSVAR_ENUM() requires "long unsigned int" and if we
+use srv_checksum_algorithm_t here then we get a compiler error:
+ha_innodb.cc:12251: error: cannot convert 'srv_checksum_algorithm_t*' to
+  'long unsigned int*' in initialization */
+UNIV_INTERN ulong	srv_checksum_algorithm = SRV_CHECKSUM_ALGORITHM_INNODB;
 
 UNIV_INTERN ulong	srv_replication_delay		= 0;
 
@@ -943,6 +950,8 @@ srv_init(void)
 
 	/* Initialize some INFORMATION SCHEMA internal structures */
 	trx_i_s_cache_init(trx_i_s_cache);
+
+	ut_crc32_init();
 }
 
 /*********************************************************************//**

=== added file 'storage/innobase/ut/ut0crc32.c'
--- a/storage/innobase/ut/ut0crc32.c	1970-01-01 00:00:00 +0000
+++ b/storage/innobase/ut/ut0crc32.c	revid:vasil.dimov@stripped
@@ -0,0 +1,320 @@
+/*****************************************************************************
+
+Copyright (C) 2009, 2010 Facebook, Inc. All Rights Reserved.
+Copyright (c) 2011, 2011, Oracle and/or its affiliates. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
+
+*****************************************************************************/
+
+/***************************************************************//**
+@file ut/ut0crc32.c
+CRC32 implementation from Facebook, based on the zlib implementation.
+
+Created Aug 8, 2011, Vasil Dimov, based on mysys/my_crc32.c and
+mysys/my_perf.c, contributed by Facebook under the following license.
+********************************************************************/
+
+/* Copyright (C) 2009-2010 Facebook, Inc.  All Rights Reserved.
+
+   Dual licensed under BSD license and GPLv2.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions are met:
+   1. Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+   THIS SOFTWARE IS PROVIDED BY FACEBOOK, INC. ``AS IS'' AND ANY EXPRESS OR
+   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
+   EVENT SHALL FACEBOOK, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+   OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   This program is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by the Free
+   Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+
+   You should have received a copy of the GNU General Public License along with
+   this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+   Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/* The below CRC32 implementation is based on the implementation included with
+ * zlib with modifications to process 8 bytes at a time and using SSE 4.2
+ * extentions when available.  The polynomial constant has been changed to
+ * match the one used by SSE 4.2 and does not return the same value as the
+ * version used by zlib.  This implementation only supports 64-bit
+ * little-endian processors.  The original zlib copyright notice follows. */
+
+/* crc32.c -- compute the CRC-32 of a buf stream
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@stripped> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of buf at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors.  This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+#include <string.h> /* memcmp() */
+
+#include "univ.i"
+#include "ut0crc32.h"
+
+/* Precalculated table used to generate the CRC32 if the CPU does not
+have support for it */
+static ib_uint32_t	ut_crc32_slice8_table[8][256];
+static ibool		ut_crc32_slice8_table_initialized = FALSE;
+
+/* Flag that tells whether the CPU supports CRC32 or not */
+static ibool		ut_crc32_sse2_enabled = FALSE;
+
+/********************************************************************//**
+Initializes the table that is used to generate the CRC32 if the CPU does
+not have support for it. */
+static
+void
+ut_crc32_slice8_table_init()
+/*========================*/
+{
+	/* bit-reversed poly 0x1EDC6F41 (from SSE42 crc32 instruction) */
+	static const ib_uint32_t	poly = 0x82f63b78;
+	ib_uint32_t			n;
+	ib_uint32_t			k;
+	ib_uint32_t			c;
+
+	for (n = 0; n < 256; n++) {
+		c = n;
+		for (k = 0; k < 8; k++) {
+			c = (c & 1) ? (poly ^ (c >> 1)) : (c >> 1);
+		}
+		ut_crc32_slice8_table[0][n] = c;
+	}
+
+	for (n = 0; n < 256; n++) {
+		c = ut_crc32_slice8_table[0][n];
+		for (k = 1; k < 8; k++) {
+			c = ut_crc32_slice8_table[0][c & 0xFF] ^ (c >> 8);
+			ut_crc32_slice8_table[k][n] = c;
+		}
+	}
+
+	ut_crc32_slice8_table_initialized = TRUE;
+}
+
+#if defined(__GNUC__) && defined(__x86_64__)
+/********************************************************************//**
+Fetches CPU info */
+static
+void
+ut_cpuid(
+/*=====*/
+	ib_uint32_t	vend[3],	/*!< out: CPU vendor */
+	ib_uint32_t*	model,		/*!< out: CPU model */
+	ib_uint32_t*	family,		/*!< out: CPU family */
+	ib_uint32_t*	stepping,	/*!< out: CPU stepping */
+	ib_uint32_t*	features_ecx,	/*!< out: CPU features ecx */
+	ib_uint32_t*	features_edx)	/*!< out: CPU features edx */
+{
+	ib_uint32_t	sig;
+	asm("cpuid" : "=b" (vend[0]), "=c" (vend[2]), "=d" (vend[1]) : "a" (0));
+	asm("cpuid" : "=a" (sig), "=c" (*features_ecx), "=d" (*features_edx)
+	    : "a" (1)
+	    : "ebx");
+
+	*model = ((sig >> 4) & 0xF);
+	*family = ((sig >> 8) & 0xF);
+	*stepping = (sig & 0xF);
+
+	if (memcmp(vend, "GenuineIntel", 12) == 0 ||
+	    (memcmp(vend, "AuthenticAMD", 12) == 0 && *family == 0xF)) {
+
+		*model += (((sig >> 16) & 0xF) << 4);
+		*family += ((sig >> 20) & 0xFF);
+	}
+}
+
+/* opcodes taken from objdump of "crc32b (%%rdx), %%rcx"
+for RHEL4 support (GCC 3 doesn't support this instruction) */
+#define ut_crc32_sse42_byte \
+	asm(".byte 0xf2, 0x48, 0x0f, 0x38, 0xf0, 0x0a" \
+	    : "=c"(crc) : "c"(crc), "d"(buf)); \
+	len--, buf++
+
+/* opcodes taken from objdump of "crc32q (%%rdx), %%rcx"
+for RHEL4 support (GCC 3 doesn't support this instruction) */
+#define ut_crc32_sse42_quadword \
+	asm(".byte 0xf2, 0x48, 0x0f, 0x38, 0xf1, 0x0a" \
+	    : "=c"(crc) : "c"(crc), "d"(buf)); \
+	len -= 8, buf += 8
+#endif /* defined(__GNUC__) && defined(__x86_64__) */
+
+/********************************************************************//**
+Calculates CRC32 using CPU instructions.
+@return CRC-32C (polynomial 0x11EDC6F41) */
+UNIV_INLINE
+ib_uint32_t
+ut_crc32_sse42(
+/*===========*/
+	const byte*	buf,	/*!< in: data over which to calculate CRC32 */
+	ulint		len)	/*!< in: data length */
+{
+#if defined(__GNUC__) && defined(__x86_64__)
+	ib_uint64_t	crc = (ib_uint32_t) (-1);
+
+	ut_a(ut_crc32_sse2_enabled);
+
+	while (len && ((ulint) buf & 7)) {
+		ut_crc32_sse42_byte;
+	}
+
+	while (len >= 32) {
+		ut_crc32_sse42_quadword;
+		ut_crc32_sse42_quadword;
+		ut_crc32_sse42_quadword;
+		ut_crc32_sse42_quadword;
+	}
+
+	while (len >= 8) {
+		ut_crc32_sse42_quadword;
+	}
+
+	while (len) {
+		ut_crc32_sse42_byte;
+	}
+
+	return((ib_uint32_t) ((~crc) & 0xFFFFFFFF));
+#else
+	ut_error;
+	/* silence compiler warning about unused parameters */
+	return((ib_uint32_t) buf[len]);
+#endif /* defined(__GNUC__) && defined(__x86_64__) */
+}
+
+#define ut_crc32_slice8_byte \
+	crc = (crc >> 8) ^ ut_crc32_slice8_table[0][(crc ^ *buf++) & 0xFF]; \
+	len--
+
+#define ut_crc32_slice8_quadword \
+	crc ^= *(ib_uint64_t*) buf; \
+	crc = ut_crc32_slice8_table[7][(crc      ) & 0xFF] ^ \
+	      ut_crc32_slice8_table[6][(crc >>  8) & 0xFF] ^ \
+	      ut_crc32_slice8_table[5][(crc >> 16) & 0xFF] ^ \
+	      ut_crc32_slice8_table[4][(crc >> 24) & 0xFF] ^ \
+	      ut_crc32_slice8_table[3][(crc >> 32) & 0xFF] ^ \
+	      ut_crc32_slice8_table[2][(crc >> 40) & 0xFF] ^ \
+	      ut_crc32_slice8_table[1][(crc >> 48) & 0xFF] ^ \
+	      ut_crc32_slice8_table[0][(crc >> 56)]; \
+	len -= 8, buf += 8
+
+/********************************************************************//**
+Calculates CRC32 manually.
+@return CRC-32C (polynomial 0x11EDC6F41) */
+UNIV_INLINE
+ib_uint32_t
+ut_crc32_slice8(
+/*============*/
+	const byte*	buf,	/*!< in: data over which to calculate CRC32 */
+	ulint		len)	/*!< in: data length */
+{
+	ib_uint64_t	crc = (ib_uint32_t) (-1);
+
+	ut_a(ut_crc32_slice8_table_initialized);
+
+	while (len && ((ulint) buf & 7)) {
+		ut_crc32_slice8_byte;
+	}
+
+	while (len >= 32) {
+		ut_crc32_slice8_quadword;
+		ut_crc32_slice8_quadword;
+		ut_crc32_slice8_quadword;
+		ut_crc32_slice8_quadword;
+	}
+
+	while (len >= 8) {
+		ut_crc32_slice8_quadword;
+	}
+
+	while (len) {
+		ut_crc32_slice8_byte;
+	}
+
+	return((ib_uint32_t) ((~crc) & 0xFFFFFFFF));
+}
+
+/********************************************************************//**
+Initializes the data structures used by ut_crc32(). Does not do any
+allocations, would not hurt if called twice, but would be pointless. */
+UNIV_INTERN
+void
+ut_crc32_init()
+/*===========*/
+{
+#if defined(__GNUC__) && defined(__x86_64__)
+	ib_uint32_t	vend[3];
+	ib_uint32_t	model;
+	ib_uint32_t	family;
+	ib_uint32_t	stepping;
+	ib_uint32_t	features_ecx;
+	ib_uint32_t	features_edx;
+
+	ut_cpuid(vend, &model, &family, &stepping,
+		 &features_ecx, &features_edx);
+
+	/* Valgrind does not understand the CRC32 instructions:
+
+	vex amd64->IR: unhandled instruction bytes: 0xF2 0x48 0xF 0x38 0xF0 0xA
+	valgrind: Unrecognised instruction at address 0xad3db5.
+	Your program just tried to execute an instruction that Valgrind
+	did not recognise.  There are two possible reasons for this.
+	1. Your program has a bug and erroneously jumped to a non-code
+	   location.  If you are running Memcheck and you just saw a
+	   warning about a bad jump, it's probably your program's fault.
+	2. The instruction is legitimate but Valgrind doesn't handle it,
+	   i.e. it's Valgrind's fault.  If you think this is the case or
+	   you are not sure, please let us know and we'll try to fix it.
+	Either way, Valgrind will now raise a SIGILL signal which will
+	probably kill your program.
+
+	*/
+#ifndef UNIV_DEBUG_VALGRIND
+	ut_crc32_sse2_enabled = (features_ecx >> 20) & 1;
+#endif /* UNIV_DEBUG_VALGRIND */
+
+#endif /* defined(__GNUC__) && defined(__x86_64__) */
+
+	if (ut_crc32_sse2_enabled) {
+		ut_crc32 = ut_crc32_sse42;
+	} else {
+		ut_crc32_slice8_table_init();
+		ut_crc32 = ut_crc32_slice8;
+	}
+
+	ut_print_timestamp(stderr);
+	fprintf(stderr, " InnoDB: CPU %s crc32 instructions\n",
+		ut_crc32_sse2_enabled ? "supports" : "does not support");
+}


Attachment: [text/bzr-bundle] bzr/vasil.dimov@oracle.com-20110822074651-jrkvgkvhj3h4tnk4.bundle
Thread
bzr commit into mysql-trunk branch (vasil.dimov:3396) WL#5652vasil.dimov22 Aug