diff options
333 files changed, 7749 insertions, 6243 deletions
diff --git a/.travis.yml b/.travis.yml index 54a6759e369..86ee6133089 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,6 @@ cache: timeout: 500 apt: true ccache: true - directories: - - /usr/local/Cellar # Fails do to permission error: https://github.com/travis-ci/travis-ci/issues/8092 addons: apt: @@ -155,7 +153,7 @@ jobs: script: *deb-script # Just one OS X build is enough - os: osx - osx_image: xcode11.3 + osx_image: xcode12u compiler: clang env: CC_VERSION=8 TYPE=RelWithDebInfo MYSQL_TEST_SUITES=main # Some chosen ones with s390x and gcc diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index c262b7d80bd..63fec217433 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -1182,7 +1182,7 @@ static int check_version_match(void) extract_variable_from_show(&ds_version, version_str)) { print_error("Version check failed. Got the following error when calling " - "the 'mysql' command line client", &ds_version); + "the 'mysql_upgrade' command line client", &ds_version); dynstr_free(&ds_version); return 1; /* Query failed */ } diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index a93d925db58..f3b6632cf5d 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -975,8 +975,12 @@ static bool print_row_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, my_b_printf(body_cache, "'%s\n", print_event_info->delimiter); // flush cache - if ((copy_event_cache_to_file_and_reinit(&print_event_info->head_cache, result_file) || - copy_event_cache_to_file_and_reinit(&print_event_info->body_cache, result_file))) + if ((copy_event_cache_to_file_and_reinit(&print_event_info->head_cache, + result_file) || + copy_event_cache_to_file_and_reinit(&print_event_info->body_cache, + result_file) || + copy_event_cache_to_file_and_reinit(&print_event_info->tail_cache, + result_file))) return 1; } } diff --git a/cmake/mariadb_connector_c.cmake b/cmake/mariadb_connector_c.cmake index b1d784ff39b..a9b103345cd 100644 --- a/cmake/mariadb_connector_c.cmake +++ b/cmake/mariadb_connector_c.cmake @@ -42,8 +42,7 @@ ADD_SUBDIRECTORY(libmariadb) IF(UNIX) INSTALL(CODE "EXECUTE_PROCESS( - COMMAND ${CMAKE_COMMAND} -E make_directory ${INSTALL_BINDIR} - WORKING_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}) + COMMAND ${CMAKE_COMMAND} -E make_directory \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${INSTALL_BINDIR}) EXECUTE_PROCESS( COMMAND ${CMAKE_COMMAND} -E create_symlink mariadb_config ${INSTALL_BINDIR}/mariadb-config WORKING_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX})" diff --git a/config.h.cmake b/config.h.cmake index ff0a039b3ac..5a48df0a135 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -102,12 +102,6 @@ /* Libraries */ #cmakedefine HAVE_LIBWRAP 1 #cmakedefine HAVE_SYSTEMD 1 -#cmakedefine HAVE_CRC32_VPMSUM 1 - -/* Support ARMv8 crc + crypto */ -#cmakedefine HAVE_ARMV8_CRC 1 -#cmakedefine HAVE_ARMV8_CRYPTO 1 -#cmakedefine HAVE_ARMV8_CRC_CRYPTO_INTRINSICS 1 /* Does "struct timespec" have a "sec" and "nsec" field? */ #cmakedefine HAVE_TIMESPEC_TS_SEC 1 diff --git a/extra/CMakeLists.txt b/extra/CMakeLists.txt index b7b1d215711..8f4c434ed34 100644 --- a/extra/CMakeLists.txt +++ b/extra/CMakeLists.txt @@ -73,20 +73,8 @@ IF(WITH_INNOBASE_STORAGE_ENGINE) # We use the InnoDB code directly in case the code changes. ADD_DEFINITIONS("-DUNIV_INNOCHECKSUM") - # Avoid generating Hardware Capabilities due to crc32 instructions - IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_SYSTEM_PROCESSOR MATCHES "i386") - MY_CHECK_CXX_COMPILER_FLAG("-Wa,-nH") - IF(have_CXX__Wa__nH) - ADD_COMPILE_FLAGS( - ../storage/innobase/ut/ut0crc32.cc - COMPILE_FLAGS "-Wa,-nH" - ) - ENDIF() - ENDIF() - SET(INNOBASE_SOURCES ../storage/innobase/buf/buf0checksum.cc - ../storage/innobase/ut/ut0crc32.cc ../storage/innobase/ut/ut0ut.cc ../storage/innobase/buf/buf0buf.cc ../storage/innobase/page/page0zip.cc diff --git a/extra/innochecksum.cc b/extra/innochecksum.cc index d8d043d89b9..7805dc4283f 100644 --- a/extra/innochecksum.cc +++ b/extra/innochecksum.cc @@ -1583,7 +1583,6 @@ int main( /* enable when space_id of given file is zero. */ bool is_system_tablespace = false; - ut_crc32_init(); MY_INIT(argv[0]); DBUG_ENTER("main"); DBUG_PROCESS(argv[0]); diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index c4dee56edd1..4ad14dc4740 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -1786,7 +1786,6 @@ copy_back() srv_max_n_threads = 1000; sync_check_init(); - ut_crc32_init(); /* copy undo tablespaces */ diff --git a/extra/mariabackup/backup_mysql.cc b/extra/mariabackup/backup_mysql.cc index 6d804f78e15..83e877ea9bb 100644 --- a/extra/mariabackup/backup_mysql.cc +++ b/extra/mariabackup/backup_mysql.cc @@ -1083,6 +1083,7 @@ write_slave_info(MYSQL *connection) char *master = NULL; char *filename = NULL; char *gtid_executed = NULL; + char *using_gtid = NULL; char *position = NULL; char *gtid_slave_pos = NULL; char *ptr; @@ -1093,6 +1094,7 @@ write_slave_info(MYSQL *connection) {"Relay_Master_Log_File", &filename}, {"Exec_Master_Log_Pos", &position}, {"Executed_Gtid_Set", >id_executed}, + {"Using_Gtid", &using_gtid}, {NULL, NULL} }; @@ -1133,7 +1135,8 @@ write_slave_info(MYSQL *connection) ut_a(asprintf(&mysql_slave_position, "master host '%s', purge list '%s'", master, gtid_executed) != -1); - } else if (gtid_slave_pos && *gtid_slave_pos) { + } else if (gtid_slave_pos && *gtid_slave_pos && + !(using_gtid && !strncmp(using_gtid, "No", 2))) { /* MariaDB >= 10.0 with GTID enabled */ result = backup_file_printf(XTRABACKUP_SLAVE_INFO, "SET GLOBAL gtid_slave_pos = '%s';\n" diff --git a/extra/mariabackup/write_filt.cc b/extra/mariabackup/write_filt.cc index 8c4d2345f91..d8910699d16 100644 --- a/extra/mariabackup/write_filt.cc +++ b/extra/mariabackup/write_filt.cc @@ -28,7 +28,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA #include "write_filt.h" #include "fil_cur.h" #include "xtrabackup.h" -#include <os0proc.h> /************************************************************************ Write-through page write filter. */ diff --git a/extra/mariabackup/xbstream.cc b/extra/mariabackup/xbstream.cc index 761b8e69890..c22c7cc8f39 100644 --- a/extra/mariabackup/xbstream.cc +++ b/extra/mariabackup/xbstream.cc @@ -97,8 +97,6 @@ main(int argc, char **argv) { MY_INIT(argv[0]); - my_checksum_init(); - if (get_options(&argc, &argv)) { goto err; } diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 6949975f7ef..6442139f17d 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -2689,6 +2689,7 @@ static bool xtrabackup_copy_logfile(bool last = false) ut_a(dst_log_file != NULL); ut_ad(recv_sys.is_initialised()); + bool overwritten_block = false; lsn_t start_lsn; lsn_t end_lsn; @@ -2714,6 +2715,11 @@ static bool xtrabackup_copy_logfile(bool last = false) } if (lsn == start_lsn) { + overwritten_block= !recv_sys.found_corrupt_log + && log_block_calc_checksum_crc32(log_sys.buf) == + log_block_get_checksum(log_sys.buf) + && log_block_get_hdr_no(log_sys.buf) > + log_block_convert_lsn_to_no(start_lsn); start_lsn = 0; } else { mutex_enter(&recv_sys.mutex); @@ -2724,9 +2730,13 @@ static bool xtrabackup_copy_logfile(bool last = false) log_mutex_exit(); if (!start_lsn) { - die(recv_sys.found_corrupt_log - ? "xtrabackup_copy_logfile() failed: corrupt log." - : "xtrabackup_copy_logfile() failed."); + const char *reason = recv_sys.found_corrupt_log + ? "corrupt log." + : (overwritten_block + ? "redo log block is overwritten, please increase redo log size with innodb_log_file_size parameter." + : "redo log block checksum does not match."); + + die("xtrabackup_copy_logfile() failed: %s", reason); return true; } } while (start_lsn == end_lsn); @@ -4002,9 +4012,6 @@ fail: ut_d(sync_check_enable()); /* Reset the system variables in the recovery module. */ trx_pool_init(); - - ut_crc32_init(); - my_checksum_init(); recv_sys.create(); #ifdef WITH_INNODB_DISALLOW_WRITES @@ -5377,7 +5384,6 @@ static bool xtrabackup_prepare_func(char** argv) sync_check_init(); ut_d(sync_check_enable()); - ut_crc32_init(); recv_sys.create(); log_sys.create(); recv_sys.recovery_on = true; diff --git a/extra/wolfssl/CMakeLists.txt b/extra/wolfssl/CMakeLists.txt index 8fe79dccf3d..953d377ebcf 100644 --- a/extra/wolfssl/CMakeLists.txt +++ b/extra/wolfssl/CMakeLists.txt @@ -19,6 +19,8 @@ ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64") MY_CHECK_C_COMPILER_FLAG(-maes) MY_CHECK_C_COMPILER_FLAG(-msse4) MY_CHECK_C_COMPILER_FLAG(-mpclmul) + MY_CHECK_C_COMPILER_FLAG(-mrdrnd) + MY_CHECK_C_COMPILER_FLAG(-mrdseed) IF(have_C__maes AND have_C__msse4 AND have_C__mpclmul) SET(WOLFSSL_INTELASM ON) ENDIF() @@ -113,20 +115,27 @@ IF(WOLFSSL_INTELASM) LIST(APPEND WOLFCRYPT_SOURCES ${WOLFCRYPT_SRCDIR}/cpuid.c) IF(MSVC) LIST(APPEND WOLFCRYPT_SOURCES ${WOLFCRYPT_SRCDIR}/aes_asm.asm) + SET(WOLFSSL_X86_64_BUILD 1) + SET(HAVE_INTEL_RDSEED 1) + SET(HAVE_INTEL_RDRAND 1) IF(CMAKE_C_COMPILER_ID MATCHES Clang) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes") - ELSE() - SET(HAVE_INTEL_RDSEED 1) - SET(WOLFSSL_X86_64_BUILD 1) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes -msse4.2 -mpclmul -mrdrnd -mrdseed") ENDIF() ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64") - SET(HAVE_INTEL_RDSEED 1) SET(USE_INTEL_SPEEDUP 1) LIST(APPEND WOLFCRYPT_SOURCES ${WOLFCRYPT_SRCDIR}/aes_asm.S ${WOLFCRYPT_SRCDIR}/sha512_asm.S ${WOLFCRYPT_SRCDIR}/sha256_asm.S) ADD_DEFINITIONS(-maes -msse4 -mpclmul) + IF(have_C__mrdrnd) + SET(HAVE_INTEL_RDRAND 1) + ADD_DEFINITIONS(-mrdrnd) + ENDIF() + IF(have_C__mrdseed) + SET(HAVE_INTEL_RDSEED 1) + ADD_DEFINITIONS(-mrdseed) + ENDIF() ENDIF() ENDIF() diff --git a/extra/wolfssl/user_settings.h.in b/extra/wolfssl/user_settings.h.in index 98f05079e05..e381e87ce71 100644 --- a/extra/wolfssl/user_settings.h.in +++ b/extra/wolfssl/user_settings.h.in @@ -32,6 +32,7 @@ #cmakedefine USE_FAST_MATH #cmakedefine TFM_TIMING_RESISTANT #cmakedefine HAVE_INTEL_RDSEED +#cmakedefine HAVE_INTEL_RDRAND #cmakedefine USE_INTEL_SPEEDUP #cmakedefine USE_FAST_MATH #cmakedefine WOLFSSL_X86_64_BUILD diff --git a/include/my_atomic_wrapper.h b/include/my_atomic_wrapper.h index 61db886d53f..64835e30ca7 100644 --- a/include/my_atomic_wrapper.h +++ b/include/my_atomic_wrapper.h @@ -48,6 +48,8 @@ public: { return m.fetch_add(i, o); } Type fetch_sub(const Type i, std::memory_order o= std::memory_order_relaxed) { return m.fetch_sub(i, o); } + Type fetch_xor(const Type i, std::memory_order o= std::memory_order_relaxed) + { return m.fetch_xor(i, o); } bool compare_exchange_strong(Type& i1, const Type i2, std::memory_order o1= std::memory_order_relaxed, std::memory_order o2= std::memory_order_relaxed) diff --git a/include/my_cpu.h b/include/my_cpu.h index fba04ccea66..e536ff285f9 100644 --- a/include/my_cpu.h +++ b/include/my_cpu.h @@ -53,6 +53,7 @@ #ifdef _WIN32 #elif defined HAVE_PAUSE_INSTRUCTION #elif defined(_ARCH_PWR8) +#elif defined __GNUC__ && (defined __arm__ || defined __aarch64__) #else # include "my_global.h" # include "my_atomic.h" @@ -81,6 +82,9 @@ static inline void MY_RELAX_CPU(void) #endif #elif defined(_ARCH_PWR8) __ppc_get_timebase(); +#elif defined __GNUC__ && (defined __arm__ || defined __aarch64__) + /* Mainly, prevent the compiler from optimizing away delay loops */ + __asm__ __volatile__ ("":::"memory"); #else int32 var, oldval = 0; my_atomic_cas32_strong_explicit(&var, &oldval, 1, MY_MEMORY_ORDER_RELAXED, diff --git a/include/my_sys.h b/include/my_sys.h index 68e52d13fff..dceae9b889e 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -905,18 +905,10 @@ extern int my_compress_buffer(uchar *dest, size_t *destLen, extern int packfrm(const uchar *, size_t, uchar **, size_t *); extern int unpackfrm(uchar **, size_t *, const uchar *); -void my_checksum_init(void); -#ifdef HAVE_CRC32_VPMSUM -extern ha_checksum my_checksum(ha_checksum, const void *, size_t); -#else -typedef ha_checksum (*my_crc32_t)(ha_checksum, const void *, size_t); -extern MYSQL_PLUGIN_IMPORT my_crc32_t my_checksum; -#endif +extern uint32 my_checksum(uint32, const void *, size_t); +extern uint32 my_crc32c(uint32, const void *, size_t); -#if defined(__GNUC__) && defined(HAVE_ARMV8_CRC) -int crc32_aarch64_available(void); -const char *crc32c_aarch64_available(void); -#endif +extern const char *my_crc32c_implementation(); #ifdef DBUG_ASSERT_EXISTS extern void my_debug_put_break_here(void); diff --git a/include/mysql/service_wsrep.h b/include/mysql/service_wsrep.h index 1b1d54c036b..f16331f1214 100644 --- a/include/mysql/service_wsrep.h +++ b/include/mysql/service_wsrep.h @@ -88,6 +88,8 @@ extern struct wsrep_service_st { my_bool (*wsrep_thd_has_ignored_error_func)(const MYSQL_THD thd); void (*wsrep_thd_set_ignored_error_func)(MYSQL_THD thd, my_bool val); bool (*wsrep_thd_set_wsrep_aborter_func)(MYSQL_THD bf_thd, MYSQL_THD thd); + void (*wsrep_report_bf_lock_wait_func)(const MYSQL_THD thd, + unsigned long long trx_id); } *wsrep_service; #define MYSQL_SERVICE_WSREP_INCLUDED @@ -132,6 +134,7 @@ extern struct wsrep_service_st { #define wsrep_thd_has_ignored_error(T) wsrep_service->wsrep_thd_has_ignored_error_func(T) #define wsrep_thd_set_ignored_error(T,V) wsrep_service->wsrep_thd_set_ignored_error_func(T,V) #define wsrep_thd_set_wsrep_aborter(T) wsrep_service->wsrep_thd_set_wsrep_aborter_func(T1, T2) +#define wsrep_report_bf_lock_wait(T,I) wsrep_service->wsrep_report_bf_lock_wait(T,I) #else #define MYSQL_SERVICE_WSREP_STATIC_INCLUDED @@ -229,5 +232,7 @@ extern "C" ulong wsrep_OSU_method_get(const MYSQL_THD thd); extern "C" my_bool wsrep_thd_has_ignored_error(const MYSQL_THD thd); extern "C" void wsrep_thd_set_ignored_error(MYSQL_THD thd, my_bool val); extern "C" bool wsrep_thd_set_wsrep_aborter(MYSQL_THD bf_thd, MYSQL_THD victim_thd); +extern "C" void wsrep_report_bf_lock_wait(const THD *thd, + unsigned long long trx_id); #endif #endif /* MYSQL_SERVICE_WSREP_INCLUDED */ diff --git a/mysql-test/suite/galera/include/have_mariabackup.inc b/mysql-test/include/have_mariabackup.inc index 6c4ad240172..6c4ad240172 100644 --- a/mysql-test/suite/galera/include/have_mariabackup.inc +++ b/mysql-test/include/have_mariabackup.inc diff --git a/mysql-test/include/innodb_prefix_index_cluster_optimization.combinations b/mysql-test/include/innodb_prefix_index_cluster_optimization.combinations new file mode 100644 index 00000000000..ad82f82aa9d --- /dev/null +++ b/mysql-test/include/innodb_prefix_index_cluster_optimization.combinations @@ -0,0 +1,5 @@ +[covering] +innodb_prefix_index_cluster_optimization=on + +[unoptimized] +innodb_prefix_index_cluster_optimization=off diff --git a/mysql-test/include/innodb_prefix_index_cluster_optimization.inc b/mysql-test/include/innodb_prefix_index_cluster_optimization.inc new file mode 100644 index 00000000000..c841fece702 --- /dev/null +++ b/mysql-test/include/innodb_prefix_index_cluster_optimization.inc @@ -0,0 +1 @@ +--source include/have_innodb.inc diff --git a/mysql-test/lib/My/ConfigFactory.pm b/mysql-test/lib/My/ConfigFactory.pm index db5c1aa1875..3249a06256c 100644 --- a/mysql-test/lib/My/ConfigFactory.pm +++ b/mysql-test/lib/My/ConfigFactory.pm @@ -347,7 +347,7 @@ sub resolve_at_variable { or croak "There is no group named '$group_name' that ", "can be used to resolve '$option_name' for test '$self->{testname}'"; - my $value= $from_group->value($option_name); + my $value= $from_group->value($option_name) || ''; $res .= $before.$value; } $res .= $after; diff --git a/mysql-test/main/ctype_utf8.result b/mysql-test/main/ctype_utf8.result index 419f64d1489..f9d99d7f246 100644 --- a/mysql-test/main/ctype_utf8.result +++ b/mysql-test/main/ctype_utf8.result @@ -10537,6 +10537,18 @@ SELECT CONVERT(1, CHAR) IN ('100', '10', '1'); CONVERT(1, CHAR) IN ('100', '10', '1') 1 # +# MDEV-23535 SIGSEGV, SIGABRT and SIGILL in typeinfo for Item_func_set_collation (on optimized builds) +# +SET NAMES utf8; +CREATE OR REPLACE TABLE t1(a DATETIME) ENGINE=MYISAM; +INSERT INTO t1 VALUES ('2019-03-10 02:55:05'); +CREATE OR REPLACE TABLE t2(a VARCHAR(50) CHARACTER SET latin1) ENGINE=MYISAM; +INSERT INTO t2 VALUES ('2019-03-10 02:55:05'); +SELECT * FROM t1 WHERE (SELECT 1,CONCAT(a) FROM t1) = (SELECT 1,CONCAT(a) FROM t2); +a +2019-03-10 02:55:05 +DROP TABLE t1, t2; +# # End of 10.1 tests # # diff --git a/mysql-test/main/ctype_utf8.test b/mysql-test/main/ctype_utf8.test index 5fd19d1b245..01e5a0e8c80 100644 --- a/mysql-test/main/ctype_utf8.test +++ b/mysql-test/main/ctype_utf8.test @@ -2052,6 +2052,18 @@ SELECT CONVERT(1, CHAR) IN ('100', 10, '101'); SELECT CONVERT(1, CHAR) IN ('100', 10, '1'); SELECT CONVERT(1, CHAR) IN ('100', '10', '1'); +--echo # +--echo # MDEV-23535 SIGSEGV, SIGABRT and SIGILL in typeinfo for Item_func_set_collation (on optimized builds) +--echo # + +SET NAMES utf8; +CREATE OR REPLACE TABLE t1(a DATETIME) ENGINE=MYISAM; +INSERT INTO t1 VALUES ('2019-03-10 02:55:05'); +CREATE OR REPLACE TABLE t2(a VARCHAR(50) CHARACTER SET latin1) ENGINE=MYISAM; +INSERT INTO t2 VALUES ('2019-03-10 02:55:05'); +SELECT * FROM t1 WHERE (SELECT 1,CONCAT(a) FROM t1) = (SELECT 1,CONCAT(a) FROM t2); +DROP TABLE t1, t2; + --echo # --echo # End of 10.1 tests diff --git a/mysql-test/main/drop_table_force.result b/mysql-test/main/drop_table_force.result index d3142887ade..622589eb3b9 100644 --- a/mysql-test/main/drop_table_force.result +++ b/mysql-test/main/drop_table_force.result @@ -120,3 +120,12 @@ flush tables; drop table t2; ERROR 42S02: Unknown table 'test.t2' db.opt +# +# MDEV-23549 CREATE fails after DROP without FRM +# +create table t1 (a int); +select * from t1; +a +drop table t1; +create table t1 (a int); +drop table t1; diff --git a/mysql-test/main/drop_table_force.test b/mysql-test/main/drop_table_force.test index 518b4e754c3..f3073e3b67d 100644 --- a/mysql-test/main/drop_table_force.test +++ b/mysql-test/main/drop_table_force.test @@ -213,3 +213,14 @@ flush tables; --error ER_BAD_TABLE_ERROR drop table t2; --list_files $DATADIR/test/ + +--echo # +--echo # MDEV-23549 CREATE fails after DROP without FRM +--echo # +create table t1 (a int); +select * from t1; +--remove_file $datadir/test/t1.frm + +drop table t1; +create table t1 (a int); +drop table t1; diff --git a/mysql-test/main/fast_prefix_index_fetch_innodb.result b/mysql-test/main/fast_prefix_index_fetch_innodb.result index c6d96389b08..ef297e5c6b5 100644 --- a/mysql-test/main/fast_prefix_index_fetch_innodb.result +++ b/mysql-test/main/fast_prefix_index_fetch_innodb.result @@ -1,4 +1,4 @@ -drop table if exists prefixinno; +SET @save_opt= @@GLOBAL.innodb_prefix_index_cluster_optimization; set global innodb_prefix_index_cluster_optimization = ON; show variables like 'innodb_prefix_index_cluster_optimization'; Variable_name Value @@ -346,10 +346,10 @@ f1 🐱🌑 select @cluster_lookups; @cluster_lookups -2 +1 select @cluster_lookups_avoided; @cluster_lookups_avoided -0 +1 # Eligible - record length is shorter than prefix length SELECT f1 FROM t1 FORCE INDEX (`f1`) WHERE f1 like '🌑%'; f1 @@ -366,10 +366,10 @@ f1 🌒 select @cluster_lookups; @cluster_lookups -1 +0 select @cluster_lookups_avoided; @cluster_lookups_avoided -1 +2 DROP TABLE t1; CREATE TABLE t1( col1 INT, @@ -398,4 +398,60 @@ select @cluster_lookups_avoided; @cluster_lookups_avoided 0 DROP TABLE t1; -set global innodb_prefix_index_cluster_optimization = OFF; +# +# MDEV-20464 Division by 0 in row_search_with_covering_prefix() +# +CREATE TABLE t1 (f1 INT, f2 INT AS (f1), f3 INT AS (f1), f4 INT AS (f1), +KEY (f1,f2,f3)) ENGINE=InnoDB; +INSERT INTO t1 (f1) VALUES (NULL),(0); +SELECT f1, MAX(f3), COUNT(f4) FROM t1 GROUP BY f1; +f1 MAX(f3) COUNT(f4) +NULL NULL 0 +0 0 1 +DROP TABLE t1; +# +# MDEV-23600 Division by 0 in row_search_with_covering_prefix() +# +CREATE TABLE t(c POINT UNIQUE) ENGINE=InnoDB; +INSERT t SET c=POINT(1,1); +SELECT * FROM t WHERE c > (SELECT MAX(c) FROM t); +c +DROP TABLE t; +# +# MDEV-12486 Wrong results with innodb_prefix_index_cluster_optimization +# +CREATE TABLE wp_blogs ( +blog_id bigint(20) NOT NULL auto_increment, +site_id bigint(20) NOT NULL default '0', +domain varchar(200) NOT NULL default '', +path varchar(100) NOT NULL default '', +registered datetime NOT NULL default '0000-00-00 00:00:00', +last_updated datetime NOT NULL default '0000-00-00 00:00:00', +public tinyint(2) NOT NULL default '1', +archived tinyint(2) NOT NULL default '0', +mature tinyint(2) NOT NULL default '0', +spam tinyint(2) NOT NULL default '0', +deleted tinyint(2) NOT NULL default '0', +lang_id int(11) NOT NULL default '0', +PRIMARY KEY (blog_id), +KEY domain (domain(50),path(5)), +KEY lang_id (lang_id) +) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; +INSERT INTO wp_blogs (domain, path) VALUES +('domain.no', '/fondsinvesteringer/'), ('domain.no', '/'), +('foo', 'bar'), ('bar', 'foo'), ('foo', 'foo'), ('bar', 'bar'), +('foo', 'foobar'), ('bar', 'foobar'), ('foobar', 'foobar'); +SET GLOBAL innodb_prefix_index_cluster_optimization=off; +SELECT blog_id FROM wp_blogs WHERE domain IN ('domain.no') +AND path IN ( '/fondsinvesteringer/', '/' ); +blog_id +2 +1 +SET GLOBAL innodb_prefix_index_cluster_optimization=on; +SELECT blog_id FROM wp_blogs WHERE domain IN ('domain.no') +AND path IN ( '/fondsinvesteringer/', '/' ); +blog_id +2 +1 +DROP TABLE wp_blogs; +SET GLOBAL innodb_prefix_index_cluster_optimization = @save_opt; diff --git a/mysql-test/main/fast_prefix_index_fetch_innodb.test b/mysql-test/main/fast_prefix_index_fetch_innodb.test index c3b3440d82d..1987416ff87 100644 --- a/mysql-test/main/fast_prefix_index_fetch_innodb.test +++ b/mysql-test/main/fast_prefix_index_fetch_innodb.test @@ -1,9 +1,6 @@ -- source include/have_innodb.inc ---disable_warnings -drop table if exists prefixinno; ---enable_warnings - +SET @save_opt= @@GLOBAL.innodb_prefix_index_cluster_optimization; set global innodb_prefix_index_cluster_optimization = ON; show variables like 'innodb_prefix_index_cluster_optimization'; @@ -665,4 +662,58 @@ select @cluster_lookups; select @cluster_lookups_avoided; DROP TABLE t1; -set global innodb_prefix_index_cluster_optimization = OFF; + +--echo # +--echo # MDEV-20464 Division by 0 in row_search_with_covering_prefix() +--echo # +CREATE TABLE t1 (f1 INT, f2 INT AS (f1), f3 INT AS (f1), f4 INT AS (f1), + KEY (f1,f2,f3)) ENGINE=InnoDB; +INSERT INTO t1 (f1) VALUES (NULL),(0); +SELECT f1, MAX(f3), COUNT(f4) FROM t1 GROUP BY f1; +DROP TABLE t1; + +--echo # +--echo # MDEV-23600 Division by 0 in row_search_with_covering_prefix() +--echo # +CREATE TABLE t(c POINT UNIQUE) ENGINE=InnoDB; +INSERT t SET c=POINT(1,1); +SELECT * FROM t WHERE c > (SELECT MAX(c) FROM t); +DROP TABLE t; + +--echo # +--echo # MDEV-12486 Wrong results with innodb_prefix_index_cluster_optimization +--echo # +CREATE TABLE wp_blogs ( + blog_id bigint(20) NOT NULL auto_increment, + site_id bigint(20) NOT NULL default '0', + domain varchar(200) NOT NULL default '', + path varchar(100) NOT NULL default '', + registered datetime NOT NULL default '0000-00-00 00:00:00', + last_updated datetime NOT NULL default '0000-00-00 00:00:00', + public tinyint(2) NOT NULL default '1', + archived tinyint(2) NOT NULL default '0', + mature tinyint(2) NOT NULL default '0', + spam tinyint(2) NOT NULL default '0', + deleted tinyint(2) NOT NULL default '0', + lang_id int(11) NOT NULL default '0', + PRIMARY KEY (blog_id), + KEY domain (domain(50),path(5)), + KEY lang_id (lang_id) +) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; + +INSERT INTO wp_blogs (domain, path) VALUES +('domain.no', '/fondsinvesteringer/'), ('domain.no', '/'), +('foo', 'bar'), ('bar', 'foo'), ('foo', 'foo'), ('bar', 'bar'), +('foo', 'foobar'), ('bar', 'foobar'), ('foobar', 'foobar'); + +SET GLOBAL innodb_prefix_index_cluster_optimization=off; +SELECT blog_id FROM wp_blogs WHERE domain IN ('domain.no') +AND path IN ( '/fondsinvesteringer/', '/' ); + +SET GLOBAL innodb_prefix_index_cluster_optimization=on; +SELECT blog_id FROM wp_blogs WHERE domain IN ('domain.no') +AND path IN ( '/fondsinvesteringer/', '/' ); + +DROP TABLE wp_blogs; + +SET GLOBAL innodb_prefix_index_cluster_optimization = @save_opt; diff --git a/mysql-test/main/func_math.result b/mysql-test/main/func_math.result index 5da1ab02159..37188dab623 100644 --- a/mysql-test/main/func_math.result +++ b/mysql-test/main/func_math.result @@ -3591,5 +3591,11 @@ t2 CREATE TABLE `t2` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2, t1; # +# MDEV-23680 Assertion `data' failed in crcr32_calc_pclmulqdq +# +SELECT CRC32(ExtractValue('<a><b/></a>', '/a/b')) AS f; +f +0 +# # End of 10.5 tests # diff --git a/mysql-test/main/func_math.test b/mysql-test/main/func_math.test index 7f8fe9e7e73..6bce8bdaad6 100644 --- a/mysql-test/main/func_math.test +++ b/mysql-test/main/func_math.test @@ -1883,6 +1883,11 @@ CREATE TABLE t2 AS SELECT UUID_SHORT() - a FROM t1; SHOW CREATE TABLE t2; DROP TABLE t2, t1; +--echo # +--echo # MDEV-23680 Assertion `data' failed in crcr32_calc_pclmulqdq +--echo # +SELECT CRC32(ExtractValue('<a><b/></a>', '/a/b')) AS f; + --echo # --echo # End of 10.5 tests diff --git a/mysql-test/main/innodb_ext_key,off.rdiff b/mysql-test/main/innodb_ext_key,off.rdiff new file mode 100644 index 00000000000..195456958d8 --- /dev/null +++ b/mysql-test/main/innodb_ext_key,off.rdiff @@ -0,0 +1,295 @@ +@@ -9,7 +9,7 @@ + explain + select count(*) from lineitem where l_orderkey=130 and l_shipdate='1992-07-01'; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE lineitem ref PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate 8 const,const 1 Using index ++1 SIMPLE lineitem ref PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity PRIMARY 4 const 5 Using where + flush status; + select count(*) from lineitem where l_orderkey=130 and l_shipdate='1992-07-01'; + count(*) +@@ -19,7 +19,7 @@ + Handler_read_first 0 + Handler_read_key 1 + Handler_read_last 0 +-Handler_read_next 1 ++Handler_read_next 5 + Handler_read_prev 0 + Handler_read_retry 0 + Handler_read_rnd 0 +@@ -50,7 +50,7 @@ + select count(*) from lineitem + where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE lineitem range PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate 8 NULL 1 Using where; Using index ++1 SIMPLE lineitem ref PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate 4 const 6 Using where; Using index + flush status; + select count(*) from lineitem + where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000; +@@ -61,7 +61,7 @@ + Handler_read_first 0 + Handler_read_key 1 + Handler_read_last 0 +-Handler_read_next 1 ++Handler_read_next 6 + Handler_read_prev 0 + Handler_read_retry 0 + Handler_read_rnd 0 +@@ -71,7 +71,7 @@ + select l_orderkey, l_linenumber from lineitem + where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE lineitem range PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate 8 NULL 3 Using where; Using index ++1 SIMPLE lineitem ref PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate 4 const 6 Using where; Using index + flush status; + select l_orderkey, l_linenumber from lineitem + where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; +@@ -84,7 +84,7 @@ + Handler_read_first 0 + Handler_read_key 1 + Handler_read_last 0 +-Handler_read_next 3 ++Handler_read_next 6 + Handler_read_prev 0 + Handler_read_retry 0 + Handler_read_rnd 0 +@@ -93,7 +93,7 @@ + explain + select min(l_orderkey) from lineitem where l_shipdate='1992-07-01'; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away ++1 SIMPLE lineitem ref i_l_shipdate i_l_shipdate 4 const 6 Using index + flush status; + select min(l_orderkey) from lineitem where l_shipdate='1992-07-01'; + min(l_orderkey) +@@ -103,7 +103,7 @@ + Handler_read_first 0 + Handler_read_key 1 + Handler_read_last 0 +-Handler_read_next 0 ++Handler_read_next 6 + Handler_read_prev 0 + Handler_read_retry 0 + Handler_read_rnd 0 +@@ -113,7 +113,7 @@ + select min(l_orderkey) from lineitem + where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away ++1 SIMPLE lineitem ref PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate 4 const 6 Using where; Using index + flush status; + select min(l_orderkey) from lineitem + where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; +@@ -124,7 +124,7 @@ + Handler_read_first 0 + Handler_read_key 1 + Handler_read_last 0 +-Handler_read_next 0 ++Handler_read_next 6 + Handler_read_prev 0 + Handler_read_retry 0 + Handler_read_rnd 0 +@@ -134,7 +134,7 @@ + select max(l_linenumber) from lineitem + where l_shipdate='1992-07-01' and l_orderkey=130; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away ++1 SIMPLE lineitem ref PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity PRIMARY 4 const 5 Using where + flush status; + select max(l_linenumber) from lineitem + where l_shipdate='1992-07-01' and l_orderkey=130; +@@ -145,7 +145,7 @@ + Handler_read_first 0 + Handler_read_key 1 + Handler_read_last 0 +-Handler_read_next 0 ++Handler_read_next 5 + Handler_read_prev 0 + Handler_read_retry 0 + Handler_read_rnd 0 +@@ -157,7 +157,7 @@ + where l_shipdate='1992-07-01' and l_orderkey=130 + or l_receiptdate='1992-07-01' and l_orderkey=5603; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE lineitem index_merge i_l_shipdate,i_l_receiptdate i_l_shipdate,i_l_receiptdate 8,8 NULL 2 Using union(i_l_shipdate,i_l_receiptdate); Using where ++1 SIMPLE lineitem index_merge i_l_shipdate,i_l_receiptdate i_l_shipdate,i_l_receiptdate 4,4 NULL 9 Using union(i_l_shipdate,i_l_receiptdate); Using where + flush status; + select l_orderkey, l_linenumber + from lineitem use index (i_l_shipdate, i_l_receiptdate) +@@ -171,10 +171,10 @@ + Handler_read_first 0 + Handler_read_key 2 + Handler_read_last 0 +-Handler_read_next 2 ++Handler_read_next 9 + Handler_read_prev 0 + Handler_read_retry 0 +-Handler_read_rnd 2 ++Handler_read_rnd 9 + Handler_read_rnd_deleted 0 + Handler_read_rnd_next 0 + explain +@@ -183,7 +183,7 @@ + where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 + or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE lineitem index_merge i_l_shipdate,i_l_receiptdate i_l_shipdate,i_l_receiptdate 8,8 NULL 3 Using sort_union(i_l_shipdate,i_l_receiptdate); Using where ++1 SIMPLE lineitem index_merge i_l_shipdate,i_l_receiptdate i_l_shipdate,i_l_receiptdate 4,4 NULL 9 Using union(i_l_shipdate,i_l_receiptdate); Using where + flush status; + select l_orderkey, l_linenumber + from lineitem use index (i_l_shipdate, i_l_receiptdate) +@@ -198,10 +198,10 @@ + Handler_read_first 0 + Handler_read_key 2 + Handler_read_last 0 +-Handler_read_next 3 ++Handler_read_next 9 + Handler_read_prev 0 + Handler_read_retry 0 +-Handler_read_rnd 3 ++Handler_read_rnd 9 + Handler_read_rnd_deleted 0 + Handler_read_rnd_next 0 + explain +@@ -209,7 +209,7 @@ + where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 + or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE lineitem index_merge PRIMARY,i_l_shipdate,i_l_receiptdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate,i_l_receiptdate 8,8 NULL 3 Using sort_union(i_l_shipdate,i_l_receiptdate); Using where ++1 SIMPLE lineitem index_merge PRIMARY,i_l_shipdate,i_l_receiptdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate,PRIMARY,i_l_receiptdate,PRIMARY 4,4,4,4 NULL 2 Using union(intersect(i_l_shipdate,PRIMARY),intersect(i_l_receiptdate,PRIMARY)); Using where + flush status; + select l_orderkey, l_linenumber from lineitem + where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 +@@ -223,7 +223,7 @@ + Handler_read_first 0 + Handler_read_key 2 + Handler_read_last 0 +-Handler_read_next 3 ++Handler_read_next 9 + Handler_read_prev 0 + Handler_read_retry 0 + Handler_read_rnd 3 +@@ -233,7 +233,7 @@ + select max(l_orderkey) from lineitem + where l_partkey between 1 and 10 group by l_partkey; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE lineitem range i_l_suppkey_partkey,i_l_partkey i_l_partkey 5 NULL # Using where; Using index for group-by ++1 SIMPLE lineitem range i_l_suppkey_partkey,i_l_partkey i_l_partkey 5 NULL # Using where; Using index + flush status; + select max(l_orderkey) from lineitem + where l_partkey between 1 and 10 group by l_partkey; +@@ -251,9 +251,9 @@ + show status like 'handler_read%'; + Variable_name Value + Handler_read_first 0 +-Handler_read_key 21 +-Handler_read_last 1 +-Handler_read_next 0 ++Handler_read_key 1 ++Handler_read_last 0 ++Handler_read_next 294 + Handler_read_prev 0 + Handler_read_retry 0 + Handler_read_rnd 0 +@@ -263,7 +263,7 @@ + select max(l_orderkey) from lineitem + where l_suppkey in (1,4) group by l_suppkey; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE lineitem range i_l_suppkey i_l_suppkey 5 NULL # Using where; Using index for group-by ++1 SIMPLE lineitem range i_l_suppkey i_l_suppkey 5 NULL # Using where; Using index + flush status; + select max(l_orderkey) from lineitem + where l_suppkey in (1,4) group by l_suppkey; +@@ -273,9 +273,9 @@ + show status like 'handler_read%'; + Variable_name Value + Handler_read_first 0 +-Handler_read_key 6 +-Handler_read_last 1 +-Handler_read_next 0 ++Handler_read_key 2 ++Handler_read_last 0 ++Handler_read_next 1230 + Handler_read_prev 0 + Handler_read_retry 0 + Handler_read_rnd 0 +@@ -291,7 +291,7 @@ + id select_type table type possible_keys key key_len ref rows Extra + 1 SIMPLE part range i_p_retailprice i_p_retailprice 9 NULL # Using where; Using index + 1 SIMPLE orders ref PRIMARY,i_o_orderdate i_o_orderdate 4 const # Using index +-1 SIMPLE lineitem ref i_l_partkey i_l_partkey 9 dbt3_s001.part.p_partkey,dbt3_s001.orders.o_orderkey # Using index ++1 SIMPLE lineitem ref i_l_partkey i_l_partkey 5 dbt3_s001.part.p_partkey # Using where; Using index + flush status; + select o_orderkey, p_partkey + from part use index (i_p_retailprice), +@@ -305,7 +305,7 @@ + Handler_read_first 0 + Handler_read_key 3 + Handler_read_last 0 +-Handler_read_next 3 ++Handler_read_next 26 + Handler_read_prev 0 + Handler_read_retry 0 + Handler_read_rnd 0 +@@ -322,8 +322,8 @@ + select * from t0, part ignore index (primary) + where p_partkey=t0.a and p_size=1; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE t0 ALL NULL NULL NULL NULL 5 Using where +-1 SIMPLE part eq_ref i_p_size i_p_size 9 const,dbt3_s001.t0.a 1 ++1 SIMPLE t0 ALL NULL NULL NULL NULL 5 ++1 SIMPLE part ref i_p_size i_p_size 5 const 5 Using index condition + select * from t0, part ignore index (primary) + where p_partkey=t0.a and p_size=1; + a p_partkey p_name p_mfgr p_brand p_type p_size p_container p_retailprice p_comment +@@ -502,7 +502,7 @@ + select * from t1, t3 where t3.col1=t1.a and t3.col2=t1.a and t3.pk1=t1.a; + id select_type table type possible_keys key key_len ref rows Extra + 1 SIMPLE t1 ALL NULL NULL NULL NULL # Using where +-1 SIMPLE t3 ref PRIMARY,col1 col1 12 test.t1.a,test.t1.a,test.t1.a # Using index ++1 SIMPLE t3 ref PRIMARY,col1 col1 8 test.t1.a,test.t1.a # Using where; Using index + drop table t1,t2,t3; + # + # Bug mdev-4340: performance regression with extended_keys=on +@@ -722,13 +722,13 @@ + select * from t1 force index(index_date_updated) + where index_date_updated= 10 and index_id < 800; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE t1 range index_date_updated index_date_updated 13 NULL # Using index condition ++1 SIMPLE t1 ref index_date_updated index_date_updated 5 const # Using index condition + # This used to work from the start: + explain + select * from t2 force index(index_date_updated) + where index_date_updated= 10 and index_id < 800; + id select_type table type possible_keys key key_len ref rows Extra +-1 SIMPLE t2 range index_date_updated index_date_updated 13 NULL # Using index condition ++1 SIMPLE t2 ref index_date_updated index_date_updated 5 const # Using index condition + drop table t0,t1,t2; + # + # MDEV-11196: Error:Run-Time Check Failure #2 - Stack around the variable 'key_buff' +@@ -763,11 +763,12 @@ + "select_id": 1, + "table": { + "table_name": "t1", +- "access_type": "range", ++ "access_type": "ref", + "possible_keys": ["f2"], + "key": "f2", +- "key_length": "3070", +- "used_key_parts": ["f2", "pk1"], ++ "key_length": "3066", ++ "used_key_parts": ["f2"], ++ "ref": ["const"], + "rows": 1, + "filtered": 100, + "index_condition": "t1.pk1 <= 5 and t1.pk2 <= 5 and t1.f2 = 'abc'", +@@ -796,8 +797,8 @@ + "access_type": "range", + "possible_keys": ["k1"], + "key": "k1", +- "key_length": "3011", +- "used_key_parts": ["pk1", "f2", "pk2"], ++ "key_length": "3007", ++ "used_key_parts": ["pk1", "f2"], + "rows": 1, + "filtered": 100, + "index_condition": "t1.f2 <= 5 and t1.pk2 <= 5 and t1.pk1 = 'abc'", diff --git a/mysql-test/main/innodb_ext_key.combinations b/mysql-test/main/innodb_ext_key.combinations new file mode 100644 index 00000000000..6ad97eaf75b --- /dev/null +++ b/mysql-test/main/innodb_ext_key.combinations @@ -0,0 +1,5 @@ +[on] +optimizer_switch=extended_keys=on + +[off] +optimizer_switch=extended_keys=off diff --git a/mysql-test/main/innodb_ext_key.result b/mysql-test/main/innodb_ext_key.result index b0792605e54..e00192e1d64 100644 --- a/mysql-test/main/innodb_ext_key.result +++ b/mysql-test/main/innodb_ext_key.result @@ -1,5 +1,3 @@ -DROP TABLE IF EXISTS t1,t2,t3,t4; -DROP DATABASE IF EXISTS dbt3_s001; SET SESSION DEFAULT_STORAGE_ENGINE='InnoDB'; set @innodb_stats_persistent_save= @@innodb_stats_persistent; set @innodb_stats_persistent_sample_pages_save= @@ -8,28 +6,6 @@ set global innodb_stats_persistent= 1; set global innodb_stats_persistent_sample_pages=100; CREATE DATABASE dbt3_s001; use dbt3_s001; -set @save_ext_key_optimizer_switch=@@optimizer_switch; -set optimizer_switch='extended_keys=off'; -explain -select count(*) from lineitem where l_orderkey=130 and l_shipdate='1992-07-01'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE lineitem ref PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity PRIMARY 4 const 5 Using where -flush status; -select count(*) from lineitem where l_orderkey=130 and l_shipdate='1992-07-01'; -count(*) -1 -show status like 'handler_read%'; -Variable_name Value -Handler_read_first 0 -Handler_read_key 1 -Handler_read_last 0 -Handler_read_next 5 -Handler_read_prev 0 -Handler_read_retry 0 -Handler_read_rnd 0 -Handler_read_rnd_deleted 0 -Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=on'; explain select count(*) from lineitem where l_orderkey=130 and l_shipdate='1992-07-01'; id select_type table type possible_keys key key_len ref rows Extra @@ -49,29 +25,6 @@ Handler_read_retry 0 Handler_read_rnd 0 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=off'; -explain -select count(*) from lineitem -where l_orderkey=130 and l_linenumber=2 and l_shipdate='1992-07-01'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE lineitem const PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity PRIMARY 8 const,const 1 -flush status; -select count(*) from lineitem -where l_orderkey=130 and l_linenumber=2 and l_shipdate='1992-07-01'; -count(*) -1 -show status like 'handler_read%'; -Variable_name Value -Handler_read_first 0 -Handler_read_key 1 -Handler_read_last 0 -Handler_read_next 0 -Handler_read_prev 0 -Handler_read_retry 0 -Handler_read_rnd 0 -Handler_read_rnd_deleted 0 -Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=on'; explain select count(*) from lineitem where l_orderkey=130 and l_linenumber=2 and l_shipdate='1992-07-01'; @@ -93,29 +46,6 @@ Handler_read_retry 0 Handler_read_rnd 0 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=off'; -explain -select count(*) from lineitem -where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE lineitem ref PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate 4 const 6 Using where; Using index -flush status; -select count(*) from lineitem -where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000; -count(*) -1 -show status like 'handler_read%'; -Variable_name Value -Handler_read_first 0 -Handler_read_key 1 -Handler_read_last 0 -Handler_read_next 6 -Handler_read_prev 0 -Handler_read_retry 0 -Handler_read_rnd 0 -Handler_read_rnd_deleted 0 -Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=on'; explain select count(*) from lineitem where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000; @@ -137,31 +67,6 @@ Handler_read_retry 0 Handler_read_rnd 0 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=off'; -explain -select l_orderkey, l_linenumber from lineitem -where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE lineitem ref PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate 4 const 6 Using where; Using index -flush status; -select l_orderkey, l_linenumber from lineitem -where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; -l_orderkey l_linenumber -1088 3 -1217 1 -1221 3 -show status like 'handler_read%'; -Variable_name Value -Handler_read_first 0 -Handler_read_key 1 -Handler_read_last 0 -Handler_read_next 6 -Handler_read_prev 0 -Handler_read_retry 0 -Handler_read_rnd 0 -Handler_read_rnd_deleted 0 -Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=on'; explain select l_orderkey, l_linenumber from lineitem where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; @@ -185,27 +90,6 @@ Handler_read_retry 0 Handler_read_rnd 0 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=off'; -explain -select min(l_orderkey) from lineitem where l_shipdate='1992-07-01'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE lineitem ref i_l_shipdate i_l_shipdate 4 const 6 Using index -flush status; -select min(l_orderkey) from lineitem where l_shipdate='1992-07-01'; -min(l_orderkey) -130 -show status like 'handler_read%'; -Variable_name Value -Handler_read_first 0 -Handler_read_key 1 -Handler_read_last 0 -Handler_read_next 6 -Handler_read_prev 0 -Handler_read_retry 0 -Handler_read_rnd 0 -Handler_read_rnd_deleted 0 -Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=on'; explain select min(l_orderkey) from lineitem where l_shipdate='1992-07-01'; id select_type table type possible_keys key key_len ref rows Extra @@ -225,29 +109,6 @@ Handler_read_retry 0 Handler_read_rnd 0 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=off'; -explain -select min(l_orderkey) from lineitem -where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE lineitem ref PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate 4 const 6 Using where; Using index -flush status; -select min(l_orderkey) from lineitem -where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; -min(l_orderkey) -1088 -show status like 'handler_read%'; -Variable_name Value -Handler_read_first 0 -Handler_read_key 1 -Handler_read_last 0 -Handler_read_next 6 -Handler_read_prev 0 -Handler_read_retry 0 -Handler_read_rnd 0 -Handler_read_rnd_deleted 0 -Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=on'; explain select min(l_orderkey) from lineitem where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; @@ -269,29 +130,6 @@ Handler_read_retry 0 Handler_read_rnd 0 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=off'; -explain -select max(l_linenumber) from lineitem -where l_shipdate='1992-07-01' and l_orderkey=130; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE lineitem ref PRIMARY,i_l_shipdate,i_l_orderkey,i_l_orderkey_quantity PRIMARY 4 const 5 Using where -flush status; -select max(l_linenumber) from lineitem -where l_shipdate='1992-07-01' and l_orderkey=130; -max(l_linenumber) -2 -show status like 'handler_read%'; -Variable_name Value -Handler_read_first 0 -Handler_read_key 1 -Handler_read_last 0 -Handler_read_next 5 -Handler_read_prev 0 -Handler_read_retry 0 -Handler_read_rnd 0 -Handler_read_rnd_deleted 0 -Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=on'; explain select max(l_linenumber) from lineitem where l_shipdate='1992-07-01' and l_orderkey=130; @@ -313,34 +151,6 @@ Handler_read_retry 0 Handler_read_rnd 0 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=off'; -explain -select l_orderkey, l_linenumber -from lineitem use index (i_l_shipdate, i_l_receiptdate) -where l_shipdate='1992-07-01' and l_orderkey=130 -or l_receiptdate='1992-07-01' and l_orderkey=5603; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE lineitem index_merge i_l_shipdate,i_l_receiptdate i_l_shipdate,i_l_receiptdate 4,4 NULL 9 Using union(i_l_shipdate,i_l_receiptdate); Using where -flush status; -select l_orderkey, l_linenumber -from lineitem use index (i_l_shipdate, i_l_receiptdate) -where l_shipdate='1992-07-01' and l_orderkey=130 -or l_receiptdate='1992-07-01' and l_orderkey=5603; -l_orderkey l_linenumber -130 2 -5603 2 -show status like 'handler_read%'; -Variable_name Value -Handler_read_first 0 -Handler_read_key 2 -Handler_read_last 0 -Handler_read_next 9 -Handler_read_prev 0 -Handler_read_retry 0 -Handler_read_rnd 9 -Handler_read_rnd_deleted 0 -Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=on'; explain select l_orderkey, l_linenumber from lineitem use index (i_l_shipdate, i_l_receiptdate) @@ -367,35 +177,6 @@ Handler_read_retry 0 Handler_read_rnd 2 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=off'; -explain -select l_orderkey, l_linenumber -from lineitem use index (i_l_shipdate, i_l_receiptdate) -where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 -or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE lineitem index_merge i_l_shipdate,i_l_receiptdate i_l_shipdate,i_l_receiptdate 4,4 NULL 9 Using union(i_l_shipdate,i_l_receiptdate); Using where -flush status; -select l_orderkey, l_linenumber -from lineitem use index (i_l_shipdate, i_l_receiptdate) -where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 -or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; -l_orderkey l_linenumber -130 2 -5603 2 -5959 3 -show status like 'handler_read%'; -Variable_name Value -Handler_read_first 0 -Handler_read_key 2 -Handler_read_last 0 -Handler_read_next 9 -Handler_read_prev 0 -Handler_read_retry 0 -Handler_read_rnd 9 -Handler_read_rnd_deleted 0 -Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=on'; explain select l_orderkey, l_linenumber from lineitem use index (i_l_shipdate, i_l_receiptdate) @@ -423,33 +204,6 @@ Handler_read_retry 0 Handler_read_rnd 3 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=off'; -explain -select l_orderkey, l_linenumber from lineitem -where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 -or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE lineitem index_merge PRIMARY,i_l_shipdate,i_l_receiptdate,i_l_orderkey,i_l_orderkey_quantity i_l_shipdate,PRIMARY,i_l_receiptdate,PRIMARY 4,4,4,4 NULL 2 Using union(intersect(i_l_shipdate,PRIMARY),intersect(i_l_receiptdate,PRIMARY)); Using where -flush status; -select l_orderkey, l_linenumber from lineitem -where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 -or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; -l_orderkey l_linenumber -130 2 -5603 2 -5959 3 -show status like 'handler_read%'; -Variable_name Value -Handler_read_first 0 -Handler_read_key 2 -Handler_read_last 0 -Handler_read_next 9 -Handler_read_prev 0 -Handler_read_retry 0 -Handler_read_rnd 3 -Handler_read_rnd_deleted 0 -Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=on'; explain select l_orderkey, l_linenumber from lineitem where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 @@ -475,38 +229,6 @@ Handler_read_retry 0 Handler_read_rnd 3 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=off'; -explain -select max(l_orderkey) from lineitem -where l_partkey between 1 and 10 group by l_partkey; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE lineitem range i_l_suppkey_partkey,i_l_partkey i_l_partkey 5 NULL # Using where; Using index -flush status; -select max(l_orderkey) from lineitem -where l_partkey between 1 and 10 group by l_partkey; -max(l_orderkey) -5984 -5957 -5892 -5856 -5959 -5957 -5794 -5894 -5859 -5632 -show status like 'handler_read%'; -Variable_name Value -Handler_read_first 0 -Handler_read_key 1 -Handler_read_last 0 -Handler_read_next 294 -Handler_read_prev 0 -Handler_read_retry 0 -Handler_read_rnd 0 -Handler_read_rnd_deleted 0 -Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=on'; explain select max(l_orderkey) from lineitem where l_partkey between 1 and 10 group by l_partkey; @@ -537,30 +259,6 @@ Handler_read_retry 0 Handler_read_rnd 0 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=off'; -explain -select max(l_orderkey) from lineitem -where l_suppkey in (1,4) group by l_suppkey; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE lineitem range i_l_suppkey i_l_suppkey 5 NULL # Using where; Using index -flush status; -select max(l_orderkey) from lineitem -where l_suppkey in (1,4) group by l_suppkey; -max(l_orderkey) -5988 -5984 -show status like 'handler_read%'; -Variable_name Value -Handler_read_first 0 -Handler_read_key 2 -Handler_read_last 0 -Handler_read_next 1230 -Handler_read_prev 0 -Handler_read_retry 0 -Handler_read_rnd 0 -Handler_read_rnd_deleted 0 -Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=on'; explain select max(l_orderkey) from lineitem where l_suppkey in (1,4) group by l_suppkey; @@ -584,37 +282,6 @@ Handler_read_rnd 0 Handler_read_rnd_deleted 0 Handler_read_rnd_next 0 create index i_p_retailprice on part(p_retailprice); -set optimizer_switch='extended_keys=off'; -explain -select o_orderkey, p_partkey -from part use index (i_p_retailprice), -lineitem use index (i_l_partkey), orders -where p_retailprice > 1100 and o_orderdate='1997-01-01' -and o_orderkey=l_orderkey and p_partkey=l_partkey; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE part range i_p_retailprice i_p_retailprice 9 NULL # Using where; Using index -1 SIMPLE orders ref PRIMARY,i_o_orderdate i_o_orderdate 4 const # Using index -1 SIMPLE lineitem ref i_l_partkey i_l_partkey 5 dbt3_s001.part.p_partkey # Using where; Using index -flush status; -select o_orderkey, p_partkey -from part use index (i_p_retailprice), -lineitem use index (i_l_partkey), orders -where p_retailprice > 1100 and o_orderdate='1997-01-01' -and o_orderkey=l_orderkey and p_partkey=l_partkey; -o_orderkey p_partkey -5895 200 -show status like 'handler_read%'; -Variable_name Value -Handler_read_first 0 -Handler_read_key 3 -Handler_read_last 0 -Handler_read_next 26 -Handler_read_prev 0 -Handler_read_retry 0 -Handler_read_rnd 0 -Handler_read_rnd_deleted 0 -Handler_read_rnd_next 0 -set optimizer_switch='extended_keys=on'; explain select o_orderkey, p_partkey from part use index (i_p_retailprice), @@ -651,7 +318,6 @@ Handler_read_rnd_next 0 create table t0 (a int); insert into t0 values (1), (2), (3), (4), (5); create index i_p_size on part(p_size); -set optimizer_switch='extended_keys=on'; explain select * from t0, part ignore index (primary) where p_partkey=t0.a and p_size=1; @@ -672,7 +338,6 @@ use test; # set @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch='materialization=on,semijoin=on'; -SET optimizer_switch='extended_keys=on'; CREATE TABLE t1 (a int, b int) ENGINE=MyISAM; INSERT INTO t1 VALUES (1,1), (2,2); SELECT * FROM t1 WHERE 2 IN (SELECT MAX(s1.a) FROM t1 AS s1, t1 AS s2); @@ -693,9 +358,7 @@ set optimizer_switch=@save_optimizer_switch; # + extended_keys = on # (valgrinf complains fixed by the patch for bug #914560) # -set @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch = 'derived_with_keys=on'; -SET optimizer_switch = 'extended_keys=on'; CREATE TABLE t1 (a varchar(1)) ENGINE=MyISAM; INSERT INTO t1 VALUES ('j'), ('v'); CREATE TABLE t2 (b varchar(1)) ENGINE=MyISAM; @@ -725,21 +388,6 @@ c int NOT NULL PRIMARY KEY INSERT INTO t2 VALUES (10), (11), (12), (13), (14), (15), (16), (17), (18), (19), (24); -set @save_optimizer_switch=@@optimizer_switch; -SET optimizer_switch = 'extended_keys=off'; -EXPLAIN -SELECT a FROM t1 AS t, t2 -WHERE c = a AND b IN (SELECT b FROM t1, t2 WHERE b = t.b); -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t index a,b b 7 NULL 10 Using index -1 PRIMARY t1 ref b b 3 test.t.b 2 Using index; Start temporary -1 PRIMARY t2 index NULL PRIMARY 4 NULL 11 Using index; End temporary; Using join buffer (flat, BNL join) -1 PRIMARY t2 eq_ref PRIMARY PRIMARY 4 test.t.a 1 Using index -SELECT a FROM t1 AS t, t2 -WHERE c = a AND b IN (SELECT b FROM t1, t2 WHERE b = t.b); -a -24 -SET optimizer_switch = 'extended_keys=on'; EXPLAIN SELECT a FROM t1 AS t, t2 WHERE c = a AND b IN (SELECT b FROM t1, t2 WHERE b = t.b); @@ -752,7 +400,6 @@ SELECT a FROM t1 AS t, t2 WHERE c = a AND b IN (SELECT b FROM t1, t2 WHERE b = t.b); a 24 -set optimizer_switch=@save_optimizer_switch; DROP TABLE t1,t2; # # LP Bug #923236: hash join + extended_keys = on @@ -761,12 +408,10 @@ CREATE TABLE t1 (a int) ENGINE=MyISAM; CREATE TABLE t2 (b int) ENGINE=MyISAM; INSERT INTO t1 (a) VALUES (4), (6); INSERT INTO t2 (b) VALUES (0), (8); -set @save_optimizer_switch=@@optimizer_switch; set @save_join_cache_level=@@join_cache_level; SET join_cache_level=3; SET optimizer_switch='join_cache_hashed=on'; SET optimizer_switch='join_cache_bka=on'; -SET optimizer_switch='extended_keys=on'; EXPLAIN SELECT * FROM t1, t2 WHERE b=a; id select_type table type possible_keys key key_len ref rows Extra @@ -791,26 +436,16 @@ UNIQUE KEY uq (c2,c3), KEY c3 (c3), KEY c4 (c4) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; -set @save_optimizer_switch=@@optimizer_switch; -set session optimizer_switch='extended_keys=off'; -INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') -ON DUPLICATE KEY UPDATE c4 = VALUES(c4); INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') ON DUPLICATE KEY UPDATE c4 = VALUES(c4); -DELETE FROM t1; -set session optimizer_switch='extended_keys=on'; INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') ON DUPLICATE KEY UPDATE c4 = VALUES(c4); -INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') -ON DUPLICATE KEY UPDATE c4 = VALUES(c4); -set optimizer_switch=@save_optimizer_switch; DROP TABLE t1; # # Bug mdev-4220: using ref instead of eq_ref # with extended_keys=on # (performance regression introduced in the patch for mdev-3851) # -set @save_optimizer_switch=@@optimizer_switch; create table t1 (a int not null) engine=innodb; insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); create table t2 ( @@ -820,29 +455,6 @@ insert into t2 select A.a + 10 * B.a, A.a + 10 * B.a, A.a + 10 * B.a from t1 A, t1 B; -set optimizer_switch='extended_keys=off'; -explain -select * from t1, t2 where t2.a=t1.a and t2.b < 2; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL # -1 SIMPLE t2 eq_ref a a 4 test.t1.a # Using where -flush status; -select * from t1, t2 where t2.a=t1.a and t2.b < 2; -a pk a b -0 0 0 0 -1 1 1 1 -show status like 'handler_read%'; -Variable_name Value -Handler_read_first 0 -Handler_read_key 10 -Handler_read_last 0 -Handler_read_next 0 -Handler_read_prev 0 -Handler_read_retry 0 -Handler_read_rnd 0 -Handler_read_rnd_deleted 0 -Handler_read_rnd_next 11 -set optimizer_switch='extended_keys=on'; explain select * from t1, t2 where t2.a=t1.a and t2.b < 2; id select_type table type possible_keys key key_len ref rows Extra @@ -881,18 +493,6 @@ test.t1 analyze status Engine-independent statistics collected test.t1 analyze status OK test.t3 analyze status Engine-independent statistics collected test.t3 analyze status OK -set optimizer_switch='extended_keys=off'; -explain -select * from t1, t3 where t3.col1=t1.a and t3.col2=t1.a; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL # Using where -1 SIMPLE t3 ref col1 col1 8 test.t1.a,test.t1.a # Using index -explain -select * from t1, t3 where t3.col1=t1.a and t3.col2=t1.a and t3.pk1=t1.a; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL # Using where -1 SIMPLE t3 ref PRIMARY,col1 col1 8 test.t1.a,test.t1.a # Using where; Using index -set optimizer_switch='extended_keys=on'; explain select * from t1, t3 where t3.col1=t1.a and t3.col2=t1.a; id select_type table type possible_keys key key_len ref rows Extra @@ -907,7 +507,6 @@ drop table t1,t2,t3; # # Bug mdev-4340: performance regression with extended_keys=on # -set @save_optimizer_switch=@@optimizer_switch; CREATE TABLE t1 ( page_id int(8) unsigned NOT NULL AUTO_INCREMENT, page_namespace int(11) NOT NULL DEFAULT '0', @@ -1011,16 +610,6 @@ INSERT INTO t3 VALUES (89,'text-8008',''),(90,'text-9008',''),(91,'text-9',''),(92,'text-1009',''), (93,'text-2009',''),(94,'text-3009',''),(95,'text-4009',''),(96,'text-5009',''), (97,'text-6009',''),(98,'text-7009',''),(99,'text-8009',''),(100,'text-9009',''); -set optimizer_switch='extended_keys=off'; -EXPLAIN -SELECT * FROM t1, t2 IGNORE INDEX (PRIMARY), t3 -WHERE page_id=rev_page AND rev_text_id=old_id AND page_namespace=4 AND page_title='Sandbox' -ORDER BY rev_timestamp ASC LIMIT 10; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 const PRIMARY,name_title name_title 261 const,const 1 -1 SIMPLE t2 ref page_timestamp page_timestamp 4 const 10 Using where -1 SIMPLE t3 eq_ref PRIMARY PRIMARY 4 test.t2.rev_text_id 1 -set optimizer_switch='extended_keys=on'; EXPLAIN SELECT * FROM t1, t2 IGNORE INDEX (PRIMARY), t3 WHERE page_id=rev_page AND rev_text_id=old_id AND page_namespace=4 AND page_title='Sandbox' @@ -1044,7 +633,6 @@ test.t1 analyze status Engine-independent statistics collected test.t1 analyze status OK test.t2 analyze status Engine-independent statistics collected test.t2 analyze status OK -set optimizer_switch='extended_keys=on'; explain select a from t1 where b is null order by a desc limit 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index b PRIMARY 8 NULL 2 Using where @@ -1059,14 +647,6 @@ select a from t2 where b is null order by a desc limit 2; a 3 2 -set optimizer_switch='extended_keys=off'; -explain select a from t2 where b is null order by a desc limit 2; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 range b b 9 NULL 3 Using where; Using filesort -select a from t2 where b is null order by a desc limit 2; -a -3 -2 explain select a from t2 where b is null order by a desc; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 index b PRIMARY 8 NULL 3 Using where @@ -1084,7 +664,6 @@ a 2 1 drop table t1, t2; -set optimizer_switch=@save_optimizer_switch; # # MDEV-10325: Queries examines all rows of a tables when it should not # diff --git a/mysql-test/main/innodb_ext_key.test b/mysql-test/main/innodb_ext_key.test index 926a3472a6a..2f6097c7850 100644 --- a/mysql-test/main/innodb_ext_key.test +++ b/mysql-test/main/innodb_ext_key.test @@ -1,9 +1,4 @@ ---source include/have_innodb.inc - ---disable_warnings -DROP TABLE IF EXISTS t1,t2,t3,t4; -DROP DATABASE IF EXISTS dbt3_s001; ---enable_warnings +--source include/innodb_prefix_index_cluster_optimization.inc SET SESSION DEFAULT_STORAGE_ENGINE='InnoDB'; @@ -26,32 +21,12 @@ use dbt3_s001; --enable_result_log --enable_query_log -set @save_ext_key_optimizer_switch=@@optimizer_switch; - -set optimizer_switch='extended_keys=off'; explain select count(*) from lineitem where l_orderkey=130 and l_shipdate='1992-07-01'; flush status; select count(*) from lineitem where l_orderkey=130 and l_shipdate='1992-07-01'; show status like 'handler_read%'; -set optimizer_switch='extended_keys=on'; -explain -select count(*) from lineitem where l_orderkey=130 and l_shipdate='1992-07-01'; -flush status; -select count(*) from lineitem where l_orderkey=130 and l_shipdate='1992-07-01'; -show status like 'handler_read%'; - -set optimizer_switch='extended_keys=off'; -explain -select count(*) from lineitem - where l_orderkey=130 and l_linenumber=2 and l_shipdate='1992-07-01'; -flush status; -select count(*) from lineitem - where l_orderkey=130 and l_linenumber=2 and l_shipdate='1992-07-01'; -show status like 'handler_read%'; - -set optimizer_switch='extended_keys=on'; explain select count(*) from lineitem where l_orderkey=130 and l_linenumber=2 and l_shipdate='1992-07-01'; @@ -60,16 +35,6 @@ select count(*) from lineitem where l_orderkey=130 and l_linenumber=2 and l_shipdate='1992-07-01'; show status like 'handler_read%'; -set optimizer_switch='extended_keys=off'; -explain -select count(*) from lineitem - where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000; -flush status; -select count(*) from lineitem - where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000; -show status like 'handler_read%'; - -set optimizer_switch='extended_keys=on'; explain select count(*) from lineitem where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000; @@ -78,16 +43,6 @@ select count(*) from lineitem where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000; show status like 'handler_read%'; -set optimizer_switch='extended_keys=off'; -explain -select l_orderkey, l_linenumber from lineitem - where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; -flush status; -select l_orderkey, l_linenumber from lineitem - where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; -show status like 'handler_read%'; - -set optimizer_switch='extended_keys=on'; explain select l_orderkey, l_linenumber from lineitem where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; @@ -96,21 +51,12 @@ select l_orderkey, l_linenumber from lineitem where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; show status like 'handler_read%'; -set optimizer_switch='extended_keys=off'; explain select min(l_orderkey) from lineitem where l_shipdate='1992-07-01'; flush status; select min(l_orderkey) from lineitem where l_shipdate='1992-07-01'; show status like 'handler_read%'; -set optimizer_switch='extended_keys=on'; -explain -select min(l_orderkey) from lineitem where l_shipdate='1992-07-01'; -flush status; -select min(l_orderkey) from lineitem where l_shipdate='1992-07-01'; -show status like 'handler_read%'; - -set optimizer_switch='extended_keys=off'; explain select min(l_orderkey) from lineitem where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; @@ -119,25 +65,6 @@ select min(l_orderkey) from lineitem where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; show status like 'handler_read%'; -set optimizer_switch='extended_keys=on'; -explain -select min(l_orderkey) from lineitem - where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; -flush status; -select min(l_orderkey) from lineitem - where l_shipdate='1992-07-01' and l_orderkey between 1001 and 2000; -show status like 'handler_read%'; - -set optimizer_switch='extended_keys=off'; -explain -select max(l_linenumber) from lineitem - where l_shipdate='1992-07-01' and l_orderkey=130; -flush status; -select max(l_linenumber) from lineitem - where l_shipdate='1992-07-01' and l_orderkey=130; -show status like 'handler_read%'; - -set optimizer_switch='extended_keys=on'; explain select max(l_linenumber) from lineitem where l_shipdate='1992-07-01' and l_orderkey=130; @@ -146,7 +73,6 @@ select max(l_linenumber) from lineitem where l_shipdate='1992-07-01' and l_orderkey=130; show status like 'handler_read%'; -set optimizer_switch='extended_keys=off'; explain select l_orderkey, l_linenumber from lineitem use index (i_l_shipdate, i_l_receiptdate) @@ -159,20 +85,6 @@ select l_orderkey, l_linenumber or l_receiptdate='1992-07-01' and l_orderkey=5603; show status like 'handler_read%'; -set optimizer_switch='extended_keys=on'; -explain -select l_orderkey, l_linenumber - from lineitem use index (i_l_shipdate, i_l_receiptdate) - where l_shipdate='1992-07-01' and l_orderkey=130 - or l_receiptdate='1992-07-01' and l_orderkey=5603; -flush status; -select l_orderkey, l_linenumber - from lineitem use index (i_l_shipdate, i_l_receiptdate) - where l_shipdate='1992-07-01' and l_orderkey=130 - or l_receiptdate='1992-07-01' and l_orderkey=5603; -show status like 'handler_read%'; - -set optimizer_switch='extended_keys=off'; explain select l_orderkey, l_linenumber from lineitem use index (i_l_shipdate, i_l_receiptdate) @@ -185,31 +97,6 @@ select l_orderkey, l_linenumber or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; show status like 'handler_read%'; -set optimizer_switch='extended_keys=on'; -explain -select l_orderkey, l_linenumber - from lineitem use index (i_l_shipdate, i_l_receiptdate) - where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 - or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; -flush status; -select l_orderkey, l_linenumber - from lineitem use index (i_l_shipdate, i_l_receiptdate) - where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 - or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; -show status like 'handler_read%'; - -set optimizer_switch='extended_keys=off'; -explain -select l_orderkey, l_linenumber from lineitem - where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 - or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; -flush status; -select l_orderkey, l_linenumber from lineitem - where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 - or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; -show status like 'handler_read%'; - -set optimizer_switch='extended_keys=on'; explain select l_orderkey, l_linenumber from lineitem where l_shipdate='1992-07-01' and l_orderkey between 1 and 1000 @@ -220,17 +107,6 @@ select l_orderkey, l_linenumber from lineitem or l_receiptdate='1992-07-01' and l_orderkey between 5001 and 6000; show status like 'handler_read%'; -set optimizer_switch='extended_keys=off'; ---replace_column 9 # -explain -select max(l_orderkey) from lineitem - where l_partkey between 1 and 10 group by l_partkey; -flush status; -select max(l_orderkey) from lineitem - where l_partkey between 1 and 10 group by l_partkey; -show status like 'handler_read%'; - -set optimizer_switch='extended_keys=on'; --replace_column 9 # explain select max(l_orderkey) from lineitem @@ -240,17 +116,6 @@ select max(l_orderkey) from lineitem where l_partkey between 1 and 10 group by l_partkey; show status like 'handler_read%'; -set optimizer_switch='extended_keys=off'; ---replace_column 9 # -explain -select max(l_orderkey) from lineitem - where l_suppkey in (1,4) group by l_suppkey; -flush status; -select max(l_orderkey) from lineitem - where l_suppkey in (1,4) group by l_suppkey; -show status like 'handler_read%'; - -set optimizer_switch='extended_keys=on'; --replace_column 9 # explain select max(l_orderkey) from lineitem @@ -262,23 +127,6 @@ show status like 'handler_read%'; create index i_p_retailprice on part(p_retailprice); -set optimizer_switch='extended_keys=off'; ---replace_column 9 # -explain -select o_orderkey, p_partkey - from part use index (i_p_retailprice), - lineitem use index (i_l_partkey), orders - where p_retailprice > 1100 and o_orderdate='1997-01-01' - and o_orderkey=l_orderkey and p_partkey=l_partkey; -flush status; -select o_orderkey, p_partkey - from part use index (i_p_retailprice), - lineitem use index (i_l_partkey), orders - where p_retailprice > 1100 and o_orderdate='1997-01-01' - and o_orderkey=l_orderkey and p_partkey=l_partkey; -show status like 'handler_read%'; - -set optimizer_switch='extended_keys=on'; --replace_column 9 # explain select o_orderkey, p_partkey @@ -303,8 +151,6 @@ create table t0 (a int); insert into t0 values (1), (2), (3), (4), (5); create index i_p_size on part(p_size); -set optimizer_switch='extended_keys=on'; - explain select * from t0, part ignore index (primary) where p_partkey=t0.a and p_size=1; @@ -327,7 +173,6 @@ use test; set @save_optimizer_switch=@@optimizer_switch; SET optimizer_switch='materialization=on,semijoin=on'; -SET optimizer_switch='extended_keys=on'; CREATE TABLE t1 (a int, b int) ENGINE=MyISAM; INSERT INTO t1 VALUES (1,1), (2,2); @@ -346,10 +191,7 @@ set optimizer_switch=@save_optimizer_switch; --echo # (valgrinf complains fixed by the patch for bug #914560) --echo # -set @save_optimizer_switch=@@optimizer_switch; - SET optimizer_switch = 'derived_with_keys=on'; -SET optimizer_switch = 'extended_keys=on'; CREATE TABLE t1 (a varchar(1)) ENGINE=MyISAM; INSERT INTO t1 VALUES ('j'), ('v'); @@ -389,24 +231,12 @@ INSERT INTO t2 VALUES (10), (11), (12), (13), (14), (15), (16), (17), (18), (19), (24); -set @save_optimizer_switch=@@optimizer_switch; - -SET optimizer_switch = 'extended_keys=off'; EXPLAIN SELECT a FROM t1 AS t, t2 WHERE c = a AND b IN (SELECT b FROM t1, t2 WHERE b = t.b); SELECT a FROM t1 AS t, t2 WHERE c = a AND b IN (SELECT b FROM t1, t2 WHERE b = t.b); -SET optimizer_switch = 'extended_keys=on'; -EXPLAIN -SELECT a FROM t1 AS t, t2 - WHERE c = a AND b IN (SELECT b FROM t1, t2 WHERE b = t.b); -SELECT a FROM t1 AS t, t2 - WHERE c = a AND b IN (SELECT b FROM t1, t2 WHERE b = t.b); - -set optimizer_switch=@save_optimizer_switch; - DROP TABLE t1,t2; --echo # @@ -420,13 +250,11 @@ CREATE TABLE t2 (b int) ENGINE=MyISAM; INSERT INTO t1 (a) VALUES (4), (6); INSERT INTO t2 (b) VALUES (0), (8); -set @save_optimizer_switch=@@optimizer_switch; set @save_join_cache_level=@@join_cache_level; SET join_cache_level=3; SET optimizer_switch='join_cache_hashed=on'; SET optimizer_switch='join_cache_bka=on'; -SET optimizer_switch='extended_keys=on'; EXPLAIN SELECT * FROM t1, t2 WHERE b=a; @@ -455,24 +283,11 @@ KEY c4 (c4) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; -set @save_optimizer_switch=@@optimizer_switch; - -set session optimizer_switch='extended_keys=off'; -INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') - ON DUPLICATE KEY UPDATE c4 = VALUES(c4); -INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') - ON DUPLICATE KEY UPDATE c4 = VALUES(c4); - -DELETE FROM t1; - -set session optimizer_switch='extended_keys=on'; INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') ON DUPLICATE KEY UPDATE c4 = VALUES(c4); INSERT INTO t1 (c2, c3, c4) VALUES (58291525, 2580, 'foobar') ON DUPLICATE KEY UPDATE c4 = VALUES(c4); -set optimizer_switch=@save_optimizer_switch; - DROP TABLE t1; --echo # @@ -481,8 +296,6 @@ DROP TABLE t1; --echo # (performance regression introduced in the patch for mdev-3851) --echo # -set @save_optimizer_switch=@@optimizer_switch; - create table t1 (a int not null) engine=innodb; insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); @@ -496,15 +309,6 @@ select A.a + 10 * B.a, A.a + 10 * B.a, A.a + 10 * B.a from t1 A, t1 B; -set optimizer_switch='extended_keys=off'; ---replace_column 9 # -explain -select * from t1, t2 where t2.a=t1.a and t2.b < 2; -flush status; -select * from t1, t2 where t2.a=t1.a and t2.b < 2; -show status like 'handler_read%'; - -set optimizer_switch='extended_keys=on'; --replace_column 9 # explain select * from t1, t2 where t2.a=t1.a and t2.b < 2; @@ -531,15 +335,6 @@ alter table t3 add primary key (pk1, pk2); alter table t3 add key (col1, col2); analyze table t1,t3; -set optimizer_switch='extended_keys=off'; ---replace_column 9 # -explain -select * from t1, t3 where t3.col1=t1.a and t3.col2=t1.a; ---replace_column 9 # -explain -select * from t1, t3 where t3.col1=t1.a and t3.col2=t1.a and t3.pk1=t1.a; - -set optimizer_switch='extended_keys=on'; --replace_column 9 # explain select * from t1, t3 where t3.col1=t1.a and t3.col2=t1.a; @@ -553,8 +348,6 @@ drop table t1,t2,t3; --echo # Bug mdev-4340: performance regression with extended_keys=on --echo # -set @save_optimizer_switch=@@optimizer_switch; - CREATE TABLE t1 ( page_id int(8) unsigned NOT NULL AUTO_INCREMENT, page_namespace int(11) NOT NULL DEFAULT '0', @@ -662,13 +455,6 @@ INSERT INTO t3 VALUES (97,'text-6009',''),(98,'text-7009',''),(99,'text-8009',''),(100,'text-9009',''); -set optimizer_switch='extended_keys=off'; -EXPLAIN -SELECT * FROM t1, t2 IGNORE INDEX (PRIMARY), t3 - WHERE page_id=rev_page AND rev_text_id=old_id AND page_namespace=4 AND page_title='Sandbox' -ORDER BY rev_timestamp ASC LIMIT 10; - -set optimizer_switch='extended_keys=on'; EXPLAIN SELECT * FROM t1, t2 IGNORE INDEX (PRIMARY), t3 WHERE page_id=rev_page AND rev_text_id=old_id AND page_namespace=4 AND page_title='Sandbox' @@ -689,14 +475,10 @@ insert into t2 (b) values (null), (null), (null); analyze table t1,t2; -set optimizer_switch='extended_keys=on'; explain select a from t1 where b is null order by a desc limit 2; select a from t1 where b is null order by a desc limit 2; explain select a from t2 where b is null order by a desc limit 2; select a from t2 where b is null order by a desc limit 2; -set optimizer_switch='extended_keys=off'; -explain select a from t2 where b is null order by a desc limit 2; -select a from t2 where b is null order by a desc limit 2; explain select a from t2 where b is null order by a desc; select a from t2 where b is null order by a desc; @@ -706,8 +488,6 @@ select a from t2 where b is null order by a desc,a,a; drop table t1, t2; -set optimizer_switch=@save_optimizer_switch; - --echo # --echo # MDEV-10325: Queries examines all rows of a tables when it should not --echo # diff --git a/mysql-test/main/invisible_field.result b/mysql-test/main/invisible_field.result index a57298dd5c5..9b42b043ec6 100644 --- a/mysql-test/main/invisible_field.result +++ b/mysql-test/main/invisible_field.result @@ -621,3 +621,9 @@ a b 1 3 2 4 drop table t1; +# +# MDEV-23467 SIGSEGV in fill_record/fill_record_n_invoke_before_triggers on INSERT DELAYED +# +create table t1 (a int, b int invisible); +insert delayed into t1 values (1); +drop table t1; diff --git a/mysql-test/main/invisible_field.test b/mysql-test/main/invisible_field.test index 0e3994a78ce..7a48347ec29 100644 --- a/mysql-test/main/invisible_field.test +++ b/mysql-test/main/invisible_field.test @@ -271,3 +271,11 @@ select a,b from t1; #cleanup drop table t1; + +--echo # +--echo # MDEV-23467 SIGSEGV in fill_record/fill_record_n_invoke_before_triggers on INSERT DELAYED +--echo # +create table t1 (a int, b int invisible); +insert delayed into t1 values (1); +# cleanup +drop table t1; diff --git a/mysql-test/main/mysql_upgrade.result b/mysql-test/main/mysql_upgrade.result index f6b9770a190..d41df55b113 100644 --- a/mysql-test/main/mysql_upgrade.result +++ b/mysql-test/main/mysql_upgrade.result @@ -145,7 +145,7 @@ test Phase 7/7: Running 'FLUSH PRIVILEGES' OK DROP USER mysqltest1@'%'; -Version check failed. Got the following error when calling the 'mysql' command line client +Version check failed. Got the following error when calling the 'mysql_upgrade' command line client ERROR 1045 (28000): Access denied for user 'mysqltest1'@'localhost' (using password: YES) FATAL ERROR: Upgrade failed Run mysql_upgrade with a non existing server socket @@ -412,7 +412,7 @@ OK # Bug #21489398: MYSQL_UPGRADE: FATAL ERROR: UPGRADE FAILED - IMPROVE ERROR # Run mysql_upgrade with unauthorized access -Version check failed. Got the following error when calling the 'mysql' command line client +Version check failed. Got the following error when calling the 'mysql_upgrade' command line client ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES) FATAL ERROR: Upgrade failed # diff --git a/mysql-test/main/mysqlbinlog_row_minimal.result b/mysql-test/main/mysqlbinlog_row_minimal.result index f385b4ca69a..659228a57e2 100644 --- a/mysql-test/main/mysqlbinlog_row_minimal.result +++ b/mysql-test/main/mysqlbinlog_row_minimal.result @@ -327,6 +327,24 @@ ROLLBACK /* added by mysqlbinlog */; /*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/; DROP TABLE t1,t2; +# +# MDEV-16372 ER_BASE64_DECODE_ERROR upon replaying binary log with system table +# +FLUSH BINARY LOGS; +CREATE TABLE t1 (pk INT PRIMARY KEY); +INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (1), (2) ON DUPLICATE KEY UPDATE pk= pk + 10; +FLUSH BINARY LOGS; +Proof: two subsequent patterns must be found +FOUND 1 /### UPDATE `test`.`t1`/ in mysqlbinlog.sql +FOUND 2 /### INSERT INTO `test`.`t1`/ in mysqlbinlog.sql +DROP TABLE t1; +SELECT * FROM t1; +pk +2 +11 +# Cleanup +DROP TABLE t1; CREATE TABLE `t1` ( `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, `is_deleted` BIT(1) DEFAULT b'0', @@ -351,23 +369,23 @@ FLUSH BINARY LOGS; /*!40019 SET @@session.max_insert_delayed_threads=0*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; DELIMITER /*!*/; -# at 387 -#<date> server id 1 end_log_pos 429 CRC32 XXX GTID 0-1-16 +# at POS +#<date> server id 1 end_log_pos END_LOG_POS CRC32 XXX GTID D-S-N /*!100101 SET @@session.skip_parallel_replication=0*//*!*/; /*!100001 SET @@session.gtid_domain_id=0*//*!*/; /*!100001 SET @@session.server_id=1*//*!*/; -/*!100001 SET @@session.gtid_seq_no=16*//*!*/; +/*!100001 SET @@session.gtid_seq_no=21*//*!*/; START TRANSACTION /*!*/; -# at 429 -# at 543 -#<date> server id 1 end_log_pos 543 CRC32 XXX Annotate_rows: +# at POS +# at POS +#<date> server id 1 end_log_pos END_LOG_POS CRC32 XXX Annotate_rows: #Q> UPDATE t1 t1 INNER JOIN t2 t2 ON t1.ref_id = t2.id #Q> SET t1.is_deleted = TRUE #Q> WHERE t1.id = -#<date> server id 1 end_log_pos 594 CRC32 XXX Table_map: `test`.`t1` mapped to number 35 -# at 594 -#<date> server id 1 end_log_pos 643 CRC32 XXX Update_rows: table id 35 flags: STMT_END_F +#<date> server id 1 end_log_pos END_LOG_POS CRC32 XXX Table_map: `test`.`t1` mapped to number TID +# at POS +#<date> server id 1 end_log_pos END_LOG_POS CRC32 XXX Update_rows: table id TID flags: STMT_END_F ### UPDATE `test`.`t1` ### WHERE ### @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */ @@ -375,10 +393,10 @@ START TRANSACTION ### @2=b'1' /* BIT(1) meta=1 nullable=1 is_null=0 */ ### @3=X /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */ # Number of rows: 1 -# at 643 -#<date> server id 1 end_log_pos 725 CRC32 XXX Query thread_id=5 exec_time=x error_code=0 +# at POS +#<date> server id 1 end_log_pos END_LOG_POS CRC32 XXX Query thread_id=TID exec_time=x error_code=0 SET TIMESTAMP=X/*!*/; -SET @@session.pseudo_thread_id=5/*!*/; +SET @@session.pseudo_thread_id=TID/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1, @@session.sql_if_exists=0/*!*/; SET @@session.sql_mode=#/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; @@ -388,8 +406,6 @@ SET @@session.lc_time_names=0/*!*/; SET @@session.collation_database=DEFAULT/*!*/; COMMIT /*!*/; -# at 725 -#<date> server id 1 end_log_pos 773 CRC32 XXX Rotate to master-bin.000004 pos: 4 DELIMITER ; # End of log file ROLLBACK /* added by mysqlbinlog */; diff --git a/mysql-test/main/mysqlbinlog_row_minimal.test b/mysql-test/main/mysqlbinlog_row_minimal.test index b69aa6da14b..b399cc4ac45 100644 --- a/mysql-test/main/mysqlbinlog_row_minimal.test +++ b/mysql-test/main/mysqlbinlog_row_minimal.test @@ -33,6 +33,33 @@ FLUSH BINARY LOGS; DROP TABLE t1,t2; +--echo # +--echo # MDEV-16372 ER_BASE64_DECODE_ERROR upon replaying binary log with system table +--echo # +FLUSH BINARY LOGS; +CREATE TABLE t1 (pk INT PRIMARY KEY); +INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (1), (2) ON DUPLICATE KEY UPDATE pk= pk + 10; + +--let $binlog = query_get_value(SHOW MASTER STATUS, File, 1) + +FLUSH BINARY LOGS; +--exec $MYSQL_BINLOG --verbose $datadir/$binlog > $MYSQLTEST_VARDIR/tmp/mysqlbinlog.sql +--echo Proof: two subsequent patterns must be found +--let SEARCH_PATTERN= ### UPDATE `test`.`t1` +--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.sql +--source include/search_pattern_in_file.inc +--let SEARCH_PATTERN= ### INSERT INTO `test`.`t1` +--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.sql +--source include/search_pattern_in_file.inc + +DROP TABLE t1; +--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/mysqlbinlog.sql +SELECT * FROM t1; + +--echo # Cleanup +DROP TABLE t1; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog.sql # # MDEV-14605 ON UPDATE CURRENT_TIMESTAMP fields by multi-table UPDATE are not logged with binlog_row_image=MINIMAL # @@ -64,11 +91,12 @@ UPDATE t1 t1 INNER JOIN t2 t2 ON t1.ref_id = t2.id WHERE t1.id = 1; --let $binlog = query_get_value(SHOW MASTER STATUS, File, 1) +--let $binlog_end= query_get_value(SHOW MASTER STATUS, Position, 1) FLUSH BINARY LOGS; --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR ---replace_regex /\d{6} *\d*:\d\d:\d\d/<date>/ /SET TIMESTAMP=\d*/SET TIMESTAMP=X/ /exec_time=\d*/exec_time=x/ /@3=\d*/@3=X/ /CRC32 0x[0-9a-f]+/CRC32 XXX/ /@@session.sql_mode=\d+/@@session.sql_mode=#/ /collation_server=\d+/collation_server=#/ ---exec $MYSQL_BINLOG --verbose --verbose --base64-output=DECODE-ROWS $datadir/$binlog --start-position=$binlog_pos +--replace_regex /table id \d*/table id TID/ /mapped to number \d*/mapped to number TID/ /at \d*/at POS/ /end_log_pos \d*/end_log_pos END_LOG_POS/ /GTID \d*-\d*-\d*/GTID D-S-N/ /\d{6} *\d*:\d\d:\d\d/<date>/ /SET TIMESTAMP=\d*/SET TIMESTAMP=X/ /exec_time=\d*/exec_time=x/ /@3=\d*/@3=X/ /CRC32 0x[0-9a-f]+/CRC32 XXX/ /@@session.sql_mode=\d+/@@session.sql_mode=#/ /collation_server=\d+/collation_server=#/ /thread_id=\d*/thread_id=TID/ +--exec $MYSQL_BINLOG --verbose --verbose --base64-output=DECODE-ROWS $datadir/$binlog --start-position=$binlog_pos --stop-position=$binlog_end DROP TABLE t1,t2; diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result index b0b6120e271..8f4f6ec97ce 100644 --- a/mysql-test/main/opt_trace.result +++ b/mysql-test/main/opt_trace.result @@ -8684,5 +8684,103 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.mark_join_nest_as_const')) } ] drop table t0, t1, t2, t3; +# +# MDEV-23767: IN-to-subquery conversion is not visible in optimizer trace +# +create table t0 (a int); +INSERT INTO t0 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +set @tmp=@@in_predicate_conversion_threshold; +set in_predicate_conversion_threshold=3; +explain select * from t0 where a in (1,2,3,4,5,6); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t0 ALL NULL NULL NULL NULL 10 Using where +1 PRIMARY <derived3> ref key0 key0 4 test.t0.a 2 FirstMatch(t0) +3 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used +select json_detailed(json_extract(trace, '$**.in_to_subquery_conversion')) +from information_schema.optimizer_trace; +json_detailed(json_extract(trace, '$**.in_to_subquery_conversion')) +[ + + { + "item": "t0.a in (1,2,3,4,5,6)", + "conversion": + [ + + { + "join_preparation": + { + "select_id": 2, + "steps": + [ + + { + "derived": + { + "table": "tvc_0", + "select_id": 3, + "algorithm": "materialized" + } + }, + + { + "transformation": + { + "select_id": 2, + "from": "IN (SELECT)", + "to": "materialization", + "sjm_scan_allowed": true, + "possible": true + } + }, + + { + "transformation": + { + "select_id": 2, + "from": "IN (SELECT)", + "to": "semijoin", + "chosen": true + } + }, + + { + "expanded_query": "/* select#2 */ select tvc_0._col_1 from (values (1),(2),(3),(4),(5),(6)) tvc_0" + } + ] + } + } + ] + } +] +explain select * from t0 where a in (1,2,3,4,5,a+1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where +select json_detailed(json_extract(trace, '$**.in_to_subquery_conversion')) +from information_schema.optimizer_trace; +json_detailed(json_extract(trace, '$**.in_to_subquery_conversion')) +[ + + { + "item": "t0.a in (1,2,3,4,5,t0.a + 1)", + "done": false, + "reason": "non-constant element in the IN-list" + } +] +explain select * from t0 where a in ('1','2','3','4','5','6'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t0 ALL NULL NULL NULL NULL 10 Using where +select json_detailed(json_extract(trace, '$**.in_to_subquery_conversion')) +from information_schema.optimizer_trace; +json_detailed(json_extract(trace, '$**.in_to_subquery_conversion')) +[ + + { + "item": "t0.a in ('1','2','3','4','5','6')", + "done": false, + "reason": "type mismatch" + } +] +set in_predicate_conversion_threshold=@tmp; +drop table t0; # End of 10.5 tests set optimizer_trace='enabled=off'; diff --git a/mysql-test/main/opt_trace.test b/mysql-test/main/opt_trace.test index d6030543313..314e5825c08 100644 --- a/mysql-test/main/opt_trace.test +++ b/mysql-test/main/opt_trace.test @@ -654,5 +654,31 @@ from information_schema.optimizer_trace; drop table t0, t1, t2, t3; +--echo # +--echo # MDEV-23767: IN-to-subquery conversion is not visible in optimizer trace +--echo # +create table t0 (a int); +INSERT INTO t0 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +set @tmp=@@in_predicate_conversion_threshold; +set in_predicate_conversion_threshold=3; + +explain select * from t0 where a in (1,2,3,4,5,6); + +select json_detailed(json_extract(trace, '$**.in_to_subquery_conversion')) +from information_schema.optimizer_trace; + +explain select * from t0 where a in (1,2,3,4,5,a+1); + +select json_detailed(json_extract(trace, '$**.in_to_subquery_conversion')) +from information_schema.optimizer_trace; + +explain select * from t0 where a in ('1','2','3','4','5','6'); +select json_detailed(json_extract(trace, '$**.in_to_subquery_conversion')) +from information_schema.optimizer_trace; + +set in_predicate_conversion_threshold=@tmp; +drop table t0; + --echo # End of 10.5 tests set optimizer_trace='enabled=off'; diff --git a/mysql-test/main/order_by.result b/mysql-test/main/order_by.result index 4379db411aa..29a31a9c28c 100644 --- a/mysql-test/main/order_by.result +++ b/mysql-test/main/order_by.result @@ -3433,6 +3433,22 @@ SET sort_buffer_size= @save_sort_buffer_size; SET max_length_for_sort_data= @save_max_length_for_sort_data; DROP TABLE t1; # +# MDEV-23596: Assertion `tab->ref.use_count' failed in join_read_key_unlock_row +# +CREATE TABLE t1 (a INT PRIMARY KEY, b INT, KEY(b)); +INSERT INTO t1 VALUES (0, 1),(1, 2); +CREATE TABLE t2 SELECT * FROM t1; +EXPLAIN SELECT (SELECT 1 FROM t1 WHERE t1.a=t2.b ORDER BY t1.b LIMIT 1) AS c FROM t2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 +2 DEPENDENT SUBQUERY t1 index PRIMARY b 5 NULL 1 Using where +SELECT (SELECT 1 FROM t1 WHERE t1.a=t2.b ORDER BY t1.b LIMIT 1) AS c FROM t2; +c +1 +NULL +DROP TABLE t1,t2; +# end of 10.1 tests +# # MDEV-13994: Bad join results with orderby_uses_equalities=on # CREATE TABLE books ( diff --git a/mysql-test/main/order_by.test b/mysql-test/main/order_by.test index 15e42848eea..fd87f54cc3d 100644 --- a/mysql-test/main/order_by.test +++ b/mysql-test/main/order_by.test @@ -2203,6 +2203,21 @@ SET max_length_for_sort_data= @save_max_length_for_sort_data; DROP TABLE t1; --echo # +--echo # MDEV-23596: Assertion `tab->ref.use_count' failed in join_read_key_unlock_row +--echo # + +CREATE TABLE t1 (a INT PRIMARY KEY, b INT, KEY(b)); +INSERT INTO t1 VALUES (0, 1),(1, 2); +CREATE TABLE t2 SELECT * FROM t1; + +EXPLAIN SELECT (SELECT 1 FROM t1 WHERE t1.a=t2.b ORDER BY t1.b LIMIT 1) AS c FROM t2; +SELECT (SELECT 1 FROM t1 WHERE t1.a=t2.b ORDER BY t1.b LIMIT 1) AS c FROM t2; + +DROP TABLE t1,t2; + +--echo # end of 10.1 tests + +--echo # --echo # MDEV-13994: Bad join results with orderby_uses_equalities=on --echo # diff --git a/mysql-test/main/parser.result b/mysql-test/main/parser.result index d37b76e5f74..1d3acaf062b 100644 --- a/mysql-test/main/parser.result +++ b/mysql-test/main/parser.result @@ -1945,6 +1945,95 @@ KILL ( SELECT 1 ) + LASTVAL(s); ERROR 42000: KILL does not support subqueries or stored functions KILL LASTVAL(s); ERROR 42000: KILL does not support subqueries or stored functions +# +# MDEV-23094: Multiple calls to a Stored Procedure from another +# Stored Procedure crashes server +# +create table t1 (id1 int primary key, data1 int); +create table t2 (id2 int primary key, data2 int); +create procedure p1(IN id int, IN dt int) +begin +if (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) +then +select 1; +end if; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(IN id int, IN dt int) +begin +case (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) +when 1 then +select 1; +else +select 0; +end case; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(IN id int, IN dt int) +begin +declare wcont int default 1; +while (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) and wcont +do +select 1; +set wcont=0; +end while; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(IN id int, IN dt int) +begin +declare count int default 1; +repeat +select 1; +set count=count+1; +until (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) and +count < 3 +end repeat; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(IN id int, IN dt int) +begin +for i in 1..(exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) +do +select 1; +end for; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +drop table t1,t2; # End of 10.4 tests # # Start of 10.5 tests diff --git a/mysql-test/main/parser.test b/mysql-test/main/parser.test index 3689f38dc7f..755cbb95c45 100644 --- a/mysql-test/main/parser.test +++ b/mysql-test/main/parser.test @@ -1698,6 +1698,103 @@ KILL ( SELECT 1 ) + LASTVAL(s); --error ER_SUBQUERIES_NOT_SUPPORTED KILL LASTVAL(s); +--echo # +--echo # MDEV-23094: Multiple calls to a Stored Procedure from another +--echo # Stored Procedure crashes server +--echo # + +create table t1 (id1 int primary key, data1 int); +create table t2 (id2 int primary key, data2 int); + +delimiter //; +create procedure p1(IN id int, IN dt int) +begin + if (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) + then + select 1; + end if; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(IN id int, IN dt int) +begin +case (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) +when 1 then + select 1; +else + select 0; +end case; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(IN id int, IN dt int) +begin +declare wcont int default 1; +while (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) and wcont +do + select 1; + set wcont=0; +end while; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(IN id int, IN dt int) +begin +declare count int default 1; +repeat + select 1; + set count=count+1; +until (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) and + count < 3 +end repeat; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(IN id int, IN dt int) +begin +for i in 1..(exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) +do + select 1; +end for; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +drop table t1,t2; + --echo # End of 10.4 tests diff --git a/mysql-test/main/rowid_filter.result b/mysql-test/main/rowid_filter.result index 6fda4b03b0f..83cf932bdae 100644 --- a/mysql-test/main/rowid_filter.result +++ b/mysql-test/main/rowid_filter.result @@ -2165,6 +2165,12 @@ A.a+1000*B.a + 10000, 'filler-data-filler-data' from t11 A, t10 B; +analyze table t1 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze Warning Engine-independent statistics are not collected for column 'el_index' +test.t1 analyze Warning Engine-independent statistics are not collected for column 'filler' +test.t1 analyze status Table is already up to date # This must not use rowid_filter with key=el_index|el_index_60: explain select * from t1 diff --git a/mysql-test/main/rowid_filter.test b/mysql-test/main/rowid_filter.test index c47710e65b8..ed1227d3770 100644 --- a/mysql-test/main/rowid_filter.test +++ b/mysql-test/main/rowid_filter.test @@ -377,6 +377,7 @@ select 'filler-data-filler-data' from t11 A, t10 B; +analyze table t1 persistent for all; --echo # This must not use rowid_filter with key=el_index|el_index_60: explain diff --git a/mysql-test/main/rowid_filter_innodb.result b/mysql-test/main/rowid_filter_innodb.result index 15e77f5689e..b2d598ca229 100644 --- a/mysql-test/main/rowid_filter_innodb.result +++ b/mysql-test/main/rowid_filter_innodb.result @@ -2114,6 +2114,12 @@ A.a+1000*B.a + 10000, 'filler-data-filler-data' from t11 A, t10 B; +analyze table t1 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze Warning Engine-independent statistics are not collected for column 'el_index' +test.t1 analyze Warning Engine-independent statistics are not collected for column 'filler' +test.t1 analyze status OK # This must not use rowid_filter with key=el_index|el_index_60: explain select * from t1 diff --git a/mysql-test/main/subselect4.result b/mysql-test/main/subselect4.result index 944515413d3..3f12322f6dc 100644 --- a/mysql-test/main/subselect4.result +++ b/mysql-test/main/subselect4.result @@ -2686,6 +2686,37 @@ SELECT * FROM t2; f bar DROP TABLE t1, t2; +# +# MDEV-18335: Assertion `!error || error == 137' failed in subselect_rowid_merge_engine::init +# +CREATE TABLE t1 (i1 int,v1 varchar(1),KEY (v1,i1)); +INSERT INTO t1 VALUES +(9,'y'),(4,'q'),(0,null),(0,'p'),(null,'j'); +CREATE TABLE t2 (pk int); +INSERT INTO t2 VALUES (1),(2); +CREATE TABLE t3 (v2 varchar(1)); +INSERT INTO t3 VALUES +('p'),('j'),('y'),('q'); +CREATE TABLE t4 (v2 varchar(1)); +INSERT INTO t4 VALUES +('a'),('a'),('b'),('b'),('c'),('c'), +('d'),('d'),('e'),('e'),('f'),('f'), +('g'),('g'),('h'),('h'),('i'),('i'), +('j'),('j'),('k'),('k'),('l'),('l'), +('m'),('m'),('n'),('n'),('o'),('o'), +('p'),('p'),('q'),('q'),('r'),('r'), +('s'),('s'),('t'),('t'),('u'),('u'),('v'),('v'), +('w'),('w'),('x'),('x'), (NULL),(NULL); +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; +select 1 +from t2 join t1 on +('i','w') not in (select t1.v1,t4.v2 from t4,t1,t3 where t3.v2 = t1.v1) LIMIT ROWS EXAMINED 500; +1 +Warnings: +Warning 1931 Query execution was interrupted. The query examined at least 3020 rows, which exceeds LIMIT ROWS EXAMINED (500). The query result may be incomplete +SET join_cache_level= @save_join_cache_level; +DROP TABLE t1,t2,t3,t4; # End of 10.2 tests # # MDEV-19134: EXISTS() slower if ORDER BY is defined diff --git a/mysql-test/main/subselect4.test b/mysql-test/main/subselect4.test index 8d2ddaab09b..c9b05c4f015 100644 --- a/mysql-test/main/subselect4.test +++ b/mysql-test/main/subselect4.test @@ -2201,6 +2201,42 @@ SELECT * FROM t2; DROP TABLE t1, t2; +--echo # +--echo # MDEV-18335: Assertion `!error || error == 137' failed in subselect_rowid_merge_engine::init +--echo # + +CREATE TABLE t1 (i1 int,v1 varchar(1),KEY (v1,i1)); +INSERT INTO t1 VALUES +(9,'y'),(4,'q'),(0,null),(0,'p'),(null,'j'); + +CREATE TABLE t2 (pk int); +INSERT INTO t2 VALUES (1),(2); + +CREATE TABLE t3 (v2 varchar(1)); +INSERT INTO t3 VALUES +('p'),('j'),('y'),('q'); + +CREATE TABLE t4 (v2 varchar(1)); +INSERT INTO t4 VALUES +('a'),('a'),('b'),('b'),('c'),('c'), +('d'),('d'),('e'),('e'),('f'),('f'), +('g'),('g'),('h'),('h'),('i'),('i'), +('j'),('j'),('k'),('k'),('l'),('l'), +('m'),('m'),('n'),('n'),('o'),('o'), +('p'),('p'),('q'),('q'),('r'),('r'), +('s'),('s'),('t'),('t'),('u'),('u'),('v'),('v'), +('w'),('w'),('x'),('x'), (NULL),(NULL); + +SET @save_join_cache_level=@@join_cache_level; +SET join_cache_level=0; + +select 1 +from t2 join t1 on +('i','w') not in (select t1.v1,t4.v2 from t4,t1,t3 where t3.v2 = t1.v1) LIMIT ROWS EXAMINED 500; +SET join_cache_level= @save_join_cache_level; + +DROP TABLE t1,t2,t3,t4; + --echo # End of 10.2 tests --echo # diff --git a/mysql-test/main/subselect_innodb.result b/mysql-test/main/subselect_innodb.result index 4d3d958c8c5..73ca2640491 100644 --- a/mysql-test/main/subselect_innodb.result +++ b/mysql-test/main/subselect_innodb.result @@ -615,6 +615,20 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select `test`.`t1`.`f1` AS `f1`,`test`.`t2`.`f2` AS `f2`,`test`.`t3`.`f3` AS `f3` from `test`.`t1` join `test`.`t2` semi join (`test`.`t4`) join `test`.`t3` where `test`.`t4`.`f4` = 1 and `test`.`t1`.`f1` >= `test`.`t2`.`f2` DROP TABLE t1,t2,t3,t4; +# +# MDEV-23535: SIGSEGV, SIGABRT and SIGILL in typeinfo for Item_func_set_collation (on optimized builds) +# +set @save_character_set_connection=@@character_set_connection; +set character_set_connection='utf8'; +CREATE TABLE t1(a DATETIME, b VARCHAR(50)) ENGINE=INNODB; +INSERT INTO t1 VALUES ('2019-03-10 02:55:05', '2019-03-10 02:55:05'); +CREATE TABLE t2(a VARCHAR(50)) ENGINE=INNODB; +INSERT INTO t2 VALUES ('2019-03-10 02:55:05'); +SELECT * FROM t1 WHERE (SELECT 1,CONCAT(a) FROM t1) = (SELECT 1,CONCAT(a) FROM t2); +a b +2019-03-10 02:55:05 2019-03-10 02:55:05 +DROP TABLE t1,t2; +set character_set_connection=@save_character_set_connection; # # MDEV-17362: SIGSEGV in JOIN::optimize_inner or Assertion `fixed == 0' # failed in Item_equal::fix_fields, server crashes after 2nd execution @@ -648,3 +662,4 @@ a b execute stmt; a b drop table t1,t2; +# End of 10.4 tests diff --git a/mysql-test/main/subselect_innodb.test b/mysql-test/main/subselect_innodb.test index b8d12d04a5e..37f8f40200e 100644 --- a/mysql-test/main/subselect_innodb.test +++ b/mysql-test/main/subselect_innodb.test @@ -611,6 +611,23 @@ FROM t1 DROP TABLE t1,t2,t3,t4; + +--echo # +--echo # MDEV-23535: SIGSEGV, SIGABRT and SIGILL in typeinfo for Item_func_set_collation (on optimized builds) +--echo # + +set @save_character_set_connection=@@character_set_connection; +set character_set_connection='utf8'; + +CREATE TABLE t1(a DATETIME, b VARCHAR(50)) ENGINE=INNODB; +INSERT INTO t1 VALUES ('2019-03-10 02:55:05', '2019-03-10 02:55:05'); +CREATE TABLE t2(a VARCHAR(50)) ENGINE=INNODB; +INSERT INTO t2 VALUES ('2019-03-10 02:55:05'); +SELECT * FROM t1 WHERE (SELECT 1,CONCAT(a) FROM t1) = (SELECT 1,CONCAT(a) FROM t2); +DROP TABLE t1,t2; + +set character_set_connection=@save_character_set_connection; + --echo # --echo # MDEV-17362: SIGSEGV in JOIN::optimize_inner or Assertion `fixed == 0' --echo # failed in Item_equal::fix_fields, server crashes after 2nd execution @@ -643,3 +660,5 @@ execute stmt; execute stmt; drop table t1,t2; + +--echo # End of 10.4 tests diff --git a/mysql-test/main/temp_table_symlink.result b/mysql-test/main/temp_table_symlink.result new file mode 100644 index 00000000000..1c5c68170ff --- /dev/null +++ b/mysql-test/main/temp_table_symlink.result @@ -0,0 +1,13 @@ +create table d1 (a int); +create temporary table t1 (a int); +create temporary table t2 (a int); +Got one of the listed errors +create temporary table t3 (a int) engine=Aria; +Got one of the listed errors +select * from information_schema.columns where table_schema='test'; +Got one of the listed errors +flush tables; +select * from d1; +a +drop temporary table t1; +drop table d1; diff --git a/mysql-test/main/temp_table_symlink.test b/mysql-test/main/temp_table_symlink.test new file mode 100644 index 00000000000..35f956e8890 --- /dev/null +++ b/mysql-test/main/temp_table_symlink.test @@ -0,0 +1,33 @@ +source include/not_windows.inc; + +# +# MDEV-23569 temporary tables can overwrite existing files +# + +let datadir=`select @@datadir`; +create table d1 (a int); +create temporary table t1 (a int); +perl; +chdir "$ENV{MYSQL_TMP_DIR}/mysqld.1/"; +for (<#sql*.MYI>) { + /^(#sql-temptable-[0-9a-f]+)(-[0-9a-f]+-)([0-9a-f]+)\.MYI$/ or die $_; + symlink "$ENV{datadir}/test/d1.MYI", sprintf "$1$2%x.MYI", hex($3)+1; + symlink "$ENV{datadir}/test/d1.MYI", sprintf "$1$2%x.MAI", hex($3)+1; + symlink "$ENV{datadir}/test/d1.MYI", sprintf "$1$2%x.MAI", hex($3)+2; + symlink "$ENV{datadir}/test/d1.MYI", sprintf "$1$2%x.MAI", hex($3)+3; + symlink "$ENV{datadir}/test/d1.MYI", "$1-0.MAI"; +} +EOF + +error 1,1030; +create temporary table t2 (a int); +error 1,1030; +create temporary table t3 (a int) engine=Aria; +error 1,1030; +select * from information_schema.columns where table_schema='test'; + +flush tables; +select * from d1; +drop temporary table t1; +remove_files_wildcard $MYSQL_TMP_DIR/mysqld.1 *sql*; +drop table d1; diff --git a/mysql-test/main/windows_debug.result b/mysql-test/main/windows_debug.result new file mode 100644 index 00000000000..e6816cdd99b --- /dev/null +++ b/mysql-test/main/windows_debug.result @@ -0,0 +1,4 @@ +# mdev-23741 sharing violation when renaming .frm file in ALTER +CREATE TABLE t(i int); +SET STATEMENT debug_dbug='+d,rename_sharing_violation' FOR ALTER TABLE t ADD PRIMARY KEY (i); +DROP TABLE t; diff --git a/mysql-test/main/windows_debug.test b/mysql-test/main/windows_debug.test new file mode 100644 index 00000000000..bb0880ddc55 --- /dev/null +++ b/mysql-test/main/windows_debug.test @@ -0,0 +1,11 @@ +# Windows-specific tests , debug mode + +--source include/have_debug.inc +--source include/windows.inc + +--echo # mdev-23741 sharing violation when renaming .frm file in ALTER +CREATE TABLE t(i int); +SET STATEMENT debug_dbug='+d,rename_sharing_violation' FOR ALTER TABLE t ADD PRIMARY KEY (i); +DROP TABLE t; + +#End of 10.3 tests diff --git a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_row.result b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_row.result index 1229ef885b4..3e400d4f272 100644 --- a/mysql-test/suite/binlog/r/binlog_mysqlbinlog_row.result +++ b/mysql-test/suite/binlog/r/binlog_mysqlbinlog_row.result @@ -5356,7 +5356,5 @@ START TRANSACTION #010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Table_map: `test`.`t1dec102` mapped to number # # at # #010909 4:46:40 server id 1 end_log_pos # CRC32 XXX Write_rows: table id # flags: STMT_END_F -### INSERT INTO `test`.`t1dec102` -### SET -### @1= + Error: Found Old DECIMAL (mysql-4.1 or earlier). Not enough metadata to display the value. diff --git a/mysql-test/suite/binlog/r/binlog_row_annotate.result b/mysql-test/suite/binlog/r/binlog_row_annotate.result index 5d70f7871ab..e41258ccafd 100644 --- a/mysql-test/suite/binlog/r/binlog_row_annotate.result +++ b/mysql-test/suite/binlog/r/binlog_row_annotate.result @@ -449,7 +449,6 @@ START TRANSACTION ### DELETE FROM `test1`.`t1` ### WHERE ### @1=3 /* INT meta=0 nullable=1 is_null=0 */ -'/*!*/; # at # #010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 SET TIMESTAMP=1000000000/*!*/; @@ -1073,7 +1072,6 @@ START TRANSACTION ### DELETE FROM `test1`.`t1` ### WHERE ### @1=3 /* INT meta=0 nullable=1 is_null=0 */ -'/*!*/; # at # #010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 SET TIMESTAMP=1000000000/*!*/; diff --git a/mysql-test/suite/binlog/r/binlog_show_binlog_event_random_pos.result b/mysql-test/suite/binlog/r/binlog_show_binlog_event_random_pos.result index 358422c5842..c2e634ebe82 100644 --- a/mysql-test/suite/binlog/r/binlog_show_binlog_event_random_pos.result +++ b/mysql-test/suite/binlog/r/binlog_show_binlog_event_random_pos.result @@ -9,4 +9,7 @@ INSERT INTO t1 VALUES (repeat('a', 255), repeat('a', 255),repeat('a', 255),repea INSERT INTO t1 VALUES (repeat('a', 255), repeat('a', 255),repeat('a', 255),repeat('a', 255),repeat('a', 255)); UPDATE t1 SET c1=repeat('b',255); INSERT INTO t1 VALUES (repeat('a', 255), repeat('a', 255),repeat('a', 255),repeat('a', 255),repeat('a', 255)); +SHOW BINLOG EVENTS FROM POS; +ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Invalid pos specified. Requested from pos:POS is greater than actual file size:MAX_POS + DROP TABLE t1; diff --git a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_row_frag.test b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_row_frag.test index 9f0d0f2588b..3e18ef1e351 100644 --- a/mysql-test/suite/binlog/t/binlog_mysqlbinlog_row_frag.test +++ b/mysql-test/suite/binlog/t/binlog_mysqlbinlog_row_frag.test @@ -11,8 +11,7 @@ SELECT a into @a from t; FLUSH LOGS; DELETE FROM t; -# Todo: MDEV-10362 to test multi-row Rows_log_event:s in verbose mode ---exec $MYSQL_BINLOG -vv --debug-binlog-row-event-max-encoded-size=256 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog.sql +--exec $MYSQL_BINLOG --verbose --debug-binlog-row-event-max-encoded-size=256 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog.sql --let SEARCH_PATTERN= BINLOG @binlog_fragment_0, @binlog_fragment_1 --let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.sql diff --git a/mysql-test/suite/binlog/t/binlog_show_binlog_event_random_pos.test b/mysql-test/suite/binlog/t/binlog_show_binlog_event_random_pos.test index e6a9e1cb2c1..05e6967c538 100644 --- a/mysql-test/suite/binlog/t/binlog_show_binlog_event_random_pos.test +++ b/mysql-test/suite/binlog/t/binlog_show_binlog_event_random_pos.test @@ -34,4 +34,9 @@ while ($pos <= $max_pos) --enable_query_log } +# Testing a case where input position is greater than actual binlog file size. +--replace_result $pos POS $max_pos MAX_POS +--error 1220 +eval SHOW BINLOG EVENTS FROM $pos; + DROP TABLE t1; diff --git a/mysql-test/suite/binlog_encryption/binlog_row_annotate.result b/mysql-test/suite/binlog_encryption/binlog_row_annotate.result index b5e6721ace1..142714f2377 100644 --- a/mysql-test/suite/binlog_encryption/binlog_row_annotate.result +++ b/mysql-test/suite/binlog_encryption/binlog_row_annotate.result @@ -456,7 +456,6 @@ START TRANSACTION ### DELETE FROM `test1`.`t1` ### WHERE ### @1=3 /* INT meta=0 nullable=1 is_null=0 */ -'/*!*/; # at # #010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0 SET TIMESTAMP=1000000000/*!*/; diff --git a/mysql-test/suite/compat/oracle/r/parser.result b/mysql-test/suite/compat/oracle/r/parser.result index c5810c7c1d5..3f02382b6e4 100644 --- a/mysql-test/suite/compat/oracle/r/parser.result +++ b/mysql-test/suite/compat/oracle/r/parser.result @@ -644,6 +644,121 @@ END; # End of 10.3 tests # # +# MDEV-21998: Server crashes in st_select_lex::add_table_to_list +# upon mix of KILL and sequences +# +KILL ( SELECT 1 ) + LASTVAL(s); +ERROR 42000: KILL does not support subqueries or stored functions +KILL LASTVAL(s); +ERROR 42000: KILL does not support subqueries or stored functions +# +# MDEV-23094: Multiple calls to a Stored Procedure from another +# Stored Procedure crashes server +# +create table t1 (id1 int primary key, data1 int); +create table t2 (id2 int primary key, data2 int); +create procedure p1(id int,dt int) as +begin +if (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) +then +select 1; +end if; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(id int, dt int) as +begin +case (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) +when 1 then +select 1; +else +select 0; +end case; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(id int, dt int) as +begin +declare wcont int default 1; +begin +while (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) and wcont +loop +select 1; +set wcont=0; +end loop; +end; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(id int, dt int) as +begin +declare count int default 1; +begin +repeat +select 1; +set count=count+1; +until (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) and +count < 3 +end repeat; +end; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +create procedure p1(id int, dt int) as +begin +for i in 1..(exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)) +loop +select 1; +end loop; +end // +call p1(1,2); +1 +1 +call p1(1,2); +1 +1 +drop procedure p1; +set sql_mode=ORACLE; +create or replace procedure p1(id int, dt int) as +begin +while (1) +loop +exit when (exists(select * from t1 where id1 = id and data1 = dt) or +not exists (select * from t2 where id2 = id and data2 = dt)); +end loop; +end; +// +call p1(1,2); +call p1(1,2); +drop procedure p1; +drop table t1,t2; +# End of 10.4 tests +# # Start of 10.5 tests # # diff --git a/mysql-test/suite/compat/oracle/t/parser.test b/mysql-test/suite/compat/oracle/t/parser.test index 99355c57dc3..d5d3b39f0b9 100644 --- a/mysql-test/suite/compat/oracle/t/parser.test +++ b/mysql-test/suite/compat/oracle/t/parser.test @@ -462,6 +462,137 @@ DELIMITER ;// --echo # +--echo # MDEV-21998: Server crashes in st_select_lex::add_table_to_list +--echo # upon mix of KILL and sequences +--echo # + +--error ER_SUBQUERIES_NOT_SUPPORTED +KILL ( SELECT 1 ) + LASTVAL(s); +--error ER_SUBQUERIES_NOT_SUPPORTED +KILL LASTVAL(s); + +--echo # +--echo # MDEV-23094: Multiple calls to a Stored Procedure from another +--echo # Stored Procedure crashes server +--echo # + +create table t1 (id1 int primary key, data1 int); +create table t2 (id2 int primary key, data2 int); + +delimiter //; +create procedure p1(id int,dt int) as +begin + if (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) + then + select 1; + end if; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(id int, dt int) as +begin +case (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) +when 1 then + select 1; +else + select 0; +end case; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(id int, dt int) as +begin +declare wcont int default 1; +begin + while (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) and wcont + loop + select 1; + set wcont=0; + end loop; +end; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(id int, dt int) as +begin +declare count int default 1; +begin + repeat + select 1; + set count=count+1; + until (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) and + count < 3 + end repeat; +end; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +create procedure p1(id int, dt int) as +begin +for i in 1..(exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)) +loop + select 1; +end loop; +end // +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +delimiter //; +set sql_mode=ORACLE; +create or replace procedure p1(id int, dt int) as +begin + while (1) + loop + exit when (exists(select * from t1 where id1 = id and data1 = dt) or + not exists (select * from t2 where id2 = id and data2 = dt)); + end loop; +end; +// +delimiter ;// + +call p1(1,2); +call p1(1,2); + +drop procedure p1; + +drop table t1,t2; + +--echo # End of 10.4 tests + +--echo # --echo # Start of 10.5 tests --echo # diff --git a/mysql-test/suite/encryption/r/create_or_replace.result b/mysql-test/suite/encryption/r/create_or_replace.result index f876de7346f..69ea113289b 100644 --- a/mysql-test/suite/encryption/r/create_or_replace.result +++ b/mysql-test/suite/encryption/r/create_or_replace.result @@ -1,8 +1,5 @@ +SET @save_threads = @@GLOBAL.innodb_encryption_threads; SET default_storage_engine = InnoDB; -CREATE TABLE t1 (pk INT PRIMARY KEY, c VARCHAR(256)); -CREATE TABLE t2 AS SELECT * FROM t1; -drop table t1,t2; -SET GLOBAL innodb_encryption_threads = 0; SET GLOBAL innodb_encryption_threads = 4; CREATE TABLE `table10_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int, key (`col_int_key` ),primary key (pk)) engine=innodb; INSERT /*! IGNORE */ INTO table10_int_autoinc VALUES (NULL, NULL, -474021888) , (1, NULL, NULL) , (1141047296, NULL, NULL) , (NULL, NULL, NULL) , (NULL, NULL, 1) , (NULL, NULL, 9) , (0, NULL, 1225785344) , (NULL, NULL, 1574174720) , (2, NULL, NULL) , (6, NULL, 3); @@ -14,14 +11,9 @@ INSERT IGNORE INTO `table1_int_autoinc` ( `col_int` ) VALUES ( 1 ), ( 0 ), ( 7 ) INSERT IGNORE INTO `table10_int_autoinc` ( `col_int` ) VALUES ( 6 ), ( 2 ), ( 3 ), ( 6 ); connect con1,localhost,root,,test; connect con2,localhost,root,,test; -connection default; -drop table if exists create_or_replace_t, table1_int_autoinc, table0_int_autoinc, table10_int_autoinc; disconnect con1; disconnect con2; -SET GLOBAL innodb_encrypt_tables = OFF; -SET GLOBAL innodb_encryption_threads = 4; -# Wait max 10 min for key encryption threads to decrypt all spaces -# Success! -SET GLOBAL innodb_encryption_threads = 0; -SET GLOBAL innodb_encrypt_tables = OFF; -# restart +connection default; +drop table create_or_replace_t, table1_int_autoinc, table0_int_autoinc, +table10_int_autoinc; +SET GLOBAL innodb_encryption_threads = @save_threads; diff --git a/mysql-test/suite/encryption/r/create_or_replace_big.result b/mysql-test/suite/encryption/r/create_or_replace_big.result new file mode 100644 index 00000000000..2eabab45f0b --- /dev/null +++ b/mysql-test/suite/encryption/r/create_or_replace_big.result @@ -0,0 +1,20 @@ +SET default_storage_engine = InnoDB; +CREATE TABLE t1 (pk INT PRIMARY KEY, c VARCHAR(256)); +CREATE TABLE t2 AS SELECT * FROM t1; +drop table t1,t2; +SET GLOBAL innodb_encryption_threads = 0; +SET GLOBAL innodb_encryption_threads = 4; +CREATE TABLE `table10_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int, key (`col_int_key` ),primary key (pk)) engine=innodb; +INSERT /*! IGNORE */ INTO table10_int_autoinc VALUES (NULL, NULL, -474021888) , (1, NULL, NULL) , (1141047296, NULL, NULL) , (NULL, NULL, NULL) , (NULL, NULL, 1) , (NULL, NULL, 9) , (0, NULL, 1225785344) , (NULL, NULL, 1574174720) , (2, NULL, NULL) , (6, NULL, 3); +CREATE TABLE `table1_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int,key (`col_int_key` ), primary key (pk)) engine=innodb; +CREATE TABLE `table0_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int, key (`col_int_key` ),primary key (pk)) engine=innodb; +INSERT /*! IGNORE */ INTO table1_int_autoinc VALUES (4, NULL, NULL); +INSERT IGNORE INTO `table0_int_autoinc` ( `col_int_key` ) VALUES ( 1 ), ( 3 ), ( 4 ), ( 1 ); +INSERT IGNORE INTO `table1_int_autoinc` ( `col_int` ) VALUES ( 1 ), ( 0 ), ( 7 ), ( 9 ); +INSERT IGNORE INTO `table10_int_autoinc` ( `col_int` ) VALUES ( 6 ), ( 2 ), ( 3 ), ( 6 ); +# Wait max 10 min for key encryption threads to decrypt all spaces +# Success! +SET GLOBAL innodb_encryption_threads = 0; +SET GLOBAL innodb_encrypt_tables = OFF; +DROP TABLE table0_int_autoinc, table1_int_autoinc, table10_int_autoinc; +# restart diff --git a/mysql-test/suite/encryption/t/create_or_replace.opt b/mysql-test/suite/encryption/t/create_or_replace.opt index 7d3f2da7971..66892f34897 100644 --- a/mysql-test/suite/encryption/t/create_or_replace.opt +++ b/mysql-test/suite/encryption/t/create_or_replace.opt @@ -1 +1 @@ ---innodb-tablespaces-encryption +--innodb-encrypt-tables diff --git a/mysql-test/suite/encryption/t/create_or_replace.test b/mysql-test/suite/encryption/t/create_or_replace.test index 3b2970e5162..2ebd599d460 100644 --- a/mysql-test/suite/encryption/t/create_or_replace.test +++ b/mysql-test/suite/encryption/t/create_or_replace.test @@ -1,41 +1,10 @@ --source include/have_innodb.inc --source include/have_file_key_management_plugin.inc ---source include/not_embedded.inc -# This is needed for longer testcase timeout at least P7/P8 ---source include/big_test.inc +--source include/count_sessions.inc -# -# MDEV-8164: Server crashes in pfs_mutex_enter_func after fil_crypt_is_closing or alike -# -SET default_storage_engine = InnoDB; - -CREATE TABLE t1 (pk INT PRIMARY KEY, c VARCHAR(256)); -CREATE TABLE t2 AS SELECT * FROM t1; - ---disable_abort_on_error ---disable_warnings ---disable_query_log +SET @save_threads = @@GLOBAL.innodb_encryption_threads; -let $i = 40; -while ($i) -{ -SET GLOBAL innodb_encrypt_tables = ON; -SET GLOBAL innodb_encryption_threads = 1; -CREATE OR REPLACE TABLE t1 AS SELECT * FROM t2; -CREATE OR REPLACE TABLE t2 AS SELECT * FROM t1; -SET GLOBAL innodb_encryption_rotation_iops = 100; -SET GLOBAL innodb_encrypt_tables = OFF; -CREATE OR REPLACE TABLE t2 AS SELECT * FROM t1; -CREATE OR REPLACE TABLE t1 AS SELECT * FROM t2; -dec $i; -} - ---enable_abort_on_error ---enable_warnings ---enable_query_log - -drop table t1,t2; -SET GLOBAL innodb_encryption_threads = 0; +SET default_storage_engine = InnoDB; # # MDEV-8173: InnoDB; Failing assertion: crypt_data->type == 1 @@ -58,11 +27,9 @@ INSERT IGNORE INTO `table10_int_autoinc` ( `col_int` ) VALUES ( 6 ), ( 2 ), ( 3 --connect (con1,localhost,root,,test) --connect (con2,localhost,root,,test) ---disable_abort_on_error ---disable_warnings --disable_query_log -let $i = 500; +let $i = 100; while ($i) { connection con1; @@ -101,42 +68,11 @@ dec $i; } --enable_query_log +disconnect con1; +disconnect con2; connection default; -drop table if exists create_or_replace_t, table1_int_autoinc, table0_int_autoinc, table10_int_autoinc; ---disconnect con1 ---disconnect con2 ---enable_abort_on_error ---enable_warnings - -SET GLOBAL innodb_encrypt_tables = OFF; -SET GLOBAL innodb_encryption_threads = 4; - ---echo # Wait max 10 min for key encryption threads to decrypt all spaces -let $cnt=600; -while ($cnt) -{ - let $success=`SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0`; - if ($success) - { - let $cnt=0; - } - if (!$success) - { - real_sleep 1; - dec $cnt; - } -} -if (!$success) -{ - SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION; - SHOW STATUS LIKE 'innodb_encryption%'; - -- die Timeout waiting for encryption threads -} ---echo # Success! - -SET GLOBAL innodb_encryption_threads = 0; -SET GLOBAL innodb_encrypt_tables = OFF; - -# Make sure that all dirty pages are flushed +drop table create_or_replace_t, table1_int_autoinc, table0_int_autoinc, +table10_int_autoinc; --- source include/restart_mysqld.inc +SET GLOBAL innodb_encryption_threads = @save_threads; +--source include/wait_until_count_sessions.inc diff --git a/mysql-test/suite/encryption/t/create_or_replace_big.opt b/mysql-test/suite/encryption/t/create_or_replace_big.opt new file mode 100644 index 00000000000..7d3f2da7971 --- /dev/null +++ b/mysql-test/suite/encryption/t/create_or_replace_big.opt @@ -0,0 +1 @@ +--innodb-tablespaces-encryption diff --git a/mysql-test/suite/encryption/t/create_or_replace_big.test b/mysql-test/suite/encryption/t/create_or_replace_big.test new file mode 100644 index 00000000000..133bdfa3cb2 --- /dev/null +++ b/mysql-test/suite/encryption/t/create_or_replace_big.test @@ -0,0 +1,86 @@ +--source include/have_innodb.inc +--source include/have_file_key_management_plugin.inc +--source include/not_embedded.inc +# This is needed for longer testcase timeout at least P7/P8 +--source include/big_test.inc + +# +# MDEV-8164: Server crashes in pfs_mutex_enter_func after fil_crypt_is_closing or alike +# +SET default_storage_engine = InnoDB; + +CREATE TABLE t1 (pk INT PRIMARY KEY, c VARCHAR(256)); +CREATE TABLE t2 AS SELECT * FROM t1; + +--disable_abort_on_error +--disable_warnings +--disable_query_log + +let $i = 40; +while ($i) +{ +SET GLOBAL innodb_encrypt_tables = ON; +SET GLOBAL innodb_encryption_threads = 1; +CREATE OR REPLACE TABLE t1 AS SELECT * FROM t2; +CREATE OR REPLACE TABLE t2 AS SELECT * FROM t1; +SET GLOBAL innodb_encryption_rotation_iops = 100; +SET GLOBAL innodb_encrypt_tables = OFF; +CREATE OR REPLACE TABLE t2 AS SELECT * FROM t1; +CREATE OR REPLACE TABLE t1 AS SELECT * FROM t2; +dec $i; +} + +--enable_abort_on_error +--enable_warnings +--enable_query_log + +drop table t1,t2; +SET GLOBAL innodb_encryption_threads = 0; + +# +# MDEV-8173: InnoDB; Failing assertion: crypt_data->type == 1 +# + +SET GLOBAL innodb_encryption_threads = 4; + +CREATE TABLE `table10_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int, key (`col_int_key` ),primary key (pk)) engine=innodb; +INSERT /*! IGNORE */ INTO table10_int_autoinc VALUES (NULL, NULL, -474021888) , (1, NULL, NULL) , (1141047296, NULL, NULL) , (NULL, NULL, NULL) , (NULL, NULL, 1) , (NULL, NULL, 9) , (0, NULL, 1225785344) , (NULL, NULL, 1574174720) , (2, NULL, NULL) , (6, NULL, 3); + +CREATE TABLE `table1_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int,key (`col_int_key` ), primary key (pk)) engine=innodb; + +CREATE TABLE `table0_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int, key (`col_int_key` ),primary key (pk)) engine=innodb; + +INSERT /*! IGNORE */ INTO table1_int_autoinc VALUES (4, NULL, NULL); +INSERT IGNORE INTO `table0_int_autoinc` ( `col_int_key` ) VALUES ( 1 ), ( 3 ), ( 4 ), ( 1 ); +INSERT IGNORE INTO `table1_int_autoinc` ( `col_int` ) VALUES ( 1 ), ( 0 ), ( 7 ), ( 9 ); +INSERT IGNORE INTO `table10_int_autoinc` ( `col_int` ) VALUES ( 6 ), ( 2 ), ( 3 ), ( 6 ); + +--echo # Wait max 10 min for key encryption threads to decrypt all spaces +let $cnt=600; +while ($cnt) +{ + let $success=`SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0`; + if ($success) + { + let $cnt=0; + } + if (!$success) + { + real_sleep 1; + dec $cnt; + } +} +if (!$success) +{ + SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION; + SHOW STATUS LIKE 'innodb_encryption%'; + -- die Timeout waiting for encryption threads +} +--echo # Success! + +SET GLOBAL innodb_encryption_threads = 0; +SET GLOBAL innodb_encrypt_tables = OFF; + +DROP TABLE table0_int_autoinc, table1_int_autoinc, table10_int_autoinc; + +-- source include/restart_mysqld.inc diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def index 1e993bca1e9..baff20752be 100644 --- a/mysql-test/suite/galera/disabled.def +++ b/mysql-test/suite/galera/disabled.def @@ -16,6 +16,7 @@ MDEV-16509 : MDEV-21523 galera.MDEV-16509 MDEV-20225 : MDEV-20886 galera.MDEV-20225 MW-286 : MDEV-18464 Killing thread can cause mutex deadlock if done concurrently with Galera/replication victim kill MW-328A : MDEV-22666 galera.MW-328A MTR failed: "Semaphore wait has lasted > 600 seconds" and do not release port 16002 +MW-328B : MDEV-22666 galera.MW-328A MTR failed: "Semaphore wait has lasted > 600 seconds" and do not release port 16002 MW-329 : MDEV-19962 Galera test failure on MW-329 galera.galera_defaults : MDEV-21494 Galera test sporadic failure on galera.galera_defaults galera_as_slave_replication_bundle : MDEV-15785 OPTION_GTID_BEGIN is set in Gtid_log_event::do_apply_event() diff --git a/mysql-test/suite/galera/r/MDEV-22055.result b/mysql-test/suite/galera/r/MDEV-22055.result new file mode 100644 index 00000000000..651f8501a0a --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-22055.result @@ -0,0 +1,18 @@ +connection node_2; +connection node_1; +ROLLBACK AND CHAIN; +CREATE TABLE t1(a int not null primary key) engine=innodb; +INSERT INTO t1 values (1); +BEGIN; +INSERT INTO t1 values (2); +ROLLBACK AND CHAIN; +SELECT * FROM t1; +a +1 +connection node_2; +SET SESSION wsrep_sync_wait=15; +SELECT * FROM t1; +a +1 +connection node_1; +DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/galera_autoinc_sst_mariabackup.result b/mysql-test/suite/galera/r/galera_autoinc_sst_mariabackup.result index 7c98b3e85ed..0ba269558d5 100644 --- a/mysql-test/suite/galera/r/galera_autoinc_sst_mariabackup.result +++ b/mysql-test/suite/galera/r/galera_autoinc_sst_mariabackup.result @@ -4,48 +4,45 @@ connection node_1; connection node_2; connection node_1; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; -CREATE PROCEDURE p1 () -BEGIN -DECLARE x INT DEFAULT 1; -DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END; -WHILE 1 DO -INSERT INTO t1 VALUES (DEFAULT); -COMMIT; -END WHILE; -END| -CALL p1();; -connection node_2; -CALL p1();; +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; connection node_2a; Killing server ... -INSERT INTO t1 VALUES (DEFAULT); -connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; -connection node_1a; -INSERT INTO t1 VALUES (DEFAULT); connection node_1; -Got one of the listed errors -connection node_2; -Got one of the listed errors -connection node_1a; +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); connection node_2a; -count_equal -1 -CALL mtr.add_suppression("WSREP: Action message in non-primary configuration from member 0"); -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -VARIABLE_VALUE -2 -SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -VARIABLE_VALUE = 2 -1 +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; connection node_1a; -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -VARIABLE_VALUE -2 -SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -VARIABLE_VALUE = 2 -1 -DROP PROCEDURE p1; +SELECT COUNT(*) FROM t1; +COUNT(*) +132 +connection node_2a; +SELECT COUNT(*) FROM t1; +COUNT(*) +132 +connection node_1; DROP TABLE t1; CALL mtr.add_suppression("gcs_caused\\(\\) returned -1 \\(Operation not permitted\\)"); CALL mtr.add_suppression("WSREP: Action message in non-primary configuration from member 0"); +disconnect node_1a; +disconnect node_2a; diff --git a/mysql-test/suite/galera/r/galera_fk_cascade_delete.result b/mysql-test/suite/galera/r/galera_fk_cascade_delete.result index 291d641db88..16db26c3c6b 100644 --- a/mysql-test/suite/galera/r/galera_fk_cascade_delete.result +++ b/mysql-test/suite/galera/r/galera_fk_cascade_delete.result @@ -1,5 +1,10 @@ connection node_2; connection node_1; +# +# test phase with cascading foreign key through 3 tables +# +connection node_1; +set wsrep_sync_wait=0; CREATE TABLE grandparent ( id INT NOT NULL PRIMARY KEY ) ENGINE=InnoDB; @@ -21,14 +26,15 @@ INSERT INTO grandparent VALUES (1),(2); INSERT INTO parent VALUES (1,1), (2,2); INSERT INTO child VALUES (1,1), (2,2); connection node_2; +set wsrep_sync_wait=0; DELETE FROM grandparent WHERE id = 1; connection node_1; -SELECT COUNT(*) = 0 FROM parent WHERE grandparent_id = 1; -COUNT(*) = 0 -1 -SELECT COUNT(*) = 0 FROM child WHERE parent_id = 1; -COUNT(*) = 0 -1 +SELECT COUNT(*), COUNT(*) = 0 FROM parent WHERE grandparent_id = 1; +COUNT(*) COUNT(*) = 0 +0 1 +SELECT COUNT(*), COUNT(*) = 0 FROM child WHERE parent_id = 1; +COUNT(*) COUNT(*) = 0 +0 1 DROP TABLE child; DROP TABLE parent; DROP TABLE grandparent; diff --git a/mysql-test/suite/galera/r/galera_fk_cascade_delete_debug.result b/mysql-test/suite/galera/r/galera_fk_cascade_delete_debug.result new file mode 100644 index 00000000000..bd76692b27c --- /dev/null +++ b/mysql-test/suite/galera/r/galera_fk_cascade_delete_debug.result @@ -0,0 +1,70 @@ +connection node_2; +connection node_1; +# +# test phase with foreign key of varchar type +# +connection node_1; +CREATE TABLE parent ( +`id` varchar(36) COLLATE utf8_unicode_ci NOT NULL, +PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +CREATE TABLE child ( +`id` int NOT NULL, +`parent_id` varchar(36) COLLATE utf8_unicode_ci DEFAULT NULL, +PRIMARY KEY (`id`), +KEY `parent_id` (`parent_id`), +CONSTRAINT `ipallocations_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +INSERT INTO parent VALUES ('row one'), ('row two'); +INSERT INTO child VALUES (1,'row one'), (2,'row two'); +connection node_2; +DELETE FROM parent; +connection node_1; +SELECT COUNT(*), COUNT(*) = 0 FROM parent; +COUNT(*) COUNT(*) = 0 +0 1 +SELECT COUNT(*), COUNT(*) = 0 FROM child; +COUNT(*) COUNT(*) = 0 +0 1 +DROP TABLE child; +DROP TABLE parent; +# +# test phase with MM conflict in FK cascade +# +connection node_1; +set wsrep_retry_autocommit=0; +CREATE TABLE parent ( +id INT NOT NULL PRIMARY KEY +) ENGINE=InnoDB; +CREATE TABLE child ( +id INT NOT NULL PRIMARY KEY, +j int default 0, +parent_id INT, +FOREIGN KEY (parent_id) +REFERENCES parent(id) +ON DELETE CASCADE +) ENGINE=InnoDB; +INSERT INTO parent VALUES (1); +INSERT INTO child VALUES (1,0,1); +connection node_2; +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; +SET GLOBAL debug_dbug = "d,sync.wsrep_apply_cb"; +connection node_2; +DELETE FROM parent; +connection node_1a; +SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached"; +connection node_1; +update child set j=2;; +connection node_1a; +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb"; +SET GLOBAL debug_dbug = ""; +SET DEBUG_SYNC = "RESET"; +connection node_1; +SELECT COUNT(*), COUNT(*) = 0 FROM parent; +COUNT(*) COUNT(*) = 0 +0 1 +SELECT COUNT(*), COUNT(*) = 0 FROM child; +COUNT(*) COUNT(*) = 0 +0 1 +DROP TABLE child; +DROP TABLE parent; diff --git a/mysql-test/suite/galera/r/galera_trigger.result b/mysql-test/suite/galera/r/galera_trigger.result new file mode 100644 index 00000000000..40b63b327af --- /dev/null +++ b/mysql-test/suite/galera/r/galera_trigger.result @@ -0,0 +1,78 @@ +connection node_2; +connection node_1; +CREATE TABLE IF NOT EXISTS t1 (id int(10) not null primary key) engine=innodb; +CREATE OR REPLACE TRIGGER tr1 +BEFORE INSERT ON t1 FOR EACH ROW +BEGIN +SET NEW.id = 100; +END| +INSERT INTO t1 VALUES (1); +SELECT * from t1; +id +100 +CREATE OR REPLACE TRIGGER tr1 +BEFORE INSERT ON t1 FOR EACH ROW +BEGIN +SET NEW.id = 200; +END| +connection node_2; +SET SESSION wsrep_sync_wait=15; +SELECT * FROM t1; +id +100 +INSERT INTO t1 values (2); +SELECT * FROM t1; +id +100 +200 +connection node_1; +SELECT * FROM t1; +id +100 +200 +DROP TRIGGER tr1; +DROP TABLE t1; +connection node_1; +CREATE TABLE t1(id int not null auto_increment, value int not null, primary key (id)) engine=innodb; +CREATE TABLE t2(id int not null auto_increment, tbl varchar(64) not null, action varchar(64) not null, primary key (id)); +create trigger log_insert after insert on t1 +for each row begin +insert into t2(tbl, action) values ('t1', 'INSERT'); +end| +insert into t1(value) values (1); +insert into t1(value) values (2); +connection node_2; +set session wsrep_sync_wait=15; +insert into t1(value) values (3); +insert into t1(value) values (4); +select * from t2; +id tbl action +1 t1 INSERT +3 t1 INSERT +4 t1 INSERT +6 t1 INSERT +connection node_1; +drop trigger if exists log_insert; +insert into t1(value) values (5); +select * from t2; +id tbl action +1 t1 INSERT +3 t1 INSERT +4 t1 INSERT +6 t1 INSERT +connection node_2; +insert into t1(value) values (6); +select * from t2; +id tbl action +1 t1 INSERT +3 t1 INSERT +4 t1 INSERT +6 t1 INSERT +connection node_1; +select * from t2; +id tbl action +1 t1 INSERT +3 t1 INSERT +4 t1 INSERT +6 t1 INSERT +drop table t1, t2; diff --git a/mysql-test/suite/galera/r/galera_wan_restart_ist.result b/mysql-test/suite/galera/r/galera_wan_restart_ist.result index 7b87d534d92..46865a9c48c 100644 --- a/mysql-test/suite/galera/r/galera_wan_restart_ist.result +++ b/mysql-test/suite/galera/r/galera_wan_restart_ist.result @@ -6,11 +6,11 @@ connection node_1; connection node_2; connection node_3; connection node_4; -SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -VARIABLE_VALUE = 4 -1 +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +EXPECT_4 +4 connection node_1; -CREATE TABLE t1 (f1 INTEGER); +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=INNODB; INSERT INTO t1 VALUES (1); connection node_2; INSERT INTO t1 VALUES (2); @@ -22,60 +22,78 @@ connection node_3; INSERT INTO t1 VALUES (13); Shutting down server ... connection node_1; +SELECT VARIABLE_VALUE AS EXPECT_3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +EXPECT_3 +3 INSERT INTO t1 VALUES (11); connection node_2; INSERT INTO t1 VALUES (12); connection node_4; INSERT INTO t1 VALUES (14); connection node_3; +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +EXPECT_4 +4 INSERT INTO t1 VALUES (131); connection node_2; INSERT INTO t1 VALUES (22); Shutting down server ... connection node_1; +SELECT VARIABLE_VALUE AS EXPECT_3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +EXPECT_3 +3 INSERT INTO t1 VALUES (21); connection node_3; INSERT INTO t1 VALUES (23); connection node_4; INSERT INTO t1 VALUES (24); connection node_2; +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +EXPECT_4 +4 INSERT INTO t1 VALUES (221); connection node_4; INSERT INTO t1 VALUES (34); Shutting down server ... connection node_1; +SELECT VARIABLE_VALUE AS EXPECT_3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +EXPECT_3 +3 INSERT INTO t1 VALUES (31); connection node_2; INSERT INTO t1 VALUES (32); connection node_3; INSERT INTO t1 VALUES (33); connection node_4; +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +EXPECT_4 +4 INSERT INTO t1 VALUES (341); connection node_1; -SELECT COUNT(*) = 19 FROM t1; -COUNT(*) = 19 -1 +SELECT COUNT(*) AS EXPECT_19 FROM t1; +EXPECT_19 +19 connection node_2; SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; VARIABLE_VALUE = 4 1 -SELECT COUNT(*) = 19 FROM t1; -COUNT(*) = 19 -1 +SELECT COUNT(*) AS EXPECT_19 FROM t1; +EXPECT_19 +19 connection node_3; SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; VARIABLE_VALUE = 4 1 -SELECT COUNT(*) = 19 FROM t1; -COUNT(*) = 19 -1 +SELECT COUNT(*) AS EXPECT_19 FROM t1; +EXPECT_19 +19 connection node_4; SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; VARIABLE_VALUE = 4 1 -SELECT COUNT(*) = 19 FROM t1; -COUNT(*) = 19 -1 +SELECT COUNT(*) AS EXPECT_19 FROM t1; +EXPECT_19 +19 connection node_1; DROP TABLE t1; CALL mtr.add_suppression("There are no nodes in the same segment that will ever be able to become donors, yet there is a suitable donor outside"); @@ -86,5 +104,6 @@ CALL mtr.add_suppression("There are no nodes in the same segment that will ever CALL mtr.add_suppression("Action message in non-primary configuration from member 0"); connection node_4; CALL mtr.add_suppression("Action message in non-primary configuration from member 0"); -disconnect node_2; -disconnect node_1; +connection node_1; +disconnect node_3; +disconnect node_4; diff --git a/mysql-test/suite/galera/t/MDEV-22055.test b/mysql-test/suite/galera/t/MDEV-22055.test new file mode 100644 index 00000000000..ae29c456bf0 --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-22055.test @@ -0,0 +1,19 @@ +--source include/galera_cluster.inc + +ROLLBACK AND CHAIN; + +CREATE TABLE t1(a int not null primary key) engine=innodb; +INSERT INTO t1 values (1); + +BEGIN; +INSERT INTO t1 values (2); +ROLLBACK AND CHAIN; + +SELECT * FROM t1; + +--connection node_2 +SET SESSION wsrep_sync_wait=15; +SELECT * FROM t1; + +--connection node_1 +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_autoinc_sst_mariabackup.test b/mysql-test/suite/galera/t/galera_autoinc_sst_mariabackup.test index 72952d271d5..ff8bdc9c4cc 100644 --- a/mysql-test/suite/galera/t/galera_autoinc_sst_mariabackup.test +++ b/mysql-test/suite/galera/t/galera_autoinc_sst_mariabackup.test @@ -2,93 +2,62 @@ # Test that autoincrement works correctly while the cluster membership # is changing and SST takes place. # - --source include/big_test.inc --source include/galera_cluster.inc ---source include/have_innodb.inc --source include/have_mariabackup.inc +--source include/force_restart.inc --let $node_1=node_1 --let $node_2=node_2 --source include/auto_increment_offset_save.inc --connection node_1 ---let $connection_id = `SELECT CONNECTION_ID()` - CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; -# Issue an endless stream of autoincrement inserts - -DELIMITER |; -CREATE PROCEDURE p1 () -BEGIN - DECLARE x INT DEFAULT 1; - DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END; - - WHILE 1 DO - INSERT INTO t1 VALUES (DEFAULT); - COMMIT; - END WHILE; -END| -DELIMITER ;| - ---send CALL p1(); ---sleep 1 - ---connection node_2 ---send CALL p1(); ---sleep 1 +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); # Kill and restart node #2 - --connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2 --connection node_2a --source include/kill_galera.inc - --remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat ---source include/start_mysqld.inc - -INSERT INTO t1 VALUES (DEFAULT); - -# Terminate the stored procedure - ---connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1 ---connection node_1a ---disable_query_log ---eval KILL CONNECTION $connection_id ---enable_query_log -INSERT INTO t1 VALUES (DEFAULT); --connection node_1 -# CR_SERVER_LOST ---error 2013,2006 ---reap - ---connection node_2 -# CR_SERVER_LOST ---error 2013,2006 ---reap +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); -# Confirm that the count is correct and that the cluster is intact +--connection node_2a +--source include/start_mysqld.inc +--source include/wait_until_connected_again.inc + +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); +--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1 --connection node_1a ---let $count = `SELECT COUNT(*) FROM t1` +SELECT COUNT(*) FROM t1; --connection node_2a ---disable_query_log ---eval SELECT COUNT(*) = $count AS count_equal FROM t1 ---enable_query_log - -CALL mtr.add_suppression("WSREP: Action message in non-primary configuration from member 0"); - -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; - ---connection node_1a -SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +SELECT COUNT(*) FROM t1; -DROP PROCEDURE p1; +--connection node_1 DROP TABLE t1; CALL mtr.add_suppression("gcs_caused\\(\\) returned -1 \\(Operation not permitted\\)"); @@ -97,3 +66,6 @@ CALL mtr.add_suppression("WSREP: Action message in non-primary configuration fro --let $node_1=node_1a --let $node_2=node_2a --source include/auto_increment_offset_restore.inc + +--disconnect node_1a +--disconnect node_2a diff --git a/mysql-test/suite/galera/t/galera_fk_cascade_delete.test b/mysql-test/suite/galera/t/galera_fk_cascade_delete.test index 9b79b4c30b6..6f0de0a1f4a 100644 --- a/mysql-test/suite/galera/t/galera_fk_cascade_delete.test +++ b/mysql-test/suite/galera/t/galera_fk_cascade_delete.test @@ -3,7 +3,13 @@ # --source include/galera_cluster.inc ---source include/have_innodb.inc + +--echo # +--echo # test phase with cascading foreign key through 3 tables +--echo # + +--connection node_1 +set wsrep_sync_wait=0; CREATE TABLE grandparent ( id INT NOT NULL PRIMARY KEY @@ -30,11 +36,17 @@ INSERT INTO parent VALUES (1,1), (2,2); INSERT INTO child VALUES (1,1), (2,2); --connection node_2 +set wsrep_sync_wait=0; + +--let $wait_condition = SELECT COUNT(*) = 2 FROM child; +--source include/wait_condition.inc DELETE FROM grandparent WHERE id = 1; --connection node_1 -SELECT COUNT(*) = 0 FROM parent WHERE grandparent_id = 1; -SELECT COUNT(*) = 0 FROM child WHERE parent_id = 1; +--let $wait_condition = SELECT COUNT(*) = 1 FROM child; +--source include/wait_condition.inc +SELECT COUNT(*), COUNT(*) = 0 FROM parent WHERE grandparent_id = 1; +SELECT COUNT(*), COUNT(*) = 0 FROM child WHERE parent_id = 1; DROP TABLE child; DROP TABLE parent; diff --git a/mysql-test/suite/galera/t/galera_fk_cascade_delete_debug.test b/mysql-test/suite/galera/t/galera_fk_cascade_delete_debug.test new file mode 100644 index 00000000000..96e633f83d7 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_fk_cascade_delete_debug.test @@ -0,0 +1,99 @@ +--source include/galera_cluster.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +--echo # +--echo # test phase with foreign key of varchar type +--echo # +--connection node_1 + CREATE TABLE parent ( + `id` varchar(36) COLLATE utf8_unicode_ci NOT NULL, + PRIMARY KEY (`id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + + + CREATE TABLE child ( + `id` int NOT NULL, + `parent_id` varchar(36) COLLATE utf8_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `parent_id` (`parent_id`), + CONSTRAINT `ipallocations_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`) ON DELETE CASCADE + ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + + +INSERT INTO parent VALUES ('row one'), ('row two'); +INSERT INTO child VALUES (1,'row one'), (2,'row two'); + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 2 FROM child; +--source include/wait_condition.inc +DELETE FROM parent; + +--connection node_1 +--let $wait_condition = SELECT COUNT(*) = 0 FROM child; +--source include/wait_condition.inc + +SELECT COUNT(*), COUNT(*) = 0 FROM parent; +SELECT COUNT(*), COUNT(*) = 0 FROM child; + +DROP TABLE child; +DROP TABLE parent; + +--echo # +--echo # test phase with MM conflict in FK cascade +--echo # + +--connection node_1 +set wsrep_retry_autocommit=0; +CREATE TABLE parent ( + id INT NOT NULL PRIMARY KEY +) ENGINE=InnoDB; + +CREATE TABLE child ( + id INT NOT NULL PRIMARY KEY, + j int default 0, + parent_id INT, + FOREIGN KEY (parent_id) + REFERENCES parent(id) + ON DELETE CASCADE +) ENGINE=InnoDB; + +INSERT INTO parent VALUES (1); +INSERT INTO child VALUES (1,0,1); + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM child; +--source include/wait_condition.inc + +# block applier before applying +--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1 +SET GLOBAL debug_dbug = "d,sync.wsrep_apply_cb"; + +--connection node_2 +DELETE FROM parent; + +--connection node_1a +# wait until applier has reached the sync point +SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached"; + +--connection node_1 +# issue conflicting write to child table, it should fail in certification +--error ER_LOCK_DEADLOCK +--send update child set j=2; + +--connection node_1a +# release the applier +SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb"; +SET GLOBAL debug_dbug = ""; +SET DEBUG_SYNC = "RESET"; + +--connection node_1 +--reap + +--let $wait_condition = SELECT COUNT(*) = 0 FROM child; +--source include/wait_condition.inc +SELECT COUNT(*), COUNT(*) = 0 FROM parent; +SELECT COUNT(*), COUNT(*) = 0 FROM child; + +DROP TABLE child; +DROP TABLE parent; diff --git a/mysql-test/suite/galera/t/galera_trigger.test b/mysql-test/suite/galera/t/galera_trigger.test new file mode 100644 index 00000000000..f85a75d0ff1 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_trigger.test @@ -0,0 +1,72 @@ +--source include/galera_cluster.inc +# +# MDEV-21578 CREATE OR REPLACE TRIGGER in Galera cluster not replicating +# +CREATE TABLE IF NOT EXISTS t1 (id int(10) not null primary key) engine=innodb; +--delimiter | +CREATE OR REPLACE TRIGGER tr1 +BEFORE INSERT ON t1 FOR EACH ROW +BEGIN +SET NEW.id = 100; +END| +--delimiter ; + +INSERT INTO t1 VALUES (1); +SELECT * from t1; + +--delimiter | +CREATE OR REPLACE TRIGGER tr1 +BEFORE INSERT ON t1 FOR EACH ROW +BEGIN +SET NEW.id = 200; +END| +--delimiter ; + +--connection node_2 +SET SESSION wsrep_sync_wait=15; +SELECT * FROM t1; +INSERT INTO t1 values (2); +SELECT * FROM t1; + +--connection node_1 +SELECT * FROM t1; + +DROP TRIGGER tr1; +DROP TABLE t1; +# +# MDEV-23638 : DROP TRIGGER in Galera Cluster not replicating +# +--connection node_1 +CREATE TABLE t1(id int not null auto_increment, value int not null, primary key (id)) engine=innodb; + +CREATE TABLE t2(id int not null auto_increment, tbl varchar(64) not null, action varchar(64) not null, primary key (id)); + +--delimiter | +create trigger log_insert after insert on t1 +for each row begin + insert into t2(tbl, action) values ('t1', 'INSERT'); +end| +--delimiter ; + +insert into t1(value) values (1); +insert into t1(value) values (2); + +--connection node_2 +set session wsrep_sync_wait=15; +insert into t1(value) values (3); +insert into t1(value) values (4); +select * from t2; + +--connection node_1 +drop trigger if exists log_insert; +insert into t1(value) values (5); +select * from t2; + +--connection node_2 +insert into t1(value) values (6); +select * from t2; + +--connection node_1 +select * from t2; + +drop table t1, t2; diff --git a/mysql-test/suite/galera/t/galera_wan_restart_ist.test b/mysql-test/suite/galera/t/galera_wan_restart_ist.test index 1cf5d4c7f74..8a011d60851 100644 --- a/mysql-test/suite/galera/t/galera_wan_restart_ist.test +++ b/mysql-test/suite/galera/t/galera_wan_restart_ist.test @@ -10,7 +10,7 @@ --source include/big_test.inc --source include/galera_cluster.inc ---source include/have_innodb.inc +--source include/force_restart.inc --connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3 --connect node_4, 127.0.0.1, root, , test, $NODE_MYPORT_4 @@ -22,10 +22,13 @@ --let $node_4=node_4 --source include/auto_increment_offset_save.inc -SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' +--source include/wait_condition.inc + +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; --connection node_1 -CREATE TABLE t1 (f1 INTEGER); +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=INNODB; INSERT INTO t1 VALUES (1); --connection node_2 @@ -46,9 +49,13 @@ INSERT INTO t1 VALUES (13); --echo Shutting down server ... --source include/shutdown_mysqld.inc ---sleep 5 + --connection node_1 +--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' +--source include/wait_condition.inc +SELECT VARIABLE_VALUE AS EXPECT_3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; + INSERT INTO t1 VALUES (11); --connection node_2 @@ -59,9 +66,12 @@ INSERT INTO t1 VALUES (14); --connection node_3 --source include/start_mysqld.inc ---sleep 5 --source include/wait_until_connected_again.inc +--let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' +--source include/wait_condition.inc +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; + INSERT INTO t1 VALUES (131); # @@ -73,9 +83,12 @@ INSERT INTO t1 VALUES (22); --echo Shutting down server ... --source include/shutdown_mysqld.inc ---sleep 5 --connection node_1 +--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' +--source include/wait_condition.inc +SELECT VARIABLE_VALUE AS EXPECT_3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; + INSERT INTO t1 VALUES (21); --connection node_3 @@ -86,9 +99,12 @@ INSERT INTO t1 VALUES (24); --connection node_2 --source include/start_mysqld.inc ---sleep 5 --source include/wait_until_connected_again.inc +--let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' +--source include/wait_condition.inc +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; + INSERT INTO t1 VALUES (221); # @@ -100,9 +116,12 @@ INSERT INTO t1 VALUES (34); --echo Shutting down server ... --source include/shutdown_mysqld.inc ---sleep 5 --connection node_1 +--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' +--source include/wait_condition.inc +SELECT VARIABLE_VALUE AS EXPECT_3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; + INSERT INTO t1 VALUES (31); --connection node_2 @@ -113,9 +132,12 @@ INSERT INTO t1 VALUES (33); --connection node_4 --source include/start_mysqld.inc ---sleep 5 --source include/wait_until_connected_again.inc +--let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' +--source include/wait_condition.inc +SELECT VARIABLE_VALUE AS EXPECT_4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; + INSERT INTO t1 VALUES (341); @@ -124,22 +146,44 @@ INSERT INTO t1 VALUES (341); # --connection node_1 ---let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' +--source include/wait_condition.inc +--let $wait_condition = SELECT COUNT(*) = 19 FROM t1 --source include/wait_condition.inc -SELECT COUNT(*) = 19 FROM t1; +SELECT COUNT(*) AS EXPECT_19 FROM t1; --connection node_2 +--let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' +--source include/wait_condition.inc SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -SELECT COUNT(*) = 19 FROM t1; + +--let $wait_condition = SELECT COUNT(*) = 19 FROM t1 +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_19 FROM t1; + --connection node_3 +--let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' +--source include/wait_condition.inc SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -SELECT COUNT(*) = 19 FROM t1; + +--let $wait_condition = SELECT COUNT(*) = 19 FROM t1 +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_19 FROM t1; --connection node_4 +--let $wait_condition = SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--source include/wait_condition.inc SELECT VARIABLE_VALUE = 4 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -SELECT COUNT(*) = 19 FROM t1; + +--let $wait_condition = SELECT COUNT(*) = 19 FROM t1 +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_19 FROM t1; + --connection node_1 DROP TABLE t1; @@ -158,4 +202,6 @@ CALL mtr.add_suppression("Action message in non-primary configuration from membe # Restore original auto_increment_offset values. --source include/auto_increment_offset_restore.inc ---source include/galera_end.inc +--connection node_1 +--disconnect node_3 +--disconnect node_4 diff --git a/mysql-test/suite/galera/t/mdev-22543.test b/mysql-test/suite/galera/t/mdev-22543.test index 53662e36942..1e7d3712639 100644 --- a/mysql-test/suite/galera/t/mdev-22543.test +++ b/mysql-test/suite/galera/t/mdev-22543.test @@ -5,15 +5,15 @@ --source include/galera_cluster.inc --source include/have_debug.inc --source include/have_debug_sync.inc - + --let $node_1 = node_1 --let $node_2 = node_2 --source include/auto_increment_offset_save.inc - + --let $galera_connection_name = node_1_ctrl --let $galera_server_number = 1 --source include/galera_connect.inc - + # # Run UPDATE on node_1 and make it block before table locks are taken. # This should block FTWRL. @@ -23,10 +23,10 @@ CREATE TABLE t1 (f1 INT PRIMARY KEY, f2 INT); INSERT INTO t1 VALUES (1, 1); SET DEBUG_SYNC = "before_lock_tables_takes_lock SIGNAL sync_point_reached WAIT_FOR sync_point_continue"; --send UPDATE t1 SET f2 = 2 WHERE f1 = 1 - + --connection node_1_ctrl SET DEBUG_SYNC = "now WAIT_FOR sync_point_reached"; - + # # Restart node_2, force SST. # @@ -40,19 +40,19 @@ SET DEBUG_SYNC = "now WAIT_FOR sync_point_reached"; # If the bug is present, FTWRL times out on node_1 in couple of # seconds and node_2 fails to join. --sleep 10 - + --connection node_1_ctrl SET DEBUG_SYNC = "now SIGNAL sync_point_continue"; - + --connection node_1 --reap SET DEBUG_SYNC = "RESET"; - + --connection node_2 --enable_reconnect --source include/wait_until_connected_again.inc - + --connection node_1 DROP TABLE t1; - + --source include/auto_increment_offset_restore.inc diff --git a/mysql-test/suite/galera_3nodes/disabled.def b/mysql-test/suite/galera_3nodes/disabled.def index 1683485981b..0e2706f2dc3 100644 --- a/mysql-test/suite/galera_3nodes/disabled.def +++ b/mysql-test/suite/galera_3nodes/disabled.def @@ -1,2 +1,16 @@ +############################################################################## +# +# List the test cases that are to be disabled temporarily. +# +# Separate the test case name and the comment with ':'. +# +# <testcasename> : MDEV-<xxxx> <comment> +# +# Do not use any TAB characters for whitespace. +# +############################################################################## + +galera_gtid_2_cluster : MDEV-23775 Galera test failure on galera_3nodes.galera_gtid_2_cluster +galera_ist_gcache_rollover : MDEV-23578 WSREP: exception caused by message: {v=0,t=1,ut=255,o=4,s=0,sr=0,as=1,f=6,src=50524cfe,srcvid=view_id(REG,50524cfe,4),insvid=view_id(UNKNOWN,00000000,0),ru=00000000,r=[-1,-1],fs=75,nl=(} galera_slave_options_do :MDEV-8798 galera_slave_options_ignore : MDEV-8798 diff --git a/mysql-test/suite/galera_3nodes/r/GAL-501.result b/mysql-test/suite/galera_3nodes/r/GAL-501.result index 063e88ec21a..850fb6f3f78 100644 --- a/mysql-test/suite/galera_3nodes/r/GAL-501.result +++ b/mysql-test/suite/galera_3nodes/r/GAL-501.result @@ -10,11 +10,11 @@ VARIABLE_VALUE = 3 connection node_2; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; connection node_1; -CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); connection node_2; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; -SELECT COUNT(*) = 1 FROM t1; -COUNT(*) = 1 +SELECT COUNT(*) AS EXPECT_1 FROM t1; +EXPECT_1 1 DROP TABLE t1; diff --git a/mysql-test/suite/galera_3nodes/r/GCF-354.result b/mysql-test/suite/galera_3nodes/r/GCF-354.result index dad57fe15ec..1fa4265edcf 100644 --- a/mysql-test/suite/galera_3nodes/r/GCF-354.result +++ b/mysql-test/suite/galera_3nodes/r/GCF-354.result @@ -1,17 +1,18 @@ connection node_2; connection node_1; -connection node_2; -SET wsrep_on=OFF; -DROP SCHEMA test; connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3; connection node_3; connection node_1; connection node_2; connection node_3; +connection node_2; SET wsrep_on=OFF; -CREATE TABLE test.t1 (f1 INTEGER); +DROP SCHEMA test; +connection node_3; +SET SESSION wsrep_on=OFF; +CREATE TABLE test.t1 (f1 INTEGER) engine=innodb; connection node_1; -CREATE TABLE test.t1 (f1 INTEGER); +CREATE TABLE test.t1 (f1 INTEGER) engine=innodb; SHOW STATUS LIKE 'wsrep_cluster_status'; Variable_name Value wsrep_cluster_status Primary diff --git a/mysql-test/suite/galera_3nodes/r/galera_innobackupex_backup.result b/mysql-test/suite/galera_3nodes/r/galera_innobackupex_backup.result deleted file mode 100644 index e3935c32fda..00000000000 --- a/mysql-test/suite/galera_3nodes/r/galera_innobackupex_backup.result +++ /dev/null @@ -1,20 +0,0 @@ -connection node_2; -connection node_1; -connection node_1; -connection node_2; -connection node_3; -connection node_1; -CREATE TABLE t1 (f1 INTEGER); -INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); -connection node_2; -SELECT COUNT(*) = 10 FROM t1; -COUNT(*) = 10 -1 -Killing server ... -connection node_1; -INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19),(20); -# restart -SELECT COUNT(*) = 20 FROM t1; -COUNT(*) = 20 -1 -DROP TABLE t1; diff --git a/mysql-test/suite/galera_3nodes/r/galera_ipv6_mariabackup.result b/mysql-test/suite/galera_3nodes/r/galera_ipv6_mariabackup.result index 8ec1ff090ff..9a96addbf57 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_ipv6_mariabackup.result +++ b/mysql-test/suite/galera_3nodes/r/galera_ipv6_mariabackup.result @@ -9,16 +9,16 @@ VARIABLE_VALUE = 3 connection node_2; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; connection node_1; -CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); connection node_2; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; -SELECT COUNT(*) = 1 FROM t1; -COUNT(*) = 1 +SELECT COUNT(*) AS EXPECT_1 FROM t1; +EXPECT_1 1 DROP TABLE t1; connection node_1; include/assert_grep.inc [Streaming the backup to joiner at \[::1\]] include/assert_grep.inc [async IST sender starting to serve tcp://\[::1\]:] include/assert_grep.inc [IST receiver addr using tcp://\[::1\]] -include/assert_grep.inc [Prepared IST receiver for 3-6, listening at: tcp://\[::1\]] +include/assert_grep.inc [, listening at: tcp://\[::1\]] diff --git a/mysql-test/suite/galera_3nodes/r/galera_ipv6_mariabackup_section.result b/mysql-test/suite/galera_3nodes/r/galera_ipv6_mariabackup_section.result index dc72260d979..182fb1af51e 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_ipv6_mariabackup_section.result +++ b/mysql-test/suite/galera_3nodes/r/galera_ipv6_mariabackup_section.result @@ -9,12 +9,12 @@ VARIABLE_VALUE = 3 connection node_2; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; connection node_1; -CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); connection node_2; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; -SELECT COUNT(*) = 1 FROM t1; -COUNT(*) = 1 +SELECT COUNT(*) AS EXPECT_1 FROM t1; +EXPECT_1 1 DROP TABLE t1; connection node_1; @@ -22,4 +22,4 @@ include/assert_grep.inc [Streaming the backup to joiner at \[::1\]] include/assert_grep.inc [async IST sender starting to serve tcp://\[::1\]:] connection node_2; include/assert_grep.inc [IST receiver addr using tcp://\[::1\]] -include/assert_grep.inc [Prepared IST receiver for 3-6, listening at: tcp://\[::1\]] +include/assert_grep.inc [, listening at: tcp://\[::1\]] diff --git a/mysql-test/suite/galera_3nodes/r/galera_ipv6_mysqldump.result b/mysql-test/suite/galera_3nodes/r/galera_ipv6_mysqldump.result index bfc210db2ba..934218492d6 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_ipv6_mysqldump.result +++ b/mysql-test/suite/galera_3nodes/r/galera_ipv6_mysqldump.result @@ -14,12 +14,12 @@ SET GLOBAL wsrep_sst_method = 'mysqldump'; Shutting down server ... connection node_1; Cleaning var directory ... -CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); connection node_2; Starting server ... -SELECT COUNT(*) = 1 FROM t1; -COUNT(*) = 1 +SELECT COUNT(*) AS EXPECT_1 FROM t1; +EXPECT_1 1 DROP TABLE t1; SELECT VARIABLE_VALUE LIKE '%[::1]%' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_incoming_addresses'; diff --git a/mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync.result b/mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync.result index 3f810d3eb97..27cbd7dbe55 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync.result +++ b/mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync.result @@ -9,11 +9,11 @@ VARIABLE_VALUE = 3 connection node_2; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; connection node_1; -CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); connection node_2; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; -SELECT COUNT(*) = 1 FROM t1; -COUNT(*) = 1 +SELECT COUNT(*) AS EXPECT_1 FROM t1; +EXPECT_1 1 DROP TABLE t1; diff --git a/mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync_section.result b/mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync_section.result index 3f810d3eb97..27cbd7dbe55 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync_section.result +++ b/mysql-test/suite/galera_3nodes/r/galera_ipv6_rsync_section.result @@ -9,11 +9,11 @@ VARIABLE_VALUE = 3 connection node_2; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; connection node_1; -CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); connection node_2; SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; -SELECT COUNT(*) = 1 FROM t1; -COUNT(*) = 1 +SELECT COUNT(*) AS EXPECT_1 FROM t1; +EXPECT_1 1 DROP TABLE t1; diff --git a/mysql-test/suite/galera_3nodes/r/galera_safe_to_bootstrap.result b/mysql-test/suite/galera_3nodes/r/galera_safe_to_bootstrap.result index be6e1a88cdf..2138f48adda 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_safe_to_bootstrap.result +++ b/mysql-test/suite/galera_3nodes/r/galera_safe_to_bootstrap.result @@ -4,7 +4,8 @@ connection node_1; connection node_2; connection node_3; connection node_1; -CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0'] include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0'] include/assert_grep.inc [grastate.dat does not have 'safe_to_bootstrap: 0'] @@ -62,6 +63,7 @@ CALL mtr.add_suppression("WSREP: gcs/src/gcs_core.cpp:core_handle_uuid_msg()"); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `f1` int(11) DEFAULT NULL + `f1` int(11) NOT NULL, + PRIMARY KEY (`f1`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 DROP TABLE t1; diff --git a/mysql-test/suite/galera_3nodes/r/galera_var_dirty_reads2.result b/mysql-test/suite/galera_3nodes/r/galera_var_dirty_reads2.result index cb327107e2a..776c54aebe1 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_var_dirty_reads2.result +++ b/mysql-test/suite/galera_3nodes/r/galera_var_dirty_reads2.result @@ -4,7 +4,7 @@ connection node_1; connection node_2; connection node_3; connection node_1; -CREATE TABLE t1 (f1 INTEGER); +CREATE TABLE t1 (f1 INTEGER) ENGINE=INNODB; INSERT INTO t1 VALUES (1); connection node_2; SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; diff --git a/mysql-test/suite/galera_3nodes/suite.pm b/mysql-test/suite/galera_3nodes/suite.pm index da02d4a9020..f93cd0e0909 100644 --- a/mysql-test/suite/galera_3nodes/suite.pm +++ b/mysql-test/suite/galera_3nodes/suite.pm @@ -17,7 +17,6 @@ push @::global_suppressions, qr(WSREP:.*down context.*), qr(WSREP: Failed to send state UUID:), qr(WSREP: last inactive check more than .* skipping check), - qr(WSREP: SQL statement was ineffective), qr(WSREP: Releasing seqno [0-9]* before [0-9]* was assigned.), qr|WSREP: access file\(.*gvwstate.dat\) failed\(No such file or directory\)|, qr(WSREP: Quorum: No node with complete state), @@ -31,14 +30,34 @@ push @::global_suppressions, qr(WSREP: user message in state LEAVING), qr(WSREP: .* sending install message failed: Transport endpoint is not connected), qr(WSREP: .* sending install message failed: Resource temporarily unavailable), - qr(WSREP: Sending JOIN failed: -107 \(Transport endpoint is not connected\). Will retry in new primary component.), + qr(WSREP: Maximum writeset size exceeded by .*), + qr(WSREP: transaction size exceeded.*), + qr(WSREP: RBR event .*), + qr(WSREP: Ignoring error for TO isolated action: .*), + qr(WSREP: transaction size limit .*), + qr(WSREP: rbr write fail, .*), + qr(WSREP: .*Backend not supported: foo.*), + qr(WSREP: .*Failed to initialize backend using .*), + qr(WSREP: .*Failed to open channel 'my_wsrep_cluster' at .*), + qr(WSREP: gcs connect failed: Socket type not supported), + qr(WSREP: failed to open gcomm backend connection: 110: failed to reach primary view: 110 .*), + qr(WSREP: .*Failed to open backend connection: -110 .*), + qr(WSREP: .*Failed to open channel 'my_wsrep_cluster' at .*), + qr(WSREP: gcs connect failed: Connection timed out), + qr|WSREP: wsrep::connect\(.*\) failed: 7|, + qr(WSREP: SYNC message from member .* in non-primary configuration. Ignored.), qr(WSREP: Could not find peer:), + qr(WSREP: TO isolation failed for: .*), qr|WSREP: gcs_caused\(\) returned .*|, qr|WSREP: Protocol violation. JOIN message sender .* is not in state transfer \(SYNCED\). Message ignored.|, qr|WSREP: Protocol violation. JOIN message sender .* is not in state transfer \(JOINED\). Message ignored.|, + qr|WSREP: Unsupported protocol downgrade: incremental data collection disabled. Expect abort.|, qr(WSREP: Action message in non-primary configuration from member [0-9]*), + qr(WSREP: Last Applied Action message in non-primary configuration from member [0-9]*), + qr(WSREP: discarding established .*), + qr|WSREP: .*core_handle_uuid_msg.*|, qr(WSREP: --wsrep-causal-reads=ON takes precedence over --wsrep-sync-wait=0. WSREP_SYNC_WAIT_BEFORE_READ is on), - qr(WSREP: JOIN message from member .* in non-primary configuration. Ignored.), + qr|WSREP: JOIN message from member .* in non-primary configuration. Ignored.|, qr|Query apply failed:*|, qr(WSREP: Ignoring error*), qr(WSREP: Failed to remove page file .*), diff --git a/mysql-test/suite/galera_3nodes/t/GAL-501.cnf b/mysql-test/suite/galera_3nodes/t/GAL-501.cnf index 7002cb5bdfd..3b18a86093c 100644 --- a/mysql-test/suite/galera_3nodes/t/GAL-501.cnf +++ b/mysql-test/suite/galera_3nodes/t/GAL-501.cnf @@ -10,6 +10,7 @@ wsrep_node_address=[::1] wsrep_provider_options='base_port=@mysqld.1.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.1.#galera_port;ist.recv_addr=[::1]' wsrep_sst_receive_address='[::1]:@mysqld.1.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.1.port' +bind-address=:: [mysqld.2] wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port' @@ -17,6 +18,7 @@ wsrep_node_address=[::1] wsrep_provider_options='base_port=@mysqld.2.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.2.#galera_port;ist.recv_addr=[::1]' wsrep_sst_receive_address='[::1]:@mysqld.2.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.2.port' +bind-address=:: [mysqld.3] wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port' @@ -24,3 +26,4 @@ wsrep_node_address=[::1] wsrep_provider_options='base_port=@mysqld.3.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.3.#galera_port;ist.recv_addr=[::1]' wsrep_sst_receive_address='[::1]:@mysqld.3.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.3.port' +bind-address=:: diff --git a/mysql-test/suite/galera_3nodes/t/GAL-501.opt b/mysql-test/suite/galera_3nodes/t/GAL-501.opt deleted file mode 100644 index c2bb4d156af..00000000000 --- a/mysql-test/suite/galera_3nodes/t/GAL-501.opt +++ /dev/null @@ -1 +0,0 @@ ---bind-address=:: diff --git a/mysql-test/suite/galera_3nodes/t/GAL-501.test b/mysql-test/suite/galera_3nodes/t/GAL-501.test index c4b17cdb21e..af5b83ae261 100644 --- a/mysql-test/suite/galera_3nodes/t/GAL-501.test +++ b/mysql-test/suite/galera_3nodes/t/GAL-501.test @@ -6,6 +6,7 @@ --source include/galera_cluster.inc --source include/check_ipv6.inc +--source include/force_restart.inc --let $galera_connection_name = node_3 --let $galera_server_number = 3 @@ -27,7 +28,7 @@ SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; --let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; --source include/wait_condition.inc -CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); --connection node_2 @@ -39,6 +40,6 @@ SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; --let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready'; --source include/wait_condition.inc -SELECT COUNT(*) = 1 FROM t1; +SELECT COUNT(*) AS EXPECT_1 FROM t1; DROP TABLE t1; diff --git a/mysql-test/suite/galera_3nodes/t/GCF-354.test b/mysql-test/suite/galera_3nodes/t/GCF-354.test index c428aee7732..d4e2bc095fa 100644 --- a/mysql-test/suite/galera_3nodes/t/GCF-354.test +++ b/mysql-test/suite/galera_3nodes/t/GCF-354.test @@ -1,11 +1,5 @@ --source include/galera_cluster.inc ---source include/have_innodb.inc -# -# 1. Create different inconsistencies on nodes 2 and 3 -# ---connection node_2 -SET wsrep_on=OFF; -DROP SCHEMA test; +--source include/force_restart.inc --connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3 --connection node_3 @@ -16,15 +10,23 @@ DROP SCHEMA test; --let $node_3=node_3 --source ../galera/include/auto_increment_offset_save.inc +# +# 1. Create different inconsistencies on nodes 2 and 3 +# +--connection node_2 SET wsrep_on=OFF; -CREATE TABLE test.t1 (f1 INTEGER); +DROP SCHEMA test; + +--connection node_3 +SET SESSION wsrep_on=OFF; +CREATE TABLE test.t1 (f1 INTEGER) engine=innodb; # # 2. The following should generate different errors on nodes 2 and 3 and # trigger voting with 3 different votes. node_1 should remain alone # in the cluster. # --connection node_1 -CREATE TABLE test.t1 (f1 INTEGER); +CREATE TABLE test.t1 (f1 INTEGER) engine=innodb; --let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' --source include/wait_condition.inc diff --git a/mysql-test/suite/galera_3nodes/t/GCF-376.test b/mysql-test/suite/galera_3nodes/t/GCF-376.test index 8543ebbc56a..ff5bfbfb209 100644 --- a/mysql-test/suite/galera_3nodes/t/GCF-376.test +++ b/mysql-test/suite/galera_3nodes/t/GCF-376.test @@ -17,6 +17,9 @@ CREATE TABLE test.t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1)) ENGINE=InnoDB; --connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1'; +--source include/wait_condition.inc + SET GLOBAL wsrep_on=OFF; INSERT INTO t1 VALUES (1, 'a'); SET GLOBAL wsrep_on=ON; diff --git a/mysql-test/suite/galera_3nodes/t/galera_innobackupex_backup.cnf b/mysql-test/suite/galera_3nodes/t/galera_innobackupex_backup.cnf deleted file mode 100644 index 35ecb8b5937..00000000000 --- a/mysql-test/suite/galera_3nodes/t/galera_innobackupex_backup.cnf +++ /dev/null @@ -1,4 +0,0 @@ -!include ../galera_3nodes.cnf - -[mysqld] -wsrep-causal-reads=OFF diff --git a/mysql-test/suite/galera_3nodes/t/galera_innobackupex_backup.test b/mysql-test/suite/galera_3nodes/t/galera_innobackupex_backup.test deleted file mode 100644 index cd5c020ae38..00000000000 --- a/mysql-test/suite/galera_3nodes/t/galera_innobackupex_backup.test +++ /dev/null @@ -1,80 +0,0 @@ -# -# This test uses innobackupex to take a backup on node #2 and then restores that node from backup -# - ---source include/galera_cluster.inc ---source include/have_innodb.inc ---source suite/galera/include/have_mariabackup.inc - ---let $galera_connection_name = node_3 ---let $galera_server_number = 3 ---source include/galera_connect.inc - -# Save original auto_increment_offset values. ---let $node_1=node_1 ---let $node_2=node_2 ---let $node_3=node_3 ---source ../galera/include/auto_increment_offset_save.inc - ---connection node_1 -CREATE TABLE t1 (f1 INTEGER); -INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); - ---connection node_2 -SELECT COUNT(*) = 10 FROM t1; - ---exec rm -rf $MYSQL_TMP_DIR/innobackupex_backup ---exec mariabackup --innobackupex --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group=mysqld.2 --galera-info --port=$NODE_MYPORT_2 --host=127.0.0.1 --no-timestamp $MYSQL_TMP_DIR/innobackupex_backup &> $MYSQL_TMP_DIR/innobackupex-backup.log ---exec mariabackup --innobackupex --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group=mysqld.2 --apply-log --galera-info --port=$NODE_MYPORT_2 --host=127.0.0.1 --no-timestamp $MYSQL_TMP_DIR/innobackupex_backup &> $MYSQL_TMP_DIR/innobackupex-apply.log - ---source ../galera/include/kill_galera.inc ---sleep 1 - ---connection node_1 -INSERT INTO t1 VALUES (11),(12),(13),(14),(15),(16),(17),(18),(19),(20); - ---exec rm -rf $MYSQLTEST_VARDIR/mysqld.2/data/* ---exec mariabackup --innobackupex --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group=mysqld.2 --copy-back --port=$NODE_MYPORT_2 --host=127.0.0.1 $MYSQL_TMP_DIR/innobackupex_backup &> $MYSQL_TMP_DIR/innobackupex-restore.log - -# -# Convert the xtrabackup_galera_info into a grastate.dat file -# - ---perl - use strict; - my $xtrabackup_galera_info_file = $ENV{'MYSQL_TMP_DIR'}.'/innobackupex_backup/xtrabackup_galera_info'; - open(XTRABACKUP_GALERA_INFO, $xtrabackup_galera_info_file) or die "Can not open $xtrabackup_galera_info_file: $!"; - my $xtrabackup_galera_info = <XTRABACKUP_GALERA_INFO>; - my ($uuid, $seqno) = split(':', $xtrabackup_galera_info); - - my $grastate_dat_file = $ENV{'MYSQLTEST_VARDIR'}.'/mysqld.2/data/grastate.dat'; - die "grastate.dat already exists" if -e $grastate_dat_file; - - open(GRASTATE_DAT, ">$grastate_dat_file") or die "Can not write to $grastate_dat_file: $!"; - print GRASTATE_DAT "version: 2.1\n"; - print GRASTATE_DAT "uuid: $uuid\n"; - print GRASTATE_DAT "seqno: $seqno\n"; - print GRASTATE_DAT "cert_index:\n"; - exit(0); -EOF - ---source include/start_mysqld.inc ---sleep 5 - ---source include/wait_until_connected_again.inc ---let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; ---source include/wait_condition.inc - -SELECT COUNT(*) = 20 FROM t1; - -DROP TABLE t1; - ---sleep 10 - ---let $galera_connection_name = node_2a ---let $galera_server_number = 2 ---source include/galera_connect.inc ---let $node_2=node_2a - -# Restore original auto_increment_offset values. ---source ../galera/include/auto_increment_offset_restore.inc diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.cnf b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.cnf index 969f364a1ec..8432b1c368c 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.cnf +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.cnf @@ -11,6 +11,7 @@ wsrep_provider_options='base_host=[::1];base_port=@mysqld.1.#galera_port;gmcast. wsrep_sst_receive_address='[::1]:@mysqld.1.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.1.port' wsrep_node_name=node_1 +bind-address=:: [mysqld.2] wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port' @@ -19,6 +20,7 @@ wsrep_sst_receive_address='[::1]:@mysqld.2.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.2.port' wsrep_node_name=node_2 wsrep_sst_donor=node_1 +bind-address=:: [mysqld.3] wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port' @@ -27,6 +29,7 @@ wsrep_sst_receive_address='[::1]:@mysqld.3.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.3.port' wsrep_node_name=node_3 wsrep_sst_donor=node_1 +bind-address=:: [SST] transferfmt=@ENV.MTR_GALERA_TFMT diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.opt b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.opt deleted file mode 100644 index c2bb4d156af..00000000000 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.opt +++ /dev/null @@ -1 +0,0 @@ ---bind-address=:: diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.test b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.test index d6b97f939f2..31613454348 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.test +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup.test @@ -1,7 +1,8 @@ --source include/galera_cluster.inc --source include/check_ipv6.inc --source include/have_innodb.inc ---source ../galera/include/have_mariabackup.inc +--source include/have_mariabackup.inc +--source include/force_restart.inc # Confirm that initial handshake happened over ipv6 @@ -17,7 +18,7 @@ SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; --let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; --source include/wait_condition.inc -CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); --connection node_2 @@ -29,7 +30,7 @@ SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; --let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready'; --source include/wait_condition.inc -SELECT COUNT(*) = 1 FROM t1; +SELECT COUNT(*) AS EXPECT_1 FROM t1; DROP TABLE t1; @@ -62,8 +63,8 @@ DROP TABLE t1; --let $assert_select = IST receiver addr using tcp://\[::1\] --source include/assert_grep.inc -# The receiver expects seqnos 3-6 only once. ---let $assert_count = 1 ---let $assert_text = Prepared IST receiver for 3-6, listening at: tcp://\[::1\] ---let $assert_select = Prepared IST receiver for 3-6, listening at: tcp://\[::1\] +# The receiver expects IST +--let $assert_count = 2 +--let $assert_text = , listening at: tcp://\[::1\] +--let $assert_select = , listening at: tcp://\[::1\] --source include/assert_grep.inc diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup_section.cnf b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup_section.cnf index dc294854056..aa3da690416 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup_section.cnf +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup_section.cnf @@ -3,35 +3,37 @@ # decoy value - should not be read by mysqld or sst scripts [mysqld] innodb-data-home-dir=/tmp - -[galera] +bind-address=:: innodb-data-home-dir= wsrep_sst_method=mariabackup wsrep_sst_auth="root:" wsrep_node_address=::1 -[galera.1] +[mysqld.1] wsrep-cluster-address=gcomm:// wsrep_provider_options='base_host=[::1];base_port=@mysqld.1.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.1.#galera_port;ist.recv_addr=[::1]:@mysqld.1.#ist_port' wsrep_sst_receive_address='[::1]:@mysqld.1.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.1.port' wsrep_node_name=node_1 +bind-address=:: -[galera.2] +[mysqld.2] wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port' wsrep_provider_options='base_host=[::1];base_port=@mysqld.2.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.2.#galera_port;ist.recv_addr=[::1]:@mysqld.2.#ist_port' wsrep_sst_receive_address='[::1]:@mysqld.2.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.2.port' wsrep_node_name=node_2 wsrep_sst_donor=node_1 +bind-address=:: -[galera.3] +[mysqld.3] wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port' wsrep_provider_options='base_host=[::1];base_port=@mysqld.3.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.3.#galera_port;ist.recv_addr=[::1]:@mysqld.3.#ist_port' wsrep_sst_receive_address='[::1]:@mysqld.3.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.3.port' wsrep_node_name=node_3 wsrep_sst_donor=node_1 +bind-address=:: [SST] transferfmt=@ENV.MTR_GALERA_TFMT diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup_section.opt b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup_section.opt deleted file mode 100644 index c2bb4d156af..00000000000 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup_section.opt +++ /dev/null @@ -1 +0,0 @@ ---bind-address=:: diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup_section.test b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup_section.test index e9425bcffdf..3b2ca0892f1 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup_section.test +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mariabackup_section.test @@ -1,7 +1,8 @@ --source include/galera_cluster.inc --source include/check_ipv6.inc --source include/have_innodb.inc ---source ../galera/include/have_mariabackup.inc +--source include/have_mariabackup.inc +--source include/force_restart.inc # Confirm that initial handshake happened over ipv6 @@ -17,7 +18,7 @@ SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; --let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; --source include/wait_condition.inc -CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); --connection node_2 @@ -29,7 +30,7 @@ SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; --let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready'; --source include/wait_condition.inc -SELECT COUNT(*) = 1 FROM t1; +SELECT COUNT(*) AS EXPECT_1 FROM t1; DROP TABLE t1; @@ -64,8 +65,8 @@ DROP TABLE t1; --let $assert_select = IST receiver addr using tcp://\[::1\] --source include/assert_grep.inc -# The receiver expects seqnos 3-6 only once. ---let $assert_count = 1 ---let $assert_text = Prepared IST receiver for 3-6, listening at: tcp://\[::1\] ---let $assert_select = Prepared IST receiver for 3-6, listening at: tcp://\[::1\] +# The receiver expects IST +--let $assert_count = 2 +--let $assert_text = , listening at: tcp://\[::1\] +--let $assert_select = , listening at: tcp://\[::1\] --source include/assert_grep.inc diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.cnf b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.cnf index 80dd0c41cc3..5e77a45210b 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.cnf +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.cnf @@ -9,18 +9,21 @@ wsrep-cluster-address=gcomm:// wsrep_provider_options='base_host=[::1];base_port=@mysqld.1.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.1.#galera_port;ist.recv_addr=[::1]:@mysqld.1.#ist_port' wsrep_sst_receive_address='[::1]:@mysqld.1.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.1.port' +bind-address=:: [mysqld.2] wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port' wsrep_provider_options='base_host=[::1];base_port=@mysqld.2.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.2.#galera_port;ist.recv_addr=[::1]:@mysqld.2.#ist_port' wsrep_sst_receive_address='[::1]:@mysqld.2.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.2.port' +bind-address=:: [mysqld.3] wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port' wsrep_provider_options='base_host=[::1];base_port=@mysqld.3.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.3.#galera_port;ist.recv_addr=[::1]:@mysqld.3.#ist_port' wsrep_sst_receive_address='[::1]:@mysqld.3.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.3.port' +bind-address=:: [SST] sockopt=",pf=ip6" diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.opt b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.opt deleted file mode 100644 index c2bb4d156af..00000000000 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.opt +++ /dev/null @@ -1 +0,0 @@ ---bind-address=:: diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.test b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.test index c9c32f23230..f5dd1aeb06d 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.test +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_mysqldump.test @@ -1,5 +1,6 @@ --source include/galera_cluster.inc --source include/check_ipv6.inc +--source include/force_restart.inc call mtr.add_suppression("WSREP: wsrep_sst_method is set to 'mysqldump' yet mysqld bind_address is set to'"); call mtr.add_suppression("Failed to load slave replication state from table mysql.gtid_slave_pos"); @@ -53,7 +54,7 @@ SET GLOBAL wsrep_sst_method = 'mysqldump'; --remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data/mysql --remove_files_wildcard $MYSQLTEST_VARDIR/mysqld.2/data -CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); --connection node_2 @@ -70,7 +71,7 @@ let $restart_noprint=2; --let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready'; --source include/wait_condition.inc -SELECT COUNT(*) = 1 FROM t1; +SELECT COUNT(*) AS EXPECT_1 FROM t1; DROP TABLE t1; diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.cnf b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.cnf index 80dd0c41cc3..5e77a45210b 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.cnf +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.cnf @@ -9,18 +9,21 @@ wsrep-cluster-address=gcomm:// wsrep_provider_options='base_host=[::1];base_port=@mysqld.1.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.1.#galera_port;ist.recv_addr=[::1]:@mysqld.1.#ist_port' wsrep_sst_receive_address='[::1]:@mysqld.1.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.1.port' +bind-address=:: [mysqld.2] wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port' wsrep_provider_options='base_host=[::1];base_port=@mysqld.2.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.2.#galera_port;ist.recv_addr=[::1]:@mysqld.2.#ist_port' wsrep_sst_receive_address='[::1]:@mysqld.2.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.2.port' +bind-address=:: [mysqld.3] wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port' wsrep_provider_options='base_host=[::1];base_port=@mysqld.3.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.3.#galera_port;ist.recv_addr=[::1]:@mysqld.3.#ist_port' wsrep_sst_receive_address='[::1]:@mysqld.3.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.3.port' +bind-address=:: [SST] sockopt=",pf=ip6" diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.opt b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.opt deleted file mode 100644 index c2bb4d156af..00000000000 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.opt +++ /dev/null @@ -1 +0,0 @@ ---bind-address=:: diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.test b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.test index 1937eb43e13..448611e34e0 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.test +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync.test @@ -1,5 +1,6 @@ --source include/galera_cluster.inc --source include/check_ipv6.inc +--source include/force_restart.inc # Confirm that initial handshake happened over ipv6 @@ -15,7 +16,7 @@ SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; --let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; --source include/wait_condition.inc -CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); --connection node_2 @@ -27,6 +28,6 @@ SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; --let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready'; --source include/wait_condition.inc -SELECT COUNT(*) = 1 FROM t1; +SELECT COUNT(*) AS EXPECT_1 FROM t1; DROP TABLE t1; diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync_section.cnf b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync_section.cnf index 7cac8e1451e..809b83bb782 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync_section.cnf +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync_section.cnf @@ -4,28 +4,31 @@ [mysqld] innodb-data-home-dir=/tmp -[mariadb] +[mysqld] innodb-data-home-dir= wsrep_sst_method=rsync wsrep_node_address=::1 -[mariadb.1] +[mysqld.1] wsrep-cluster-address=gcomm:// wsrep_provider_options='base_host=[::1];base_port=@mysqld.1.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.1.#galera_port;ist.recv_addr=[::1]:@mysqld.1.#ist_port' wsrep_sst_receive_address='[::1]:@mysqld.1.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.1.port' +bind-address=:: -[mariadb.2] +[mysqld.2] wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port' wsrep_provider_options='base_host=[::1];base_port=@mysqld.2.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.2.#galera_port;ist.recv_addr=[::1]:@mysqld.2.#ist_port' wsrep_sst_receive_address='[::1]:@mysqld.2.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.2.port' +bind-address=:: -[mariadb.3] +[mysqld.3] wsrep_cluster_address='gcomm://[::1]:@mysqld.1.#galera_port' wsrep_provider_options='base_host=[::1];base_port=@mysqld.3.#galera_port;gmcast.listen_addr=tcp://[::]:@mysqld.3.#galera_port;ist.recv_addr=[::1]:@mysqld.3.#ist_port' wsrep_sst_receive_address='[::1]:@mysqld.3.#sst_port' wsrep_node_incoming_address='[::1]:@mysqld.3.port' +bind-address=:: [SST] sockopt=",pf=ip6" diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync_section.opt b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync_section.opt deleted file mode 100644 index c2bb4d156af..00000000000 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync_section.opt +++ /dev/null @@ -1 +0,0 @@ ---bind-address=:: diff --git a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync_section.test b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync_section.test index 1937eb43e13..448611e34e0 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync_section.test +++ b/mysql-test/suite/galera_3nodes/t/galera_ipv6_rsync_section.test @@ -1,5 +1,6 @@ --source include/galera_cluster.inc --source include/check_ipv6.inc +--source include/force_restart.inc # Confirm that initial handshake happened over ipv6 @@ -15,7 +16,7 @@ SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; --let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; --source include/wait_condition.inc -CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); --connection node_2 @@ -27,6 +28,6 @@ SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; --let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_ready'; --source include/wait_condition.inc -SELECT COUNT(*) = 1 FROM t1; +SELECT COUNT(*) AS EXPECT_1 FROM t1; DROP TABLE t1; diff --git a/mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.cnf b/mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.cnf new file mode 100644 index 00000000000..880a413f4b6 --- /dev/null +++ b/mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.cnf @@ -0,0 +1,10 @@ +!include ../galera_3nodes.cnf + +[mysqld.1] +wsrep_debug=1 + +[mysqld.2] +wsrep_debug=1 + +[mysqld.3] +wsrep_debug=1 diff --git a/mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.test b/mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.test index 8e13aed8f5f..65b4000cd1f 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.test +++ b/mysql-test/suite/galera_3nodes/t/galera_safe_to_bootstrap.test @@ -2,6 +2,7 @@ # Test the safe_to_bootstrap in grastate.dat # --source include/galera_cluster.inc +--source include/force_restart.inc # # Create connection node_3 and save auto increment variables. @@ -17,8 +18,11 @@ --source ../galera/include/auto_increment_offset_save.inc --connection node_1 +CREATE TABLE t1 (f1 INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); -CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; +--let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--source include/wait_condition.inc # # At start, all grastate.dat files have safe_to_boostrap: 0 @@ -157,11 +161,19 @@ let $restart_noprint=2; --source include/start_mysqld.inc --source include/wait_until_connected_again.inc +--let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--source include/wait_condition.inc + + --connection node_2 --let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.2.expect let $restart_noprint=2; --source include/start_mysqld.inc +--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +--source include/wait_condition.inc + + --connection node_3 --let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.3.expect let $restart_noprint=2; diff --git a/mysql-test/suite/galera_3nodes/t/galera_var_dirty_reads2.test b/mysql-test/suite/galera_3nodes/t/galera_var_dirty_reads2.test index 9f9d6da17b9..cbee81b7f94 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_var_dirty_reads2.test +++ b/mysql-test/suite/galera_3nodes/t/galera_var_dirty_reads2.test @@ -16,10 +16,13 @@ --source ../galera/include/auto_increment_offset_save.inc --connection node_1 -CREATE TABLE t1 (f1 INTEGER); +CREATE TABLE t1 (f1 INTEGER) ENGINE=INNODB; INSERT INTO t1 VALUES (1); --connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM t1; +--source include/wait_condition.inc + SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; --connection node_1 @@ -28,7 +31,6 @@ SET GLOBAL wsrep_provider_options='gmcast.isolate=1'; --connection node_2 SET SESSION wsrep_sync_wait = 0; - --let $wait_condition = SELECT VARIABLE_VALUE = 'non-Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; --source include/wait_condition.inc @@ -111,6 +113,7 @@ SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.PROCESSLIST; # Restore cluster SET GLOBAL wsrep_provider_options='gmcast.isolate=0'; +--source include/galera_wait_ready.inc --connection node_1 --let $wait_condition = SELECT VARIABLE_VALUE = 3 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; diff --git a/mysql-test/suite/galera_3nodes/t/inconsistency_shutdown.test b/mysql-test/suite/galera_3nodes/t/inconsistency_shutdown.test index 7add9f48cfc..aa9ef08c107 100644 --- a/mysql-test/suite/galera_3nodes/t/inconsistency_shutdown.test +++ b/mysql-test/suite/galera_3nodes/t/inconsistency_shutdown.test @@ -7,7 +7,7 @@ --source include/have_innodb.inc --source include/have_debug.inc --source include/have_debug_sync.inc ---source ../galera/include/galera_have_debug_sync.inc +--source include/galera_have_debug_sync.inc # Save original auto_increment_offset values. --let $node_1=node_1 diff --git a/mysql-test/suite/galera_sr/disabled.def b/mysql-test/suite/galera_sr/disabled.def index 1d8b79a8fb5..c0e5857d6bc 100644 --- a/mysql-test/suite/galera_sr/disabled.def +++ b/mysql-test/suite/galera_sr/disabled.def @@ -10,8 +10,6 @@ # ############################################################################## -GCF-1018B : MDEV-21613 galera_sr.GCF-1018B MTR failed: Failed to open table mysql.wsrep_streaming_log for writing -GCF-1043A : MDEV-21170 Galera test failure on galera_sr.GCF-1043A GCF-1060 : MDEV-20848 galera_sr.GCF_1060 galera-features#56 : MDEV-18542 galera_sr.galera-features#56 diff --git a/mysql-test/suite/galera_sr/r/GCF-1043A.result b/mysql-test/suite/galera_sr/r/GCF-1043A.result deleted file mode 100644 index cc90461291d..00000000000 --- a/mysql-test/suite/galera_sr/r/GCF-1043A.result +++ /dev/null @@ -1,21 +0,0 @@ -connection node_2; -connection node_1; -connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; -Running a concurrent test with the following queries: -DELETE FROM t1 -REPLACE INTO t1 VALUES (1,'y'),(2,'x') -REPLACE INTO t1 VALUES (1,'y'),(2,'y'),(3,'y') -connection node_1; -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB; -SET SESSION wsrep_sync_wait = 0; -SET SESSION wsrep_trx_fragment_size = 1;;; -connection node_1a; -SET SESSION wsrep_sync_wait = 0; -SET SESSION wsrep_trx_fragment_size = 1;;; -connection node_2; -SET SESSION wsrep_sync_wait = 0; -SET SESSION wsrep_trx_fragment_size = 1;;; -include/diff_servers.inc [servers=1 2] -DROP TABLE t1; -Concurrent test end diff --git a/mysql-test/suite/galera_sr/r/GCF-1043B.result b/mysql-test/suite/galera_sr/r/GCF-1043B.result deleted file mode 100644 index a10295c00b9..00000000000 --- a/mysql-test/suite/galera_sr/r/GCF-1043B.result +++ /dev/null @@ -1,21 +0,0 @@ -connection node_2; -connection node_1; -connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; -Running a concurrent test with the following queries: -DELETE FROM t1 -INSERT INTO t1 VALUES (1,'y'),(2,'x') -UPDATE t1 SET f2 = 'y' WHERE f1 = 1 OR f1 = 2; -connection node_1; -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (f1 INTEGER PRIMARY KEY AUTO_INCREMENT, f2 CHAR(255)) ENGINE=InnoDB; -SET SESSION wsrep_sync_wait = 0; -SET SESSION wsrep_trx_fragment_size = 1;;; -connection node_1a; -SET SESSION wsrep_sync_wait = 0; -SET SESSION wsrep_trx_fragment_size = 1;;; -connection node_2; -SET SESSION wsrep_sync_wait = 0; -SET SESSION wsrep_trx_fragment_size = 1;;; -include/diff_servers.inc [servers=1 2] -DROP TABLE t1; -Concurrent test end diff --git a/mysql-test/suite/galera_sr/r/GCF-597.result b/mysql-test/suite/galera_sr/r/GCF-597.result index 7afca229251..52b13ba3268 100644 --- a/mysql-test/suite/galera_sr/r/GCF-597.result +++ b/mysql-test/suite/galera_sr/r/GCF-597.result @@ -15,7 +15,13 @@ INSERT INTO t1 VALUES (2); INSERT INTO t1 VALUES (3); INSERT INTO t1 VALUES (4); INSERT INTO t1 VALUES (5); +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; +connection node_1a; +connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; +connection node_2a; connection node_2; ROLLBACK; ERROR 40001: Deadlock found when trying to get lock; try restarting transaction DROP TABLE t1; +disconnect node_1a; +disconnect node_2a; diff --git a/mysql-test/suite/galera_sr/r/galera_sr_kill_query.result b/mysql-test/suite/galera_sr/r/galera_sr_kill_query.result index 82f41a2faaa..c775cd854a7 100644 --- a/mysql-test/suite/galera_sr/r/galera_sr_kill_query.result +++ b/mysql-test/suite/galera_sr/r/galera_sr_kill_query.result @@ -17,17 +17,25 @@ SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT COUNT(*) AS EXPECT_0 FROM t1; EXPECT_0 0 -SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; -EXPECT_0 -0 INSERT INTO t1 SELECT 1 FROM ten AS t1, ten AS t2, ten AS t3; SELECT COUNT(*) AS EXPECT_1000 FROM t1; EXPECT_1000 1000 -connection node_1a; +connection node_1; SET GLOBAL wsrep_sync_wait=15; SELECT COUNT(*) AS EXPECT_1000 FROM t1; EXPECT_1000 1000 +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; +EXPECT_0 +0 +connection node_2; +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +EXPECT_1000 +1000 +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; +EXPECT_0 +0 +connection node_1; DROP TABLE t1; DROP TABLE ten; diff --git a/mysql-test/suite/galera_sr/r/galera_sr_kill_slave.result b/mysql-test/suite/galera_sr/r/galera_sr_kill_slave.result index d14de27d2b7..eab6110afb1 100644 --- a/mysql-test/suite/galera_sr/r/galera_sr_kill_slave.result +++ b/mysql-test/suite/galera_sr/r/galera_sr_kill_slave.result @@ -2,9 +2,9 @@ connection node_2; connection node_1; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; connection node_2; -SELECT COUNT(*) = 0 FROM t1; -COUNT(*) = 0 -1 +SELECT COUNT(*) AS EXPECT_0 FROM t1; +EXPECT_0 +0 connection node_1; CREATE TABLE t2 (f1 INTEGER); connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; @@ -39,16 +39,16 @@ INSERT INTO t1 VALUES (13); INSERT INTO t1 VALUES (14); INSERT INTO t1 VALUES (15); COMMIT; -SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log; -COUNT(*) = 0 -1 +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; +EXPECT_0 +0 connection node_2; -SELECT COUNT(*) = 15 FROM t1; -COUNT(*) = 15 -1 -SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log; -COUNT(*) = 0 -1 +SELECT COUNT(*) AS EXPECT_15 FROM t1; +EXPECT_15 +15 +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; +EXPECT_0 +0 connection node_1; DROP TABLE t1; DROP TABLE t2; diff --git a/mysql-test/suite/galera_sr/r/galera_sr_rollback_retry.result b/mysql-test/suite/galera_sr/r/galera_sr_rollback_retry.result index 054f7cf2eae..1117a50ded1 100644 --- a/mysql-test/suite/galera_sr/r/galera_sr_rollback_retry.result +++ b/mysql-test/suite/galera_sr/r/galera_sr_rollback_retry.result @@ -11,10 +11,11 @@ INSERT INTO t1 VALUES (3); INSERT INTO t1 VALUES (4); INSERT INTO t1 VALUES (5); connection node_2; -SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; connection node_1; ROLLBACK; connection node_2; +SELECT * FROM t1; +f1 SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES (1); @@ -23,11 +24,11 @@ INSERT INTO t1 VALUES (3); INSERT INTO t1 VALUES (4); INSERT INTO t1 VALUES (5); COMMIT; -SELECT COUNT(*) = 5 FROM t1; -COUNT(*) = 5 -1 +SELECT COUNT(*) AS EXPECT_5 FROM t1; +EXPECT_5 +5 connection node_1; -SELECT COUNT(*) = 5 FROM t1; -COUNT(*) = 5 -1 +SELECT COUNT(*) AS EXPECT_5 FROM t1; +EXPECT_5 +5 DROP TABLE t1; diff --git a/mysql-test/suite/galera_sr/t/GCF-1043A.test b/mysql-test/suite/galera_sr/t/GCF-1043A.test deleted file mode 100644 index c76623742d7..00000000000 --- a/mysql-test/suite/galera_sr/t/GCF-1043A.test +++ /dev/null @@ -1,13 +0,0 @@ -# -# Assertion `retval == WSREP_OK || retval == WSREP_TRX_FAIL || retval == WSREP_BF_ABORT || retval == WSREP_CONN_FAIL' failed with SR -# - ---source include/galera_cluster.inc - ---let $count = 1000; ---let $wsrep_trx_fragment_size = 1; ---let $query_node_1 = DELETE FROM t1 ---let $query_node_1a = REPLACE INTO t1 VALUES (1,'y'),(2,'x') ---let $query_node_2 = REPLACE INTO t1 VALUES (1,'y'),(2,'y'),(3,'y') - ---source suite/galera/include/galera_concurrent_test.inc diff --git a/mysql-test/suite/galera_sr/t/GCF-1043B.test b/mysql-test/suite/galera_sr/t/GCF-1043B.test deleted file mode 100644 index e3b6b7439ca..00000000000 --- a/mysql-test/suite/galera_sr/t/GCF-1043B.test +++ /dev/null @@ -1,13 +0,0 @@ -# -# Assertion `retval == WSREP_OK || retval == WSREP_TRX_FAIL || retval == WSREP_BF_ABORT || retval == WSREP_CONN_FAIL' failed with SR -# - ---source include/galera_cluster.inc - ---let $count = 1000; ---let $wsrep_trx_fragment_size = 1; ---let $query_node_1 = DELETE FROM t1 ---let $query_node_1a = INSERT INTO t1 VALUES (1,'y'),(2,'x') ---let $query_node_2 = UPDATE t1 SET f2 = 'y' WHERE f1 = 1 OR f1 = 2; - ---source suite/galera/include/galera_concurrent_test.inc diff --git a/mysql-test/suite/galera_sr/t/GCF-597.test b/mysql-test/suite/galera_sr/t/GCF-597.test index d3d80ffc4f8..9c86e598154 100644 --- a/mysql-test/suite/galera_sr/t/GCF-597.test +++ b/mysql-test/suite/galera_sr/t/GCF-597.test @@ -22,8 +22,21 @@ INSERT INTO t1 VALUES (3); INSERT INTO t1 VALUES (4); INSERT INTO t1 VALUES (5); +--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1 +--connection node_1a +--let $wait_condition = SELECT COUNT(*) = 5 FROM mysql.wsrep_streaming_log +--source include/wait_condition.inc + +--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2 +--connection node_2a +--let $wait_condition = SELECT COUNT(*) = 5 FROM mysql.wsrep_streaming_log +--source include/wait_condition.inc + --connection node_2 --error ER_LOCK_DEADLOCK ROLLBACK; -DROP TABLE t1;
\ No newline at end of file +DROP TABLE t1; + +--disconnect node_1a +--disconnect node_2a diff --git a/mysql-test/suite/galera_sr/t/galera_sr_kill_query.test b/mysql-test/suite/galera_sr/t/galera_sr_kill_query.test index 5282baed86d..8bce5f6bc36 100644 --- a/mysql-test/suite/galera_sr/t/galera_sr_kill_query.test +++ b/mysql-test/suite/galera_sr/t/galera_sr_kill_query.test @@ -33,18 +33,27 @@ SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; # Confirm that the kill caused the updates made so far to be removed --connection node_2 +--let $wait_condition = SELECT COUNT(*) = 0 FROM t1 +--source include/wait_condition.inc SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT COUNT(*) AS EXPECT_0 FROM t1; -SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; # Confirm that the transaction can be reissued in its entirety on the slave without a conflict INSERT INTO t1 SELECT 1 FROM ten AS t1, ten AS t2, ten AS t3; SELECT COUNT(*) AS EXPECT_1000 FROM t1; ---connection node_1a +--connection node_1 SET GLOBAL wsrep_sync_wait=15; +--let $wait_condition = SELECT COUNT(*) = 1000 FROM t1; +--source include/wait_condition.inc +SELECT COUNT(*) AS EXPECT_1000 FROM t1; +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; + +--connection node_2 SELECT COUNT(*) AS EXPECT_1000 FROM t1; +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; +--connection node_1 DROP TABLE t1; DROP TABLE ten; diff --git a/mysql-test/suite/galera_sr/t/galera_sr_kill_slave.test b/mysql-test/suite/galera_sr/t/galera_sr_kill_slave.test index a76a03e49b9..cbf7213c69f 100644 --- a/mysql-test/suite/galera_sr/t/galera_sr_kill_slave.test +++ b/mysql-test/suite/galera_sr/t/galera_sr_kill_slave.test @@ -13,12 +13,17 @@ CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; # Block node #2's applier before table t1's inserts have come into play --connection node_2 -SELECT COUNT(*) = 0 FROM t1; +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1' +--source include/wait_condition.inc +SELECT COUNT(*) AS EXPECT_0 FROM t1; --connection node_1 CREATE TABLE t2 (f1 INTEGER); --connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2' +--source include/wait_condition.inc + LOCK TABLE t2 WRITE; --connection node_1 @@ -39,11 +44,8 @@ INSERT INTO t1 VALUES (3); INSERT INTO t1 VALUES (4); INSERT INTO t1 VALUES (5); ---sleep 2 - --connection node_2 --source include/kill_galera.inc ---sleep 1 --connection node_1 INSERT INTO t1 VALUES (6); @@ -54,8 +56,6 @@ INSERT INTO t1 VALUES (10); --connection node_2 --source include/start_mysqld.inc ---sleep 1 - --source include/wait_until_connected_again.inc --source include/galera_wait_ready.inc @@ -67,12 +67,17 @@ INSERT INTO t1 VALUES (14); INSERT INTO t1 VALUES (15); COMMIT; -SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log; +--let $wait_condition = SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; --connection node_2 ---sleep 5 -SELECT COUNT(*) = 15 FROM t1; -SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log; +--let $wait_condition = SELECT COUNT(*) = 15 FROM t1 +--source include/wait_condition.inc + +SELECT COUNT(*) AS EXPECT_15 FROM t1; +SELECT COUNT(*) AS EXPECT_0 FROM mysql.wsrep_streaming_log; --connection node_1 diff --git a/mysql-test/suite/galera_sr/t/galera_sr_rollback_retry.test b/mysql-test/suite/galera_sr/t/galera_sr_rollback_retry.test index c6c443a0828..e5d204d85c8 100644 --- a/mysql-test/suite/galera_sr/t/galera_sr_rollback_retry.test +++ b/mysql-test/suite/galera_sr/t/galera_sr_rollback_retry.test @@ -19,8 +19,7 @@ INSERT INTO t1 VALUES (4); INSERT INTO t1 VALUES (5); --connection node_2 -SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; ---let $wait_condition = SELECT COUNT(*) > 0 FROM t1; +--let $wait_condition = SELECT COUNT(*) > 0 FROM mysql.wsrep_streaming_log --source include/wait_condition.inc --connection node_1 @@ -33,6 +32,7 @@ ROLLBACK; --connection node_2 --let $wait_condition = SELECT COUNT(*) = 0 FROM t1; --source include/wait_condition.inc +SELECT * FROM t1; # # It should be possible to reissue the same transaction against node #2 @@ -47,9 +47,11 @@ INSERT INTO t1 VALUES (4); INSERT INTO t1 VALUES (5); COMMIT; -SELECT COUNT(*) = 5 FROM t1; +SELECT COUNT(*) AS EXPECT_5 FROM t1; --connection node_1 -SELECT COUNT(*) = 5 FROM t1; +--let $wait_condition = SELECT COUNT(*) = 5 FROM t1; +--source include/wait_condition.inc +SELECT COUNT(*) AS EXPECT_5 FROM t1; DROP TABLE t1; diff --git a/mysql-test/suite/gcol/inc/gcol_keys.inc b/mysql-test/suite/gcol/inc/gcol_keys.inc index 97c9e41b5e8..475ab96e56f 100644 --- a/mysql-test/suite/gcol/inc/gcol_keys.inc +++ b/mysql-test/suite/gcol/inc/gcol_keys.inc @@ -747,4 +747,66 @@ ANALYZE TABLE t1, t2; --eval $query DROP TABLE t1, t2; +if($support_virtual_index) +{ +--echo # +--echo # MDEV-20618 Assertion `btr_validate_index(index, 0, false)' failed +--echo # in row_upd_sec_index_entry +--echo # +CREATE TABLE t1 (A BIT(15), VA BIT(10) GENERATED ALWAYS AS (A),PK INT, + PRIMARY KEY (PK), UNIQUE KEY (VA)); + +INSERT IGNORE INTO t1 VALUES ( '\r1','a',1); +--error ER_DATA_TOO_LONG +REPLACE INTO t1 (PK) VALUES (1); + +DROP TABLE t1; + +--echo # +--echo # MDEV-17890 Record in index was not found on update, server crash in +--echo # row_upd_build_difference_binary or +--echo # Assertion `0' failed in row_upd_sec_index_entry +--echo # +CREATE TABLE t1 ( + pk BIGINT AUTO_INCREMENT, + b BIT(15), + v BIT(10) AS (b) VIRTUAL, + PRIMARY KEY(pk), + UNIQUE(v) +); + +INSERT IGNORE INTO t1 (b) VALUES (b'101110001110100'),(b'011101'); +SELECT pk, b INTO OUTFILE 'load.data' FROM t1; +--error ER_DATA_TOO_LONG +LOAD DATA INFILE 'load.data' REPLACE INTO TABLE t1 (pk, b); + +--let $datadir= `SELECT @@datadir` +--remove_file $datadir/test/load.data +DROP TABLE t1; + +--echo # +--echo # MDEV-17834 Server crashes in row_upd_build_difference_binary +--echo # on LOAD DATA into table with indexed virtual column --echo # +CREATE TABLE t1 ( + pk INT, + i TINYINT, + ts TIMESTAMP NULL, + vi TINYINT AS (i+1) PERSISTENT, + vts TIMESTAMP(5) AS (ts) VIRTUAL, + PRIMARY KEY(pk), + UNIQUE(vts) +); + +INSERT IGNORE INTO t1 (pk,i) VALUES (1,127); + +--write_file $MYSQLTEST_VARDIR/tmp/load.data +1 4 2019-01-01 00:00:00 +EOF +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--error ER_WARN_DATA_OUT_OF_RANGE +eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/load.data' REPLACE INTO TABLE t1 (pk,i,ts); + +--remove_file $MYSQLTEST_VARDIR/tmp/load.data +DROP TABLE t1; +} diff --git a/mysql-test/suite/gcol/r/gcol_keys_innodb.result b/mysql-test/suite/gcol/r/gcol_keys_innodb.result index 2028a95a081..4f7d654ac4e 100644 --- a/mysql-test/suite/gcol/r/gcol_keys_innodb.result +++ b/mysql-test/suite/gcol/r/gcol_keys_innodb.result @@ -833,6 +833,56 @@ a1 a2 b 0 NULL 1 DROP TABLE t1, t2; # +# MDEV-20618 Assertion `btr_validate_index(index, 0, false)' failed +# in row_upd_sec_index_entry +# +CREATE TABLE t1 (A BIT(15), VA BIT(10) GENERATED ALWAYS AS (A),PK INT, +PRIMARY KEY (PK), UNIQUE KEY (VA)); +INSERT IGNORE INTO t1 VALUES ( '\r1','a',1); +Warnings: +Warning 1906 The value specified for generated column 'VA' in table 't1' has been ignored +Warning 1264 Out of range value for column 'VA' at row 1 +REPLACE INTO t1 (PK) VALUES (1); +ERROR 22001: Data too long for column 'VA' at row 1 +DROP TABLE t1; +# +# MDEV-17890 Record in index was not found on update, server crash in +# row_upd_build_difference_binary or +# Assertion `0' failed in row_upd_sec_index_entry +# +CREATE TABLE t1 ( +pk BIGINT AUTO_INCREMENT, +b BIT(15), +v BIT(10) AS (b) VIRTUAL, +PRIMARY KEY(pk), +UNIQUE(v) +); +INSERT IGNORE INTO t1 (b) VALUES (b'101110001110100'),(b'011101'); +Warnings: +Warning 1264 Out of range value for column 'v' at row 1 +SELECT pk, b INTO OUTFILE 'load.data' FROM t1; +LOAD DATA INFILE 'load.data' REPLACE INTO TABLE t1 (pk, b); +ERROR 22001: Data too long for column 'v' at row 1 +DROP TABLE t1; +# +# MDEV-17834 Server crashes in row_upd_build_difference_binary +# on LOAD DATA into table with indexed virtual column +# +CREATE TABLE t1 ( +pk INT, +i TINYINT, +ts TIMESTAMP NULL, +vi TINYINT AS (i+1) PERSISTENT, +vts TIMESTAMP(5) AS (ts) VIRTUAL, +PRIMARY KEY(pk), +UNIQUE(vts) +); +INSERT IGNORE INTO t1 (pk,i) VALUES (1,127); +Warnings: +Warning 1264 Out of range value for column 'vi' at row 1 +LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/load.data' REPLACE INTO TABLE t1 (pk,i,ts); +ERROR 22003: Out of range value for column 'vi' at row 1 +DROP TABLE t1; # # BUG#21365158 WL8149:ASSERTION `!TABLE || (!TABLE->WRITE_SET # diff --git a/mysql-test/suite/gcol/r/gcol_keys_myisam.result b/mysql-test/suite/gcol/r/gcol_keys_myisam.result index 91bd8fcdb78..3f00d344901 100644 --- a/mysql-test/suite/gcol/r/gcol_keys_myisam.result +++ b/mysql-test/suite/gcol/r/gcol_keys_myisam.result @@ -833,6 +833,56 @@ a1 a2 b 0 NULL 1 DROP TABLE t1, t2; # +# MDEV-20618 Assertion `btr_validate_index(index, 0, false)' failed +# in row_upd_sec_index_entry +# +CREATE TABLE t1 (A BIT(15), VA BIT(10) GENERATED ALWAYS AS (A),PK INT, +PRIMARY KEY (PK), UNIQUE KEY (VA)); +INSERT IGNORE INTO t1 VALUES ( '\r1','a',1); +Warnings: +Warning 1906 The value specified for generated column 'VA' in table 't1' has been ignored +Warning 1264 Out of range value for column 'VA' at row 1 +REPLACE INTO t1 (PK) VALUES (1); +ERROR 22001: Data too long for column 'VA' at row 1 +DROP TABLE t1; +# +# MDEV-17890 Record in index was not found on update, server crash in +# row_upd_build_difference_binary or +# Assertion `0' failed in row_upd_sec_index_entry +# +CREATE TABLE t1 ( +pk BIGINT AUTO_INCREMENT, +b BIT(15), +v BIT(10) AS (b) VIRTUAL, +PRIMARY KEY(pk), +UNIQUE(v) +); +INSERT IGNORE INTO t1 (b) VALUES (b'101110001110100'),(b'011101'); +Warnings: +Warning 1264 Out of range value for column 'v' at row 1 +SELECT pk, b INTO OUTFILE 'load.data' FROM t1; +LOAD DATA INFILE 'load.data' REPLACE INTO TABLE t1 (pk, b); +ERROR 22001: Data too long for column 'v' at row 1 +DROP TABLE t1; +# +# MDEV-17834 Server crashes in row_upd_build_difference_binary +# on LOAD DATA into table with indexed virtual column +# +CREATE TABLE t1 ( +pk INT, +i TINYINT, +ts TIMESTAMP NULL, +vi TINYINT AS (i+1) PERSISTENT, +vts TIMESTAMP(5) AS (ts) VIRTUAL, +PRIMARY KEY(pk), +UNIQUE(vts) +); +INSERT IGNORE INTO t1 (pk,i) VALUES (1,127); +Warnings: +Warning 1264 Out of range value for column 'vi' at row 1 +LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/load.data' REPLACE INTO TABLE t1 (pk,i,ts); +ERROR 22003: Out of range value for column 'vi' at row 1 +DROP TABLE t1; DROP VIEW IF EXISTS v1,v2; DROP TABLE IF EXISTS t1,t2,t3; DROP PROCEDURE IF EXISTS p1; diff --git a/mysql-test/suite/gcol/r/innodb_virtual_fk.result b/mysql-test/suite/gcol/r/innodb_virtual_fk.result index d5b4755e3c5..a3cdacb67a2 100644 --- a/mysql-test/suite/gcol/r/innodb_virtual_fk.result +++ b/mysql-test/suite/gcol/r/innodb_virtual_fk.result @@ -740,3 +740,32 @@ t1 CREATE TABLE `t1` ( KEY `v4` (`v4`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 DROP TABLE t1; +# +# MDEV-20396 Server crashes after DELETE with SEL NULL Foreign key and a +# virtual column in index +# +CREATE TABLE parent +( +ID int unsigned NOT NULL, +PRIMARY KEY (ID) +); +CREATE TABLE child +( +ID int unsigned NOT NULL, +ParentID int unsigned NULL, +Value int unsigned NOT NULL DEFAULT 0, +Flag int unsigned AS (Value) VIRTUAL, +PRIMARY KEY (ID), +KEY (ParentID, Flag), +FOREIGN KEY (ParentID) REFERENCES parent (ID) ON DELETE SET NULL +ON UPDATE CASCADE +); +INSERT INTO parent (ID) VALUES (100); +INSERT INTO child (ID,ParentID,Value) VALUES (123123,100,1); +DELETE FROM parent WHERE ID=100; +select * from child; +ID ParentID Value Flag +123123 NULL 1 1 +INSERT INTO parent (ID) VALUES (100); +UPDATE child SET ParentID=100 WHERE ID=123123; +DROP TABLE child, parent; diff --git a/mysql-test/suite/gcol/r/innodb_virtual_index.result b/mysql-test/suite/gcol/r/innodb_virtual_index.result index 3918cf95ae1..70c9d10a68b 100644 --- a/mysql-test/suite/gcol/r/innodb_virtual_index.result +++ b/mysql-test/suite/gcol/r/innodb_virtual_index.result @@ -255,6 +255,9 @@ ERROR 22007: Incorrect date value: '20190132' for column `test`.`t1`.`vb` at row SELECT * FROM t1; a b vb ROLLBACK; +SELECT * FROM t1; +a b vb +1 20190132 0000-00-00 CHECK TABLE t1; Table Op Msg_type Msg_text test.t1 check status OK diff --git a/mysql-test/suite/gcol/t/innodb_virtual_fk.test b/mysql-test/suite/gcol/t/innodb_virtual_fk.test index c484bb5dc0c..226bacabaef 100644 --- a/mysql-test/suite/gcol/t/innodb_virtual_fk.test +++ b/mysql-test/suite/gcol/t/innodb_virtual_fk.test @@ -605,3 +605,35 @@ ALTER TABLE t1 ADD CONSTRAINT fk FOREIGN KEY (v4) REFERENCES nosuch(col); SHOW CREATE TABLE t1; # Cleanup DROP TABLE t1; + +--echo # +--echo # MDEV-20396 Server crashes after DELETE with SEL NULL Foreign key and a +--echo # virtual column in index +--echo # +CREATE TABLE parent +( + ID int unsigned NOT NULL, + PRIMARY KEY (ID) +); + +CREATE TABLE child +( + ID int unsigned NOT NULL, + ParentID int unsigned NULL, + Value int unsigned NOT NULL DEFAULT 0, + Flag int unsigned AS (Value) VIRTUAL, + PRIMARY KEY (ID), + KEY (ParentID, Flag), + FOREIGN KEY (ParentID) REFERENCES parent (ID) ON DELETE SET NULL + ON UPDATE CASCADE +); + +INSERT INTO parent (ID) VALUES (100); +INSERT INTO child (ID,ParentID,Value) VALUES (123123,100,1); +DELETE FROM parent WHERE ID=100; +select * from child; +INSERT INTO parent (ID) VALUES (100); +UPDATE child SET ParentID=100 WHERE ID=123123; + +# Cleanup +DROP TABLE child, parent; diff --git a/mysql-test/suite/gcol/t/innodb_virtual_index.test b/mysql-test/suite/gcol/t/innodb_virtual_index.test index c2f9cd78fe2..353841840dc 100644 --- a/mysql-test/suite/gcol/t/innodb_virtual_index.test +++ b/mysql-test/suite/gcol/t/innodb_virtual_index.test @@ -278,7 +278,6 @@ DELETE FROM t1; INSERT INTO t1 (a,b) VALUES(1,20190123); SELECT * FROM t1; ROLLBACK; -# MDEV-18366 FIXME: fix the crash and enable this -# SELECT * FROM t1; +SELECT * FROM t1; CHECK TABLE t1; DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/alter_table.result b/mysql-test/suite/innodb/r/alter_table.result index b1de6be804a..58e2b22273b 100644 --- a/mysql-test/suite/innodb/r/alter_table.result +++ b/mysql-test/suite/innodb/r/alter_table.result @@ -60,6 +60,16 @@ CREATE TABLE t1(a INT NOT NULL UNIQUE) ENGINE=InnoDB; INSERT INTO t1 SELECT * FROM seq_1_to_128; ALTER TABLE t1 ADD b TINYINT AUTO_INCREMENT PRIMARY KEY, DROP KEY a; DROP TABLE t1; +# +# MDEV-22939 Server crashes in row_make_new_pathname() +# +CREATE TABLE t (a INT) ENGINE=INNODB; +ALTER TABLE t DISCARD TABLESPACE; +ALTER TABLE t ENGINE INNODB; +ERROR HY000: Tablespace has been discarded for table `t` +ALTER TABLE t FORCE; +ERROR HY000: Tablespace has been discarded for table `t` +DROP TABLE t; create table t1 (a int) transactional=1 engine=aria; create table t2 (a int) transactional=1 engine=innodb; show create table t1; diff --git a/mysql-test/suite/innodb/r/foreign-keys.result b/mysql-test/suite/innodb/r/foreign-keys.result index 62b4d37a979..45177a4bddf 100644 --- a/mysql-test/suite/innodb/r/foreign-keys.result +++ b/mysql-test/suite/innodb/r/foreign-keys.result @@ -220,3 +220,19 @@ drop table t1,t2; ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails drop table t1,t2; ERROR 42S02: Unknown table 'test.t2' +# +# MDEV-23470 InnoDB: Failing assertion: cmp < 0 in +# row_ins_check_foreign_constraint +# +CREATE TABLE t1(f1 INT NOT NULL PRIMARY KEY, f2 INT NOT NULL)ENGINE=InnoDB; +CREATE TABLE t2(f1 VARCHAR(100), f2 INT NOT NULL, +INDEX(f2))ENGINE=InnoDB; +INSERT INTO t1 VALUES(99, 2); +ALTER TABLE t2 ADD FOREIGN KEY(f2) REFERENCES t1(f1); +SET FOREIGN_KEY_CHECKS=0; +DROP INDEX f2 ON t2; +SET FOREIGN_KEY_CHECKS=1; +INSERT INTO t2 VALUES('G', 3); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`f2`) REFERENCES `t1` (`f1`)) +DROP TABLE t2, t1; +SET FOREIGN_KEY_CHECKS=DEFAULT; diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index 854b53b3083..aadfc338501 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -168,7 +168,6 @@ PRIMARY KEY (store_id), UNIQUE KEY idx_unique_manager (manager_staff_id), CONSTRAINT fk_store_staff FOREIGN KEY (manager_staff_id) REFERENCES staff (staff_id) ON DELETE RESTRICT ON UPDATE CASCADE ) ENGINE=InnoDB; -SET FOREIGN_KEY_CHECKS=DEFAULT; LOCK TABLE staff WRITE; UNLOCK TABLES; DROP TABLES staff, store; @@ -737,6 +736,17 @@ t2 CREATE TABLE `t2` ( CREATE TABLE t2 (f1 INT NOT NULL)ENGINE=InnoDB; ERROR 42S01: Table 't2' already exists DROP TABLE t2, t1; +# +# MDEV-23685 SIGSEGV on ADD FOREIGN KEY after failed attempt +# to create unique key on virtual column +# +CREATE TABLE t1 (pk INT PRIMARY KEY, a INT, b INT AS (a)) ENGINE=InnODB; +INSERT INTO t1 (pk,a) VALUES (1,10),(2,10); +ALTER TABLE t1 ADD UNIQUE INDEX ind9 (b), LOCK=SHARED; +ERROR 23000: Duplicate entry '10' for key 'ind9' +SET FOREIGN_KEY_CHECKS= 0; +ALTER TABLE t1 ADD FOREIGN KEY (a) REFERENCES t1 (pk); +DROP TABLE t1; # End of 10.2 tests CREATE TABLE t1 (a GEOMETRY, INDEX(a(8)), FOREIGN KEY (a) REFERENCES x (xx)) ENGINE=InnoDB; diff --git a/mysql-test/suite/innodb/r/innodb-wl5522-debug.result b/mysql-test/suite/innodb/r/innodb-wl5522-debug.result index ad79967a2e5..8e255e18bec 100644 --- a/mysql-test/suite/innodb/r/innodb-wl5522-debug.result +++ b/mysql-test/suite/innodb/r/innodb-wl5522-debug.result @@ -488,8 +488,6 @@ INDEX idx3(c4(512))) Engine=InnoDB; connect purge_control,localhost,root; START TRANSACTION WITH CONSISTENT SNAPSHOT; connection default; -SET GLOBAL innodb_monitor_reset = ibuf_merges; -SET GLOBAL innodb_monitor_reset = ibuf_merges_insert; INSERT INTO t1 SELECT 1 + seq, 1 + (seq MOD 4), REPEAT(SUBSTR('abcd', 1 + (seq MOD 4), 1), 2048), @@ -660,22 +658,9 @@ COUNT(*) SELECT SUM(c2) FROM t1; SUM(c2) 124160 -SELECT name -FROM information_schema.innodb_metrics -WHERE name = 'ibuf_merges_insert' AND count = 0; -name -ibuf_merges_insert FLUSH TABLES t1 FOR EXPORT; backup: t1 UNLOCK TABLES; -SELECT name -FROM information_schema.innodb_metrics -WHERE name = 'ibuf_merges' AND count > 0; -name -SELECT name -FROM information_schema.innodb_metrics -WHERE name = 'ibuf_merges_inserts' AND count > 0; -name connection purge_control; COMMIT; disconnect purge_control; @@ -954,10 +939,4 @@ SET SESSION debug_dbug=@saved_debug_dbug; DROP TABLE t1; unlink: t1.ibd unlink: t1.cfg -set global innodb_monitor_disable = all; -set global innodb_monitor_reset_all = all; -set global innodb_monitor_enable = default; -set global innodb_monitor_disable = default; -set global innodb_monitor_reset = default; -set global innodb_monitor_reset_all = default; SET GLOBAL INNODB_FILE_PER_TABLE=@file_per_table; diff --git a/mysql-test/suite/innodb/r/purge_secondary.result b/mysql-test/suite/innodb/r/purge_secondary.result index 1b5f2896887..7c2b4151e76 100644 --- a/mysql-test/suite/innodb/r/purge_secondary.result +++ b/mysql-test/suite/innodb/r/purge_secondary.result @@ -141,18 +141,9 @@ WHERE NAME='test/t1'; OTHER_INDEX_SIZE 1 ALTER TABLE t1 DROP INDEX `sidx`; -INSERT INTO t1 () VALUES (),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(); -INSERT INTO t1 (a) SELECT NULL FROM t1; -INSERT INTO t1 (a) SELECT NULL FROM t1; -INSERT INTO t1 (a) SELECT NULL FROM t1; -INSERT INTO t1 (a) SELECT NULL FROM t1; -INSERT INTO t1 (a) SELECT NULL FROM t1; +INSERT INTO t1 (a) SELECT * FROM seq_1_to_544; ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; -SELECT NAME, SUBSYSTEM FROM INFORMATION_SCHEMA.INNODB_METRICS -WHERE NAME="buffer_LRU_batch_flush_total_pages" AND COUNT > 0; -NAME SUBSYSTEM -buffer_LRU_batch_flush_total_pages buffer SELECT (variable_value > 0) FROM information_schema.global_status WHERE LOWER(variable_name) LIKE 'INNODB_BUFFER_POOL_PAGES_FLUSHED'; (variable_value > 0) diff --git a/mysql-test/suite/innodb/r/row_format_redundant.result b/mysql-test/suite/innodb/r/row_format_redundant.result index 0b42d297395..0eede61b175 100644 --- a/mysql-test/suite/innodb/r/row_format_redundant.result +++ b/mysql-test/suite/innodb/r/row_format_redundant.result @@ -6,8 +6,7 @@ SET GLOBAL innodb_file_per_table=1; # SET GLOBAL innodb_file_per_table=ON; create table t1 (a int not null, d varchar(15) not null, b -varchar(198) not null, c char(156), -fulltext ftsic(c)) engine=InnoDB +varchar(198) not null, c char(156)) engine=InnoDB row_format=redundant; insert into t1 values(123, 'abcdef', 'jghikl', 'mnop'); insert into t1 values(456, 'abcdef', 'jghikl', 'mnop'); @@ -76,7 +75,7 @@ DROP TABLE t1; Warnings: Warning 1932 Table 'test.t1' doesn't exist in engine DROP TABLE t2,t3; -FOUND 49 /\[ERROR\] InnoDB: Table `test`\.`t1` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=1 SYS_TABLES\.MIX_LEN=511\b/ in mysqld.1.err +FOUND 5 /\[ERROR\] InnoDB: Table `test`\.`t1` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=1 SYS_TABLES\.MIX_LEN=511\b/ in mysqld.1.err # restart ib_buffer_pool ib_logfile0 diff --git a/mysql-test/suite/innodb/r/table_flags.result b/mysql-test/suite/innodb/r/table_flags.result index 82935944027..347ba5ef52c 100644 --- a/mysql-test/suite/innodb/r/table_flags.result +++ b/mysql-test/suite/innodb/r/table_flags.result @@ -200,3 +200,13 @@ CREATE TABLE t1(f1 INT, f2 VARCHAR(1), KEY k1(f2), FULLTEXT KEY(f2), FOREIGN KEY (f2) REFERENCES t1(f3))ENGINE=InnoDB; ERROR HY000: Can't create table `test`.`t1` (errno: 150 "Foreign key constraint is incorrectly formed") +# +# MDEV-23199 page_compression flag is missing +# for full_crc32 tablespace +# +CREATE TABLE t1(f1 BIGINT PRIMARY KEY)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1); +ALTER TABLE t1 PAGE_COMPRESSED = 1; +INSERT INTO t1 VALUES(2); +# restart +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/truncate.result b/mysql-test/suite/innodb/r/truncate.result index 0e5ffeea34f..180414f47c7 100644 --- a/mysql-test/suite/innodb/r/truncate.result +++ b/mysql-test/suite/innodb/r/truncate.result @@ -39,3 +39,14 @@ TRUNCATE t1; SELECT * FROM t1; a DROP TEMPORARY TABLE t1; +# +# MDEV-23705 Assertion 'table->data_dir_path || !space' +# +CREATE TABLE t(c INT) ENGINE=InnoDB; +ALTER TABLE t DISCARD TABLESPACE; +RENAME TABLE t TO u; +TRUNCATE u; +Warnings: +Warning 1814 Tablespace has been discarded for table `u` +TRUNCATE u; +DROP TABLE u; diff --git a/mysql-test/suite/innodb/t/alter_table.test b/mysql-test/suite/innodb/t/alter_table.test index 26f3a9f013f..ec01d34fdd8 100644 --- a/mysql-test/suite/innodb/t/alter_table.test +++ b/mysql-test/suite/innodb/t/alter_table.test @@ -69,6 +69,17 @@ INSERT INTO t1 SELECT * FROM seq_1_to_128; ALTER TABLE t1 ADD b TINYINT AUTO_INCREMENT PRIMARY KEY, DROP KEY a; DROP TABLE t1; +--echo # +--echo # MDEV-22939 Server crashes in row_make_new_pathname() +--echo # +CREATE TABLE t (a INT) ENGINE=INNODB; +ALTER TABLE t DISCARD TABLESPACE; +--error ER_TABLESPACE_DISCARDED +ALTER TABLE t ENGINE INNODB; +--error ER_TABLESPACE_DISCARDED +ALTER TABLE t FORCE; +DROP TABLE t; + # # Check that innodb supports transactional=1 # diff --git a/mysql-test/suite/innodb/t/foreign-keys.test b/mysql-test/suite/innodb/t/foreign-keys.test index aec6bb54e72..b93f82c93ef 100644 --- a/mysql-test/suite/innodb/t/foreign-keys.test +++ b/mysql-test/suite/innodb/t/foreign-keys.test @@ -249,3 +249,22 @@ show create table t2; drop table t1,t2; --error ER_BAD_TABLE_ERROR drop table t1,t2; + +--echo # +--echo # MDEV-23470 InnoDB: Failing assertion: cmp < 0 in +--echo # row_ins_check_foreign_constraint +--echo # +CREATE TABLE t1(f1 INT NOT NULL PRIMARY KEY, f2 INT NOT NULL)ENGINE=InnoDB; +CREATE TABLE t2(f1 VARCHAR(100), f2 INT NOT NULL, + INDEX(f2))ENGINE=InnoDB; + +INSERT INTO t1 VALUES(99, 2); +ALTER TABLE t2 ADD FOREIGN KEY(f2) REFERENCES t1(f1); + +SET FOREIGN_KEY_CHECKS=0; +DROP INDEX f2 ON t2; +SET FOREIGN_KEY_CHECKS=1; +--error ER_NO_REFERENCED_ROW_2 +INSERT INTO t2 VALUES('G', 3); +DROP TABLE t2, t1; +SET FOREIGN_KEY_CHECKS=DEFAULT; diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test index c595cf92690..c1713cb9742 100644 --- a/mysql-test/suite/innodb/t/foreign_key.test +++ b/mysql-test/suite/innodb/t/foreign_key.test @@ -136,7 +136,6 @@ CREATE TABLE store ( UNIQUE KEY idx_unique_manager (manager_staff_id), CONSTRAINT fk_store_staff FOREIGN KEY (manager_staff_id) REFERENCES staff (staff_id) ON DELETE RESTRICT ON UPDATE CASCADE ) ENGINE=InnoDB; -SET FOREIGN_KEY_CHECKS=DEFAULT; LOCK TABLE staff WRITE; UNLOCK TABLES; @@ -721,6 +720,19 @@ SHOW CREATE TABLE t2; CREATE TABLE t2 (f1 INT NOT NULL)ENGINE=InnoDB; DROP TABLE t2, t1; +--echo # +--echo # MDEV-23685 SIGSEGV on ADD FOREIGN KEY after failed attempt +--echo # to create unique key on virtual column +--echo # +CREATE TABLE t1 (pk INT PRIMARY KEY, a INT, b INT AS (a)) ENGINE=InnODB; + +INSERT INTO t1 (pk,a) VALUES (1,10),(2,10); +--error ER_DUP_ENTRY +ALTER TABLE t1 ADD UNIQUE INDEX ind9 (b), LOCK=SHARED; +SET FOREIGN_KEY_CHECKS= 0; +ALTER TABLE t1 ADD FOREIGN KEY (a) REFERENCES t1 (pk); +DROP TABLE t1; + --echo # End of 10.2 tests # MDEV-21792 Server aborts upon attempt to create foreign key on spatial field diff --git a/mysql-test/suite/innodb/t/innodb-wl5522-debug.test b/mysql-test/suite/innodb/t/innodb-wl5522-debug.test index 30746f5fad8..07c2adeb550 100644 --- a/mysql-test/suite/innodb/t/innodb-wl5522-debug.test +++ b/mysql-test/suite/innodb/t/innodb-wl5522-debug.test @@ -1016,14 +1016,6 @@ EOF DROP TABLE t1; ---disable_query_log -# Enable metrics for the counters we are going to use -set global innodb_monitor_enable = purge_stop_count; -set global innodb_monitor_enable = purge_resume_count; -set global innodb_monitor_enable = ibuf_merges; -set global innodb_monitor_enable = ibuf_merges_insert; ---enable_query_log - # # Create a large table with delete marked records, disable purge during # the update so that we can test the IMPORT purge code. @@ -1042,9 +1034,6 @@ connect (purge_control,localhost,root); START TRANSACTION WITH CONSISTENT SNAPSHOT; connection default; -SET GLOBAL innodb_monitor_reset = ibuf_merges; -SET GLOBAL innodb_monitor_reset = ibuf_merges_insert; - INSERT INTO t1 SELECT 1 + seq, 1 + (seq MOD 4), REPEAT(SUBSTR('abcd', 1 + (seq MOD 4), 1), 2048), @@ -1075,10 +1064,6 @@ SELECT c1, c2 FROM t1; SELECT COUNT(*) FROM t1; SELECT SUM(c2) FROM t1; -SELECT name - FROM information_schema.innodb_metrics - WHERE name = 'ibuf_merges_insert' AND count = 0; - FLUSH TABLES t1 FOR EXPORT; perl; @@ -1088,14 +1073,6 @@ EOF UNLOCK TABLES; -SELECT name - FROM information_schema.innodb_metrics - WHERE name = 'ibuf_merges' AND count > 0; - -SELECT name - FROM information_schema.innodb_metrics - WHERE name = 'ibuf_merges_inserts' AND count > 0; - # Enable normal operation connection purge_control; COMMIT; @@ -1385,21 +1362,9 @@ do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl"; ib_unlink_tablespace("test", "t1"); EOF -set global innodb_monitor_disable = all; -set global innodb_monitor_reset_all = all; - --- disable_warnings -set global innodb_monitor_enable = default; -set global innodb_monitor_disable = default; -set global innodb_monitor_reset = default; -set global innodb_monitor_reset_all = default; --- enable_warnings - --disable_query_log call mtr.add_suppression("InnoDB: The log sequence numbers [0-9]+ and [0-9]+ in ibdata files do not match the log sequence number [0-9]+ in the ib_logfiles!"); call mtr.add_suppression("'Resource temporarily unavailable'"); -call mtr.add_suppression("Monitor ibuf_merges is already enabled"); -call mtr.add_suppression("Monitor ibuf_merges_insert is already enabled"); call mtr.add_suppression("Got error -1 when reading table '.*'"); call mtr.add_suppression("InnoDB: Table '.*' tablespace is set as discarded."); call mtr.add_suppression("InnoDB: Tablespace '.*' exists in the cache.*"); diff --git a/mysql-test/suite/innodb/t/purge_secondary.test b/mysql-test/suite/innodb/t/purge_secondary.test index bf702b6b737..34b4ce06f5f 100644 --- a/mysql-test/suite/innodb/t/purge_secondary.test +++ b/mysql-test/suite/innodb/t/purge_secondary.test @@ -1,4 +1,5 @@ --source include/have_innodb.inc +--source include/have_sequence.inc # Ensure that the history list length will actually be decremented by purge. SET @saved_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; @@ -123,18 +124,10 @@ WHERE NAME='test/t1'; # Work around MDEV-13942, Dropping the spatial index to avoid the possible hang ALTER TABLE t1 DROP INDEX `sidx`; -INSERT INTO t1 () VALUES (),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(); -INSERT INTO t1 (a) SELECT NULL FROM t1; -INSERT INTO t1 (a) SELECT NULL FROM t1; -INSERT INTO t1 (a) SELECT NULL FROM t1; -INSERT INTO t1 (a) SELECT NULL FROM t1; -INSERT INTO t1 (a) SELECT NULL FROM t1; +INSERT INTO t1 (a) SELECT * FROM seq_1_to_544; ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; -SELECT NAME, SUBSYSTEM FROM INFORMATION_SCHEMA.INNODB_METRICS -WHERE NAME="buffer_LRU_batch_flush_total_pages" AND COUNT > 0; - SELECT (variable_value > 0) FROM information_schema.global_status WHERE LOWER(variable_name) LIKE 'INNODB_BUFFER_POOL_PAGES_FLUSHED'; diff --git a/mysql-test/suite/innodb/t/row_format_redundant.test b/mysql-test/suite/innodb/t/row_format_redundant.test index 6f38835d7e9..e8869b886c8 100644 --- a/mysql-test/suite/innodb/t/row_format_redundant.test +++ b/mysql-test/suite/innodb/t/row_format_redundant.test @@ -32,8 +32,7 @@ SET GLOBAL innodb_file_per_table=1; SET GLOBAL innodb_file_per_table=ON; create table t1 (a int not null, d varchar(15) not null, b -varchar(198) not null, c char(156), -fulltext ftsic(c)) engine=InnoDB +varchar(198) not null, c char(156)) engine=InnoDB row_format=redundant; insert into t1 values(123, 'abcdef', 'jghikl', 'mnop'); diff --git a/mysql-test/suite/innodb/t/table_flags.test b/mysql-test/suite/innodb/t/table_flags.test index 238530d25c5..79b2c3dd77a 100644 --- a/mysql-test/suite/innodb/t/table_flags.test +++ b/mysql-test/suite/innodb/t/table_flags.test @@ -16,6 +16,7 @@ call mtr.add_suppression("InnoDB: Operating system error number .* in a file ope call mtr.add_suppression("InnoDB: The error means the system cannot find the path specified"); call mtr.add_suppression("InnoDB: If you are installing InnoDB, remember that you must create directories yourself"); call mtr.add_suppression("InnoDB: adjusting FSP_SPACE_FLAGS of file "); +call mtr.add_suppression("InnoDB: Parent table of FTS auxiliary table .* not found."); FLUSH TABLES; --enable_query_log @@ -237,3 +238,16 @@ call mtr.add_suppression("ERROR HY000: Can't create table `test`.`t1`"); CREATE TABLE t1(f1 INT, f2 VARCHAR(1), KEY k1(f2), FULLTEXT KEY(f2), FOREIGN KEY (f2) REFERENCES t1(f3))ENGINE=InnoDB; + +--echo # +--echo # MDEV-23199 page_compression flag is missing +--echo # for full_crc32 tablespace +--echo # + +CREATE TABLE t1(f1 BIGINT PRIMARY KEY)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1); +ALTER TABLE t1 PAGE_COMPRESSED = 1; +INSERT INTO t1 VALUES(2); +let $shutdown_timeout = 0; +--source include/restart_mysqld.inc +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/truncate.test b/mysql-test/suite/innodb/t/truncate.test index cd1d827e157..ca9ccb677e9 100644 --- a/mysql-test/suite/innodb/t/truncate.test +++ b/mysql-test/suite/innodb/t/truncate.test @@ -50,3 +50,13 @@ INSERT INTO t1 VALUES(1); TRUNCATE t1; SELECT * FROM t1; DROP TEMPORARY TABLE t1; + +--echo # +--echo # MDEV-23705 Assertion 'table->data_dir_path || !space' +--echo # +CREATE TABLE t(c INT) ENGINE=InnoDB; +ALTER TABLE t DISCARD TABLESPACE; +RENAME TABLE t TO u; +TRUNCATE u; +TRUNCATE u; +DROP TABLE u; diff --git a/mysql-test/suite/innodb/t/undo_truncate.test b/mysql-test/suite/innodb/t/undo_truncate.test index b4c8e46150b..d2a4e287305 100644 --- a/mysql-test/suite/innodb/t/undo_truncate.test +++ b/mysql-test/suite/innodb/t/undo_truncate.test @@ -84,7 +84,8 @@ drop PROCEDURE populate_t2; # Truncation will normally not occur with innodb_page_size=64k, # and occasionally not with innodb_page_size=32k, # because the undo log will not grow enough. -if (`select @@innodb_page_size IN (4096,8192,16384)`) +# TODO: For some reason this does not occur on 4k either! +if (`select @@innodb_page_size IN (8192,16384)`) { let $wait_condition = (SELECT variable_value!=@trunc_start FROM information_schema.global_status @@ -109,7 +110,7 @@ EOF if ($size1 == $size2) { # This fails for innodb_page_size=64k, occasionally also for 32k. - if (`select @@innodb_page_size IN (4096,8192,16384)`) + if (`select @@innodb_page_size IN (8192,16384)`) { echo Truncation did not happen: $size1; } diff --git a/mysql-test/suite/mariabackup/innodb_redo_overwrite.opt b/mysql-test/suite/mariabackup/innodb_redo_overwrite.opt new file mode 100644 index 00000000000..19c08c8c945 --- /dev/null +++ b/mysql-test/suite/mariabackup/innodb_redo_overwrite.opt @@ -0,0 +1 @@ +--loose-innodb-log-file-size=2m diff --git a/mysql-test/suite/mariabackup/innodb_redo_overwrite.result b/mysql-test/suite/mariabackup/innodb_redo_overwrite.result new file mode 100644 index 00000000000..9076dbaa57a --- /dev/null +++ b/mysql-test/suite/mariabackup/innodb_redo_overwrite.result @@ -0,0 +1,27 @@ +CREATE TABLE t(i INT) ENGINE=INNODB; +INSERT INTO t VALUES +(0), (1), (2), (3), (4), (5), (6), (7), (8), (9), +(0), (1), (2), (3), (4), (5), (6), (7), (8), (9), +(0), (1), (2), (3), (4), (5), (6), (7), (8), (9), +(0), (1), (2), (3), (4), (5), (6), (7), (8), (9), +(0), (1), (2), (3), (4), (5), (6), (7), (8), (9), +(0), (1), (2), (3), (4), (5), (6), (7), (8), (9), +(0), (1), (2), (3), (4), (5), (6), (7), (8), (9), +(0), (1), (2), (3), (4), (5), (6), (7), (8), (9), +(0), (1), (2), (3), (4), (5), (6), (7), (8), (9), +(0), (1), (2), (3), (4), (5), (6), (7), (8), (9); +# Generate enough data to overwrite innodb redo log +# on the next "INSERT INTO t SELECT * FROM t" execution. +INSERT INTO t SELECT * FROM t; +INSERT INTO t SELECT * FROM t; +INSERT INTO t SELECT * FROM t; +INSERT INTO t SELECT * FROM t; +INSERT INTO t SELECT * FROM t; +INSERT INTO t SELECT * FROM t; +INSERT INTO t SELECT * FROM t; +INSERT INTO t SELECT * FROM t; +INSERT INTO t SELECT * FROM t; +# xtrabackup backup +FOUND 1 /failed: redo log block is overwritten/ in backup.log +FOUND 1 /failed: redo log block checksum does not match/ in backup.log +DROP TABLE t; diff --git a/mysql-test/suite/mariabackup/innodb_redo_overwrite.test b/mysql-test/suite/mariabackup/innodb_redo_overwrite.test new file mode 100644 index 00000000000..e27229c5f33 --- /dev/null +++ b/mysql-test/suite/mariabackup/innodb_redo_overwrite.test @@ -0,0 +1,57 @@ +--source include/have_innodb.inc +--source include/have_debug_sync.inc + +CREATE TABLE t(i INT) ENGINE=INNODB; + +INSERT INTO t VALUES + (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), + (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), + (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), + (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), + (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), + (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), + (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), + (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), + (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), + (0), (1), (2), (3), (4), (5), (6), (7), (8), (9); +--echo # Generate enough data to overwrite innodb redo log +--echo # on the next "INSERT INTO t SELECT * FROM t" execution. +--let $i = 0 +while ($i < 9) { +INSERT INTO t SELECT * FROM t; +--inc $i +} + +--echo # xtrabackup backup +--let $targetdir=$MYSQLTEST_VARDIR/tmp/backup +--let $backuplog=$MYSQLTEST_VARDIR/tmp/backup.log + +--let before_innodb_log_copy_thread_started=INSERT INTO test.t SELECT * FROM test.t + +--disable_result_log +--error 1 +--exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir --dbug=+d,mariabackup_events > $backuplog +--enable_result_log + +--let SEARCH_PATTERN=failed: redo log block is overwritten +--let SEARCH_FILE=$backuplog +--source include/search_pattern_in_file.inc +--remove_file $backuplog +--rmdir $targetdir + +--let before_innodb_log_copy_thread_started=INSERT INTO test.t VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9) + +--disable_result_log +--error 1 +--exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir --dbug=+d,mariabackup_events,log_checksum_mismatch > $backuplog +--enable_result_log + +--let SEARCH_PATTERN=failed: redo log block checksum does not match +--let SEARCH_FILE=$backuplog +--source include/search_pattern_in_file.inc +--remove_file $backuplog +--rmdir $targetdir + +--let before_innodb_log_copy_thread_started= + +DROP TABLE t; diff --git a/mysql-test/suite/mariabackup/rpl_slave_info.result b/mysql-test/suite/mariabackup/rpl_slave_info.result new file mode 100644 index 00000000000..13044fd6c39 --- /dev/null +++ b/mysql-test/suite/mariabackup/rpl_slave_info.result @@ -0,0 +1,37 @@ +include/master-slave.inc +[connection master] +connection slave; +############### +# If Using_Gtid != 'No', backup gtid_slave_pos +######################## +include/stop_slave.inc +change master to master_use_gtid=slave_pos; +include/start_slave.inc +connection master; +CREATE TABLE t(i INT); +connection slave; +"using_gtid: Slave_Pos" +FOUND 1 /gtid_slave_pos/ in xtrabackup_slave_info +NOT FOUND /MASTER_LOG_FILE/ in xtrabackup_slave_info +############### +# If Using_Gtid != 'No' and !gtid_slave_pos, backup master position +######################## +include/stop_slave.inc +SET GLOBAL gtid_slave_pos=""; +NOT FOUND /gtid_slave_pos/ in xtrabackup_slave_info +FOUND 1 /MASTER_LOG_FILE/ in xtrabackup_slave_info +############### +# If Using_Gtid == 'No', backup Exec_Master_Log_Pos +######################## +change master to master_use_gtid=no; +include/start_slave.inc +connection master; +INSERT INTO t VALUES(1); +connection slave; +"using_gtid: No" +NOT FOUND /gtid_slave_pos/ in xtrabackup_slave_info +FOUND 1 /MASTER_LOG_FILE/ in xtrabackup_slave_info +connection master; +DROP TABLE t; +connection slave; +include/rpl_end.inc diff --git a/mysql-test/suite/mariabackup/rpl_slave_info.test b/mysql-test/suite/mariabackup/rpl_slave_info.test new file mode 100644 index 00000000000..ca7682d8af9 --- /dev/null +++ b/mysql-test/suite/mariabackup/rpl_slave_info.test @@ -0,0 +1,84 @@ +--source include/master-slave.inc + +--connection slave + +--echo ############### +--echo # If Using_Gtid != 'No', backup gtid_slave_pos +--echo ######################## + +--source include/stop_slave.inc +change master to master_use_gtid=slave_pos; +--source include/start_slave.inc + +--connection master +CREATE TABLE t(i INT); +--sync_slave_with_master + +--let $using_gtid=query_get_value(SHOW SLAVE STATUS,Using_Gtid,1) +--echo "using_gtid: $using_gtid" + +--let $targetdir=$MYSQLTEST_VARDIR/tmp/backup +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group-suffix=.2 --slave-info --backup --target-dir=$targetdir; +--enable_result_log + +--let SEARCH_FILE=$targetdir/xtrabackup_slave_info +--let SEARCH_PATTERN=gtid_slave_pos +--source include/search_pattern_in_file.inc +--let SEARCH_PATTERN=MASTER_LOG_FILE +--source include/search_pattern_in_file.inc + +rmdir $targetdir; + +--echo ############### +--echo # If Using_Gtid != 'No' and !gtid_slave_pos, backup master position +--echo ######################## + +--source include/stop_slave.inc +SET GLOBAL gtid_slave_pos=""; + +--let $targetdir=$MYSQLTEST_VARDIR/tmp/backup +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group-suffix=.2 --slave-info --backup --target-dir=$targetdir; +--enable_result_log + +--let SEARCH_FILE=$targetdir/xtrabackup_slave_info +--let SEARCH_PATTERN=gtid_slave_pos +--source include/search_pattern_in_file.inc +--let SEARCH_PATTERN=MASTER_LOG_FILE +--source include/search_pattern_in_file.inc + +rmdir $targetdir; + +--echo ############### +--echo # If Using_Gtid == 'No', backup Exec_Master_Log_Pos +--echo ######################## + +change master to master_use_gtid=no; +--source include/start_slave.inc + +--connection master +INSERT INTO t VALUES(1); +--sync_slave_with_master + +--let $using_gtid=query_get_value(SHOW SLAVE STATUS,Using_Gtid,1) +--echo "using_gtid: $using_gtid" + +--let $targetdir=$MYSQLTEST_VARDIR/tmp/backup +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --defaults-group-suffix=.2 --slave-info --backup --target-dir=$targetdir; +--enable_result_log + +--let SEARCH_FILE=$targetdir/xtrabackup_slave_info +--let SEARCH_PATTERN=gtid_slave_pos +--source include/search_pattern_in_file.inc +--let SEARCH_PATTERN=MASTER_LOG_FILE +--source include/search_pattern_in_file.inc + +rmdir $targetdir; + +# Cleanup +--connection master +DROP TABLE t; +--sync_slave_with_master +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_binlog_index.result b/mysql-test/suite/rpl/r/rpl_binlog_index.result index 4257dbde57a..78665ba1a7b 100644 --- a/mysql-test/suite/rpl/r/rpl_binlog_index.result +++ b/mysql-test/suite/rpl/r/rpl_binlog_index.result @@ -7,13 +7,20 @@ CREATE TABLE t1 (a INT); FLUSH BINARY LOGS; INSERT INTO t1 VALUES (1); connection slave; +include/stop_slave.inc connection master; # Shutdown master include/rpl_stop_server.inc [server_number=1] # Move the master binlog files and the index file to a new place # Restart master with log-bin option set to the new path # Master has restarted successfully +connection slave; +include/start_slave.inc +connection master; # Create the master-bin.index file with the old format +connection slave; +include/stop_slave.inc +connection master; # Shutdown master include/rpl_stop_server.inc [server_number=1] # Move back the master binlog files @@ -21,6 +28,9 @@ include/rpl_stop_server.inc [server_number=1] # Restart master with log-bin option set to default # Master has restarted successfully connection slave; +include/start_slave.inc +connection master; +connection slave; # stop slave include/stop_slave.inc include/rpl_stop_server.inc [server_number=2] diff --git a/mysql-test/suite/rpl/r/rpl_filter_tables_dynamic.result b/mysql-test/suite/rpl/r/rpl_filter_tables_dynamic.result index b6c82e3754c..9ef2f4a89db 100644 --- a/mysql-test/suite/rpl/r/rpl_filter_tables_dynamic.result +++ b/mysql-test/suite/rpl/r/rpl_filter_tables_dynamic.result @@ -7,6 +7,8 @@ SET @@GLOBAL.replicate_ignore_table="test.t4,test.t5,test.t6"; ERROR HY000: This operation cannot be performed as you have a running slave ''; run STOP SLAVE '' first connection slave; include/stop_slave.inc +SET @@GLOBAL.replicate_do_table=""; +SET @@GLOBAL.replicate_ignore_table=""; SET @@GLOBAL.replicate_do_table="test.t1,test.t2,test.t3"; SET @@GLOBAL.replicate_ignore_table="test.t4,test.t5,test.t6"; include/start_slave.inc diff --git a/mysql-test/suite/rpl/r/rpl_gtid_crash.result b/mysql-test/suite/rpl/r/rpl_gtid_crash.result index ed2a2b287e9..153081d9ca5 100644 --- a/mysql-test/suite/rpl/r/rpl_gtid_crash.result +++ b/mysql-test/suite/rpl/r/rpl_gtid_crash.result @@ -9,6 +9,9 @@ ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB; INSERT INTO t1 VALUES (1, 0); connection server_2; +SET sql_log_bin=0; +call mtr.add_suppression('Master command COM_REGISTER_SLAVE failed: failed registering on master, reconnecting to try again'); +SET sql_log_bin=1; include/stop_slave.inc CHANGE MASTER TO master_host = '127.0.0.1', master_port = MASTER_PORT, MASTER_USE_GTID=CURRENT_POS; diff --git a/mysql-test/suite/rpl/t/rpl_binlog_index.test b/mysql-test/suite/rpl/t/rpl_binlog_index.test index 8586b1d7489..95c49c3d574 100644 --- a/mysql-test/suite/rpl/t/rpl_binlog_index.test +++ b/mysql-test/suite/rpl/t/rpl_binlog_index.test @@ -43,7 +43,7 @@ FLUSH BINARY LOGS; INSERT INTO t1 VALUES (1); sync_slave_with_master; - +--source include/stop_slave.inc # # Test on master # @@ -58,13 +58,15 @@ source include/rpl_stop_server.inc; --move_file $master_datadir/master-bin.index $tmpdir/master-bin.index --echo # Restart master with log-bin option set to the new path ---let $rpl_server_parameters=--log-bin=$tmpdir/master-bin +--let $rpl_server_parameters=--log-bin=$tmpdir/master-bin --log-bin-index=$tmpdir/master-bin --let $keep_include_silent=1 source include/rpl_start_server.inc; --let $keep_include_silent=0 --echo # Master has restarted successfully - +--connection slave +--source include/start_slave.inc +--connection master # # Test master can handle old format with directory path in index file # @@ -85,7 +87,10 @@ if (!$is_windows) --disable_query_log source include/write_var_to_file.inc; --enable_query_log +--sync_slave_with_master +--source include/stop_slave.inc +--connection master --echo # Shutdown master --let $rpl_server_number=1 source include/rpl_stop_server.inc; @@ -99,14 +104,17 @@ source include/rpl_stop_server.inc; --remove_file $tmpdir/master-bin.index --echo # Restart master with log-bin option set to default ---let $rpl_server_parameters=--log-bin=$master_datadir/master-bin +--let $rpl_server_parameters=--log-bin=$master_datadir/master-bin --log-bin-index=$master_datadir/master-bin --let $keep_include_silent=1 source include/rpl_start_server.inc; --let $keep_include_silent=0 --echo # Master has restarted successfully +--connection slave +--source include/start_slave.inc -connection slave; +--connection master +--sync_slave_with_master --echo # stop slave --source include/stop_slave.inc --let $rpl_server_number= 2 diff --git a/mysql-test/suite/rpl/t/rpl_filter_tables_dynamic.test b/mysql-test/suite/rpl/t/rpl_filter_tables_dynamic.test index d4a4faf8d67..529613b37b1 100644 --- a/mysql-test/suite/rpl/t/rpl_filter_tables_dynamic.test +++ b/mysql-test/suite/rpl/t/rpl_filter_tables_dynamic.test @@ -51,6 +51,8 @@ SET @@GLOBAL.replicate_ignore_table="test.t4,test.t5,test.t6"; connection slave; source include/stop_slave.inc; +SET @@GLOBAL.replicate_do_table=""; +SET @@GLOBAL.replicate_ignore_table=""; SET @@GLOBAL.replicate_do_table="test.t1,test.t2,test.t3"; SET @@GLOBAL.replicate_ignore_table="test.t4,test.t5,test.t6"; source include/start_slave.inc; diff --git a/mysql-test/suite/rpl/t/rpl_gtid_crash.test b/mysql-test/suite/rpl/t/rpl_gtid_crash.test index e72d1c3ef47..d0af69a65ed 100644 --- a/mysql-test/suite/rpl/t/rpl_gtid_crash.test +++ b/mysql-test/suite/rpl/t/rpl_gtid_crash.test @@ -21,6 +21,9 @@ INSERT INTO t1 VALUES (1, 0); --connection server_2 --sync_with_master +SET sql_log_bin=0; +call mtr.add_suppression('Master command COM_REGISTER_SLAVE failed: failed registering on master, reconnecting to try again'); +SET sql_log_bin=1; --source include/stop_slave.inc --replace_result $MASTER_MYPORT MASTER_PORT eval CHANGE MASTER TO master_host = '127.0.0.1', master_port = $MASTER_MYPORT, diff --git a/mysql-test/suite/rpl/t/show_status_stop_slave_race-7126.test b/mysql-test/suite/rpl/t/show_status_stop_slave_race-7126.test index 06a9e8ad75b..12794dbd898 100644 --- a/mysql-test/suite/rpl/t/show_status_stop_slave_race-7126.test +++ b/mysql-test/suite/rpl/t/show_status_stop_slave_race-7126.test @@ -10,7 +10,7 @@ call mtr.add_suppression("Master is configured to log replication events"); # If everything is okay, the test will end in several seconds; maybe a minute. # If the problem shows up, it will hang until testcase timeout is exceeded. ---exec $MYSQL_SLAP --silent --socket=$SLAVE_MYSOCK -q "START SLAVE; STOP SLAVE; SHOW GLOBAL STATUS" -c 2 --number-of-queries=100 --create-schema=test +--exec $MYSQL_SLAP --silent --host=127.0.0.1 -P $SLAVE_MYPORT -q "START SLAVE; STOP SLAVE; SHOW GLOBAL STATUS" -c 2 --number-of-queries=100 --create-schema=test # All done. diff --git a/mysql-test/suite/s3/basic.result b/mysql-test/suite/s3/basic.result index 9cddca79fc5..cf7d7377d92 100644 --- a/mysql-test/suite/s3/basic.result +++ b/mysql-test/suite/s3/basic.result @@ -94,11 +94,13 @@ s3_pagecache_age_threshold X s3_pagecache_buffer_size X s3_pagecache_division_limit X s3_pagecache_file_hash_size X +s3_port X s3_protocol_version X s3_region X s3_replicate_alter_as_create_select X s3_secret_key X s3_slave_ignore_updates X +s3_use_http X show variables like "s3_slave%"; Variable_name Value s3_slave_ignore_updates OFF diff --git a/mysql-test/suite/s3/disabled.def b/mysql-test/suite/s3/disabled.def new file mode 100644 index 00000000000..8eae300e21e --- /dev/null +++ b/mysql-test/suite/s3/disabled.def @@ -0,0 +1,3 @@ +replication_partition : MDEV-23730: Server crashes in ha_maria::extra +replication_mixed : MDEV-23770: Replication failure +replication_stmt : MDEV-23770: Replication failure diff --git a/mysql-test/suite/s3/my.cnf b/mysql-test/suite/s3/my.cnf index 6f8c27d4d0d..a979bf31817 100644 --- a/mysql-test/suite/s3/my.cnf +++ b/mysql-test/suite/s3/my.cnf @@ -2,7 +2,8 @@ !include include/default_client.cnf [mysqld.1] -plugin-load-add=ha_s3 +plugin-maturity = alpha +plugin-load-add=@ENV.HA_S3_SO s3=ON #s3-host-name=s3.amazonaws.com #s3-protocol-version=Amazon @@ -10,3 +11,15 @@ s3=ON #s3-access-key=... #s3-secret-key=... #s3-region=eu-north-1 + +## +## Configuration for local MinIO +## +s3-host-name="127.0.0.1" +# Note: s3-host-name="localhost" doesn't work. It causes +# libmarias3 to use the wrong variant of the protocol. +s3-bucket=storage-engine +s3-access-key=minio +s3-secret-key=minioadmin +s3-port=9000 +s3-use-http=ON diff --git a/mysql-test/suite/s3/no_s3.result b/mysql-test/suite/s3/no_s3.result index 89ab3ea97a1..9333944cf66 100644 --- a/mysql-test/suite/s3/no_s3.result +++ b/mysql-test/suite/s3/no_s3.result @@ -9,5 +9,3 @@ ERROR 42000: Table 's3_unique_table' uses an extension that doesn't exist in thi rename table s3_unique_table to t1; ERROR HY000: Error on rename of './test/s3_unique_table' to './test/t1' (errno: 138 "Unsupported extension used for table") drop table s3_unique_table; -Warnings: -Warning 1112 Table 's3_unique_table' uses an extension that doesn't exist in this MariaDB version diff --git a/mysql-test/suite/s3/partition.test b/mysql-test/suite/s3/partition.test index 03bbc2f0da9..b60eb1bf2dd 100644 --- a/mysql-test/suite/s3/partition.test +++ b/mysql-test/suite/s3/partition.test @@ -1,3 +1,8 @@ +if (`SELECT @@s3_host_name <> "s3.amazonaws.com"`) +{ + skip The test is disabled for emulator environment due to MDEV-23648; +} + --source include/have_partition.inc --source include/have_s3.inc --source create_database.inc diff --git a/mysql-test/suite/s3/partition_move.test b/mysql-test/suite/s3/partition_move.test index 35edbd75b5a..1a5c45ca0b1 100644 --- a/mysql-test/suite/s3/partition_move.test +++ b/mysql-test/suite/s3/partition_move.test @@ -1,3 +1,8 @@ +if (`SELECT @@s3_host_name <> "s3.amazonaws.com"`) +{ + skip The test is disabled for emulator environment due to MDEV-23648; +} + --source include/have_partition.inc --source include/have_innodb.inc --source include/have_s3.inc diff --git a/mysql-test/suite/s3/slave.cnf b/mysql-test/suite/s3/slave.cnf index 250a46e6322..b9b1da73a92 100644 --- a/mysql-test/suite/s3/slave.cnf +++ b/mysql-test/suite/s3/slave.cnf @@ -1,4 +1,6 @@ [mysqld.2] +plugin-maturity = alpha +plugin-load-add=@ENV.HA_S3_SO s3=ON #s3-host-name=s3.amazonaws.com #s3-protocol-version=Amazon @@ -6,3 +8,15 @@ s3=ON #s3-access-key=... #s3-secret-key=... #s3-region=eu-north-1 + +## +## Configuration for local MinIO +## +s3-host-name="127.0.0.1" +# Note: s3-host-name="localhost" doesn't work. It causes +# libmarias3 to use the wrong variant of the protocol. +s3-bucket=storage-engine +s3-access-key=minio +s3-secret-key=minioadmin +s3-port=9000 +s3-use-http=ON diff --git a/mysql-test/suite/sys_vars/r/foreign_key_checks_basic.result b/mysql-test/suite/sys_vars/r/foreign_key_checks_basic.result index 834d693edb8..0bf9d859d40 100644 --- a/mysql-test/suite/sys_vars/r/foreign_key_checks_basic.result +++ b/mysql-test/suite/sys_vars/r/foreign_key_checks_basic.result @@ -7,7 +7,7 @@ SET @@session.foreign_key_checks = 1; SET @@session.foreign_key_checks = DEFAULT; SELECT @@session.foreign_key_checks; @@session.foreign_key_checks -0 +1 '#---------------------FN_DYNVARS_032_02-------------------------#' SET foreign_key_checks = 1; SELECT @@foreign_key_checks; diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index 704f893e32e..7bfa2f626f0 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -2328,7 +2328,7 @@ VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BIGINT VARIABLE_COMMENT Size of the statement digest. Use 0 to disable, -1 for automated sizing. NUMERIC_MIN_VALUE -1 -NUMERIC_MAX_VALUE 200 +NUMERIC_MAX_VALUE 1048576 NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL READ_ONLY YES diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index f2b7f14cc99..8854fab4209 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -2488,7 +2488,7 @@ VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BIGINT VARIABLE_COMMENT Size of the statement digest. Use 0 to disable, -1 for automated sizing. NUMERIC_MIN_VALUE -1 -NUMERIC_MAX_VALUE 200 +NUMERIC_MAX_VALUE 1048576 NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL READ_ONLY YES diff --git a/mysql-test/suite/sys_vars/r/unique_checks_basic.result b/mysql-test/suite/sys_vars/r/unique_checks_basic.result index 60cf2795309..83fb9edb4cd 100644 --- a/mysql-test/suite/sys_vars/r/unique_checks_basic.result +++ b/mysql-test/suite/sys_vars/r/unique_checks_basic.result @@ -7,7 +7,7 @@ SET @@session.unique_checks= 1; SET @@session.unique_checks= DEFAULT; SELECT @@session.unique_checks; @@session.unique_checks -0 +1 '#--------------------FN_DYNVARS_005_04-------------------------#' SET @@session.unique_checks =1; SELECT @@session.unique_checks; diff --git a/mysql-test/suite/vcol/r/vcol_misc.result b/mysql-test/suite/vcol/r/vcol_misc.result index 1df31a4dfab..b7bd63f662e 100644 --- a/mysql-test/suite/vcol/r/vcol_misc.result +++ b/mysql-test/suite/vcol/r/vcol_misc.result @@ -476,8 +476,7 @@ select pk, col_bit+0, vcol_bit+0 from t1; pk col_bit+0 vcol_bit+0 99 10000 1023 REPLACE LOW_PRIORITY INTO `t1` (`pk`) VALUES (99); -Warnings: -Warning 1264 Out of range value for column 'vcol_bit' at row 1 +ERROR 22001: Data too long for column 'vcol_bit' at row 1 drop table t1; # # MDEV-17837 REPLACE on table with virtual_field can cause crash in set_ok_status() @@ -496,8 +495,7 @@ INSERT IGNORE INTO t1 (pk,i) VALUES (1,127); Warnings: Warning 1264 Out of range value for column 'vi' at row 1 REPLACE INTO t1 (pk,i) VALUES (1,2); -Warnings: -Warning 1264 Out of range value for column 'vi' at row 1 +ERROR 22003: Out of range value for column 'vi' at row 1 DROP TABLE t1; SET @sql_mode=@old_sql_mode; # diff --git a/mysql-test/suite/vcol/t/vcol_misc.test b/mysql-test/suite/vcol/t/vcol_misc.test index 1bbd18d6eab..6f770190bb1 100644 --- a/mysql-test/suite/vcol/t/vcol_misc.test +++ b/mysql-test/suite/vcol/t/vcol_misc.test @@ -448,6 +448,7 @@ replace INTO `t1` (`pk`,col_bit) VALUES (99,1000); select pk, col_bit+0, vcol_bit+0 from t1; replace INTO `t1` (`pk`,col_bit) VALUES (99,10000); select pk, col_bit+0, vcol_bit+0 from t1; +--error ER_DATA_TOO_LONG REPLACE LOW_PRIORITY INTO `t1` (`pk`) VALUES (99); drop table t1; @@ -468,6 +469,7 @@ CREATE TABLE t1 ( INSERT INTO t1 (pk,i) VALUES (1,1); TRUNCATE TABLE t1; INSERT IGNORE INTO t1 (pk,i) VALUES (1,127); +--error ER_WARN_DATA_OUT_OF_RANGE REPLACE INTO t1 (pk,i) VALUES (1,2); DROP TABLE t1; SET @sql_mode=@old_sql_mode; diff --git a/mysql-test/suite/versioning/r/sysvars.result b/mysql-test/suite/versioning/r/sysvars.result index ac0a1237902..66513741631 100644 --- a/mysql-test/suite/versioning/r/sysvars.result +++ b/mysql-test/suite/versioning/r/sysvars.result @@ -186,4 +186,13 @@ SELECT @@global.system_versioning_asof; @@global.system_versioning_asof 2002-01-01 00:00:00.000000 SET @@global.system_versioning_asof= DEFAULT; +# +# MDEV-23562 Assertion `time_type == MYSQL_TIMESTAMP_DATETIME' failed upon SELECT from versioned table +# +CREATE TABLE t1 (a INT) WITH SYSTEM VERSIONING; +SET system_versioning_asof= DATE(NOW()); +SELECT * FROM t1; +a +DROP TABLE t1; +SET system_versioning_asof= DEFAULT; # End of 10.4 tests diff --git a/mysql-test/suite/versioning/t/sysvars.test b/mysql-test/suite/versioning/t/sysvars.test index 7c5e818ec81..a1026418e98 100644 --- a/mysql-test/suite/versioning/t/sysvars.test +++ b/mysql-test/suite/versioning/t/sysvars.test @@ -138,4 +138,14 @@ SET @@global.system_versioning_asof= timestamp'2001-12-31 23:59:59.9999999'; SELECT @@global.system_versioning_asof; SET @@global.system_versioning_asof= DEFAULT; +--echo # +--echo # MDEV-23562 Assertion `time_type == MYSQL_TIMESTAMP_DATETIME' failed upon SELECT from versioned table +--echo # + +CREATE TABLE t1 (a INT) WITH SYSTEM VERSIONING; +SET system_versioning_asof= DATE(NOW()); +SELECT * FROM t1; +DROP TABLE t1; +SET system_versioning_asof= DEFAULT; + --echo # End of 10.4 tests diff --git a/mysql-test/suite/wsrep/disabled.def b/mysql-test/suite/wsrep/disabled.def index 0e2027b7153..11577bfe8b0 100644 --- a/mysql-test/suite/wsrep/disabled.def +++ b/mysql-test/suite/wsrep/disabled.def @@ -10,4 +10,3 @@ # ############################################################################## -variables : MDEV-17585,MDEV-20581 Crash on wsrep.variables test case diff --git a/mysql-test/suite/wsrep/r/variables.result b/mysql-test/suite/wsrep/r/variables.result index db5ce3d2a77..1ff221f1459 100644 --- a/mysql-test/suite/wsrep/r/variables.result +++ b/mysql-test/suite/wsrep/r/variables.result @@ -163,7 +163,7 @@ SET GLOBAL wsrep_provider=none; call mtr.add_suppression("WSREP: Failed to get provider options"); SELECT @@global.wsrep_provider; @@global.wsrep_provider -/usr/lib/libgalera_4_smm.so +libgalera_smm.so SELECT @@global.wsrep_slave_threads; @@global.wsrep_slave_threads 1 @@ -182,7 +182,7 @@ wsrep_thread_count 0 SELECT @@global.wsrep_provider; @@global.wsrep_provider -/usr/lib/libgalera_4_smm.so +libgalera_smm.so SELECT @@global.wsrep_cluster_address; @@global.wsrep_cluster_address @@ -212,7 +212,7 @@ EXPECT_2 2 SELECT @@global.wsrep_provider; @@global.wsrep_provider -/usr/lib/libgalera_4_smm.so +libgalera_smm.so SELECT @@global.wsrep_cluster_address; @@global.wsrep_cluster_address gcomm:// @@ -268,7 +268,4 @@ SELECT @@global.wsrep_sst_auth; @@global.wsrep_sst_auth NULL SET @@global.wsrep_sst_auth= @wsrep_sst_auth_saved; -SET GLOBAL wsrep_slave_threads= @wsrep_slave_threads_saved; -SET GLOBAL wsrep_cluster_address= @wsrep_cluster_address_saved; -SET GLOBAL wsrep_provider_options= @wsrep_provider_options_saved; # End of test. diff --git a/mysql-test/suite/wsrep/t/variables.test b/mysql-test/suite/wsrep/t/variables.test index cf5280fa688..89b1ff99012 100644 --- a/mysql-test/suite/wsrep/t/variables.test +++ b/mysql-test/suite/wsrep/t/variables.test @@ -160,12 +160,14 @@ SELECT @@global.wsrep_sst_auth; SET @@global.wsrep_sst_auth= @wsrep_sst_auth_saved; # Reset (for mtr internal checks) + +--disable_query_log SET GLOBAL wsrep_slave_threads= @wsrep_slave_threads_saved; +eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; SET GLOBAL wsrep_cluster_address= @wsrep_cluster_address_saved; SET GLOBAL wsrep_provider_options= @wsrep_provider_options_saved; ---disable_query_log -eval SET GLOBAL wsrep_provider= '$WSREP_PROVIDER'; --enable_query_log ---echo # End of test. +--source include/galera_wait_ready.inc +--echo # End of test. diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 3be4bc1b103..e7fd75b5359 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -16,7 +16,7 @@ INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/mysys) -SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c my_default.c +SET(MYSYS_SOURCES array.c charset-def.c charset.c crc32ieee.cc my_default.c get_password.c errors.c hash.c list.c mf_cache.c mf_dirname.c mf_fn_ext.c @@ -45,7 +45,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c my_default.c my_uuid.c wqueue.c waiting_threads.c ma_dyncol.c ../sql-common/my_time.c my_rdtsc.c psi_noop.c my_atomic_writes.c my_cpu.c my_likely.c my_largepage.c - file_logger.c my_dlerror.c) + file_logger.c my_dlerror.c crc32/crc32c.cc) IF (WIN32) SET (MYSYS_SOURCES ${MYSYS_SOURCES} @@ -58,20 +58,24 @@ IF (WIN32) my_win_popen.cc) ENDIF() -IF(NOT MSVC AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64") - #Check for PCLMUL instruction (x86) - CHECK_C_SOURCE_COMPILES(" - int main() - { - asm volatile (\"pclmulqdq \\$0x00, %%xmm1, %%xmm0\":::\"cc\"); - return 0; - }" HAVE_CLMUL_INSTRUCTION) - - IF(HAVE_CLMUL_INSTRUCTION) +IF(MSVC) + SET(MYSYS_SOURCES ${MYSYS_SOURCES} crc32/crc32_x86.c) + ADD_DEFINITIONS(-DHAVE_SSE42 -DHAVE_PCLMUL) + IF(CLANG_CL) + SET_SOURCE_FILES_PROPERTIES(crc32/crc32_x86.cc crc32/crc32c.c PROPERTIES COMPILE_FLAGS "-msse4.2 -mpclmul") + ENDIF() +ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|i386|i686") + MY_CHECK_C_COMPILER_FLAG(-msse4.2) + MY_CHECK_C_COMPILER_FLAG(-mpclmul) + CHECK_INCLUDE_FILE(cpuid.h HAVE_CPUID_H) + CHECK_INCLUDE_FILE(x86intrin.h HAVE_X86INTRIN_H) + IF(have_C__msse4.2 AND have_C__mpclmul AND HAVE_CPUID_H AND HAVE_X86INTRIN_H) SET(MYSYS_SOURCES ${MYSYS_SOURCES} crc32/crc32_x86.c) + SET_SOURCE_FILES_PROPERTIES(crc32/crc32_x86.c crc32/crc32c.cc PROPERTIES COMPILE_FLAGS "-msse4.2 -mpclmul") + ADD_DEFINITIONS(-DHAVE_SSE42 -DHAVE_PCLMUL) ENDIF() ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64") - IF(CMAKE_COMPILER_IS_GNUCC AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1) + IF(CMAKE_COMPILER_IS_GNUCC) include(CheckCXXSourceCompiles) CHECK_CXX_SOURCE_COMPILES(" @@ -93,23 +97,29 @@ ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64") #include <sys/auxv.h> int main() { foo(0); getauxval(AT_HWCAP); }" HAVE_ARMV8_CRYPTO) - CHECK_C_COMPILER_FLAG(-march=armv8-a+crc+crypto HAVE_ARMV8_CRC_CRYPTO_INTRINSICS) - IF(HAVE_ARMV8_CRC_CRYPTO_INTRINSICS) + CHECK_C_COMPILER_FLAG(-march=armv8-a+crc+crypto HAVE_ARMV8_CRC_CRYPTO_MARCH) + + IF(HAVE_ARMV8_CRC_CRYPTO_MARCH) + CHECK_INCLUDE_FILE(arm_acle.h HAVE_ARM_ACLE_H -march=armv8-a+crc+crypto) + IF(HAVE_ARM_ACLE_H) + ADD_DEFINITIONS(-DHAVE_ARMV8_CRC_CRYPTO_INTRINSICS) + ENDIF() + IF(HAVE_ARMV8_CRC) + ADD_DEFINITIONS(-DHAVE_ARMV8_CRC) + ENDIF() + IF(HAVE_ARMV8_CRYPTO) + ADD_DEFINITIONS(-DHAVE_ARMV8_CRYPTO) + ENDIF() SET(MYSYS_SOURCES ${MYSYS_SOURCES} crc32/crc32_arm64.c) SET_SOURCE_FILES_PROPERTIES(crc32/crc32_arm64.c PROPERTIES COMPILE_FLAGS "-march=armv8-a+crc+crypto") ENDIF() ENDIF() ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64") - SET(HAVE_CRC32_VPMSUM 1 PARENT_SCOPE) - SET(MYSYS_SOURCES ${MYSYS_SOURCES} $<TARGET_OBJECTS:crc32c> $<TARGET_OBJECTS:crc32ieee>) - - ADD_LIBRARY(crc32c OBJECT crc32/crc32_ppc64.c) - ADD_LIBRARY(crc32ieee OBJECT crc32/crc32_ppc64.c) - - SET_TARGET_PROPERTIES(crc32c crc32ieee PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -maltivec -mvsx -mpower8-vector -mcrypto -mpower8-vector") - SET_TARGET_PROPERTIES(crc32ieee PROPERTIES COMPILE_DEFINITIONS "CRC32_FUNCTION=my_checksum;CRC32_CONSTANTS_HEADER=\"pcc_crc32_constants.h\"") - SET_TARGET_PROPERTIES(crc32c PROPERTIES COMPILE_DEFINITIONS "CRC32_FUNCTION=crc32c_vpmsum;CRC32_CONSTANTS_HEADER=\"pcc_crc32c_constants.h\"") + SET(MYSYS_SOURCES ${MYSYS_SOURCES} crc32/crc32_ppc64.c crc32/crc32c_ppc.c) + SET_SOURCE_FILES_PROPERTIES(crc32/crc32_ppc64.c crc32/crc32c_ppc.c PROPERTIES + COMPILE_FLAGS "${COMPILE_FLAGS} -maltivec -mvsx -mpower8-vector -mcrypto -mpower8-vector") + ADD_DEFINITIONS(-DHAVE_POWER8 -DHAS_ALTIVEC) ENDIF() IF(UNIX) diff --git a/mysys/crc32/crc32_arm64.c b/mysys/crc32/crc32_arm64.c index a7eb2a47442..b82d4701e6f 100644 --- a/mysys/crc32/crc32_arm64.c +++ b/mysys/crc32/crc32_arm64.c @@ -57,6 +57,12 @@ asm(".arch_extension crypto"); #define CRC32CH(crc, value) __asm__("crc32ch %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) #define CRC32CB(crc, value) __asm__("crc32cb %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) +#define CRC32X(crc, value) __asm__("crc32x %w[c], %w[c], %x[v]":[c]"+r"(crc):[v]"r"(value)) +#define CRC32W(crc, value) __asm__("crc32w %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) +#define CRC32H(crc, value) __asm__("crc32h %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) +#define CRC32B(crc, value) __asm__("crc32b %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value)) + + #define CRC32C3X8(buffer, ITR) \ __asm__("crc32cx %w[c1], %w[c1], %x[v]":[c1]"+r"(crc1):[v]"r"(*((const uint64_t *)buffer + 42*1 + (ITR))));\ __asm__("crc32cx %w[c2], %w[c2], %x[v]":[c2]"+r"(crc2):[v]"r"(*((const uint64_t *)buffer + 42*2 + (ITR))));\ @@ -73,6 +79,11 @@ asm(".arch_extension crypto"); #define CRC32CH(crc, value) (crc) = __crc32ch((crc), (value)) #define CRC32CB(crc, value) (crc) = __crc32cb((crc), (value)) +#define CRC32X(crc, value) (crc) = __crc32d((crc), (value)) +#define CRC32W(crc, value) (crc) = __crc32w((crc), (value)) +#define CRC32H(crc, value) (crc) = __crc32h((crc), (value)) +#define CRC32B(crc, value) (crc) = __crc32b((crc), (value)) + #define CRC32C3X8(buffer, ITR) \ crc1 = __crc32cd(crc1, *((const uint64_t *)buffer + 42*1 + (ITR)));\ crc2 = __crc32cd(crc2, *((const uint64_t *)buffer + 42*2 + (ITR)));\ @@ -119,7 +130,7 @@ uint32_t crc32c_aarch64(uint32_t crc, const unsigned char *buffer, uint64_t len) uint32_t crc0, crc1, crc2; int64_t length= (int64_t)len; - crc= 0xFFFFFFFFU; + crc^= 0xffffffff; /* Pmull runtime check here. * Raspberry Pi 4 supports crc32 but doesn't support pmull (MDEV-23030). @@ -282,16 +293,16 @@ unsigned int crc32_aarch64(unsigned int crc, const void *buf, size_t len) /* if start pointer is not 8 bytes aligned */ while ((buf1 != (const uint8_t *) buf8) && len) { - crc= __crc32b(crc, *buf1++); + CRC32B(crc, *buf1++); len--; } for (; len >= 8; len-= 8) - crc= __crc32d(crc, *buf8++); + CRC32X(crc, *buf8++); buf1= (const uint8_t *) buf8; while (len--) - crc= __crc32b(crc, *buf1++); + CRC32B(crc, *buf1++); return ~crc; } diff --git a/mysys/crc32/crc32_ppc64.c b/mysys/crc32/crc32_ppc64.c index 2e8b9fc1b12..76df88ee231 100644 --- a/mysys/crc32/crc32_ppc64.c +++ b/mysys/crc32/crc32_ppc64.c @@ -1,675 +1,5 @@ -/* - * Calculate the checksum of data that is 16 byte aligned and a multiple of - * 16 bytes. - * - * The first step is to reduce it to 1024 bits. We do this in 8 parallel - * chunks in order to mask the latency of the vpmsum instructions. If we - * have more than 32 kB of data to checksum we repeat this step multiple - * times, passing in the previous 1024 bits. - * - * The next step is to reduce the 1024 bits to 64 bits. This step adds - * 32 bits of 0s to the end - this matches what a CRC does. We just - * calculate constants that land the data in this 32 bits. - * - * We then use fixed point Barrett reduction to compute a mod n over GF(2) - * for n = CRC using POWER8 instructions. We use x = 32. - * - * http://en.wikipedia.org/wiki/Barrett_reduction - * - * This code uses gcc vector builtins instead using assembly directly. - * - * Copyright (C) 2017 Rogerio Alves <rogealve@br.ibm.com>, IBM - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of either: - * - * a) the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) - * any later version, or - * b) the Apache License, Version 2.0 - */ - -#include <altivec.h> - -#define POWER8_INTRINSICS +#define CRC32_FUNCTION my_checksum #define CRC_TABLE - -#ifdef CRC32_CONSTANTS_HEADER -#include CRC32_CONSTANTS_HEADER -#else -#include "crc32_constants.h" -#endif - -#define VMX_ALIGN 16 -#define VMX_ALIGN_MASK (VMX_ALIGN-1) - -#ifdef REFLECT -static unsigned int crc32_align(unsigned int crc, const unsigned char *p, - unsigned long len) -{ - while (len--) - crc = crc_table[(crc ^ *p++) & 0xff] ^ (crc >> 8); - return crc; -} -#else -static unsigned int crc32_align(unsigned int crc, const unsigned char *p, - unsigned long len) -{ - while (len--) - crc = crc_table[((crc >> 24) ^ *p++) & 0xff] ^ (crc << 8); - return crc; -} -#endif - -static unsigned int __attribute__ ((aligned (32))) -__crc32_vpmsum(unsigned int crc, const void* p, unsigned long len); - -#ifndef CRC32_FUNCTION -#define CRC32_FUNCTION crc32_vpmsum -#endif - -unsigned int CRC32_FUNCTION(unsigned int crc, const unsigned char *p, - unsigned long len) -{ - unsigned int prealign; - unsigned int tail; - -#ifdef CRC_XOR - crc ^= 0xffffffff; -#endif - - if (len < VMX_ALIGN + VMX_ALIGN_MASK) { - crc = crc32_align(crc, p, len); - goto out; - } - - if ((unsigned long)p & VMX_ALIGN_MASK) { - prealign = VMX_ALIGN - ((unsigned long)p & VMX_ALIGN_MASK); - crc = crc32_align(crc, p, prealign); - len -= prealign; - p += prealign; - } - - crc = __crc32_vpmsum(crc, p, len & ~VMX_ALIGN_MASK); - - tail = len & VMX_ALIGN_MASK; - if (tail) { - p += len & ~VMX_ALIGN_MASK; - crc = crc32_align(crc, p, tail); - } - -out: -#ifdef CRC_XOR - crc ^= 0xffffffff; -#endif - - return crc; -} - -#if defined (__clang__) -#include "clang_workaround.h" -#else -#define __builtin_pack_vector(a, b) __builtin_pack_vector_int128 ((a), (b)) -#define __builtin_unpack_vector_0(a) __builtin_unpack_vector_int128 ((vector __int128_t)(a), 0) -#define __builtin_unpack_vector_1(a) __builtin_unpack_vector_int128 ((vector __int128_t)(a), 1) -#endif - -/* When we have a load-store in a single-dispatch group and address overlap - * such that foward is not allowed (load-hit-store) the group must be flushed. - * A group ending NOP prevents the flush. - */ -#define GROUP_ENDING_NOP asm("ori 2,2,0" ::: "memory") - -#if defined(__BIG_ENDIAN__) && defined (REFLECT) -#define BYTESWAP_DATA -#elif defined(__LITTLE_ENDIAN__) && !defined(REFLECT) -#define BYTESWAP_DATA -#endif - -#ifdef BYTESWAP_DATA -#define VEC_PERM(vr, va, vb, vc) vr = vec_perm(va, vb,\ - (__vector unsigned char) vc) -#if defined(__LITTLE_ENDIAN__) -/* Byte reverse permute constant LE. */ -static const __vector unsigned long long vperm_const - __attribute__ ((aligned(16))) = { 0x08090A0B0C0D0E0FUL, - 0x0001020304050607UL }; -#else -static const __vector unsigned long long vperm_const - __attribute__ ((aligned(16))) = { 0x0F0E0D0C0B0A0908UL, - 0X0706050403020100UL }; -#endif -#else -#define VEC_PERM(vr, va, vb, vc) -#endif - -static unsigned int __attribute__ ((aligned (32))) -__crc32_vpmsum(unsigned int crc, const void* p, unsigned long len) { - - const __vector unsigned long long vzero = {0,0}; - const __vector unsigned long long vones = {0xffffffffffffffffUL, - 0xffffffffffffffffUL}; - -#ifdef REFLECT - __vector unsigned char vsht_splat; - const __vector unsigned long long vmask_32bit = - (__vector unsigned long long)vec_sld((__vector unsigned char)vzero, - (__vector unsigned char)vones, 4); -#endif - - const __vector unsigned long long vmask_64bit = - (__vector unsigned long long)vec_sld((__vector unsigned char)vzero, - (__vector unsigned char)vones, 8); - - __vector unsigned long long vcrc; - - __vector unsigned long long vconst1, vconst2; - - /* vdata0-vdata7 will contain our data (p). */ - __vector unsigned long long vdata0, vdata1, vdata2, vdata3, vdata4, - vdata5, vdata6, vdata7; - - /* v0-v7 will contain our checksums */ - __vector unsigned long long v0 = {0,0}; - __vector unsigned long long v1 = {0,0}; - __vector unsigned long long v2 = {0,0}; - __vector unsigned long long v3 = {0,0}; - __vector unsigned long long v4 = {0,0}; - __vector unsigned long long v5 = {0,0}; - __vector unsigned long long v6 = {0,0}; - __vector unsigned long long v7 = {0,0}; - - - /* Vector auxiliary variables. */ - __vector unsigned long long va0, va1, va2, va3, va4, va5, va6, va7; - - unsigned int result = 0; - unsigned int offset; /* Constant table offset. */ - - unsigned long i; /* Counter. */ - unsigned long chunks; - - unsigned long block_size; - int next_block = 0; - - /* Align by 128 bits. The last 128 bit block will be processed at end. */ - unsigned long length = len & 0xFFFFFFFFFFFFFF80UL; - -#ifdef REFLECT - vcrc = (__vector unsigned long long)__builtin_pack_vector(0UL, crc); -#else - vcrc = (__vector unsigned long long)__builtin_pack_vector(crc, 0UL); - - /* Shift into top 32 bits */ - vcrc = (__vector unsigned long long)vec_sld((__vector unsigned char)vcrc, - (__vector unsigned char)vzero, 4); -#endif - - /* Short version. */ - if (len < 256) { - /* Calculate where in the constant table we need to start. */ - offset = 256 - len; - - vconst1 = vec_ld(offset, vcrc_short_const); - vdata0 = vec_ld(0, (__vector unsigned long long*) p); - VEC_PERM(vdata0, vdata0, vconst1, vperm_const); - - /* xor initial value*/ - vdata0 = vec_xor(vdata0, vcrc); - - vdata0 = (__vector unsigned long long) __builtin_crypto_vpmsumw - ((__vector unsigned int)vdata0, (__vector unsigned int)vconst1); - v0 = vec_xor(v0, vdata0); - - for (i = 16; i < len; i += 16) { - vconst1 = vec_ld(offset + i, vcrc_short_const); - vdata0 = vec_ld(i, (__vector unsigned long long*) p); - VEC_PERM(vdata0, vdata0, vconst1, vperm_const); - vdata0 = (__vector unsigned long long) __builtin_crypto_vpmsumw - ((__vector unsigned int)vdata0, (__vector unsigned int)vconst1); - v0 = vec_xor(v0, vdata0); - } - } else { - - /* Load initial values. */ - vdata0 = vec_ld(0, (__vector unsigned long long*) p); - vdata1 = vec_ld(16, (__vector unsigned long long*) p); - - VEC_PERM(vdata0, vdata0, vdata0, vperm_const); - VEC_PERM(vdata1, vdata1, vdata1, vperm_const); - - vdata2 = vec_ld(32, (__vector unsigned long long*) p); - vdata3 = vec_ld(48, (__vector unsigned long long*) p); - - VEC_PERM(vdata2, vdata2, vdata2, vperm_const); - VEC_PERM(vdata3, vdata3, vdata3, vperm_const); - - vdata4 = vec_ld(64, (__vector unsigned long long*) p); - vdata5 = vec_ld(80, (__vector unsigned long long*) p); - - VEC_PERM(vdata4, vdata4, vdata4, vperm_const); - VEC_PERM(vdata5, vdata5, vdata5, vperm_const); - - vdata6 = vec_ld(96, (__vector unsigned long long*) p); - vdata7 = vec_ld(112, (__vector unsigned long long*) p); - - VEC_PERM(vdata6, vdata6, vdata6, vperm_const); - VEC_PERM(vdata7, vdata7, vdata7, vperm_const); - - /* xor in initial value */ - vdata0 = vec_xor(vdata0, vcrc); - - p = (char *)p + 128; - - do { - /* Checksum in blocks of MAX_SIZE. */ - block_size = length; - if (block_size > MAX_SIZE) { - block_size = MAX_SIZE; - } - - length = length - block_size; - - /* - * Work out the offset into the constants table to start at. Each - * constant is 16 bytes, and it is used against 128 bytes of input - * data - 128 / 16 = 8 - */ - offset = (MAX_SIZE/8) - (block_size/8); - /* We reduce our final 128 bytes in a separate step */ - chunks = (block_size/128)-1; - - vconst1 = vec_ld(offset, vcrc_const); - - va0 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata0, - (__vector unsigned long long)vconst1); - va1 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata1, - (__vector unsigned long long)vconst1); - va2 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata2, - (__vector unsigned long long)vconst1); - va3 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata3, - (__vector unsigned long long)vconst1); - va4 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata4, - (__vector unsigned long long)vconst1); - va5 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata5, - (__vector unsigned long long)vconst1); - va6 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata6, - (__vector unsigned long long)vconst1); - va7 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata7, - (__vector unsigned long long)vconst1); - - if (chunks > 1) { - offset += 16; - vconst2 = vec_ld(offset, vcrc_const); - GROUP_ENDING_NOP; - - vdata0 = vec_ld(0, (__vector unsigned long long*) p); - VEC_PERM(vdata0, vdata0, vdata0, vperm_const); - - vdata1 = vec_ld(16, (__vector unsigned long long*) p); - VEC_PERM(vdata1, vdata1, vdata1, vperm_const); - - vdata2 = vec_ld(32, (__vector unsigned long long*) p); - VEC_PERM(vdata2, vdata2, vdata2, vperm_const); - - vdata3 = vec_ld(48, (__vector unsigned long long*) p); - VEC_PERM(vdata3, vdata3, vdata3, vperm_const); - - vdata4 = vec_ld(64, (__vector unsigned long long*) p); - VEC_PERM(vdata4, vdata4, vdata4, vperm_const); - - vdata5 = vec_ld(80, (__vector unsigned long long*) p); - VEC_PERM(vdata5, vdata5, vdata5, vperm_const); - - vdata6 = vec_ld(96, (__vector unsigned long long*) p); - VEC_PERM(vdata6, vdata6, vdata6, vperm_const); - - vdata7 = vec_ld(112, (__vector unsigned long long*) p); - VEC_PERM(vdata7, vdata7, vdata7, vperm_const); - - p = (char *)p + 128; - - /* - * main loop. We modulo schedule it such that it takes three - * iterations to complete - first iteration load, second - * iteration vpmsum, third iteration xor. - */ - for (i = 0; i < chunks-2; i++) { - vconst1 = vec_ld(offset, vcrc_const); - offset += 16; - GROUP_ENDING_NOP; - - v0 = vec_xor(v0, va0); - va0 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata0, (__vector unsigned long long)vconst2); - vdata0 = vec_ld(0, (__vector unsigned long long*) p); - VEC_PERM(vdata0, vdata0, vdata0, vperm_const); - GROUP_ENDING_NOP; - - v1 = vec_xor(v1, va1); - va1 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata1, (__vector unsigned long long)vconst2); - vdata1 = vec_ld(16, (__vector unsigned long long*) p); - VEC_PERM(vdata1, vdata1, vdata1, vperm_const); - GROUP_ENDING_NOP; - - v2 = vec_xor(v2, va2); - va2 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata2, (__vector unsigned long long)vconst2); - vdata2 = vec_ld(32, (__vector unsigned long long*) p); - VEC_PERM(vdata2, vdata2, vdata2, vperm_const); - GROUP_ENDING_NOP; - - v3 = vec_xor(v3, va3); - va3 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata3, (__vector unsigned long long)vconst2); - vdata3 = vec_ld(48, (__vector unsigned long long*) p); - VEC_PERM(vdata3, vdata3, vdata3, vperm_const); - - vconst2 = vec_ld(offset, vcrc_const); - GROUP_ENDING_NOP; - - v4 = vec_xor(v4, va4); - va4 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata4, (__vector unsigned long long)vconst1); - vdata4 = vec_ld(64, (__vector unsigned long long*) p); - VEC_PERM(vdata4, vdata4, vdata4, vperm_const); - GROUP_ENDING_NOP; - - v5 = vec_xor(v5, va5); - va5 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata5, (__vector unsigned long long)vconst1); - vdata5 = vec_ld(80, (__vector unsigned long long*) p); - VEC_PERM(vdata5, vdata5, vdata5, vperm_const); - GROUP_ENDING_NOP; - - v6 = vec_xor(v6, va6); - va6 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata6, (__vector unsigned long long)vconst1); - vdata6 = vec_ld(96, (__vector unsigned long long*) p); - VEC_PERM(vdata6, vdata6, vdata6, vperm_const); - GROUP_ENDING_NOP; - - v7 = vec_xor(v7, va7); - va7 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata7, (__vector unsigned long long)vconst1); - vdata7 = vec_ld(112, (__vector unsigned long long*) p); - VEC_PERM(vdata7, vdata7, vdata7, vperm_const); - - p = (char *)p + 128; - } - - /* First cool down*/ - vconst1 = vec_ld(offset, vcrc_const); - offset += 16; - - v0 = vec_xor(v0, va0); - va0 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata0, (__vector unsigned long long)vconst1); - GROUP_ENDING_NOP; - - v1 = vec_xor(v1, va1); - va1 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata1, (__vector unsigned long long)vconst1); - GROUP_ENDING_NOP; - - v2 = vec_xor(v2, va2); - va2 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata2, (__vector unsigned long long)vconst1); - GROUP_ENDING_NOP; - - v3 = vec_xor(v3, va3); - va3 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata3, (__vector unsigned long long)vconst1); - GROUP_ENDING_NOP; - - v4 = vec_xor(v4, va4); - va4 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata4, (__vector unsigned long long)vconst1); - GROUP_ENDING_NOP; - - v5 = vec_xor(v5, va5); - va5 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata5, (__vector unsigned long long)vconst1); - GROUP_ENDING_NOP; - - v6 = vec_xor(v6, va6); - va6 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata6, (__vector unsigned long long)vconst1); - GROUP_ENDING_NOP; - - v7 = vec_xor(v7, va7); - va7 = __builtin_crypto_vpmsumd ((__vector unsigned long - long)vdata7, (__vector unsigned long long)vconst1); - }/* else */ - - /* Second cool down. */ - v0 = vec_xor(v0, va0); - v1 = vec_xor(v1, va1); - v2 = vec_xor(v2, va2); - v3 = vec_xor(v3, va3); - v4 = vec_xor(v4, va4); - v5 = vec_xor(v5, va5); - v6 = vec_xor(v6, va6); - v7 = vec_xor(v7, va7); - -#ifdef REFLECT - /* - * vpmsumd produces a 96 bit result in the least significant bits - * of the register. Since we are bit reflected we have to shift it - * left 32 bits so it occupies the least significant bits in the - * bit reflected domain. - */ - v0 = (__vector unsigned long long)vec_sld((__vector unsigned char)v0, - (__vector unsigned char)vzero, 4); - v1 = (__vector unsigned long long)vec_sld((__vector unsigned char)v1, - (__vector unsigned char)vzero, 4); - v2 = (__vector unsigned long long)vec_sld((__vector unsigned char)v2, - (__vector unsigned char)vzero, 4); - v3 = (__vector unsigned long long)vec_sld((__vector unsigned char)v3, - (__vector unsigned char)vzero, 4); - v4 = (__vector unsigned long long)vec_sld((__vector unsigned char)v4, - (__vector unsigned char)vzero, 4); - v5 = (__vector unsigned long long)vec_sld((__vector unsigned char)v5, - (__vector unsigned char)vzero, 4); - v6 = (__vector unsigned long long)vec_sld((__vector unsigned char)v6, - (__vector unsigned char)vzero, 4); - v7 = (__vector unsigned long long)vec_sld((__vector unsigned char)v7, - (__vector unsigned char)vzero, 4); -#endif - - /* xor with the last 1024 bits. */ - va0 = vec_ld(0, (__vector unsigned long long*) p); - VEC_PERM(va0, va0, va0, vperm_const); - - va1 = vec_ld(16, (__vector unsigned long long*) p); - VEC_PERM(va1, va1, va1, vperm_const); - - va2 = vec_ld(32, (__vector unsigned long long*) p); - VEC_PERM(va2, va2, va2, vperm_const); - - va3 = vec_ld(48, (__vector unsigned long long*) p); - VEC_PERM(va3, va3, va3, vperm_const); - - va4 = vec_ld(64, (__vector unsigned long long*) p); - VEC_PERM(va4, va4, va4, vperm_const); - - va5 = vec_ld(80, (__vector unsigned long long*) p); - VEC_PERM(va5, va5, va5, vperm_const); - - va6 = vec_ld(96, (__vector unsigned long long*) p); - VEC_PERM(va6, va6, va6, vperm_const); - - va7 = vec_ld(112, (__vector unsigned long long*) p); - VEC_PERM(va7, va7, va7, vperm_const); - - p = (char *)p + 128; - - vdata0 = vec_xor(v0, va0); - vdata1 = vec_xor(v1, va1); - vdata2 = vec_xor(v2, va2); - vdata3 = vec_xor(v3, va3); - vdata4 = vec_xor(v4, va4); - vdata5 = vec_xor(v5, va5); - vdata6 = vec_xor(v6, va6); - vdata7 = vec_xor(v7, va7); - - /* Check if we have more blocks to process */ - next_block = 0; - if (length != 0) { - next_block = 1; - - /* zero v0-v7 */ - v0 = vec_xor(v0, v0); - v1 = vec_xor(v1, v1); - v2 = vec_xor(v2, v2); - v3 = vec_xor(v3, v3); - v4 = vec_xor(v4, v4); - v5 = vec_xor(v5, v5); - v6 = vec_xor(v6, v6); - v7 = vec_xor(v7, v7); - } - length = length + 128; - - } while (next_block); - - /* Calculate how many bytes we have left. */ - length = (len & 127); - - /* Calculate where in (short) constant table we need to start. */ - offset = 128 - length; - - v0 = vec_ld(offset, vcrc_short_const); - v1 = vec_ld(offset + 16, vcrc_short_const); - v2 = vec_ld(offset + 32, vcrc_short_const); - v3 = vec_ld(offset + 48, vcrc_short_const); - v4 = vec_ld(offset + 64, vcrc_short_const); - v5 = vec_ld(offset + 80, vcrc_short_const); - v6 = vec_ld(offset + 96, vcrc_short_const); - v7 = vec_ld(offset + 112, vcrc_short_const); - - offset += 128; - - v0 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( - (__vector unsigned int)vdata0,(__vector unsigned int)v0); - v1 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( - (__vector unsigned int)vdata1,(__vector unsigned int)v1); - v2 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( - (__vector unsigned int)vdata2,(__vector unsigned int)v2); - v3 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( - (__vector unsigned int)vdata3,(__vector unsigned int)v3); - v4 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( - (__vector unsigned int)vdata4,(__vector unsigned int)v4); - v5 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( - (__vector unsigned int)vdata5,(__vector unsigned int)v5); - v6 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( - (__vector unsigned int)vdata6,(__vector unsigned int)v6); - v7 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( - (__vector unsigned int)vdata7,(__vector unsigned int)v7); - - /* Now reduce the tail (0-112 bytes). */ - for (i = 0; i < length; i+=16) { - vdata0 = vec_ld(i,(__vector unsigned long long*)p); - VEC_PERM(vdata0, vdata0, vdata0, vperm_const); - va0 = vec_ld(offset + i,vcrc_short_const); - va0 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( - (__vector unsigned int)vdata0,(__vector unsigned int)va0); - v0 = vec_xor(v0, va0); - } - - /* xor all parallel chunks together. */ - v0 = vec_xor(v0, v1); - v2 = vec_xor(v2, v3); - v4 = vec_xor(v4, v5); - v6 = vec_xor(v6, v7); - - v0 = vec_xor(v0, v2); - v4 = vec_xor(v4, v6); - - v0 = vec_xor(v0, v4); - } - - /* Barrett Reduction */ - vconst1 = vec_ld(0, v_Barrett_const); - vconst2 = vec_ld(16, v_Barrett_const); - - v1 = (__vector unsigned long long)vec_sld((__vector unsigned char)v0, - (__vector unsigned char)v0, 8); - v0 = vec_xor(v1,v0); - -#ifdef REFLECT - /* shift left one bit */ - vsht_splat = vec_splat_u8 (1); - v0 = (__vector unsigned long long)vec_sll ((__vector unsigned char)v0, - vsht_splat); -#endif - - v0 = vec_and(v0, vmask_64bit); - -#ifndef REFLECT - - /* - * Now for the actual algorithm. The idea is to calculate q, - * the multiple of our polynomial that we need to subtract. By - * doing the computation 2x bits higher (ie 64 bits) and shifting the - * result back down 2x bits, we round down to the nearest multiple. - */ - - /* ma */ - v1 = __builtin_crypto_vpmsumd ((__vector unsigned long long)v0, - (__vector unsigned long long)vconst1); - /* q = floor(ma/(2^64)) */ - v1 = (__vector unsigned long long)vec_sld ((__vector unsigned char)vzero, - (__vector unsigned char)v1, 8); - /* qn */ - v1 = __builtin_crypto_vpmsumd ((__vector unsigned long long)v1, - (__vector unsigned long long)vconst2); - /* a - qn, subtraction is xor in GF(2) */ - v0 = vec_xor (v0, v1); - /* - * Get the result into r3. We need to shift it left 8 bytes: - * V0 [ 0 1 2 X ] - * V0 [ 0 X 2 3 ] - */ - result = __builtin_unpack_vector_1 (v0); -#else - - /* - * The reflected version of Barrett reduction. Instead of bit - * reflecting our data (which is expensive to do), we bit reflect our - * constants and our algorithm, which means the intermediate data in - * our vector registers goes from 0-63 instead of 63-0. We can reflect - * the algorithm because we don't carry in mod 2 arithmetic. - */ - - /* bottom 32 bits of a */ - v1 = vec_and(v0, vmask_32bit); - - /* ma */ - v1 = __builtin_crypto_vpmsumd ((__vector unsigned long long)v1, - (__vector unsigned long long)vconst1); - - /* bottom 32bits of ma */ - v1 = vec_and(v1, vmask_32bit); - /* qn */ - v1 = __builtin_crypto_vpmsumd ((__vector unsigned long long)v1, - (__vector unsigned long long)vconst2); - /* a - qn, subtraction is xor in GF(2) */ - v0 = vec_xor (v0, v1); - - /* - * Since we are bit reflected, the result (ie the low 32 bits) is in - * the high 32 bits. We just need to shift it left 4 bytes - * V0 [ 0 1 X 3 ] - * V0 [ 0 X 2 3 ] - */ - - /* shift result into top 64 bits of */ - v0 = (__vector unsigned long long)vec_sld((__vector unsigned char)v0, - (__vector unsigned char)vzero, 4); - - result = __builtin_unpack_vector_0 (v0); -#endif - - return result; -} +#define POWER8_INTRINSICS +#include "pcc_crc32_constants.h" +#include "crc_ppc64.h" diff --git a/mysys/crc32/crc32_x86.c b/mysys/crc32/crc32_x86.c index 3f176a6c145..1e5d2a0a089 100644 --- a/mysys/crc32/crc32_x86.c +++ b/mysys/crc32/crc32_x86.c @@ -1,545 +1,358 @@ -/****************************************************** -Copyright (c) 2017 Percona LLC and/or its affiliates. +/* Copyright (c) 2020 MariaDB + + 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 St, Fifth Floor, Boston, MA 02110-1335 USA */ + +/* + Implementation of CRC32 (Ethernet) uing Intel PCLMULQDQ + Ported from Intels work, see https://github.com/intel/soft-crc +*/ + +/******************************************************************************* + Copyright (c) 2009-2018, Intel Corporation + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * 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. + * Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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. +*******************************************************************************/ -CRC32 using Intel's PCLMUL instruction. -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. +#include <my_global.h> +#include <my_compiler.h> -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. +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <stddef.h> -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, Fifth Floor, Boston, MA 02110-1335 USA +#if defined(__GNUC__) +#include <x86intrin.h> +#include <cpuid.h> +#elif defined(_MSC_VER) +#include <intrin.h> +#else +#error "unknown compiler" +#endif -*******************************************************/ +static int has_sse42_and_pclmul(uint32_t recx) +{ + /* 1 << 20 is SSE42, 1 << 1 is PCLMULQDQ */ +#define bits_SSE42_AND_PCLMUL (1 << 20 | 1 << 1) + return (recx & bits_SSE42_AND_PCLMUL) == bits_SSE42_AND_PCLMUL; +} -/* crc-intel-pclmul.c - Intel PCLMUL accelerated CRC implementation - * Copyright (C) 2016 Jussi Kivilinna <jussi.kivilinna@iki.fi> +#ifdef __GNUC__ +int crc32_pclmul_enabled(void) +{ + uint32_t reax= 0, rebx= 0, recx= 0, redx= 0; + __cpuid(1, reax, rebx, recx, redx); + return has_sse42_and_pclmul(recx); +} +#elif defined(_MSC_VER) +int crc32_pclmul_enabled(void) +{ + int regs[4]; + __cpuid(regs, 1); + return has_sse42_and_pclmul(regs[2]); +} +#endif + +/** + * @brief Shifts left 128 bit register by specified number of bytes * - * This file is part of Libgcrypt. + * @param reg 128 bit value + * @param num number of bytes to shift left \a reg by (0-16) * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. + * @return \a reg << (\a num * 8) + */ +static inline __m128i xmm_shift_left(__m128i reg, const unsigned int num) +{ + static const MY_ALIGNED(16) uint8_t crc_xmm_shift_tab[48]= { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + const __m128i *p= (const __m128i *) (crc_xmm_shift_tab + 16 - num); + + return _mm_shuffle_epi8(reg, _mm_loadu_si128(p)); +} + +struct crcr_pclmulqdq_ctx +{ + uint64_t rk1; + uint64_t rk2; + uint64_t rk5; + uint64_t rk6; + uint64_t rk7; + uint64_t rk8; +}; + +/** + * @brief Performs one folding round * - * Libgcrypt 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 Lesser General Public License for more details. + * Logically function operates as follows: + * DATA = READ_NEXT_16BYTES(); + * F1 = LSB8(FOLD) + * F2 = MSB8(FOLD) + * T1 = CLMUL(F1, RK1) + * T2 = CLMUL(F2, RK2) + * FOLD = XOR(T1, T2, DATA) * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA + * @param data_block 16 byte data block + * @param precomp precomputed rk1 constanst + * @param fold running 16 byte folded data * + * @return New 16 byte folded data */ +static inline __m128i crcr32_folding_round(const __m128i data_block, + const __m128i precomp, const __m128i fold) +{ + __m128i tmp0= _mm_clmulepi64_si128(fold, precomp, 0x01); + __m128i tmp1= _mm_clmulepi64_si128(fold, precomp, 0x10); -#include <my_global.h> + return _mm_xor_si128(tmp1, _mm_xor_si128(data_block, tmp0)); +} -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdint.h> +/** + * @brief Performs reduction from 128 bits to 64 bits + * + * @param data128 128 bits data to be reduced + * @param precomp rk5 and rk6 precomputed constants + * + * @return data reduced to 64 bits + */ +static inline __m128i crcr32_reduce_128_to_64(__m128i data128, const __m128i precomp) +{ + __m128i tmp0, tmp1, tmp2; -# define U64_C(c) (c ## UL) + /* 64b fold */ + tmp0= _mm_clmulepi64_si128(data128, precomp, 0x00); + tmp1= _mm_srli_si128(data128, 8); + tmp0= _mm_xor_si128(tmp0, tmp1); -typedef uint32_t u32; -typedef uint16_t u16; -typedef uint64_t u64; -#ifndef byte -typedef uint8_t byte; -#endif + /* 32b fold */ + tmp2= _mm_slli_si128(tmp0, 4); + tmp1= _mm_clmulepi64_si128(tmp2, precomp, 0x10); -# define _gcry_bswap32 __builtin_bswap32 + return _mm_xor_si128(tmp1, tmp0); +} -#if __GNUC__ >= 4 && defined(__x86_64__) +/** + * @brief Performs Barret's reduction from 64 bits to 32 bits + * + * @param data64 64 bits data to be reduced + * @param precomp rk7 precomputed constant + * + * @return data reduced to 32 bits + */ +static inline uint32_t crcr32_reduce_64_to_32(__m128i data64, const __m128i precomp) +{ + static const MY_ALIGNED(16) uint32_t mask1[4]= { + 0xffffffff, 0xffffffff, 0x00000000, 0x00000000}; + static const MY_ALIGNED(16) uint32_t mask2[4]= { + 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff}; + __m128i tmp0, tmp1, tmp2; -#if defined(_GCRY_GCC_VERSION) && _GCRY_GCC_VERSION >= 40400 /* 4.4 */ -/* Prevent compiler from issuing SSE instructions between asm blocks. */ -# pragma GCC target("no-sse") -#endif + tmp0= _mm_and_si128(data64, _mm_load_si128((__m128i *) mask2)); + tmp1= _mm_clmulepi64_si128(tmp0, precomp, 0x00); + tmp1= _mm_xor_si128(tmp1, tmp0); + tmp1= _mm_and_si128(tmp1, _mm_load_si128((__m128i *) mask1)); -#define ALIGNED_16 __attribute__ ((aligned (16))) + tmp2= _mm_clmulepi64_si128(tmp1, precomp, 0x10); + tmp2= _mm_xor_si128(tmp2, tmp1); + tmp2= _mm_xor_si128(tmp2, tmp0); + return _mm_extract_epi32(tmp2, 2); +} -struct u16_unaligned_s +/** + * @brief Calculates reflected 32-bit CRC for given \a data block + * by applying folding and reduction methods. + * + * Algorithm operates on 32 bit CRCs. + * Polynomials and initial values may need to be promoted to + * 32 bits where required. + * + * @param crc initial CRC value (32 bit value) + * @param data pointer to data block + * @param data_len length of \a data block in bytes + * @param params pointer to PCLMULQDQ CRC calculation context + * + * @return CRC for given \a data block (32 bits wide). + */ +static inline uint32_t crcr32_calc_pclmulqdq(const uint8_t *data, uint32_t data_len, + uint32_t crc, + const struct crcr_pclmulqdq_ctx *params) { - u16 a; -} __attribute__((packed, aligned (1), may_alias)); + __m128i temp, fold, k; + uint32_t n; + DBUG_ASSERT(data != NULL || data_len == 0); + DBUG_ASSERT(params); -/* Constants structure for generic reflected/non-reflected CRC32 CLMUL - * functions. */ -struct crc32_consts_s -{ - /* k: { x^(32*17), x^(32*15), x^(32*5), x^(32*3), x^(32*2), 0 } mod P(x) */ - u64 k[6]; - /* my_p: { floor(x^64 / P(x)), P(x) } */ - u64 my_p[2]; -}; + if (unlikely(data_len == 0)) + return crc; + /** + * Get CRC init value + */ + temp= _mm_insert_epi32(_mm_setzero_si128(), crc, 0); -/* CLMUL constants for CRC32 and CRC32RFC1510. */ -static const struct crc32_consts_s crc32_consts ALIGNED_16 = -{ - { /* k[6] = reverse_33bits( x^(32*y) mod P(x) ) */ - U64_C(0x154442bd4), U64_C(0x1c6e41596), /* y = { 17, 15 } */ - U64_C(0x1751997d0), U64_C(0x0ccaa009e), /* y = { 5, 3 } */ - U64_C(0x163cd6124), 0 /* y = 2 */ - }, - { /* my_p[2] = reverse_33bits ( { floor(x^64 / P(x)), P(x) } ) */ - U64_C(0x1f7011641), U64_C(0x1db710641) - } -}; + /** + * ------------------------------------------------- + * Folding all data into single 16 byte data block + * Assumes: \a fold holds first 16 bytes of data + */ -/* Common constants for CRC32 algorithms. */ -static const byte crc32_refl_shuf_shift[3 * 16] ALIGNED_16 = - { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - }; -static const byte crc32_partial_fold_input_mask[16 + 16] ALIGNED_16 = - { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - }; -static const u64 crc32_merge9to15_shuf[15 - 9 + 1][2] ALIGNED_16 = + if (unlikely(data_len < 32)) { - { U64_C(0x0706050403020100), U64_C(0xffffffffffffff0f) }, /* 9 */ - { U64_C(0x0706050403020100), U64_C(0xffffffffffff0f0e) }, - { U64_C(0x0706050403020100), U64_C(0xffffffffff0f0e0d) }, - { U64_C(0x0706050403020100), U64_C(0xffffffff0f0e0d0c) }, - { U64_C(0x0706050403020100), U64_C(0xffffff0f0e0d0c0b) }, - { U64_C(0x0706050403020100), U64_C(0xffff0f0e0d0c0b0a) }, - { U64_C(0x0706050403020100), U64_C(0xff0f0e0d0c0b0a09) }, /* 15 */ - }; -static const u64 crc32_merge5to7_shuf[7 - 5 + 1][2] ALIGNED_16 = - { - { U64_C(0xffffff0703020100), U64_C(0xffffffffffffffff) }, /* 5 */ - { U64_C(0xffff070603020100), U64_C(0xffffffffffffffff) }, - { U64_C(0xff07060503020100), U64_C(0xffffffffffffffff) }, /* 7 */ - }; - -/* PCLMUL functions for reflected CRC32. */ -static inline void -crc32_reflected_bulk (u32 *pcrc, const byte *inbuf, size_t inlen, - const struct crc32_consts_s *consts) -{ - if (inlen >= 8 * 16) + if (unlikely(data_len == 16)) { - asm volatile ("movd %[crc], %%xmm4\n\t" - "movdqu %[inbuf_0], %%xmm0\n\t" - "movdqu %[inbuf_1], %%xmm1\n\t" - "movdqu %[inbuf_2], %%xmm2\n\t" - "movdqu %[inbuf_3], %%xmm3\n\t" - "pxor %%xmm4, %%xmm0\n\t" - : - : [inbuf_0] "m" (inbuf[0 * 16]), - [inbuf_1] "m" (inbuf[1 * 16]), - [inbuf_2] "m" (inbuf[2 * 16]), - [inbuf_3] "m" (inbuf[3 * 16]), - [crc] "m" (*pcrc) - ); - - inbuf += 4 * 16; - inlen -= 4 * 16; - - asm volatile ("movdqa %[k1k2], %%xmm4\n\t" - : - : [k1k2] "m" (consts->k[1 - 1]) - ); - - /* Fold by 4. */ - while (inlen >= 4 * 16) - { - asm volatile ("movdqu %[inbuf_0], %%xmm5\n\t" - "movdqa %%xmm0, %%xmm6\n\t" - "pclmulqdq $0x00, %%xmm4, %%xmm0\n\t" - "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t" - "pxor %%xmm5, %%xmm0\n\t" - "pxor %%xmm6, %%xmm0\n\t" - - "movdqu %[inbuf_1], %%xmm5\n\t" - "movdqa %%xmm1, %%xmm6\n\t" - "pclmulqdq $0x00, %%xmm4, %%xmm1\n\t" - "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t" - "pxor %%xmm5, %%xmm1\n\t" - "pxor %%xmm6, %%xmm1\n\t" - - "movdqu %[inbuf_2], %%xmm5\n\t" - "movdqa %%xmm2, %%xmm6\n\t" - "pclmulqdq $0x00, %%xmm4, %%xmm2\n\t" - "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t" - "pxor %%xmm5, %%xmm2\n\t" - "pxor %%xmm6, %%xmm2\n\t" - - "movdqu %[inbuf_3], %%xmm5\n\t" - "movdqa %%xmm3, %%xmm6\n\t" - "pclmulqdq $0x00, %%xmm4, %%xmm3\n\t" - "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t" - "pxor %%xmm5, %%xmm3\n\t" - "pxor %%xmm6, %%xmm3\n\t" - : - : [inbuf_0] "m" (inbuf[0 * 16]), - [inbuf_1] "m" (inbuf[1 * 16]), - [inbuf_2] "m" (inbuf[2 * 16]), - [inbuf_3] "m" (inbuf[3 * 16]) - ); - - inbuf += 4 * 16; - inlen -= 4 * 16; - } - - asm volatile ("movdqa %[k3k4], %%xmm6\n\t" - "movdqa %[my_p], %%xmm5\n\t" - : - : [k3k4] "m" (consts->k[3 - 1]), - [my_p] "m" (consts->my_p[0]) - ); - - /* Fold 4 to 1. */ - - asm volatile ("movdqa %%xmm0, %%xmm4\n\t" - "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t" - "pclmulqdq $0x11, %%xmm6, %%xmm4\n\t" - "pxor %%xmm1, %%xmm0\n\t" - "pxor %%xmm4, %%xmm0\n\t" - - "movdqa %%xmm0, %%xmm4\n\t" - "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t" - "pclmulqdq $0x11, %%xmm6, %%xmm4\n\t" - "pxor %%xmm2, %%xmm0\n\t" - "pxor %%xmm4, %%xmm0\n\t" - - "movdqa %%xmm0, %%xmm4\n\t" - "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t" - "pclmulqdq $0x11, %%xmm6, %%xmm4\n\t" - "pxor %%xmm3, %%xmm0\n\t" - "pxor %%xmm4, %%xmm0\n\t" - : - : - ); + /* 16 bytes */ + fold= _mm_loadu_si128((__m128i *) data); + fold= _mm_xor_si128(fold, temp); + goto reduction_128_64; } - else + if (unlikely(data_len < 16)) { - asm volatile ("movd %[crc], %%xmm1\n\t" - "movdqu %[inbuf], %%xmm0\n\t" - "movdqa %[k3k4], %%xmm6\n\t" - "pxor %%xmm1, %%xmm0\n\t" - "movdqa %[my_p], %%xmm5\n\t" - : - : [inbuf] "m" (*inbuf), - [crc] "m" (*pcrc), - [k3k4] "m" (consts->k[3 - 1]), - [my_p] "m" (consts->my_p[0]) - ); - - inbuf += 16; - inlen -= 16; + /* 0 to 15 bytes */ + MY_ALIGNED(16) uint8_t buffer[16]; + + memset(buffer, 0, sizeof(buffer)); + memcpy(buffer, data, data_len); + + fold= _mm_load_si128((__m128i *) buffer); + fold= _mm_xor_si128(fold, temp); + if ((data_len < 4)) + { + fold= xmm_shift_left(fold, 8 - data_len); + goto barret_reduction; + } + fold= xmm_shift_left(fold, 16 - data_len); + goto reduction_128_64; } + /* 17 to 31 bytes */ + fold= _mm_loadu_si128((__m128i *) data); + fold= _mm_xor_si128(fold, temp); + n= 16; + k= _mm_load_si128((__m128i *) (¶ms->rk1)); + goto partial_bytes; + } - /* Fold by 1. */ - if (inlen >= 16) - { - while (inlen >= 16) - { - /* Load next block to XMM2. Fold XMM0 to XMM0:XMM1. */ - asm volatile ("movdqu %[inbuf], %%xmm2\n\t" - "movdqa %%xmm0, %%xmm1\n\t" - "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t" - "pclmulqdq $0x11, %%xmm6, %%xmm1\n\t" - "pxor %%xmm2, %%xmm0\n\t" - "pxor %%xmm1, %%xmm0\n\t" - : - : [inbuf] "m" (*inbuf) - ); - - inbuf += 16; - inlen -= 16; - } - } + /** + * At least 32 bytes in the buffer + */ + + /** + * Apply CRC initial value + */ + fold= _mm_loadu_si128((const __m128i *) data); + fold= _mm_xor_si128(fold, temp); + + /** + * Main folding loop + * - the last 16 bytes is processed separately + */ + k= _mm_load_si128((__m128i *) (¶ms->rk1)); + for (n= 16; (n + 16) <= data_len; n+= 16) + { + temp= _mm_loadu_si128((__m128i *) &data[n]); + fold= crcr32_folding_round(temp, k, fold); + } - /* Partial fold. */ - if (inlen) - { - /* Load last input and add padding zeros. */ - asm volatile ("movdqu %[shr_shuf], %%xmm3\n\t" - "movdqu %[shl_shuf], %%xmm4\n\t" - "movdqu %[mask], %%xmm2\n\t" - - "movdqa %%xmm0, %%xmm1\n\t" - "pshufb %%xmm4, %%xmm0\n\t" - "movdqu %[inbuf], %%xmm4\n\t" - "pshufb %%xmm3, %%xmm1\n\t" - "pand %%xmm4, %%xmm2\n\t" - "por %%xmm1, %%xmm2\n\t" - - "movdqa %%xmm0, %%xmm1\n\t" - "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t" - "pclmulqdq $0x11, %%xmm6, %%xmm1\n\t" - "pxor %%xmm2, %%xmm0\n\t" - "pxor %%xmm1, %%xmm0\n\t" - : - : [inbuf] "m" (*(inbuf - 16 + inlen)), - [mask] "m" (crc32_partial_fold_input_mask[inlen]), - [shl_shuf] "m" (crc32_refl_shuf_shift[inlen]), - [shr_shuf] "m" (crc32_refl_shuf_shift[inlen + 16]) - ); - - inbuf += inlen; - inlen -= inlen; - } +partial_bytes: + if (likely(n < data_len)) + { + static const MY_ALIGNED(16) uint32_t mask3[4]= {0x80808080, 0x80808080, + 0x80808080, 0x80808080}; + static const MY_ALIGNED(16) uint8_t shf_table[32]= { + 0x00, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, + 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + __m128i last16, a, b; - /* Final fold. */ - asm volatile (/* reduce 128-bits to 96-bits */ - "movdqa %%xmm0, %%xmm1\n\t" - "pclmulqdq $0x10, %%xmm6, %%xmm0\n\t" - "psrldq $8, %%xmm1\n\t" - "pxor %%xmm1, %%xmm0\n\t" - - /* reduce 96-bits to 64-bits */ - "pshufd $0xfc, %%xmm0, %%xmm1\n\t" /* [00][00][00][x] */ - "pshufd $0xf9, %%xmm0, %%xmm0\n\t" /* [00][00][x>>64][x>>32] */ - "pclmulqdq $0x00, %[k5], %%xmm1\n\t" /* [00][00][xx][xx] */ - "pxor %%xmm1, %%xmm0\n\t" /* top 64-bit are zero */ - - /* barrett reduction */ - "pshufd $0xf3, %%xmm0, %%xmm1\n\t" /* [00][00][x>>32][00] */ - "pslldq $4, %%xmm0\n\t" /* [??][x>>32][??][??] */ - "pclmulqdq $0x00, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */ - "pclmulqdq $0x10, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */ - "pxor %%xmm1, %%xmm0\n\t" - - /* store CRC */ - "pextrd $2, %%xmm0, %[out]\n\t" - : [out] "=m" (*pcrc) - : [k5] "m" (consts->k[5 - 1]) - ); -} + last16= _mm_loadu_si128((const __m128i *) &data[data_len - 16]); -static inline void -crc32_reflected_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen, - const struct crc32_consts_s *consts) -{ - if (inlen < 4) - { - u32 crc = *pcrc; - u32 data; - - asm volatile ("movdqa %[my_p], %%xmm5\n\t" - : - : [my_p] "m" (consts->my_p[0]) - ); - - if (inlen == 1) - { - data = inbuf[0]; - data ^= crc; - data <<= 24; - crc >>= 8; - } - else if (inlen == 2) - { - data = ((const struct u16_unaligned_s *)inbuf)->a; - data ^= crc; - data <<= 16; - crc >>= 16; - } - else - { - data = ((const struct u16_unaligned_s *)inbuf)->a; - data |= ((u32) inbuf[2]) << 16; - data ^= crc; - data <<= 8; - crc >>= 24; - } - - /* Barrett reduction */ - asm volatile ("movd %[in], %%xmm0\n\t" - "movd %[crc], %%xmm1\n\t" - - "pclmulqdq $0x00, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */ - "psllq $32, %%xmm1\n\t" - "pshufd $0xfc, %%xmm0, %%xmm0\n\t" /* [00][00][00][x] */ - "pclmulqdq $0x10, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */ - "pxor %%xmm1, %%xmm0\n\t" - - "pextrd $1, %%xmm0, %[out]\n\t" - : [out] "=m" (*pcrc) - : [in] "rm" (data), - [crc] "rm" (crc) - ); - } - else if (inlen == 4) - { - /* Barrett reduction */ - asm volatile ("movd %[crc], %%xmm1\n\t" - "movd %[in], %%xmm0\n\t" - "movdqa %[my_p], %%xmm5\n\t" - "pxor %%xmm1, %%xmm0\n\t" - - "pclmulqdq $0x00, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */ - "pshufd $0xfc, %%xmm0, %%xmm0\n\t" /* [00][00][00][x] */ - "pclmulqdq $0x10, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */ - - "pextrd $1, %%xmm0, %[out]\n\t" - : [out] "=m" (*pcrc) - : [in] "m" (*inbuf), - [crc] "m" (*pcrc), - [my_p] "m" (consts->my_p[0]) - ); - } - else - { - asm volatile ("movdqu %[shuf], %%xmm4\n\t" - "movd %[crc], %%xmm1\n\t" - "movdqa %[my_p], %%xmm5\n\t" - "movdqa %[k3k4], %%xmm6\n\t" - : - : [shuf] "m" (crc32_refl_shuf_shift[inlen]), - [crc] "m" (*pcrc), - [my_p] "m" (consts->my_p[0]), - [k3k4] "m" (consts->k[3 - 1]) - ); - - if (inlen >= 8) - { - asm volatile ("movq %[inbuf], %%xmm0\n\t" - : - : [inbuf] "m" (*inbuf) - ); - if (inlen > 8) - { - asm volatile (/*"pinsrq $1, %[inbuf_tail], %%xmm0\n\t"*/ - "movq %[inbuf_tail], %%xmm2\n\t" - "punpcklqdq %%xmm2, %%xmm0\n\t" - "pshufb %[merge_shuf], %%xmm0\n\t" - : - : [inbuf_tail] "m" (inbuf[inlen - 8]), - [merge_shuf] "m" - (*crc32_merge9to15_shuf[inlen - 9]) - ); - } - } - else - { - asm volatile ("movd %[inbuf], %%xmm0\n\t" - "pinsrd $1, %[inbuf_tail], %%xmm0\n\t" - "pshufb %[merge_shuf], %%xmm0\n\t" - : - : [inbuf] "m" (*inbuf), - [inbuf_tail] "m" (inbuf[inlen - 4]), - [merge_shuf] "m" - (*crc32_merge5to7_shuf[inlen - 5]) - ); - } - - /* Final fold. */ - asm volatile ("pxor %%xmm1, %%xmm0\n\t" - "pshufb %%xmm4, %%xmm0\n\t" - - /* reduce 128-bits to 96-bits */ - "movdqa %%xmm0, %%xmm1\n\t" - "pclmulqdq $0x10, %%xmm6, %%xmm0\n\t" - "psrldq $8, %%xmm1\n\t" - "pxor %%xmm1, %%xmm0\n\t" /* top 32-bit are zero */ - - /* reduce 96-bits to 64-bits */ - "pshufd $0xfc, %%xmm0, %%xmm1\n\t" /* [00][00][00][x] */ - "pshufd $0xf9, %%xmm0, %%xmm0\n\t" /* [00][00][x>>64][x>>32] */ - "pclmulqdq $0x00, %[k5], %%xmm1\n\t" /* [00][00][xx][xx] */ - "pxor %%xmm1, %%xmm0\n\t" /* top 64-bit are zero */ - - /* barrett reduction */ - "pshufd $0xf3, %%xmm0, %%xmm1\n\t" /* [00][00][x>>32][00] */ - "pslldq $4, %%xmm0\n\t" /* [??][x>>32][??][??] */ - "pclmulqdq $0x00, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */ - "pclmulqdq $0x10, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */ - "pxor %%xmm1, %%xmm0\n\t" - - /* store CRC */ - "pextrd $2, %%xmm0, %[out]\n\t" - : [out] "=m" (*pcrc) - : [k5] "m" (consts->k[5 - 1]) - ); - } -} + temp= _mm_loadu_si128((const __m128i *) &shf_table[data_len & 15]); + a= _mm_shuffle_epi8(fold, temp); -void -crc32_intel_pclmul (u32 *pcrc, const byte *inbuf, size_t inlen) -{ - const struct crc32_consts_s *consts = &crc32_consts; -#if defined(__x86_64__) && defined(__WIN64__) - char win64tmp[2 * 16]; - - /* XMM6-XMM7 need to be restored after use. */ - asm volatile ("movdqu %%xmm6, 0*16(%0)\n\t" - "movdqu %%xmm7, 1*16(%0)\n\t" - : - : "r" (win64tmp) - : "memory"); -#endif + temp= _mm_xor_si128(temp, _mm_load_si128((const __m128i *) mask3)); + b= _mm_shuffle_epi8(fold, temp); + b= _mm_blendv_epi8(b, last16, temp); - if (!inlen) - return; - - if (inlen >= 16) - crc32_reflected_bulk(pcrc, inbuf, inlen, consts); - else - crc32_reflected_less_than_16(pcrc, inbuf, inlen, consts); - -#if defined(__x86_64__) && defined(__WIN64__) - /* Restore used registers. */ - asm volatile("movdqu 0*16(%0), %%xmm6\n\t" - "movdqu 1*16(%0), %%xmm7\n\t" - : - : "r" (win64tmp) - : "memory"); -#endif -} + /* k = rk1 & rk2 */ + temp= _mm_clmulepi64_si128(a, k, 0x01); + fold= _mm_clmulepi64_si128(a, k, 0x10); -#ifdef __GNUC__ -int crc32_pclmul_enabled(void) -{ - int eax, ecx; - /* We assume that the CPUID instruction and its parameter 1 are available. - We do not support any precursors of the Intel 80486. */ - asm("cpuid" : "=a"(eax), "=c"(ecx) : "0"(1) : "ebx", "edx"); - return !(~ecx & (1 << 19 | 1 << 1)); -} -#elif 0 /* defined _MSC_VER */ /* FIXME: implement the pclmul interface */ -#include <intrin.h> -int crc32_pclmul_enabled(void) -{ - /* We assume that the CPUID instruction and its parameter 1 are available. - We do not support any precursors of the Intel 80486. */ - int regs[4]; - __cpuid(regs, 1); - return !(~regs[2] & (1 << 19 | 1 << 1)); -} -#else -int crc32_pclmul_enabled(void) -{ - return 0; + fold= _mm_xor_si128(fold, temp); + fold= _mm_xor_si128(fold, b); + } + + /** + * ------------------------------------------------- + * Reduction 128 -> 32 + * Assumes: \a fold holds 128bit folded data + */ +reduction_128_64: + k= _mm_load_si128((__m128i *) (¶ms->rk5)); + fold= crcr32_reduce_128_to_64(fold, k); + +barret_reduction: + k= _mm_load_si128((__m128i *) (¶ms->rk7)); + n= crcr32_reduce_64_to_32(fold, k); + return n; } -#endif +static const MY_ALIGNED(16) struct crcr_pclmulqdq_ctx ether_crc32_clmul= { + 0xccaa009e, /**< rk1 */ + 0x1751997d0, /**< rk2 */ + 0xccaa009e, /**< rk5 */ + 0x163cd6124, /**< rk6 */ + 0x1f7011640, /**< rk7 */ + 0x1db710641 /**< rk8 */ +}; + +/** + * @brief Calculates Ethernet CRC32 using PCLMULQDQ method. + * + * @param data pointer to data block to calculate CRC for + * @param data_len size of data block + * + * @return New CRC value + */ unsigned int crc32_pclmul(unsigned int crc32, const void *buf, size_t len) { - crc32= ~crc32; - crc32_intel_pclmul(&crc32, buf, len); - return ~crc32; + return ~crcr32_calc_pclmulqdq(buf, (uint32_t)len, ~crc32, ðer_crc32_clmul); } -#endif diff --git a/mysys/crc32/crc32c.cc b/mysys/crc32/crc32c.cc new file mode 100644 index 00000000000..4eaceb8c438 --- /dev/null +++ b/mysys/crc32/crc32c.cc @@ -0,0 +1,1254 @@ +// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). +// +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. +// +// A portable implementation of crc32c, optimized to handle +// four bytes at a time. + +// +// Copyright (c) 2011 The LevelDB Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. See the AUTHORS file for names of contributors. + + +#include <stddef.h> +#include <stdint.h> +#include <string> +#include <my_global.h> +#include <my_byteorder.h> +static inline uint32_t DecodeFixed32(const char *ptr) +{ + return uint4korr(ptr); +} + +static inline uint64_t DecodeFixed64(const char *ptr) +{ + return uint8korr(ptr); +} + +#include <stdint.h> +#ifdef _MSC_VER +#include <intrin.h> +#endif + +#ifdef HAVE_SSE42 +#include <nmmintrin.h> +#include <wmmintrin.h> +#ifdef __GNUC__ +#include <cpuid.h> +#endif +#endif + + +#ifdef __powerpc64__ +#include "crc32c_ppc.h" + +#if __linux__ +#include <sys/auxv.h> + +#ifndef PPC_FEATURE2_VEC_CRYPTO +#define PPC_FEATURE2_VEC_CRYPTO 0x02000000 +#endif + +#ifndef AT_HWCAP2 +#define AT_HWCAP2 26 +#endif + +#endif /* __linux__ */ + +#endif + +namespace mysys_namespace { +namespace crc32c { + +#if defined(HAVE_POWER8) && defined(HAS_ALTIVEC) +#ifdef __powerpc64__ +static int arch_ppc_crc32 = 0; +#endif /* __powerpc64__ */ +#endif + +static const uint32_t table0_[256] = { + 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, + 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, + 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, + 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, + 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, + 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, + 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, + 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, + 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, + 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, + 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, + 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, + 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, + 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, + 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, + 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, + 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, + 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, + 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, + 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, + 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, + 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, + 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, + 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, + 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, + 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, + 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, + 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, + 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, + 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, + 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, + 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, + 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, + 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, + 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, + 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, + 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, + 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, + 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, + 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, + 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, + 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, + 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, + 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, + 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, + 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, + 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, + 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, + 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, + 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, + 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, + 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, + 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, + 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, + 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, + 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, + 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, + 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, + 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, + 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, + 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, + 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, + 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, + 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351 +}; +static const uint32_t table1_[256] = { + 0x00000000, 0x13a29877, 0x274530ee, 0x34e7a899, + 0x4e8a61dc, 0x5d28f9ab, 0x69cf5132, 0x7a6dc945, + 0x9d14c3b8, 0x8eb65bcf, 0xba51f356, 0xa9f36b21, + 0xd39ea264, 0xc03c3a13, 0xf4db928a, 0xe7790afd, + 0x3fc5f181, 0x2c6769f6, 0x1880c16f, 0x0b225918, + 0x714f905d, 0x62ed082a, 0x560aa0b3, 0x45a838c4, + 0xa2d13239, 0xb173aa4e, 0x859402d7, 0x96369aa0, + 0xec5b53e5, 0xfff9cb92, 0xcb1e630b, 0xd8bcfb7c, + 0x7f8be302, 0x6c297b75, 0x58ced3ec, 0x4b6c4b9b, + 0x310182de, 0x22a31aa9, 0x1644b230, 0x05e62a47, + 0xe29f20ba, 0xf13db8cd, 0xc5da1054, 0xd6788823, + 0xac154166, 0xbfb7d911, 0x8b507188, 0x98f2e9ff, + 0x404e1283, 0x53ec8af4, 0x670b226d, 0x74a9ba1a, + 0x0ec4735f, 0x1d66eb28, 0x298143b1, 0x3a23dbc6, + 0xdd5ad13b, 0xcef8494c, 0xfa1fe1d5, 0xe9bd79a2, + 0x93d0b0e7, 0x80722890, 0xb4958009, 0xa737187e, + 0xff17c604, 0xecb55e73, 0xd852f6ea, 0xcbf06e9d, + 0xb19da7d8, 0xa23f3faf, 0x96d89736, 0x857a0f41, + 0x620305bc, 0x71a19dcb, 0x45463552, 0x56e4ad25, + 0x2c896460, 0x3f2bfc17, 0x0bcc548e, 0x186eccf9, + 0xc0d23785, 0xd370aff2, 0xe797076b, 0xf4359f1c, + 0x8e585659, 0x9dface2e, 0xa91d66b7, 0xbabffec0, + 0x5dc6f43d, 0x4e646c4a, 0x7a83c4d3, 0x69215ca4, + 0x134c95e1, 0x00ee0d96, 0x3409a50f, 0x27ab3d78, + 0x809c2506, 0x933ebd71, 0xa7d915e8, 0xb47b8d9f, + 0xce1644da, 0xddb4dcad, 0xe9537434, 0xfaf1ec43, + 0x1d88e6be, 0x0e2a7ec9, 0x3acdd650, 0x296f4e27, + 0x53028762, 0x40a01f15, 0x7447b78c, 0x67e52ffb, + 0xbf59d487, 0xacfb4cf0, 0x981ce469, 0x8bbe7c1e, + 0xf1d3b55b, 0xe2712d2c, 0xd69685b5, 0xc5341dc2, + 0x224d173f, 0x31ef8f48, 0x050827d1, 0x16aabfa6, + 0x6cc776e3, 0x7f65ee94, 0x4b82460d, 0x5820de7a, + 0xfbc3faf9, 0xe861628e, 0xdc86ca17, 0xcf245260, + 0xb5499b25, 0xa6eb0352, 0x920cabcb, 0x81ae33bc, + 0x66d73941, 0x7575a136, 0x419209af, 0x523091d8, + 0x285d589d, 0x3bffc0ea, 0x0f186873, 0x1cbaf004, + 0xc4060b78, 0xd7a4930f, 0xe3433b96, 0xf0e1a3e1, + 0x8a8c6aa4, 0x992ef2d3, 0xadc95a4a, 0xbe6bc23d, + 0x5912c8c0, 0x4ab050b7, 0x7e57f82e, 0x6df56059, + 0x1798a91c, 0x043a316b, 0x30dd99f2, 0x237f0185, + 0x844819fb, 0x97ea818c, 0xa30d2915, 0xb0afb162, + 0xcac27827, 0xd960e050, 0xed8748c9, 0xfe25d0be, + 0x195cda43, 0x0afe4234, 0x3e19eaad, 0x2dbb72da, + 0x57d6bb9f, 0x447423e8, 0x70938b71, 0x63311306, + 0xbb8de87a, 0xa82f700d, 0x9cc8d894, 0x8f6a40e3, + 0xf50789a6, 0xe6a511d1, 0xd242b948, 0xc1e0213f, + 0x26992bc2, 0x353bb3b5, 0x01dc1b2c, 0x127e835b, + 0x68134a1e, 0x7bb1d269, 0x4f567af0, 0x5cf4e287, + 0x04d43cfd, 0x1776a48a, 0x23910c13, 0x30339464, + 0x4a5e5d21, 0x59fcc556, 0x6d1b6dcf, 0x7eb9f5b8, + 0x99c0ff45, 0x8a626732, 0xbe85cfab, 0xad2757dc, + 0xd74a9e99, 0xc4e806ee, 0xf00fae77, 0xe3ad3600, + 0x3b11cd7c, 0x28b3550b, 0x1c54fd92, 0x0ff665e5, + 0x759baca0, 0x663934d7, 0x52de9c4e, 0x417c0439, + 0xa6050ec4, 0xb5a796b3, 0x81403e2a, 0x92e2a65d, + 0xe88f6f18, 0xfb2df76f, 0xcfca5ff6, 0xdc68c781, + 0x7b5fdfff, 0x68fd4788, 0x5c1aef11, 0x4fb87766, + 0x35d5be23, 0x26772654, 0x12908ecd, 0x013216ba, + 0xe64b1c47, 0xf5e98430, 0xc10e2ca9, 0xd2acb4de, + 0xa8c17d9b, 0xbb63e5ec, 0x8f844d75, 0x9c26d502, + 0x449a2e7e, 0x5738b609, 0x63df1e90, 0x707d86e7, + 0x0a104fa2, 0x19b2d7d5, 0x2d557f4c, 0x3ef7e73b, + 0xd98eedc6, 0xca2c75b1, 0xfecbdd28, 0xed69455f, + 0x97048c1a, 0x84a6146d, 0xb041bcf4, 0xa3e32483 +}; +static const uint32_t table2_[256] = { + 0x00000000, 0xa541927e, 0x4f6f520d, 0xea2ec073, + 0x9edea41a, 0x3b9f3664, 0xd1b1f617, 0x74f06469, + 0x38513ec5, 0x9d10acbb, 0x773e6cc8, 0xd27ffeb6, + 0xa68f9adf, 0x03ce08a1, 0xe9e0c8d2, 0x4ca15aac, + 0x70a27d8a, 0xd5e3eff4, 0x3fcd2f87, 0x9a8cbdf9, + 0xee7cd990, 0x4b3d4bee, 0xa1138b9d, 0x045219e3, + 0x48f3434f, 0xedb2d131, 0x079c1142, 0xa2dd833c, + 0xd62de755, 0x736c752b, 0x9942b558, 0x3c032726, + 0xe144fb14, 0x4405696a, 0xae2ba919, 0x0b6a3b67, + 0x7f9a5f0e, 0xdadbcd70, 0x30f50d03, 0x95b49f7d, + 0xd915c5d1, 0x7c5457af, 0x967a97dc, 0x333b05a2, + 0x47cb61cb, 0xe28af3b5, 0x08a433c6, 0xade5a1b8, + 0x91e6869e, 0x34a714e0, 0xde89d493, 0x7bc846ed, + 0x0f382284, 0xaa79b0fa, 0x40577089, 0xe516e2f7, + 0xa9b7b85b, 0x0cf62a25, 0xe6d8ea56, 0x43997828, + 0x37691c41, 0x92288e3f, 0x78064e4c, 0xdd47dc32, + 0xc76580d9, 0x622412a7, 0x880ad2d4, 0x2d4b40aa, + 0x59bb24c3, 0xfcfab6bd, 0x16d476ce, 0xb395e4b0, + 0xff34be1c, 0x5a752c62, 0xb05bec11, 0x151a7e6f, + 0x61ea1a06, 0xc4ab8878, 0x2e85480b, 0x8bc4da75, + 0xb7c7fd53, 0x12866f2d, 0xf8a8af5e, 0x5de93d20, + 0x29195949, 0x8c58cb37, 0x66760b44, 0xc337993a, + 0x8f96c396, 0x2ad751e8, 0xc0f9919b, 0x65b803e5, + 0x1148678c, 0xb409f5f2, 0x5e273581, 0xfb66a7ff, + 0x26217bcd, 0x8360e9b3, 0x694e29c0, 0xcc0fbbbe, + 0xb8ffdfd7, 0x1dbe4da9, 0xf7908dda, 0x52d11fa4, + 0x1e704508, 0xbb31d776, 0x511f1705, 0xf45e857b, + 0x80aee112, 0x25ef736c, 0xcfc1b31f, 0x6a802161, + 0x56830647, 0xf3c29439, 0x19ec544a, 0xbcadc634, + 0xc85da25d, 0x6d1c3023, 0x8732f050, 0x2273622e, + 0x6ed23882, 0xcb93aafc, 0x21bd6a8f, 0x84fcf8f1, + 0xf00c9c98, 0x554d0ee6, 0xbf63ce95, 0x1a225ceb, + 0x8b277743, 0x2e66e53d, 0xc448254e, 0x6109b730, + 0x15f9d359, 0xb0b84127, 0x5a968154, 0xffd7132a, + 0xb3764986, 0x1637dbf8, 0xfc191b8b, 0x595889f5, + 0x2da8ed9c, 0x88e97fe2, 0x62c7bf91, 0xc7862def, + 0xfb850ac9, 0x5ec498b7, 0xb4ea58c4, 0x11abcaba, + 0x655baed3, 0xc01a3cad, 0x2a34fcde, 0x8f756ea0, + 0xc3d4340c, 0x6695a672, 0x8cbb6601, 0x29faf47f, + 0x5d0a9016, 0xf84b0268, 0x1265c21b, 0xb7245065, + 0x6a638c57, 0xcf221e29, 0x250cde5a, 0x804d4c24, + 0xf4bd284d, 0x51fcba33, 0xbbd27a40, 0x1e93e83e, + 0x5232b292, 0xf77320ec, 0x1d5de09f, 0xb81c72e1, + 0xccec1688, 0x69ad84f6, 0x83834485, 0x26c2d6fb, + 0x1ac1f1dd, 0xbf8063a3, 0x55aea3d0, 0xf0ef31ae, + 0x841f55c7, 0x215ec7b9, 0xcb7007ca, 0x6e3195b4, + 0x2290cf18, 0x87d15d66, 0x6dff9d15, 0xc8be0f6b, + 0xbc4e6b02, 0x190ff97c, 0xf321390f, 0x5660ab71, + 0x4c42f79a, 0xe90365e4, 0x032da597, 0xa66c37e9, + 0xd29c5380, 0x77ddc1fe, 0x9df3018d, 0x38b293f3, + 0x7413c95f, 0xd1525b21, 0x3b7c9b52, 0x9e3d092c, + 0xeacd6d45, 0x4f8cff3b, 0xa5a23f48, 0x00e3ad36, + 0x3ce08a10, 0x99a1186e, 0x738fd81d, 0xd6ce4a63, + 0xa23e2e0a, 0x077fbc74, 0xed517c07, 0x4810ee79, + 0x04b1b4d5, 0xa1f026ab, 0x4bdee6d8, 0xee9f74a6, + 0x9a6f10cf, 0x3f2e82b1, 0xd50042c2, 0x7041d0bc, + 0xad060c8e, 0x08479ef0, 0xe2695e83, 0x4728ccfd, + 0x33d8a894, 0x96993aea, 0x7cb7fa99, 0xd9f668e7, + 0x9557324b, 0x3016a035, 0xda386046, 0x7f79f238, + 0x0b899651, 0xaec8042f, 0x44e6c45c, 0xe1a75622, + 0xdda47104, 0x78e5e37a, 0x92cb2309, 0x378ab177, + 0x437ad51e, 0xe63b4760, 0x0c158713, 0xa954156d, + 0xe5f54fc1, 0x40b4ddbf, 0xaa9a1dcc, 0x0fdb8fb2, + 0x7b2bebdb, 0xde6a79a5, 0x3444b9d6, 0x91052ba8 +}; +static const uint32_t table3_[256] = { + 0x00000000, 0xdd45aab8, 0xbf672381, 0x62228939, + 0x7b2231f3, 0xa6679b4b, 0xc4451272, 0x1900b8ca, + 0xf64463e6, 0x2b01c95e, 0x49234067, 0x9466eadf, + 0x8d665215, 0x5023f8ad, 0x32017194, 0xef44db2c, + 0xe964b13d, 0x34211b85, 0x560392bc, 0x8b463804, + 0x924680ce, 0x4f032a76, 0x2d21a34f, 0xf06409f7, + 0x1f20d2db, 0xc2657863, 0xa047f15a, 0x7d025be2, + 0x6402e328, 0xb9474990, 0xdb65c0a9, 0x06206a11, + 0xd725148b, 0x0a60be33, 0x6842370a, 0xb5079db2, + 0xac072578, 0x71428fc0, 0x136006f9, 0xce25ac41, + 0x2161776d, 0xfc24ddd5, 0x9e0654ec, 0x4343fe54, + 0x5a43469e, 0x8706ec26, 0xe524651f, 0x3861cfa7, + 0x3e41a5b6, 0xe3040f0e, 0x81268637, 0x5c632c8f, + 0x45639445, 0x98263efd, 0xfa04b7c4, 0x27411d7c, + 0xc805c650, 0x15406ce8, 0x7762e5d1, 0xaa274f69, + 0xb327f7a3, 0x6e625d1b, 0x0c40d422, 0xd1057e9a, + 0xaba65fe7, 0x76e3f55f, 0x14c17c66, 0xc984d6de, + 0xd0846e14, 0x0dc1c4ac, 0x6fe34d95, 0xb2a6e72d, + 0x5de23c01, 0x80a796b9, 0xe2851f80, 0x3fc0b538, + 0x26c00df2, 0xfb85a74a, 0x99a72e73, 0x44e284cb, + 0x42c2eeda, 0x9f874462, 0xfda5cd5b, 0x20e067e3, + 0x39e0df29, 0xe4a57591, 0x8687fca8, 0x5bc25610, + 0xb4868d3c, 0x69c32784, 0x0be1aebd, 0xd6a40405, + 0xcfa4bccf, 0x12e11677, 0x70c39f4e, 0xad8635f6, + 0x7c834b6c, 0xa1c6e1d4, 0xc3e468ed, 0x1ea1c255, + 0x07a17a9f, 0xdae4d027, 0xb8c6591e, 0x6583f3a6, + 0x8ac7288a, 0x57828232, 0x35a00b0b, 0xe8e5a1b3, + 0xf1e51979, 0x2ca0b3c1, 0x4e823af8, 0x93c79040, + 0x95e7fa51, 0x48a250e9, 0x2a80d9d0, 0xf7c57368, + 0xeec5cba2, 0x3380611a, 0x51a2e823, 0x8ce7429b, + 0x63a399b7, 0xbee6330f, 0xdcc4ba36, 0x0181108e, + 0x1881a844, 0xc5c402fc, 0xa7e68bc5, 0x7aa3217d, + 0x52a0c93f, 0x8fe56387, 0xedc7eabe, 0x30824006, + 0x2982f8cc, 0xf4c75274, 0x96e5db4d, 0x4ba071f5, + 0xa4e4aad9, 0x79a10061, 0x1b838958, 0xc6c623e0, + 0xdfc69b2a, 0x02833192, 0x60a1b8ab, 0xbde41213, + 0xbbc47802, 0x6681d2ba, 0x04a35b83, 0xd9e6f13b, + 0xc0e649f1, 0x1da3e349, 0x7f816a70, 0xa2c4c0c8, + 0x4d801be4, 0x90c5b15c, 0xf2e73865, 0x2fa292dd, + 0x36a22a17, 0xebe780af, 0x89c50996, 0x5480a32e, + 0x8585ddb4, 0x58c0770c, 0x3ae2fe35, 0xe7a7548d, + 0xfea7ec47, 0x23e246ff, 0x41c0cfc6, 0x9c85657e, + 0x73c1be52, 0xae8414ea, 0xcca69dd3, 0x11e3376b, + 0x08e38fa1, 0xd5a62519, 0xb784ac20, 0x6ac10698, + 0x6ce16c89, 0xb1a4c631, 0xd3864f08, 0x0ec3e5b0, + 0x17c35d7a, 0xca86f7c2, 0xa8a47efb, 0x75e1d443, + 0x9aa50f6f, 0x47e0a5d7, 0x25c22cee, 0xf8878656, + 0xe1873e9c, 0x3cc29424, 0x5ee01d1d, 0x83a5b7a5, + 0xf90696d8, 0x24433c60, 0x4661b559, 0x9b241fe1, + 0x8224a72b, 0x5f610d93, 0x3d4384aa, 0xe0062e12, + 0x0f42f53e, 0xd2075f86, 0xb025d6bf, 0x6d607c07, + 0x7460c4cd, 0xa9256e75, 0xcb07e74c, 0x16424df4, + 0x106227e5, 0xcd278d5d, 0xaf050464, 0x7240aedc, + 0x6b401616, 0xb605bcae, 0xd4273597, 0x09629f2f, + 0xe6264403, 0x3b63eebb, 0x59416782, 0x8404cd3a, + 0x9d0475f0, 0x4041df48, 0x22635671, 0xff26fcc9, + 0x2e238253, 0xf36628eb, 0x9144a1d2, 0x4c010b6a, + 0x5501b3a0, 0x88441918, 0xea669021, 0x37233a99, + 0xd867e1b5, 0x05224b0d, 0x6700c234, 0xba45688c, + 0xa345d046, 0x7e007afe, 0x1c22f3c7, 0xc167597f, + 0xc747336e, 0x1a0299d6, 0x782010ef, 0xa565ba57, + 0xbc65029d, 0x6120a825, 0x0302211c, 0xde478ba4, + 0x31035088, 0xec46fa30, 0x8e647309, 0x5321d9b1, + 0x4a21617b, 0x9764cbc3, 0xf54642fa, 0x2803e842 +}; + +// Used to fetch a naturally-aligned 32-bit word in little endian byte-order +static inline uint32_t LE_LOAD32(const uint8_t *p) { + return DecodeFixed32(reinterpret_cast<const char*>(p)); +} + +#if defined(HAVE_SSE42) && (SIZEOF_SIZE_T == 8) +static inline uint64_t LE_LOAD64(const uint8_t *p) { + return DecodeFixed64(reinterpret_cast<const char*>(p)); +} +#endif + +static inline void Slow_CRC32(uint64_t* l, uint8_t const **p) { + uint32_t c = static_cast<uint32_t>(*l ^ LE_LOAD32(*p)); + *p += 4; + *l = table3_[c & 0xff] ^ + table2_[(c >> 8) & 0xff] ^ + table1_[(c >> 16) & 0xff] ^ + table0_[c >> 24]; + // DO it twice. + c = static_cast<uint32_t>(*l ^ LE_LOAD32(*p)); + *p += 4; + *l = table3_[c & 0xff] ^ + table2_[(c >> 8) & 0xff] ^ + table1_[(c >> 16) & 0xff] ^ + table0_[c >> 24]; +} + +static inline void Fast_CRC32(uint64_t* l, uint8_t const **p) { +#ifndef HAVE_SSE42 + Slow_CRC32(l, p); +#elif (SIZEOF_SIZE_T == 8) + *l = _mm_crc32_u64(*l, LE_LOAD64(*p)); + *p += 8; +#else + *l = _mm_crc32_u32(static_cast<unsigned int>(*l), LE_LOAD32(*p)); + *p += 4; + *l = _mm_crc32_u32(static_cast<unsigned int>(*l), LE_LOAD32(*p)); + *p += 4; +#endif +} + +template<void (*CRC32)(uint64_t*, uint8_t const**)> +uint32_t ExtendImpl(uint32_t crc, const char* buf, size_t size) { + + const uint8_t *p = reinterpret_cast<const uint8_t *>(buf); + const uint8_t *e = p + size; + uint64_t l = crc ^ 0xffffffffu; + +// Align n to (1 << m) byte boundary +#define ALIGN(n, m) ((n + ((1 << m) - 1)) & ~((1 << m) - 1)) + +#define STEP1 do { \ + int c = (l & 0xff) ^ *p++; \ + l = table0_[c] ^ (l >> 8); \ +} while (0) + + + // Point x at first 16-byte aligned byte in string. This might be + // just past the end of the string. + const uintptr_t pval = reinterpret_cast<uintptr_t>(p); + const uint8_t* x = reinterpret_cast<const uint8_t*>(ALIGN(pval, 4)); + if (x <= e) { + // Process bytes until finished or p is 16-byte aligned + while (p != x) { + STEP1; + } + } + // Process bytes 16 at a time + while ((e-p) >= 16) { + CRC32(&l, &p); + CRC32(&l, &p); + } + // Process bytes 8 at a time + while ((e-p) >= 8) { + CRC32(&l, &p); + } + // Process the last few bytes + while (p != e) { + STEP1; + } +#undef STEP1 +#undef ALIGN + return static_cast<uint32_t>(l ^ 0xffffffffu); +} + +// Detect if ARM64 CRC or not. +#ifndef HAVE_ARMV8_CRC +// Detect if SS42 or not. +#ifndef HAVE_POWER8 + +static bool isSSE42() { +#ifndef HAVE_SSE42 + return false; +#elif defined(__GNUC__) + uint32_t reax= 0, rebx= 0, recx= 0, redx= 0; + __cpuid(1, reax, rebx, recx, redx); + return (recx & ((int)1 << 20)) != 0; +#elif defined(_MSC_VER) + int info[4]; + __cpuid(info, 0x00000001); + return (info[2] & ((int)1 << 20)) != 0; +#else + return false; +#endif +} + +#ifdef HAVE_SSE42 +extern "C" int crc32_pclmul_enabled(); +#endif + +static bool isPCLMULQDQ() { +#ifdef HAVE_SSE42 + return crc32_pclmul_enabled(); +#else + return false; +#endif +} + +#endif // HAVE_POWER8 +#endif // HAVE_ARMV8_CRC + +typedef uint32_t (*Function)(uint32_t, const char*, size_t); + +#if defined(HAVE_POWER8) && defined(HAS_ALTIVEC) +uint32_t ExtendPPCImpl(uint32_t crc, const char *buf, size_t size) { + return crc32c_ppc(crc, (const unsigned char *)buf, size); +} + +#if __linux__ +static int arch_ppc_probe(void) { + arch_ppc_crc32 = 0; + +#if defined(__powerpc64__) + if (getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) arch_ppc_crc32 = 1; +#endif /* __powerpc64__ */ + + return arch_ppc_crc32; +} +#endif // __linux__ + +static bool isAltiVec() { + if (arch_ppc_probe()) { + return true; + } else { + return false; + } +} +#endif + +#if defined(HAVE_ARMV8_CRC) +extern "C" const char *crc32c_aarch64_available(void); +extern "C" uint32_t crc32c_aarch64(uint32_t crc, const unsigned char *buffer, uint64_t len); + +static uint32_t ExtendARMImpl(uint32_t crc, const char *buf, size_t size) { + return crc32c_aarch64(crc, (const unsigned char *)buf, (size_t) size); +} +#endif + +extern "C" const char * my_crc32c_implementation() +{ +#if defined(HAVE_POWER8) && defined(HAS_ALTIVEC) + if (arch_ppc_probe()) + return "Using POWER8 crc32 instructions"; +#elif defined(HAVE_ARMV8_CRC) + const char *ret = crc32c_aarch64_available(); + if (ret) + return ret ; +#elif HAVE_SSE42 + if (isSSE42()) + { + if (SIZEOF_SIZE_T == 8 && isPCLMULQDQ()) + return "Using crc32 + pclmulqdq instructions"; + return "Using SSE4.2 crc32 instructions"; + } +#endif + return "Using generic crc32 instructions"; +} + + +/* + * Copyright 2016 Ferry Toth, Exalon Delft BV, The Netherlands + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the author be held liable for any damages + * arising from the use of this software. + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * Ferry Toth + * ftoth@exalondelft.nl + * + * https://github.com/htot/crc32c + * + * Modified by Facebook + * + * Original intel whitepaper: + * "Fast CRC Computation for iSCSI Polynomial Using CRC32 Instruction" + * https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/crc-iscsi-polynomial-crc32-instruction-paper.pdf + * + * This version is from the folly library, created by Dave Watson <davejwatson@fb.com> + * +*/ +#if defined HAVE_SSE42 && defined HAVE_PCLMUL && SIZEOF_SIZE_T == 8 + + +#define CRCtriplet(crc, buf, offset) \ + crc##0 = _mm_crc32_u64(crc##0, *(buf##0 + offset)); \ + crc##1 = _mm_crc32_u64(crc##1, *(buf##1 + offset)); \ + crc##2 = _mm_crc32_u64(crc##2, *(buf##2 + offset)); + +#define CRCduplet(crc, buf, offset) \ + crc##0 = _mm_crc32_u64(crc##0, *(buf##0 + offset)); \ + crc##1 = _mm_crc32_u64(crc##1, *(buf##1 + offset)); + +#define CRCsinglet(crc, buf, offset) \ + crc = _mm_crc32_u64(crc, *(uint64_t*)(buf + offset)); + + +// Numbers taken directly from intel whitepaper. +// clang-format off +static const uint64_t clmul_constants[] = { + 0x14cd00bd6, 0x105ec76f0, 0x0ba4fc28e, 0x14cd00bd6, + 0x1d82c63da, 0x0f20c0dfe, 0x09e4addf8, 0x0ba4fc28e, + 0x039d3b296, 0x1384aa63a, 0x102f9b8a2, 0x1d82c63da, + 0x14237f5e6, 0x01c291d04, 0x00d3b6092, 0x09e4addf8, + 0x0c96cfdc0, 0x0740eef02, 0x18266e456, 0x039d3b296, + 0x0daece73e, 0x0083a6eec, 0x0ab7aff2a, 0x102f9b8a2, + 0x1248ea574, 0x1c1733996, 0x083348832, 0x14237f5e6, + 0x12c743124, 0x02ad91c30, 0x0b9e02b86, 0x00d3b6092, + 0x018b33a4e, 0x06992cea2, 0x1b331e26a, 0x0c96cfdc0, + 0x17d35ba46, 0x07e908048, 0x1bf2e8b8a, 0x18266e456, + 0x1a3e0968a, 0x11ed1f9d8, 0x0ce7f39f4, 0x0daece73e, + 0x061d82e56, 0x0f1d0f55e, 0x0d270f1a2, 0x0ab7aff2a, + 0x1c3f5f66c, 0x0a87ab8a8, 0x12ed0daac, 0x1248ea574, + 0x065863b64, 0x08462d800, 0x11eef4f8e, 0x083348832, + 0x1ee54f54c, 0x071d111a8, 0x0b3e32c28, 0x12c743124, + 0x0064f7f26, 0x0ffd852c6, 0x0dd7e3b0c, 0x0b9e02b86, + 0x0f285651c, 0x0dcb17aa4, 0x010746f3c, 0x018b33a4e, + 0x1c24afea4, 0x0f37c5aee, 0x0271d9844, 0x1b331e26a, + 0x08e766a0c, 0x06051d5a2, 0x093a5f730, 0x17d35ba46, + 0x06cb08e5c, 0x11d5ca20e, 0x06b749fb2, 0x1bf2e8b8a, + 0x1167f94f2, 0x021f3d99c, 0x0cec3662e, 0x1a3e0968a, + 0x19329634a, 0x08f158014, 0x0e6fc4e6a, 0x0ce7f39f4, + 0x08227bb8a, 0x1a5e82106, 0x0b0cd4768, 0x061d82e56, + 0x13c2b89c4, 0x188815ab2, 0x0d7a4825c, 0x0d270f1a2, + 0x10f5ff2ba, 0x105405f3e, 0x00167d312, 0x1c3f5f66c, + 0x0f6076544, 0x0e9adf796, 0x026f6a60a, 0x12ed0daac, + 0x1a2adb74e, 0x096638b34, 0x19d34af3a, 0x065863b64, + 0x049c3cc9c, 0x1e50585a0, 0x068bce87a, 0x11eef4f8e, + 0x1524fa6c6, 0x19f1c69dc, 0x16cba8aca, 0x1ee54f54c, + 0x042d98888, 0x12913343e, 0x1329d9f7e, 0x0b3e32c28, + 0x1b1c69528, 0x088f25a3a, 0x02178513a, 0x0064f7f26, + 0x0e0ac139e, 0x04e36f0b0, 0x0170076fa, 0x0dd7e3b0c, + 0x141a1a2e2, 0x0bd6f81f8, 0x16ad828b4, 0x0f285651c, + 0x041d17b64, 0x19425cbba, 0x1fae1cc66, 0x010746f3c, + 0x1a75b4b00, 0x18db37e8a, 0x0f872e54c, 0x1c24afea4, + 0x01e41e9fc, 0x04c144932, 0x086d8e4d2, 0x0271d9844, + 0x160f7af7a, 0x052148f02, 0x05bb8f1bc, 0x08e766a0c, + 0x0a90fd27a, 0x0a3c6f37a, 0x0b3af077a, 0x093a5f730, + 0x04984d782, 0x1d22c238e, 0x0ca6ef3ac, 0x06cb08e5c, + 0x0234e0b26, 0x063ded06a, 0x1d88abd4a, 0x06b749fb2, + 0x04597456a, 0x04d56973c, 0x0e9e28eb4, 0x1167f94f2, + 0x07b3ff57a, 0x19385bf2e, 0x0c9c8b782, 0x0cec3662e, + 0x13a9cba9e, 0x0e417f38a, 0x093e106a4, 0x19329634a, + 0x167001a9c, 0x14e727980, 0x1ddffc5d4, 0x0e6fc4e6a, + 0x00df04680, 0x0d104b8fc, 0x02342001e, 0x08227bb8a, + 0x00a2a8d7e, 0x05b397730, 0x168763fa6, 0x0b0cd4768, + 0x1ed5a407a, 0x0e78eb416, 0x0d2c3ed1a, 0x13c2b89c4, + 0x0995a5724, 0x1641378f0, 0x19b1afbc4, 0x0d7a4825c, + 0x109ffedc0, 0x08d96551c, 0x0f2271e60, 0x10f5ff2ba, + 0x00b0bf8ca, 0x00bf80dd2, 0x123888b7a, 0x00167d312, + 0x1e888f7dc, 0x18dcddd1c, 0x002ee03b2, 0x0f6076544, + 0x183e8d8fe, 0x06a45d2b2, 0x133d7a042, 0x026f6a60a, + 0x116b0f50c, 0x1dd3e10e8, 0x05fabe670, 0x1a2adb74e, + 0x130004488, 0x0de87806c, 0x000bcf5f6, 0x19d34af3a, + 0x18f0c7078, 0x014338754, 0x017f27698, 0x049c3cc9c, + 0x058ca5f00, 0x15e3e77ee, 0x1af900c24, 0x068bce87a, + 0x0b5cfca28, 0x0dd07448e, 0x0ded288f8, 0x1524fa6c6, + 0x059f229bc, 0x1d8048348, 0x06d390dec, 0x16cba8aca, + 0x037170390, 0x0a3e3e02c, 0x06353c1cc, 0x042d98888, + 0x0c4584f5c, 0x0d73c7bea, 0x1f16a3418, 0x1329d9f7e, + 0x0531377e2, 0x185137662, 0x1d8d9ca7c, 0x1b1c69528, + 0x0b25b29f2, 0x18a08b5bc, 0x19fb2a8b0, 0x02178513a, + 0x1a08fe6ac, 0x1da758ae0, 0x045cddf4e, 0x0e0ac139e, + 0x1a91647f2, 0x169cf9eb0, 0x1a0f717c4, 0x0170076fa, +}; + +// Compute the crc32c value for buffer smaller than 8 +static inline void align_to_8( + size_t len, + uint64_t& crc0, // crc so far, updated on return + const unsigned char*& next) { // next data pointer, updated on return + uint32_t crc32bit = static_cast<uint32_t>(crc0); + if (len & 0x04) { + crc32bit = _mm_crc32_u32(crc32bit, *(uint32_t*)next); + next += sizeof(uint32_t); + } + if (len & 0x02) { + crc32bit = _mm_crc32_u16(crc32bit, *(uint16_t*)next); + next += sizeof(uint16_t); + } + if (len & 0x01) { + crc32bit = _mm_crc32_u8(crc32bit, *(next)); + next++; + } + crc0 = crc32bit; +} + +// +// CombineCRC performs pclmulqdq multiplication of 2 partial CRC's and a well +// chosen constant and xor's these with the remaining CRC. +// +static inline uint64_t CombineCRC( + size_t block_size, + uint64_t crc0, + uint64_t crc1, + uint64_t crc2, + const uint64_t* next2) { + const auto multiplier = + *(reinterpret_cast<const __m128i*>(clmul_constants) + block_size - 1); + const auto crc0_xmm = _mm_set_epi64x(0, crc0); + const auto res0 = _mm_clmulepi64_si128(crc0_xmm, multiplier, 0x00); + const auto crc1_xmm = _mm_set_epi64x(0, crc1); + const auto res1 = _mm_clmulepi64_si128(crc1_xmm, multiplier, 0x10); + const auto res = _mm_xor_si128(res0, res1); + crc0 = _mm_cvtsi128_si64(res); + crc0 = crc0 ^ *((uint64_t*)next2 - 1); + crc2 = _mm_crc32_u64(crc2, crc0); + return crc2; +} + +// Compute CRC-32C using the Intel hardware instruction. +static inline uint32_t crc32c_3way(uint32_t crc, const char* buf, size_t len) { + const unsigned char* next = (const unsigned char*)buf; + uint64_t count; + uint64_t crc0, crc1, crc2; + crc0 = crc ^ 0xffffffffu; + + + if (len >= 8) { + // if len > 216 then align and use triplets + if (len > 216) { + { + // Work on the bytes (< 8) before the first 8-byte alignment addr starts + auto align_bytes = (8 - (uintptr_t)next) & 7; + len -= align_bytes; + align_to_8(align_bytes, crc0, next); + } + + // Now work on the remaining blocks + count = len / 24; // number of triplets + len %= 24; // bytes remaining + uint64_t n = count >> 7; // #blocks = first block + full blocks + uint64_t block_size = count & 127; + if (block_size == 0) { + block_size = 128; + } else { + n++; + } + // points to the first byte of the next block + const uint64_t* next0 = (uint64_t*)next + block_size; + const uint64_t* next1 = next0 + block_size; + const uint64_t* next2 = next1 + block_size; + + crc1 = crc2 = 0; + // Use Duff's device, a for() loop inside a switch() + // statement. This needs to execute at least once, round len + // down to nearest triplet multiple + switch (block_size) { + case 128: + do { + // jumps here for a full block of len 128 + CRCtriplet(crc, next, -128); + /* fallthrough */ + case 127: + // jumps here or below for the first block smaller + CRCtriplet(crc, next, -127); + /* fallthrough */ + case 126: + CRCtriplet(crc, next, -126); // than 128 + /* fallthrough */ + case 125: + CRCtriplet(crc, next, -125); + /* fallthrough */ + case 124: + CRCtriplet(crc, next, -124); + /* fallthrough */ + case 123: + CRCtriplet(crc, next, -123); + /* fallthrough */ + case 122: + CRCtriplet(crc, next, -122); + /* fallthrough */ + case 121: + CRCtriplet(crc, next, -121); + /* fallthrough */ + case 120: + CRCtriplet(crc, next, -120); + /* fallthrough */ + case 119: + CRCtriplet(crc, next, -119); + /* fallthrough */ + case 118: + CRCtriplet(crc, next, -118); + /* fallthrough */ + case 117: + CRCtriplet(crc, next, -117); + /* fallthrough */ + case 116: + CRCtriplet(crc, next, -116); + /* fallthrough */ + case 115: + CRCtriplet(crc, next, -115); + /* fallthrough */ + case 114: + CRCtriplet(crc, next, -114); + /* fallthrough */ + case 113: + CRCtriplet(crc, next, -113); + /* fallthrough */ + case 112: + CRCtriplet(crc, next, -112); + /* fallthrough */ + case 111: + CRCtriplet(crc, next, -111); + /* fallthrough */ + case 110: + CRCtriplet(crc, next, -110); + /* fallthrough */ + case 109: + CRCtriplet(crc, next, -109); + /* fallthrough */ + case 108: + CRCtriplet(crc, next, -108); + /* fallthrough */ + case 107: + CRCtriplet(crc, next, -107); + /* fallthrough */ + case 106: + CRCtriplet(crc, next, -106); + /* fallthrough */ + case 105: + CRCtriplet(crc, next, -105); + /* fallthrough */ + case 104: + CRCtriplet(crc, next, -104); + /* fallthrough */ + case 103: + CRCtriplet(crc, next, -103); + /* fallthrough */ + case 102: + CRCtriplet(crc, next, -102); + /* fallthrough */ + case 101: + CRCtriplet(crc, next, -101); + /* fallthrough */ + case 100: + CRCtriplet(crc, next, -100); + /* fallthrough */ + case 99: + CRCtriplet(crc, next, -99); + /* fallthrough */ + case 98: + CRCtriplet(crc, next, -98); + /* fallthrough */ + case 97: + CRCtriplet(crc, next, -97); + /* fallthrough */ + case 96: + CRCtriplet(crc, next, -96); + /* fallthrough */ + case 95: + CRCtriplet(crc, next, -95); + /* fallthrough */ + case 94: + CRCtriplet(crc, next, -94); + /* fallthrough */ + case 93: + CRCtriplet(crc, next, -93); + /* fallthrough */ + case 92: + CRCtriplet(crc, next, -92); + /* fallthrough */ + case 91: + CRCtriplet(crc, next, -91); + /* fallthrough */ + case 90: + CRCtriplet(crc, next, -90); + /* fallthrough */ + case 89: + CRCtriplet(crc, next, -89); + /* fallthrough */ + case 88: + CRCtriplet(crc, next, -88); + /* fallthrough */ + case 87: + CRCtriplet(crc, next, -87); + /* fallthrough */ + case 86: + CRCtriplet(crc, next, -86); + /* fallthrough */ + case 85: + CRCtriplet(crc, next, -85); + /* fallthrough */ + case 84: + CRCtriplet(crc, next, -84); + /* fallthrough */ + case 83: + CRCtriplet(crc, next, -83); + /* fallthrough */ + case 82: + CRCtriplet(crc, next, -82); + /* fallthrough */ + case 81: + CRCtriplet(crc, next, -81); + /* fallthrough */ + case 80: + CRCtriplet(crc, next, -80); + /* fallthrough */ + case 79: + CRCtriplet(crc, next, -79); + /* fallthrough */ + case 78: + CRCtriplet(crc, next, -78); + /* fallthrough */ + case 77: + CRCtriplet(crc, next, -77); + /* fallthrough */ + case 76: + CRCtriplet(crc, next, -76); + /* fallthrough */ + case 75: + CRCtriplet(crc, next, -75); + /* fallthrough */ + case 74: + CRCtriplet(crc, next, -74); + /* fallthrough */ + case 73: + CRCtriplet(crc, next, -73); + /* fallthrough */ + case 72: + CRCtriplet(crc, next, -72); + /* fallthrough */ + case 71: + CRCtriplet(crc, next, -71); + /* fallthrough */ + case 70: + CRCtriplet(crc, next, -70); + /* fallthrough */ + case 69: + CRCtriplet(crc, next, -69); + /* fallthrough */ + case 68: + CRCtriplet(crc, next, -68); + /* fallthrough */ + case 67: + CRCtriplet(crc, next, -67); + /* fallthrough */ + case 66: + CRCtriplet(crc, next, -66); + /* fallthrough */ + case 65: + CRCtriplet(crc, next, -65); + /* fallthrough */ + case 64: + CRCtriplet(crc, next, -64); + /* fallthrough */ + case 63: + CRCtriplet(crc, next, -63); + /* fallthrough */ + case 62: + CRCtriplet(crc, next, -62); + /* fallthrough */ + case 61: + CRCtriplet(crc, next, -61); + /* fallthrough */ + case 60: + CRCtriplet(crc, next, -60); + /* fallthrough */ + case 59: + CRCtriplet(crc, next, -59); + /* fallthrough */ + case 58: + CRCtriplet(crc, next, -58); + /* fallthrough */ + case 57: + CRCtriplet(crc, next, -57); + /* fallthrough */ + case 56: + CRCtriplet(crc, next, -56); + /* fallthrough */ + case 55: + CRCtriplet(crc, next, -55); + /* fallthrough */ + case 54: + CRCtriplet(crc, next, -54); + /* fallthrough */ + case 53: + CRCtriplet(crc, next, -53); + /* fallthrough */ + case 52: + CRCtriplet(crc, next, -52); + /* fallthrough */ + case 51: + CRCtriplet(crc, next, -51); + /* fallthrough */ + case 50: + CRCtriplet(crc, next, -50); + /* fallthrough */ + case 49: + CRCtriplet(crc, next, -49); + /* fallthrough */ + case 48: + CRCtriplet(crc, next, -48); + /* fallthrough */ + case 47: + CRCtriplet(crc, next, -47); + /* fallthrough */ + case 46: + CRCtriplet(crc, next, -46); + /* fallthrough */ + case 45: + CRCtriplet(crc, next, -45); + /* fallthrough */ + case 44: + CRCtriplet(crc, next, -44); + /* fallthrough */ + case 43: + CRCtriplet(crc, next, -43); + /* fallthrough */ + case 42: + CRCtriplet(crc, next, -42); + /* fallthrough */ + case 41: + CRCtriplet(crc, next, -41); + /* fallthrough */ + case 40: + CRCtriplet(crc, next, -40); + /* fallthrough */ + case 39: + CRCtriplet(crc, next, -39); + /* fallthrough */ + case 38: + CRCtriplet(crc, next, -38); + /* fallthrough */ + case 37: + CRCtriplet(crc, next, -37); + /* fallthrough */ + case 36: + CRCtriplet(crc, next, -36); + /* fallthrough */ + case 35: + CRCtriplet(crc, next, -35); + /* fallthrough */ + case 34: + CRCtriplet(crc, next, -34); + /* fallthrough */ + case 33: + CRCtriplet(crc, next, -33); + /* fallthrough */ + case 32: + CRCtriplet(crc, next, -32); + /* fallthrough */ + case 31: + CRCtriplet(crc, next, -31); + /* fallthrough */ + case 30: + CRCtriplet(crc, next, -30); + /* fallthrough */ + case 29: + CRCtriplet(crc, next, -29); + /* fallthrough */ + case 28: + CRCtriplet(crc, next, -28); + /* fallthrough */ + case 27: + CRCtriplet(crc, next, -27); + /* fallthrough */ + case 26: + CRCtriplet(crc, next, -26); + /* fallthrough */ + case 25: + CRCtriplet(crc, next, -25); + /* fallthrough */ + case 24: + CRCtriplet(crc, next, -24); + /* fallthrough */ + case 23: + CRCtriplet(crc, next, -23); + /* fallthrough */ + case 22: + CRCtriplet(crc, next, -22); + /* fallthrough */ + case 21: + CRCtriplet(crc, next, -21); + /* fallthrough */ + case 20: + CRCtriplet(crc, next, -20); + /* fallthrough */ + case 19: + CRCtriplet(crc, next, -19); + /* fallthrough */ + case 18: + CRCtriplet(crc, next, -18); + /* fallthrough */ + case 17: + CRCtriplet(crc, next, -17); + /* fallthrough */ + case 16: + CRCtriplet(crc, next, -16); + /* fallthrough */ + case 15: + CRCtriplet(crc, next, -15); + /* fallthrough */ + case 14: + CRCtriplet(crc, next, -14); + /* fallthrough */ + case 13: + CRCtriplet(crc, next, -13); + /* fallthrough */ + case 12: + CRCtriplet(crc, next, -12); + /* fallthrough */ + case 11: + CRCtriplet(crc, next, -11); + /* fallthrough */ + case 10: + CRCtriplet(crc, next, -10); + /* fallthrough */ + case 9: + CRCtriplet(crc, next, -9); + /* fallthrough */ + case 8: + CRCtriplet(crc, next, -8); + /* fallthrough */ + case 7: + CRCtriplet(crc, next, -7); + /* fallthrough */ + case 6: + CRCtriplet(crc, next, -6); + /* fallthrough */ + case 5: + CRCtriplet(crc, next, -5); + /* fallthrough */ + case 4: + CRCtriplet(crc, next, -4); + /* fallthrough */ + case 3: + CRCtriplet(crc, next, -3); + /* fallthrough */ + case 2: + CRCtriplet(crc, next, -2); + /* fallthrough */ + case 1: + CRCduplet(crc, next, -1); // the final triplet is actually only 2 + //{ CombineCRC(); } + crc0 = CombineCRC(block_size, crc0, crc1, crc2, next2); + if (--n > 0) { + crc1 = crc2 = 0; + block_size = 128; + // points to the first byte of the next block + next0 = next2 + 128; + next1 = next0 + 128; // from here on all blocks are 128 long + next2 = next1 + 128; + } + /* fallthrough */ + case 0:; + } while (n > 0); + } + next = (const unsigned char*)next2; + } + uint64_t count2 = len >> 3; // 216 of less bytes is 27 or less singlets + len = len & 7; + next += (count2 * 8); + switch (count2) { + case 27: + CRCsinglet(crc0, next, -27 * 8); + /* fallthrough */ + case 26: + CRCsinglet(crc0, next, -26 * 8); + /* fallthrough */ + case 25: + CRCsinglet(crc0, next, -25 * 8); + /* fallthrough */ + case 24: + CRCsinglet(crc0, next, -24 * 8); + /* fallthrough */ + case 23: + CRCsinglet(crc0, next, -23 * 8); + /* fallthrough */ + case 22: + CRCsinglet(crc0, next, -22 * 8); + /* fallthrough */ + case 21: + CRCsinglet(crc0, next, -21 * 8); + /* fallthrough */ + case 20: + CRCsinglet(crc0, next, -20 * 8); + /* fallthrough */ + case 19: + CRCsinglet(crc0, next, -19 * 8); + /* fallthrough */ + case 18: + CRCsinglet(crc0, next, -18 * 8); + /* fallthrough */ + case 17: + CRCsinglet(crc0, next, -17 * 8); + /* fallthrough */ + case 16: + CRCsinglet(crc0, next, -16 * 8); + /* fallthrough */ + case 15: + CRCsinglet(crc0, next, -15 * 8); + /* fallthrough */ + case 14: + CRCsinglet(crc0, next, -14 * 8); + /* fallthrough */ + case 13: + CRCsinglet(crc0, next, -13 * 8); + /* fallthrough */ + case 12: + CRCsinglet(crc0, next, -12 * 8); + /* fallthrough */ + case 11: + CRCsinglet(crc0, next, -11 * 8); + /* fallthrough */ + case 10: + CRCsinglet(crc0, next, -10 * 8); + /* fallthrough */ + case 9: + CRCsinglet(crc0, next, -9 * 8); + /* fallthrough */ + case 8: + CRCsinglet(crc0, next, -8 * 8); + /* fallthrough */ + case 7: + CRCsinglet(crc0, next, -7 * 8); + /* fallthrough */ + case 6: + CRCsinglet(crc0, next, -6 * 8); + /* fallthrough */ + case 5: + CRCsinglet(crc0, next, -5 * 8); + /* fallthrough */ + case 4: + CRCsinglet(crc0, next, -4 * 8); + /* fallthrough */ + case 3: + CRCsinglet(crc0, next, -3 * 8); + /* fallthrough */ + case 2: + CRCsinglet(crc0, next, -2 * 8); + /* fallthrough */ + case 1: + CRCsinglet(crc0, next, -1 * 8); + /* fallthrough */ + case 0:; + } + } + { + align_to_8(len, crc0, next); + return (uint32_t)crc0 ^ 0xffffffffu; + } +} + +#else +#define NO_THREEWAY_CRC32C +#endif //HAVE_SSE42 && HAVE_PCLMUL + +static inline Function Choose_Extend() { +#ifdef HAVE_POWER8 + return isAltiVec() ? ExtendPPCImpl : ExtendImpl<Slow_CRC32>; +#elif defined(HAVE_ARMV8_CRC) + if(crc32c_aarch64_available()) { + return ExtendARMImpl; + } else { + return ExtendImpl<Slow_CRC32>; + } +#else + if (isSSE42()) { + if (isPCLMULQDQ()) { +#if defined HAVE_SSE42 && defined HAVE_PCLMUL && !defined NO_THREEWAY_CRC32C + return crc32c_3way; +#else + return ExtendImpl<Fast_CRC32>; // Fast_CRC32 will check HAVE_SSE42 itself +#endif + } + else { // no runtime PCLMULQDQ support but has SSE42 support + return ExtendImpl<Fast_CRC32>; + } + } // end of isSSE42() + else { + return ExtendImpl<Slow_CRC32>; + } +#endif +} + +static const Function ChosenExtend = Choose_Extend(); + +static inline uint32_t Extend(uint32_t crc, const char* buf, size_t size) { + return ChosenExtend(crc, buf, size); +} +} // namespace crc32c +} // namespace mysys_namespace + +extern "C" unsigned int my_crc32c(unsigned int crc, const char *buf, size_t size) +{ + return mysys_namespace::crc32c::Extend(crc,buf, size); +} diff --git a/mysys/crc32/crc32c_ppc.c b/mysys/crc32/crc32c_ppc.c new file mode 100644 index 00000000000..72f24283454 --- /dev/null +++ b/mysys/crc32/crc32c_ppc.c @@ -0,0 +1,5 @@ +#define CRC32_FUNCTION crc32c_ppc +#define CRC_TABLE +#define POWER8_INTRINSICS +#include "pcc_crc32c_constants.h" +#include "crc_ppc64.h" diff --git a/mysys/crc32/crc32c_ppc.h b/mysys/crc32/crc32c_ppc.h new file mode 100644 index 00000000000..c359061c610 --- /dev/null +++ b/mysys/crc32/crc32c_ppc.h @@ -0,0 +1,19 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. +// Copyright (c) 2017 International Business Machines Corp. +// All rights reserved. +// This source code is licensed under both the GPLv2 (found in the +// COPYING file in the root directory) and Apache 2.0 License +// (found in the LICENSE.Apache file in the root directory). + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t crc32c_ppc(uint32_t crc, unsigned char const *buffer, + unsigned len); + +#ifdef __cplusplus +} +#endif diff --git a/mysys/crc32/crc_ppc64.h b/mysys/crc32/crc_ppc64.h new file mode 100644 index 00000000000..eb9379abc6c --- /dev/null +++ b/mysys/crc32/crc_ppc64.h @@ -0,0 +1,664 @@ +/* + * Calculate the checksum of data that is 16 byte aligned and a multiple of + * 16 bytes. + * + * The first step is to reduce it to 1024 bits. We do this in 8 parallel + * chunks in order to mask the latency of the vpmsum instructions. If we + * have more than 32 kB of data to checksum we repeat this step multiple + * times, passing in the previous 1024 bits. + * + * The next step is to reduce the 1024 bits to 64 bits. This step adds + * 32 bits of 0s to the end - this matches what a CRC does. We just + * calculate constants that land the data in this 32 bits. + * + * We then use fixed point Barrett reduction to compute a mod n over GF(2) + * for n = CRC using POWER8 instructions. We use x = 32. + * + * http://en.wikipedia.org/wiki/Barrett_reduction + * + * This code uses gcc vector builtins instead using assembly directly. + * + * Copyright (C) 2017 Rogerio Alves <rogealve@br.ibm.com>, IBM + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of either: + * + * a) the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version, or + * b) the Apache License, Version 2.0 + */ + +#include <altivec.h> + + +#define VMX_ALIGN 16 +#define VMX_ALIGN_MASK (VMX_ALIGN-1) + +#ifdef REFLECT +static unsigned int crc32_align(unsigned int crc, const unsigned char *p, + unsigned long len) +{ + while (len--) + crc = crc_table[(crc ^ *p++) & 0xff] ^ (crc >> 8); + return crc; +} +#else +static unsigned int crc32_align(unsigned int crc, const unsigned char *p, + unsigned long len) +{ + while (len--) + crc = crc_table[((crc >> 24) ^ *p++) & 0xff] ^ (crc << 8); + return crc; +} +#endif + +static unsigned int __attribute__ ((aligned (32))) +__crc32_vpmsum(unsigned int crc, const void* p, unsigned long len); + + +unsigned int CRC32_FUNCTION(unsigned int crc, const unsigned char *p, + unsigned long len) +{ + unsigned int prealign; + unsigned int tail; + +#ifdef CRC_XOR + crc ^= 0xffffffff; +#endif + + if (len < VMX_ALIGN + VMX_ALIGN_MASK) { + crc = crc32_align(crc, p, len); + goto out; + } + + if ((unsigned long)p & VMX_ALIGN_MASK) { + prealign = VMX_ALIGN - ((unsigned long)p & VMX_ALIGN_MASK); + crc = crc32_align(crc, p, prealign); + len -= prealign; + p += prealign; + } + + crc = __crc32_vpmsum(crc, p, len & ~VMX_ALIGN_MASK); + + tail = len & VMX_ALIGN_MASK; + if (tail) { + p += len & ~VMX_ALIGN_MASK; + crc = crc32_align(crc, p, tail); + } + +out: +#ifdef CRC_XOR + crc ^= 0xffffffff; +#endif + + return crc; +} + +#if defined (__clang__) +#include "clang_workaround.h" +#else +#define __builtin_pack_vector(a, b) __builtin_pack_vector_int128 ((a), (b)) +#define __builtin_unpack_vector_0(a) __builtin_unpack_vector_int128 ((vector __int128_t)(a), 0) +#define __builtin_unpack_vector_1(a) __builtin_unpack_vector_int128 ((vector __int128_t)(a), 1) +#endif + +/* When we have a load-store in a single-dispatch group and address overlap + * such that foward is not allowed (load-hit-store) the group must be flushed. + * A group ending NOP prevents the flush. + */ +#define GROUP_ENDING_NOP asm("ori 2,2,0" ::: "memory") + +#if defined(__BIG_ENDIAN__) && defined (REFLECT) +#define BYTESWAP_DATA +#elif defined(__LITTLE_ENDIAN__) && !defined(REFLECT) +#define BYTESWAP_DATA +#endif + +#ifdef BYTESWAP_DATA +#define VEC_PERM(vr, va, vb, vc) vr = vec_perm(va, vb,\ + (__vector unsigned char) vc) +#if defined(__LITTLE_ENDIAN__) +/* Byte reverse permute constant LE. */ +static const __vector unsigned long long vperm_const + __attribute__ ((aligned(16))) = { 0x08090A0B0C0D0E0FUL, + 0x0001020304050607UL }; +#else +static const __vector unsigned long long vperm_const + __attribute__ ((aligned(16))) = { 0x0F0E0D0C0B0A0908UL, + 0X0706050403020100UL }; +#endif +#else +#define VEC_PERM(vr, va, vb, vc) +#endif + +static unsigned int __attribute__ ((aligned (32))) +__crc32_vpmsum(unsigned int crc, const void* p, unsigned long len) { + + const __vector unsigned long long vzero = {0,0}; + const __vector unsigned long long vones = {0xffffffffffffffffUL, + 0xffffffffffffffffUL}; + +#ifdef REFLECT + __vector unsigned char vsht_splat; + const __vector unsigned long long vmask_32bit = + (__vector unsigned long long)vec_sld((__vector unsigned char)vzero, + (__vector unsigned char)vones, 4); +#endif + + const __vector unsigned long long vmask_64bit = + (__vector unsigned long long)vec_sld((__vector unsigned char)vzero, + (__vector unsigned char)vones, 8); + + __vector unsigned long long vcrc; + + __vector unsigned long long vconst1, vconst2; + + /* vdata0-vdata7 will contain our data (p). */ + __vector unsigned long long vdata0, vdata1, vdata2, vdata3, vdata4, + vdata5, vdata6, vdata7; + + /* v0-v7 will contain our checksums */ + __vector unsigned long long v0 = {0,0}; + __vector unsigned long long v1 = {0,0}; + __vector unsigned long long v2 = {0,0}; + __vector unsigned long long v3 = {0,0}; + __vector unsigned long long v4 = {0,0}; + __vector unsigned long long v5 = {0,0}; + __vector unsigned long long v6 = {0,0}; + __vector unsigned long long v7 = {0,0}; + + + /* Vector auxiliary variables. */ + __vector unsigned long long va0, va1, va2, va3, va4, va5, va6, va7; + + unsigned int result = 0; + unsigned int offset; /* Constant table offset. */ + + unsigned long i; /* Counter. */ + unsigned long chunks; + + unsigned long block_size; + int next_block = 0; + + /* Align by 128 bits. The last 128 bit block will be processed at end. */ + unsigned long length = len & 0xFFFFFFFFFFFFFF80UL; + +#ifdef REFLECT + vcrc = (__vector unsigned long long)__builtin_pack_vector(0UL, crc); +#else + vcrc = (__vector unsigned long long)__builtin_pack_vector(crc, 0UL); + + /* Shift into top 32 bits */ + vcrc = (__vector unsigned long long)vec_sld((__vector unsigned char)vcrc, + (__vector unsigned char)vzero, 4); +#endif + + /* Short version. */ + if (len < 256) { + /* Calculate where in the constant table we need to start. */ + offset = 256 - len; + + vconst1 = vec_ld(offset, vcrc_short_const); + vdata0 = vec_ld(0, (__vector unsigned long long*) p); + VEC_PERM(vdata0, vdata0, vconst1, vperm_const); + + /* xor initial value*/ + vdata0 = vec_xor(vdata0, vcrc); + + vdata0 = (__vector unsigned long long) __builtin_crypto_vpmsumw + ((__vector unsigned int)vdata0, (__vector unsigned int)vconst1); + v0 = vec_xor(v0, vdata0); + + for (i = 16; i < len; i += 16) { + vconst1 = vec_ld(offset + i, vcrc_short_const); + vdata0 = vec_ld(i, (__vector unsigned long long*) p); + VEC_PERM(vdata0, vdata0, vconst1, vperm_const); + vdata0 = (__vector unsigned long long) __builtin_crypto_vpmsumw + ((__vector unsigned int)vdata0, (__vector unsigned int)vconst1); + v0 = vec_xor(v0, vdata0); + } + } else { + + /* Load initial values. */ + vdata0 = vec_ld(0, (__vector unsigned long long*) p); + vdata1 = vec_ld(16, (__vector unsigned long long*) p); + + VEC_PERM(vdata0, vdata0, vdata0, vperm_const); + VEC_PERM(vdata1, vdata1, vdata1, vperm_const); + + vdata2 = vec_ld(32, (__vector unsigned long long*) p); + vdata3 = vec_ld(48, (__vector unsigned long long*) p); + + VEC_PERM(vdata2, vdata2, vdata2, vperm_const); + VEC_PERM(vdata3, vdata3, vdata3, vperm_const); + + vdata4 = vec_ld(64, (__vector unsigned long long*) p); + vdata5 = vec_ld(80, (__vector unsigned long long*) p); + + VEC_PERM(vdata4, vdata4, vdata4, vperm_const); + VEC_PERM(vdata5, vdata5, vdata5, vperm_const); + + vdata6 = vec_ld(96, (__vector unsigned long long*) p); + vdata7 = vec_ld(112, (__vector unsigned long long*) p); + + VEC_PERM(vdata6, vdata6, vdata6, vperm_const); + VEC_PERM(vdata7, vdata7, vdata7, vperm_const); + + /* xor in initial value */ + vdata0 = vec_xor(vdata0, vcrc); + + p = (char *)p + 128; + + do { + /* Checksum in blocks of MAX_SIZE. */ + block_size = length; + if (block_size > MAX_SIZE) { + block_size = MAX_SIZE; + } + + length = length - block_size; + + /* + * Work out the offset into the constants table to start at. Each + * constant is 16 bytes, and it is used against 128 bytes of input + * data - 128 / 16 = 8 + */ + offset = (MAX_SIZE/8) - (block_size/8); + /* We reduce our final 128 bytes in a separate step */ + chunks = (block_size/128)-1; + + vconst1 = vec_ld(offset, vcrc_const); + + va0 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata0, + (__vector unsigned long long)vconst1); + va1 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata1, + (__vector unsigned long long)vconst1); + va2 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata2, + (__vector unsigned long long)vconst1); + va3 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata3, + (__vector unsigned long long)vconst1); + va4 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata4, + (__vector unsigned long long)vconst1); + va5 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata5, + (__vector unsigned long long)vconst1); + va6 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata6, + (__vector unsigned long long)vconst1); + va7 = __builtin_crypto_vpmsumd ((__vector unsigned long long)vdata7, + (__vector unsigned long long)vconst1); + + if (chunks > 1) { + offset += 16; + vconst2 = vec_ld(offset, vcrc_const); + GROUP_ENDING_NOP; + + vdata0 = vec_ld(0, (__vector unsigned long long*) p); + VEC_PERM(vdata0, vdata0, vdata0, vperm_const); + + vdata1 = vec_ld(16, (__vector unsigned long long*) p); + VEC_PERM(vdata1, vdata1, vdata1, vperm_const); + + vdata2 = vec_ld(32, (__vector unsigned long long*) p); + VEC_PERM(vdata2, vdata2, vdata2, vperm_const); + + vdata3 = vec_ld(48, (__vector unsigned long long*) p); + VEC_PERM(vdata3, vdata3, vdata3, vperm_const); + + vdata4 = vec_ld(64, (__vector unsigned long long*) p); + VEC_PERM(vdata4, vdata4, vdata4, vperm_const); + + vdata5 = vec_ld(80, (__vector unsigned long long*) p); + VEC_PERM(vdata5, vdata5, vdata5, vperm_const); + + vdata6 = vec_ld(96, (__vector unsigned long long*) p); + VEC_PERM(vdata6, vdata6, vdata6, vperm_const); + + vdata7 = vec_ld(112, (__vector unsigned long long*) p); + VEC_PERM(vdata7, vdata7, vdata7, vperm_const); + + p = (char *)p + 128; + + /* + * main loop. We modulo schedule it such that it takes three + * iterations to complete - first iteration load, second + * iteration vpmsum, third iteration xor. + */ + for (i = 0; i < chunks-2; i++) { + vconst1 = vec_ld(offset, vcrc_const); + offset += 16; + GROUP_ENDING_NOP; + + v0 = vec_xor(v0, va0); + va0 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata0, (__vector unsigned long long)vconst2); + vdata0 = vec_ld(0, (__vector unsigned long long*) p); + VEC_PERM(vdata0, vdata0, vdata0, vperm_const); + GROUP_ENDING_NOP; + + v1 = vec_xor(v1, va1); + va1 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata1, (__vector unsigned long long)vconst2); + vdata1 = vec_ld(16, (__vector unsigned long long*) p); + VEC_PERM(vdata1, vdata1, vdata1, vperm_const); + GROUP_ENDING_NOP; + + v2 = vec_xor(v2, va2); + va2 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata2, (__vector unsigned long long)vconst2); + vdata2 = vec_ld(32, (__vector unsigned long long*) p); + VEC_PERM(vdata2, vdata2, vdata2, vperm_const); + GROUP_ENDING_NOP; + + v3 = vec_xor(v3, va3); + va3 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata3, (__vector unsigned long long)vconst2); + vdata3 = vec_ld(48, (__vector unsigned long long*) p); + VEC_PERM(vdata3, vdata3, vdata3, vperm_const); + + vconst2 = vec_ld(offset, vcrc_const); + GROUP_ENDING_NOP; + + v4 = vec_xor(v4, va4); + va4 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata4, (__vector unsigned long long)vconst1); + vdata4 = vec_ld(64, (__vector unsigned long long*) p); + VEC_PERM(vdata4, vdata4, vdata4, vperm_const); + GROUP_ENDING_NOP; + + v5 = vec_xor(v5, va5); + va5 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata5, (__vector unsigned long long)vconst1); + vdata5 = vec_ld(80, (__vector unsigned long long*) p); + VEC_PERM(vdata5, vdata5, vdata5, vperm_const); + GROUP_ENDING_NOP; + + v6 = vec_xor(v6, va6); + va6 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata6, (__vector unsigned long long)vconst1); + vdata6 = vec_ld(96, (__vector unsigned long long*) p); + VEC_PERM(vdata6, vdata6, vdata6, vperm_const); + GROUP_ENDING_NOP; + + v7 = vec_xor(v7, va7); + va7 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata7, (__vector unsigned long long)vconst1); + vdata7 = vec_ld(112, (__vector unsigned long long*) p); + VEC_PERM(vdata7, vdata7, vdata7, vperm_const); + + p = (char *)p + 128; + } + + /* First cool down*/ + vconst1 = vec_ld(offset, vcrc_const); + offset += 16; + + v0 = vec_xor(v0, va0); + va0 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata0, (__vector unsigned long long)vconst1); + GROUP_ENDING_NOP; + + v1 = vec_xor(v1, va1); + va1 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata1, (__vector unsigned long long)vconst1); + GROUP_ENDING_NOP; + + v2 = vec_xor(v2, va2); + va2 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata2, (__vector unsigned long long)vconst1); + GROUP_ENDING_NOP; + + v3 = vec_xor(v3, va3); + va3 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata3, (__vector unsigned long long)vconst1); + GROUP_ENDING_NOP; + + v4 = vec_xor(v4, va4); + va4 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata4, (__vector unsigned long long)vconst1); + GROUP_ENDING_NOP; + + v5 = vec_xor(v5, va5); + va5 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata5, (__vector unsigned long long)vconst1); + GROUP_ENDING_NOP; + + v6 = vec_xor(v6, va6); + va6 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata6, (__vector unsigned long long)vconst1); + GROUP_ENDING_NOP; + + v7 = vec_xor(v7, va7); + va7 = __builtin_crypto_vpmsumd ((__vector unsigned long + long)vdata7, (__vector unsigned long long)vconst1); + }/* else */ + + /* Second cool down. */ + v0 = vec_xor(v0, va0); + v1 = vec_xor(v1, va1); + v2 = vec_xor(v2, va2); + v3 = vec_xor(v3, va3); + v4 = vec_xor(v4, va4); + v5 = vec_xor(v5, va5); + v6 = vec_xor(v6, va6); + v7 = vec_xor(v7, va7); + +#ifdef REFLECT + /* + * vpmsumd produces a 96 bit result in the least significant bits + * of the register. Since we are bit reflected we have to shift it + * left 32 bits so it occupies the least significant bits in the + * bit reflected domain. + */ + v0 = (__vector unsigned long long)vec_sld((__vector unsigned char)v0, + (__vector unsigned char)vzero, 4); + v1 = (__vector unsigned long long)vec_sld((__vector unsigned char)v1, + (__vector unsigned char)vzero, 4); + v2 = (__vector unsigned long long)vec_sld((__vector unsigned char)v2, + (__vector unsigned char)vzero, 4); + v3 = (__vector unsigned long long)vec_sld((__vector unsigned char)v3, + (__vector unsigned char)vzero, 4); + v4 = (__vector unsigned long long)vec_sld((__vector unsigned char)v4, + (__vector unsigned char)vzero, 4); + v5 = (__vector unsigned long long)vec_sld((__vector unsigned char)v5, + (__vector unsigned char)vzero, 4); + v6 = (__vector unsigned long long)vec_sld((__vector unsigned char)v6, + (__vector unsigned char)vzero, 4); + v7 = (__vector unsigned long long)vec_sld((__vector unsigned char)v7, + (__vector unsigned char)vzero, 4); +#endif + + /* xor with the last 1024 bits. */ + va0 = vec_ld(0, (__vector unsigned long long*) p); + VEC_PERM(va0, va0, va0, vperm_const); + + va1 = vec_ld(16, (__vector unsigned long long*) p); + VEC_PERM(va1, va1, va1, vperm_const); + + va2 = vec_ld(32, (__vector unsigned long long*) p); + VEC_PERM(va2, va2, va2, vperm_const); + + va3 = vec_ld(48, (__vector unsigned long long*) p); + VEC_PERM(va3, va3, va3, vperm_const); + + va4 = vec_ld(64, (__vector unsigned long long*) p); + VEC_PERM(va4, va4, va4, vperm_const); + + va5 = vec_ld(80, (__vector unsigned long long*) p); + VEC_PERM(va5, va5, va5, vperm_const); + + va6 = vec_ld(96, (__vector unsigned long long*) p); + VEC_PERM(va6, va6, va6, vperm_const); + + va7 = vec_ld(112, (__vector unsigned long long*) p); + VEC_PERM(va7, va7, va7, vperm_const); + + p = (char *)p + 128; + + vdata0 = vec_xor(v0, va0); + vdata1 = vec_xor(v1, va1); + vdata2 = vec_xor(v2, va2); + vdata3 = vec_xor(v3, va3); + vdata4 = vec_xor(v4, va4); + vdata5 = vec_xor(v5, va5); + vdata6 = vec_xor(v6, va6); + vdata7 = vec_xor(v7, va7); + + /* Check if we have more blocks to process */ + next_block = 0; + if (length != 0) { + next_block = 1; + + /* zero v0-v7 */ + v0 = vec_xor(v0, v0); + v1 = vec_xor(v1, v1); + v2 = vec_xor(v2, v2); + v3 = vec_xor(v3, v3); + v4 = vec_xor(v4, v4); + v5 = vec_xor(v5, v5); + v6 = vec_xor(v6, v6); + v7 = vec_xor(v7, v7); + } + length = length + 128; + + } while (next_block); + + /* Calculate how many bytes we have left. */ + length = (len & 127); + + /* Calculate where in (short) constant table we need to start. */ + offset = 128 - length; + + v0 = vec_ld(offset, vcrc_short_const); + v1 = vec_ld(offset + 16, vcrc_short_const); + v2 = vec_ld(offset + 32, vcrc_short_const); + v3 = vec_ld(offset + 48, vcrc_short_const); + v4 = vec_ld(offset + 64, vcrc_short_const); + v5 = vec_ld(offset + 80, vcrc_short_const); + v6 = vec_ld(offset + 96, vcrc_short_const); + v7 = vec_ld(offset + 112, vcrc_short_const); + + offset += 128; + + v0 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( + (__vector unsigned int)vdata0,(__vector unsigned int)v0); + v1 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( + (__vector unsigned int)vdata1,(__vector unsigned int)v1); + v2 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( + (__vector unsigned int)vdata2,(__vector unsigned int)v2); + v3 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( + (__vector unsigned int)vdata3,(__vector unsigned int)v3); + v4 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( + (__vector unsigned int)vdata4,(__vector unsigned int)v4); + v5 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( + (__vector unsigned int)vdata5,(__vector unsigned int)v5); + v6 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( + (__vector unsigned int)vdata6,(__vector unsigned int)v6); + v7 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( + (__vector unsigned int)vdata7,(__vector unsigned int)v7); + + /* Now reduce the tail (0-112 bytes). */ + for (i = 0; i < length; i+=16) { + vdata0 = vec_ld(i,(__vector unsigned long long*)p); + VEC_PERM(vdata0, vdata0, vdata0, vperm_const); + va0 = vec_ld(offset + i,vcrc_short_const); + va0 = (__vector unsigned long long)__builtin_crypto_vpmsumw ( + (__vector unsigned int)vdata0,(__vector unsigned int)va0); + v0 = vec_xor(v0, va0); + } + + /* xor all parallel chunks together. */ + v0 = vec_xor(v0, v1); + v2 = vec_xor(v2, v3); + v4 = vec_xor(v4, v5); + v6 = vec_xor(v6, v7); + + v0 = vec_xor(v0, v2); + v4 = vec_xor(v4, v6); + + v0 = vec_xor(v0, v4); + } + + /* Barrett Reduction */ + vconst1 = vec_ld(0, v_Barrett_const); + vconst2 = vec_ld(16, v_Barrett_const); + + v1 = (__vector unsigned long long)vec_sld((__vector unsigned char)v0, + (__vector unsigned char)v0, 8); + v0 = vec_xor(v1,v0); + +#ifdef REFLECT + /* shift left one bit */ + vsht_splat = vec_splat_u8 (1); + v0 = (__vector unsigned long long)vec_sll ((__vector unsigned char)v0, + vsht_splat); +#endif + + v0 = vec_and(v0, vmask_64bit); + +#ifndef REFLECT + + /* + * Now for the actual algorithm. The idea is to calculate q, + * the multiple of our polynomial that we need to subtract. By + * doing the computation 2x bits higher (ie 64 bits) and shifting the + * result back down 2x bits, we round down to the nearest multiple. + */ + + /* ma */ + v1 = __builtin_crypto_vpmsumd ((__vector unsigned long long)v0, + (__vector unsigned long long)vconst1); + /* q = floor(ma/(2^64)) */ + v1 = (__vector unsigned long long)vec_sld ((__vector unsigned char)vzero, + (__vector unsigned char)v1, 8); + /* qn */ + v1 = __builtin_crypto_vpmsumd ((__vector unsigned long long)v1, + (__vector unsigned long long)vconst2); + /* a - qn, subtraction is xor in GF(2) */ + v0 = vec_xor (v0, v1); + /* + * Get the result into r3. We need to shift it left 8 bytes: + * V0 [ 0 1 2 X ] + * V0 [ 0 X 2 3 ] + */ + result = __builtin_unpack_vector_1 (v0); +#else + + /* + * The reflected version of Barrett reduction. Instead of bit + * reflecting our data (which is expensive to do), we bit reflect our + * constants and our algorithm, which means the intermediate data in + * our vector registers goes from 0-63 instead of 63-0. We can reflect + * the algorithm because we don't carry in mod 2 arithmetic. + */ + + /* bottom 32 bits of a */ + v1 = vec_and(v0, vmask_32bit); + + /* ma */ + v1 = __builtin_crypto_vpmsumd ((__vector unsigned long long)v1, + (__vector unsigned long long)vconst1); + + /* bottom 32bits of ma */ + v1 = vec_and(v1, vmask_32bit); + /* qn */ + v1 = __builtin_crypto_vpmsumd ((__vector unsigned long long)v1, + (__vector unsigned long long)vconst2); + /* a - qn, subtraction is xor in GF(2) */ + v0 = vec_xor (v0, v1); + + /* + * Since we are bit reflected, the result (ie the low 32 bits) is in + * the high 32 bits. We just need to shift it left 4 bytes + * V0 [ 0 1 X 3 ] + * V0 [ 0 X 2 3 ] + */ + + /* shift result into top 64 bits of */ + v0 = (__vector unsigned long long)vec_sld((__vector unsigned char)v0, + (__vector unsigned char)vzero, 4); + + result = __builtin_unpack_vector_0 (v0); +#endif + + return result; +} diff --git a/mysys/checksum.c b/mysys/crc32ieee.cc index 948b9be6164..5f8344b4f9d 100644 --- a/mysys/checksum.c +++ b/mysys/crc32ieee.cc @@ -18,41 +18,46 @@ #include <my_sys.h> #include <zlib.h> -#if !defined(HAVE_CRC32_VPMSUM) /* TODO: remove this once zlib adds inherent support for hardware accelerated crc32 for all architectures. */ static unsigned int my_crc32_zlib(unsigned int crc, const void *data, size_t len) { - return (unsigned int) crc32(crc, data, (unsigned int) len); + return (unsigned int) crc32(crc, (const Bytef *)data, (unsigned int) len); } -my_crc32_t my_checksum= my_crc32_zlib; +#ifdef HAVE_PCLMUL +extern "C" int crc32_pclmul_enabled(); +extern "C" unsigned int crc32_pclmul(unsigned int, const void *, size_t); +#elif defined(__GNUC__) && defined(HAVE_ARMV8_CRC) +extern "C" int crc32_aarch64_available(); +extern "C" unsigned int crc32_aarch64(unsigned int, const void *, size_t); #endif -#if __GNUC__ >= 4 && defined(__x86_64__) -extern int crc32_pclmul_enabled(); -extern unsigned int crc32_pclmul(unsigned int, const void *, size_t); +typedef unsigned int (*my_crc32_t)(unsigned int, const void *, size_t); -/*----------------------------- x86_64 ---------------------------------*/ -void my_checksum_init(void) +static my_crc32_t init_crc32() { + my_crc32_t func= my_crc32_zlib; +#ifdef HAVE_PCLMUL if (crc32_pclmul_enabled()) - my_checksum= crc32_pclmul; -} + func = crc32_pclmul; #elif defined(__GNUC__) && defined(HAVE_ARMV8_CRC) -/*----------------------------- aarch64 --------------------------------*/ + if (crc32_aarch64_available()) + func= crc32_aarch64; +#endif + return func; +} -extern unsigned int crc32_aarch64(unsigned int, const void *, size_t); +static const my_crc32_t my_checksum_func= init_crc32(); -/* Ideally all ARM 64 bit processor should support crc32 but if some model -doesn't support better to find it out through auxillary vector. */ -void my_checksum_init(void) +#ifndef __powerpc64__ +/* For powerpc, my_checksum is defined elsewhere.*/ +extern "C" unsigned int my_checksum(unsigned int crc, const void *data, size_t len) { - if (crc32_aarch64_available()) - my_checksum= crc32_aarch64; + return my_checksum_func(crc, data, len); } -#else -void my_checksum_init(void) {} #endif + + diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c index 2e34cef5d19..75ff99b40a5 100644 --- a/mysys/mf_iocache.c +++ b/mysys/mf_iocache.c @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2011, Oracle and/or its affiliates - Copyright (c) 2010, 2015, MariaDB + Copyright (c) 2010, 2020, MariaDB 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 @@ -769,7 +769,8 @@ int _my_b_cache_read(IO_CACHE *info, uchar *Buffer, size_t Count) info->read_pos=info->buffer+Count; info->read_end=info->buffer+length; info->pos_in_file=pos_in_file; - memcpy(Buffer, info->buffer, Count); + if (Count) + memcpy(Buffer, info->buffer, Count); DBUG_RETURN(0); } @@ -1270,7 +1271,8 @@ static int _my_b_cache_read_r(IO_CACHE *cache, uchar *Buffer, size_t Count) DBUG_RETURN(1); } cnt= (len > Count) ? Count : len; - memcpy(Buffer, cache->read_pos, cnt); + if (cnt) + memcpy(Buffer, cache->read_pos, cnt); Count -= cnt; Buffer+= cnt; left_length+= cnt; diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index b4a63e93be3..d7e62726b22 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -1,5 +1,6 @@ /* Copyright (c) 2000, 2010, Oracle and/or its affiliates + Copyright (c) 2010, 2020, MariaDB 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 @@ -465,7 +466,8 @@ char *strmake_root(MEM_ROOT *root, const char *str, size_t len) char *pos; if ((pos=alloc_root(root,len+1))) { - memcpy(pos,str,len); + if (len) + memcpy(pos,str,len); pos[len]=0; } return pos; diff --git a/mysys/my_init.c b/mysys/my_init.c index cd9875017f0..2b420da03be 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -100,9 +100,6 @@ my_bool my_init(void) /* Initialize our mutex handling */ my_mutex_init(); - /* Initialize CPU architecture specific hardware based crc32 optimization */ - my_checksum_init(); - if (my_thread_global_init()) return 1; diff --git a/mysys/my_rename.c b/mysys/my_rename.c index 9f0770e8140..7b31e83be20 100644 --- a/mysys/my_rename.c +++ b/mysys/my_rename.c @@ -19,8 +19,62 @@ #include "m_string.h" #undef my_rename - /* On unix rename deletes to file if it exists */ +#ifdef _WIN32 + +#define RENAME_MAX_RETRIES 50 + +/* + On Windows, bad 3rd party programs (backup or anitivirus, or something else) + can have file open with a sharing mode incompatible with renaming, i.e they + won't use FILE_SHARE_DELETE when opening file. + + The following function will do a couple of retries, in case MoveFileEx returns + ERROR_SHARING_VIOLATION. +*/ +static BOOL win_rename_with_retries(const char *from, const char *to) +{ +#ifndef DBUG_OFF + FILE *fp = NULL; + DBUG_EXECUTE_IF("rename_sharing_violation", + { + fp= fopen(from, "r"); + DBUG_ASSERT(fp); + } + ); +#endif + + for (int retry= RENAME_MAX_RETRIES; retry--;) + { + DWORD ret = MoveFileEx(from, to, + MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); + + DBUG_ASSERT(fp == NULL || (ret == FALSE && GetLastError() == ERROR_SHARING_VIOLATION)); + + if (!ret && (GetLastError() == ERROR_SHARING_VIOLATION)) + { +#ifndef DBUG_OFF + /* + If error was injected in via DBUG_EXECUTE_IF, close the file + that is causing ERROR_SHARING_VIOLATION, so that retry succeeds. + */ + if (fp) + { + fclose(fp); + fp= NULL; + } +#endif + + Sleep(10); + } + else + return ret; + } + return FALSE; +} +#endif + + /* On unix rename deletes to file if it exists */ int my_rename(const char *from, const char *to, myf MyFlags) { int error = 0; @@ -28,8 +82,7 @@ int my_rename(const char *from, const char *to, myf MyFlags) DBUG_PRINT("my",("from %s to %s MyFlags %lu", from, to, MyFlags)); #if defined(__WIN__) - if (!MoveFileEx(from, to, MOVEFILE_COPY_ALLOWED | - MOVEFILE_REPLACE_EXISTING)) + if (!win_rename_with_retries(from, to)) { my_osmaperr(GetLastError()); #elif defined(HAVE_RENAME) diff --git a/plugin/aws_key_management/aws_key_management_plugin.cc b/plugin/aws_key_management/aws_key_management_plugin.cc index 489dd375387..348c171b618 100644 --- a/plugin/aws_key_management/aws_key_management_plugin.cc +++ b/plugin/aws_key_management/aws_key_management_plugin.cc @@ -81,6 +81,7 @@ static unsigned long key_spec; static unsigned long log_level; static int rotate_key; static int request_timeout; +static char* endpoint_url; #ifndef DBUG_OFF #define WITH_AWS_MOCK 1 @@ -229,6 +230,10 @@ static int aws_init() { clientConfiguration.region = region; } + if (endpoint_url && endpoint_url[0]) + { + clientConfiguration.endpointOverride = endpoint_url; + } if (request_timeout) { clientConfiguration.requestTimeoutMs= request_timeout; @@ -711,6 +716,11 @@ static MYSQL_SYSVAR_STR(region, region, "AWS region. For example us-east-1, or eu-central-1. If no value provided, SDK default is used.", NULL, NULL, ""); +static MYSQL_SYSVAR_STR(endpoint_url, endpoint_url, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + "Used to override the default AWS API endpoint. If not set, the default will be used", + NULL, NULL, ""); + #if WITH_AWS_MOCK static MYSQL_SYSVAR_BOOL(mock, mock, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, @@ -725,6 +735,7 @@ static struct st_mysql_sys_var* settings[]= { MYSQL_SYSVAR(log_level), MYSQL_SYSVAR(request_timeout), MYSQL_SYSVAR(region), + MYSQL_SYSVAR(endpoint_url), #if WITH_AWS_MOCK MYSQL_SYSVAR(mock), #endif diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index 9c4fdf6a234..8d6a486a29d 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -173,7 +173,7 @@ ELSE() SET(CHECK_PID "kill -s SIGCONT $PID > /dev/null 2> /dev/null") ENDIF() -SET(HOSTNAME "hostname") +SET(HOSTNAME "uname -n") SET(MYSQLD_USER "mysql") ENDIF(UNIX) diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh index 63ff5646535..15e5ebeacf0 100644 --- a/scripts/wsrep_sst_mariabackup.sh +++ b/scripts/wsrep_sst_mariabackup.sh @@ -1,6 +1,6 @@ #!/bin/bash -ue # Copyright (C) 2013 Percona Inc -# Copyright (C) 2017-2019 MariaDB +# Copyright (C) 2017-2020 MariaDB # # 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 @@ -359,7 +359,7 @@ read_cnf() iopts=$(parse_cnf sst inno-backup-opts "") iapts=$(parse_cnf sst inno-apply-opts "") impts=$(parse_cnf sst inno-move-opts "") - stimeout=$(parse_cnf sst sst-initial-timeout 100) + stimeout=$(parse_cnf sst sst-initial-timeout 300) ssyslog=$(parse_cnf sst sst-syslog 0) ssystag=$(parse_cnf mysqld_safe syslog-tag "${SST_SYSLOG_TAG:-}") ssystag+="-" @@ -620,7 +620,8 @@ recv_joiner() popd 1>/dev/null if [[ ${RC[0]} -eq 124 ]];then - wsrep_log_error "Possible timeout in receving first data from donor in gtid stage" + wsrep_log_error "Possible timeout in receiving first data from " + "donor in gtid stage: exit codes: ${RC[@]}" exit 32 fi diff --git a/sql-common/my_time.c b/sql-common/my_time.c index 5c14b8071a3..96674723b34 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -1454,23 +1454,161 @@ void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type) /* - Helper function for datetime formatting. - Format number as string, left-padded with 0. + A formatting routine to print a 2 digit zero padded number. + It prints 2 digits at a time, which gives a performance improvement. + The idea is taken from "class TwoDigitWriter" in MySQL. + + The old implementation printed one digit at a time, using the division + and the remainder operators, which appeared to be slow. + It's cheaper to have a cached array of 2-digit numbers + in their string representation. + + Benchmark results showed a 10% to 23% time reduce for these queries: + SELECT BENCHMARK(10*1000*1000,CONCAT(TIME'10:20:30')); + SELECT BENCHMARK(10*1000*1000,CONCAT(DATE'2001-01-01')); + SELECT BENCHMARK(10*1000*1000,CONCAT(TIMESTAMP'2001-01-01 10:20:30')); + SELECT BENCHMARK(10*1000*1000,CONCAT(TIME'10:20:30.123456')); + SELECT BENCHMARK(10*1000*1000,CONCAT(TIMESTAMP'2001-01-01 10:20:30.123456')); + (depending on the exact data type and fractional precision). + + The array has extra elements for values 100..255. + This is done for safety. If the caller passes a value + outside of the expected range 0..99, the value will be printed as "XX". + + Part2: + + As an additional improvement over "class TwoDigitWriter", we store + the string representations of the numbers in an array uint16[256] + instead of char[512]. This allows to copy data using int2store(), + which copies two bytes at a time on x86 and gives an additional + 7% to 26% time reduce over copying the two bytes separately. + + The total time reduce is 15% to 38% on the above queries. + + The bytes in the following array are swapped: + e.g. 0x3130 in two_digit_numbers[1] means the following: + - 0x31 is '1' (the left byte, the right digit) + - 0x30 is '0' (the right byte, the left digit) + int2store() puts the lower byte first, so the output string becomes '01'. +*/ +static const uint16 two_digit_numbers[256]= +{ + /* 0..99 */ + 0x3030,0x3130,0x3230,0x3330,0x3430,0x3530,0x3630,0x3730,0x3830,0x3930, + 0x3031,0x3131,0x3231,0x3331,0x3431,0x3531,0x3631,0x3731,0x3831,0x3931, + 0x3032,0x3132,0x3232,0x3332,0x3432,0x3532,0x3632,0x3732,0x3832,0x3932, + 0x3033,0x3133,0x3233,0x3333,0x3433,0x3533,0x3633,0x3733,0x3833,0x3933, + 0x3034,0x3134,0x3234,0x3334,0x3434,0x3534,0x3634,0x3734,0x3834,0x3934, + 0x3035,0x3135,0x3235,0x3335,0x3435,0x3535,0x3635,0x3735,0x3835,0x3935, + 0x3036,0x3136,0x3236,0x3336,0x3436,0x3536,0x3636,0x3736,0x3836,0x3936, + 0x3037,0x3137,0x3237,0x3337,0x3437,0x3537,0x3637,0x3737,0x3837,0x3937, + 0x3038,0x3138,0x3238,0x3338,0x3438,0x3538,0x3638,0x3738,0x3838,0x3938, + 0x3039,0x3139,0x3239,0x3339,0x3439,0x3539,0x3639,0x3739,0x3839,0x3939, + /* 100..199 - safety */ + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, + /* 200..255 - safety */ + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, + 0x5858,0x5858,0x5858,0x5858,0x5858,0x5858, +}; + +static inline char* fmt_number2(uint8 val, char *out) +{ + int2store(out, two_digit_numbers[val]); + return out + 2; +} + + +/* + We tried the same trick with a char array of 16384 zerofill 4-digit numbers, + with 10000 elements with numbers 0000..9999, and a tail filled with "XXXX". + + Benchmark results for a RelWithDebInfo build: + + SELECT BENCHMARK(10*1000*1000,CONCAT(TIMESTAMP'2001-01-01 10:20:30.123456')); + - 0.379 sec (current) + - 0.369 sec (array) + + SELECT BENCHMARK(10*1000*1000,CONCAT(DATE'2001-01-01')); + - 0.225 sec (current) + - 0.219 sec (array) + + It demonstrated an additional 3% performance imrovement one these queries. + However, as the array size is too huge, we afraid that it will flush data + from the CPU memory cache, which under real load may affect negatively. + + Let's keep using the fmt_number4() version with division and remainder + for now. This can be revised later. We could try some smaller array, + e.g. for YEARs in the range 1970..2098 (fitting into a 256 element array). +*/ +/* +static inline char* fmt_number4(uint16 val, char *out) +{ + const char *src= four_digit_numbers + (val & 0x3FFF) * 4; + memcpy(out, src, 4); + return out + 4; +} +*/ - The reason to use own formatting rather than sprintf() is performance - in a - datetime benchmark it helped to reduced the datetime formatting overhead - from ~30% down to ~4%. + +/* + A formatting routine to print a 4 digit zero padded number. */ +static inline char* fmt_number4(uint16 val, char *out) +{ + out= fmt_number2((uint8) (val / 100), out); + out= fmt_number2((uint8) (val % 100), out); + return out; +} + + +/* + A formatting routine to print a 6 digit zero padded number. +*/ +static inline char* fmt_number6(uint val, char *out) +{ + out= fmt_number2((uint8) (val / 10000), out); + val%= 10000; + out= fmt_number2((uint8) (val / 100), out); + out= fmt_number2((uint8) (val % 100), out); + return out; +} + -static char* fmt_number(uint val, char *out, uint digits) +static char* fmt_usec(uint val, char *out, uint digits) { - uint i; - for(i= 0; i < digits; i++) + switch (digits) { - out[digits-i-1]= '0' + val%10; - val/=10; + case 1: + *out++= '0' + (val % 10); + return out; + case 2: + return fmt_number2((uint8) val, out); + case 3: + *out++= '0' + (val / 100) % 10; + return fmt_number2((uint8) (val % 100), out); + case 4: + return fmt_number4((uint16) val, out); + case 5: + *out++= '0' + (val / 10000) % 10; + return fmt_number4((uint16) (val % 10000), out); + case 6: + return fmt_number6(val, out); } - return out + digits; + DBUG_ASSERT(0); + return out; } @@ -1480,13 +1618,13 @@ static int my_mmssff_to_str(const MYSQL_TIME *ltime, char *to, uint fsp) if (fsp == AUTO_SEC_PART_DIGITS) fsp= ltime->second_part ? TIME_SECOND_PART_DIGITS : 0; DBUG_ASSERT(fsp <= TIME_SECOND_PART_DIGITS); - pos= fmt_number(ltime->minute, pos, 2); + pos= fmt_number2((uint8) ltime->minute, pos); *pos++= ':'; - pos= fmt_number(ltime->second, pos, 2); + pos= fmt_number2((uint8) ltime->second, pos); if (fsp) { *pos++= '.'; - pos= fmt_number((uint)sec_part_shift(ltime->second_part, fsp), pos, fsp); + pos= fmt_usec((uint)sec_part_shift(ltime->second_part, fsp), pos, fsp); } return (int) (pos - to); } @@ -1506,7 +1644,7 @@ int my_interval_DDhhmmssff_to_str(const MYSQL_TIME *ltime, char *to, uint fsp) pos= longlong10_to_str((longlong) hour / 24, pos, 10); *pos++= ' '; } - pos= fmt_number(hour % 24, pos, 2); + pos= fmt_number2((uint8) (hour % 24), pos); *pos++= ':'; pos+= my_mmssff_to_str(ltime, pos, fsp); *pos= 0; @@ -1538,7 +1676,7 @@ int my_time_to_str(const MYSQL_TIME *l_time, char *to, uint digits) /* Need more than 2 digits for hours in string representation. */ pos= longlong10_to_str((longlong)hour, pos, 10); else - pos= fmt_number(hour, pos, 2); + pos= fmt_number2((uint8) hour, pos); *pos++= ':'; pos+= my_mmssff_to_str(l_time, pos, digits); @@ -1550,11 +1688,11 @@ int my_time_to_str(const MYSQL_TIME *l_time, char *to, uint digits) int my_date_to_str(const MYSQL_TIME *l_time, char *to) { char *pos=to; - pos= fmt_number(l_time->year, pos, 4); + pos= fmt_number4((uint16) l_time->year, pos); *pos++='-'; - pos= fmt_number(l_time->month, pos, 2); + pos= fmt_number2((uint8) l_time->month, pos); *pos++='-'; - pos= fmt_number(l_time->day, pos, 2); + pos= fmt_number2((uint8) l_time->day, pos); *pos= 0; return (int)(pos - to); } @@ -1563,13 +1701,13 @@ int my_date_to_str(const MYSQL_TIME *l_time, char *to) int my_datetime_to_str(const MYSQL_TIME *l_time, char *to, uint digits) { char *pos= to; - pos= fmt_number(l_time->year, pos, 4); + pos= fmt_number4((uint16) l_time->year, pos); *pos++='-'; - pos= fmt_number(l_time->month, pos, 2); + pos= fmt_number2((uint8) l_time->month, pos); *pos++='-'; - pos= fmt_number(l_time->day, pos, 2); + pos= fmt_number2((uint8) l_time->day, pos); *pos++=' '; - pos= fmt_number(l_time->hour, pos, 2); + pos= fmt_number2((uint8) l_time->hour, pos); *pos++= ':'; pos+= my_mmssff_to_str(l_time, pos, digits); *pos= 0; @@ -1625,7 +1763,7 @@ int my_timeval_to_str(const struct timeval *tm, char *to, uint dec) if (dec) { *pos++= '.'; - pos= fmt_number((uint) sec_part_shift(tm->tv_usec, dec), pos, dec); + pos= fmt_usec((uint) sec_part_shift(tm->tv_usec, dec), pos, dec); } *pos= '\0'; return (int) (pos - to); diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc index d2656f36967..dde3ce5a35b 100644 --- a/sql/debug_sync.cc +++ b/sql/debug_sync.cc @@ -348,7 +348,8 @@ static char *debug_sync_bmove_len(char *to, char *to_end, DBUG_ASSERT(to_end); DBUG_ASSERT(!length || from); set_if_smaller(length, (size_t) (to_end - to)); - memcpy(to, from, length); + if (length) + memcpy(to, from, length); return (to + length); } diff --git a/sql/field.cc b/sql/field.cc index 491cd1b5079..f8d9cbf93ce 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5892,9 +5892,7 @@ Item *Field_temporal::get_equal_const_item_datetime(THD *thd, See comments about truncation in the same place in Field_time::get_equal_const_item(). */ - return new (thd->mem_root) Item_datetime_literal(thd, - dt.get_mysql_time(), - decimals()); + return new (thd->mem_root) Item_datetime_literal(thd, &dt, decimals()); } break; case ANY_SUBST: @@ -5906,7 +5904,7 @@ Item *Field_temporal::get_equal_const_item_datetime(THD *thd, if (!dt.is_valid_datetime()) return NULL; return new (thd->mem_root) - Item_datetime_literal_for_invalid_dates(thd, dt.get_mysql_time(), + Item_datetime_literal_for_invalid_dates(thd, &dt, dt.get_mysql_time()-> second_part ? TIME_SECOND_PART_DIGITS : 0); @@ -6246,7 +6244,7 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx, (assuming CURRENT_DATE is '2015-08-30' */ - return new (thd->mem_root) Item_time_literal(thd, tm.get_mysql_time(), + return new (thd->mem_root) Item_time_literal(thd, &tm, tm.get_mysql_time()-> second_part ? TIME_SECOND_PART_DIGITS : @@ -6275,8 +6273,7 @@ Item *Field_time::get_equal_const_item(THD *thd, const Context &ctx, decimals()); if (!tm.is_valid_time()) return NULL; - return new (thd->mem_root) Item_time_literal(thd, tm.get_mysql_time(), - decimals()); + return new (thd->mem_root) Item_time_literal(thd, &tm, decimals()); } break; } @@ -6842,12 +6839,12 @@ Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx, */ if (!dt.hhmmssff_is_zero()) return new (thd->mem_root) - Item_datetime_literal_for_invalid_dates(thd, dt.get_mysql_time(), + Item_datetime_literal_for_invalid_dates(thd, &dt, dt.get_mysql_time()-> second_part ? TIME_SECOND_PART_DIGITS : 0); - return new (thd->mem_root) - Item_date_literal_for_invalid_dates(thd, Date(&dt).get_mysql_time()); + Date d(&dt); + return new (thd->mem_root) Item_date_literal_for_invalid_dates(thd, &d); } break; case IDENTITY_SUBST: @@ -6862,8 +6859,8 @@ Item *Field_newdate::get_equal_const_item(THD *thd, const Context &ctx, Datetime dt(thd, const_item, Datetime::Options(TIME_CONV_NONE, thd)); if (!dt.is_valid_datetime()) return NULL; - return new (thd->mem_root) - Item_date_literal(thd, Date(&dt).get_mysql_time()); + Date d(&dt); + return new (thd->mem_root) Item_date_literal(thd, &d); } break; } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 4556c5f482e..8d0557f4ae4 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1619,9 +1619,8 @@ public: return h; } - ha_rows part_records(void *_part_elem) + ha_rows part_records(partition_element *part_elem) { - partition_element *part_elem= reinterpret_cast<partition_element *>(_part_elem); DBUG_ASSERT(m_part_info); uint32 sub_factor= m_part_info->num_subparts ? m_part_info->num_subparts : 1; uint32 part_id= part_elem->id * sub_factor; diff --git a/sql/item.cc b/sql/item.cc index 733b5d56b1b..52274380cd1 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2576,8 +2576,6 @@ bool Type_std_attributes::agg_item_set_converter(const DTCollation &coll, Item* conv= (*arg)->safe_charset_converter(thd, coll.collation); if (conv == *arg) continue; - if (!conv && ((*arg)->collation.repertoire == MY_REPERTOIRE_ASCII)) - conv= new (thd->mem_root) Item_func_conv_charset(thd, *arg, coll.collation, 1); if (!conv) { @@ -7067,7 +7065,7 @@ void Item_date_literal::print(String *str, enum_query_type query_type) { str->append("DATE'"); char buf[MAX_DATE_STRING_REP_LENGTH]; - my_date_to_str(&cached_time, buf); + my_date_to_str(cached_time.get_mysql_time(), buf); str->append(buf); str->append('\''); } @@ -7082,7 +7080,7 @@ Item *Item_date_literal::clone_item(THD *thd) bool Item_date_literal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { fuzzydate |= sql_mode_for_dates(thd); - *ltime= cached_time; + cached_time.copy_to_mysql_time(ltime); return (null_value= check_date_with_warn(thd, ltime, fuzzydate, MYSQL_TIMESTAMP_ERROR)); } @@ -7092,7 +7090,7 @@ void Item_datetime_literal::print(String *str, enum_query_type query_type) { str->append("TIMESTAMP'"); char buf[MAX_DATE_STRING_REP_LENGTH]; - my_datetime_to_str(&cached_time, buf, decimals); + my_datetime_to_str(cached_time.get_mysql_time(), buf, decimals); str->append(buf); str->append('\''); } @@ -7107,7 +7105,7 @@ Item *Item_datetime_literal::clone_item(THD *thd) bool Item_datetime_literal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { fuzzydate |= sql_mode_for_dates(thd); - *ltime= cached_time; + cached_time.copy_to_mysql_time(ltime); return (null_value= check_date_with_warn(thd, ltime, fuzzydate, MYSQL_TIMESTAMP_ERROR)); } @@ -7117,7 +7115,7 @@ void Item_time_literal::print(String *str, enum_query_type query_type) { str->append("TIME'"); char buf[MAX_DATE_STRING_REP_LENGTH]; - my_time_to_str(&cached_time, buf, decimals); + my_time_to_str(cached_time.get_mysql_time(), buf, decimals); str->append(buf); str->append('\''); } @@ -7131,7 +7129,7 @@ Item *Item_time_literal::clone_item(THD *thd) bool Item_time_literal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - *ltime= cached_time; + cached_time.copy_to_mysql_time(ltime); if (fuzzydate & TIME_TIME_ONLY) return (null_value= false); return (null_value= check_date_with_warn(thd, ltime, fuzzydate, @@ -9990,23 +9988,20 @@ Item *Item_cache_temporal::convert_to_basic_const_item(THD *thd) Item *Item_cache_datetime::make_literal(THD *thd) { - MYSQL_TIME ltime; - unpack_time(val_datetime_packed(thd), <ime, MYSQL_TIMESTAMP_DATETIME); - return new (thd->mem_root) Item_datetime_literal(thd, <ime, decimals); + Datetime dt(thd, this, TIME_CONV_NONE | TIME_FRAC_NONE); + return new (thd->mem_root) Item_datetime_literal(thd, &dt, decimals); } Item *Item_cache_date::make_literal(THD *thd) { - MYSQL_TIME ltime; - unpack_time(val_datetime_packed(thd), <ime, MYSQL_TIMESTAMP_DATE); - return new (thd->mem_root) Item_date_literal(thd, <ime); + Date d(thd, this, TIME_CONV_NONE | TIME_FRAC_NONE); + return new (thd->mem_root) Item_date_literal(thd, &d); } Item *Item_cache_time::make_literal(THD *thd) { - MYSQL_TIME ltime; - unpack_time(val_time_packed(thd), <ime, MYSQL_TIMESTAMP_TIME); - return new (thd->mem_root) Item_time_literal(thd, <ime, decimals); + Time t(thd, this); + return new (thd->mem_root) Item_time_literal(thd, &t, decimals); } diff --git a/sql/item.h b/sql/item.h index e872335bb77..19b7b5d03e9 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2392,7 +2392,7 @@ public: if (join_tab_idx_arg < join_tab_idx) join_tab_idx= join_tab_idx_arg; } - virtual uint get_join_tab_idx() { return join_tab_idx; } + uint get_join_tab_idx() const { return join_tab_idx; } table_map view_used_tables(TABLE_LIST *view) { @@ -4820,29 +4820,20 @@ public: class Item_temporal_literal :public Item_literal { -protected: - MYSQL_TIME cached_time; public: - /** - Constructor for Item_date_literal. - @param ltime DATE value. - */ - Item_temporal_literal(THD *thd, const MYSQL_TIME *ltime) + Item_temporal_literal(THD *thd) :Item_literal(thd) { collation= DTCollation_numeric(); decimals= 0; - cached_time= *ltime; } - Item_temporal_literal(THD *thd, const MYSQL_TIME *ltime, uint dec_arg): + Item_temporal_literal(THD *thd, uint dec_arg): Item_literal(thd) { collation= DTCollation_numeric(); decimals= dec_arg; - cached_time= *ltime; } - const MYSQL_TIME *const_ptr_mysql_time() const { return &cached_time; } int save_in_field(Field *field, bool no_conversions) { return save_date_in_field(field, no_conversions); } }; @@ -4853,27 +4844,62 @@ public: */ class Item_date_literal: public Item_temporal_literal { +protected: + Date cached_time; + bool update_null() + { + return maybe_null && + (null_value= cached_time.check_date_with_warn(current_thd)); + } public: - Item_date_literal(THD *thd, const MYSQL_TIME *ltime) - :Item_temporal_literal(thd, ltime) + Item_date_literal(THD *thd, const Date *ltime) + :Item_temporal_literal(thd), + cached_time(*ltime) { + DBUG_ASSERT(cached_time.is_valid_date()); max_length= MAX_DATE_WIDTH; /* If date has zero month or day, it can return NULL in case of NO_ZERO_DATE or NO_ZERO_IN_DATE. - We can't just check the current sql_mode here in constructor, + If date is `February 30`, it can return NULL in case if + no ALLOW_INVALID_DATES is set. + We can't set null_value using the current sql_mode here in constructor, because sql_mode can change in case of prepared statements between PREPARE and EXECUTE. + Here we only set maybe_null to true if the value has such anomalies. + Later (during execution time), if maybe_null is true, then the value + will be checked per row, according to the execution time sql_mode. + The check_date() below call should cover all cases mentioned. */ - maybe_null= !ltime->month || !ltime->day; + maybe_null= cached_time.check_date(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE); } const Type_handler *type_handler() const { return &type_handler_newdate; } void print(String *str, enum_query_type query_type); + const MYSQL_TIME *const_ptr_mysql_time() const + { + return cached_time.get_mysql_time(); + } Item *clone_item(THD *thd); - longlong val_int() { return Date(this).to_longlong(); } - double val_real() { return Date(this).to_double(); } - String *val_str(String *to) { return Date(this).to_string(to); } - my_decimal *val_decimal(my_decimal *to) { return Date(this).to_decimal(to); } + longlong val_int() + { + return update_null() ? 0 : cached_time.to_longlong(); + } + double val_real() + { + return update_null() ? 0 : cached_time.to_double(); + } + String *val_str(String *to) + { + return update_null() ? 0 : cached_time.to_string(to); + } + my_decimal *val_decimal(my_decimal *to) + { + return update_null() ? 0 : cached_time.to_decimal(to); + } + longlong val_datetime_packed(THD *thd) + { + return update_null() ? 0 : cached_time.valid_date_to_packed(); + } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate); Item *get_copy(THD *thd) { return get_item_copy<Item_date_literal>(thd, this); } @@ -4885,19 +4911,31 @@ public: */ class Item_time_literal: public Item_temporal_literal { +protected: + Time cached_time; public: - Item_time_literal(THD *thd, const MYSQL_TIME *ltime, uint dec_arg): - Item_temporal_literal(thd, ltime, dec_arg) + Item_time_literal(THD *thd, const Time *ltime, uint dec_arg): + Item_temporal_literal(thd, dec_arg), + cached_time(*ltime) { + DBUG_ASSERT(cached_time.is_valid_time()); max_length= MIN_TIME_WIDTH + (decimals ? decimals + 1 : 0); } const Type_handler *type_handler() const { return &type_handler_time2; } void print(String *str, enum_query_type query_type); + const MYSQL_TIME *const_ptr_mysql_time() const + { + return cached_time.get_mysql_time(); + } Item *clone_item(THD *thd); - longlong val_int() { return Time(this).to_longlong(); } - double val_real() { return Time(this).to_double(); } - String *val_str(String *to) { return Time(this).to_string(to, decimals); } - my_decimal *val_decimal(my_decimal *to) { return Time(this).to_decimal(to); } + longlong val_int() { return cached_time.to_longlong(); } + double val_real() { return cached_time.to_double(); } + String *val_str(String *to) { return cached_time.to_string(to, decimals); } + my_decimal *val_decimal(my_decimal *to) { return cached_time.to_decimal(to); } + longlong val_time_packed(THD *thd) + { + return cached_time.valid_time_to_packed(); + } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate); bool val_native(THD *thd, Native *to) { @@ -4913,26 +4951,49 @@ public: */ class Item_datetime_literal: public Item_temporal_literal { +protected: + Datetime cached_time; + bool update_null() + { + return maybe_null && + (null_value= cached_time.check_date_with_warn(current_thd)); + } public: - Item_datetime_literal(THD *thd, const MYSQL_TIME *ltime, uint dec_arg): - Item_temporal_literal(thd, ltime, dec_arg) + Item_datetime_literal(THD *thd, const Datetime *ltime, uint dec_arg): + Item_temporal_literal(thd, dec_arg), + cached_time(*ltime) { + DBUG_ASSERT(cached_time.is_valid_datetime()); max_length= MAX_DATETIME_WIDTH + (decimals ? decimals + 1 : 0); // See the comment on maybe_null in Item_date_literal - maybe_null= !ltime->month || !ltime->day; + maybe_null= cached_time.check_date(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE); } const Type_handler *type_handler() const { return &type_handler_datetime2; } void print(String *str, enum_query_type query_type); + const MYSQL_TIME *const_ptr_mysql_time() const + { + return cached_time.get_mysql_time(); + } Item *clone_item(THD *thd); - longlong val_int() { return Datetime(this).to_longlong(); } - double val_real() { return Datetime(this).to_double(); } + longlong val_int() + { + return update_null() ? 0 : cached_time.to_longlong(); + } + double val_real() + { + return update_null() ? 0 : cached_time.to_double(); + } String *val_str(String *to) { - return Datetime(this).to_string(to, decimals); + return update_null() ? NULL : cached_time.to_string(to, decimals); } my_decimal *val_decimal(my_decimal *to) { - return Datetime(this).to_decimal(to); + return update_null() ? NULL : cached_time.to_decimal(to); + } + longlong val_datetime_packed(THD *thd) + { + return update_null() ? 0 : cached_time.valid_datetime_to_packed(); } bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate); Item *get_copy(THD *thd) @@ -4969,11 +5030,14 @@ class Item_date_literal_for_invalid_dates: public Item_date_literal in sql_mode=TRADITIONAL. */ public: - Item_date_literal_for_invalid_dates(THD *thd, const MYSQL_TIME *ltime) - :Item_date_literal(thd, ltime) { } + Item_date_literal_for_invalid_dates(THD *thd, const Date *ltime) + :Item_date_literal(thd, ltime) + { + maybe_null= false; + } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - *ltime= cached_time; + cached_time.copy_to_mysql_time(ltime); return (null_value= false); } }; @@ -4987,11 +5051,14 @@ class Item_datetime_literal_for_invalid_dates: public Item_datetime_literal { public: Item_datetime_literal_for_invalid_dates(THD *thd, - const MYSQL_TIME *ltime, uint dec_arg) - :Item_datetime_literal(thd, ltime, dec_arg) { } + const Datetime *ltime, uint dec_arg) + :Item_datetime_literal(thd, ltime, dec_arg) + { + maybe_null= false; + } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - *ltime= cached_time; + cached_time.copy_to_mysql_time(ltime); return (null_value= false); } }; diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 186efdf7fb9..1ae62a4a6e8 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -1434,11 +1434,19 @@ public: /* Conversion from and to "binary" is safe. Conversion to Unicode is safe. + Conversion from an expression with the ASCII repertoire + to any character set that can store characters U+0000..U+007F + is safe: + - All supported multibyte character sets can store U+0000..U+007F + - All supported 7bit character sets can store U+0000..U+007F + except those marked with MY_CS_NONASCII (e.g. swe7). Other kind of conversions are potentially lossy. */ safe= (args[0]->collation.collation == &my_charset_bin || cs == &my_charset_bin || - (cs->state & MY_CS_UNICODE)); + (cs->state & MY_CS_UNICODE) || + (args[0]->collation.repertoire == MY_REPERTOIRE_ASCII && + (cs->mbmaxlen > 1 || !(cs->state & MY_CS_NONASCII)))); } } bool is_json_type() { return args[0]->is_json_type(); } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 9525019888d..334fec2e048 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -6361,6 +6361,9 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, while (TRUE) { error= tmp_table->file->ha_rnd_next(tmp_table->record[0]); + + if (error == HA_ERR_ABORTED_BY_USER) + break; /* This is a temp table that we fully own, there should be no other cause to stop the iteration than EOF. diff --git a/sql/log_event.h b/sql/log_event.h index 5e110dbd3fd..222e611ecae 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -896,6 +896,7 @@ typedef struct st_print_event_info */ IO_CACHE head_cache; IO_CACHE body_cache; + IO_CACHE tail_cache; #ifdef WHEN_FLASHBACK_REVIEW_READY /* Storing the SQL for reviewing */ IO_CACHE review_sql_cache; @@ -906,6 +907,7 @@ typedef struct st_print_event_info ~st_print_event_info() { close_cached_file(&head_cache); close_cached_file(&body_cache); + close_cached_file(&tail_cache); #ifdef WHEN_FLASHBACK_REVIEW_READY close_cached_file(&review_sql_cache); #endif diff --git a/sql/log_event_client.cc b/sql/log_event_client.cc index bdc42885312..4c26acd2cc1 100644 --- a/sql/log_event_client.cc +++ b/sql/log_event_client.cc @@ -1729,7 +1729,7 @@ bool Log_event::print_base64(IO_CACHE* file, ev->need_flashback_review= need_flashback_review; if (print_event_info->verbose) { - if (ev->print_verbose(file, print_event_info)) + if (ev->print_verbose(&print_event_info->tail_cache, print_event_info)) goto err; } else @@ -1753,22 +1753,9 @@ bool Log_event::print_base64(IO_CACHE* file, } #else if (print_event_info->verbose) - { - /* - Verbose event printout can't start before encoded data - got enquoted. This is done at this point though multi-row - statement remain vulnerable. - TODO: fix MDEV-10362 to remove this workaround. - */ - if (print_event_info->base64_output_mode != - BASE64_OUTPUT_DECODE_ROWS) - my_b_printf(file, "'%s\n", print_event_info->delimiter); - error= ev->print_verbose(file, print_event_info); - } + error= ev->print_verbose(&print_event_info->tail_cache, print_event_info); else - { ev->count_row_events(print_event_info); - } #endif delete ev; if (unlikely(error)) @@ -2763,7 +2750,7 @@ bool copy_cache_to_file_wrapped(IO_CACHE *body, FILE *file, bool do_wrap, const char *delimiter, - bool is_verbose) + bool is_verbose /*TODO: remove */) { const my_off_t cache_size= my_b_tell(body); @@ -2796,8 +2783,7 @@ bool copy_cache_to_file_wrapped(IO_CACHE *body, my_fprintf(file, fmt_frag, 1); if (my_b_copy_to_file(body, file, SIZE_T_MAX)) goto err; - if (!is_verbose) - my_fprintf(file, fmt_delim, delimiter); + my_fprintf(file, fmt_delim, delimiter); my_fprintf(file, fmt_binlog2, delimiter); } @@ -2806,8 +2792,7 @@ bool copy_cache_to_file_wrapped(IO_CACHE *body, my_fprintf(file, str_binlog); if (my_b_copy_to_file(body, file, SIZE_T_MAX)) goto err; - if (!is_verbose) - my_fprintf(file, fmt_delim, delimiter); + my_fprintf(file, fmt_delim, delimiter); } reinit_io_cache(body, WRITE_CACHE, 0, FALSE, TRUE); @@ -2893,7 +2878,6 @@ bool copy_cache_to_string_wrapped(IO_CACHE *cache, goto err; str += (add_to_len= uint32(cache->end_of_file - (cache_size/2 + 1))); to->length += add_to_len; - if (!is_verbose) { str += (add_to_len= sprintf(str , fmt_delim, delimiter)); to->length += add_to_len; @@ -2909,7 +2893,6 @@ bool copy_cache_to_string_wrapped(IO_CACHE *cache, goto err; str += cache->end_of_file; to->length += (size_t)cache->end_of_file; - if (!is_verbose) to->length += sprintf(str , fmt_delim, delimiter); } @@ -2957,6 +2940,7 @@ bool Rows_log_event::print_helper(FILE *file, { IO_CACHE *const head= &print_event_info->head_cache; IO_CACHE *const body= &print_event_info->body_cache; + IO_CACHE *const tail= &print_event_info->tail_cache; #ifdef WHEN_FLASHBACK_REVIEW_READY IO_CACHE *const sql= &print_event_info->review_sql_cache; #endif @@ -2987,7 +2971,8 @@ bool Rows_log_event::print_helper(FILE *file, if (copy_event_cache_to_file_and_reinit(head, file) || copy_cache_to_file_wrapped(body, file, do_print_encoded, print_event_info->delimiter, - print_event_info->verbose)) + print_event_info->verbose) || + copy_event_cache_to_file_and_reinit(tail, file)) goto err; } else @@ -3005,6 +2990,11 @@ bool Rows_log_event::print_helper(FILE *file, return 1; output_buf.append(tmp_str.str, tmp_str.length); my_free(tmp_str.str); + if (copy_event_cache_to_string_and_reinit(tail, &tmp_str)) + return 1; + output_buf.append(tmp_str.str, tmp_str.length); + my_free(tmp_str.str); + #ifdef WHEN_FLASHBACK_REVIEW_READY if (copy_event_cache_to_string_and_reinit(sql, &tmp_str)) return 1; @@ -3787,6 +3777,7 @@ st_print_event_info::st_print_event_info() base64_output_mode=BASE64_OUTPUT_UNSPEC; open_cached_file(&head_cache, NULL, NULL, 0, flags); open_cached_file(&body_cache, NULL, NULL, 0, flags); + open_cached_file(&tail_cache, NULL, NULL, 0, flags); #ifdef WHEN_FLASHBACK_REVIEW_READY open_cached_file(&review_sql_cache, NULL, NULL, 0, flags); #endif diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index f02f74ca093..10d1df4f3e7 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1850,6 +1850,7 @@ bool Old_rows_log_event::print_helper(FILE *file, { IO_CACHE *const head= &print_event_info->head_cache; IO_CACHE *const body= &print_event_info->body_cache; + IO_CACHE *const tail= &print_event_info->tail_cache; bool do_print_encoded= print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS && print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER && @@ -1869,8 +1870,9 @@ bool Old_rows_log_event::print_helper(FILE *file, { if (copy_event_cache_to_file_and_reinit(head, file) || copy_cache_to_file_wrapped(body, file, do_print_encoded, - print_event_info->delimiter, - print_event_info->verbose)) + print_event_info->delimiter, + print_event_info->verbose) || + copy_event_cache_to_file_and_reinit(tail, file)) goto err; } return 0; diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index 88e30827dfd..5a97f4c81b1 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -1033,6 +1033,9 @@ void Query_log_event::pack_info(Protocol *protocol) append_identifier(protocol->thd, &buf, db, db_len); buf.append(STRING_WITH_LEN("; ")); } + + DBUG_ASSERT(!flags2 || flags2_inited); + if (flags2 & (OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_AUTO_IS_NULL | OPTION_RELAXED_UNIQUE_CHECKS | OPTION_NO_CHECK_CONSTRAINT_CHECKS | diff --git a/sql/mdl.cc b/sql/mdl.cc index 240ef97b1c4..4772dc017f9 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -25,9 +25,6 @@ #include <mysql/plugin.h> #include <mysql/service_thd_wait.h> #include <mysql/psi/mysql_stage.h> -#ifdef WITH_WSREP -#include "wsrep_sst.h" -#endif #include <tpool.h> #include <pfs_metadata_provider.h> #include <mysql/psi/mysql_mdl.h> @@ -2335,26 +2332,18 @@ MDL_context::acquire_lock(MDL_request *mdl_request, double lock_wait_timeout) wait_status= m_wait.timed_wait(m_owner, &abs_shortwait, FALSE, mdl_request->key.get_wait_state_name()); - THD* thd= m_owner->get_thd(); - if (wait_status != MDL_wait::EMPTY) break; /* Check if the client is gone while we were waiting. */ - if (! thd_is_connected(thd)) + if (! thd_is_connected(m_owner->get_thd())) { -#if defined(WITH_WSREP) && !defined(EMBEDDED_LIBRARY) - // During SST client might not be connected - if (!wsrep_is_sst_progress()) -#endif - { - /* - * The client is disconnected. Don't wait forever: - * assume it's the same as a wait timeout, this - * ensures all error handling is correct. - */ - wait_status= MDL_wait::TIMEOUT; - break; - } + /* + * The client is disconnected. Don't wait forever: + * assume it's the same as a wait timeout, this + * ensures all error handling is correct. + */ + wait_status= MDL_wait::TIMEOUT; + break; } mysql_prlock_wrlock(&lock->m_rwlock); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7de425338ea..aa3b1b31172 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3603,7 +3603,8 @@ static const char *rpl_make_log_name(PSI_memory_key key, const char *opt, const char *def, const char *ext) { DBUG_ENTER("rpl_make_log_name"); - DBUG_PRINT("enter", ("opt: %s, def: %s, ext: %s", opt, def, ext)); + DBUG_PRINT("enter", ("opt: %s, def: %s, ext: %s", opt ? opt : "(null)", + def, ext)); char buff[FN_REFLEN]; const char *base= opt ? opt : def; unsigned int options= diff --git a/sql/net_serv.cc b/sql/net_serv.cc index ebd92a0e45a..a96c43a94fe 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -612,7 +612,8 @@ net_write_buff(NET *net, const uchar *packet, size_t len) return net_real_write(net, packet, len) ? 1 : 0; /* Send out rest of the blocks as full sized blocks */ } - memcpy((char*) net->write_pos,packet,len); + if (len) + memcpy((char*) net->write_pos,packet,len); net->write_pos+= len; return 0; } diff --git a/sql/opt_index_cond_pushdown.cc b/sql/opt_index_cond_pushdown.cc index 360ae028f36..15bc2074e1f 100644 --- a/sql/opt_index_cond_pushdown.cc +++ b/sql/opt_index_cond_pushdown.cc @@ -206,7 +206,7 @@ static Item *make_cond_for_index(THD *thd, Item *cond, TABLE *table, uint keyno, new_cond->argument_list()->push_back(fix, thd->mem_root); used_tables|= fix->used_tables(); } - if (MY_TEST(item->marker == ICP_COND_USES_INDEX_ONLY)) + if (item->marker == ICP_COND_USES_INDEX_ONLY) { n_marked++; item->marker= 0; @@ -239,7 +239,7 @@ static Item *make_cond_for_index(THD *thd, Item *cond, TABLE *table, uint keyno, if (!fix) return (COND*) 0; new_cond->argument_list()->push_back(fix, thd->mem_root); - if (MY_TEST(item->marker == ICP_COND_USES_INDEX_ONLY)) + if (item->marker == ICP_COND_USES_INDEX_ONLY) { n_marked++; item->marker= 0; diff --git a/sql/service_wsrep.cc b/sql/service_wsrep.cc index f61db1e80e8..e7eee5f67a5 100644 --- a/sql/service_wsrep.cc +++ b/sql/service_wsrep.cc @@ -372,4 +372,27 @@ extern "C" bool wsrep_thd_set_wsrep_aborter(THD *bf_thd, THD *victim_thd) } victim_thd->wsrep_aborter = bf_thd->thread_id; return false; -}
\ No newline at end of file +} + +extern "C" void wsrep_report_bf_lock_wait(const THD *thd, + unsigned long long trx_id) +{ + if (thd) + { + WSREP_ERROR("Thread %s trx_id: %llu thread: %ld " + "seqno: %lld client_state: %s client_mode: %s transaction_mode: %s " + "applier: %d toi: %d local: %d " + "query: %s", + wsrep_thd_is_BF(thd, false) ? "BF" : "normal", + trx_id, + thd_get_thread_id(thd), + wsrep_thd_trx_seqno(thd), + wsrep_thd_client_state_str(thd), + wsrep_thd_client_mode_str(thd), + wsrep_thd_transaction_state_str(thd), + wsrep_thd_is_applying(thd), + wsrep_thd_is_toi(thd), + wsrep_thd_is_local(thd), + wsrep_thd_query(thd)); + } +} diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index d25410292ef..4ad4c478937 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1851,15 +1851,13 @@ int write_record(THD *thd, TABLE *table, COPY_INFO *info, select_result *sink) } if (table->vfield) { - my_bool abort_on_warning= thd->abort_on_warning; /* We have not yet called update_virtual_fields(VOL_UPDATE_FOR_READ) in handler methods for the just read row in record[1]. */ table->move_fields(table->field, table->record[1], table->record[0]); - thd->abort_on_warning= 0; - table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_REPLACE); - thd->abort_on_warning= abort_on_warning; + if (table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_REPLACE)) + goto err; table->move_fields(table->field, table->record[0], table->record[1]); } if (info->handle_duplicates == DUP_UPDATE) @@ -2683,6 +2681,7 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) if (!(*field= (*org_field)->make_new_field(client_thd->mem_root, copy, 1))) goto error; (*field)->unireg_check= (*org_field)->unireg_check; + (*field)->invisible= (*org_field)->invisible; (*field)->orig_table= copy; // Remove connection (*field)->move_field_offset(adjust_ptrs); // Point at copy->record[0] (*field)->flags|= ((*org_field)->flags & LONG_UNIQUE_HASH_FIELD); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 37def6df7ed..592b53ceecf 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -400,6 +400,9 @@ bool sp_create_assignment_lex(THD *thd, const char *pos) new_lex->sphead->m_tmp_query= pos; return thd->lex->sphead->reset_lex(thd, new_lex); } + else + if (thd->lex->main_select_push(false)) + return true; return false; } @@ -491,6 +494,8 @@ bool sp_create_assignment_instr(THD *thd, bool no_lookahead, /* Copy option_type to outer lex in case it has changed. */ thd->lex->option_type= inner_option_type; } + else + lex->pop_select(); return false; } @@ -2960,6 +2965,7 @@ void st_select_lex::init_query() changed_elements= 0; first_natural_join_processing= 1; first_cond_optimization= 1; + is_service_select= 0; parsing_place= NO_MATTER; save_parsing_place= NO_MATTER; exclude_from_table_unique_test= no_wrap_view_item= FALSE; @@ -8242,7 +8248,7 @@ Item *LEX::create_item_ident_sp(THD *thd, Lex_ident_sys_st *name, return new (thd->mem_root) Item_func_sqlerrm(thd); } - if (!select_stack_head() && + if (fields_are_impossible() && (current_select->parsing_place != FOR_LOOP_BOUND || spcont->find_cursor(name, &unused_off, false) == NULL)) { @@ -9579,11 +9585,13 @@ void st_select_lex::add_statistics(SELECT_LEX_UNIT *unit) } -bool LEX::main_select_push() +bool LEX::main_select_push(bool service) { DBUG_ENTER("LEX::main_select_push"); + DBUG_PRINT("info", ("service: %u", service)); current_select_number= 1; builtin_select.select_number= 1; + builtin_select.is_service_select= service; if (push_select(&builtin_select)) DBUG_RETURN(TRUE); DBUG_RETURN(FALSE); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index f516219c01a..a07121b9a58 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1293,6 +1293,8 @@ public: bool no_wrap_view_item; /* exclude this select from check of unique_table() */ bool exclude_from_table_unique_test; + /* the select is "service-select" and can not have tables*/ + bool is_service_select; /* index in the select list of the expression currently being fixed */ int cur_pos_in_select_list; @@ -3701,8 +3703,9 @@ public: if (unlikely(!select_stack_top)) { current_select= &builtin_select; - DBUG_PRINT("info", ("Top Select is empty -> sel builtin: %p", - current_select)); + DBUG_PRINT("info", ("Top Select is empty -> sel builtin: %p service: %u", + current_select, builtin_select.is_service_select)); + builtin_select.is_service_select= false; } else current_select= select_stack[select_stack_top - 1]; @@ -4528,7 +4531,7 @@ public: wild= 0; exchange= 0; } - bool main_select_push(); + bool main_select_push(bool service= false); bool insert_select_hack(SELECT_LEX *sel); SELECT_LEX *create_priority_nest(SELECT_LEX *first_in_nest); @@ -4678,6 +4681,14 @@ public: void mark_first_table_as_inserting(); + bool fields_are_impossible() + { + // no select or it is last select with no tables (service select) + return !select_stack_head() || + (select_stack_top == 1 && + select_stack[0]->is_service_select); + } + bool add_table_foreign_key(const LEX_CSTRING *name, const LEX_CSTRING *constraint_name, Table_ident *table_name, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8c95aa0a760..554c62f6538 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7986,6 +7986,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, (alias ? alias->str : table->table.str), table, this, select_number)); + DBUG_ASSERT(!is_service_select || (table_options & TL_OPTION_SEQUENCE)); if (unlikely(!table)) DBUG_RETURN(0); // End of memory diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic index e4f9f3c0d13..0911170fb74 100644 --- a/sql/sql_plugin_services.ic +++ b/sql/sql_plugin_services.ic @@ -1,5 +1,5 @@ /* Copyright (c) 2009, 2010, Oracle and/or its affiliates. - Copyright (c) 2012, 2019, MariaDB Corporation. + Copyright (c) 2012, 2020, MariaDB Corporation. 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 @@ -178,7 +178,8 @@ static struct wsrep_service_st wsrep_handler = { wsrep_OSU_method_get, wsrep_thd_has_ignored_error, wsrep_thd_set_ignored_error, - wsrep_thd_set_wsrep_aborter + wsrep_thd_set_wsrep_aborter, + wsrep_report_bf_lock_wait }; static struct thd_specifics_service_st thd_specifics_handler= diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 4a1484df2c2..c7efcfd1074 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -3983,6 +3983,7 @@ bool mysql_show_binlog_events(THD* thd) { Protocol *protocol= thd->protocol; List<Item> field_list; + char errmsg_buf[MYSYS_ERRMSG_SIZE]; const char *errmsg = 0; bool ret = TRUE; /* @@ -3997,6 +3998,9 @@ bool mysql_show_binlog_events(THD* thd) Master_info *mi= 0; LOG_INFO linfo; LEX_MASTER_INFO *lex_mi= &thd->lex->mi; + enum enum_binlog_checksum_alg checksum_alg; + my_off_t binlog_size; + MY_STAT s; DBUG_ENTER("mysql_show_binlog_events"); @@ -4045,10 +4049,6 @@ bool mysql_show_binlog_events(THD* thd) mi= 0; } - /* Validate user given position using checksum */ - if (lex_mi->pos == pos && !opt_master_verify_checksum) - verify_checksum_once= true; - unit->set_limit(thd->lex->current_select); name= search_file_name; @@ -4070,6 +4070,17 @@ bool mysql_show_binlog_events(THD* thd) if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0) goto err; + my_stat(linfo.log_file_name, &s, MYF(0)); + binlog_size= s.st_size; + if (lex_mi->pos > binlog_size) + { + sprintf(errmsg_buf, "Invalid pos specified. Requested from pos:%llu is " + "greater than actual file size:%lu\n", lex_mi->pos, + (ulong)s.st_size); + errmsg= errmsg_buf; + goto err; + } + /* to account binlog event header size */ @@ -4121,7 +4132,43 @@ bool mysql_show_binlog_events(THD* thd) } } - my_b_seek(&log, pos); + if (lex_mi->pos > BIN_LOG_HEADER_SIZE) + { + checksum_alg= description_event->checksum_alg; + /* Validate user given position using checksum */ + if (checksum_alg != BINLOG_CHECKSUM_ALG_OFF && + checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF) + { + if (!opt_master_verify_checksum) + verify_checksum_once= true; + my_b_seek(&log, pos); + } + else + { + my_off_t cur_pos= my_b_tell(&log); + ulong next_event_len= 0; + uchar buff[IO_SIZE]; + while (cur_pos < pos) + { + my_b_seek(&log, cur_pos + EVENT_LEN_OFFSET); + if (my_b_read(&log, (uchar *)buff, sizeof(next_event_len))) + { + mysql_mutex_unlock(log_lock); + errmsg = "Could not read event_length"; + goto err; + } + next_event_len= uint4korr(buff); + cur_pos= cur_pos + next_event_len; + } + if (cur_pos > pos) + { + mysql_mutex_unlock(log_lock); + errmsg= "Invalid input pos specified please provide valid one."; + goto err; + } + my_b_seek(&log, cur_pos); + } + } for (event_count = 0; (ev = Log_event::read_log_event(&log, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b0869e15289..420a64ba827 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -729,8 +729,9 @@ bool vers_select_conds_t::init_from_sysvar(THD *thd) if (type != SYSTEM_TIME_UNSPECIFIED && type != SYSTEM_TIME_ALL) { DBUG_ASSERT(type == SYSTEM_TIME_AS_OF); + Datetime dt(&in.ltime); start.item= new (thd->mem_root) - Item_datetime_literal(thd, &in.ltime, TIME_SECOND_PART_DIGITS); + Item_datetime_literal(thd, &dt, TIME_SECOND_PART_DIGITS); if (!start.item) return true; } @@ -794,15 +795,17 @@ Item* period_get_condition(THD *thd, TABLE_LIST *table, SELECT_LEX *select, { case SYSTEM_TIME_UNSPECIFIED: case SYSTEM_TIME_HISTORY: + { thd->variables.time_zone->gmt_sec_to_TIME(&max_time, TIMESTAMP_MAX_VALUE); max_time.second_part= TIME_MAX_SECOND_PART; - curr= newx Item_datetime_literal(thd, &max_time, TIME_SECOND_PART_DIGITS); + Datetime dt(&max_time); + curr= newx Item_datetime_literal(thd, &dt, TIME_SECOND_PART_DIGITS); if (conds->type == SYSTEM_TIME_UNSPECIFIED) cond1= newx Item_func_eq(thd, conds->field_end, curr); else cond1= newx Item_func_lt(thd, conds->field_end, curr); break; - break; + } case SYSTEM_TIME_AS_OF: cond1= newx Item_func_le(thd, conds->field_start, conds->start.item); cond2= newx Item_func_gt(thd, conds->field_end, conds->start.item); @@ -1134,6 +1137,8 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num, proc_param= proc_param_init; tables_list= tables_init; select_lex= select_lex_arg; + DBUG_PRINT("info", ("select %p (%u) = JOIN %p", + select_lex, select_lex->select_number, this)); select_lex->join= this; join_list= &select_lex->top_join_list; union_part= unit_arg->is_unit_op(); @@ -4478,6 +4483,9 @@ int JOIN::destroy() { DBUG_ENTER("JOIN::destroy"); + + DBUG_PRINT("info", ("select %p (%u) <> JOIN %p", + select_lex, select_lex->select_number, this)); select_lex->join= 0; cond_equal= 0; @@ -23706,6 +23714,9 @@ check_reverse_order: else if (select && select->quick) select->quick->need_sorted_output(); + tab->read_record.unlock_row= (tab->type == JT_EQ_REF) ? + join_read_key_unlock_row : rr_unlock_row; + } // QEP has been modified /* diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 452690f3237..1e32e8b2925 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -9669,11 +9669,6 @@ int finalize_schema_table(st_plugin_int *plugin) DBUG_RETURN(0); } -/* - This is used to create a timestamp field -*/ - -MYSQL_TIME zero_time={ 0,0,0,0,0,0,0,0, MYSQL_TIMESTAMP_TIME }; /** Output trigger information (SHOW CREATE TRIGGER) to the client. @@ -9758,8 +9753,9 @@ static bool show_create_trigger_impl(THD *thd, Trigger *trigger) MY_CS_NAME_SIZE), mem_root); + static const Datetime zero_datetime(Datetime::zero()); Item_datetime_literal *tmp= (new (mem_root) - Item_datetime_literal(thd, &zero_time, 2)); + Item_datetime_literal(thd, &zero_datetime, 2)); tmp->set_name(thd, Lex_cstring(STRING_WITH_LEN("Created"))); fields.push_back(tmp, mem_root); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8834c4d26e9..15d190c3139 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -578,7 +578,7 @@ uint build_table_filename(char *buff, size_t bufflen, const char *db, /** - Create path to a temporary table mysql_tmpdir/#sql1234_12_1 + Create path to a temporary table mysql_tmpdir/#sql-temptable-1234-12-1 (i.e. to its .FRM file but without an extension). @param thd The thread handle. @@ -2443,6 +2443,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, was_table|= wrong_drop_sequence; local_non_tmp_error= 1; error= table_type == TABLE_TYPE_UNKNOWN ? ENOENT : -1; + tdc_remove_table(thd, db.str, table_name.str); } else { diff --git a/sql/sql_test.cc b/sql/sql_test.cc index f19d27df71f..cc3c9badefb 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -387,10 +387,10 @@ void print_sjm(SJ_MATERIALIZATION_INFO *sjm) /* Debugging help: force List<...>::elem function not be removed as unused. */ -Item* (List<Item>:: *dbug_list_item_elem_ptr)(uint)= &List<Item>::elem; -Item_equal* (List<Item_equal>:: *dbug_list_item_equal_elem_ptr)(uint)= +Item* (List<Item>::*dbug_list_item_elem_ptr)(uint)= &List<Item>::elem; +Item_equal* (List<Item_equal>::*dbug_list_item_equal_elem_ptr)(uint)= &List<Item_equal>::elem; -TABLE_LIST* (List<TABLE_LIST>:: *dbug_list_table_list_elem_ptr)(uint) = +TABLE_LIST* (List<TABLE_LIST>::*dbug_list_table_list_elem_ptr)(uint) = &List<TABLE_LIST>::elem; #endif diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc index 37f0f80e8a0..df774a5d8dd 100644 --- a/sql/sql_tvc.cc +++ b/sql/sql_tvc.cc @@ -22,6 +22,7 @@ #include "sql_explain.h" #include "sql_parse.h" #include "sql_cte.h" +#include "my_json_writer.h" /** @@ -903,6 +904,10 @@ Item *Item_func_in::in_predicate_to_in_subs_transformer(THD *thd, if (!transform_into_subq) return this; + Json_writer_object trace_wrapper(thd); + Json_writer_object trace_conv(thd, "in_to_subquery_conversion"); + trace_conv.add("item", this); + transform_into_subq= false; List<List_item> values; @@ -922,13 +927,29 @@ Item *Item_func_in::in_predicate_to_in_subs_transformer(THD *thd, uint32 length= max_length_of_left_expr(); if (!length || length > tmp_table_max_key_length() || args[0]->cols() > tmp_table_max_key_parts()) + { + trace_conv.add("done", false); + trace_conv.add("reason", "key is too long"); return this; - + } + for (uint i=1; i < arg_count; i++) { - if (!args[i]->const_item() || cmp_row_types(args[0], args[i])) + if (!args[i]->const_item()) + { + trace_conv.add("done", false); + trace_conv.add("reason", "non-constant element in the IN-list"); return this; + } + + if (cmp_row_types(args[0], args[i])) + { + trace_conv.add("done", false); + trace_conv.add("reason", "type mismatch"); + return this; + } } + Json_writer_array trace_nested_obj(thd, "conversion"); Query_arena backup; Query_arena *arena= thd->activate_stmt_arena_if_needed(&backup); @@ -1020,6 +1041,7 @@ Item *Item_func_in::in_predicate_to_in_subs_transformer(THD *thd, goto err; parent_select->curr_tvc_name++; + return sq; err: diff --git a/sql/sql_type.cc b/sql/sql_type.cc index fdd92d3d7bb..22375d2962c 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -8820,7 +8820,10 @@ Type_handler_date_common::create_literal_item(THD *thd, if (tmp.is_valid_temporal() && tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATE && !have_important_literal_warnings(&st)) - item= new (thd->mem_root) Item_date_literal(thd, tmp.get_mysql_time()); + { + Date d(&tmp); + item= new (thd->mem_root) Item_date_literal(thd, &d); + } literal_warn(thd, item, str, length, cs, &st, "DATE", send_error); return item; } @@ -8839,8 +8842,10 @@ Type_handler_temporal_with_date::create_literal_item(THD *thd, if (tmp.is_valid_temporal() && tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATETIME && !have_important_literal_warnings(&st)) - item= new (thd->mem_root) Item_datetime_literal(thd, tmp.get_mysql_time(), - st.precision); + { + Datetime dt(&tmp); + item= new (thd->mem_root) Item_datetime_literal(thd, &dt, st.precision); + } literal_warn(thd, item, str, length, cs, &st, "DATETIME", send_error); return item; } @@ -8859,8 +8864,7 @@ Type_handler_time_common::create_literal_item(THD *thd, Time tmp(thd, &st, str, length, cs, opt); if (tmp.is_valid_time() && !have_important_literal_warnings(&st)) - item= new (thd->mem_root) Item_time_literal(thd, tmp.get_mysql_time(), - st.precision); + item= new (thd->mem_root) Item_time_literal(thd, &tmp, st.precision); literal_warn(thd, item, str, length, cs, &st, "TIME", send_error); return item; } diff --git a/sql/sql_type.h b/sql/sql_type.h index f94d17541a4..41e840d9ed7 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -1201,6 +1201,13 @@ public: } // End of constuctors + bool copy_valid_value_to_mysql_time(MYSQL_TIME *ltime) const + { + DBUG_ASSERT(is_valid_temporal()); + *ltime= *this; + return false; + } + longlong to_longlong() const { if (!is_valid_temporal()) @@ -1867,6 +1874,11 @@ public: { return is_valid_time() ? Temporal::to_packed() : 0; } + longlong valid_time_to_packed() const + { + DBUG_ASSERT(is_valid_time_slow()); + return Temporal::to_packed(); + } long fraction_remainder(uint dec) const { DBUG_ASSERT(is_valid_time()); @@ -2041,6 +2053,11 @@ public: { return ::check_date_with_warn(thd, this, flags, MYSQL_TIMESTAMP_ERROR); } + bool check_date_with_warn(THD *thd) + { + return ::check_date_with_warn(thd, this, Temporal::sql_mode_for_dates(thd), + MYSQL_TIMESTAMP_ERROR); + } static date_conv_mode_t comparison_flags_for_get_date() { return TIME_INVALID_DATES | TIME_FUZZY_DATES; } }; @@ -2109,11 +2126,37 @@ public: datetime_to_date(this); DBUG_ASSERT(is_valid_date_slow()); } + explicit Date(const Temporal_hybrid *from) + { + from->copy_valid_value_to_mysql_time(this); + DBUG_ASSERT(is_valid_date_slow()); + } bool is_valid_date() const { DBUG_ASSERT(is_valid_value_slow()); return time_type == MYSQL_TIMESTAMP_DATE; } + bool check_date(date_conv_mode_t flags, int *warnings) const + { + DBUG_ASSERT(is_valid_date_slow()); + return ::check_date(this, (year || month || day), + ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE), + warnings); + } + bool check_date(THD *thd, int *warnings) const + { + return check_date(Temporal::sql_mode_for_dates(thd), warnings); + } + bool check_date(date_conv_mode_t flags) const + { + int dummy; /* unused */ + return check_date(flags, &dummy); + } + bool check_date(THD *thd) const + { + int dummy; + return check_date(Temporal::sql_mode_for_dates(thd), &dummy); + } const MYSQL_TIME *get_mysql_time() const { DBUG_ASSERT(is_valid_date_slow()); @@ -2156,6 +2199,11 @@ public: return Temporal_with_date::yearweek(week_behaviour); } + longlong valid_date_to_packed() const + { + DBUG_ASSERT(is_valid_date_slow()); + return Temporal::to_packed(); + } longlong to_longlong() const { return is_valid_date() ? (longlong) TIME_to_ulonglong_date(this) : 0LL; @@ -2342,6 +2390,16 @@ public: { round(thd, dec, time_round_mode_t(fuzzydate), warn); } + explicit Datetime(const Temporal_hybrid *from) + { + from->copy_valid_value_to_mysql_time(this); + DBUG_ASSERT(is_valid_datetime_slow()); + } + explicit Datetime(const MYSQL_TIME *from) + { + *(static_cast<MYSQL_TIME*>(this))= *from; + DBUG_ASSERT(is_valid_datetime_slow()); + } bool is_valid_datetime() const { @@ -2364,6 +2422,10 @@ public: int dummy; /* unused */ return check_date(flags, &dummy); } + bool check_date(THD *thd) const + { + return check_date(Temporal::sql_mode_for_dates(thd)); + } bool hhmmssff_is_zero() const { DBUG_ASSERT(is_valid_datetime_slow()); @@ -2472,6 +2534,11 @@ public: { return is_valid_datetime() ? Temporal::to_packed() : 0; } + longlong valid_datetime_to_packed() const + { + DBUG_ASSERT(is_valid_datetime_slow()); + return Temporal::to_packed(); + } long fraction_remainder(uint dec) const { DBUG_ASSERT(is_valid_datetime()); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index f1df76508d7..99a199886ce 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -2721,6 +2721,8 @@ bool st_select_lex::cleanup() bool error= FALSE; DBUG_ENTER("st_select_lex::cleanup()"); + DBUG_PRINT("info", ("select: %p (%u) JOIN %p", + this, select_number, join)); cleanup_order(order_list.first); cleanup_order(group_list.first); cleanup_ftfuncs(this); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 3fa54a3bf54..e54b335e418 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2447,8 +2447,6 @@ create: Lex->create_info.default_table_charset= NULL; Lex->create_info.schema_comment= NULL; Lex->create_info.used_fields= 0; - if (Lex->main_select_push()) - MYSQL_YYABORT; } opt_create_database_options { @@ -2457,7 +2455,6 @@ create: $1 | $3))) MYSQL_YYABORT; lex->name= $4; - Lex->pop_select(); //main select } | create_or_replace definer_opt opt_view_suid VIEW_SYM opt_if_not_exists table_ident @@ -3174,10 +3171,13 @@ sp_cursor_stmt: { DBUG_ASSERT(thd->free_list == NULL); Lex->sphead->reset_lex(thd, $1); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; } select { DBUG_ASSERT(Lex == $1); + Lex->pop_select(); //main select if (unlikely($1->stmt_finalize(thd)) || unlikely($1->sphead->restore_lex(thd))) MYSQL_YYABORT; @@ -3623,6 +3623,11 @@ sp_proc_stmt_statement: Lex_input_stream *lip= YYLIP; lex->sphead->reset_lex(thd); + /* + We should not push main select here, it will be done or not + done by the statement, we just provide only a new LEX for the + statement here as if it is start of parsing a new statement. + */ lex->sphead->m_tmp_query= lip->get_tok_start(); } sp_statement @@ -3736,12 +3741,15 @@ expr_lex: sp_expr_lex(thd, thd->lex)))) MYSQL_YYABORT; Lex->sphead->reset_lex(thd, $<expr_lex>$); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; } expr { $$= $<expr_lex>1; $$->sp_lex_in_use= true; $$->set_item($2); + Lex->pop_select(); //min select if ($$->sphead->restore_lex(thd)) MYSQL_YYABORT; } @@ -3762,6 +3770,8 @@ assignment_source_expr: { DBUG_ASSERT(thd->free_list == NULL); Lex->sphead->reset_lex(thd, $1); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; } expr { @@ -3770,6 +3780,7 @@ assignment_source_expr: $$->sp_lex_in_use= true; $$->set_item_and_free_list($3, thd->free_list); thd->free_list= NULL; + Lex->pop_select(); //min select if ($$->sphead->restore_lex(thd)) MYSQL_YYABORT; } @@ -3779,6 +3790,8 @@ for_loop_bound_expr: assignment_source_lex { Lex->sphead->reset_lex(thd, $1); + if (Lex->main_select_push(true)) + MYSQL_YYABORT; Lex->current_select->parsing_place= FOR_LOOP_BOUND; } expr @@ -3787,6 +3800,7 @@ for_loop_bound_expr: $$= $1; $$->sp_lex_in_use= true; $$->set_item_and_free_list($3, NULL); + Lex->pop_select(); //main select if (unlikely($$->sphead->restore_lex(thd))) MYSQL_YYABORT; Lex->current_select->parsing_place= NO_MATTER; @@ -7160,7 +7174,7 @@ alter: Lex->create_info.default_table_charset= NULL; Lex->create_info.schema_comment= NULL; Lex->create_info.used_fields= 0; - if (Lex->main_select_push()) + if (Lex->main_select_push(true)) MYSQL_YYABORT; } create_database_options @@ -12611,7 +12625,7 @@ do: { LEX *lex=Lex; lex->sql_command = SQLCOM_DO; - if (lex->main_select_push()) + if (lex->main_select_push(true)) MYSQL_YYABORT; mysql_init_select(lex); } @@ -16070,12 +16084,13 @@ set: SET { LEX *lex=Lex; - if (lex->main_select_push()) - MYSQL_YYABORT; lex->set_stmt_init(); } set_param - stmt_end {} + { + if (Lex->check_main_unit_semantics()) + MYSQL_YYABORT; + } ; set_param: @@ -16178,24 +16193,44 @@ opt_var_ident_type: Let's put them to the main ones. */ set_stmt_option: - ident_cli equal set_expr_or_default + ident_cli equal + { + if (Lex->main_select_push(false)) + MYSQL_YYABORT; + } + set_expr_or_default { Lex_ident_sys tmp(thd, &$1); if (unlikely(!tmp.str) || - unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $3))) + unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $4))) MYSQL_YYABORT; + Lex->pop_select(); //min select } - | ident_cli '.' ident equal set_expr_or_default + | ident_cli '.' ident equal + { + if (Lex->main_select_push(false)) + MYSQL_YYABORT; + } + set_expr_or_default { Lex_ident_sys tmp(thd, &$1); if (unlikely(!tmp.str) || - unlikely(Lex->set_system_variable(thd, Lex->option_type, &tmp, &$3, $5))) + unlikely(Lex->set_system_variable(thd, Lex->option_type, + &tmp, &$3, $6))) + MYSQL_YYABORT; + Lex->pop_select(); //min select + } + | DEFAULT '.' ident equal + { + if (Lex->main_select_push(false)) MYSQL_YYABORT; } - | DEFAULT '.' ident equal set_expr_or_default + set_expr_or_default { - if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $5))) + if (unlikely(Lex->set_default_system_variable(Lex->option_type, + &$3, $6))) MYSQL_YYABORT; + Lex->pop_select(); //min select } ; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 4bda42b2ffa..64040243df0 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -362,7 +362,7 @@ static Sys_var_long Sys_pfs_digest_size( "Size of the statement digest." " Use 0 to disable, -1 for automated sizing.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_digest_sizing), - CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 200), + CMD_LINE(REQUIRED_ARG), VALID_RANGE(-1, 1024*1024), DEFAULT(PFS_AUTOSCALE_VALUE), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_events_transactions_history_long_size( diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index ba56a7b4bfb..c21a4a83165 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -1861,13 +1861,16 @@ public: return false; } void session_save_default(THD *thd, set_var *var) - { var->save_result.ulonglong_value= global_var(ulonglong) & bitmask; } + { + var->save_result.ulonglong_value= + (reverse_semantics == !(global_var(ulonglong) & bitmask)); + } void global_save_default(THD *thd, set_var *var) { var->save_result.ulonglong_value= option.def_value; } uchar *valptr(THD *thd, ulonglong val) { - thd->sys_var_tmp.my_bool_value= reverse_semantics ^ ((val & bitmask) != 0); + thd->sys_var_tmp.my_bool_value= (reverse_semantics == !(val & bitmask)); return (uchar*) &thd->sys_var_tmp.my_bool_value; } uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) @@ -2723,7 +2726,11 @@ private: Datetime::Options opt(TIME_CONV_NONE | TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE, thd); - res= var->value->get_date(thd, &out.ltime, opt); + /* + var->value is allowed to return DATETIME and DATE + Make sure to convert DATE to DATETIME. + */ + res= Datetime(thd, var->value, opt).copy_to_mysql_time(&out.ltime); } else // set DEFAULT from global var { diff --git a/sql/table.cc b/sql/table.cc index 6f0aa8d3418..779ce768eee 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -9600,7 +9600,8 @@ bool TR_table::query(MYSQL_TIME &commit_time, bool backwards) SELECT_LEX &slex= *(thd->lex->first_select_lex()); Name_resolution_context_backup backup(slex.context, *this); Item *field= newx Item_field(thd, &slex.context, (*this)[FLD_COMMIT_TS]); - Item *value= newx Item_datetime_literal(thd, &commit_time, 6); + Datetime dt(&commit_time); + Item *value= newx Item_datetime_literal(thd, &dt, 6); COND *conds; if (backwards) conds= newx Item_func_ge(thd, field, value); diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc index 139cd5cd7ae..8ea9ca79697 100644 --- a/sql/wsrep_dummy.cc +++ b/sql/wsrep_dummy.cc @@ -151,4 +151,8 @@ void wsrep_thd_set_ignored_error(THD*, my_bool) ulong wsrep_OSU_method_get(const THD*) { return 0;} bool wsrep_thd_set_wsrep_aborter(THD*, THD*) -{ return 0;}
\ No newline at end of file +{ return 0;} + +void wsrep_report_bf_lock_wait(const THD*, + unsigned long long) +{} diff --git a/sql/wsrep_high_priority_service.cc b/sql/wsrep_high_priority_service.cc index 8f52938f9ed..5961a9574eb 100644 --- a/sql/wsrep_high_priority_service.cc +++ b/sql/wsrep_high_priority_service.cc @@ -317,9 +317,15 @@ int Wsrep_high_priority_service::commit(const wsrep::ws_handle& ws_handle, DBUG_ASSERT(thd->wsrep_trx().active()); thd->wsrep_cs().prepare_for_ordering(ws_handle, ws_meta, true); thd_proc_info(thd, "committing"); + int ret=0; const bool is_ordered= !ws_meta.seqno().is_undefined(); - int ret= trans_commit(thd); + + if (!thd->transaction->stmt.is_empty()) + ret= trans_commit_stmt(thd); + + if (ret == 0) + ret= trans_commit(thd); if (ret == 0) { diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index d0155f27d6d..a6b0991e82b 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1927,6 +1927,14 @@ bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, } return true; break; + case SQLCOM_DROP_TRIGGER: + DBUG_ASSERT(table_list); + if (thd->find_temporary_table(table_list)) + { + return false; + } + return true; + break; case SQLCOM_ALTER_TABLE: if (create_info && !wsrep_should_replicate_ddl(thd, create_info->db_type->db_type)) @@ -2867,7 +2875,14 @@ int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len) definer_host.length= 0; } - stmt_query.append(STRING_WITH_LEN("CREATE ")); + const LEX_CSTRING command[2]= + {{ C_STRING_WITH_LEN("CREATE ") }, + { C_STRING_WITH_LEN("CREATE OR REPLACE ") }}; + + if (thd->lex->create_info.or_replace()) + stmt_query.append(command[1]); + else + stmt_query.append(command[0]); append_definer(thd, &stmt_query, &definer_user, &definer_host); diff --git a/sql/wsrep_schema.cc b/sql/wsrep_schema.cc index 643f0072ebf..434f8779544 100644 --- a/sql/wsrep_schema.cc +++ b/sql/wsrep_schema.cc @@ -251,6 +251,11 @@ static int open_table(THD* thd, NULL, lock_type); if (!open_n_lock_single_table(thd, &tables, tables.lock_type, flags)) { + if (thd->is_error()) { + WSREP_WARN("Can't lock table %s.%s : %d (%s)", + schema_name->str, table_name->str, + thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message()); + } close_thread_tables(thd); my_error(ER_NO_SUCH_TABLE, MYF(0), schema_name->str, table_name->str); DBUG_RETURN(1); @@ -953,7 +958,7 @@ int Wsrep_schema::update_fragment_meta(THD* thd, Wsrep_schema_impl::binlog_off binlog_off(thd); int error; - uchar key[MAX_KEY_LENGTH]; + uchar key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; key_part_map key_map= 0; TABLE* frag_table= 0; @@ -1015,7 +1020,7 @@ static int remove_fragment(THD* thd, seqno.get()); int ret= 0; int error; - uchar key[MAX_KEY_LENGTH]; + uchar key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; key_part_map key_map= 0; DBUG_ASSERT(server_id.is_undefined() == false); @@ -1141,7 +1146,7 @@ int Wsrep_schema::replay_transaction(THD* orig_thd, int ret= 1; int error; TABLE* frag_table= 0; - uchar key[MAX_KEY_LENGTH]; + uchar key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; key_part_map key_map= 0; for (std::vector<wsrep::seqno>::const_iterator i= fragments.begin(); diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index 610e864593e..f8c3f4d299b 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -1,4 +1,4 @@ -/* Copyright 2008-2017 Codership Oy <http://www.codership.com> +/* Copyright 2008-2020 Codership Oy <http://www.codership.com> 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 @@ -54,7 +54,6 @@ my_bool wsrep_sst_donor_rejects_queries= FALSE; bool sst_joiner_completed = false; bool sst_donor_completed = false; -bool sst_needed = false; struct sst_thread_arg { @@ -308,7 +307,6 @@ bool wsrep_before_SE() && strcmp (wsrep_sst_method, WSREP_SST_MYSQLDUMP)); } -static bool sst_in_progress = false; // Signal end of SST static void wsrep_sst_complete (THD* thd, int const rcode) @@ -1629,12 +1627,11 @@ static void* sst_donor_thread (void* a) wsrep_uuid_t ret_uuid= WSREP_UUID_UNDEFINED; // seqno of complete SST wsrep_seqno_t ret_seqno= WSREP_SEQNO_UNDEFINED; - // SST is now in progress - sst_in_progress= true; - - wsp::thd thd(FALSE); // we turn off wsrep_on for this THD so that it can - // operate with wsrep_ready == OFF + // We turn off wsrep_on for this THD so that it can + // operate with wsrep_ready == OFF + // We also set this SST thread THD as system thread + wsp::thd thd(FALSE, true); wsp::process proc(arg->cmd, "r", arg->env); err= -proc.error(); @@ -1736,10 +1733,7 @@ wait_signal: proc.wait(); wsrep_donor_monitor_end(); - sst_in_progress= false; - - - return NULL; + return nullptr; } static int sst_donate_other (const char* method, @@ -1891,8 +1885,3 @@ int wsrep_sst_donate(const std::string& msg, return (ret >= 0 ? 0 : 1); } - -bool wsrep_is_sst_progress() -{ - return (sst_in_progress); -} diff --git a/sql/wsrep_sst.h b/sql/wsrep_sst.h index 50f2d362c5a..2389db4abe7 100644 --- a/sql/wsrep_sst.h +++ b/sql/wsrep_sst.h @@ -77,7 +77,6 @@ extern void wsrep_SE_init_grab(); /*! grab init critical section */ extern void wsrep_SE_init_wait(); /*! wait for SE init to complete */ extern void wsrep_SE_init_done(); /*! signal that SE init is complte */ extern void wsrep_SE_initialized(); /*! mark SE initialization complete */ -extern bool wsrep_is_sst_progress(); /** Return a string containing the state transfer request string. @@ -103,6 +102,5 @@ int wsrep_sst_donate(const std::string& request, #define wsrep_SE_init_grab() do { } while(0) #define wsrep_SE_init_done() do { } while(0) #define wsrep_sst_continue() (0) -#define wsrep_is_sst_progress() (0) #endif /* WSREP_SST_H */ diff --git a/sql/wsrep_trans_observer.h b/sql/wsrep_trans_observer.h index 35f670b9af6..35b93cb4bf5 100644 --- a/sql/wsrep_trans_observer.h +++ b/sql/wsrep_trans_observer.h @@ -136,9 +136,11 @@ static inline size_t wsrep_fragments_certified_for_stmt(THD* thd) static inline int wsrep_start_transaction(THD* thd, wsrep_trx_id_t trx_id) { - return (thd->wsrep_cs().state() != wsrep::client_state::s_none ? - thd->wsrep_cs().start_transaction(wsrep::transaction_id(trx_id)) : - 0); + if (thd->wsrep_cs().state() != wsrep::client_state::s_none) { + if (wsrep_is_active(thd) == false) + return thd->wsrep_cs().start_transaction(wsrep::transaction_id(trx_id)); + } + return 0; } /**/ diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc index 148def54aaf..a679304c40a 100644 --- a/sql/wsrep_utils.cc +++ b/sql/wsrep_utils.cc @@ -417,7 +417,7 @@ process::wait () return err_; } -thd::thd (my_bool won) : init(), ptr(new THD(0)) +thd::thd (my_bool won, bool system_thread) : init(), ptr(new THD(0)) { if (ptr) { @@ -426,6 +426,8 @@ thd::thd (my_bool won) : init(), ptr(new THD(0)) wsrep_store_threadvars(ptr); ptr->variables.option_bits&= ~OPTION_BIN_LOG; // disable binlog ptr->variables.wsrep_on= won; + if (system_thread) + ptr->system_thread= SYSTEM_THREAD_GENERIC; ptr->security_ctx->master_access= ALL_KNOWN_ACL; lex_start(ptr); } diff --git a/sql/wsrep_utils.h b/sql/wsrep_utils.h index 4b010816a40..974c623521e 100644 --- a/sql/wsrep_utils.h +++ b/sql/wsrep_utils.h @@ -303,7 +303,7 @@ class thd public: - thd(my_bool wsrep_on); + thd(my_bool wsrep_on, bool system_thread=false); ~thd(); THD* const ptr; }; diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index 0547674a4dd..4fac94d211e 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -190,7 +190,6 @@ SET(INNOBASE_SOURCES include/os0event.h include/os0file.h include/os0file.ic - include/os0proc.h include/os0thread.h include/page0cur.h include/page0cur.ic @@ -265,7 +264,6 @@ SET(INNOBASE_SOURCES include/ut0byte.h include/ut0byte.ic include/ut0counter.h - include/ut0crc32.h include/ut0dbg.h include/ut0list.h include/ut0list.ic @@ -296,7 +294,6 @@ SET(INNOBASE_SOURCES mem/mem0mem.cc mtr/mtr0mtr.cc os/os0file.cc - os/os0proc.cc os/os0event.cc os/os0thread.cc page/page0cur.cc @@ -342,7 +339,6 @@ SET(INNOBASE_SOURCES trx/trx0sys.cc trx/trx0trx.cc trx/trx0undo.cc - ut/ut0crc32.cc ut/ut0dbg.cc ut/ut0list.cc ut/ut0mem.cc diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 40684e95615..8ed25db8cb7 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -1025,8 +1025,7 @@ btr_create( if (UNIV_UNLIKELY(type & DICT_IBUF)) { /* Allocate first the ibuf header page */ buf_block_t* ibuf_hdr_block = fseg_create( - space, 0, - IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr); + space, IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr); if (ibuf_hdr_block == NULL) { return(FIL_NULL); @@ -1056,8 +1055,8 @@ btr_create( flst_init(block, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr); } else { - block = fseg_create(space, 0, - PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr); + block = fseg_create(space, PAGE_HEADER + PAGE_BTR_SEG_TOP, + mtr); if (block == NULL) { return(FIL_NULL); @@ -1065,8 +1064,8 @@ btr_create( buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); - if (!fseg_create(space, block->page.id().page_no(), - PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr)) { + if (!fseg_create(space, PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr, + false, block)) { /* Not enough space for new segment, free root segment before return. */ btr_free_root(block, mtr); diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 9c627ecd145..a190c11eb0a 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -5423,8 +5423,7 @@ btr_cur_compress_if_useful( const buf_block_t* block = btr_cur_get_block(cursor); /* Check whether page lock prevents the compression */ - if (!lock_test_prdt_page_lock(trx, block->page.id().space(), - block->page.id().page_no())) { + if (!lock_test_prdt_page_lock(trx, block->page.id())) { return(false); } } diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 5977271dc20..85e21371e37 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -1763,10 +1763,6 @@ inline bool buf_pool_t::realloc(buf_block_t *block) new_block->left_side = TRUE; #endif /* BTR_CUR_HASH_ADAPT */ - new_block->lock_hash_val = block->lock_hash_val; - ut_ad(new_block->lock_hash_val == lock_rec_hash( - id.space(), id.page_no())); - hash_lock->write_unlock(); /* free block */ @@ -3368,9 +3364,6 @@ evict_from_pool: /* Set after buf_relocate(). */ block->page.set_buf_fix_count(1); - block->lock_hash_val = lock_rec_hash(page_id.space(), - page_id.page_no()); - if (!block->page.oldest_modification()) { ut_d(UT_LIST_REMOVE(buf_pool.zip_clean, &block->page)); } else { @@ -3800,7 +3793,6 @@ void buf_block_t::initialise(const page_id_t page_id, ulint zip_size, { ut_ad(page.state() != BUF_BLOCK_FILE_PAGE); buf_block_init_low(this); - lock_hash_val= lock_rec_hash(page_id.space(), page_id.page_no()); page.init(page_id, fix); page_zip_set_size(&page.zip, zip_size); } @@ -3823,6 +3815,7 @@ buf_page_create(fil_space_t *space, uint32_t offset, ut_ad(page_id.space() != 0 || !zip_size); space->free_page(offset, false); +loop: buf_block_t *free_block= buf_LRU_get_free_block(false); free_block->initialise(page_id, zip_size, 1); @@ -3837,35 +3830,69 @@ buf_page_create(fil_space_t *space, uint32_t offset, !buf_pool.watch_is_sentinel(block->page)) { #ifdef BTR_CUR_HASH_ADAPT - const bool drop_hash_entry= block->page.state() == BUF_BLOCK_FILE_PAGE && - UNIV_LIKELY_NULL(block->index); - if (UNIV_UNLIKELY(drop_hash_entry)) + const dict_index_t *drop_hash_entry= nullptr; +#endif + switch (block->page.state()) { + default: + ut_ad(0); + break; + case BUF_BLOCK_FILE_PAGE: + buf_block_buf_fix_inc(block, __FILE__, __LINE__); + { + const auto num_fix_count= mtr->get_fix_count(block) + 1; + while (block->page.io_fix() != BUF_IO_NONE || + num_fix_count != block->page.buf_fix_count()) + { + mutex_exit(&buf_pool.mutex); + os_thread_yield(); + mutex_enter(&buf_pool.mutex); + } + } rw_lock_x_lock(&block->lock); -#endif /* BTR_CUR_HASH_ADAPT */ +#ifdef BTR_CUR_HASH_ADAPT + drop_hash_entry= block->index; +#endif + buf_LRU_block_free_non_file_page(free_block); + break; + case BUF_BLOCK_ZIP_PAGE: + page_hash_latch *hash_lock= buf_pool.page_hash.lock_get(fold); + hash_lock->write_lock(); + if (block->page.io_fix() != BUF_IO_NONE) + { + hash_lock->write_unlock(); + buf_LRU_block_free_non_file_page(block); + mutex_exit(&buf_pool.mutex); + goto loop; + } + + rw_lock_x_lock(&free_block->lock); + buf_relocate(&block->page, &free_block->page); + + if (block->page.oldest_modification() > 0) + buf_flush_relocate_on_flush_list(&block->page, &free_block->page); +#ifdef UNIV_DEBUG + else + UT_LIST_REMOVE(buf_pool.zip_clean, &block->page); +#endif + + free_block->page.set_state(BUF_BLOCK_FILE_PAGE); + buf_unzip_LRU_add_block(free_block, FALSE); + hash_lock->write_unlock(); + buf_page_free_descriptor(&block->page); + block= free_block; + buf_block_buf_fix_inc(block, __FILE__, __LINE__); + break; + } - /* Page can be found in buf_pool */ - buf_LRU_block_free_non_file_page(free_block); mutex_exit(&buf_pool.mutex); #ifdef BTR_CUR_HASH_ADAPT - if (UNIV_UNLIKELY(drop_hash_entry)) - { + if (drop_hash_entry) btr_search_drop_page_hash_index(block); - rw_lock_x_unlock(&block->lock); - } #endif /* BTR_CUR_HASH_ADAPT */ - if (!recv_recovery_is_on()) - /* FIXME: Remove the redundant lookup and avoid - the unnecessary invocation of buf_zip_decompress(). - We may have to convert buf_page_t to buf_block_t, - but we are going to initialize the page. */ - return buf_page_get_gen(page_id, zip_size, RW_NO_LATCH, - block, BUF_GET_POSSIBLY_FREED, - __FILE__, __LINE__, mtr); - mutex_exit(&recv_sys.mutex); - block= buf_page_get_with_no_latch(page_id, zip_size, mtr); - mutex_enter(&recv_sys.mutex); + mtr_memo_push(mtr, block, MTR_MEMO_PAGE_X_FIX); + return block; } @@ -3889,13 +3916,13 @@ buf_page_create(fil_space_t *space, uint32_t offset, ut_d(block->page.in_page_hash= true); HASH_INSERT(buf_page_t, hash, &buf_pool.page_hash, fold, &block->page); + rw_lock_x_lock(&block->lock); if (UNIV_UNLIKELY(zip_size)) { /* Prevent race conditions during buf_buddy_alloc(), which may release and reacquire buf_pool.mutex, by IO-fixing and X-latching the block. */ block->page.set_io_fix(BUF_IO_READ); - rw_lock_x_lock(&block->lock); hash_lock->write_unlock(); /* buf_pool.mutex may be released and reacquired by @@ -3911,14 +3938,13 @@ buf_page_create(fil_space_t *space, uint32_t offset, buf_unzip_LRU_add_block(block, FALSE); block->page.set_io_fix(BUF_IO_NONE); - rw_lock_x_unlock(&block->lock); } else hash_lock->write_unlock(); mutex_exit(&buf_pool.mutex); - mtr->memo_push(block, MTR_MEMO_BUF_FIX); + mtr->memo_push(block, MTR_MEMO_PAGE_X_FIX); block->page.set_accessed(); buf_pool.stat.n_pages_created++; diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index 516aeef1002..4b2822bf865 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -166,9 +166,9 @@ start_again: } } - block2 = fseg_create(fil_system.sys_space, TRX_SYS_PAGE_NO, - TRX_SYS_DOUBLEWRITE - + TRX_SYS_DOUBLEWRITE_FSEG, &mtr); + block2 = fseg_create(fil_system.sys_space, + TRX_SYS_DOUBLEWRITE + TRX_SYS_DOUBLEWRITE_FSEG, + &mtr, false, trx_sys_block); if (block2 == NULL) { too_small: diff --git a/storage/innobase/dict/dict0boot.cc b/storage/innobase/dict/dict0boot.cc index 833f2621de6..359684416ed 100644 --- a/storage/innobase/dict/dict0boot.cc +++ b/storage/innobase/dict/dict0boot.cc @@ -134,7 +134,7 @@ dict_hdr_create( /* Create the dictionary header file block in a new, allocated file segment in the system tablespace */ - block = fseg_create(fil_system.sys_space, 0, + block = fseg_create(fil_system.sys_space, DICT_HDR + DICT_HDR_FSEG_HEADER, mtr); ut_a(block->page.id() == page_id_t(DICT_HDR_SPACE, DICT_HDR_PAGE_NO)); diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 097c907a826..d9338af1327 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -5027,7 +5027,11 @@ dict_foreign_qualify_index( return(false); } - if (index->type & (DICT_SPATIAL | DICT_FTS)) { + if (index->type & (DICT_SPATIAL | DICT_FTS | DICT_CORRUPT)) { + return false; + } + + if (index->online_status >= ONLINE_INDEX_ABORTED) { return false; } diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index b135e042dc7..489f4d491d1 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -2632,7 +2632,7 @@ static const char* dict_load_table_low(const table_name_t& name, name.m_name, NULL, n_cols + n_v_col, n_v_col, flags, flags2); (*table)->space_id = space_id; (*table)->id = table_id; - (*table)->file_unreadable = false; + (*table)->file_unreadable = !!(flags2 & DICT_TF2_DISCARDED); return(NULL); } @@ -2686,28 +2686,22 @@ dict_get_and_save_data_dir_path( ut_ad(!table->is_temporary()); ut_ad(!table->space || table->space->id == table->space_id); - if (!table->data_dir_path && table->space_id) { + if (!table->data_dir_path && table->space_id && table->space) { if (!dict_mutex_own) { dict_mutex_enter_for_mysql(); } - if (const char* p = table->space - ? table->space->chain.start->name : NULL) { - table->flags |= 1 << DICT_TF_POS_DATA_DIR - & ((1U << DICT_TF_BITS) - 1); - dict_save_data_dir_path(table, p); - } else if (char* path = dict_get_first_path(table->space_id)) { - table->flags |= 1 << DICT_TF_POS_DATA_DIR - & ((1U << DICT_TF_BITS) - 1); - dict_save_data_dir_path(table, path); - ut_free(path); - } + table->flags |= 1 << DICT_TF_POS_DATA_DIR + & ((1U << DICT_TF_BITS) - 1); + dict_save_data_dir_path(table, + table->space->chain.start->name); if (table->data_dir_path == NULL) { /* Since we did not set the table data_dir_path, unset the flag. This does not change SYS_DATAFILES - or SYS_TABLES or FSP_FLAGS on the header page of the - tablespace, but it makes dict_table_t consistent. */ + or SYS_TABLES or FSP_SPACE_FLAGS on the header page + of the tablespace, but it makes dict_table_t + consistent. */ table->flags &= ~DICT_TF_MASK_DATA_DIR & ((1U << DICT_TF_BITS) - 1); } diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 9fdd5f6b457..7cd939fcc54 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -1490,12 +1490,15 @@ inline fil_space_t *fil_system_t::keyrotate_next(fil_space_t *space, } } - if (it == end) - return NULL; + while (it != end) + { + space= &*it; + if (space->acquire()) + return space; + while (++it != end && (!UT_LIST_GET_LEN(it->chain) || it->is_stopping())); + } - space= &*it; - space->acquire(); - return space; + return NULL; } /** Return the next tablespace. @@ -1517,12 +1520,14 @@ static fil_space_t *fil_space_next(fil_space_t *space, bool recheck, space= UT_LIST_GET_FIRST(fil_system.space_list); /* We can trust that space is not NULL because at least the system tablespace is always present and loaded first. */ - space->acquire(); + if (!space->acquire()) + goto next; } else { /* Move on to the next fil_space_t */ space->release(); +next: space= UT_LIST_GET_NEXT(space_list, space); /* Skip abnormal tablespaces or those that are being created by @@ -1532,8 +1537,8 @@ static fil_space_t *fil_space_next(fil_space_t *space, bool recheck, space->is_stopping() || space->purpose != FIL_TYPE_TABLESPACE)) space= UT_LIST_GET_NEXT(space_list, space); - if (space) - space->acquire(); + if (space && !space->acquire()) + goto next; } mutex_exit(&fil_system.mutex); @@ -1552,6 +1557,11 @@ static bool fil_crypt_find_space_to_rotate( { /* we need iops to start rotating */ while (!state->should_shutdown() && !fil_crypt_alloc_iops(state)) { + if (state->space && state->space->is_stopping()) { + state->space->release(); + state->space = NULL; + } + os_event_reset(fil_crypt_threads_event); os_event_wait_time(fil_crypt_threads_event, 100000); } @@ -2246,31 +2256,27 @@ static void fil_crypt_rotation_list_fill() space = UT_LIST_GET_NEXT(space_list, space)) { if (space->purpose != FIL_TYPE_TABLESPACE || space->is_in_rotation_list - || space->is_stopping() - || UT_LIST_GET_LEN(space->chain) == 0) { + || UT_LIST_GET_LEN(space->chain) == 0 + || !space->acquire()) { continue; } /* Ensure that crypt_data has been initialized. */ if (!space->size) { - /* Protect the tablespace while we may - release fil_system.mutex. */ - ut_d(space->acquire()); ut_d(const fil_space_t* s=) fil_system.read_page0(space->id); ut_ad(!s || s == space); - ut_d(space->release()); if (!space->size) { /* Page 0 was not loaded. Skip this tablespace. */ - continue; + goto next; } } /* Skip ENCRYPTION!=DEFAULT tablespaces. */ if (space->crypt_data && !space->crypt_data->is_default_encryption()) { - continue; + goto next; } if (srv_encrypt_tables) { @@ -2278,19 +2284,21 @@ static void fil_crypt_rotation_list_fill() innodb_encrypt_tables!=OFF */ if (space->crypt_data && space->crypt_data->min_key_version) { - continue; + goto next; } } else { /* Skip unencrypted tablespaces if innodb_encrypt_tables=OFF */ if (!space->crypt_data || !space->crypt_data->min_key_version) { - continue; + goto next; } } fil_system.rotation_list.push_back(*space); space->is_in_rotation_list = true; +next: + space->release(); } } @@ -2410,6 +2418,7 @@ fil_space_crypt_close_tablespace( /* wakeup throttle (all) sleepers */ os_event_set(fil_crypt_throttle_sleep_event); + os_event_set(fil_crypt_threads_event); os_thread_sleep(20000); dict_mutex_enter_for_mysql(); diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 3874616e230..21743a0e076 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -588,8 +588,7 @@ fil_try_to_close_file_in_LRU( static void fil_flush_low(fil_space_t* space, bool metadata = false) { ut_ad(mutex_own(&fil_system.mutex)); - ut_ad(space); - ut_ad(!space->stop_new_ops); + ut_ad(!space->is_stopping()); if (srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC) { /* No need to flush. User has explicitly disabled @@ -859,14 +858,14 @@ fil_mutex_enter_and_prepare_for_io( this tablespace (multiple threads trying to extend this tablespace). - Also, fil_space_set_recv_size() may have been invoked - again during the file extension while fil_system.mutex - was not being held by us. + Also, fil_space_set_recv_size_and_flags() may have been + invoked again during the file extension while + fil_system.mutex was not being held by us. Only if space->recv_size matches what we read originally, reset the field. In this way, a subsequent I/O request will handle any pending - fil_space_set_recv_size(). */ + fil_space_set_recv_size_and_flags(). */ if (size == space->recv_size) { space->recv_size = 0; @@ -1321,22 +1320,18 @@ fil_space_get_space( return(space); } -/** Set the recovered size of a tablespace in pages. -@param id tablespace ID -@param size recovered size in pages */ -UNIV_INTERN -void -fil_space_set_recv_size(ulint id, ulint size) +void fil_space_set_recv_size_and_flags(ulint id, ulint size, uint32_t flags) { - mutex_enter(&fil_system.mutex); - ut_ad(size); - ut_ad(id < SRV_SPACE_ID_UPPER_BOUND); - - if (fil_space_t* space = fil_space_get_space(id)) { - space->recv_size = size; - } - - mutex_exit(&fil_system.mutex); + ut_ad(id < SRV_SPACE_ID_UPPER_BOUND); + mutex_enter(&fil_system.mutex); + if (fil_space_t *space= fil_space_get_space(id)) + { + if (size) + space->recv_size= size; + if (flags != FSP_FLAGS_FCRC32_MASK_MARKER) + space->flags= flags; + } + mutex_exit(&fil_system.mutex); } /*******************************************************************//** @@ -1724,10 +1719,8 @@ fil_space_t* fil_space_acquire_low(ulint id, bool silent) ib::warn() << "Trying to access missing" " tablespace " << id; } - } else if (space->is_stopping()) { + } else if (!space->acquire()) { space = NULL; - } else { - space->acquire(); } mutex_exit(&fil_system.mutex); @@ -1955,14 +1948,14 @@ static ulint fil_check_pending_ops(const fil_space_t* space, ulint count) { ut_ad(mutex_own(&fil_system.mutex)); - if (space == NULL) { + if (!space) { return 0; } - if (ulint n_pending_ops = space->n_pending_ops) { + if (auto n_pending_ops = space->referenced()) { - /* Give a warning every 10 second, starting after 1 second */ - if ((count % 500) == 50) { + /* Give a warning every 10 second, starting after 1 second */ + if ((count % 500) == 50) { ib::warn() << "Trying to delete" " tablespace '" << space->name << "' but there are " << n_pending_ops @@ -2033,14 +2026,13 @@ fil_check_pending_operations( fil_space_t* sp = fil_space_get_by_id(id); if (sp) { - sp->stop_new_ops = true; - if (sp->crypt_data) { - sp->acquire(); + if (sp->crypt_data && sp->acquire()) { mutex_exit(&fil_system.mutex); fil_space_crypt_close_tablespace(sp); mutex_enter(&fil_system.mutex); sp->release(); } + sp->set_stopping(true); } /* Check for pending operations. */ @@ -2521,7 +2513,7 @@ fil_rename_tablespace( multiple datafiles per tablespace. */ ut_a(UT_LIST_GET_LEN(space->chain) == 1); node = UT_LIST_GET_FIRST(space->chain); - space->n_pending_ops++; + ut_a(space->acquire()); mutex_exit(&fil_system.mutex); @@ -2543,8 +2535,7 @@ fil_rename_tablespace( /* log_sys.mutex is above fil_system.mutex in the latching order */ ut_ad(log_mutex_own()); mutex_enter(&fil_system.mutex); - ut_ad(space->n_pending_ops); - space->n_pending_ops--; + space->release(); ut_ad(space->name == old_space_name); ut_ad(node->name == old_file_name); bool success; @@ -3797,7 +3788,7 @@ fil_io( if (!space || (req_type.is_read() && !sync - && space->stop_new_ops + && space->is_stopping() && !space->is_being_truncated)) { mutex_exit(&fil_system.mutex); @@ -4223,7 +4214,7 @@ fil_space_validate_for_mtr_commit( mini-transaction, we should have !space->stop_new_ops. This is guaranteed by meta-data locks or transactional locks, or dict_sys.latch (X-lock in DROP, S-lock in purge). */ - ut_ad(!space->stop_new_ops + ut_ad(!space->is_stopping() || space->is_being_truncated /* fil_truncate_prepare() */ || space->referenced()); } @@ -4430,23 +4421,3 @@ fil_space_get_block_size(const fil_space_t* space, unsigned offset) return block_size; } - -/*******************************************************************//** -Returns the table space by a given id, NULL if not found. */ -fil_space_t* -fil_space_found_by_id( -/*==================*/ - ulint id) /*!< in: space id */ -{ - fil_space_t* space = NULL; - mutex_enter(&fil_system.mutex); - space = fil_space_get_by_id(id); - - /* Not found if space is being deleted */ - if (space && space->stop_new_ops) { - space = NULL; - } - - mutex_exit(&fil_system.mutex); - return space; -} diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index a2a6335a17a..6ac57ca395c 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -101,7 +101,6 @@ minimize file space fragmentation. @param[in] direction if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR -@param[in] rw_latch RW_SX_LATCH, RW_X_LATCH @param[in,out] mtr mini-transaction @param[in,out] init_mtr mtr or another mini-transaction in which the page should be initialized. @@ -114,7 +113,6 @@ fseg_alloc_free_page_low( buf_block_t* iblock, ulint hint, byte direction, - rw_lock_type_t rw_latch, #ifdef UNIV_DEBUG bool has_done_reservation, /*!< whether the space has already been reserved */ @@ -147,7 +145,8 @@ template<bool free> inline void xdes_set_free(const buf_block_t &block, xdes_t *descr, ulint offset, mtr_t *mtr) { - ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_SX_FIX)); + ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_SX_FIX | + MTR_MEMO_PAGE_X_FIX)); ut_ad(offset < FSP_EXTENT_SIZE); ut_ad(page_align(descr) == block.frame); compile_time_assert(XDES_BITS_PER_PAGE == 2); @@ -218,7 +217,8 @@ inline void xdes_set_state(const buf_block_t &block, xdes_t *descr, ut_ad(descr && mtr); ut_ad(state >= XDES_FREE); ut_ad(state <= XDES_FSEG); - ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_SX_FIX)); + ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_SX_FIX | + MTR_MEMO_PAGE_X_FIX)); ut_ad(page_align(descr) == block.frame); ut_ad(mach_read_from_4(descr + XDES_STATE) <= XDES_FSEG); mtr->write<1>(block, XDES_STATE + 3 + descr, state); @@ -245,7 +245,8 @@ xdes_get_state( Inits an extent descriptor to the free and clean state. */ inline void xdes_init(const buf_block_t &block, xdes_t *descr, mtr_t *mtr) { - ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_SX_FIX)); + ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_SX_FIX | + MTR_MEMO_PAGE_X_FIX)); mtr->memset(&block, uint16_t(descr - block.frame) + XDES_BITMAP, XDES_SIZE - XDES_BITMAP, 0xff); xdes_set_state(block, descr, XDES_FREE, mtr); @@ -320,7 +321,8 @@ xdes_get_descriptor_with_space_hdr( ulint size; ulint descr_page_no; ut_ad(mtr->memo_contains(*space)); - ut_ad(mtr->memo_contains_flagged(header, MTR_MEMO_PAGE_SX_FIX)); + ut_ad(mtr->memo_contains_flagged(header, MTR_MEMO_PAGE_SX_FIX + | MTR_MEMO_PAGE_X_FIX)); /* Read free limit and space size */ limit = mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT + header->frame); @@ -553,9 +555,7 @@ void fsp_header_init(fil_space_t* space, ulint size, mtr_t* mtr) mtr_x_lock_space(space, mtr); - const auto savepoint = mtr->get_savepoint(); buf_block_t* block = buf_page_create(space, 0, zip_size, mtr); - mtr->sx_latch_at_savepoint(savepoint, block); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); space->size_in_header = size; @@ -874,11 +874,9 @@ fsp_fill_free_list( pages should be ignored. */ if (i > 0) { - const auto savepoint = mtr->get_savepoint(); block= buf_page_create( space, static_cast<uint32_t>(i), zip_size, mtr); - mtr->sx_latch_at_savepoint(savepoint, block); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); fsp_init_file_page(space, block, mtr); @@ -888,13 +886,11 @@ fsp_fill_free_list( } if (space->purpose != FIL_TYPE_TEMPORARY) { - const auto savepoint = mtr->get_savepoint(); block = buf_page_create( space, static_cast<uint32_t>( i + FSP_IBUF_BITMAP_OFFSET), zip_size, mtr); - mtr->sx_latch_at_savepoint(savepoint, block); buf_block_dbg_add_level(block, SYNC_FSP_PAGE); fsp_init_file_page(space, block, mtr); @@ -1040,46 +1036,22 @@ fsp_alloc_from_free_frag(buf_block_t *header, buf_block_t *xdes, xdes_t *descr, /** Gets a buffer block for an allocated page. @param[in,out] space tablespace @param[in] offset page number of the allocated page -@param[in] rw_latch RW_SX_LATCH, RW_X_LATCH @param[in,out] mtr mini-transaction @return block, initialized */ static buf_block_t* -fsp_page_create( - fil_space_t* space, - page_no_t offset, - rw_lock_type_t rw_latch, - mtr_t* mtr) +fsp_page_create(fil_space_t *space, page_no_t offset, mtr_t *mtr) { - buf_block_t* block = buf_page_create( - space, static_cast<uint32_t>(offset), - space->zip_size(), mtr); - - /* The latch may already have been acquired, so we cannot invoke - mtr_t::x_latch_at_savepoint() or mtr_t::sx_latch_at_savepoint(). */ - mtr_memo_type_t memo; - - if (rw_latch == RW_X_LATCH) { - rw_lock_x_lock(&block->lock); - memo = MTR_MEMO_PAGE_X_FIX; - } else { - ut_ad(rw_latch == RW_SX_LATCH); - rw_lock_sx_lock(&block->lock); - memo = MTR_MEMO_PAGE_SX_FIX; - } - - mtr_memo_push(mtr, block, memo); - buf_block_buf_fix_inc(block, __FILE__, __LINE__); - fsp_init_file_page(space, block, mtr); - - return(block); + buf_block_t *block= buf_page_create(space, static_cast<uint32_t>(offset), + space->zip_size(), mtr); + fsp_init_file_page(space, block, mtr); + return block; } /** Allocates a single free page from a space. The page is marked as used. @param[in,out] space tablespace @param[in] hint hint of which page would be desirable -@param[in] rw_latch RW_SX_LATCH, RW_X_LATCH @param[in,out] mtr mini-transaction @param[in,out] init_mtr mini-transaction in which the page should be initialized (may be the same as mtr) @@ -1089,7 +1061,6 @@ buf_block_t* fsp_alloc_free_page( fil_space_t* space, ulint hint, - rw_lock_type_t rw_latch, mtr_t* mtr, mtr_t* init_mtr) { @@ -1184,7 +1155,7 @@ fsp_alloc_free_page( } fsp_alloc_from_free_frag(block, xdes, descr, free, mtr); - return fsp_page_create(space, page_no, rw_latch, init_mtr); + return fsp_page_create(space, page_no, init_mtr); } /** Frees a single page of a space. @@ -1376,13 +1347,13 @@ bool fsp_alloc_seg_inode_page(fil_space_t *space, buf_block_t *header, mtr_t *mtr) { ut_ad(header->page.id().space() == space->id); - buf_block_t *block= fsp_alloc_free_page(space, 0, RW_SX_LATCH, mtr, mtr); + buf_block_t *block= fsp_alloc_free_page(space, 0, mtr, mtr); if (!block) return false; buf_block_dbg_add_level(block, SYNC_FSP_PAGE); - ut_ad(rw_lock_get_sx_lock_count(&block->lock) == 1); + ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1); mtr->write<2>(*block, block->frame + FIL_PAGE_TYPE, FIL_PAGE_INODE); @@ -1650,48 +1621,40 @@ static ulint fseg_get_n_frag_pages(const fseg_inode_t *inode) return(count); } -/**********************************************************************//** -Creates a new segment. -@return the block where the segment header is placed, x-latched, NULL -if could not create segment because of lack of space */ +/** Create a new segment. +@param space tablespace +@param byte_offset byte offset of the created segment header +@param mtr mini-transaction +@param has_done_reservation whether fsp_reserve_free_extents() was invoked +@param block block where segment header is placed, + or NULL to allocate an additional page for that +@return the block where the segment header is placed, x-latched +@retval NULL if could not create segment because of lack of space */ buf_block_t* -fseg_create( - fil_space_t* space, /*!< in,out: tablespace */ - ulint page, /*!< in: page where the segment header is placed: if - this is != 0, the page must belong to another segment, - if this is 0, a new page will be allocated and it - will belong to the created segment */ - ulint byte_offset, /*!< in: byte offset of the created segment header - on the page */ - mtr_t* mtr, - bool has_done_reservation) /*!< in: whether the caller - has already done the reservation for the pages with - fsp_reserve_free_extents (at least 2 extents: one for - the inode and the other for the segment) then there is - no need to do the check for this individual - operation */ +fseg_create(fil_space_t *space, ulint byte_offset, mtr_t *mtr, + bool has_done_reservation, buf_block_t *block) { fseg_inode_t* inode; ib_id_t seg_id; - buf_block_t* block = 0; /* remove warning */ ulint n_reserved; DBUG_ENTER("fseg_create"); ut_ad(mtr); + ut_ad(byte_offset >= FIL_PAGE_DATA); ut_ad(byte_offset + FSEG_HEADER_SIZE <= srv_page_size - FIL_PAGE_DATA_END); mtr_x_lock_space(space, mtr); ut_d(space->modify_check(*mtr)); - if (page != 0) { - block = buf_page_get(page_id_t(space->id, page), - space->zip_size(), - RW_SX_LATCH, mtr); + if (block) { + ut_ad(block->page.id().space() == space->id); + if (!space->full_crc32()) { - fil_block_check_type(*block, space->id == TRX_SYS_SPACE - && page == TRX_SYS_PAGE_NO + fil_block_check_type(*block, block->page.id() + == page_id_t(TRX_SYS_SPACE, + TRX_SYS_PAGE_NO) ? FIL_PAGE_TYPE_TRX_SYS : FIL_PAGE_TYPE_SYS, mtr); @@ -1734,10 +1697,9 @@ fseg_create( mtr->memset(iblock, uint16_t(inode - iblock->frame) + FSEG_FRAG_ARR, FSEG_FRAG_SLOT_SIZE * FSEG_FRAG_ARR_N_SLOTS, 0xff); - if (page == 0) { + if (!block) { block = fseg_alloc_free_page_low(space, inode, iblock, 0, FSP_UP, - RW_SX_LATCH, #ifdef UNIV_DEBUG has_done_reservation, #endif /* UNIV_DEBUG */ @@ -1752,7 +1714,7 @@ fseg_create( goto funct_exit; } - ut_ad(rw_lock_get_sx_lock_count(&block->lock) == 1); + ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1); ut_ad(!fil_page_get_type(block->frame)); mtr->write<1>(*block, FIL_PAGE_TYPE + 1 + block->frame, FIL_PAGE_TYPE_SYS); @@ -1957,7 +1919,6 @@ minimize file space fragmentation. @param[in] direction if the new page is needed because of an index page split, and records are inserted there in order, into which direction they go alphabetically: FSP_DOWN, FSP_UP, FSP_NO_DIR -@param[in] rw_latch RW_SX_LATCH, RW_X_LATCH @param[in,out] mtr mini-transaction @param[in,out] init_mtr mtr or another mini-transaction in which the page should be initialized. @@ -1970,7 +1931,6 @@ fseg_alloc_free_page_low( buf_block_t* iblock, ulint hint, byte direction, - rw_lock_type_t rw_latch, #ifdef UNIV_DEBUG bool has_done_reservation, /*!< whether the space has already been reserved */ @@ -2111,11 +2071,11 @@ take_hinted_page: /* 6. We allocate an individual page from the space ===================================================*/ buf_block_t* block = fsp_alloc_free_page( - space, hint, rw_latch, mtr, init_mtr); + space, hint, mtr, init_mtr); - ut_ad(!has_done_reservation || block != NULL); + ut_ad(!has_done_reservation || block); - if (block != NULL) { + if (block) { /* Put the page in the fragment page array of the segment */ n = fseg_find_free_frag_page_slot(seg_inode); @@ -2192,7 +2152,7 @@ got_hinted_page: xdes, mtr); } - return fsp_page_create(space, ret_page, rw_latch, init_mtr); + return fsp_page_create(space, ret_page, init_mtr); } /**********************************************************************//** @@ -2243,7 +2203,6 @@ fseg_alloc_free_page_general( block = fseg_alloc_free_page_low(space, inode, iblock, hint, direction, - RW_X_LATCH, #ifdef UNIV_DEBUG has_done_reservation, #endif /* UNIV_DEBUG */ diff --git a/storage/innobase/fts/fts0config.cc b/storage/innobase/fts/fts0config.cc index 8ae10c2465d..9e2b40911ae 100644 --- a/storage/innobase/fts/fts0config.cc +++ b/storage/innobase/fts/fts0config.cc @@ -148,9 +148,7 @@ fts_config_create_index_param_name( ::strcpy(name, param); name[len] = '_'; - fts_write_object_id(index->id, name + len + 1, - DICT_TF2_FLAG_IS_SET(index->table, - DICT_TF2_FTS_AUX_HEX_NAME)); + fts_write_object_id(index->id, name + len + 1); return(name); } diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index cc69863f54b..b95b77d5d0d 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -1551,18 +1551,19 @@ fts_rename_aux_tables( return(DB_SUCCESS); } -/****************************************************************//** -Drops the common ancillary tables needed for supporting an FTS index +/** Drops the common ancillary tables needed for supporting an FTS index on the given table. row_mysql_lock_data_dictionary must have been called before this. +@param[in] trx transaction to drop fts common table +@param[in] fts_table table with an FTS index +@param[in] drop_orphan True if the function is used to drop + orphaned table @return DB_SUCCESS or error code */ -static MY_ATTRIBUTE((nonnull, warn_unused_result)) -dberr_t +static dberr_t fts_drop_common_tables( -/*===================*/ - trx_t* trx, /*!< in: transaction */ - fts_table_t* fts_table) /*!< in: table with an FTS - index */ + trx_t* trx, + fts_table_t* fts_table, + bool drop_orphan=false) { ulint i; dberr_t error = DB_SUCCESS; @@ -1580,6 +1581,16 @@ fts_drop_common_tables( if (err != DB_SUCCESS && err != DB_FAIL) { error = err; } + + if (drop_orphan && err == DB_FAIL) { + char* path = fil_make_filepath( + NULL, table_name, IBD, false); + if (path != NULL) { + os_file_delete_if_exists( + innodb_data_file_key, path, NULL); + ut_free(path); + } + } } return(error); @@ -2092,38 +2103,6 @@ fts_create_index_tables(trx_t* trx, const dict_index_t* index, table_id_t id) return(error); } -#if 0 -/******************************************************************//** -Return string representation of state. */ -static -const char* -fts_get_state_str( -/*==============*/ - /* out: string representation of state */ - fts_row_state state) /*!< in: state */ -{ - switch (state) { - case FTS_INSERT: - return("INSERT"); - - case FTS_MODIFY: - return("MODIFY"); - - case FTS_DELETE: - return("DELETE"); - - case FTS_NOTHING: - return("NOTHING"); - - case FTS_INVALID: - return("INVALID"); - - default: - return("UNKNOWN"); - } -} -#endif - /******************************************************************//** Calculate the new state of a row given the existing state and a new event. @return new state of row */ @@ -5673,1309 +5652,245 @@ fts_savepoint_rollback( } } -/** Check if a table is an FTS auxiliary table name. -@param[out] table FTS table info -@param[in] name Table name -@param[in] len Length of table name -@return true if the name matches an auxiliary table name pattern */ -static -bool -fts_is_aux_table_name( - fts_aux_table_t* table, - const char* name, - ulint len) -{ - const char* ptr; - char* end; - char my_name[MAX_FULL_NAME_LEN + 1]; - - ut_ad(len <= MAX_FULL_NAME_LEN); - memcpy(my_name, name, len); - my_name[len] = 0; - end = my_name + len; - - ptr = static_cast<const char*>(memchr(my_name, '/', len)); - - if (ptr != NULL) { - /* We will start the match after the '/' */ - ++ptr; - len = ulint(end - ptr); - } - - /* All auxiliary tables are prefixed with "FTS_" and the name - length will be at the very least greater than 20 bytes. */ - if (ptr != NULL && len > 20 && strncmp(ptr, "FTS_", 4) == 0) { - ulint i; - - /* Skip the prefix. */ - ptr += 4; - len -= 4; - - /* Try and read the table id. */ - if (!fts_read_object_id(&table->parent_id, ptr)) { - return(false); - } - - /* Skip the table id. */ - ptr = static_cast<const char*>(memchr(ptr, '_', len)); - - if (ptr == NULL) { - return(false); - } - - /* Skip the underscore. */ - ++ptr; - ut_a(end > ptr); - len = ulint(end - ptr); - - /* First search the common table suffix array. */ - for (i = 0; fts_common_tables[i] != NULL; ++i) { - - if (strncmp(ptr, fts_common_tables[i], len) == 0) { - return(true); - } - } - - /* Could be obsolete common tables. */ - if (strncmp(ptr, "ADDED", len) == 0 - || strncmp(ptr, "STOPWORDS", len) == 0) { - return(true); - } +bool fts_check_aux_table(const char *name, + table_id_t *table_id, + index_id_t *index_id) +{ + ulint len= strlen(name); + const char* ptr; + const char* end= name + len; - /* Try and read the index id. */ - if (!fts_read_object_id(&table->index_id, ptr)) { - return(false); - } + ut_ad(len <= MAX_FULL_NAME_LEN); + ptr= static_cast<const char*>(memchr(name, '/', len)); - /* Skip the table id. */ - ptr = static_cast<const char*>(memchr(ptr, '_', len)); + if (ptr != NULL) + { + /* We will start the match after the '/' */ + ++ptr; + len = end - ptr; + } + + /* All auxiliary tables are prefixed with "FTS_" and the name + length will be at the very least greater than 20 bytes. */ + if (ptr && len > 20 && !memcmp(ptr, "FTS_", 4)) + { + /* Skip the prefix. */ + ptr+= 4; + len-= 4; + + const char *table_id_ptr= ptr; + /* Skip the table id. */ + ptr= static_cast<const char*>(memchr(ptr, '_', len)); + + if (!ptr) + return false; + + /* Skip the underscore. */ + ++ptr; + ut_ad(end > ptr); + len= end - ptr; + + sscanf(table_id_ptr, UINT64PFx, table_id); + /* First search the common table suffix array. */ + for (ulint i = 0; fts_common_tables[i]; ++i) + { + if (!strncmp(ptr, fts_common_tables[i], len)) + return true; + } + + /* Could be obsolete common tables. */ + if ((len == 5 && !memcmp(ptr, "ADDED", len)) || + (len == 9 && !memcmp(ptr, "STOPWORDS", len))) + return true; + + const char* index_id_ptr= ptr; + /* Skip the index id. */ + ptr= static_cast<const char*>(memchr(ptr, '_', len)); + if (!ptr) + return false; + + sscanf(index_id_ptr, UINT64PFx, index_id); + + /* Skip the underscore. */ + ++ptr; + ut_a(end > ptr); + len= end - ptr; + + if (len > 7) + return false; + + /* Search the FT index specific array. */ + for (ulint i = 0; i < FTS_NUM_AUX_INDEX; ++i) + { + if (!memcmp(ptr, "INDEX_", len - 1)) + return true; + } + + /* Other FT index specific table(s). */ + if (len == 6 && !memcmp(ptr, "DOC_ID", len)) + return true; + } + + return false; +} + +typedef std::pair<table_id_t,index_id_t> fts_aux_id; +typedef std::set<fts_aux_id> fts_space_set_t; + +/** Iterate over all the spaces in the space list and fetch the +fts parent table id and index id. +@param[in,out] fts_space_set store the list of tablespace id and + index id */ +static void fil_get_fts_spaces(fts_space_set_t& fts_space_set) +{ + mutex_enter(&fil_system.mutex); + + for (fil_space_t *space= UT_LIST_GET_FIRST(fil_system.space_list); + space; + space= UT_LIST_GET_NEXT(space_list, space)) + { + index_id_t index_id= 0; + table_id_t table_id= 0; + + if (space->purpose == FIL_TYPE_TABLESPACE + && fts_check_aux_table(space->name, &table_id, &index_id)) + fts_space_set.insert(std::make_pair(table_id, index_id)); + } + + mutex_exit(&fil_system.mutex); +} + +/** Check whether the parent table id and index id of fts auxilary +tables with SYS_INDEXES. If it exists then we can safely ignore the +fts table from orphaned tables. +@param[in,out] fts_space_set fts space set contains set of auxiliary + table ids */ +static void fts_check_orphaned_tables(fts_space_set_t& fts_space_set) +{ + btr_pcur_t pcur; + mtr_t mtr; + trx_t* trx = trx_create(); + trx->op_info = "checking fts orphaned tables"; + + row_mysql_lock_data_dictionary(trx); + + mtr.start(); + btr_pcur_open_at_index_side( + true, dict_table_get_first_index(dict_sys.sys_indexes), + BTR_SEARCH_LEAF, &pcur, true, 0, &mtr); + + do + { + const rec_t *rec; + const byte *tbl_field; + const byte *index_field; + ulint len; + + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + if (!btr_pcur_is_on_user_rec(&pcur)) + break; + + rec= btr_pcur_get_rec(&pcur); + if (rec_get_deleted_flag(rec, 0)) + continue; + + tbl_field= rec_get_nth_field_old(rec, 0, &len); + if (len != 8) + continue; + + index_field= rec_get_nth_field_old(rec, 1, &len); + if (len != 8) + continue; + + table_id_t table_id = mach_read_from_8(tbl_field); + index_id_t index_id = mach_read_from_8(index_field); + + fts_space_set_t::iterator it = fts_space_set.find( + fts_aux_id(table_id, index_id)); - if (ptr == NULL) { - return(false); - } - - /* Skip the underscore. */ - ++ptr; - ut_a(end > ptr); - len = ulint(end - ptr); + if (it != fts_space_set.end()) + fts_space_set.erase(*it); + else + { + it= fts_space_set.find(fts_aux_id(table_id, 0)); + if (it != fts_space_set.end()) + fts_space_set.erase(*it); + } + } while(!fts_space_set.empty()); + + btr_pcur_close(&pcur); + mtr.commit(); + row_mysql_unlock_data_dictionary(trx); + trx->free(); +} - /* Search the FT index specific array. */ - for (i = 0; i < FTS_NUM_AUX_INDEX; ++i) { - - if (strncmp(ptr, fts_get_suffix(i), len) == 0) { - return(true); - } - } - - /* Other FT index specific table(s). */ - if (strncmp(ptr, "DOC_ID", len) == 0) { - return(true); - } - } - - return(false); -} - -/**********************************************************************//** -Callback function to read a single table ID column. -@return Always return TRUE */ -static -ibool -fts_read_tables( -/*============*/ - void* row, /*!< in: sel_node_t* */ - void* user_arg) /*!< in: pointer to ib_vector_t */ +/** Drop all fts auxilary table for the respective fts_id +@param[in] fts_id fts auxilary table ids */ +static void fts_drop_all_aux_tables(trx_t *trx, fts_table_t *fts_table) { - int i; - fts_aux_table_t*table; - mem_heap_t* heap; - ibool done = FALSE; - ib_vector_t* tables = static_cast<ib_vector_t*>(user_arg); - sel_node_t* sel_node = static_cast<sel_node_t*>(row); - que_node_t* exp = sel_node->select_list; + char fts_table_name[MAX_FULL_NAME_LEN]; + for (ulint i= 0;i < FTS_NUM_AUX_INDEX; i++) + { + fts_table->suffix= fts_get_suffix(i); + fts_get_table_name(fts_table, fts_table_name, true); + + /* Drop all fts aux and common table */ + dberr_t err= fts_drop_table(trx, fts_table_name); + + if (err == DB_FAIL) + { + char *path= fil_make_filepath(NULL, fts_table_name, IBD, false); + + if (path != NULL) + { + os_file_delete_if_exists(innodb_data_file_key, path , NULL); + ut_free(path); + } + } + } +} + +/** Drop all orphaned FTS auxiliary tables, those that don't have +a parent table or FTS index defined on them. */ +void fts_drop_orphaned_tables() +{ + fts_space_set_t fts_space_set; + fil_get_fts_spaces(fts_space_set); - /* Must be a heap allocated vector. */ - ut_a(tables->allocator->arg != NULL); - - /* We will use this heap for allocating strings. */ - heap = static_cast<mem_heap_t*>(tables->allocator->arg); - table = static_cast<fts_aux_table_t*>(ib_vector_push(tables, NULL)); - - memset(table, 0x0, sizeof(*table)); - - /* Iterate over the columns and read the values. */ - for (i = 0; exp && !done; exp = que_node_get_next(exp), ++i) { - - dfield_t* dfield = que_node_get_val(exp); - void* data = dfield_get_data(dfield); - ulint len = dfield_get_len(dfield); - - ut_a(len != UNIV_SQL_NULL); - - /* Note: The column numbers below must match the SELECT */ - switch (i) { - case 0: /* NAME */ - - if (!fts_is_aux_table_name( - table, static_cast<const char*>(data), len)) { - ib_vector_pop(tables); - done = TRUE; - break; - } - - table->name = static_cast<char*>( - mem_heap_alloc(heap, len + 1)); - memcpy(table->name, data, len); - table->name[len] = 0; - break; - - case 1: /* ID */ - ut_a(len == 8); - table->id = mach_read_from_8( - static_cast<const byte*>(data)); - break; - - default: - ut_error; - } - } - - return(TRUE); -} - -/******************************************************************//** -Callback that sets a hex formatted FTS table's flags2 in -SYS_TABLES. The flags is stored in MIX_LEN column. -@return FALSE if all OK */ -static -ibool -fts_set_hex_format( -/*===============*/ - void* row, /*!< in: sel_node_t* */ - void* user_arg) /*!< in: bool set/unset flag */ -{ - sel_node_t* node = static_cast<sel_node_t*>(row); - dfield_t* dfield = que_node_get_val(node->select_list); - - ut_ad(dtype_get_mtype(dfield_get_type(dfield)) == DATA_INT); - ut_ad(dfield_get_len(dfield) == sizeof(ib_uint32_t)); - /* There should be at most one matching record. So the value - must be the default value. */ - ut_ad(mach_read_from_4(static_cast<byte*>(user_arg)) - == ULINT32_UNDEFINED); - - ulint flags2 = mach_read_from_4( - static_cast<byte*>(dfield_get_data(dfield))); - - flags2 |= DICT_TF2_FTS_AUX_HEX_NAME; - - mach_write_to_4(static_cast<byte*>(user_arg), flags2); - - return(FALSE); -} - -/*****************************************************************//** -Update the DICT_TF2_FTS_AUX_HEX_NAME flag in SYS_TABLES. -@return DB_SUCCESS or error code. */ -static -dberr_t -fts_update_hex_format_flag( -/*=======================*/ - trx_t* trx, /*!< in/out: transaction that - covers the update */ - table_id_t table_id, /*!< in: Table for which we want - to set the root table->flags2 */ - bool dict_locked) /*!< in: set to true if the - caller already owns the - dict_sys_t::mutex. */ -{ - pars_info_t* info; - ib_uint32_t flags2; - - static const char sql[] = - "PROCEDURE UPDATE_HEX_FORMAT_FLAG() IS\n" - "DECLARE FUNCTION my_func;\n" - "DECLARE CURSOR c IS\n" - " SELECT MIX_LEN" - " FROM SYS_TABLES" - " WHERE ID = :table_id FOR UPDATE;" - "\n" - "BEGIN\n" - "OPEN c;\n" - "WHILE 1 = 1 LOOP\n" - " FETCH c INTO my_func();\n" - " IF c % NOTFOUND THEN\n" - " EXIT;\n" - " END IF;\n" - "END LOOP;\n" - "UPDATE SYS_TABLES" - " SET MIX_LEN = :flags2" - " WHERE ID = :table_id;\n" - "CLOSE c;\n" - "END;\n"; - - flags2 = ULINT32_UNDEFINED; - - info = pars_info_create(); - - pars_info_add_ull_literal(info, "table_id", table_id); - pars_info_bind_int4_literal(info, "flags2", &flags2); - - pars_info_bind_function( - info, "my_func", fts_set_hex_format, &flags2); - - if (trx_get_dict_operation(trx) == TRX_DICT_OP_NONE) { - trx_set_dict_operation(trx, TRX_DICT_OP_INDEX); - } - - dberr_t err = que_eval_sql(info, sql, !dict_locked, trx); - - ut_a(flags2 != ULINT32_UNDEFINED); - - return(err); -} - -/*********************************************************************//** -Rename an aux table to HEX format. It's called when "%016llu" is used -to format an object id in table name, which only happens in Windows. */ -static MY_ATTRIBUTE((nonnull, warn_unused_result)) -dberr_t -fts_rename_one_aux_table_to_hex_format( -/*===================================*/ - trx_t* trx, /*!< in: transaction */ - const fts_aux_table_t* aux_table, /*!< in: table info */ - const dict_table_t* parent_table) /*!< in: parent table name */ -{ - const char* ptr; - fts_table_t fts_table; - char new_name[MAX_FULL_NAME_LEN]; - dberr_t error; - - ptr = strchr(aux_table->name, '/'); - ut_a(ptr != NULL); - ++ptr; - /* Skip "FTS_", table id and underscore */ - for (ulint i = 0; i < 2; ++i) { - ptr = strchr(ptr, '_'); - ut_a(ptr != NULL); - ++ptr; - } - - fts_table.suffix = NULL; - if (aux_table->index_id == 0) { - fts_table.type = FTS_COMMON_TABLE; - - for (ulint i = 0; fts_common_tables[i] != NULL; ++i) { - if (strcmp(ptr, fts_common_tables[i]) == 0) { - fts_table.suffix = fts_common_tables[i]; - break; - } - } - } else { - fts_table.type = FTS_INDEX_TABLE; - - /* Skip index id and underscore */ - ptr = strchr(ptr, '_'); - ut_a(ptr != NULL); - ++ptr; - - for (ulint i = 0; fts_index_selector[i].value; ++i) { - if (strcmp(ptr, fts_get_suffix(i)) == 0) { - fts_table.suffix = fts_get_suffix(i); - break; - } - } - } - - ut_a(fts_table.suffix != NULL); - - fts_table.table_id = aux_table->parent_id; - fts_table.index_id = aux_table->index_id; - fts_table.table = parent_table; - - fts_get_table_name(&fts_table, new_name); - ut_ad(strcmp(new_name, aux_table->name) != 0); - - if (trx_get_dict_operation(trx) == TRX_DICT_OP_NONE) { - trx_set_dict_operation(trx, TRX_DICT_OP_INDEX); - } - - error = row_rename_table_for_mysql(aux_table->name, new_name, trx, - false, false); - - if (error != DB_SUCCESS) { - ib::warn() << "Failed to rename aux table '" - << aux_table->name << "' to new format '" - << new_name << "'."; - } else { - ib::info() << "Renamed aux table '" << aux_table->name - << "' to '" << new_name << "'."; - } - - return(error); -} - -/**********************************************************************//** -Rename all aux tables of a parent table to HEX format. Also set aux tables' -flags2 and parent table's flags2 with DICT_TF2_FTS_AUX_HEX_NAME. -It's called when "%016llu" is used to format an object id in table name, -which only happens in Windows. -Note the ids in tables are correct but the names are old ambiguous ones. - -This function should make sure that either all the parent table and aux tables -are set DICT_TF2_FTS_AUX_HEX_NAME with flags2 or none of them are set */ -static MY_ATTRIBUTE((nonnull, warn_unused_result)) -dberr_t -fts_rename_aux_tables_to_hex_format_low( -/*====================================*/ - trx_t* trx, /*!< in: transaction */ - dict_table_t* parent_table, /*!< in: parent table */ - ib_vector_t* tables) /*!< in: aux tables to rename. */ -{ - dberr_t error; - ulint count; - - ut_ad(!DICT_TF2_FLAG_IS_SET(parent_table, DICT_TF2_FTS_AUX_HEX_NAME)); - ut_ad(!ib_vector_is_empty(tables)); - - error = fts_update_hex_format_flag(trx, parent_table->id, true); - - if (error != DB_SUCCESS) { - ib::warn() << "Setting parent table " << parent_table->name - << " to hex format failed."; - fts_sql_rollback(trx); - return(error); - } - - DICT_TF2_FLAG_SET(parent_table, DICT_TF2_FTS_AUX_HEX_NAME); - - for (count = 0; count < ib_vector_size(tables); ++count) { - dict_table_t* table; - fts_aux_table_t* aux_table; - - aux_table = static_cast<fts_aux_table_t*>( - ib_vector_get(tables, count)); - - table = dict_table_open_on_id(aux_table->id, TRUE, - DICT_TABLE_OP_NORMAL); - - ut_ad(table != NULL); - ut_ad(!DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_AUX_HEX_NAME)); - - /* Set HEX_NAME flag here to make sure we can get correct - new table name in following function */ - DICT_TF2_FLAG_SET(table, DICT_TF2_FTS_AUX_HEX_NAME); - error = fts_rename_one_aux_table_to_hex_format(trx, - aux_table, parent_table); - /* We will rollback the trx if the error != DB_SUCCESS, - so setting the flag here is the same with setting it in - row_rename_table_for_mysql */ - DBUG_EXECUTE_IF("rename_aux_table_fail", error = DB_ERROR;); - - if (error != DB_SUCCESS) { - dict_table_close(table, TRUE, FALSE); - - ib::warn() << "Failed to rename one aux table " - << aux_table->name << ". Will revert" - " all successful rename operations."; - - fts_sql_rollback(trx); - break; - } - - error = fts_update_hex_format_flag(trx, aux_table->id, true); - dict_table_close(table, TRUE, FALSE); - - if (error != DB_SUCCESS) { - ib::warn() << "Setting aux table " << aux_table->name - << " to hex format failed."; - - fts_sql_rollback(trx); - break; - } - } - - if (error != DB_SUCCESS) { - ut_ad(count != ib_vector_size(tables)); - - /* If rename fails, thr trx would be rolled back, we can't - use it any more, we'll start a new background trx to do - the reverting. */ - - ut_ad(!trx_is_started(trx)); - - bool not_rename = false; - - /* Try to revert those succesful rename operations - in order to revert the ibd file rename. */ - for (ulint i = 0; i <= count; ++i) { - dict_table_t* table; - fts_aux_table_t* aux_table; - trx_t* trx_bg; - dberr_t err; - - aux_table = static_cast<fts_aux_table_t*>( - ib_vector_get(tables, i)); - - table = dict_table_open_on_id(aux_table->id, TRUE, - DICT_TABLE_OP_NORMAL); - ut_ad(table != NULL); - - if (not_rename) { - DICT_TF2_FLAG_UNSET(table, - DICT_TF2_FTS_AUX_HEX_NAME); - } - - if (!DICT_TF2_FLAG_IS_SET(table, - DICT_TF2_FTS_AUX_HEX_NAME)) { - dict_table_close(table, TRUE, FALSE); - continue; - } - - trx_bg = trx_create(); - trx_bg->op_info = "Revert half done rename"; - trx_bg->dict_operation_lock_mode = RW_X_LATCH; - trx_start_for_ddl(trx_bg, TRX_DICT_OP_TABLE); - - DICT_TF2_FLAG_UNSET(table, DICT_TF2_FTS_AUX_HEX_NAME); - err = row_rename_table_for_mysql(table->name.m_name, - aux_table->name, - trx_bg, false, false); - - trx_bg->dict_operation_lock_mode = 0; - dict_table_close(table, TRUE, FALSE); - - if (err != DB_SUCCESS) { - ib::warn() << "Failed to revert table " - << table->name << ". Please revert" - " manually."; - fts_sql_rollback(trx_bg); - /* Continue to clear aux tables' flags2 */ - not_rename = true; - } else { - fts_sql_commit(trx_bg); - } - trx_bg->free(); - } - - DICT_TF2_FLAG_UNSET(parent_table, DICT_TF2_FTS_AUX_HEX_NAME); - } - - return(error); -} - -/**********************************************************************//** -Convert an id, which is actually a decimal number but was regard as a HEX -from a string, to its real value. */ -static -ib_id_t -fts_fake_hex_to_dec( -/*================*/ - ib_id_t id) /*!< in: number to convert */ -{ - ib_id_t dec_id = 0; - char tmp_id[FTS_AUX_MIN_TABLE_ID_LENGTH]; - -#ifdef UNIV_DEBUG - int ret = -#endif /* UNIV_DEBUG */ - sprintf(tmp_id, UINT64PFx, id); - ut_ad(ret == 16); -#ifdef UNIV_DEBUG - ret = -#endif /* UNIV_DEBUG */ - sscanf(tmp_id, "%016" UINT64scan, &dec_id); - ut_ad(ret == 1); - - return dec_id; -} - -/*********************************************************************//** -Compare two fts_aux_table_t parent_ids. -@return < 0 if n1 < n2, 0 if n1 == n2, > 0 if n1 > n2 */ -UNIV_INLINE -int -fts_check_aux_table_parent_id_cmp( -/*==============================*/ - const void* p1, /*!< in: id1 */ - const void* p2) /*!< in: id2 */ -{ - const fts_aux_table_t* fa1 = static_cast<const fts_aux_table_t*>(p1); - const fts_aux_table_t* fa2 = static_cast<const fts_aux_table_t*>(p2); - - return static_cast<int>(fa1->parent_id - fa2->parent_id); -} - -/** Mark all the fts index associated with the parent table as corrupted. -@param[in] trx transaction -@param[in, out] parent_table fts index associated with this parent table - will be marked as corrupted. */ -static -void -fts_parent_all_index_set_corrupt( - trx_t* trx, - dict_table_t* parent_table) -{ - fts_t* fts = parent_table->fts; - - if (trx_get_dict_operation(trx) == TRX_DICT_OP_NONE) { - trx_set_dict_operation(trx, TRX_DICT_OP_INDEX); - } - - for (ulint j = 0; j < ib_vector_size(fts->indexes); j++) { - dict_index_t* index = static_cast<dict_index_t*>( - ib_vector_getp_const(fts->indexes, j)); - dict_set_corrupted(index, - trx, "DROP ORPHANED TABLE"); - } -} - -/** Mark the fts index which index id matches the id as corrupted. -@param[in] trx transaction -@param[in] id index id to search -@param[in, out] parent_table parent table to check with all - the index. */ -static -void -fts_set_index_corrupt( - trx_t* trx, - index_id_t id, - dict_table_t* table) -{ - fts_t* fts = table->fts; - - if (trx_get_dict_operation(trx) == TRX_DICT_OP_NONE) { - trx_set_dict_operation(trx, TRX_DICT_OP_INDEX); - } - - for (ulint j = 0; j < ib_vector_size(fts->indexes); j++) { - dict_index_t* index = static_cast<dict_index_t*>( - ib_vector_getp_const(fts->indexes, j)); - if (index->id == id) { - dict_set_corrupted(index, trx, - "DROP ORPHANED TABLE"); - break; - } - } -} - -/** Check the index for the aux table is corrupted. -@param[in] aux_table auxiliary table -@retval nonzero if index is corrupted, zero for valid index */ -static -ulint -fts_check_corrupt_index( - fts_aux_table_t* aux_table) -{ - dict_table_t* table; - dict_index_t* index; - table = dict_table_open_on_id( - aux_table->parent_id, TRUE, DICT_TABLE_OP_NORMAL); - - if (table == NULL) { - return(0); - } - - for (index = UT_LIST_GET_FIRST(table->indexes); - index; - index = UT_LIST_GET_NEXT(indexes, index)) { - if (index->id == aux_table->index_id) { - ut_ad(index->type & DICT_FTS); - dict_table_close(table, true, false); - return index->is_corrupted(); - } - } - - dict_table_close(table, true, false); - return(0); -} - -/* Get parent table name if it's a fts aux table -@param[in] aux_table_name aux table name -@param[in] aux_table_len aux table length -@return parent table name, or NULL */ -char* -fts_get_parent_table_name( - const char* aux_table_name, - ulint aux_table_len) -{ - fts_aux_table_t aux_table; - char* parent_table_name = NULL; - - if (fts_is_aux_table_name(&aux_table, aux_table_name, aux_table_len)) { - dict_table_t* parent_table; - - parent_table = dict_table_open_on_id( - aux_table.parent_id, TRUE, DICT_TABLE_OP_NORMAL); - - if (parent_table != NULL) { - parent_table_name = mem_strdupl( - parent_table->name.m_name, - strlen(parent_table->name.m_name)); - - dict_table_close(parent_table, TRUE, FALSE); - } - } - - return(parent_table_name); -} - -/** Check the validity of the parent table. -@param[in] aux_table auxiliary table -@return true if it is a valid table or false if it is not */ -static -bool -fts_valid_parent_table( - const fts_aux_table_t* aux_table) -{ - dict_table_t* parent_table; - bool valid = false; - - parent_table = dict_table_open_on_id( - aux_table->parent_id, TRUE, DICT_TABLE_OP_NORMAL); - - if (parent_table != NULL && parent_table->fts != NULL) { - if (aux_table->index_id == 0) { - valid = true; - } else { - index_id_t id = aux_table->index_id; - dict_index_t* index; - - /* Search for the FT index in the table's list. */ - for (index = UT_LIST_GET_FIRST(parent_table->indexes); - index; - index = UT_LIST_GET_NEXT(indexes, index)) { - if (index->id == id) { - valid = true; - break; - } - - } - } - } - - if (parent_table) { - dict_table_close(parent_table, TRUE, FALSE); - } - - return(valid); -} - -/** Try to rename all aux tables of the specified parent table. -@param[in] aux_tables aux_tables to be renamed -@param[in] parent_table parent table of all aux - tables stored in tables. */ -static -void -fts_rename_aux_tables_to_hex_format( - ib_vector_t* aux_tables, - dict_table_t* parent_table) -{ - dberr_t err; - trx_t* trx_rename = trx_create(); - trx_rename->op_info = "Rename aux tables to hex format"; - trx_rename->dict_operation_lock_mode = RW_X_LATCH; - trx_start_for_ddl(trx_rename, TRX_DICT_OP_TABLE); - - err = fts_rename_aux_tables_to_hex_format_low(trx_rename, - parent_table, aux_tables); - - trx_rename->dict_operation_lock_mode = 0; - - if (err != DB_SUCCESS) { - fts_sql_rollback(trx_rename); - - ib::warn() << "Rollback operations on all aux tables of " - "table "<< parent_table->name << ". All the fts index " - "associated with the table are marked as corrupted. " - "Please rebuild the index again."; - - /* Corrupting the fts index related to parent table. */ - trx_rename->dict_operation_lock_mode = RW_X_LATCH; - trx_start_for_ddl(trx_rename, TRX_DICT_OP_TABLE); - fts_parent_all_index_set_corrupt(trx_rename, parent_table); - trx_rename->dict_operation_lock_mode = 0; - } - - fts_sql_commit(trx_rename); - trx_rename->free(); - ib_vector_reset(aux_tables); -} - -/** Set the hex format flag for the parent table. -@param[in, out] parent_table parent table -@param[in] trx transaction */ -static -void -fts_set_parent_hex_format_flag( - dict_table_t* parent_table, - trx_t* trx) -{ - if (!DICT_TF2_FLAG_IS_SET(parent_table, - DICT_TF2_FTS_AUX_HEX_NAME)) { - DBUG_EXECUTE_IF("parent_table_flag_fail", DBUG_SUICIDE();); - - dberr_t err = fts_update_hex_format_flag( - trx, parent_table->id, true); - - if (err != DB_SUCCESS) { - ib::fatal() << "Setting parent table " - << parent_table->name - << "to hex format failed. Please try " - << "to restart the server again, if it " - << "doesn't work, the system tables " - << "might be corrupted."; - } else { - DICT_TF2_FLAG_SET( - parent_table, DICT_TF2_FTS_AUX_HEX_NAME); - } - } -} - -/** Drop the obsolete auxilary table. -@param[in] tables tables to be dropped. */ -static -void -fts_drop_obsolete_aux_table_from_vector( - ib_vector_t* tables) -{ - dberr_t err; - - for (ulint count = 0; count < ib_vector_size(tables); - ++count) { - - fts_aux_table_t* aux_drop_table; - aux_drop_table = static_cast<fts_aux_table_t*>( - ib_vector_get(tables, count)); - trx_t* trx_drop = trx_create(); - trx_drop->op_info = "Drop obsolete aux tables"; - trx_drop->dict_operation_lock_mode = RW_X_LATCH; - trx_start_for_ddl(trx_drop, TRX_DICT_OP_TABLE); - - err = row_drop_table_for_mysql( - aux_drop_table->name, trx_drop, - SQLCOM_DROP_TABLE, true); - - trx_drop->dict_operation_lock_mode = 0; - - if (err != DB_SUCCESS) { - /* We don't need to worry about the - failure, since server would try to - drop it on next restart, even if - the table was broken. */ - ib::warn() << "Failed to drop obsolete aux table " - << aux_drop_table->name << ", which is " - << "harmless. will try to drop it on next " - << "restart."; - - fts_sql_rollback(trx_drop); - } else { - ib::info() << "Dropped obsolete aux" - " table '" << aux_drop_table->name - << "'."; - - fts_sql_commit(trx_drop); - } - - trx_drop->free(); - } -} - -/** Drop all the auxiliary table present in the vector. -@param[in] trx transaction -@param[in] tables tables to be dropped */ -static -void -fts_drop_aux_table_from_vector( - trx_t* trx, - ib_vector_t* tables) -{ - for (ulint count = 0; count < ib_vector_size(tables); - ++count) { - fts_aux_table_t* aux_drop_table; - aux_drop_table = static_cast<fts_aux_table_t*>( - ib_vector_get(tables, count)); - - /* Check for the validity of the parent table */ - if (!fts_valid_parent_table(aux_drop_table)) { - - ib::warn() << "Parent table of FTS auxiliary table " - << aux_drop_table->name << " not found."; - - dberr_t err = fts_drop_table(trx, aux_drop_table->name); - if (err == DB_FAIL) { - - char* path = fil_make_filepath( - NULL, aux_drop_table->name, IBD, false); - - if (path != NULL) { - os_file_delete_if_exists( - innodb_data_file_key, - path , NULL); - ut_free(path); - } - } - } - } -} - -/**********************************************************************//** -Check and drop all orphaned FTS auxiliary tables, those that don't have -a parent table or FTS index defined on them. -@return DB_SUCCESS or error code */ -static MY_ATTRIBUTE((nonnull)) -void -fts_check_and_drop_orphaned_tables( -/*===============================*/ - trx_t* trx, /*!< in: transaction */ - ib_vector_t* tables) /*!< in: tables to check */ -{ - mem_heap_t* heap; - ib_vector_t* aux_tables_to_rename; - ib_vector_t* invalid_aux_tables; - ib_vector_t* valid_aux_tables; - ib_vector_t* drop_aux_tables; - ib_vector_t* obsolete_aux_tables; - ib_alloc_t* heap_alloc; - - heap = mem_heap_create(1024); - heap_alloc = ib_heap_allocator_create(heap); - - /* We store all aux tables belonging to the same parent table here, - and rename all these tables in a batch mode. */ - aux_tables_to_rename = ib_vector_create(heap_alloc, - sizeof(fts_aux_table_t), 128); - - /* We store all fake auxiliary table and orphaned table here. */ - invalid_aux_tables = ib_vector_create(heap_alloc, - sizeof(fts_aux_table_t), 128); - - /* We store all valid aux tables. We use this to filter the - fake auxiliary table from invalid auxiliary tables. */ - valid_aux_tables = ib_vector_create(heap_alloc, - sizeof(fts_aux_table_t), 128); - - /* We store all auxiliary tables to be dropped. */ - drop_aux_tables = ib_vector_create(heap_alloc, - sizeof(fts_aux_table_t), 128); - - /* We store all obsolete auxiliary tables to be dropped. */ - obsolete_aux_tables = ib_vector_create(heap_alloc, - sizeof(fts_aux_table_t), 128); - - /* Sort by parent_id first, in case rename will fail */ - ib_vector_sort(tables, fts_check_aux_table_parent_id_cmp); - - for (ulint i = 0; i < ib_vector_size(tables); ++i) { - dict_table_t* parent_table; - fts_aux_table_t* aux_table; - bool drop = false; - dict_table_t* table; - fts_aux_table_t* next_aux_table = NULL; - ib_id_t orig_parent_id = 0; - ib_id_t orig_index_id = 0; - bool rename = false; - - aux_table = static_cast<fts_aux_table_t*>( - ib_vector_get(tables, i)); - - table = dict_table_open_on_id( - aux_table->id, TRUE, DICT_TABLE_OP_NORMAL); - orig_parent_id = aux_table->parent_id; - orig_index_id = aux_table->index_id; - - if (table == NULL - || strcmp(table->name.m_name, aux_table->name)) { - - bool fake_aux = false; - - if (table != NULL) { - dict_table_close(table, TRUE, FALSE); - } - - if (i + 1 < ib_vector_size(tables)) { - next_aux_table = static_cast<fts_aux_table_t*>( - ib_vector_get(tables, i + 1)); - } - - /* To know whether aux table is fake fts or - orphan fts table. */ - for (ulint count = 0; - count < ib_vector_size(valid_aux_tables); - count++) { - fts_aux_table_t* valid_aux; - valid_aux = static_cast<fts_aux_table_t*>( - ib_vector_get(valid_aux_tables, count)); - if (strcmp(valid_aux->name, - aux_table->name) == 0) { - fake_aux = true; - break; - } - } - - /* All aux tables of parent table, whose id is - last_parent_id, have been checked, try to rename - them if necessary. */ - if ((next_aux_table == NULL - || orig_parent_id != next_aux_table->parent_id) - && (!ib_vector_is_empty(aux_tables_to_rename))) { - - ib_id_t parent_id = fts_fake_hex_to_dec( - aux_table->parent_id); - - parent_table = dict_table_open_on_id( - parent_id, TRUE, - DICT_TABLE_OP_NORMAL); - - fts_rename_aux_tables_to_hex_format( - aux_tables_to_rename, parent_table); - - dict_table_close(parent_table, TRUE, - FALSE); - } - - /* If the aux table is fake aux table. Skip it. */ - if (!fake_aux) { - ib_vector_push(invalid_aux_tables, aux_table); - } - - continue; - } else if (!DICT_TF2_FLAG_IS_SET(table, - DICT_TF2_FTS_AUX_HEX_NAME)) { - - aux_table->parent_id = fts_fake_hex_to_dec( - aux_table->parent_id); - - if (aux_table->index_id != 0) { - aux_table->index_id = fts_fake_hex_to_dec( - aux_table->index_id); - } - - ut_ad(aux_table->id > aux_table->parent_id); - - /* Check whether parent table id and index id - are stored as decimal format. */ - if (fts_valid_parent_table(aux_table)) { - - parent_table = dict_table_open_on_id( - aux_table->parent_id, true, - DICT_TABLE_OP_NORMAL); - - ut_ad(parent_table != NULL); - ut_ad(parent_table->fts != NULL); - - if (!DICT_TF2_FLAG_IS_SET( - parent_table, - DICT_TF2_FTS_AUX_HEX_NAME)) { - rename = true; - } - - dict_table_close(parent_table, TRUE, FALSE); - } - - if (!rename) { - /* Reassign the original value of - aux table if it is not in decimal format */ - aux_table->parent_id = orig_parent_id; - aux_table->index_id = orig_index_id; - } - } - - if (table != NULL) { - dict_table_close(table, TRUE, FALSE); - } - - if (!rename) { - /* Check the validity of the parent table. */ - if (!fts_valid_parent_table(aux_table)) { - drop = true; - } - } - - /* Filter out the fake aux table by comparing with the - current valid auxiliary table name. */ - for (ulint count = 0; - count < ib_vector_size(invalid_aux_tables); count++) { - fts_aux_table_t* invalid_aux; - invalid_aux = static_cast<fts_aux_table_t*>( - ib_vector_get(invalid_aux_tables, count)); - if (strcmp(invalid_aux->name, aux_table->name) == 0) { - ib_vector_remove( - invalid_aux_tables, - *reinterpret_cast<void**>(invalid_aux)); - break; - } - } - - ib_vector_push(valid_aux_tables, aux_table); - - /* If the index associated with aux table is corrupted, - skip it. */ - if (fts_check_corrupt_index(aux_table) > 0) { - - if (i + 1 < ib_vector_size(tables)) { - next_aux_table = static_cast<fts_aux_table_t*>( - ib_vector_get(tables, i + 1)); - } - - if (next_aux_table == NULL - || orig_parent_id != next_aux_table->parent_id) { - - parent_table = dict_table_open_on_id( - aux_table->parent_id, TRUE, - DICT_TABLE_OP_NORMAL); - - if (!ib_vector_is_empty(aux_tables_to_rename)) { - fts_rename_aux_tables_to_hex_format( - aux_tables_to_rename, parent_table); - } else { - fts_set_parent_hex_format_flag( - parent_table, trx); - } - - dict_table_close(parent_table, TRUE, FALSE); - } - - continue; - } - - parent_table = dict_table_open_on_id( - aux_table->parent_id, TRUE, DICT_TABLE_OP_NORMAL); - - if (drop) { - ib_vector_push(drop_aux_tables, aux_table); - } else { - if (FTS_IS_OBSOLETE_AUX_TABLE(aux_table->name)) { - ib_vector_push(obsolete_aux_tables, aux_table); - continue; - } - } - - /* If the aux table is in decimal format, we should - rename it, so push it to aux_tables_to_rename */ - if (!drop && rename) { - bool rename_table = true; - for (ulint count = 0; - count < ib_vector_size(aux_tables_to_rename); - count++) { - fts_aux_table_t* rename_aux = - static_cast<fts_aux_table_t*>( - ib_vector_get(aux_tables_to_rename, - count)); - if (strcmp(rename_aux->name, - aux_table->name) == 0) { - rename_table = false; - break; - } - } - - if (rename_table) { - ib_vector_push(aux_tables_to_rename, - aux_table); - } - } - - if (i + 1 < ib_vector_size(tables)) { - next_aux_table = static_cast<fts_aux_table_t*>( - ib_vector_get(tables, i + 1)); - } - - if ((next_aux_table == NULL - || orig_parent_id != next_aux_table->parent_id) - && !ib_vector_is_empty(aux_tables_to_rename)) { - - ut_ad(rename); - ut_ad(!DICT_TF2_FLAG_IS_SET( - parent_table, DICT_TF2_FTS_AUX_HEX_NAME)); - - fts_rename_aux_tables_to_hex_format( - aux_tables_to_rename,parent_table); - } - - /* The IDs are already in correct hex format. */ - if (!drop && !rename) { - dict_table_t* table; - - table = dict_table_open_on_id( - aux_table->id, TRUE, DICT_TABLE_OP_NORMAL); - - if (table != NULL - && strcmp(table->name.m_name, aux_table->name)) { - dict_table_close(table, TRUE, FALSE); - table = NULL; - } - - if (table != NULL - && !DICT_TF2_FLAG_IS_SET( - table, - DICT_TF2_FTS_AUX_HEX_NAME)) { - - DBUG_EXECUTE_IF("aux_table_flag_fail", - ib::warn() << "Setting aux table " - << table->name << " to hex " - "format failed."; - fts_set_index_corrupt( - trx, aux_table->index_id, - parent_table); - goto table_exit;); - - dberr_t err = fts_update_hex_format_flag( - trx, table->id, true); - - if (err != DB_SUCCESS) { - ib::warn() << "Setting aux table " - << table->name << " to hex " - "format failed."; - - fts_set_index_corrupt( - trx, aux_table->index_id, - parent_table); - } else { - DICT_TF2_FLAG_SET(table, - DICT_TF2_FTS_AUX_HEX_NAME); - } - } -#ifndef DBUG_OFF -table_exit: -#endif /* !DBUG_OFF */ - - if (table != NULL) { - dict_table_close(table, TRUE, FALSE); - } - - ut_ad(parent_table != NULL); - - fts_set_parent_hex_format_flag( - parent_table, trx); - } - - if (parent_table != NULL) { - dict_table_close(parent_table, TRUE, FALSE); - } - } - - fts_drop_aux_table_from_vector(trx, invalid_aux_tables); - fts_drop_aux_table_from_vector(trx, drop_aux_tables); - fts_sql_commit(trx); - - fts_drop_obsolete_aux_table_from_vector(obsolete_aux_tables); - - /* Free the memory allocated at the beginning */ - if (heap != NULL) { - mem_heap_free(heap); - } -} - -/**********************************************************************//** -Drop all orphaned FTS auxiliary tables, those that don't have a parent -table or FTS index defined on them. */ -void -fts_drop_orphaned_tables(void) -/*==========================*/ -{ - trx_t* trx; - pars_info_t* info; - mem_heap_t* heap; - que_t* graph; - ib_vector_t* tables; - ib_alloc_t* heap_alloc; - - heap = mem_heap_create(1024); - heap_alloc = ib_heap_allocator_create(heap); - - /* We store the table ids of all the FTS indexes that were found. */ - tables = ib_vector_create(heap_alloc, sizeof(fts_aux_table_t), 128); - - /* Get the list of all known .ibd files and check for orphaned - FTS auxiliary files in that list. We need to remove them because - users can't map them back to table names and this will create - unnecessary clutter. */ - - mutex_enter(&fil_system.mutex); - - for (fil_space_t* space = UT_LIST_GET_FIRST(fil_system.space_list); - space != NULL; - space = UT_LIST_GET_NEXT(space_list, space)) { - - if (space->purpose != FIL_TYPE_TABLESPACE) { - continue; - } - - fts_aux_table_t fts_aux_table; - memset(&fts_aux_table, 0x0, sizeof fts_aux_table); - - size_t len = strlen(space->name); - - if (!fts_is_aux_table_name(&fts_aux_table, space->name, len)) { - continue; - } - - fts_aux_table.id = space->id; - fts_aux_table.name = mem_heap_strdupl(heap, space->name, len); - ib_vector_push(tables, &fts_aux_table); - } - - mutex_exit(&fil_system.mutex); - - trx = trx_create(); - trx->op_info = "dropping orphaned FTS tables"; - row_mysql_lock_data_dictionary(trx); - - info = pars_info_create(); - - pars_info_bind_function(info, "my_func", fts_read_tables, tables); - - graph = fts_parse_sql_no_dict_lock( - info, - "DECLARE FUNCTION my_func;\n" - "DECLARE CURSOR c IS" - " SELECT NAME, ID" - " FROM SYS_TABLES;\n" - "BEGIN\n" - "\n" - "OPEN c;\n" - "WHILE 1 = 1 LOOP\n" - " FETCH c INTO my_func();\n" - " IF c % NOTFOUND THEN\n" - " EXIT;\n" - " END IF;\n" - "END LOOP;\n" - "CLOSE c;"); - - for (;;) { - dberr_t error = fts_eval_sql(trx, graph); - - if (UNIV_LIKELY(error == DB_SUCCESS)) { - fts_check_and_drop_orphaned_tables(trx, tables); - break; /* Exit the loop. */ - } else { - ib_vector_reset(tables); - - fts_sql_rollback(trx); - - if (error == DB_LOCK_WAIT_TIMEOUT) { - ib::warn() << "lock wait timeout reading" - " SYS_TABLES. Retrying!"; - - trx->error_state = DB_SUCCESS; - } else { - ib::error() << "(" << error - << ") while reading SYS_TABLES."; - - break; /* Exit the loop. */ - } - } - } - - que_graph_free(graph); + if (fts_space_set.empty()) + return; - row_mysql_unlock_data_dictionary(trx); + fts_check_orphaned_tables(fts_space_set); - trx->free(); + if (fts_space_set.empty()) + return; - if (heap != NULL) { - mem_heap_free(heap); - } + trx_t* trx= trx_create(); + trx->op_info= "Drop orphaned aux FTS tables"; + row_mysql_lock_data_dictionary(trx); + + for (fts_space_set_t::iterator it = fts_space_set.begin(); + it != fts_space_set.end(); it++) + { + fts_table_t fts_table; + dict_table_t *table= dict_table_open_on_id(it->first, TRUE, + DICT_TABLE_OP_NORMAL); + if (!table) + continue; + + FTS_INIT_FTS_TABLE(&fts_table, NULL, FTS_COMMON_TABLE, table); + fts_drop_common_tables(trx, &fts_table, true); + + fts_table.type= FTS_INDEX_TABLE; + fts_table.index_id= it->second; + fts_drop_all_aux_tables(trx, &fts_table); + + dict_table_close(table, true, false); + } + trx_commit_for_mysql(trx); + row_mysql_unlock_data_dictionary(trx); + trx->dict_operation_lock_mode= 0; + trx->free(); } /**********************************************************************//** diff --git a/storage/innobase/fts/fts0sql.cc b/storage/innobase/fts/fts0sql.cc index 94269ef001c..180500f64a5 100644 --- a/storage/innobase/fts/fts0sql.cc +++ b/storage/innobase/fts/fts0sql.cc @@ -55,28 +55,23 @@ fts_get_table_id( long */ { int len; - bool hex_name = DICT_TF2_FLAG_IS_SET(fts_table->table, - DICT_TF2_FTS_AUX_HEX_NAME); ut_a(fts_table->table != NULL); switch (fts_table->type) { case FTS_COMMON_TABLE: - len = fts_write_object_id(fts_table->table_id, table_id, - hex_name); + len = fts_write_object_id(fts_table->table_id, table_id); break; case FTS_INDEX_TABLE: - len = fts_write_object_id(fts_table->table_id, table_id, - hex_name); + len = fts_write_object_id(fts_table->table_id, table_id); table_id[len] = '_'; ++len; table_id += len; - len += fts_write_object_id(fts_table->index_id, table_id, - hex_name); + len += fts_write_object_id(fts_table->index_id, table_id); break; default: diff --git a/storage/innobase/gis/gis0rtree.cc b/storage/innobase/gis/gis0rtree.cc index 778202a11c6..2e50d1b2cad 100644 --- a/storage/innobase/gis/gis0rtree.cc +++ b/storage/innobase/gis/gis0rtree.cc @@ -652,8 +652,7 @@ rtr_adjust_upper_level( new_prdt.op = 0; lock_prdt_update_parent(block, new_block, &prdt, &new_prdt, - index->table->space_id, - page_cursor->block->page.id().page_no()); + page_cursor->block->page.id()); mem_heap_free(heap); @@ -881,8 +880,6 @@ rtr_page_split_and_insert( buf_block_t* block; page_t* page; page_t* new_page; - ulint page_no; - ulint hint_page_no; buf_block_t* new_block; page_zip_des_t* page_zip; page_zip_des_t* new_page_zip; @@ -931,7 +928,7 @@ func_start: ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX)); ut_ad(page_get_n_recs(page) >= 1); - page_no = block->page.id().page_no(); + const page_id_t page_id(block->page.id()); if (!page_has_prev(page) && !page_is_leaf(page)) { first_rec = page_rec_get_next( @@ -969,10 +966,9 @@ func_start: static_cast<uchar*>(first_rec)); /* Allocate a new page to the index */ - hint_page_no = page_no + 1; const uint16_t page_level = btr_page_get_level(page); - new_block = btr_page_alloc(cursor->index, hint_page_no, FSP_UP, - page_level, mtr, mtr); + new_block = btr_page_alloc(cursor->index, page_id.page_no() + 1, + FSP_UP, page_level, mtr, mtr); if (!new_block) { return NULL; } @@ -1155,8 +1151,7 @@ after_insert: /* Check any predicate locks need to be moved/copied to the new page */ - lock_prdt_update_split(new_block, &prdt, &new_prdt, - cursor->index->table->space_id, page_no); + lock_prdt_update_split(new_block, &prdt, &new_prdt, page_id); /* Adjust the upper level. */ rtr_adjust_upper_level(cursor, flags, block, new_block, diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc index 853db180277..21783a94e9c 100644 --- a/storage/innobase/gis/gis0sea.cc +++ b/storage/innobase/gis/gis0sea.cc @@ -298,8 +298,9 @@ rtr_pcur_getnext_from_path( && mode != PAGE_CUR_RTREE_LOCATE) { ut_ad(rtr_info->thr); lock_place_prdt_page_lock( - index->table->space_id, - next_page_no, index, + page_id_t(block->page.id().space(), + next_page_no), + index, rtr_info->thr); } new_split = true; @@ -1528,7 +1529,6 @@ rtr_copy_buf( ut_d(matches->block.in_withdraw_list = block->in_withdraw_list); /* Skip buf_block_t::lock */ - matches->block.lock_hash_val = block->lock_hash_val; matches->block.modify_clock = block->modify_clock; #ifdef BTR_CUR_HASH_ADAPT matches->block.n_hash_helps = block->n_hash_helps; @@ -1690,7 +1690,6 @@ rtr_cur_search_with_match( const rec_t* best_rec; const rec_t* last_match_rec = NULL; bool match_init = false; - ulint space = block->page.id().space(); page_cur_mode_t orig_mode = mode; const rec_t* first_rec = NULL; @@ -1871,7 +1870,11 @@ rtr_cur_search_with_match( /* Lock the page, preventing it from being shrunk */ lock_place_prdt_page_lock( - space, page_no, index, + page_id_t(block->page + .id() + .space(), + page_no), + index, rtr_info->thr); } } else { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 6c40a7690f3..3d10ca03f20 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -106,6 +106,7 @@ this program; if not, write to the Free Software Foundation, Inc., #include "fil0crypt.h" #include "srv0mon.h" #include "srv0start.h" +#include "rem0rec.h" #ifdef UNIV_DEBUG #include "trx0purge.h" #endif /* UNIV_DEBUG */ @@ -5041,14 +5042,13 @@ innobase_vcol_build_templ( mysql_row_templ_t* templ, ulint col_no) { - if (col->is_virtual()) { - templ->is_virtual = true; - templ->col_no = col_no; + templ->col_no = col_no; + templ->is_virtual = col->is_virtual(); + + if (templ->is_virtual) { templ->clust_rec_field_no = ULINT_UNDEFINED; templ->rec_field_no = col->ind; } else { - templ->is_virtual = false; - templ->col_no = col_no; templ->clust_rec_field_no = dict_col_get_clust_pos( col, clust_index); ut_a(templ->clust_rec_field_no != ULINT_UNDEFINED); @@ -6660,6 +6660,8 @@ build_template_field( templ = prebuilt->mysql_template + prebuilt->n_template++; MEM_UNDEFINED(templ, sizeof *templ); + templ->rec_field_is_prefix = FALSE; + templ->rec_prefix_field_no = ULINT_UNDEFINED; templ->is_virtual = !field->stored_in_db(); if (!templ->is_virtual) { @@ -6721,8 +6723,6 @@ build_template_field( << " query " << innobase_get_stmt_unsafe(current_thd, &size); } - templ->rec_field_is_prefix = FALSE; - templ->rec_prefix_field_no = ULINT_UNDEFINED; if (dict_index_is_clust(index)) { templ->rec_field_no = templ->clust_rec_field_no; @@ -6740,7 +6740,6 @@ build_template_field( DBUG_ASSERT(!ha_innobase::omits_virtual_cols(*table->s)); col = &dict_table_get_nth_v_col(index->table, v_no)->m_col; templ->clust_rec_field_no = v_no; - templ->rec_prefix_field_no = ULINT_UNDEFINED; if (dict_index_is_clust(index)) { templ->rec_field_no = templ->clust_rec_field_no; @@ -20063,64 +20062,53 @@ innobase_get_field_from_update_vector( Allocate a heap and record for calculating virtual fields Used mainly for virtual fields in indexes -@param[in] thd MariaDB THD -@param[in] index Index in use -@param[out] heap Heap that holds temporary row -@param[in,out] table MariaDB table -@param[out] record Pointer to allocated MariaDB record -@param[out] storage Internal storage for blobs etc +@param[in] thd MariaDB THD +@param[in] index Index in use +@param[out] heap Heap that holds temporary row +@param[in,out] table MariaDB table +@param[out] record Pointer to allocated MariaDB record +@param[out] storage Internal storage for blobs etc -@retval false on success -@retval true on malloc failure or failed to open the maria table +@retval true on success +@retval false on malloc failure or failed to open the maria table for purge thread. */ -bool innobase_allocate_row_for_vcol( - THD * thd, - dict_index_t* index, - mem_heap_t** heap, - TABLE** table, - byte** record, - VCOL_STORAGE** storage) -{ - TABLE *maria_table; - String *blob_value_storage; - if (!*table) - *table= innodb_find_table_for_vc(thd, index->table); - - /* For purge thread, there is a possiblity that table could have - dropped, corrupted or unaccessible. */ - if (!*table) - return true; - maria_table= *table; - if (!*heap && !(*heap= mem_heap_create(srv_page_size))) - { - *storage= 0; - return TRUE; - } - *record= static_cast<byte*>(mem_heap_alloc(*heap, - maria_table->s->reclength)); - *storage= static_cast<VCOL_STORAGE*> - (mem_heap_alloc(*heap, sizeof(**storage))); - blob_value_storage= static_cast<String*> - (mem_heap_alloc(*heap, - maria_table->s->virtual_not_stored_blob_fields * - sizeof(String))); - if (!*record || !*storage || !blob_value_storage) - { - *storage= 0; - return TRUE; - } - (*storage)->maria_table= maria_table; - (*storage)->innobase_record= *record; - (*storage)->maria_record= maria_table->field[0]->record_ptr(); - (*storage)->blob_value_storage= blob_value_storage; +bool innobase_allocate_row_for_vcol(THD *thd, dict_index_t *index, + mem_heap_t **heap, TABLE **table, + VCOL_STORAGE *storage) +{ + TABLE *maria_table; + String *blob_value_storage; + if (!*table) + *table = innodb_find_table_for_vc(thd, index->table); + + /* For purge thread, there is a possiblity that table could have + dropped, corrupted or unaccessible. */ + if (!*table) + return false; + maria_table = *table; + if (!*heap && !(*heap = mem_heap_create(srv_page_size))) + return false; + + uchar *record = static_cast<byte *>(mem_heap_alloc(*heap, + maria_table->s->reclength)); - maria_table->move_fields(maria_table->field, *record, - (*storage)->maria_record); - maria_table->remember_blob_values(blob_value_storage); + size_t len = maria_table->s->virtual_not_stored_blob_fields * sizeof(String); + blob_value_storage = static_cast<String *>(mem_heap_alloc(*heap, len)); - return FALSE; + if (!record || !blob_value_storage) + return false; + + storage->maria_table = maria_table; + storage->innobase_record = record; + storage->maria_record = maria_table->field[0]->record_ptr(); + storage->blob_value_storage = blob_value_storage; + + maria_table->move_fields(maria_table->field, record, storage->maria_record); + maria_table->remember_blob_values(blob_value_storage); + + return true; } @@ -20135,6 +20123,13 @@ void innobase_free_row_for_vcol(VCOL_STORAGE *storage) } +void innobase_report_computed_value_failed(dtuple_t *row) +{ + ib::error() << "Compute virtual column values failed for " + << rec_printer(row).str(); +} + + /** Get the computed value by supplying the base column values. @param[in,out] row the data row @param[in] col virtual column @@ -20270,13 +20265,6 @@ innobase_get_computed_value( dbug_tmp_restore_column_map(mysql_table->write_set, old_write_set); if (ret != 0) { - // FIXME: Why this error message is macro-hidden? -#ifdef INNODB_VIRTUAL_DEBUG - ib::warn() << "Compute virtual column values failed "; - fputs("InnoDB: Cannot compute value for following record ", - stderr); - dtuple_print(stderr, row); -#endif /* INNODB_VIRTUAL_DEBUG */ DBUG_RETURN(NULL); } diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index ceda6187374..f80ee865746 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -10902,9 +10902,14 @@ ha_innobase::commit_inplace_alter_table( = static_cast<ha_innobase_inplace_ctx*>(*pctx); DBUG_ASSERT(new_clustered == ctx->need_rebuild()); - - fail = commit_set_autoinc(ha_alter_info, ctx, altered_table, - table); + if (ctx->need_rebuild() && !ctx->old_table->space) { + my_error(ER_TABLESPACE_DISCARDED, MYF(0), + table->s->table_name.str); + fail = true; + } else { + fail = commit_set_autoinc(ha_alter_info, ctx, + altered_table, table); + } if (fail) { } else if (ctx->need_rebuild()) { diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 125456c1ad4..a5713e32d86 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -699,10 +699,10 @@ fill_innodb_locks_from_cache( OK(field_store_string(fields[IDX_LOCK_INDEX], row->lock_index)); OK(fields[IDX_LOCK_SPACE]->store( - row->lock_space, true)); + row->lock_page.space(), true)); fields[IDX_LOCK_SPACE]->set_notnull(); OK(fields[IDX_LOCK_PAGE]->store( - row->lock_page, true)); + row->lock_page.page_no(), true)); fields[IDX_LOCK_PAGE]->set_notnull(); OK(fields[IDX_LOCK_REC]->store( row->lock_rec, true)); @@ -7048,8 +7048,7 @@ i_s_tablespaces_encryption_fill_table( for (fil_space_t* space = UT_LIST_GET_FIRST(fil_system.space_list); space; space = UT_LIST_GET_NEXT(space_list, space)) { if (space->purpose == FIL_TYPE_TABLESPACE - && !space->is_stopping()) { - space->acquire(); + && space->acquire()) { mutex_exit(&fil_system.mutex); if (int err = i_s_dict_fill_tablespaces_encryption( thd, space, tables->table)) { diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index a3ed5b104c6..ca13e2e33af 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -3329,18 +3329,22 @@ fail_exit: and done mtr_commit(&mtr) to release the latch. */ ibuf_mtr_start(&bitmap_mtr); - index->set_modified(bitmap_mtr); bitmap_page = ibuf_bitmap_get_map_page(page_id, zip_size, &bitmap_mtr); /* We check if the index page is suitable for buffered entries */ - if (buf_pool.page_hash_contains(page_id) - || lock_rec_expl_exist_on_page(page_id.space(), - page_id.page_no())) { - + if (buf_pool.page_hash_contains(page_id)) { +commit_exit: ibuf_mtr_commit(&bitmap_mtr); goto fail_exit; + } else { + lock_mutex_enter(); + const auto lock_exists = lock_sys.get_first(page_id); + lock_mutex_exit(); + if (lock_exists) { + goto commit_exit; + } } if (op == IBUF_OP_INSERT) { @@ -3378,8 +3382,7 @@ fail_exit: dfield_t* field; if (counter == ULINT_UNDEFINED) { - ibuf_mtr_commit(&bitmap_mtr); - goto fail_exit; + goto commit_exit; } field = dtuple_get_nth_field( @@ -3391,6 +3394,7 @@ fail_exit: /* Set the bitmap bit denoting that the insert buffer contains buffered entries for this index page, if the bit is not set yet */ + index->set_modified(bitmap_mtr); ibuf_bitmap_page_set_bits<IBUF_BITMAP_BUFFERED>( bitmap_page, page_id, physical_size, true, &bitmap_mtr); ibuf_mtr_commit(&bitmap_mtr); diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 20bf8d5b24b..04d74b6e36f 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -40,7 +40,6 @@ Created 11/5/1995 Heikki Tuuri #include "ut0byte.h" #include "page0types.h" #include "ut0rbt.h" -#include "os0proc.h" #include "log0log.h" #include "srv0srv.h" #include <ostream> @@ -597,16 +596,6 @@ inline uint buf_page_full_crc32_size(const byte* buf, bool* comp, bool* cr) } #ifndef UNIV_INNOCHECKSUM -/**********************************************************************//** -Gets the hash value of a block. This can be used in searches in the -lock hash table. -@return lock hash value */ -UNIV_INLINE -unsigned -buf_block_get_lock_hash_val( -/*========================*/ - const buf_block_t* block) /*!< in: block */ - MY_ATTRIBUTE((warn_unused_result)); #ifdef UNIV_DEBUG /** Find a block in the buffer pool that points to a given compressed page. @param[in] data pointer to compressed page @@ -1071,13 +1060,6 @@ struct buf_block_t{ a block is in the unzip_LRU list if page.state() == BUF_BLOCK_FILE_PAGE and page.zip.data != NULL */ - uint32_t lock_hash_val; /*!< hashed value of the page address - in the record lock hash table; - protected by buf_block_t::lock - (or buf_pool.mutex - in buf_page_get_gen(), - buf_page_init_for_read() - and buf_page_create()) */ /* @} */ /** @name Optimistic search field */ /* @{ */ diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic index cda7d435725..2384c46af02 100644 --- a/storage/innobase/include/buf0buf.ic +++ b/storage/innobase/include/buf0buf.ic @@ -154,24 +154,6 @@ ok: } #endif /* UNIV_DEBUG */ -/**********************************************************************//** -Gets the hash value of the page the pointer is pointing to. This can be used -in searches in the lock hash table. -@return lock hash value */ -UNIV_INLINE -unsigned -buf_block_get_lock_hash_val( -/*========================*/ - const buf_block_t* block) /*!< in: block */ -{ - ut_ad(block); - ut_ad(block->page.in_file()); - ut_ad(rw_lock_own(&(((buf_block_t*) block)->lock), RW_LOCK_X) - || rw_lock_own(&(((buf_block_t*) block)->lock), RW_LOCK_S)); - - return(block->lock_hash_val); -} - /********************************************************************//** Allocates a buf_page_t descriptor. This function must succeed. In case of failure we assert in this function. diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 3a2f78fa25f..96cf0a45b65 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -330,14 +330,6 @@ struct fil_space_t Protected by log_sys.mutex. If and only if this is nonzero, the tablespace will be in named_spaces. */ - /** set when an .ibd file is about to be deleted, - or an undo tablespace is about to be truncated. - When this is set, the following new ops are not allowed: - * read IO request - * file flush - Note that we can still possibly have new write operations - because we don't check this flag when doing flush batches. */ - bool stop_new_ops; /** whether undo tablespace truncation is in progress */ bool is_being_truncated; fil_type_t purpose;/*!< purpose */ @@ -364,14 +356,22 @@ struct fil_space_t ulint n_pending_flushes; /*!< this is positive when flushing the tablespace to disk; dropping of the tablespace is forbidden if this is positive */ - /** Number of pending buffer pool operations accessing the tablespace - without holding a table lock or dict_sys.latch S-latch - that would prevent the table (and tablespace) from being - dropped. An example is fil_crypt_thread. - The tablespace cannot be dropped while this is nonzero, - or while fil_node_t::n_pending is nonzero. - Protected by fil_system.mutex and std::atomic. */ - std::atomic<ulint> n_pending_ops; +private: + /** Number of pending buffer pool operations accessing the + tablespace without holding a table lock or dict_operation_lock + S-latch that would prevent the table (and tablespace) from being + dropped. An example is encryption key rotation. + + The tablespace cannot be dropped while this is nonzero, or while + fil_node_t::n_pending is nonzero. + + The most significant bit contains the STOP_NEW_OPS flag. */ + Atomic_relaxed<size_t> n_pending_ops; + + /** Flag in n_pending_ops that indicates that the tablespace is being + deleted, and no further operations should be performed */ + static const size_t STOP_NEW_OPS= ~(~size_t(0) >> 1); +public: /** Number of pending block read or write operations (when a write is imminent or a read has recently completed). The tablespace object cannot be freed while this is nonzero, @@ -415,9 +415,6 @@ struct fil_space_t ulint magic_n;/*!< FIL_SPACE_MAGIC_N */ - /** @return whether the tablespace is about to be dropped */ - bool is_stopping() const { return stop_new_ops; } - /** Clamp a page number for batched I/O, such as read-ahead. @param offset page number limit @return offset clamped to the tablespace size */ @@ -502,20 +499,45 @@ struct fil_space_t /** Close each file. Only invoked on fil_system.temp_space. */ void close(); - /** Acquire a tablespace reference. */ - void acquire() { n_pending_ops++; } - /** Release a tablespace reference. - @return whether this was the last reference */ - bool release() { auto n= n_pending_ops--; ut_ad(n); return n == 1; } - /** @return whether references are being held */ - bool referenced() const { return n_pending_ops; } - - /** Acquire a tablespace reference for I/O. */ - void acquire_for_io() { n_pending_ios++; } - /** Release a tablespace reference for I/O. */ - void release_for_io() { ut_ad(pending_io()); n_pending_ios--; } - /** @return whether I/O is pending */ - bool pending_io() const { return n_pending_ios; } + /** @return whether the tablespace is about to be dropped */ + bool is_stopping() const { return n_pending_ops & STOP_NEW_OPS; } + + /** @return number of references being held */ + size_t referenced() const { return n_pending_ops & ~STOP_NEW_OPS; } + + /** Note that operations on the tablespace must stop or can resume */ + void set_stopping(bool stopping) + { + ut_d(auto n=) n_pending_ops.fetch_xor(STOP_NEW_OPS); + ut_ad(!(n & STOP_NEW_OPS) == stopping); + } + + MY_ATTRIBUTE((warn_unused_result)) + /** @return whether a tablespace reference was successfully acquired */ + bool acquire() + { + size_t n= 0; + while (!n_pending_ops.compare_exchange_strong(n, n + 1, + std::memory_order_acquire, + std::memory_order_relaxed)) + if (UNIV_UNLIKELY(n & STOP_NEW_OPS)) + return false; + return true; + } + /** Release a tablespace reference. + @return whether this was the last reference */ + bool release() + { + auto n= n_pending_ops.fetch_sub(1); + ut_ad(n & ~STOP_NEW_OPS); + return (n & ~STOP_NEW_OPS) == 1; + } + /** Acquire a tablespace reference for I/O. */ + void acquire_for_io() { n_pending_ios++; } + /** Release a tablespace reference for I/O. */ + void release_for_io() { ut_d(auto n=) n_pending_ios--; ut_ad(n); } + /** @return whether I/O is pending */ + bool pending_io() const { return n_pending_ios; } /** @return whether the tablespace file can be closed and reopened */ bool belongs_in_lru() const @@ -557,7 +579,7 @@ struct fil_space_t ulint flags; /** Determine if full_crc32 is used for a data file - @param[in] flags tablespace flags (FSP_FLAGS) + @param[in] flags tablespace flags (FSP_SPACE_FLAGS) @return whether the full_crc32 algorithm is active */ static bool full_crc32(ulint flags) { return flags & FSP_FLAGS_FCRC32_MASK_MARKER; @@ -676,23 +698,23 @@ struct fil_space_t static bool is_flags_full_crc32_equal(ulint flags, ulint expected) { ut_ad(full_crc32(flags)); - ulint page_ssize = FSP_FLAGS_FCRC32_GET_PAGE_SSIZE(flags); + ulint fcrc32_psize = FSP_FLAGS_FCRC32_GET_PAGE_SSIZE(flags); if (full_crc32(expected)) { /* The data file may have been created with a different innodb_compression_algorithm. But we only support one innodb_page_size for all files. */ - return page_ssize - == FSP_FLAGS_FCRC32_GET_PAGE_SSIZE(expected); + return fcrc32_psize + == FSP_FLAGS_FCRC32_GET_PAGE_SSIZE(expected); } - ulint space_page_ssize = FSP_FLAGS_GET_PAGE_SSIZE(expected); + ulint non_fcrc32_psize = FSP_FLAGS_GET_PAGE_SSIZE(expected); - if (page_ssize == 5) { - if (space_page_ssize) { + if (!non_fcrc32_psize) { + if (fcrc32_psize != 5) { return false; } - } else if (space_page_ssize != page_ssize) { + } else if (fcrc32_psize != non_fcrc32_psize) { return false; } @@ -710,15 +732,15 @@ struct fil_space_t return false; } - ulint page_ssize = FSP_FLAGS_GET_PAGE_SSIZE(flags); - ulint space_page_ssize = FSP_FLAGS_FCRC32_GET_PAGE_SSIZE( + ulint non_fcrc32_psize = FSP_FLAGS_GET_PAGE_SSIZE(flags); + ulint fcrc32_psize = FSP_FLAGS_FCRC32_GET_PAGE_SSIZE( expected); - if (page_ssize) { - if (space_page_ssize != 5) { + if (!non_fcrc32_psize) { + if (fcrc32_psize != 5) { return false; } - } else if (space_page_ssize != page_ssize) { + } else if (fcrc32_psize != non_fcrc32_psize) { return false; } @@ -1402,11 +1424,12 @@ fil_space_free( bool x_latched); /** Set the recovered size of a tablespace in pages. -@param id tablespace ID -@param size recovered size in pages */ +@param id tablespace ID +@param size recovered size in pages +@param flags tablespace flags */ UNIV_INTERN -void -fil_space_set_recv_size(ulint id, ulint size); +void fil_space_set_recv_size_and_flags(ulint id, ulint size, uint32_t flags); + /*******************************************************************//** Returns the size of the space in pages. The tablespace must be cached in the memory cache. diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index e5bc4c8a6ed..31c66cb57ea 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/include/fsp0fsp.h @@ -362,26 +362,18 @@ fsp_header_init_fields( void fsp_header_init(fil_space_t* space, ulint size, mtr_t* mtr) MY_ATTRIBUTE((nonnull)); -/**********************************************************************//** -Creates a new segment. -@return the block where the segment header is placed, x-latched, NULL -if could not create segment because of lack of space */ +/** Create a new segment. +@param space tablespace +@param byte_offset byte offset of the created segment header +@param mtr mini-transaction +@param has_done_reservation whether fsp_reserve_free_extents() was invoked +@param block block where segment header is placed, + or NULL to allocate an additional page for that +@return the block where the segment header is placed, x-latched +@retval NULL if could not create segment because of lack of space */ buf_block_t* -fseg_create( - fil_space_t* space, /*!< in,out: tablespace */ - ulint page, /*!< in: page where the segment header is placed: if - this is != 0, the page must belong to another segment, - if this is 0, a new page will be allocated and it - will belong to the created segment */ - ulint byte_offset, /*!< in: byte offset of the created segment header - on the page */ - mtr_t* mtr, - bool has_done_reservation = false); /*!< in: whether the caller - has already done the reservation for the pages with - fsp_reserve_free_extents (at least 2 extents: one for - the inode and the other for the segment) then there is - no need to do the check for this individual - operation */ +fseg_create(fil_space_t *space, ulint byte_offset, mtr_t *mtr, + bool has_done_reservation= false, buf_block_t *block= NULL); /** Calculate the number of pages reserved by a segment, and how many pages are currently used. diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h index 9e0cab12373..5c35e5dac4f 100644 --- a/storage/innobase/include/fts0fts.h +++ b/storage/innobase/include/fts0fts.h @@ -737,12 +737,9 @@ fts_savepoint_rollback_last_stmt( /*=============================*/ trx_t* trx); /*!< in: transaction */ -/***********************************************************************//** -Drop all orphaned FTS auxiliary tables, those that don't have a parent +/** Drop all orphaned FTS auxiliary tables, those that don't have a parent table or FTS index defined on them. */ -void -fts_drop_orphaned_tables(void); -/*==========================*/ +void fts_drop_orphaned_tables(); /** Run SYNC on the table, i.e., write out data from the cache to the FTS auxiliary INDEX table and clear the cache at the end. @@ -776,15 +773,6 @@ fts_init_doc_id( /*============*/ const dict_table_t* table); /*!< in: table */ -/* Get parent table name if it's a fts aux table -@param[in] aux_table_name aux table name -@param[in] aux_table_len aux table length -@return parent table name, or NULL */ -char* -fts_get_parent_table_name( - const char* aux_table_name, - ulint aux_table_len); - /******************************************************************//** compare two character string according to their charset. */ extern @@ -991,6 +979,16 @@ and there are no new fts index to add. @param[in] trx transaction to drop all fts tables */ void fts_clear_all(dict_table_t *table, trx_t *trx); +/** Check whether the given name is fts auxiliary table +and fetch the parent table id and index id +@param[in] name table name +@param[in,out] table_id parent table id +@param[in,out] index_id index id +@return true if it is auxilary table */ +bool fts_check_aux_table(const char *name, + table_id_t *table_id, + index_id_t *index_id); + /** Sync the table during commit phase @param[in] table table to be synced */ void fts_sync_during_ddl(dict_table_t* table); diff --git a/storage/innobase/include/fts0priv.h b/storage/innobase/include/fts0priv.h index 09d3a77ba79..4261fc25773 100644 --- a/storage/innobase/include/fts0priv.h +++ b/storage/innobase/include/fts0priv.h @@ -447,11 +447,7 @@ int fts_write_object_id( /*================*/ ib_id_t id, /*!< in: a table/index id */ - char* str, /*!< in: buffer to write the id to */ - bool hex_format MY_ATTRIBUTE((unused))) - /*!< in: true for fixed hex format, - false for old ambiguous format */ - MY_ATTRIBUTE((nonnull)); + char* str); /*!< in: buffer to write the id to */ /******************************************************************//** Read the table id from the string generated by fts_write_object_id(). @return TRUE if parse successful */ diff --git a/storage/innobase/include/fts0priv.ic b/storage/innobase/include/fts0priv.ic index ed737e520d6..da14cfcb013 100644 --- a/storage/innobase/include/fts0priv.ic +++ b/storage/innobase/include/fts0priv.ic @@ -32,10 +32,7 @@ int fts_write_object_id( /*================*/ ib_id_t id, /* in: a table/index id */ - char* str, /* in: buffer to write the id to */ - bool hex_format MY_ATTRIBUTE((unused))) - /* in: true for fixed hex format, - false for old ambiguous format */ + char* str) /* in: buffer to write the id to */ { #ifdef _WIN32 @@ -60,11 +57,6 @@ fts_write_object_id( #endif /* _WIN32 */ - /* As above, but this is only for those tables failing to rename. */ - if (!hex_format) { - return(sprintf(str, "%016llu", (ulonglong) id)); - } - return(sprintf(str, "%016llx", (ulonglong) id)); } diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index ab697a730d2..dd25c52101f 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -252,15 +252,6 @@ lock_rec_restore_from_page_infimum( state; lock bits are reset on the infimum */ /*********************************************************************//** -Determines if there are explicit record locks on a page. -@return an explicit record lock on the page, or NULL if there are none */ -lock_t* -lock_rec_expl_exist_on_page( -/*========================*/ - ulint space, /*!< in: space id */ - ulint page_no)/*!< in: page number */ - MY_ATTRIBUTE((warn_unused_result)); -/*********************************************************************//** Checks if locks of other transactions prevent an immediate insert of a record. If they do, first tests if the query thread should anyway be suspended for some reason; if not, then puts the transaction and @@ -487,28 +478,6 @@ lock_rec_unlock( and release possible other transactions waiting because of these locks. */ void lock_release(trx_t* trx); -/*********************************************************************//** -Calculates the fold value of a page file address: used in inserting or -searching for a lock in the hash table. -@return folded value */ -UNIV_INLINE -ulint -lock_rec_fold( -/*==========*/ - ulint space, /*!< in: space */ - ulint page_no)/*!< in: page number */ - MY_ATTRIBUTE((const)); -/*********************************************************************//** -Calculates the hash value of a page file address: used in inserting or -searching for a lock in the hash table. -@return hashed value */ -UNIV_INLINE -unsigned -lock_rec_hash( -/*==========*/ - ulint space, /*!< in: space */ - ulint page_no);/*!< in: page number */ - /*************************************************************//** Get the lock hash table */ UNIV_INLINE @@ -819,6 +788,46 @@ public: /** Closes the lock system at database shutdown. */ void close(); + + /** @return the hash value for a page address */ + ulint hash(const page_id_t id) const + { ut_ad(mutex_own(&mutex)); return rec_hash.calc_hash(id.fold()); } + + /** Get the first lock on a page. + @param lock_hash hash table to look at + @param id page number + @return first lock + @retval nullptr if none exists */ + lock_t *get_first(const hash_table_t &lock_hash, const page_id_t id) const + { + ut_ad(&lock_hash == &rec_hash || &lock_hash == &prdt_hash || + &lock_hash == &prdt_page_hash); + for (lock_t *lock= static_cast<lock_t*> + (HASH_GET_FIRST(&lock_hash, hash(id))); + lock; lock= static_cast<lock_t*>(HASH_GET_NEXT(hash, lock))) + if (lock->un_member.rec_lock.page_id == id) + return lock; + return nullptr; + } + + /** Get the first record lock on a page. + @param id page number + @return first lock + @retval nullptr if none exists */ + lock_t *get_first(const page_id_t id) const + { return get_first(rec_hash, id); } + /** Get the first predicate lock on a SPATIAL INDEX page. + @param id page number + @return first lock + @retval nullptr if none exists */ + lock_t *get_first_prdt(const page_id_t id) const + { return get_first(prdt_hash, id); } + /** Get the first predicate lock on a SPATIAL INDEX page. + @param id page number + @return first lock + @retval nullptr if none exists */ + lock_t *get_first_prdt_page(const page_id_t id) const + { return get_first(prdt_page_hash, id); } }; /*********************************************************************//** @@ -858,8 +867,7 @@ lock_rec_discard( without checking for deadlocks or conflicts. @param[in] type_mode lock mode and wait flag; type will be replaced with LOCK_REC -@param[in] space tablespace id -@param[in] page_no index page number +@param[in] page_id index page number @param[in] page R-tree index page, or NULL @param[in] heap_no record heap number in the index page @param[in] index the index tree @@ -873,8 +881,7 @@ lock_rec_create_low( que_thr_t* thr, /*!< thread owning trx */ #endif unsigned type_mode, - ulint space, - ulint page_no, + const page_id_t page_id, const page_t* page, ulint heap_no, dict_index_t* index, diff --git a/storage/innobase/include/lock0lock.ic b/storage/innobase/include/lock0lock.ic index 6146f835be9..2d5b6ff37f1 100644 --- a/storage/innobase/include/lock0lock.ic +++ b/storage/innobase/include/lock0lock.ic @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2020, MariaDB Corporation. 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 @@ -29,34 +29,6 @@ Created 5/7/1996 Heikki Tuuri #include "page0page.h" /*********************************************************************//** -Calculates the fold value of a page file address: used in inserting or -searching for a lock in the hash table. -@return folded value */ -UNIV_INLINE -ulint -lock_rec_fold( -/*==========*/ - ulint space, /*!< in: space */ - ulint page_no)/*!< in: page number */ -{ - return(ut_fold_ulint_pair(space, page_no)); -} - -/*********************************************************************//** -Calculates the hash value of a page file address: used in inserting or -searching for a lock in the hash table. -@return hashed value */ -UNIV_INLINE -unsigned -lock_rec_hash( -/*==========*/ - ulint space, /*!< in: space */ - ulint page_no)/*!< in: page number */ -{ - return unsigned(lock_sys.rec_hash.calc_hash(lock_rec_fold(space, page_no))); -} - -/*********************************************************************//** Gets the heap_no of the smallest user record on a page. @return heap_no of smallest user record, or PAGE_HEAP_NO_SUPREMUM */ UNIV_INLINE @@ -122,12 +94,10 @@ lock_rec_create( trx mutex */ { btr_assert_not_corrupted(block, index); - const page_id_t id(block->page.id()); return lock_rec_create_low( #ifdef WITH_WSREP c_lock, thr, #endif - type_mode, id.space(), id.page_no(), - block->frame, heap_no, + type_mode, block->page.id(), block->frame, heap_no, index, trx, caller_owns_trx_mutex); } diff --git a/storage/innobase/include/lock0prdt.h b/storage/innobase/include/lock0prdt.h index 59cf0130625..43d68996691 100644 --- a/storage/innobase/include/lock0prdt.h +++ b/storage/innobase/include/lock0prdt.h @@ -58,9 +58,7 @@ Acquire a "Page" lock on a block @return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_place_prdt_page_lock( -/*======================*/ - ulint space, /*!< in: space for the page to lock */ - ulint pageno, /*!< in: page number */ + const page_id_t page_id, /*!< in: page identifier */ dict_index_t* index, /*!< in: secondary index */ que_thr_t* thr); /*!< in: query thread */ @@ -108,8 +106,7 @@ lock_prdt_update_split( buf_block_t* new_block, /*!< in/out: the new half page */ lock_prdt_t* prdt, /*!< in: MBR on the old page */ lock_prdt_t* new_prdt, /*!< in: MBR on the new page */ - ulint space, /*!< in: space id */ - ulint page_no); /*!< in: page number */ + const page_id_t page_id); /*!< in: page number */ /**************************************************************//** Ajust locks from an ancester page of Rtree on the appropriate level . */ @@ -120,8 +117,7 @@ lock_prdt_update_parent( buf_block_t* right_block, /*!< in/out: the new half page */ lock_prdt_t* left_prdt, /*!< in: MBR on the old page */ lock_prdt_t* right_prdt, /*!< in: MBR on the new page */ - ulint space, /*!< in: space id */ - ulint page_no); /*!< in: page number */ + const page_id_t page_id); /*!< in: parent page */ /*********************************************************************//** Checks if locks of other transactions prevent an immediate insert of @@ -190,17 +186,11 @@ lock_prdt_rec_move( const buf_block_t* donator); /*!< in: buffer block containing the donating record */ -/** Check whether there are R-tree Page lock on a buffer page +/** Check whether there are R-tree Page lock on a page @param[in] trx trx to test the lock -@param[in] space space id for the page -@param[in] page_no page number -@return true if there is none */ -bool -lock_test_prdt_page_lock( -/*=====================*/ - const trx_t* trx, - ulint space, - ulint page_no); +@param[in] page_id page identifier +@return true if there is none */ +bool lock_test_prdt_page_lock(const trx_t *trx, const page_id_t page_id); /** Removes predicate lock objects set on an index page which is discarded. @param[in] block page to be discarded diff --git a/storage/innobase/include/lock0priv.h b/storage/innobase/include/lock0priv.h index 2743becea8f..1b2f9d0f0d3 100644 --- a/storage/innobase/include/lock0priv.h +++ b/storage/innobase/include/lock0priv.h @@ -539,29 +539,6 @@ lock_t* lock_rec_get_next_on_page( /*======================*/ lock_t* lock); /*!< in: a record lock */ -/*********************************************************************//** -Gets the first record lock on a page, where the page is identified by its -file address. -@return first lock, NULL if none exists */ -UNIV_INLINE -lock_t* -lock_rec_get_first_on_page_addr( -/*============================*/ - hash_table_t* lock_hash, /* Lock hash table */ - ulint space, /*!< in: space */ - ulint page_no); /*!< in: page number */ - -/*********************************************************************//** -Gets the first record lock on a page, where the page is identified by a -pointer to it. -@return first lock, NULL if none exists */ -UNIV_INLINE -lock_t* -lock_rec_get_first_on_page( -/*=======================*/ - hash_table_t* lock_hash, /*!< in: lock hash table */ - const buf_block_t* block); /*!< in: buffer block */ - /*********************************************************************//** Gets the next explicit lock request on a record. @@ -633,20 +610,6 @@ lock_get_wait( const lock_t* lock); /*!< in: lock */ /*********************************************************************//** -Looks for a suitable type record lock struct by the same trx on the same page. -This can be used to save space when a new record lock should be set on a page: -no new struct is needed, if a suitable old is found. -@return lock or NULL */ -UNIV_INLINE -lock_t* -lock_rec_find_similar_on_page( -/*==========================*/ - ulint type_mode, /*!< in: lock type_mode field */ - ulint heap_no, /*!< in: heap number of the record */ - lock_t* lock, /*!< in: lock_rec_get_first_on_page() */ - const trx_t* trx); /*!< in: transaction */ - -/*********************************************************************//** Checks if a transaction has the specified table lock, or stronger. This function should only be called by the thread that owns the transaction. @return lock or NULL */ diff --git a/storage/innobase/include/lock0priv.ic b/storage/innobase/include/lock0priv.ic index 7468110deeb..e16949a4917 100644 --- a/storage/innobase/include/lock0priv.ic +++ b/storage/innobase/include/lock0priv.ic @@ -122,68 +122,6 @@ lock_rec_get_next_on_page( } /*********************************************************************//** -Gets the first record lock on a page, where the page is identified by its -file address. -@return first lock, NULL if none exists */ -UNIV_INLINE -lock_t* -lock_rec_get_first_on_page_addr( -/*============================*/ - hash_table_t* lock_hash, /* Lock hash table */ - ulint space, /*!< in: space */ - ulint page_no) /*!< in: page number */ -{ - ut_ad(lock_mutex_own()); - - for (lock_t* lock = static_cast<lock_t*>( - HASH_GET_FIRST(lock_hash, - lock_rec_hash(space, page_no))); - lock != NULL; - lock = static_cast<lock_t*>(HASH_GET_NEXT(hash, lock))) { - - if (lock->un_member.rec_lock.space == space - && lock->un_member.rec_lock.page_no == page_no) { - - return(lock); - } - } - - return(NULL); -} - -/*********************************************************************//** -Gets the first record lock on a page, where the page is identified by a -pointer to it. -@return first lock, NULL if none exists */ -UNIV_INLINE -lock_t* -lock_rec_get_first_on_page( -/*=======================*/ - hash_table_t* lock_hash, /*!< in: lock hash table */ - const buf_block_t* block) /*!< in: buffer block */ -{ - ut_ad(lock_mutex_own()); - - ulint space = block->page.id().space(); - ulint page_no = block->page.id().page_no(); - ulint hash = buf_block_get_lock_hash_val(block); - - for (lock_t* lock = static_cast<lock_t*>( - HASH_GET_FIRST(lock_hash, hash)); - lock != NULL; - lock = static_cast<lock_t*>(HASH_GET_NEXT(hash, lock))) { - - if (lock->un_member.rec_lock.space == space - && lock->un_member.rec_lock.page_no == page_no) { - - return(lock); - } - } - - return(NULL); -} - -/*********************************************************************//** Gets the next explicit lock request on a record. @return next lock, NULL if none exists or if heap_no == ULINT_UNDEFINED */ UNIV_INLINE @@ -227,16 +165,11 @@ lock_rec_get_first( const buf_block_t* block, /*!< in: block containing the record */ ulint heap_no)/*!< in: heap number of the record */ { - ut_ad(lock_mutex_own()); - - for (lock_t* lock = lock_rec_get_first_on_page(hash, block); lock; - lock = lock_rec_get_next_on_page(lock)) { - if (lock_rec_get_nth_bit(lock, heap_no)) { - return(lock); - } - } - - return(NULL); + for (lock_t *lock= lock_sys.get_first(*hash, block->page.id()); + lock; lock= lock_rec_get_next_on_page(lock)) + if (lock_rec_get_nth_bit(lock, heap_no)) + return lock; + return nullptr; } /*********************************************************************//** @@ -273,23 +206,15 @@ lock_rec_get_next_on_page_const( /*============================*/ const lock_t* lock) /*!< in: a record lock */ { - ut_ad(lock_mutex_own()); - ut_ad(lock_get_type_low(lock) == LOCK_REC); - - ulint space = lock->un_member.rec_lock.space; - ulint page_no = lock->un_member.rec_lock.page_no; - - while ((lock = static_cast<const lock_t*>(HASH_GET_NEXT(hash, lock))) - != NULL) { - - if (lock->un_member.rec_lock.space == space - && lock->un_member.rec_lock.page_no == page_no) { + ut_ad(lock_mutex_own()); + ut_ad(lock_get_type_low(lock) == LOCK_REC); - return(lock); - } - } + const page_id_t page_id(lock->un_member.rec_lock.page_id); - return(NULL); + while (!!(lock= static_cast<const lock_t*>(HASH_GET_NEXT(hash, lock)))) + if (lock->un_member.rec_lock.page_id == page_id) + break; + return lock; } /*********************************************************************//** @@ -353,37 +278,6 @@ lock_get_wait( } /*********************************************************************//** -Looks for a suitable type record lock struct by the same trx on the same page. -This can be used to save space when a new record lock should be set on a page: -no new struct is needed, if a suitable old is found. -@return lock or NULL */ -UNIV_INLINE -lock_t* -lock_rec_find_similar_on_page( -/*==========================*/ - ulint type_mode, /*!< in: lock type_mode field */ - ulint heap_no, /*!< in: heap number of the record */ - lock_t* lock, /*!< in: lock_rec_get_first_on_page() */ - const trx_t* trx) /*!< in: transaction */ -{ - ut_ad(lock_mutex_own()); - - for (/* No op */; - lock != NULL; - lock = lock_rec_get_next_on_page(lock)) { - - if (lock->trx == trx - && lock->type_mode == type_mode - && lock_rec_get_n_bits(lock) > heap_no) { - - return(lock); - } - } - - return(NULL); -} - -/*********************************************************************//** Checks if a transaction has the specified table lock, or stronger. This function should only be called by the thread that owns the transaction. @return lock or NULL */ diff --git a/storage/innobase/include/lock0types.h b/storage/innobase/include/lock0types.h index cb04afdf9db..23307375426 100644 --- a/storage/innobase/include/lock0types.h +++ b/storage/innobase/include/lock0types.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2018, 2019, MariaDB Corporation. +Copyright (c) 2018, 2020, MariaDB Corporation. 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 @@ -25,6 +25,7 @@ Created 5/7/1996 Heikki Tuuri *******************************************************/ #include "dict0types.h" +#include "buf0types.h" #include "ut0lst.h" #ifndef lock0types_h @@ -89,8 +90,8 @@ struct lock_table_t { /** Record lock for a page */ struct lock_rec_t { - ib_uint32_t space; /*!< space id */ - ib_uint32_t page_no; /*!< page number */ + /** page identifier */ + page_id_t page_id; ib_uint32_t n_bits; /*!< number of bits in the lock bitmap; NOTE: the lock bitmap is placed immediately after the @@ -105,12 +106,12 @@ struct lock_rec_t { /** Print the record lock into the given output stream @param[in,out] out the output stream @return the given output stream. */ -inline -std::ostream& lock_rec_t::print(std::ostream& out) const +inline std::ostream &lock_rec_t::print(std::ostream &out) const { - out << "[lock_rec_t: space=" << space << ", page_no=" << page_no - << ", n_bits=" << n_bits << "]"; - return(out); + out << "[lock_rec_t: space=" << page_id.space() + << ", page_no=" << page_id.page_no() + << ", n_bits=" << n_bits << "]"; + return out; } inline diff --git a/storage/innobase/include/mtr0log.h b/storage/innobase/include/mtr0log.h index ee611f6f2ee..2bcd69d8899 100644 --- a/storage/innobase/include/mtr0log.h +++ b/storage/innobase/include/mtr0log.h @@ -513,7 +513,8 @@ inline void mtr_t::init(buf_block_t *b) { if (UNIV_LIKELY_NULL(m_freed_pages)) { - ut_ad(m_user_space->id == b->page.id().space()); + ut_ad(m_log_mode != MTR_LOG_ALL || + m_user_space_id == b->page.id().space()); if (m_freed_pages->remove_if_exists(b->page.id().page_no()) && m_freed_pages->empty()) { diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 599da234904..4487bf94e01 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -591,6 +591,11 @@ public: m_freed_pages->add_value(id.page_no()); } + /** Determine the added buffer fix count of a block. + @param block block to be checked + @return number of buffer count added by this mtr */ + uint32_t get_fix_count(const buf_block_t *block) const; + private: /** Log a write of a byte string to a page. @param block buffer page diff --git a/storage/innobase/include/os0proc.h b/storage/innobase/include/os0proc.h deleted file mode 100644 index 2a507e013fe..00000000000 --- a/storage/innobase/include/os0proc.h +++ /dev/null @@ -1,50 +0,0 @@ -/***************************************************************************** - -Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. - -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, Fifth Floor, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/**************************************************//** -@file include/os0proc.h -The interface to the operating system -process control primitives - -Created 9/30/1995 Heikki Tuuri -*******************************************************/ - -#ifndef os0proc_h -#define os0proc_h - -#include "univ.i" - -#ifdef UNIV_LINUX -#include <sys/ipc.h> -#include <sys/shm.h> -#endif - -typedef void* os_process_t; -typedef unsigned long int os_process_id_t; - -/** The total amount of memory currently allocated from the operating -system with allocate_large(). */ -extern Atomic_counter<ulint> os_total_large_mem_allocated; - -/** Converts the current process id to a number. -@return process id as a number */ -ulint -os_proc_get_number(void); - -#endif diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h index 0acff406326..82941b18a33 100644 --- a/storage/innobase/include/rem0rec.h +++ b/storage/innobase/include/rem0rec.h @@ -1186,16 +1186,17 @@ struct rec_offsets_print @param[in,out] o output stream @param[in] r record to display @return the output stream */ +ATTRIBUTE_COLD std::ostream& operator<<(std::ostream& o, const rec_offsets_print& r); -# ifndef DBUG_OFF /** Pretty-printer of records and tuples */ class rec_printer : public std::ostringstream { public: /** Construct a pretty-printed record. @param rec record with header @param offsets rec_get_offsets(rec, ...) */ + ATTRIBUTE_COLD rec_printer(const rec_t* rec, const rec_offs* offsets) : std::ostringstream () @@ -1209,6 +1210,7 @@ public: @param rec record, possibly lacking header @param info rec_get_info_bits(rec) @param offsets rec_get_offsets(rec, ...) */ + ATTRIBUTE_COLD rec_printer(const rec_t* rec, ulint info, const rec_offs* offsets) : std::ostringstream () @@ -1218,6 +1220,7 @@ public: /** Construct a pretty-printed tuple. @param tuple data tuple */ + ATTRIBUTE_COLD rec_printer(const dtuple_t* tuple) : std::ostringstream () @@ -1228,6 +1231,7 @@ public: /** Construct a pretty-printed tuple. @param field array of data tuple fields @param n number of fields */ + ATTRIBUTE_COLD rec_printer(const dfield_t* field, ulint n) : std::ostringstream () @@ -1244,7 +1248,7 @@ private: /** Assignment operator */ rec_printer& operator=(const rec_printer& other); }; -# endif /* !DBUG_OFF */ + # ifdef UNIV_DEBUG /** Read the DB_TRX_ID of a clustered index record. diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index c4163f8d2e0..fc454826c2b 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -848,6 +848,8 @@ struct VCOL_STORAGE byte *innobase_record; byte *maria_record; String *blob_value_storage; + VCOL_STORAGE(): maria_table(NULL), innobase_record(NULL), + maria_record(NULL), blob_value_storage(NULL) {} }; /** @@ -870,12 +872,48 @@ bool innobase_allocate_row_for_vcol( dict_index_t* index, mem_heap_t** heap, TABLE** table, - byte** record, - VCOL_STORAGE** storage); + VCOL_STORAGE* storage); /** Free memory allocated by innobase_allocate_row_for_vcol() */ void innobase_free_row_for_vcol(VCOL_STORAGE *storage); +class ib_vcol_row +{ + VCOL_STORAGE storage; +public: + mem_heap_t *heap; + + ib_vcol_row(mem_heap_t *heap) : heap(heap) {} + + byte *record(THD *thd, dict_index_t *index, TABLE **table) + { + if (!storage.innobase_record) + { + bool ok = innobase_allocate_row_for_vcol(thd, index, &heap, table, + &storage); + if (!ok) + return NULL; + } + return storage.innobase_record; + }; + + ~ib_vcol_row() + { + if (heap) + { + if (storage.innobase_record) + innobase_free_row_for_vcol(&storage); + mem_heap_free(heap); + } + } +}; + +/** Report virtual value computation failure in ib::error +@param[in] row the data row +*/ +ATTRIBUTE_COLD +void innobase_report_computed_value_failed(dtuple_t *row); + /** Get the computed value by supplying the base column values. @param[in,out] row the data row @param[in] col virtual column diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h index f9d949fc2d7..58c60a0a4da 100644 --- a/storage/innobase/include/row0upd.h +++ b/storage/innobase/include/row0upd.h @@ -184,24 +184,18 @@ row_upd_index_replace_new_col_vals_index_pos( const upd_t* update, mem_heap_t* heap) MY_ATTRIBUTE((nonnull)); -/***********************************************************//** -Replaces the new column values stored in the update vector to the index entry -given. */ -void -row_upd_index_replace_new_col_vals( -/*===============================*/ - dtuple_t* entry, /*!< in/out: index entry where replaced; - the clustered index record must be - covered by a lock or a page latch to - prevent deletion (rollback or purge) */ - dict_index_t* index, /*!< in: index; NOTE that this may also be a - non-clustered index */ - const upd_t* update, /*!< in: an update vector built for the - CLUSTERED index so that the field number in - an upd_field is the clustered index position */ - mem_heap_t* heap) /*!< in: memory heap for allocating and - copying the new values */ - MY_ATTRIBUTE((nonnull)); +/** Replace the new column values stored in the update vector, +during trx_undo_prev_version_build(). +@param entry clustered index tuple where the values are replaced + (the clustered index leaf page latch must be held) +@param index clustered index +@param update update vector for the clustered index +@param heap memory heap for allocating and copying values +@return whether the previous version was built successfully */ +bool +row_upd_index_replace_new_col_vals(dtuple_t *entry, const dict_index_t &index, + const upd_t *update, mem_heap_t *heap) + MY_ATTRIBUTE((nonnull, warn_unused_result)); /***********************************************************//** Replaces the new column values stored in the update vector. */ void diff --git a/storage/innobase/include/trx0i_s.h b/storage/innobase/include/trx0i_s.h index 892ee3cfe18..98b84fe0985 100644 --- a/storage/innobase/include/trx0i_s.h +++ b/storage/innobase/include/trx0i_s.h @@ -31,6 +31,7 @@ Created July 17, 2007 Vasil Dimov #include "trx0types.h" #include "dict0types.h" +#include "buf0types.h" /** The maximum amount of memory that can be consumed by innodb_trx, innodb_locks and innodb_lock_waits information schema tables. */ @@ -90,10 +91,8 @@ struct i_s_locks_row_t { lock_get_table_name() */ /** index name of a record lock; NULL for table locks */ const char* lock_index; - /** tablespace identifier of the record; 0 if !lock_index */ - uint32_t lock_space; - /** page number of the record; 0 if !lock_index */ - uint32_t lock_page; + /** page identifier of the record; (0,0) if !lock_index */ + page_id_t lock_page; /** heap number of the record; 0 if !lock_index */ uint16_t lock_rec; /** lock mode corresponding to lock_mode_values_typelib */ diff --git a/storage/innobase/include/ut0crc32.h b/storage/innobase/include/ut0crc32.h index f33ca54cb96..0cbccb976e2 100644 --- a/storage/innobase/include/ut0crc32.h +++ b/storage/innobase/include/ut0crc32.h @@ -28,33 +28,10 @@ Created Aug 10, 2011 Vasil Dimov #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. */ -void ut_crc32_init(); - -/** Append data to a CRC-32C checksum. -@param crc current checksum -@param s data to append to the checksum -@param size data length in bytes -@return CRC-32C, using the GF(2) primitive polynomial 0x11EDC6F41, -or 0x1EDC6F41 without the highest degree term */ -typedef uint32_t (*ut_crc32_func_t)(uint32_t crc, const byte *s, size_t size); - -/** Pointer to CRC32 calculation function. */ -extern ut_crc32_func_t ut_crc32_low; - -/** Text description of CRC32 implementation */ -extern const char* ut_crc32_implementation; - -/** Compute CRC-32C over a string of bytes. -@param s data -@param len data length in bytes -@return the CRC-32C of the data */ +#include <my_sys.h> static inline uint32_t ut_crc32(const byte *s, size_t size) { - return ut_crc32_low(0, s, size); + return my_crc32c(0, s, size); } #endif /* ut0crc32_h */ diff --git a/storage/innobase/include/ut0new.h b/storage/innobase/include/ut0new.h index 87249062a83..e8469db9dc3 100644 --- a/storage/innobase/include/ut0new.h +++ b/storage/innobase/include/ut0new.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2014, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2017, 2020, MariaDB Corporation. 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 @@ -137,7 +137,6 @@ InnoDB: #include "mysql/psi/psi_memory.h" /* PSI_memory_key, PSI_memory_info */ #include "os0thread.h" /* os_thread_sleep() */ -#include "os0proc.h" /* os_total_large_mem_allocated */ #include "ut0ut.h" /* ut_strcmp_functor, ut_basename_noext() */ #define OUT_OF_MEMORY_MSG \ @@ -145,6 +144,10 @@ InnoDB: " operating system. Note that on most 32-bit computers the process" \ " memory space is limited to 2 GB or 4 GB." +/** The total amount of memory currently allocated from the operating +system with allocate_large() */ +extern Atomic_counter<ulint> os_total_large_mem_allocated; + /** Maximum number of retries to allocate memory. */ extern const size_t alloc_max_retries; diff --git a/storage/innobase/innodb.cmake b/storage/innobase/innodb.cmake index dc6afe59088..978b33a2abe 100644 --- a/storage/innobase/innodb.cmake +++ b/storage/innobase/innodb.cmake @@ -209,16 +209,6 @@ IF(CMAKE_CXX_COMPILER_ID MATCHES "SunPro" PROPERTIES COMPILE_FLAGS -xO3) ENDIF() -# Avoid generating Hardware Capabilities due to crc32 instructions -IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_SYSTEM_PROCESSOR MATCHES "i386") - MY_CHECK_CXX_COMPILER_FLAG("-Wa,-nH") - IF(have_CXX__Wa__nH) - ADD_COMPILE_FLAGS( - ut/ut0crc32.cc - COMPILE_FLAGS "-Wa,-nH" - ) - ENDIF() -ENDIF() IF(MSVC) # Avoid "unreferenced label" warning in generated file diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 2c888f55b69..df206af34c7 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -477,13 +477,9 @@ void lock_sys_t::create(ulint n_cells) /** Calculates the fold value of a lock: used in migrating the hash table. @param[in] lock record lock object @return folded value */ -static -ulint -lock_rec_lock_fold( - const lock_t* lock) +static ulint lock_rec_lock_fold(const lock_t *lock) { - return(lock_rec_fold(lock->un_member.rec_lock.space, - lock->un_member.rec_lock.page_no)); + return lock->un_member.rec_lock.page_id.fold(); } @@ -515,18 +511,6 @@ void lock_sys_t::resize(ulint n_cells) HASH_MIGRATE(&old_hash, &prdt_page_hash, lock_t, hash, lock_rec_lock_fold); old_hash.free(); - - /* need to update block->lock_hash_val */ - mutex_enter(&buf_pool.mutex); - for (buf_page_t* bpage = UT_LIST_GET_FIRST(buf_pool.LRU); - bpage; bpage = UT_LIST_GET_NEXT(LRU, bpage)) { - if (bpage->state() == BUF_BLOCK_FILE_PAGE) { - const page_id_t id(bpage->id()); - reinterpret_cast<buf_block_t*>(bpage)->lock_hash_val - = lock_rec_hash(id.space(), id.page_no()); - } - } - mutex_exit(&buf_pool.mutex); mutex_exit(&mutex); } @@ -621,6 +605,57 @@ lock_rec_get_insert_intention( return(lock->type_mode & LOCK_INSERT_INTENTION); } +#ifdef WITH_WSREP +/** Check if both conflicting lock and other record lock are brute force +(BF). This case is a bug so report lock information and wsrep state. +@param[in] lock_rec1 conflicting waiting record lock or NULL +@param[in] lock_rec2 other waiting record lock +@param[in] trx1 lock_rec1 can be NULL, trx +*/ +static void wsrep_assert_no_bf_bf_wait( + const lock_t* lock_rec1, + const lock_t* lock_rec2, + const trx_t* trx1) +{ + ut_ad(!lock_rec1 || lock_get_type_low(lock_rec1) == LOCK_REC); + ut_ad(lock_get_type_low(lock_rec2) == LOCK_REC); + + if (!trx1->is_wsrep() || !lock_rec2->trx->is_wsrep()) + return; + if (UNIV_LIKELY(!wsrep_thd_is_BF(trx1->mysql_thd, FALSE))) + return; + if (UNIV_LIKELY(!wsrep_thd_is_BF(lock_rec2->trx->mysql_thd, FALSE))) + return; + + mtr_t mtr; + + if (lock_rec1) { + ib::error() << "Waiting lock on table: " + << lock_rec1->index->table->name + << " index: " + << lock_rec1->index->name() + << " that has conflicting lock "; + lock_rec_print(stderr, lock_rec1, mtr); + } + + ib::error() << "Conflicting lock on table: " + << lock_rec2->index->table->name + << " index: " + << lock_rec2->index->name() + << " that has lock "; + lock_rec_print(stderr, lock_rec2, mtr); + + ib::error() << "WSREP state: "; + + wsrep_report_bf_lock_wait(trx1->mysql_thd, + trx1->id); + wsrep_report_bf_lock_wait(lock_rec2->trx->mysql_thd, + lock_rec2->trx->id); + /* BF-BF wait is a bug */ + ut_error; +} +#endif /* WITH_WSREP */ + /*********************************************************************//** Checks if a lock request for a new lock has to wait for request lock2. @return TRUE if new lock has to wait for lock2 to be removed */ @@ -727,72 +762,9 @@ lock_rec_has_to_wait( } #ifdef WITH_WSREP - /* if BF thread is locking and has conflict with another BF - thread, we need to look at trx ordering and lock types */ - if (wsrep_thd_is_BF(trx->mysql_thd, FALSE) - && wsrep_thd_is_BF(lock2->trx->mysql_thd, FALSE)) { - mtr_t mtr; - - if (UNIV_UNLIKELY(wsrep_debug)) { - ib::info() << "BF-BF lock conflict, locking: " - << for_locking; - lock_rec_print(stderr, lock2, mtr); - ib::info() - << " SQL1: " << wsrep_thd_query(trx->mysql_thd) - << " SQL2: " - << wsrep_thd_query(lock2->trx->mysql_thd); - } - - if ((type_mode & LOCK_MODE_MASK) == LOCK_X - && (lock2->type_mode & LOCK_MODE_MASK) == LOCK_X) { - if (for_locking || UNIV_UNLIKELY(wsrep_debug)) { - /* exclusive lock conflicts are not - accepted */ - ib::info() - << "BF-BF X lock conflict,mode: " - << type_mode - << " supremum: " << lock_is_on_supremum - << "conflicts states: my " - << wsrep_thd_transaction_state_str( - trx->mysql_thd) - << " locked " - << wsrep_thd_transaction_state_str( - lock2->trx->mysql_thd); - lock_rec_print(stderr, lock2, mtr); - ib::info() << " SQL1: " - << wsrep_thd_query(trx->mysql_thd) - << " SQL2: " - << wsrep_thd_query( - lock2->trx->mysql_thd); - - if (for_locking) { - return false; - } - } - } else { - /* if lock2->index->n_uniq <= - lock2->index->n_user_defined_cols - operation is on uniq index - */ - if (wsrep_debug) { - ib::info() - << "BF conflict, modes: " << type_mode - << ":" << lock2->type_mode - << " idx: " << lock2->index->name() - << " table: " - << lock2->index->table->name - << " n_uniq: " << lock2->index->n_uniq - << " n_user: " - << lock2->index->n_user_defined_cols - << " SQL1: " - << wsrep_thd_query(trx->mysql_thd) - << " SQL2: " - << wsrep_thd_query( - lock2->trx->mysql_thd); - } - return false; - } - } + /* There should not be two conflicting locks that are + brute force. If there is it is a bug. */ + wsrep_assert_no_bf_bf_wait(NULL, lock2, trx); #endif /* WITH_WSREP */ return true; @@ -859,26 +831,6 @@ lock_rec_find_set_bit( } /*********************************************************************//** -Determines if there are explicit record locks on a page. -@return an explicit record lock on the page, or NULL if there are none */ -lock_t* -lock_rec_expl_exist_on_page( -/*========================*/ - ulint space, /*!< in: space id */ - ulint page_no)/*!< in: page number */ -{ - lock_t* lock; - - lock_mutex_enter(); - /* Only used in ibuf pages, so rec_hash is good enough */ - lock = lock_rec_get_first_on_page_addr(&lock_sys.rec_hash, - space, page_no); - lock_mutex_exit(); - - return(lock); -} - -/*********************************************************************//** Resets the record lock bitmap to zero. NOTE: does not touch the wait_lock pointer in the transaction! This function is used in lock object creation and resetting. */ @@ -899,7 +851,7 @@ lock_rec_bitmap_reset( ut_ad((lock_rec_get_n_bits(lock) % 8) == 0); - memset(&lock[1], 0, n_bytes); + memset(reinterpret_cast<void*>(&lock[1]), 0, n_bytes); } /*********************************************************************//** @@ -931,35 +883,21 @@ lock_rec_get_prev( ulint heap_no)/*!< in: heap number of the record */ { lock_t* lock; - ulint space; - ulint page_no; lock_t* found_lock = NULL; - hash_table_t* hash; ut_ad(lock_mutex_own()); ut_ad(lock_get_type_low(in_lock) == LOCK_REC); - space = in_lock->un_member.rec_lock.space; - page_no = in_lock->un_member.rec_lock.page_no; - - hash = lock_hash_get(in_lock->type_mode); - - for (lock = lock_rec_get_first_on_page_addr(hash, space, page_no); - /* No op */; + for (lock = lock_sys.get_first(*lock_hash_get(in_lock->type_mode), + in_lock->un_member.rec_lock.page_id); + lock != in_lock; lock = lock_rec_get_next_on_page(lock)) { - - ut_ad(lock); - - if (lock == in_lock) { - - return(found_lock); - } - if (lock_rec_get_nth_bit(lock, heap_no)) { - found_lock = lock; } } + + return found_lock; } /*============= FUNCTIONS FOR ANALYZING RECORD LOCK QUEUE ================*/ @@ -1297,8 +1235,7 @@ wsrep_print_wait_locks( without checking for deadlocks or conflicts. @param[in] type_mode lock mode and wait flag; type will be replaced with LOCK_REC -@param[in] space tablespace id -@param[in] page_no index page number +@param[in] page_id index page number @param[in] page R-tree index page, or NULL @param[in] heap_no record heap number in the index page @param[in] index the index tree @@ -1312,8 +1249,7 @@ lock_rec_create_low( que_thr_t* thr, /*!< thread owning trx */ #endif unsigned type_mode, - ulint space, - ulint page_no, + const page_id_t page_id, const page_t* page, ulint heap_no, dict_index_t* index, @@ -1382,8 +1318,7 @@ lock_rec_create_low( lock->trx = trx; lock->type_mode = (type_mode & unsigned(~LOCK_TYPE_MASK)) | LOCK_REC; lock->index = index; - lock->un_member.rec_lock.space = uint32_t(space); - lock->un_member.rec_lock.page_no = uint32_t(page_no); + lock->un_member.rec_lock.page_id = page_id; if (UNIV_LIKELY(!(type_mode & (LOCK_PREDICATE | LOCK_PRDT_PAGE)))) { lock->un_member.rec_lock.n_bits = uint32_t(n_bytes * 8); @@ -1451,11 +1386,8 @@ lock_rec_create_low( trx_mutex_exit(c_lock->trx); if (UNIV_UNLIKELY(wsrep_debug)) { - ib::info() << "WSREP: c_lock canceled " - << ib::hex(c_lock->trx->id) - << " SQL: " - << wsrep_thd_query( - c_lock->trx->mysql_thd); + wsrep_report_bf_lock_wait(trx->mysql_thd, trx->id); + wsrep_report_bf_lock_wait(c_lock->trx->mysql_thd, c_lock->trx->id); } /* have to bail out here to avoid lock_set_lock... */ @@ -1469,10 +1401,10 @@ lock_rec_create_low( == INNODB_LOCK_SCHEDULE_ALGORITHM_VATS && !thd_is_replication_slave_thread(trx->mysql_thd)) { HASH_PREPEND(lock_t, hash, &lock_sys.rec_hash, - lock_rec_fold(space, page_no), lock); + page_id.fold(), lock); } else { HASH_INSERT(lock_t, hash, lock_hash_get(type_mode), - lock_rec_fold(space, page_no), lock); + page_id.fold(), lock); } if (!holds_trx_mutex) { @@ -1526,19 +1458,15 @@ static dberr_t lock_rec_insert_by_trx_age( lock_t *in_lock) /*!< in: lock to be insert */{ - ulint space; - ulint page_no; - ulint rec_fold; lock_t* node; lock_t* next; hash_table_t* hash; hash_cell_t* cell; - space = in_lock->un_member.rec_lock.space; - page_no = in_lock->un_member.rec_lock.page_no; - rec_fold = lock_rec_fold(space, page_no); + ut_ad(!in_lock->trx->is_wsrep()); + const page_id_t page_id(in_lock->un_member.rec_lock.page_id); hash = lock_hash_get(in_lock->type_mode); - cell = &hash->array[hash->calc_hash(rec_fold)]; + cell = &hash->array[hash->calc_hash(page_id.fold())]; node = (lock_t *) cell->node; // If in_lock is not a wait lock, we insert it to the head of the list. @@ -1580,9 +1508,6 @@ bool lock_queue_validate( const lock_t *in_lock) /*!< in: lock whose hash list is to be validated */ { - ulint space; - ulint page_no; - ulint rec_fold; hash_table_t* hash; hash_cell_t* cell; lock_t* next; @@ -1592,11 +1517,9 @@ lock_queue_validate( return true; } - space = in_lock->un_member.rec_lock.space; - page_no = in_lock->un_member.rec_lock.page_no; - rec_fold = lock_rec_fold(space, page_no); + const page_id_t page_id(in_lock->un_member.rec_lock.page_id); hash = lock_hash_get(in_lock->type_mode); - cell = &hash->array[hash->calc_hash(rec_fold)]; + cell = &hash->array[hash->calc_hash(page_id.fold())]; next = (lock_t *) cell->node; while (next != NULL) { // If this is a granted lock, check that there's no wait lock before it. @@ -1754,6 +1677,36 @@ lock_rec_enqueue_waiting( } /*********************************************************************//** +Looks for a suitable type record lock struct by the same trx on the same page. +This can be used to save space when a new record lock should be set on a page: +no new struct is needed, if a suitable old is found. +@return lock or NULL */ +static inline +lock_t* +lock_rec_find_similar_on_page( + ulint type_mode, /*!< in: lock type_mode field */ + ulint heap_no, /*!< in: heap number of the record */ + lock_t* lock, /*!< in: lock_sys.get_first() */ + const trx_t* trx) /*!< in: transaction */ +{ + ut_ad(lock_mutex_own()); + + for (/* No op */; + lock != NULL; + lock = lock_rec_get_next_on_page(lock)) { + + if (lock->trx == trx + && lock->type_mode == type_mode + && lock_rec_get_n_bits(lock) > heap_no) { + + return(lock); + } + } + + return(NULL); +} + +/*********************************************************************//** Adds a record lock request in the record queue. The request is normally added as the last in the queue, but if there are no waiting lock requests on the record, and the request to be added is not a waiting request, we @@ -1798,27 +1751,19 @@ lock_rec_add_to_queue( = lock_rec_other_has_expl_req( mode, block, false, heap_no, trx); #ifdef WITH_WSREP - if (other_lock && trx->is_wsrep() && - !wsrep_thd_is_BF(trx->mysql_thd, FALSE) && - !wsrep_thd_is_BF(other_lock->trx->mysql_thd, FALSE)) { - - ib::info() << "WSREP BF lock conflict for my lock:\n BF:" << - ((wsrep_thd_is_BF(trx->mysql_thd, FALSE)) ? "BF" : "normal") << " exec: " << - wsrep_thd_client_state_str(trx->mysql_thd) << " conflict: " << - wsrep_thd_transaction_state_str(trx->mysql_thd) << " seqno: " << - wsrep_thd_trx_seqno(trx->mysql_thd) << " SQL: " << - wsrep_thd_query(trx->mysql_thd); - trx_t* otrx = other_lock->trx; - ib::info() << "WSREP other lock:\n BF:" << - ((wsrep_thd_is_BF(otrx->mysql_thd, FALSE)) ? "BF" : "normal") << " exec: " << - wsrep_thd_client_state_str(otrx->mysql_thd) << " conflict: " << - wsrep_thd_transaction_state_str(otrx->mysql_thd) << " seqno: " << - wsrep_thd_trx_seqno(otrx->mysql_thd) << " SQL: " << - wsrep_thd_query(otrx->mysql_thd); - } -#else - ut_a(!other_lock); + if (UNIV_LIKELY_NULL(other_lock) && trx->is_wsrep()) { + /* Only BF transaction may be granted lock + before other conflicting lock request. */ + if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) + && !wsrep_thd_is_BF(other_lock->trx->mysql_thd, FALSE)) { + /* If it is not BF, this case is a bug. */ + wsrep_report_bf_lock_wait(trx->mysql_thd, trx->id); + wsrep_report_bf_lock_wait(other_lock->trx->mysql_thd, other_lock->trx->id); + ut_error; + } + } else #endif /* WITH_WSREP */ + ut_ad(!other_lock); } #endif /* UNIV_DEBUG */ @@ -1840,11 +1785,11 @@ lock_rec_add_to_queue( lock_t* lock; lock_t* first_lock; - hash_table_t* hash = lock_hash_get(type_mode); /* Look for a waiting lock request on the same record or on a gap */ - for (first_lock = lock = lock_rec_get_first_on_page(hash, block); + for (first_lock = lock = lock_sys.get_first(*lock_hash_get(type_mode), + block->page.id()); lock != NULL; lock = lock_rec_get_next_on_page(lock)) { @@ -1923,7 +1868,7 @@ lock_rec_lock( if (lock_table_has(trx, index->table, static_cast<lock_mode>(LOCK_MODE_MASK & mode))); - else if (lock_t *lock= lock_rec_get_first_on_page(&lock_sys.rec_hash, block)) + else if (lock_t *lock= lock_sys.get_first(block->page.id())) { trx_mutex_enter(trx); if (lock_rec_get_next_on_page(lock) || @@ -2004,31 +1949,22 @@ lock_rec_has_to_wait_in_queue( const lock_t* wait_lock) /*!< in: waiting record lock */ { const lock_t* lock; - ulint space; - ulint page_no; ulint heap_no; ulint bit_mask; ulint bit_offset; - hash_table_t* hash; ut_ad(wait_lock); ut_ad(lock_mutex_own()); ut_ad(lock_get_wait(wait_lock)); ut_ad(lock_get_type_low(wait_lock) == LOCK_REC); - space = wait_lock->un_member.rec_lock.space; - page_no = wait_lock->un_member.rec_lock.page_no; heap_no = lock_rec_find_set_bit(wait_lock); bit_offset = heap_no / 8; bit_mask = static_cast<ulint>(1) << (heap_no % 8); - hash = lock_hash_get(wait_lock->type_mode); - - for (lock = lock_rec_get_first_on_page_addr(hash, space, page_no); -#ifdef WITH_WSREP - lock && -#endif + for (lock = lock_sys.get_first(*lock_hash_get(wait_lock->type_mode), + wait_lock->un_member.rec_lock.page_id); lock != wait_lock; lock = lock_rec_get_next_on_page_const(lock)) { const byte* p = (const byte*) &lock[1]; @@ -2036,24 +1972,6 @@ lock_rec_has_to_wait_in_queue( if (heap_no < lock_rec_get_n_bits(lock) && (p[bit_offset] & bit_mask) && lock_has_to_wait(wait_lock, lock)) { -#ifdef WITH_WSREP - if (wsrep_thd_is_BF(wait_lock->trx->mysql_thd, FALSE) && - wsrep_thd_is_BF(lock->trx->mysql_thd, FALSE)) { - - if (UNIV_UNLIKELY(wsrep_debug)) { - mtr_t mtr; - ib::info() << "WSREP: waiting BF trx: " << ib::hex(wait_lock->trx->id) - << " query: " << wsrep_thd_query(wait_lock->trx->mysql_thd); - lock_rec_print(stderr, wait_lock, mtr); - ib::info() << "WSREP: do not wait another BF trx: " << ib::hex(lock->trx->id) - << " query: " << wsrep_thd_query(lock->trx->mysql_thd); - lock_rec_print(stderr, lock, mtr); - } - /* don't wait for another BF lock */ - continue; - } -#endif /* WITH_WSREP */ - return(lock); } } @@ -2144,9 +2062,7 @@ lock_rec_cancel( trx_mutex_exit(lock->trx); } -static -void -lock_grant_and_move_on_page(ulint rec_fold, ulint space, ulint page_no) +static void lock_grant_and_move_on_page(ulint rec_fold, const page_id_t id) { lock_t* lock; lock_t* previous = static_cast<lock_t*>( @@ -2155,27 +2071,25 @@ lock_grant_and_move_on_page(ulint rec_fold, ulint space, ulint page_no) if (previous == NULL) { return; } - if (previous->un_member.rec_lock.space == space && - previous->un_member.rec_lock.page_no == page_no) { + if (previous->un_member.rec_lock.page_id == id) { lock = previous; } else { while (previous->hash && - (previous->hash->un_member.rec_lock.space != space || - previous->hash->un_member.rec_lock.page_no != page_no)) { - previous = previous->hash; + (previous->hash->un_member.rec_lock.page_id != id)) { + previous = previous->hash; } lock = previous->hash; } + ut_ad(!lock->trx->is_wsrep()); ut_ad(previous->hash == lock || previous == lock); /* Grant locks if there are no conflicting locks ahead. Move granted locks to the head of the list. */ while (lock) { /* If the lock is a wait lock on this page, and it does not need to wait. */ if (lock_get_wait(lock) - && lock->un_member.rec_lock.space == space - && lock->un_member.rec_lock.page_no == page_no + && lock->un_member.rec_lock.page_id == id && !lock_rec_has_to_wait_in_queue(lock)) { lock_grant(lock); @@ -2202,22 +2116,19 @@ to a lock. NOTE: all record locks contained in in_lock are removed. @param[in,out] in_lock record lock */ static void lock_rec_dequeue_from_page(lock_t* in_lock) { - ulint space; - ulint page_no; hash_table_t* lock_hash; ut_ad(lock_mutex_own()); ut_ad(lock_get_type_low(in_lock) == LOCK_REC); /* We may or may not be holding in_lock->trx->mutex here. */ - space = in_lock->un_member.rec_lock.space; - page_no = in_lock->un_member.rec_lock.page_no; + const page_id_t page_id(in_lock->un_member.rec_lock.page_id); in_lock->index->table->n_rec_locks--; lock_hash = lock_hash_get(in_lock->type_mode); - ulint rec_fold = lock_rec_fold(space, page_no); + const ulint rec_fold = page_id.fold(); HASH_DELETE(lock_t, hash, lock_hash, rec_fold, in_lock); UT_LIST_REMOVE(in_lock->trx->lock.trx_locks, in_lock); @@ -2233,20 +2144,26 @@ static void lock_rec_dequeue_from_page(lock_t* in_lock) grant locks if there are no conflicting locks ahead. Stop at the first X lock that is waiting or has been granted. */ - for (lock_t* lock = lock_rec_get_first_on_page_addr( - lock_hash, space, page_no); + for (lock_t* lock = lock_sys.get_first(*lock_hash, page_id); lock != NULL; lock = lock_rec_get_next_on_page(lock)) { - if (lock_get_wait(lock) - && !lock_rec_has_to_wait_in_queue(lock)) { + if (!lock_get_wait(lock)) { + continue; + } + const lock_t* c = lock_rec_has_to_wait_in_queue(lock); + if (!c) { /* Grant the lock */ ut_ad(lock->trx != in_lock->trx); lock_grant(lock); +#ifdef WITH_WSREP + } else { + wsrep_assert_no_bf_bf_wait(c, lock, c->trx); +#endif /* WITH_WSREP */ } } } else { - lock_grant_and_move_on_page(rec_fold, space, page_no); + lock_grant_and_move_on_page(rec_fold, page_id); } } @@ -2259,8 +2176,6 @@ lock_rec_discard( record locks which are contained in this lock object are removed */ { - ulint space; - ulint page_no; trx_lock_t* trx_lock; ut_ad(lock_mutex_own()); @@ -2268,13 +2183,10 @@ lock_rec_discard( trx_lock = &in_lock->trx->lock; - space = in_lock->un_member.rec_lock.space; - page_no = in_lock->un_member.rec_lock.page_no; - in_lock->index->table->n_rec_locks--; HASH_DELETE(lock_t, hash, lock_hash_get(in_lock->type_mode), - lock_rec_fold(space, page_no), in_lock); + in_lock->un_member.rec_lock.page_id.fold(), in_lock); UT_LIST_REMOVE(trx_lock->trx_locks, in_lock); @@ -2286,29 +2198,19 @@ lock_rec_discard( Removes record lock objects set on an index page which is discarded. This function does not move locks, or check for waiting locks, therefore the lock bitmaps must already be reset when this function is called. */ -static -void -lock_rec_free_all_from_discard_page_low( -/*====================================*/ - ulint space, - ulint page_no, - hash_table_t* lock_hash) +static void lock_rec_free_all_from_discard_page_low(const page_id_t id, + hash_table_t *lock_hash) { - lock_t* lock; - lock_t* next_lock; - - lock = lock_rec_get_first_on_page_addr(lock_hash, space, page_no); - - while (lock != NULL) { - ut_ad(lock_rec_find_set_bit(lock) == ULINT_UNDEFINED); - ut_ad(!lock_get_wait(lock)); - - next_lock = lock_rec_get_next_on_page(lock); + lock_t *lock= lock_sys.get_first(*lock_hash, id); - lock_rec_discard(lock); - - lock = next_lock; - } + while (lock) + { + ut_ad(lock_rec_find_set_bit(lock) == ULINT_UNDEFINED); + ut_ad(!lock_get_wait(lock)); + lock_t *next_lock= lock_rec_get_next_on_page(lock); + lock_rec_discard(lock); + lock= next_lock; + } } /*************************************************************//** @@ -2320,20 +2222,10 @@ lock_rec_free_all_from_discard_page( /*================================*/ const buf_block_t* block) /*!< in: page to be discarded */ { - ulint space; - ulint page_no; - - ut_ad(lock_mutex_own()); - - space = block->page.id().space(); - page_no = block->page.id().page_no(); - - lock_rec_free_all_from_discard_page_low( - space, page_no, &lock_sys.rec_hash); - lock_rec_free_all_from_discard_page_low( - space, page_no, &lock_sys.prdt_hash); - lock_rec_free_all_from_discard_page_low( - space, page_no, &lock_sys.prdt_page_hash); + const page_id_t page_id(block->page.id()); + lock_rec_free_all_from_discard_page_low(page_id, &lock_sys.rec_hash); + lock_rec_free_all_from_discard_page_low(page_id, &lock_sys.prdt_hash); + lock_rec_free_all_from_discard_page_low(page_id, &lock_sys.prdt_page_hash); } /*============= RECORD LOCK MOVING AND INHERITING ===================*/ @@ -2600,7 +2492,7 @@ lock_move_reorganize_page( lock_mutex_enter(); /* FIXME: This needs to deal with predicate lock too */ - lock = lock_rec_get_first_on_page(&lock_sys.rec_hash, block); + lock = lock_sys.get_first(block->page.id()); if (lock == NULL) { lock_mutex_exit(); @@ -2733,7 +2625,7 @@ lock_move_rec_list_end( table to the end of the hash chain, and lock_rec_add_to_queue does not reuse locks if there are waiters in the queue. */ - for (lock = lock_rec_get_first_on_page(&lock_sys.rec_hash, block); + for (lock = lock_sys.get_first(block->page.id()); lock; lock = lock_rec_get_next_on_page(lock)) { const rec_t* rec1 = rec; @@ -2849,7 +2741,7 @@ lock_move_rec_list_start( lock_mutex_enter(); - for (lock = lock_rec_get_first_on_page(&lock_sys.rec_hash, block); + for (lock = lock_sys.get_first(block->page.id()); lock; lock = lock_rec_get_next_on_page(lock)) { const rec_t* rec1; @@ -2962,7 +2854,7 @@ lock_rtr_move_rec_list( lock_mutex_enter(); - for (lock = lock_rec_get_first_on_page(&lock_sys.rec_hash, block); + for (lock = lock_sys.get_first(block->page.id()); lock; lock = lock_rec_get_next_on_page(lock)) { ulint moved = 0; @@ -3079,10 +2971,7 @@ lock_update_merge_right( /* there should exist no page lock on the left page, otherwise, it will be blocked from merge */ - ut_ad(!lock_rec_get_first_on_page_addr( - &lock_sys.prdt_page_hash, - left_block->page.id().space(), - left_block->page.id().page_no())); + ut_ad(!lock_sys.get_first_prdt_page(left_block->page.id())); lock_rec_free_all_from_discard_page(left_block); @@ -3201,10 +3090,7 @@ lock_update_merge_left( /* there should exist no page lock on the right page, otherwise, it will be blocked from merge */ - ut_ad(!lock_rec_get_first_on_page_addr( - &lock_sys.prdt_page_hash, - right_block->page.id().space(), - right_block->page.id().page_no())); + ut_ad(!lock_sys.get_first_prdt_page(right_block->page.id())); lock_rec_free_all_from_discard_page(right_block); @@ -3252,13 +3138,13 @@ lock_update_discard( const page_t* page = block->frame; const rec_t* rec; ulint heap_no; + const page_id_t page_id(block->page.id()); lock_mutex_enter(); - if (lock_rec_get_first_on_page(&lock_sys.rec_hash, block)) { - ut_ad(!lock_rec_get_first_on_page(&lock_sys.prdt_hash, block)); - ut_ad(!lock_rec_get_first_on_page(&lock_sys.prdt_page_hash, - block)); + if (lock_sys.get_first(page_id)) { + ut_ad(!lock_sys.get_first_prdt(page_id)); + ut_ad(!lock_sys.get_first_prdt_page(page_id)); /* Inherit all the locks on the page to the record and reset all the locks on the page */ @@ -3292,16 +3178,13 @@ lock_update_discard( } while (heap_no != PAGE_HEAP_NO_SUPREMUM); } - lock_rec_free_all_from_discard_page_low( - block->page.id().space(), block->page.id().page_no(), - &lock_sys.rec_hash); + lock_rec_free_all_from_discard_page_low(page_id, + &lock_sys.rec_hash); } else { + lock_rec_free_all_from_discard_page_low(page_id, + &lock_sys.prdt_hash); lock_rec_free_all_from_discard_page_low( - block->page.id().space(), block->page.id().page_no(), - &lock_sys.prdt_hash); - lock_rec_free_all_from_discard_page_low( - block->page.id().space(), block->page.id().page_no(), - &lock_sys.prdt_page_hash); + page_id, &lock_sys.prdt_page_hash); } lock_mutex_exit(); @@ -3506,11 +3389,8 @@ lock_table_create( ut_list_insert(table->locks, c_lock, lock, TableLockGetNode()); if (UNIV_UNLIKELY(wsrep_debug)) { - ib::info() << "table lock BF conflict for " - << ib::hex(c_lock->trx->id) - << " SQL: " - << wsrep_thd_query( - c_lock->trx->mysql_thd); + wsrep_report_bf_lock_wait(trx->mysql_thd, trx->id); + wsrep_report_bf_lock_wait(c_lock->trx->mysql_thd, c_lock->trx->id); } } else { ut_list_append(table->locks, lock, TableLockGetNode()); @@ -3522,6 +3402,8 @@ lock_table_create( c_lock->trx->lock.was_chosen_as_deadlock_victim = TRUE; if (UNIV_UNLIKELY(wsrep_debug)) { + wsrep_report_bf_lock_wait(trx->mysql_thd, trx->id); + wsrep_report_bf_lock_wait(c_lock->trx->mysql_thd, c_lock->trx->id); wsrep_print_wait_locks(c_lock); } @@ -3531,14 +3413,6 @@ lock_table_create( lock_cancel_waiting_and_release( c_lock->trx->lock.wait_lock); trx_mutex_enter(trx); - - if (UNIV_UNLIKELY(wsrep_debug)) { - ib::info() << "WSREP: c_lock canceled " - << ib::hex(c_lock->trx->id) - << " SQL: " - << wsrep_thd_query( - c_lock->trx->mysql_thd); - } } trx_mutex_exit(c_lock->trx); @@ -4073,16 +3947,10 @@ lock_grant_and_move_on_rec( ulint heap_no) { lock_t* lock; - ulint space; - ulint page_no; - ulint rec_fold; - - space = first_lock->un_member.rec_lock.space; - page_no = first_lock->un_member.rec_lock.page_no; - rec_fold = lock_rec_fold(space, page_no); - + const page_id_t page_id(first_lock->un_member.rec_lock.page_id); + const ulint rec_fold= page_id.fold(); lock_t* previous = static_cast<lock_t*>( - lock_sys.rec_hash.array[lock_sys.rec_hash.calc_hash(rec_fold)] + lock_sys.rec_hash.array[lock_sys.hash(page_id)] .node); if (previous == NULL) { return; @@ -4096,13 +3964,13 @@ lock_grant_and_move_on_rec( } lock = previous->hash; } + ut_ad(!lock->trx->is_wsrep()); /* Grant locks if there are no conflicting locks ahead. Move granted locks to the head of the list. */ for (;lock != NULL;) { /* If the lock is a wait lock on this page, and it does not need to wait. */ - if (lock->un_member.rec_lock.space == space - && lock->un_member.rec_lock.page_no == page_no + if (lock->un_member.rec_lock.page_id == page_id && lock_rec_get_nth_bit(lock, heap_no) && lock_get_wait(lock) && !lock_rec_has_to_wait_in_queue(lock)) { @@ -4195,12 +4063,18 @@ released: for (lock = first_lock; lock != NULL; lock = lock_rec_get_next(heap_no, lock)) { - if (lock_get_wait(lock) - && !lock_rec_has_to_wait_in_queue(lock)) { - + if (!lock_get_wait(lock)) { + continue; + } + const lock_t* c = lock_rec_has_to_wait_in_queue(lock); + if (!c) { /* Grant the lock */ ut_ad(trx != lock->trx); lock_grant(lock); +#ifdef WITH_WSREP + } else { + wsrep_assert_no_bf_bf_wait(c, lock, c->trx); +#endif /* WITH_WSREP */ } } } else { @@ -4404,19 +4278,15 @@ lock_table_print(FILE* file, const lock_t* lock) @param[in,out] mtr mini-transaction for accessing the record */ static void lock_rec_print(FILE* file, const lock_t* lock, mtr_t& mtr) { - ulint space; - ulint page_no; - ut_ad(lock_mutex_own()); ut_a(lock_get_type_low(lock) == LOCK_REC); - space = lock->un_member.rec_lock.space; - page_no = lock->un_member.rec_lock.page_no; + const page_id_t page_id(lock->un_member.rec_lock.page_id); - fprintf(file, "RECORD LOCKS space id %lu page no %lu n bits %lu " - "index %s of table ", - (ulong) space, (ulong) page_no, - (ulong) lock_rec_get_n_bits(lock), + fprintf(file, "RECORD LOCKS space id %u page no %u n bits " ULINTPF + " index %s of table ", + page_id.space(), page_id.page_no(), + lock_rec_get_n_bits(lock), lock->index->name()); ut_print_name(file, lock->trx, lock->index->table->name.m_name); fprintf(file, " trx id " TRX_ID_FMT, trx_get_id_for_print(lock->trx)); @@ -4453,8 +4323,7 @@ static void lock_rec_print(FILE* file, const lock_t* lock, mtr_t& mtr) rec_offs_init(offsets_); mtr.start(); - const buf_block_t* block = buf_page_try_get(page_id_t(space, page_no), - &mtr); + const buf_block_t* block = buf_page_try_get(page_id, &mtr); for (ulint i = 0; i < lock_rec_get_n_bits(lock); ++i) { @@ -4855,24 +4724,28 @@ func_exit: explicit granted lock. */ #ifdef WITH_WSREP - if (other_lock->trx->is_wsrep()) { - if (!lock_get_wait(other_lock) ) { - ib::info() << "WSREP impl BF lock conflict for my impl lock:\n BF:" << - ((wsrep_thd_is_BF(impl_trx->mysql_thd, FALSE)) ? "BF" : "normal") << " exec: " << - wsrep_thd_client_state_str(impl_trx->mysql_thd) << " conflict: " << - wsrep_thd_transaction_state_str(impl_trx->mysql_thd) << " seqno: " << - wsrep_thd_trx_seqno(impl_trx->mysql_thd) << " SQL: " << - wsrep_thd_query(impl_trx->mysql_thd); - - trx_t* otrx = other_lock->trx; - - ib::info() << "WSREP other lock:\n BF:" << - ((wsrep_thd_is_BF(otrx->mysql_thd, FALSE)) ? "BF" : "normal") << " exec: " << - wsrep_thd_client_state_str(otrx->mysql_thd) << " conflict: " << - wsrep_thd_transaction_state_str(otrx->mysql_thd) << " seqno: " << - wsrep_thd_trx_seqno(otrx->mysql_thd) << " SQL: " << - wsrep_thd_query(otrx->mysql_thd); - } + /** Galera record locking rules: + * If there is no other record lock to the same record, we may grant + the lock request. + * If there is other record lock but this requested record lock is + compatible, we may grant the lock request. + * If there is other record lock and it is not compatible with + requested lock, all normal transactions must wait. + * BF (brute force) additional exceptions : + ** If BF already holds record lock for requested record, we may + grant new record lock even if there is conflicting record lock(s) + waiting on a queue. + ** If conflicting transaction holds requested record lock, + we will cancel this record lock and select conflicting transaction + for BF abort or kill victim. + ** If conflicting transaction is waiting for requested record lock + we will cancel this wait and select conflicting transaction + for BF abort or kill victim. + ** There should not be two BF transactions waiting for same record lock + */ + if (other_lock->trx->is_wsrep() && !lock_get_wait(other_lock)) { + wsrep_report_bf_lock_wait(impl_trx->mysql_thd, impl_trx->id); + wsrep_report_bf_lock_wait(other_lock->trx->mysql_thd, other_lock->trx->id); if (!lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, block, heap_no, @@ -4881,9 +4754,11 @@ func_exit: } } else #endif /* WITH_WSREP */ - ut_ad(lock_get_wait(other_lock)); - ut_ad(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, - block, heap_no, impl_trx)); + { + ut_ad(lock_get_wait(other_lock)); + ut_ad(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, + block, heap_no, impl_trx)); + } } mutex_exit(&impl_trx->mutex); @@ -4915,13 +4790,20 @@ func_exit: mode, block, false, heap_no, lock->trx); #ifdef WITH_WSREP - ut_a(!other_lock - || wsrep_thd_is_BF(lock->trx->mysql_thd, FALSE) - || wsrep_thd_is_BF(other_lock->trx->mysql_thd, FALSE)); - -#else - ut_a(!other_lock); + if (UNIV_UNLIKELY(other_lock && lock->trx->is_wsrep())) { + /* Only BF transaction may be granted + lock before other conflicting lock + request. */ + if (!wsrep_thd_is_BF(lock->trx->mysql_thd, FALSE) + && !wsrep_thd_is_BF(other_lock->trx->mysql_thd, FALSE)) { + /* If no BF, this case is a bug. */ + wsrep_report_bf_lock_wait(lock->trx->mysql_thd, lock->trx->id); + wsrep_report_bf_lock_wait(other_lock->trx->mysql_thd, other_lock->trx->id); + ut_error; + } + } else #endif /* WITH_WSREP */ + ut_ad(!other_lock); } else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) { ut_a(lock_rec_has_to_wait_in_queue(lock)); @@ -4953,13 +4835,9 @@ lock_rec_validate_page( rec_offs* offsets = offsets_; rec_offs_init(offsets_); - ut_ad(!lock_mutex_own()); - lock_mutex_enter(); loop: - lock = lock_rec_get_first_on_page_addr( - &lock_sys.rec_hash, - block->page.id().space(), block->page.id().page_no()); + lock = lock_sys.get_first(block->page.id()); if (!lock) { goto function_exit; @@ -5031,7 +4909,7 @@ lock_rec_validate( /*==============*/ ulint start, /*!< in: lock_sys.rec_hash bucket */ - ib_uint64_t* limit) /*!< in/out: upper limit of + page_id_t* limit) /*!< in/out: upper limit of (space, page_no) */ { ut_ad(lock_mutex_own()); @@ -5041,14 +4919,10 @@ lock_rec_validate( lock != NULL; lock = static_cast<const lock_t*>(HASH_GET_NEXT(hash, lock))) { - ib_uint64_t current; - ut_ad(!trx_is_ac_nl_ro(lock->trx)); ut_ad(lock_get_type(lock) == LOCK_REC); - current = ut_ull_create( - lock->un_member.rec_lock.space, - lock->un_member.rec_lock.page_no); + page_id_t current(lock->un_member.rec_lock.page_id); if (current > *limit) { *limit = current + 1; @@ -5061,12 +4935,7 @@ lock_rec_validate( /*********************************************************************//** Validate a record lock's block */ -static -void -lock_rec_block_validate( -/*====================*/ - ulint space_id, - ulint page_no) +static void lock_rec_block_validate(const page_id_t page_id) { /* The lock and the block that it is referring to may be freed at this point. We pass BUF_GET_POSSIBLY_FREED to skip a debug check. @@ -5081,12 +4950,12 @@ lock_rec_block_validate( discard or rebuild a tablespace do hold an exclusive table lock, which would conflict with any locks referring to the tablespace from other transactions. */ - if (fil_space_t* space = fil_space_acquire(space_id)) { + if (fil_space_t* space = fil_space_acquire(page_id.space())) { dberr_t err = DB_SUCCESS; mtr_start(&mtr); block = buf_page_get_gen( - page_id_t(space_id, page_no), + page_id, space->zip_size(), RW_X_LATCH, NULL, BUF_GET_POSSIBLY_FREED, @@ -5095,8 +4964,7 @@ lock_rec_block_validate( if (err != DB_SUCCESS) { ib::error() << "Lock rec block validate failed for tablespace " << space->name - << " space_id " << space_id - << " page_no " << page_no << " err " << err; + << page_id << " err " << err; } if (block) { @@ -5140,13 +5008,7 @@ bool lock_validate() /*===========*/ { - typedef std::pair<ulint, ulint> page_addr_t; - typedef std::set< - page_addr_t, - std::less<page_addr_t>, - ut_allocator<page_addr_t> > page_addr_set; - - page_addr_set pages; + std::set<page_id_t> pages; lock_mutex_enter(); @@ -5158,24 +5020,21 @@ lock_validate() validation check. */ for (ulint i = 0; i < lock_sys.rec_hash.n_cells; i++) { - ib_uint64_t limit = 0; + page_id_t limit(0, 0); while (const lock_t* lock = lock_rec_validate(i, &limit)) { if (lock_rec_find_set_bit(lock) == ULINT_UNDEFINED) { /* The lock bitmap is empty; ignore it. */ continue; } - const lock_rec_t& l = lock->un_member.rec_lock; - pages.insert(std::make_pair(l.space, l.page_no)); + pages.insert(lock->un_member.rec_lock.page_id); } } lock_mutex_exit(); - for (page_addr_set::const_iterator it = pages.begin(); - it != pages.end(); - ++it) { - lock_rec_block_validate((*it).first, (*it).second); + for (const page_id_t page_id : pages) { + lock_rec_block_validate(page_id); } return(true); @@ -6472,10 +6331,6 @@ DeadlockChecker::get_first_lock(ulint* heap_no) const const lock_t* lock = m_wait_lock; if (lock_get_type_low(lock) == LOCK_REC) { - hash_table_t* lock_hash = lock->type_mode & LOCK_PREDICATE - ? &lock_sys.prdt_hash - : &lock_sys.rec_hash; - /* We are only interested in records that match the heap_no. */ *heap_no = lock_rec_find_set_bit(lock); @@ -6483,10 +6338,11 @@ DeadlockChecker::get_first_lock(ulint* heap_no) const ut_ad(*heap_no != ULINT_UNDEFINED); /* Find the locks on the page. */ - lock = lock_rec_get_first_on_page_addr( - lock_hash, - lock->un_member.rec_lock.space, - lock->un_member.rec_lock.page_no); + lock = lock_sys.get_first( + lock->type_mode & LOCK_PREDICATE + ? lock_sys.prdt_hash + : lock_sys.rec_hash, + lock->un_member.rec_lock.page_id); /* Position on the first lock on the physical record.*/ if (!lock_rec_get_nth_bit(lock, *heap_no)) { diff --git a/storage/innobase/lock/lock0prdt.cc b/storage/innobase/lock/lock0prdt.cc index a04fd3fe73c..1eb96a0dcf0 100644 --- a/storage/innobase/lock/lock0prdt.cc +++ b/storage/innobase/lock/lock0prdt.cc @@ -394,7 +394,8 @@ lock_prdt_find_on_page( ut_ad(lock_mutex_own()); - for (lock = lock_rec_get_first_on_page(lock_hash_get(type_mode), block); + for (lock = lock_sys.get_first(*lock_hash_get(type_mode), + block->page.id()); lock != NULL; lock = lock_rec_get_next_on_page(lock)) { @@ -457,7 +458,8 @@ lock_prdt_add_to_queue( lock_t* lock; - for (lock = lock_rec_get_first_on_page(lock_hash_get(type_mode), block); + for (lock = lock_sys.get_first(*lock_hash_get(type_mode), + block->page.id()); lock != NULL; lock = lock_rec_get_next_on_page(lock)) { @@ -619,16 +621,12 @@ lock_prdt_update_parent( buf_block_t* right_block, /*!< in/out: the new half page */ lock_prdt_t* left_prdt, /*!< in: MBR on the old page */ lock_prdt_t* right_prdt, /*!< in: MBR on the new page */ - ulint space, /*!< in: parent space id */ - ulint page_no) /*!< in: parent page number */ + const page_id_t page_id) /*!< in: parent page */ { - lock_t* lock; - lock_mutex_enter(); /* Get all locks in parent */ - for (lock = lock_rec_get_first_on_page_addr( - &lock_sys.prdt_hash, space, page_no); + for (lock_t *lock = lock_sys.get_first_prdt(page_id); lock; lock = lock_rec_get_next_on_page(lock)) { lock_prdt_t* lock_prdt; @@ -675,21 +673,15 @@ lock_prdt_update_split_low( buf_block_t* new_block, /*!< in/out: the new half page */ lock_prdt_t* prdt, /*!< in: MBR on the old page */ lock_prdt_t* new_prdt, /*!< in: MBR on the new page */ - ulint space, /*!< in: space id */ - ulint page_no, /*!< in: page number */ + const page_id_t page_id, /*!< in: page number */ unsigned type_mode) /*!< in: LOCK_PREDICATE or LOCK_PRDT_PAGE */ { lock_t* lock; - lock_mutex_enter(); - - for (lock = lock_rec_get_first_on_page_addr( - lock_hash_get(type_mode), space, page_no); + for (lock = lock_sys.get_first(*lock_hash_get(type_mode), page_id); lock; lock = lock_rec_get_next_on_page(lock)) { - ut_ad(lock); - /* First dealing with Page Lock */ if (lock->type_mode & LOCK_PRDT_PAGE) { /* Duplicate the lock to new page */ @@ -739,8 +731,6 @@ lock_prdt_update_split_low( trx_mutex_exit(lock->trx); } } - - lock_mutex_exit(); } /**************************************************************//** @@ -751,14 +741,17 @@ lock_prdt_update_split( buf_block_t* new_block, /*!< in/out: the new half page */ lock_prdt_t* prdt, /*!< in: MBR on the old page */ lock_prdt_t* new_prdt, /*!< in: MBR on the new page */ - ulint space, /*!< in: space id */ - ulint page_no) /*!< in: page number */ + const page_id_t page_id) /*!< in: page number */ { + lock_mutex_enter(); + lock_prdt_update_split_low(new_block, prdt, new_prdt, - space, page_no, LOCK_PREDICATE); + page_id, LOCK_PREDICATE); lock_prdt_update_split_low(new_block, NULL, NULL, - space, page_no, LOCK_PRDT_PAGE); + page_id, LOCK_PRDT_PAGE); + + lock_mutex_exit(); } /*********************************************************************//** @@ -814,9 +807,9 @@ lock_prdt_lock( ut_ad(!dict_index_is_online_ddl(index)); ut_ad(type_mode & (LOCK_PREDICATE | LOCK_PRDT_PAGE)); - hash_table_t* hash = type_mode == LOCK_PREDICATE - ? &lock_sys.prdt_hash - : &lock_sys.prdt_page_hash; + const hash_table_t& hash = type_mode == LOCK_PREDICATE + ? lock_sys.prdt_hash + : lock_sys.prdt_page_hash; /* Another transaction cannot have an implicit lock on the record, because when we come here, we already have modified the clustered @@ -826,7 +819,7 @@ lock_prdt_lock( lock_mutex_enter(); const unsigned prdt_mode = type_mode | mode; - lock_t* lock = lock_rec_get_first_on_page(hash, block); + lock_t* lock = lock_sys.get_first(hash, block->page.id()); if (lock == NULL) { lock = lock_rec_create( @@ -905,9 +898,7 @@ Acquire a "Page" lock on a block @return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */ dberr_t lock_place_prdt_page_lock( -/*======================*/ - ulint space, /*!< in: space for the page to lock */ - ulint page_no, /*!< in: page number */ + const page_id_t page_id, /*!< in: page identifier */ dict_index_t* index, /*!< in: secondary index */ que_thr_t* thr) /*!< in: query thread */ { @@ -924,9 +915,7 @@ lock_place_prdt_page_lock( lock_mutex_enter(); - const lock_t* lock = lock_rec_get_first_on_page_addr( - &lock_sys.prdt_page_hash, space, page_no); - + const lock_t* lock = lock_sys.get_first_prdt_page(page_id); const ulint mode = LOCK_S | LOCK_PRDT_PAGE; trx_t* trx = thr_get_trx(thr); @@ -952,7 +941,7 @@ lock_place_prdt_page_lock( #ifdef WITH_WSREP NULL, NULL, /* FIXME: replicate SPATIAL INDEX locks */ #endif - mode, space, page_no, NULL, PRDT_HEAPNO, + mode, page_id, NULL, PRDT_HEAPNO, index, trx, FALSE); #ifdef PRDT_DIAG @@ -967,25 +956,19 @@ lock_place_prdt_page_lock( /** Check whether there are R-tree Page lock on a page @param[in] trx trx to test the lock -@param[in] space space id for the page -@param[in] page_no page number +@param[in] page_id page identifier @return true if there is none */ -bool -lock_test_prdt_page_lock( - const trx_t* trx, - ulint space, - ulint page_no) +bool lock_test_prdt_page_lock(const trx_t *trx, const page_id_t page_id) { lock_t* lock; lock_mutex_enter(); - lock = lock_rec_get_first_on_page_addr( - &lock_sys.prdt_page_hash, space, page_no); + lock = lock_sys.get_first_prdt_page(page_id); lock_mutex_exit(); - return(lock == NULL || trx == lock->trx); + return(!lock || trx == lock->trx); } /*************************************************************//** @@ -1030,15 +1013,10 @@ lock_prdt_page_free_from_discard( { lock_t* lock; lock_t* next_lock; - ulint space; - ulint page_no; ut_ad(lock_mutex_own()); - space = block->page.id().space(); - page_no = block->page.id().page_no(); - - lock = lock_rec_get_first_on_page_addr(lock_hash, space, page_no); + lock = lock_sys.get_first(*lock_hash, block->page.id()); while (lock != NULL) { next_lock = lock_rec_get_next_on_page(lock); diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 46830db1323..2cb798b61fc 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -526,7 +526,7 @@ struct file_name_t { /** Tablespace file name (FILE_MODIFY) */ std::string name; /** Tablespace object (NULL if not valid or not found) */ - fil_space_t* space; + fil_space_t* space = nullptr; /** Tablespace status. */ enum fil_status { @@ -542,16 +542,19 @@ struct file_name_t { fil_status status; /** FSP_SIZE of tablespace */ - ulint size; + ulint size = 0; /** Freed pages of tablespace */ range_set freed_ranges; + /** Dummy flags before they have been read from the .ibd file */ + static constexpr uint32_t initial_flags = FSP_FLAGS_FCRC32_MASK_MARKER; + /** FSP_SPACE_FLAGS of tablespace */ + uint32_t flags = initial_flags; + /** Constructor */ file_name_t(std::string name_, bool deleted) - : name(std::move(name_)), space(NULL), - status(deleted ? DELETED: NORMAL), - size(0) {} + : name(std::move(name_)), status(deleted ? DELETED: NORMAL) {} /** Add the freed pages */ void add_freed_page(uint32_t page_no) { freed_ranges.add_value(page_no); } @@ -825,14 +828,18 @@ fil_name_process(char* name, ulint len, ulint space_id, bool deleted) case FIL_LOAD_OK: ut_ad(space != NULL); - if (f.space == NULL || f.space == space) { - - if (f.size && f.space == NULL) { - fil_space_set_recv_size(space->id, f.size); + if (!f.space) { + if (f.size + || f.flags != f.initial_flags) { + fil_space_set_recv_size_and_flags( + space->id, f.size, f.flags); } - f.name = fname.name; f.space = space; + goto same_space; + } else if (f.space == space) { +same_space: + f.name = fname.name; f.status = file_name_t::NORMAL; } else { ib::error() << "Tablespace " << space_id @@ -1218,6 +1225,8 @@ fail: } }); + DBUG_EXECUTE_IF("log_checksum_mismatch", { cksum = crc + 1; }); + if (UNIV_UNLIKELY(crc != cksum)) { ib::error() << "Invalid log block checksum." << " block: " << block_number @@ -2058,19 +2067,36 @@ same_page: { if (UNIV_UNLIKELY(rlen + last_offset > srv_page_size)) goto record_corrupted; - if (UNIV_UNLIKELY(page_no == 0) && apply && - last_offset <= FSP_HEADER_OFFSET + FSP_SIZE && - last_offset + rlen >= FSP_HEADER_OFFSET + FSP_SIZE + 4) + if (UNIV_UNLIKELY(!page_no) && apply) { - recv_spaces_t::iterator it= recv_spaces.find(space_id); - const uint32_t size= mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE - + l - last_offset); - if (it == recv_spaces.end()) - ut_ad(!mlog_checkpoint_lsn || space_id == TRX_SYS_SPACE || - srv_is_undo_tablespace(space_id)); - else if (!it->second.space) - it->second.size= size; - fil_space_set_recv_size(space_id, size); + const bool has_size= last_offset <= FSP_HEADER_OFFSET + FSP_SIZE && + last_offset + rlen >= FSP_HEADER_OFFSET + FSP_SIZE + 4; + const bool has_flags= last_offset <= + FSP_HEADER_OFFSET + FSP_SPACE_FLAGS && + last_offset + rlen >= FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + 4; + if (has_size || has_flags) + { + recv_spaces_t::iterator it= recv_spaces.find(space_id); + const uint32_t size= has_size + ? mach_read_from_4(FSP_HEADER_OFFSET + FSP_SIZE + l - + last_offset) + : 0; + const uint32_t flags= has_flags + ? mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + l - + last_offset) + : file_name_t::initial_flags; + if (it == recv_spaces.end()) + ut_ad(!mlog_checkpoint_lsn || space_id == TRX_SYS_SPACE || + srv_is_undo_tablespace(space_id)); + else if (!it->second.space) + { + if (has_size) + it->second.size= size; + if (has_flags) + it->second.flags= flags; + } + fil_space_set_recv_size_and_flags(space_id, size, flags); + } } last_offset+= rlen; break; @@ -2592,7 +2618,6 @@ inline buf_block_t *recv_sys_t::recover_low(const page_id_t page_id, ut_ad(&recs == &p->second); i.created= true; buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK); - mtr.x_latch_at_savepoint(0, block); recv_recover_page(block, mtr, p, space, &i); ut_ad(mtr.has_committed()); recs.log.clear(); diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index 94a88bd3f83..17b524f610f 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -702,6 +702,31 @@ inline lsn_t mtr_t::finish_write(ulint len) return start_lsn; } +/** Find buffer fix count of the given block acquired by the +mini-transaction */ +struct FindBlock +{ + int32_t num_fix; + const buf_block_t *const block; + + FindBlock(const buf_block_t *block_buf): num_fix(0), block(block_buf) {} + + bool operator()(const mtr_memo_slot_t* slot) + { + if (slot->object == block) + num_fix++; + return true; + } +}; + +uint32_t mtr_t::get_fix_count(const buf_block_t *block) const +{ + Iterate<FindBlock> iteration((FindBlock(block))); + if (m_memo.for_each_block(iteration)) + return iteration.functor.num_fix; + return 0; +} + #ifdef UNIV_DEBUG /** Check if we are holding an rw-latch in this mini-transaction @param lock latch to search for diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 8f0e8e99bd0..accd2417cf5 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -3633,6 +3633,7 @@ fallback: errno = err; return false; case EINVAL: + case EOPNOTSUPP: /* fall back to the code below */ break; } diff --git a/storage/innobase/os/os0proc.cc b/storage/innobase/os/os0proc.cc deleted file mode 100644 index 819e16f2302..00000000000 --- a/storage/innobase/os/os0proc.cc +++ /dev/null @@ -1,45 +0,0 @@ -/***************************************************************************** - -Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2019, 2020, MariaDB Corporation. - -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, Fifth Floor, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/**************************************************//** -@file os/os0proc.cc -The interface to the operating system -process control primitives - -Created 9/30/1995 Heikki Tuuri -*******************************************************/ - -#include "univ.i" - -/** The total amount of memory currently allocated from the operating -system with allocacte_large(). */ -Atomic_counter<ulint> os_total_large_mem_allocated; - -/** Converts the current process id to a number. -@return process id as a number */ -ulint -os_proc_get_number(void) -/*====================*/ -{ -#ifdef _WIN32 - return(static_cast<ulint>(GetCurrentProcessId())); -#else - return(static_cast<ulint>(getpid())); -#endif -} diff --git a/storage/innobase/pars/lexyy.cc b/storage/innobase/pars/lexyy.cc index ab49aab953b..e57a28ce7f1 100644 --- a/storage/innobase/pars/lexyy.cc +++ b/storage/innobase/pars/lexyy.cc @@ -816,7 +816,6 @@ Created 12/14/1997 Heikki Tuuri #include "pars0grm.h" #include "pars0sym.h" #include "mem0mem.h" -#include "os0proc.h" #define malloc(A) ut_malloc_nokey(A) #define free(A) ut_free(A) diff --git a/storage/innobase/pars/pars0lex.l b/storage/innobase/pars/pars0lex.l index 64a3dc0c461..1ddc5132da1 100644 --- a/storage/innobase/pars/pars0lex.l +++ b/storage/innobase/pars/pars0lex.l @@ -58,7 +58,6 @@ Created 12/14/1997 Heikki Tuuri #include "pars0grm.h" #include "pars0sym.h" #include "mem0mem.h" -#include "os0proc.h" #define malloc(A) ut_malloc_nokey(A) #define free(A) ut_free(A) diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index cdd12a10cf7..75a7238c1df 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -877,16 +877,15 @@ row_ins_invalidate_query_cache( @param[in] index clustered index of child table @param[in] node parent update node @param[in] foreign foreign key information -@param[out] err error code. */ +@return error code. */ static -void +dberr_t row_ins_foreign_fill_virtual( upd_node_t* cascade, const rec_t* rec, dict_index_t* index, upd_node_t* node, - dict_foreign_t* foreign, - dberr_t* err) + dict_foreign_t* foreign) { THD* thd = current_thd; row_ext_t* ext; @@ -895,10 +894,7 @@ row_ins_foreign_fill_virtual( const rec_offs* offsets = rec_get_offsets(rec, index, offsets_, true, ULINT_UNDEFINED, &cascade->heap); - mem_heap_t* v_heap = NULL; TABLE* mysql_table= NULL; - VCOL_STORAGE* vcol_storage= NULL; - byte* record; upd_t* update = cascade->update; ulint n_v_fld = index->table->n_v_def; ulint n_diff; @@ -910,20 +906,16 @@ row_ins_foreign_fill_virtual( &ext, cascade->heap); n_diff = update->n_fields; - update->n_fields += n_v_fld; - if (index->table->vc_templ == NULL) { /** This can occur when there is a cascading delete or update after restart. */ innobase_init_vc_templ(index->table); } - if (innobase_allocate_row_for_vcol(thd, index, &v_heap, - &mysql_table, - &record, &vcol_storage)) { - if (v_heap) mem_heap_free(v_heap); - *err = DB_OUT_OF_MEMORY; - goto func_exit; + ib_vcol_row vc(NULL); + uchar *record = vc.record(thd, index, &mysql_table); + if (!record) { + return DB_OUT_OF_MEMORY; } for (uint16_t i = 0; i < n_v_fld; i++) { @@ -939,15 +931,14 @@ row_ins_foreign_fill_virtual( dfield_t* vfield = innobase_get_computed_value( update->old_vrow, col, index, - &v_heap, update->heap, NULL, thd, mysql_table, + &vc.heap, update->heap, NULL, thd, mysql_table, record, NULL, NULL, NULL); if (vfield == NULL) { - *err = DB_COMPUTE_VALUE_FAILED; - goto func_exit; + return DB_COMPUTE_VALUE_FAILED; } - upd_field = upd_get_nth_field(update, n_diff); + upd_field = update->fields + n_diff; upd_field->old_v_val = static_cast<dfield_t*>( mem_heap_alloc(cascade->heap, @@ -957,42 +948,31 @@ row_ins_foreign_fill_virtual( upd_field_set_v_field_no(upd_field, i, index); - if (node->is_delete - ? (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) - : (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)) { - - dfield_set_null(&upd_field->new_val); - } - - if (!node->is_delete - && (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)) { - - dfield_t* new_vfield = innobase_get_computed_value( - update->old_vrow, col, index, - &v_heap, update->heap, NULL, thd, - mysql_table, record, NULL, - node->update, foreign); + bool set_null = + node->is_delete + ? (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) + : (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL); - if (new_vfield == NULL) { - *err = DB_COMPUTE_VALUE_FAILED; - goto func_exit; - } + dfield_t* new_vfield = innobase_get_computed_value( + update->old_vrow, col, index, + &vc.heap, update->heap, NULL, thd, + mysql_table, record, NULL, + set_null ? update : node->update, foreign); - dfield_copy(&(upd_field->new_val), new_vfield); + if (new_vfield == NULL) { + return DB_COMPUTE_VALUE_FAILED; } - n_diff++; + dfield_copy(&upd_field->new_val, new_vfield); + + if (!dfield_datas_are_binary_equal( + upd_field->old_v_val, + &upd_field->new_val, 0)) + n_diff++; } update->n_fields = n_diff; - *err = DB_SUCCESS; - -func_exit: - if (v_heap) { - if (vcol_storage) - innobase_free_row_for_vcol(vcol_storage); - mem_heap_free(v_heap); - } + return DB_SUCCESS; } #ifdef WITH_WSREP @@ -1279,9 +1259,9 @@ row_ins_foreign_check_on_constraint( if (foreign->v_cols != NULL && foreign->v_cols->size() > 0) { - row_ins_foreign_fill_virtual( + err = row_ins_foreign_fill_virtual( cascade, clust_rec, clust_index, - node, foreign, &err); + node, foreign); if (err != DB_SUCCESS) { goto nonstandard_exit_func; @@ -1317,9 +1297,9 @@ row_ins_foreign_check_on_constraint( node, foreign, tmp_heap, trx); if (foreign->v_cols && !foreign->v_cols->empty()) { - row_ins_foreign_fill_virtual( + err = row_ins_foreign_fill_virtual( cascade, clust_rec, clust_index, - node, foreign, &err); + node, foreign); if (err != DB_SUCCESS) { goto nonstandard_exit_func; @@ -1377,21 +1357,20 @@ row_ins_foreign_check_on_constraint( btr_pcur_store_position(cascade->pcur, mtr); } +#ifdef WITH_WSREP + err = wsrep_append_foreign_key(trx, foreign, clust_rec, clust_index, + FALSE, WSREP_SERVICE_KEY_EXCLUSIVE); + if (err != DB_SUCCESS) { + ib::info() << "WSREP: foreign key append failed: " << err; + goto nonstandard_exit_func; + } +#endif /* WITH_WSREP */ mtr_commit(mtr); ut_a(cascade->pcur->rel_pos == BTR_PCUR_ON); cascade->state = UPD_NODE_UPDATE_CLUSTERED; -#ifdef WITH_WSREP - err = wsrep_append_foreign_key(trx, foreign, cascade->pcur->old_rec, - clust_index, - FALSE, WSREP_SERVICE_KEY_EXCLUSIVE); - if (err != DB_SUCCESS) { - fprintf(stderr, - "WSREP: foreign key append failed: %d\n", err); - } else -#endif /* WITH_WSREP */ err = row_update_cascade_for_mysql(thr, cascade, foreign->foreign_table); @@ -1911,6 +1890,39 @@ exit_func: DBUG_RETURN(err); } +/** Sets the values of the dtuple fields in ref_entry from the values of +foreign columns in entry. +@param[in] foreign foreign key constraint +@param[in] index clustered index +@param[in] entry tuple of clustered index +@param[in] ref_entry tuple of foreign columns +@return true if all foreign key fields present in clustered index */ +static +bool row_ins_foreign_index_entry(dict_foreign_t *foreign, + const dict_index_t *index, + const dtuple_t *entry, + dtuple_t *ref_entry) +{ + for (ulint i= 0; i < foreign->n_fields; i++) + { + for (ulint j= 0; j < index->n_fields; j++) + { + const char *col_name= dict_table_get_col_name( + index->table, dict_index_get_nth_col_no(index, j)); + if (0 == innobase_strcasecmp(col_name, foreign->foreign_col_names[i])) + { + dfield_copy(&ref_entry->fields[i], &entry->fields[j]); + goto got_match; + } + } + return false; +got_match: + continue; + } + + return true; +} + /***************************************************************//** Checks if foreign key constraints fail for an index entry. If index is not mentioned in any constraint, this function does nothing, @@ -1929,9 +1941,10 @@ row_ins_check_foreign_constraints( que_thr_t* thr) /*!< in: query thread */ { dict_foreign_t* foreign; - dberr_t err; + dberr_t err = DB_SUCCESS; trx_t* trx; ibool got_s_lock = FALSE; + mem_heap_t* heap = NULL; DBUG_ASSERT(index->is_primary() == pk); @@ -1941,13 +1954,36 @@ row_ins_check_foreign_constraints( "foreign_constraint_check_for_ins"); for (dict_foreign_set::iterator it = table->foreign_set.begin(); - it != table->foreign_set.end(); + err == DB_SUCCESS && it != table->foreign_set.end(); ++it) { foreign = *it; if (foreign->foreign_index == index || (pk && !foreign->foreign_index)) { + + dtuple_t* ref_tuple = entry; + if (UNIV_UNLIKELY(!foreign->foreign_index)) { + /* Change primary key entry to + foreign key index entry */ + if (!heap) { + heap = mem_heap_create(1000); + } else { + mem_heap_empty(heap); + } + + ref_tuple = dtuple_create( + heap, foreign->n_fields); + dtuple_set_n_fields_cmp( + ref_tuple, foreign->n_fields); + if (!row_ins_foreign_index_entry( + foreign, index, entry, ref_tuple)) { + err = DB_NO_REFERENCED_ROW; + break; + } + + } + dict_table_t* ref_table = NULL; dict_table_t* referenced_table = foreign->referenced_table; @@ -1975,7 +2011,7 @@ row_ins_check_foreign_constraints( table from being dropped while the check is running. */ err = row_ins_check_foreign_constraint( - TRUE, foreign, table, entry, thr); + TRUE, foreign, table, ref_tuple, thr); if (referenced_table) { foreign->foreign_table->dec_fk_checks(); @@ -1988,15 +2024,14 @@ row_ins_check_foreign_constraints( if (ref_table != NULL) { dict_table_close(ref_table, FALSE, FALSE); } - - if (err != DB_SUCCESS) { - - return(err); - } } } - return(DB_SUCCESS); + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + + return err; } /***************************************************************//** diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 4f4329082fe..37814b70188 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -513,8 +513,7 @@ row_merge_buf_add( ulint bucket = 0; doc_id_t write_doc_id; ulint n_row_added = 0; - VCOL_STORAGE* vcol_storage= 0; - byte* record; + VCOL_STORAGE vcol_storage; DBUG_ENTER("row_merge_buf_add"); if (buf->n_tuples >= buf->max_tuples) { @@ -548,23 +547,16 @@ row_merge_buf_add( for (i = 0; i < n_fields; i++, field++, ifield++) { ulint len; - const dict_col_t* col; - ulint col_no; ulint fixed_len; const dfield_t* row_field; - - col = ifield->col; - const dict_v_col_t* v_col = NULL; - if (col->is_virtual()) { - v_col = reinterpret_cast<const dict_v_col_t*>(col); - } - - col_no = dict_col_get_no(col); + const dict_col_t* const col = ifield->col; + const dict_v_col_t* const v_col = col->is_virtual() + ? reinterpret_cast<const dict_v_col_t*>(col) + : NULL; /* Process the Doc ID column */ - if (*doc_id > 0 - && col_no == index->table->fts->doc_col - && !col->is_virtual()) { + if (!v_col && *doc_id + && col->ind == index->table->fts->doc_col) { fts_write_doc_id((byte*) &write_doc_id, *doc_id); /* Note: field->data now points to a value on the @@ -583,12 +575,15 @@ row_merge_buf_add( field->type.len = ifield->col->len; } else { /* Use callback to get the virtual column value */ - if (col->is_virtual()) { + if (v_col) { dict_index_t* clust_index = dict_table_get_first_index(new_table); - if (!vcol_storage && - innobase_allocate_row_for_vcol(trx->mysql_thd, clust_index, v_heap, &my_table, &record, &vcol_storage)) { + if (!vcol_storage.innobase_record && + !innobase_allocate_row_for_vcol( + trx->mysql_thd, clust_index, + v_heap, &my_table, + &vcol_storage)) { *err = DB_OUT_OF_MEMORY; goto error; } @@ -596,8 +591,8 @@ row_merge_buf_add( row_field = innobase_get_computed_value( row, v_col, clust_index, v_heap, NULL, ifield, trx->mysql_thd, - my_table, record, old_table, NULL, - NULL); + my_table, vcol_storage.innobase_record, + old_table, NULL, NULL); if (row_field == NULL) { *err = DB_COMPUTE_VALUE_FAILED; @@ -605,7 +600,8 @@ row_merge_buf_add( } dfield_copy(field, row_field); } else { - row_field = dtuple_get_nth_field(row, col_no); + row_field = dtuple_get_nth_field(row, + col->ind); dfield_copy(field, row_field); } @@ -712,7 +708,7 @@ row_merge_buf_add( } else if (!ext) { } else if (dict_index_is_clust(index)) { /* Flag externally stored fields. */ - const byte* buf = row_ext_lookup(ext, col_no, + const byte* buf = row_ext_lookup(ext, col->ind, &len); if (UNIV_LIKELY_NULL(buf)) { ut_a(buf != field_ref_zero); @@ -723,9 +719,9 @@ row_merge_buf_add( len = dfield_get_len(field); } } - } else if (!col->is_virtual()) { + } else if (!v_col) { /* Only non-virtual column are stored externally */ - const byte* buf = row_ext_lookup(ext, col_no, + const byte* buf = row_ext_lookup(ext, col->ind, &len); if (UNIV_LIKELY_NULL(buf)) { ut_a(buf != field_ref_zero); @@ -840,13 +836,13 @@ row_merge_buf_add( } end: - if (vcol_storage) - innobase_free_row_for_vcol(vcol_storage); + if (vcol_storage.innobase_record) + innobase_free_row_for_vcol(&vcol_storage); DBUG_RETURN(n_row_added); error: - if (vcol_storage) - innobase_free_row_for_vcol(vcol_storage); + if (vcol_storage.innobase_record) + innobase_free_row_for_vcol(&vcol_storage); DBUG_RETURN(0); } diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 42ed2aaf415..00c2c41c1d0 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -3925,9 +3925,21 @@ loop: avoid accessing dropped fts aux tables in information scheam when parent table still exists. Note: Drop parent table will drop fts aux tables. */ - char* parent_table_name; - parent_table_name = fts_get_parent_table_name( - table_name, strlen(table_name)); + char* parent_table_name = NULL; + table_id_t table_id; + index_id_t index_id; + + if (fts_check_aux_table( + table_name, &table_id, &index_id)) { + dict_table_t* parent_table = dict_table_open_on_id( + table_id, TRUE, DICT_TABLE_OP_NORMAL); + if (parent_table != NULL) { + parent_table_name = mem_strdupl( + parent_table->name.m_name, + strlen(parent_table->name.m_name)); + dict_table_close(parent_table, TRUE, FALSE); + } + } if (parent_table_name != NULL) { ut_free(table_name); diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc index aec4fa32ad7..5579e53b6c1 100644 --- a/storage/innobase/row/row0purge.cc +++ b/storage/innobase/row/row0purge.cc @@ -499,9 +499,8 @@ row_purge_remove_sec_if_poss_leaf( && btr_cur->rtr_info->thr ? thr_get_trx( btr_cur->rtr_info->thr) - : NULL, - block->page.id().space(), - block->page.id().page_no())) { + : nullptr, + block->page.id())) { /* this is the last record on page, and it has a "page" lock on it, which mean search is still depending diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 595a72eb415..239544c453e 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -156,11 +156,15 @@ fields are compared with collation! must be protected by a page s-latch @param[in] clust_index clustered index @param[in] thr query thread -@return TRUE if the secondary record is equal to the corresponding -fields in the clustered record, when compared with collation; -FALSE if not equal or if the clustered record has been marked for deletion */ +@retval DB_COMPUTE_VALUE_FAILED in case of virtual column value computation + failure. +@retval DB_SUCCESS_LOCKED_REC if the secondary record is equal to the + corresponding fields in the clustered record, when compared with + collation; +@retval DB_SUCCESS if not equal or if the clustered record has been marked + for deletion */ static -ibool +dberr_t row_sel_sec_rec_is_for_clust_rec( const rec_t* sec_rec, dict_index_t* sec_index, @@ -178,9 +182,6 @@ row_sel_sec_rec_is_for_clust_rec( rec_offs sec_offsets_[REC_OFFS_SMALL_SIZE]; rec_offs* clust_offs = clust_offsets_; rec_offs* sec_offs = sec_offsets_; - ibool is_equal = TRUE; - VCOL_STORAGE* vcol_storage= 0; - byte* record; rec_offs_init(clust_offsets_); rec_offs_init(sec_offsets_); @@ -195,10 +196,11 @@ row_sel_sec_rec_is_for_clust_rec( it is not visible in the read view. Besides, if there are any externally stored columns, some of them may have already been purged. */ - return(FALSE); + return DB_SUCCESS; } heap = mem_heap_create(256); + ib_vcol_row vc(heap); clust_offs = rec_get_offsets(clust_rec, clust_index, clust_offs, true, ULINT_UNDEFINED, &heap); @@ -227,16 +229,9 @@ row_sel_sec_rec_is_for_clust_rec( dfield_t* vfield; row_ext_t* ext; - if (!vcol_storage) - { - TABLE *mysql_table= thr->prebuilt->m_mysql_table; - innobase_allocate_row_for_vcol(thr_get_trx(thr)->mysql_thd, - clust_index, - &heap, - &mysql_table, - &record, - &vcol_storage); - } + byte *record = vc.record(thr_get_trx(thr)->mysql_thd, + clust_index, + &thr->prebuilt->m_mysql_table); v_col = reinterpret_cast<const dict_v_col_t*>(col); @@ -253,6 +248,10 @@ row_sel_sec_rec_is_for_clust_rec( thr->prebuilt->m_mysql_table, record, NULL, NULL, NULL); + if (vfield == NULL) { + innobase_report_computed_value_failed(row); + return DB_COMPUTE_VALUE_FAILED; + } clust_len = vfield->len; clust_field = static_cast<byte*>(vfield->data); } else { @@ -286,7 +285,7 @@ row_sel_sec_rec_is_for_clust_rec( sec_field, sec_len, ifield->prefix_len, clust_index->table)) { - goto inequal; + return DB_SUCCESS; } continue; @@ -321,28 +320,19 @@ row_sel_sec_rec_is_for_clust_rec( rtr_read_mbr(sec_field, &sec_mbr); if (!MBR_EQUAL_CMP(&sec_mbr, &tmp_mbr)) { - is_equal = FALSE; - goto func_exit; + return DB_SUCCESS; } } else { if (0 != cmp_data_data(col->mtype, col->prtype, clust_field, len, sec_field, sec_len)) { -inequal: - is_equal = FALSE; - goto func_exit; + return DB_SUCCESS; } } } -func_exit: - if (UNIV_LIKELY_NULL(heap)) { - if (UNIV_LIKELY_NULL(vcol_storage)) - innobase_free_row_for_vcol(vcol_storage); - mem_heap_free(heap); - } - return(is_equal); + return DB_SUCCESS_LOCKED_REC; } /*********************************************************************//** @@ -908,7 +898,7 @@ row_sel_get_clust_rec( dict_index_t* index; rec_t* clust_rec; rec_t* old_vers; - dberr_t err; + dberr_t err = DB_SUCCESS; mem_heap_t* heap = NULL; rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs* offsets = offsets_; @@ -950,7 +940,7 @@ row_sel_get_clust_rec( clustered index record did not exist in the read view of trx. */ - goto func_exit; + goto err_exit; } offsets = rec_get_offsets(clust_rec, index, offsets, true, @@ -1003,7 +993,7 @@ row_sel_get_clust_rec( clust_rec = old_vers; if (clust_rec == NULL) { - goto func_exit; + goto err_exit; } } @@ -1020,13 +1010,14 @@ row_sel_get_clust_rec( visit through secondary index records that would not really exist in our snapshot. */ - if ((old_vers - || rec_get_deleted_flag(rec, dict_table_is_comp( - plan->table))) - && !row_sel_sec_rec_is_for_clust_rec(rec, plan->index, - clust_rec, index, - thr)) { - goto func_exit; + if (old_vers || rec_get_deleted_flag(rec, dict_table_is_comp( + plan->table))) { + err = row_sel_sec_rec_is_for_clust_rec(rec, + plan->index, clust_rec, + index, thr); + if (err != DB_SUCCESS_LOCKED_REC) { + goto err_exit; + } } } @@ -1039,7 +1030,6 @@ row_sel_get_clust_rec( row_sel_fetch_columns(index, clust_rec, offsets, UT_LIST_GET_FIRST(plan->columns)); *out_rec = clust_rec; -func_exit: err = DB_SUCCESS; err_exit: if (UNIV_LIKELY_NULL(heap)) { @@ -3188,20 +3178,46 @@ row_sel_build_prev_vers_for_mysql( return(err); } -/** Helper class to cache clust_rec and old_ver */ +/** Helper class to cache clust_rec and old_vers */ class Row_sel_get_clust_rec_for_mysql { - const rec_t *cached_clust_rec; - rec_t *cached_old_vers; + const rec_t *cached_clust_rec; + rec_t *cached_old_vers; + lsn_t cached_lsn; + page_id_t cached_page_id; -public: - Row_sel_get_clust_rec_for_mysql() : - cached_clust_rec(NULL), cached_old_vers(NULL) {} +#ifdef UNIV_DEBUG + void check_eq(const dict_index_t *index, const rec_offs *offsets) const + { + rec_offs vers_offs[REC_OFFS_HEADER_SIZE + MAX_REF_PARTS]; + rec_offs_init(vers_offs); + mem_heap_t *heap= nullptr; + + ut_ad(rec_offs_validate(cached_clust_rec, index, offsets)); + ut_ad(index->first_user_field() <= rec_offs_n_fields(offsets)); + ut_ad(vers_offs == rec_get_offsets(cached_old_vers, index, vers_offs, true, + index->db_trx_id(), &heap)); + ut_ad(!heap); + for (auto n= index->db_trx_id(); n--; ) + { + const dict_col_t *col= dict_index_get_nth_col(index, n); + ulint len1, len2; + const byte *b1= rec_get_nth_field(cached_clust_rec, offsets, n, &len1); + const byte *b2= rec_get_nth_field(cached_old_vers, vers_offs, n, &len2); + ut_ad(!cmp_data_data(col->mtype, col->prtype, b1, len1, b2, len2)); + } + } +#endif - dberr_t operator()(row_prebuilt_t *prebuilt, dict_index_t *sec_index, - const rec_t *rec, que_thr_t *thr, const rec_t **out_rec, - rec_offs **offsets, mem_heap_t **offset_heap, - dtuple_t **vrow, mtr_t *mtr); +public: + Row_sel_get_clust_rec_for_mysql() : + cached_clust_rec(NULL), cached_old_vers(NULL), cached_lsn(0), + cached_page_id(page_id_t(0,0)) {} + + dberr_t operator()(row_prebuilt_t *prebuilt, dict_index_t *sec_index, + const rec_t *rec, que_thr_t *thr, const rec_t **out_rec, + rec_offs **offsets, mem_heap_t **offset_heap, + dtuple_t **vrow, mtr_t *mtr); }; /*********************************************************************//** @@ -3401,8 +3417,15 @@ Row_sel_get_clust_rec_for_mysql::operator()( && !lock_clust_rec_cons_read_sees( clust_rec, clust_index, *offsets, &trx->read_view)) { + const buf_page_t& bpage = btr_pcur_get_block( + prebuilt->clust_pcur)->page; - if (clust_rec != cached_clust_rec) { + const lsn_t lsn = mach_read_from_8( + page_align(clust_rec) + FIL_PAGE_LSN); + + if (lsn != cached_lsn + || bpage.id() != cached_page_id + || clust_rec != cached_clust_rec) { /* The following call returns 'offsets' associated with 'old_vers' */ err = row_sel_build_prev_vers_for_mysql( @@ -3414,6 +3437,8 @@ Row_sel_get_clust_rec_for_mysql::operator()( goto err_exit; } + cached_lsn = lsn; + cached_page_id = bpage.id(); cached_clust_rec = clust_rec; cached_old_vers = old_vers; } else { @@ -3424,7 +3449,8 @@ Row_sel_get_clust_rec_for_mysql::operator()( version of clust_rec and its old version old_vers. Re-calculate the offsets for old_vers. */ - if (old_vers != NULL) { + if (old_vers) { + ut_d(check_eq(clust_index, *offsets)); *offsets = rec_get_offsets( old_vers, clust_index, *offsets, true, ULINT_UNDEFINED, offset_heap); @@ -3458,10 +3484,18 @@ Row_sel_get_clust_rec_for_mysql::operator()( || trx->isolation_level <= TRX_ISO_READ_UNCOMMITTED || dict_index_is_spatial(sec_index) || rec_get_deleted_flag(rec, dict_table_is_comp( - sec_index->table))) - && !row_sel_sec_rec_is_for_clust_rec( - rec, sec_index, clust_rec, clust_index, thr)) { - clust_rec = NULL; + sec_index->table)))) { + err = row_sel_sec_rec_is_for_clust_rec(rec, sec_index, + clust_rec, clust_index, thr); + switch (err) { + case DB_SUCCESS: + clust_rec = NULL; + break; + case DB_SUCCESS_LOCKED_REC: + break; + default: + goto err_exit; + } } err = DB_SUCCESS; @@ -4091,6 +4125,10 @@ bool row_search_with_covering_prefix( const dict_index_t* index = prebuilt->index; ut_ad(!dict_index_is_clust(index)); + if (dict_index_is_spatial(index)) { + return false; + } + if (!srv_prefix_index_cluster_optimization) { return false; } @@ -4101,9 +4139,16 @@ bool row_search_with_covering_prefix( return false; } + /* We can avoid a clustered index lookup if + all of the following hold: + (1) all columns are in the secondary index + (2) all values for columns that are prefix-only + indexes are shorter than the prefix size + This optimization can avoid many IOs for certain schemas. */ for (ulint i = 0; i < prebuilt->n_template; i++) { mysql_row_templ_t* templ = prebuilt->mysql_template + i; ulint j = templ->rec_prefix_field_no; + ut_ad(!templ->mbminlen == !templ->mbmaxlen); /** Condition (1) : is the field in the index. */ if (j == ULINT_UNDEFINED) { @@ -4113,33 +4158,29 @@ bool row_search_with_covering_prefix( /** Condition (2): If this is a prefix index then row's value size shorter than prefix length. */ - if (!templ->rec_field_is_prefix) { + if (!templ->rec_field_is_prefix + || rec_offs_nth_sql_null(offsets, j)) { continue; } - ulint rec_size = rec_offs_nth_size(offsets, j); const dict_field_t* field = dict_index_get_nth_field(index, j); - ulint max_chars = field->prefix_len / templ->mbmaxlen; - - ut_a(field->prefix_len > 0); - if (rec_size < max_chars) { - /* Record in bytes shorter than the index - prefix length in char. */ + if (!field->prefix_len) { continue; } - if (rec_size * templ->mbminlen >= field->prefix_len) { + const ulint rec_size = rec_offs_nth_size(offsets, j); + + if (rec_size >= field->prefix_len) { /* Shortest representation string by the byte length of the record is longer than the maximum possible index prefix. */ return false; } - size_t num_chars = rec_field_len_in_chars( - field->col, j, rec, offsets); - - if (num_chars >= max_chars) { + if (templ->mbminlen != templ->mbmaxlen + && rec_field_len_in_chars(field->col, j, rec, offsets) + >= field->prefix_len / templ->mbmaxlen) { /* No of chars to store the record exceeds the index prefix character length. */ return false; diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 2639f3ec7ea..fa3fad5fe26 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -739,10 +739,6 @@ row_upd_build_difference_binary( for purge/mvcc purpose) */ if (n_v_fld > 0) { row_ext_t* ext; - mem_heap_t* v_heap = NULL; - byte* record; - VCOL_STORAGE* vcol_storage; - THD* thd; if (trx == NULL) { @@ -753,9 +749,8 @@ row_upd_build_difference_binary( ut_ad(!update->old_vrow); - innobase_allocate_row_for_vcol(thd, index, &v_heap, - &mysql_table, - &record, &vcol_storage); + ib_vcol_row vc(NULL); + uchar *record = vc.record(thd, index, &mysql_table); for (uint16_t i = 0; i < n_v_fld; i++) { const dict_v_col_t* col @@ -773,10 +768,9 @@ row_upd_build_difference_binary( dfield_t* vfield = innobase_get_computed_value( update->old_vrow, col, index, - &v_heap, heap, NULL, thd, mysql_table, record, + &vc.heap, heap, NULL, thd, mysql_table, record, NULL, NULL, NULL); if (vfield == NULL) { - if (v_heap) mem_heap_free(v_heap); *error = DB_COMPUTE_VALUE_FAILED; return(NULL); } @@ -797,12 +791,6 @@ row_upd_build_difference_binary( upd_field_set_v_field_no(uf, i, index); } } - - if (v_heap) { - if (vcol_storage) - innobase_free_row_for_vcol(vcol_storage); - mem_heap_free(v_heap); - } } update->n_fields = n_diff; @@ -821,7 +809,9 @@ containing also the reference to the external part @param[in,out] len input - length of prefix to fetch; output: fetched length of the prefix @param[in,out] heap heap where to allocate -@return BLOB prefix */ +@return BLOB prefix +@retval NULL if the record is incomplete (should only happen +in row_vers_vc_matches_cluster() executed concurrently with another purge) */ static byte* row_upd_ext_fetch( @@ -836,10 +826,7 @@ row_upd_ext_fetch( *len = btr_copy_externally_stored_field_prefix( buf, *len, zip_size, data, local_len); - /* We should never update records containing a half-deleted BLOB. */ - ut_a(*len); - - return(buf); + return *len ? buf : NULL; } /** Replaces the new column value stored in the update vector in @@ -850,9 +837,11 @@ the given index entry field. @param[in] uf update field @param[in,out] heap memory heap for allocating and copying the new value -@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 */ +@param[in] zip_size ROW_FORMAT=COMPRESSED page size, or 0 +@return whether the previous version was built successfully */ +MY_ATTRIBUTE((nonnull, warn_unused_result)) static -void +bool row_upd_index_replace_new_col_val( dfield_t* dfield, const dict_field_t* field, @@ -867,13 +856,13 @@ row_upd_index_replace_new_col_val( dfield_copy_data(dfield, &uf->new_val); if (dfield_is_null(dfield)) { - return; + return true; } len = dfield_get_len(dfield); data = static_cast<const byte*>(dfield_get_data(dfield)); - if (field && field->prefix_len > 0) { + if (field->prefix_len > 0) { ibool fetch_ext = dfield_is_ext(dfield) && len < (ulint) field->prefix_len + BTR_EXTERN_FIELD_REF_SIZE; @@ -885,6 +874,9 @@ row_upd_index_replace_new_col_val( data = row_upd_ext_fetch(data, l, zip_size, &len, heap); + if (UNIV_UNLIKELY(!data)) { + return false; + } } len = dtype_get_at_most_n_mbchars(col->prtype, @@ -898,7 +890,7 @@ row_upd_index_replace_new_col_val( dfield_dup(dfield, heap); } - return; + return true; } switch (uf->orig_len) { @@ -937,6 +929,8 @@ row_upd_index_replace_new_col_val( dfield_set_ext(dfield); break; } + + return true; } /** Apply an update vector to an metadata entry. @@ -983,8 +977,11 @@ row_upd_index_replace_metadata( f -= f > first; const dict_field_t* field = dict_index_get_nth_field(index, f); - row_upd_index_replace_new_col_val(dfield, field, field->col, - uf, heap, zip_size); + if (!row_upd_index_replace_new_col_val(dfield, field, + field->col, + uf, heap, zip_size)) { + ut_error; + } } ut_ad(found_mblob); @@ -1035,69 +1032,58 @@ row_upd_index_replace_new_col_vals_index_pos( update, i, false); } - if (uf) { - row_upd_index_replace_new_col_val( - dtuple_get_nth_field(entry, i), - field, col, uf, heap, zip_size); + if (uf && UNIV_UNLIKELY(!row_upd_index_replace_new_col_val( + dtuple_get_nth_field(entry, i), + field, col, uf, heap, + zip_size))) { + ut_error; } } } -/***********************************************************//** -Replaces the new column values stored in the update vector to the index entry -given. */ -void -row_upd_index_replace_new_col_vals( -/*===============================*/ - dtuple_t* entry, /*!< in/out: index entry where replaced; - the clustered index record must be - covered by a lock or a page latch to - prevent deletion (rollback or purge) */ - dict_index_t* index, /*!< in: index; NOTE that this may also be a - non-clustered index */ - const upd_t* update, /*!< in: an update vector built for the - CLUSTERED index so that the field number in - an upd_field is the clustered index position */ - mem_heap_t* heap) /*!< in: memory heap for allocating and - copying the new values */ +/** Replace the new column values stored in the update vector, +during trx_undo_prev_version_build(). +@param entry clustered index tuple where the values are replaced + (the clustered index leaf page latch must be held) +@param index clustered index +@param update update vector for the clustered index +@param heap memory heap for allocating and copying values +@return whether the previous version was built successfully */ +bool +row_upd_index_replace_new_col_vals(dtuple_t *entry, const dict_index_t &index, + const upd_t *update, mem_heap_t *heap) { - ulint i; - const dict_index_t* clust_index - = dict_table_get_first_index(index->table); - const ulint zip_size = index->table->space->zip_size(); - - ut_ad(!index->table->skip_alter_undo); + ut_ad(index.is_primary()); + const ulint zip_size= index.table->space->zip_size(); - dtuple_set_info_bits(entry, update->info_bits); + ut_ad(!index.table->skip_alter_undo); + dtuple_set_info_bits(entry, update->info_bits); - for (i = 0; i < dict_index_get_n_fields(index); i++) { - const dict_field_t* field; - const dict_col_t* col; - const upd_field_t* uf; - - field = dict_index_get_nth_field(index, i); - col = dict_field_get_col(field); - if (col->is_virtual()) { - const dict_v_col_t* vcol = reinterpret_cast< - const dict_v_col_t*>( - col); - - uf = upd_get_field_by_field_no( - update, vcol->v_pos, true); - } else { - uf = upd_get_field_by_field_no( - update, static_cast<uint16_t>( - dict_col_get_clust_pos( - col, clust_index)), - false); - } + for (ulint i= 0; i < index.n_fields; i++) + { + const dict_field_t *field= &index.fields[i]; + const dict_col_t* col= dict_field_get_col(field); + const upd_field_t *uf; + + if (col->is_virtual()) + { + const dict_v_col_t *vcol= reinterpret_cast<const dict_v_col_t*>(col); + uf= upd_get_field_by_field_no(update, vcol->v_pos, true); + } + else + uf= upd_get_field_by_field_no(update, static_cast<uint16_t> + (dict_col_get_clust_pos(col, &index)), + false); + + if (!uf) + continue; + + if (!row_upd_index_replace_new_col_val(dtuple_get_nth_field(entry, i), + field, col, uf, heap, zip_size)) + return false; + } - if (uf) { - row_upd_index_replace_new_col_val( - dtuple_get_nth_field(entry, i), - field, col, uf, heap, zip_size); - } - } + return true; } /** Replaces the virtual column values stored in the update vector. @@ -1794,23 +1780,19 @@ row_upd_eval_new_vals( @param[in,out] node row update node @param[in] update an update vector if it is update @param[in] thd mysql thread handle -@param[in,out] mysql_table mysql table object */ +@param[in,out] mysql_table mysql table object +@return true if success + false if virtual column value computation fails. */ static -void +bool row_upd_store_v_row( upd_node_t* node, const upd_t* update, THD* thd, TABLE* mysql_table) { - mem_heap_t* heap = NULL; dict_index_t* index = dict_table_get_first_index(node->table); - byte* record= 0; - VCOL_STORAGE *vcol_storage= 0; - - if (!update) - innobase_allocate_row_for_vcol(thd, index, &heap, &mysql_table, - &record, &vcol_storage); + ib_vcol_row vc(NULL); for (ulint col_no = 0; col_no < dict_table_get_n_v_cols(node->table); col_no++) { @@ -1860,33 +1842,37 @@ row_upd_store_v_row( dfield_dup(dfield, node->heap); } } else { + uchar *record = vc.record(thd, index, + &mysql_table); /* Need to compute, this happens when deleting row */ - innobase_get_computed_value( - node->row, col, index, - &heap, node->heap, NULL, - thd, mysql_table, record, NULL, - NULL, NULL); + dfield_t* vfield = + innobase_get_computed_value( + node->row, col, index, + &vc.heap, node->heap, + NULL, thd, mysql_table, + record, NULL, NULL, + NULL); + if (vfield == NULL) { + return false; + } } } } } - if (heap) { - if (vcol_storage) - innobase_free_row_for_vcol(vcol_storage); - mem_heap_free(heap); - } - + return true; } /** Stores to the heap the row on which the node->pcur is positioned. @param[in] node row update node @param[in] thd mysql thread handle @param[in,out] mysql_table NULL, or mysql table object when - user thread invokes dml */ + user thread invokes dml +@return false if virtual column value computation fails + true otherwise. */ static -void +bool row_upd_store_row( upd_node_t* node, THD* thd, @@ -1930,8 +1916,12 @@ row_upd_store_row( NULL, NULL, NULL, ext, node->heap); if (node->table->n_v_cols) { - row_upd_store_v_row(node, node->is_delete ? NULL : node->update, + bool ok = row_upd_store_v_row(node, + node->is_delete ? NULL : node->update, thd, mysql_table); + if (!ok) { + return false; + } } if (node->is_delete == PLAIN_DELETE) { @@ -1946,6 +1936,7 @@ row_upd_store_row( if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } + return true; } /***********************************************************//** @@ -2114,7 +2105,7 @@ row_upd_sec_index_entry( #ifdef UNIV_DEBUG mtr_commit(&mtr); mtr_start(&mtr); - ut_ad(btr_validate_index(index, 0)); + ut_ad(btr_validate_index(index, 0) == DB_SUCCESS); ut_ad(0); #endif /* UNIV_DEBUG */ break; @@ -2677,9 +2668,12 @@ row_upd_del_mark_clust_rec( /* Store row because we have to build also the secondary index entries */ - row_upd_store_row(node, trx->mysql_thd, + if (!row_upd_store_row(node, trx->mysql_thd, thr->prebuilt && thr->prebuilt->table == node->table - ? thr->prebuilt->m_mysql_table : NULL); + ? thr->prebuilt->m_mysql_table : NULL)) { + err = DB_COMPUTE_VALUE_FAILED; + return err; + } /* Mark the clustered index record deleted; we do not have to check locks, because we assume that we have an x-lock on the record */ @@ -2896,8 +2890,11 @@ row_upd_clust_step( goto exit_func; } - row_upd_store_row(node, trx->mysql_thd, - thr->prebuilt ? thr->prebuilt->m_mysql_table : NULL); + if(!row_upd_store_row(node, trx->mysql_thd, + thr->prebuilt ? thr->prebuilt->m_mysql_table : NULL)) { + err = DB_COMPUTE_VALUE_FAILED; + goto exit_func; + } if (row_upd_changes_ord_field_binary(index, node->update, thr, node->row, node->ext)) { diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc index eb948855032..7f410487b9a 100644 --- a/storage/innobase/row/row0vers.cc +++ b/storage/innobase/row/row0vers.cc @@ -442,52 +442,44 @@ row_vers_impl_x_locked( @param[in] index the secondary index @param[in] heap heap used to build virtual dtuple. */ static -void +bool row_vers_build_clust_v_col( dtuple_t* row, dict_index_t* clust_index, dict_index_t* index, mem_heap_t* heap) { - mem_heap_t* local_heap = NULL; - VCOL_STORAGE *vcol_storage= NULL; THD* thd= current_thd; TABLE* maria_table= 0; - byte* record= 0; ut_ad(dict_index_has_virtual(index)); ut_ad(index->table == clust_index->table); - innobase_allocate_row_for_vcol(thd, index, - &local_heap, - &maria_table, - &record, - &vcol_storage); + ib_vcol_row vc(nullptr); + byte *record = vc.record(thd, index, &maria_table); ut_ad(maria_table); for (ulint i = 0; i < dict_index_get_n_fields(index); i++) { - const dict_field_t* ind_field = dict_index_get_nth_field( - index, i); - - if (ind_field->col->is_virtual()) { - const dict_v_col_t* col; + const dict_col_t* c = dict_index_get_nth_col(index, i); - col = reinterpret_cast<const dict_v_col_t*>( - ind_field->col); + if (c->is_virtual()) { + const dict_v_col_t* col + = reinterpret_cast<const dict_v_col_t*>(c); - innobase_get_computed_value( - row, col, clust_index, &local_heap, + dfield_t *vfield = innobase_get_computed_value( + row, col, clust_index, &vc.heap, heap, NULL, thd, maria_table, record, NULL, NULL, NULL); + if (!vfield) { + innobase_report_computed_value_failed(row); + ut_ad(0); + return false; + } } } - if (local_heap) { - if (vcol_storage) - innobase_free_row_for_vcol(vcol_storage); - mem_heap_free(local_heap); - } + return true; } /** Build latest virtual column data from undo log @@ -568,9 +560,8 @@ row_vers_build_cur_vrow_low( all_filled = true; for (i = 0; i < entry_len; i++) { - const dict_field_t* ind_field - = dict_index_get_nth_field(index, i); - const dict_col_t* col = ind_field->col; + const dict_col_t* col + = dict_index_get_nth_col(index, i); if (!col->is_virtual()) { continue; @@ -816,8 +807,10 @@ row_vers_build_cur_vrow( rec, *clust_offsets, NULL, NULL, NULL, NULL, heap); - row_vers_build_clust_v_col( - row, clust_index, index, heap); + if (!row_vers_build_clust_v_col(row, clust_index, index, + heap)) { + return nullptr; + } cur_vrow = dtuple_copy(row, v_heap); dtuple_dup_v_fld(cur_vrow, v_heap); @@ -925,8 +918,10 @@ row_vers_old_has_index_entry( if (trx_undo_roll_ptr_is_insert(t_roll_ptr) || dbug_v_purge) { - row_vers_build_clust_v_col( - row, clust_index, index, heap); + if (!row_vers_build_clust_v_col( + row, clust_index, index, heap)) { + goto unsafe_to_purge; + } entry = row_build_index_entry( row, ext, index, heap); diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index ceb9245f659..14ed15a81c9 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -55,7 +55,6 @@ Created 10/8/1995 Heikki Tuuri #include "lock0lock.h" #include "log0recv.h" #include "mem0mem.h" -#include "os0proc.h" #include "pars0pars.h" #include "que0que.h" #include "row0mysql.h" @@ -763,7 +762,6 @@ static void srv_init() /* Initialize some INFORMATION SCHEMA internal structures */ trx_i_s_cache_init(trx_i_s_cache); - ut_crc32_init(); } /*********************************************************************//** diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 85fc90a8e0c..229f4879bf8 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -76,7 +76,6 @@ Created 2/16/1996 Heikki Tuuri #include "btr0defragment.h" #include "mysql/service_wsrep.h" /* wsrep_recovery */ #include "trx0rseg.h" -#include "os0proc.h" #include "buf0flu.h" #include "buf0rea.h" #include "dict0boot.h" @@ -1224,7 +1223,7 @@ dberr_t srv_start(bool create_new_db) srv_boot(); - ib::info() << ut_crc32_implementation; + ib::info() << my_crc32c_implementation(); if (!srv_read_only_mode) { @@ -1241,7 +1240,8 @@ dberr_t srv_start(bool create_new_db) sprintf(srv_monitor_file_name, "%s/innodb_status." ULINTPF, fil_path_to_mysql_datadir, - os_proc_get_number()); + static_cast<ulint> + (IF_WIN(GetCurrentProcessId(), getpid()))); srv_monitor_file = my_fopen(srv_monitor_file_name, O_RDWR|O_TRUNC|O_CREAT, diff --git a/storage/innobase/trx/trx0i_s.cc b/storage/innobase/trx/trx0i_s.cc index 2736dbd285f..82477399552 100644 --- a/storage/innobase/trx/trx0i_s.cc +++ b/storage/innobase/trx/trx0i_s.cc @@ -394,13 +394,11 @@ i_s_locks_row_validate( if (!row->lock_index) { /* table lock */ ut_ad(!row->lock_data); - ut_ad(!row->lock_space); - ut_ad(!row->lock_page); + ut_ad(row->lock_page == page_id_t(0, 0)); ut_ad(!row->lock_rec); } else { /* record lock */ /* row->lock_data == NULL if buf_page_try_get() == NULL */ - ut_ad(row->lock_page); } return(TRUE); @@ -631,9 +629,7 @@ fill_lock_data( mtr_start(&mtr); - block = buf_page_try_get(page_id_t(lock->un_member.rec_lock.space, - lock->un_member.rec_lock.page_no), - &mtr); + block = buf_page_try_get(lock->un_member.rec_lock.page_id, &mtr); if (block == NULL) { @@ -754,8 +750,7 @@ static bool fill_locks_row( return false; } - row->lock_space = lock->un_member.rec_lock.space; - row->lock_page = lock->un_member.rec_lock.page_no; + row->lock_page = lock->un_member.rec_lock.page_id; row->lock_rec = heap_no; if (!fill_lock_data(&row->lock_data, lock, heap_no, cache)) { @@ -766,8 +761,7 @@ static bool fill_locks_row( } else { row->lock_index = NULL; - row->lock_space = 0; - row->lock_page = 0; + row->lock_page = page_id_t(0, 0); row->lock_rec = 0; row->lock_data = NULL; @@ -831,13 +825,9 @@ fold_lock( switch (lock_get_type(lock)) { case LOCK_REC: ut_a(heap_no != 0xFFFF); - ret = ut_fold_ulint_pair((ulint) lock->trx->id, - lock->un_member.rec_lock.space); - - ret = ut_fold_ulint_pair(ret, - lock->un_member.rec_lock.page_no); - + lock->un_member.rec_lock.page_id. + fold()); ret = ut_fold_ulint_pair(ret, heap_no); break; @@ -880,8 +870,7 @@ locks_row_eq_lock( ut_a(heap_no != 0xFFFF); return(row->lock_trx_id == lock->trx->id - && row->lock_space == lock->un_member.rec_lock.space - && row->lock_page == lock->un_member.rec_lock.page_no + && row->lock_page == lock->un_member.rec_lock.page_id && row->lock_rec == heap_no); case LOCK_TABLE: @@ -1477,8 +1466,8 @@ trx_i_s_create_lock_id( res_len = snprintf(lock_id, lock_id_size, TRX_ID_FMT ":%u:%u:%u", - row->lock_trx_id, row->lock_space, - row->lock_page, row->lock_rec); + row->lock_trx_id, row->lock_page.space(), + row->lock_page.page_no(), row->lock_rec); } else { /* table lock */ res_len = snprintf(lock_id, lock_id_size, diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 3f1d4258484..393f044d23a 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -778,12 +778,12 @@ not_free: /* This is only executed by srv_purge_coordinator_thread. */ export_vars.innodb_undo_truncations++; - /* TODO: PUNCH_HOLE the garbage (with write-ahead logging) */ + /* In MDEV-8319 (10.5) we will PUNCH_HOLE the garbage + (with write-ahead logging). */ mutex_enter(&fil_system.mutex); ut_ad(&space == purge_sys.truncate.current); - ut_ad(space.stop_new_ops); ut_ad(space.is_being_truncated); - purge_sys.truncate.current->stop_new_ops = false; + purge_sys.truncate.current->set_stopping(false); purge_sys.truncate.current->is_being_truncated = false; mutex_exit(&fil_system.mutex); diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index 040618015d4..e4dd666a1f2 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -2364,7 +2364,11 @@ trx_undo_prev_version_build( /* The page containing the clustered index record corresponding to entry is latched in mtr. Thus the following call is safe. */ - row_upd_index_replace_new_col_vals(entry, index, update, heap); + if (!row_upd_index_replace_new_col_vals(entry, *index, update, + heap)) { + ut_a(v_status & TRX_UNDO_PREV_IN_PURGE); + return false; + } /* Get number of externally stored columns in updated record */ const ulint n_ext = index->is_primary() diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc index b90ad9b73c8..fb58687beab 100644 --- a/storage/innobase/trx/trx0rseg.cc +++ b/storage/innobase/trx/trx0rseg.cc @@ -316,7 +316,7 @@ trx_rseg_header_create( ut_ad(!sys_header == (space == fil_system.temp_space)); /* Allocate a new file segment for the rollback segment */ - block = fseg_create(space, 0, TRX_RSEG + TRX_RSEG_FSEG_HEADER, mtr); + block = fseg_create(space, TRX_RSEG + TRX_RSEG_FSEG_HEADER, mtr); if (block == NULL) { /* No space left */ diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index 7144ccff6f5..a3ada6636fd 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -158,7 +158,7 @@ trx_sysf_create( compile_time_assert(TRX_SYS_SPACE == 0); /* Create the trx sys file block in a new allocated file segment */ - block = fseg_create(fil_system.sys_space, 0, + block = fseg_create(fil_system.sys_space, TRX_SYS + TRX_SYS_FSEG_HEADER, mtr); buf_block_dbg_add_level(block, SYNC_TRX_SYS_HEADER); diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index d1f6a66f09b..074667a22f9 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -35,7 +35,6 @@ Created 3/26/1996 Heikki Tuuri #include "btr0sea.h" #include "lock0lock.h" #include "log0log.h" -#include "os0proc.h" #include "que0que.h" #include "srv0mon.h" #include "srv0srv.h" diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index 9ec219870c4..ae3224a29a6 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -383,7 +383,7 @@ trx_undo_seg_create(fil_space_t *space, buf_block_t *rseg_hdr, ulint *id, } /* Allocate a new file segment for the undo log */ - block = fseg_create(space, 0, TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER, + block = fseg_create(space, TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER, mtr, true); space->release_free_extents(n_reserved); diff --git a/storage/innobase/ut/ut0crc32.cc b/storage/innobase/ut/ut0crc32.cc deleted file mode 100644 index 1ddac168d95..00000000000 --- a/storage/innobase/ut/ut0crc32.cc +++ /dev/null @@ -1,362 +0,0 @@ -/***************************************************************************** - -Copyright (c) 2009, 2010 Facebook, Inc. All Rights Reserved. -Copyright (c) 2011, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2020, MariaDB Corporation. - -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, Fifth Floor, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/***************************************************************//** -@file ut/ut0crc32.cc -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., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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 - * extensions 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. 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@csc.com.au> 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. - */ - -// First include (the generated) my_config.h, to get correct platform defines. -#include "my_config.h" -#include <string.h> - -#include "ut0crc32.h" -#include "my_valgrind.h" - -#ifdef _MSC_VER -# include <intrin.h> -#endif - -/* CRC32 hardware implementation. */ - -#ifdef HAVE_CRC32_VPMSUM -extern "C" -unsigned int crc32c_vpmsum(unsigned int crc, const unsigned char *p, unsigned long len); -ut_crc32_func_t ut_crc32_low= crc32c_vpmsum; -const char* ut_crc32_implementation = "Using POWER8 crc32 instructions"; -#else -# if defined(__GNUC__) && defined(HAVE_ARMV8_CRC) -extern "C" { -uint32_t crc32c_aarch64(uint32_t crc, const unsigned char *buffer, uint64_t len); -}; -# elif defined(_MSC_VER) -# define TRY_SSE4_2 -# elif defined (__GNUC__) -# ifdef __x86_64__ -# define TRY_SSE4_2 -# elif defined(__i386__) && (__GNUC__ > 4 || defined __clang__) -# define TRY_SSE4_2 -# endif -# endif - -# ifdef TRY_SSE4_2 -/** return whether SSE4.2 instructions are available */ -static inline bool has_sse4_2() -{ - /* We assume that the CPUID instruction and its parameter 1 are available. - We do not support any precursors of the Intel 80486. */ -# ifdef _MSC_VER - int data[4]; - __cpuid(data, 1); - return !!(data[2] & 1 << 20); -# else - uint32_t eax, ecx; - asm("cpuid" : "=a"(eax), "=c"(ecx) : "a"(1) : "ebx", "edx"); - return !!(ecx & 1 << 20); -# endif -} - -/** Append 8 bits (1 byte) to a CRC-32C checksum. -@param crc CRC-32C checksum so far -@param data data to be checksummed -@return the updated CRC-32C */ -static inline ulint ut_crc32c_8(ulint crc, byte data) -{ -# ifdef _MSC_VER - return _mm_crc32_u8(static_cast<uint32_t>(crc), data); -# elif __has_feature(memory_sanitizer) - return __builtin_ia32_crc32qi(static_cast<uint32_t>(crc), data); -# else - asm("crc32b %1, %0" : "+r" (crc) : "rm" (data)); - return crc; -# endif -} - -/** Append 64 bits (8 aligned bytes) to a CRC-32C checksum -@param[in] crc CRC-32C checksum so far -@param[in] data 8 bytes of aligned data -@return the updated CRC-32C */ -static inline ulint ut_crc32c_64(ulint crc, uint64_t data) -{ -# ifdef _MSC_VER -# ifdef _M_X64 - return _mm_crc32_u64(crc, data); -# elif defined(_M_IX86) - crc= _mm_crc32_u32(crc, static_cast<uint32_t>(data)); - crc= _mm_crc32_u32(crc, static_cast<uint32_t>(data >> 32)); - return crc; -# else -# error Unsupported processor type -# endif -# elif __has_feature(memory_sanitizer) - return __builtin_ia32_crc32di(crc, data); -# elif defined __x86_64__ - asm("crc32q %1, %0" : "+r" (crc) : "rm" (data)); - return crc; -# else - asm("crc32l %1, %0" : "+r" (crc) : "rm" (static_cast<uint32_t>(data))); - asm("crc32l %1, %0" : "+r" (crc) : "rm" (static_cast<uint32_t>(data >> 32))); - return crc; -# endif -} - -/** Calculate CRC-32C using dedicated IA-32 or AMD64 instructions -@param crc current checksum -@param buf data to append to the checksum -@param len data length in bytes -@return CRC-32C (polynomial 0x11EDC6F41) */ -uint32_t ut_crc32_hw(uint32_t crc, const byte *buf, size_t len) -{ - ulint c= static_cast<uint32_t>(~crc); - - /* Calculate byte-by-byte up to an 8-byte aligned address. After - this consume the input 8-bytes at a time. */ - while (len > 0 && (reinterpret_cast<uintptr_t>(buf) & 7) != 0) - { - c= ut_crc32c_8(c, *buf++); - len--; - } - - const uint64_t* b64= reinterpret_cast<const uint64_t*>(buf); - - for (; len >= 128; len-= 128) - { - /* This call is repeated 16 times. 16 * 8 = 128. */ - c= ut_crc32c_64(c, *b64++); - c= ut_crc32c_64(c, *b64++); - c= ut_crc32c_64(c, *b64++); - c= ut_crc32c_64(c, *b64++); - c= ut_crc32c_64(c, *b64++); - c= ut_crc32c_64(c, *b64++); - c= ut_crc32c_64(c, *b64++); - c= ut_crc32c_64(c, *b64++); - c= ut_crc32c_64(c, *b64++); - c= ut_crc32c_64(c, *b64++); - c= ut_crc32c_64(c, *b64++); - c= ut_crc32c_64(c, *b64++); - c= ut_crc32c_64(c, *b64++); - c= ut_crc32c_64(c, *b64++); - c= ut_crc32c_64(c, *b64++); - c= ut_crc32c_64(c, *b64++); - } - - for (; len >= 8; len-= 8) - c= ut_crc32c_64(c, *b64++); - - buf= reinterpret_cast<const byte*>(b64); - - while (len--) - c= ut_crc32c_8(c, *buf++); - - return ~static_cast<uint32_t>(c); -} -# endif /* (defined(__GNUC__) && defined(__i386__)) || _MSC_VER */ - -/* CRC32 software implementation. */ - -/* Precalculated table used to generate the CRC32 if the CPU does not -have support for it */ -static uint32_t ut_crc32_slice8_table[8][256]; - -/********************************************************************//** -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 uint32_t poly = 0x82f63b78; - uint32_t n; - uint32_t k; - 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; - } - } -} - -/** Append 8 bits (1 byte) to a CRC-32C checksum. -@param crc CRC-32C checksum so far -@param data data to be checksummed -@return the updated CRC-32C */ -static inline uint32_t ut_crc32c_8_sw(uint32_t crc, byte data) -{ - const uint8_t i= (crc ^ data) & 0xFF; - - return (crc >> 8) ^ ut_crc32_slice8_table[0][i]; -} - -/** Append 64 bits (8 aligned bytes) to a CRC-32C checksum -@param[in] crc CRC-32C checksum so far -@param[in] data 8 bytes of aligned data -@return the updated CRC-32C */ -static inline uint32_t ut_crc32c_64_sw(uint32_t crc, uint64_t data) -{ -# ifdef WORDS_BIGENDIAN - data= data << 56 | - (data & 0x000000000000FF00ULL) << 40 | - (data & 0x0000000000FF0000ULL) << 24 | - (data & 0x00000000FF000000ULL) << 8 | - (data & 0x000000FF00000000ULL) >> 8 | - (data & 0x0000FF0000000000ULL) >> 24 | - (data & 0x00FF000000000000ULL) >> 40 | - data >> 56; -# endif /* WORDS_BIGENDIAN */ - - data^= crc; - return - ut_crc32_slice8_table[7][(data ) & 0xFF] ^ - ut_crc32_slice8_table[6][(data >> 8) & 0xFF] ^ - ut_crc32_slice8_table[5][(data >> 16) & 0xFF] ^ - ut_crc32_slice8_table[4][(data >> 24) & 0xFF] ^ - ut_crc32_slice8_table[3][(data >> 32) & 0xFF] ^ - ut_crc32_slice8_table[2][(data >> 40) & 0xFF] ^ - ut_crc32_slice8_table[1][(data >> 48) & 0xFF] ^ - ut_crc32_slice8_table[0][(data >> 56)]; -} - -/** Calculate CRC-32C using a look-up table. -@param crc current checksum -@param buf data to append to the checksum -@param len data length in bytes -@return CRC-32C (polynomial 0x11EDC6F41) */ -uint32_t ut_crc32_sw(uint32_t crc, const byte *buf, size_t len) -{ - crc= ~crc; - - /* Calculate byte-by-byte up to an 8-byte aligned address. After - this consume the input 8-bytes at a time. */ - while (len > 0 && (reinterpret_cast<uintptr_t>(buf) & 7) != 0) - { - crc= ut_crc32c_8_sw(crc, *buf++); - len--; - } - - const uint64_t* b64= reinterpret_cast<const uint64_t*>(buf); - - for (; len >= 8; len-= 8) - crc= ut_crc32c_64_sw(crc, *b64++); - - buf= reinterpret_cast<const byte*>(b64); - - while (len--) - crc= ut_crc32c_8_sw(crc, *buf++); - - return ~crc; -} - -ut_crc32_func_t ut_crc32_low= ut_crc32_sw; -const char *ut_crc32_implementation= "Using generic crc32 instructions"; -#endif - -/********************************************************************//** -Initializes the data structures used by ut_crc32*(). Does not do any -allocations, would not hurt if called twice, but would be pointless. */ -void ut_crc32_init() -{ -#ifndef HAVE_CRC32_VPMSUM -# if defined(__GNUC__) && defined(HAVE_ARMV8_CRC) - if (const char *crc32c_implementation= crc32c_aarch64_available()) - { - ut_crc32_low= crc32c_aarch64; - ut_crc32_implementation= crc32c_implementation; - return; - } -# elif defined(TRY_SSE4_2) - if (has_sse4_2()) - { - ut_crc32_low= ut_crc32_hw; - ut_crc32_implementation= "Using SSE4.2 crc32 instructions"; - return; - } -# endif - ut_crc32_slice8_table_init(); -#endif /* !HAVE_CRC32_VPMSUM */ -} diff --git a/storage/innobase/ut/ut0new.cc b/storage/innobase/ut/ut0new.cc index c4cf8364806..5e00a4ca0ea 100644 --- a/storage/innobase/ut/ut0new.cc +++ b/storage/innobase/ut/ut0new.cc @@ -26,6 +26,10 @@ Created May 26, 2014 Vasil Dimov #include "univ.i" #include <algorithm> +/** The total amount of memory currently allocated from the operating +system with allocate_large(). */ +Atomic_counter<ulint> os_total_large_mem_allocated; + /** Maximum number of retries to allocate memory. */ const size_t alloc_max_retries = 60; diff --git a/storage/maria/ha_s3.cc b/storage/maria/ha_s3.cc index 1aae5a5b81f..190d99035a5 100644 --- a/storage/maria/ha_s3.cc +++ b/storage/maria/ha_s3.cc @@ -80,6 +80,8 @@ static ulong s3_pagecache_file_hash_size; static ulonglong s3_pagecache_buffer_size; static char *s3_bucket, *s3_access_key=0, *s3_secret_key=0, *s3_region; static char *s3_host_name; +static int s3_port; +static my_bool s3_use_http; static char *s3_tmp_access_key=0, *s3_tmp_secret_key=0; static my_bool s3_debug= 0, s3_slave_ignore_updates= 0; static my_bool s3_replicate_alter_as_create_select= 0; @@ -181,6 +183,15 @@ static MYSQL_SYSVAR_STR(host_name, s3_host_name, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "AWS host name", 0, 0, DEFAULT_AWS_HOST_NAME); +static MYSQL_SYSVAR_INT(port, s3_port, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + "Port number to connect to (0 means use default)", + NULL /*check*/, NULL /*update*/, 0 /*default*/, + 0 /*min*/, 65535 /*max*/, 1 /*blk*/); +static MYSQL_SYSVAR_BOOL(use_http, s3_use_http, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + "If true, force use of HTTP protocol", + NULL /*check*/, NULL /*update*/, 0 /*default*/); static MYSQL_SYSVAR_STR(access_key, s3_tmp_access_key, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC, "AWS access key", @@ -276,6 +287,8 @@ static my_bool s3_info_init(S3_INFO *info) return 1; info->protocol_version= (uint8_t) s3_protocol_version; lex_string_set(&info->host_name, s3_host_name); + info->port= s3_port; + info->use_http= s3_use_http; lex_string_set(&info->access_key, s3_access_key); lex_string_set(&info->secret_key, s3_secret_key); lex_string_set(&info->region, s3_region); @@ -1050,6 +1063,8 @@ static struct st_mysql_sys_var* system_variables[]= { MYSQL_SYSVAR(pagecache_division_limit), MYSQL_SYSVAR(pagecache_file_hash_size), MYSQL_SYSVAR(host_name), + MYSQL_SYSVAR(port), + MYSQL_SYSVAR(use_http), MYSQL_SYSVAR(bucket), MYSQL_SYSVAR(access_key), MYSQL_SYSVAR(secret_key), diff --git a/storage/maria/libmarias3 b/storage/maria/libmarias3 -Subproject d172e86c16224b4e0229ca6f102e662a2315aef +Subproject 7aa450e3a02a20ef62616666a2b582f4d07fb5b diff --git a/storage/maria/ma_create.c b/storage/maria/ma_create.c index 25c44f7c90e..d64dc8308c5 100644 --- a/storage/maria/ma_create.c +++ b/storage/maria/ma_create.c @@ -319,7 +319,7 @@ int maria_create(const char *name, enum data_file_type datafile_type, { options|= HA_OPTION_TMP_TABLE; tmp_table= TRUE; - create_mode|= O_NOFOLLOW; + create_mode|= O_NOFOLLOW | (internal_table ? 0 : O_EXCL); /* "CREATE TEMPORARY" tables are not crash-safe (dropped at restart) */ ci->transactional= FALSE; flags&= ~HA_CREATE_PAGE_CHECKSUM; @@ -894,9 +894,10 @@ int maria_create(const char *name, enum data_file_type datafile_type, { char *iext= strrchr(name, '.'); int have_iext= iext && !strcmp(iext, MARIA_NAME_IEXT); - fn_format(kfilename, name, "", MARIA_NAME_IEXT, - MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH | + fn_format(kfilename, name, "", MARIA_NAME_IEXT, MY_UNPACK_FILENAME | + (internal_table ? 0 : MY_RETURN_REAL_PATH) | (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT)); + klinkname_ptr= NullS; /* Replace the current file. Don't sync dir now if the data file has the same path. @@ -1173,14 +1174,7 @@ int maria_create(const char *name, enum data_file_type datafile_type, FALSE, TRUE)) goto err; my_free(log_data); - - /* - We don't need to sync directory as we can use the log to recreate - the index and data files if needed. - */ - sync_dir= 0; } - DBUG_ASSERT(!internal_table || sync_dir == 0); if (!(flags & HA_DONT_TOUCH_DATA)) { @@ -1218,7 +1212,7 @@ int maria_create(const char *name, enum data_file_type datafile_type, if ((dfile= mysql_file_create_with_symlink(key_file_dfile, dlinkname_ptr, dfilename, 0, create_mode, - MYF(MY_WME | create_flag))) < 0) + MYF(MY_WME | create_flag | sync_dir))) < 0) goto err; errpos=3; diff --git a/storage/maria/s3_func.c b/storage/maria/s3_func.c index bbaf048d534..9f40790a371 100644 --- a/storage/maria/s3_func.c +++ b/storage/maria/s3_func.c @@ -157,6 +157,12 @@ ms3_st *s3_open_connection(S3_INFO *s3) if (s3->protocol_version) ms3_set_option(s3_client, MS3_OPT_FORCE_PROTOCOL_VERSION, &s3->protocol_version); + if (s3->port) + ms3_set_option(s3_client, MS3_OPT_PORT_NUMBER, &s3->port); + + if (s3->use_http) + ms3_set_option(s3_client, MS3_OPT_USE_HTTP, NULL); + return s3_client; } diff --git a/storage/maria/s3_func.h b/storage/maria/s3_func.h index 8981517dd4d..bd5275494bc 100644 --- a/storage/maria/s3_func.h +++ b/storage/maria/s3_func.h @@ -45,6 +45,8 @@ typedef struct s3_info { /* Connection strings */ LEX_CSTRING access_key, secret_key, region, bucket, host_name; + int port; // 0 means 'Use default' + my_bool use_http; /* Will be set by caller or by ma_open() */ LEX_CSTRING database, table; diff --git a/storage/myisam/mi_create.c b/storage/myisam/mi_create.c index 6f2825a3319..51354e0e8b5 100644 --- a/storage/myisam/mi_create.c +++ b/storage/myisam/mi_create.c @@ -185,7 +185,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, if (flags & HA_CREATE_TMP_TABLE) { options|= HA_OPTION_TMP_TABLE; - create_mode|= O_NOFOLLOW; + create_mode|= O_NOFOLLOW | (internal_table ? 0 : O_EXCL); } if (flags & HA_CREATE_CHECKSUM || (options & HA_OPTION_CHECKSUM)) { @@ -620,9 +620,10 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, { char *iext= strrchr(name, '.'); int have_iext= iext && !strcmp(iext, MI_NAME_IEXT); - fn_format(kfilename, name, "", MI_NAME_IEXT, - MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH | + fn_format(kfilename, name, "", MI_NAME_IEXT, MY_UNPACK_FILENAME | + (internal_table ? 0 : MY_RETURN_REAL_PATH) | (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT)); + klinkname_ptr= 0; /* Replace the current file */ create_flag=(flags & HA_CREATE_KEEP_FILES) ? 0 : MY_DELETE_OLD; } diff --git a/storage/perfschema/CMakeLists.txt b/storage/perfschema/CMakeLists.txt index c871677d0a9..a40e5ba6206 100644 --- a/storage/perfschema/CMakeLists.txt +++ b/storage/perfschema/CMakeLists.txt @@ -298,6 +298,16 @@ int main(int ac, char **av) }" HAVE_SYS_GETTID) +# Check for getthrid() +CHECK_C_SOURCE_COMPILES(" +#include <unistd.h> +int main(int ac, char **av) +{ + unsigned long long tid = getthrid(); + return (tid != 0 ? 0 : 1); +}" +HAVE_GETTHRID) + # Check for pthread_getthreadid_np() CHECK_C_SOURCE_COMPILES(" #include <pthread_np.h> diff --git a/storage/perfschema/my_thread.h b/storage/perfschema/my_thread.h index 12e01a510ed..b9f3f7775ff 100644 --- a/storage/perfschema/my_thread.h +++ b/storage/perfschema/my_thread.h @@ -67,6 +67,10 @@ static inline my_thread_os_id_t my_thread_os_id() /* FreeBSD 10.2 */ return pthread_getthreadid_np(); #else +#ifdef HAVE_GETTHRID + /* OpenBSD */ + return getthrid(); +#else #ifdef HAVE_INTEGER_PTHREAD_SELF /* Unknown platform, fallback. */ return pthread_self(); @@ -74,6 +78,7 @@ static inline my_thread_os_id_t my_thread_os_id() /* Feature not available. */ return 0; #endif /* HAVE_INTEGER_PTHREAD_SELF */ +#endif /* HAVE_GETTHRID */ #endif /* HAVE_PTHREAD_GETTHREADID_NP */ #endif /* _WIN32 */ #endif /* HAVE_SYS_GETTID */ diff --git a/storage/perfschema/pfs_config.h.cmake b/storage/perfschema/pfs_config.h.cmake index 0dc29da72d9..1b518fe3211 100644 --- a/storage/perfschema/pfs_config.h.cmake +++ b/storage/perfschema/pfs_config.h.cmake @@ -1,4 +1,5 @@ #cmakedefine HAVE_PTHREAD_THREADID_NP 1 #cmakedefine HAVE_SYS_GETTID 1 +#cmakedefine HAVE_GETTHRID 1 #cmakedefine HAVE_PTHREAD_GETTHREADID_NP 1 #cmakedefine HAVE_INTEGER_PTHREAD_SELF 1 diff --git a/storage/rocksdb/CMakeLists.txt b/storage/rocksdb/CMakeLists.txt index 19f0d3cfa99..c2fc8de8149 100644 --- a/storage/rocksdb/CMakeLists.txt +++ b/storage/rocksdb/CMakeLists.txt @@ -54,6 +54,9 @@ IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU") SKIP_ROCKSDB_PLUGIN("${OLD_COMPILER_MSG}") ENDIF() SET(CXX11_FLAGS "-std=c++11") + IF (GCC_VERSION VERSION_LESS 5.0) + SET(CXX11_FLAGS "-std=c++11 -Wno-missing-field-initializers") + ENDIF() ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang") IF ((CMAKE_CXX_COMPILER_VERSION AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.3) OR (CLANG_VERSION_STRING AND CLANG_VERSION_STRING VERSION_LESS 3.3)) diff --git a/strings/ctype.c b/strings/ctype.c index c9977824176..46951c3ae1f 100644 --- a/strings/ctype.c +++ b/strings/ctype.c @@ -921,7 +921,7 @@ my_string_metadata_get(MY_STRING_METADATA *metadata, /* Check repertoire: detect pure ascii strings */ -uint +my_repertoire_t my_string_repertoire(CHARSET_INFO *cs, const char *str, size_t length) { if (cs->mbminlen == 1 && !(cs->state & MY_CS_NONASCII)) @@ -948,7 +948,7 @@ my_string_repertoire(CHARSET_INFO *cs, const char *str, size_t length) /* Returns repertoire for charset */ -uint my_charset_repertoire(CHARSET_INFO *cs) +my_repertoire_t my_charset_repertoire(CHARSET_INFO *cs) { return cs->state & MY_CS_PUREASCII ? MY_REPERTOIRE_ASCII : MY_REPERTOIRE_UNICODE30; diff --git a/support-files/CMakeLists.txt b/support-files/CMakeLists.txt index 001b91a4b0c..0e5a62a9514 100644 --- a/support-files/CMakeLists.txt +++ b/support-files/CMakeLists.txt @@ -30,7 +30,7 @@ ELSE() SET(CXXFLAGS ${CMAKE_CXX_FLAGS}) SET(MYSQLD_USER "mysql") SET(ini_file_extension "cnf") - SET(HOSTNAME "hostname") + SET(HOSTNAME "uname -n") ENDIF() # XXX: shouldn't we just have variables for all this stuff and centralise diff --git a/support-files/use_galera_new_cluster.conf b/support-files/use_galera_new_cluster.conf index 4d8ad253ce5..79d191094d4 100644 --- a/support-files/use_galera_new_cluster.conf +++ b/support-files/use_galera_new_cluster.conf @@ -15,6 +15,7 @@ ConditionPathExists= Type=oneshot Restart=no +# Don't install or try to prepare for galera SST. ExecStartPre= # Override the multi instance service for a bootstrap start instance @@ -22,4 +23,5 @@ ExecStart= ExecStart=/usr/bin/echo "Please use galera_new_cluster to start the mariadb service with --wsrep-new-cluster" ExecStart=/usr/bin/false +# This isn't a service meant to execute anything but a message ExecStartPost= diff --git a/unittest/mysys/CMakeLists.txt b/unittest/mysys/CMakeLists.txt index 984b033e7aa..4b947ab780f 100644 --- a/unittest/mysys/CMakeLists.txt +++ b/unittest/mysys/CMakeLists.txt @@ -15,11 +15,11 @@ MY_ADD_TESTS(bitmap base64 my_atomic my_rdtsc lf my_malloc my_getopt dynstring byte_order - queues stacktrace LINK_LIBRARIES mysys) + queues stacktrace crc32 LINK_LIBRARIES mysys) MY_ADD_TESTS(my_vsnprintf LINK_LIBRARIES strings mysys) MY_ADD_TESTS(aes LINK_LIBRARIES mysys mysys_ssl) ADD_DEFINITIONS(${SSL_DEFINES}) - +INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR}) MY_ADD_TESTS(ma_dyncol LINK_LIBRARIES mysys) IF(WIN32) diff --git a/unittest/mysys/crc32-t.c b/unittest/mysys/crc32-t.c new file mode 100644 index 00000000000..c43be2cd586 --- /dev/null +++ b/unittest/mysys/crc32-t.c @@ -0,0 +1,69 @@ +/* Copyright (c) MariaDB 2020 + + 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 St, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_sys.h> +#include <my_crypt.h> +#include <tap.h> +#include <string.h> +#include <ctype.h> +#include <zlib.h> + +/* + Check that optimized crc32 (ieee, or ethernet polynomical) returns the same + result as zlib (not so well optimized, yet, but trustworthy) +*/ +#define DO_TEST_CRC32(crc,str) \ + ok(crc32(crc,(const Bytef *)str,(uint)(sizeof(str)-1)) == my_checksum(crc, str, sizeof(str)-1), "crc32 '%s'",str) + +/* Check that CRC32-C calculation returns correct result*/ +#define DO_TEST_CRC32C(crc,str,expected) \ + do { \ + unsigned int v = my_crc32c(crc, str, sizeof(str)-1); \ + printf("crc32(%u,'%s',%zu)=%u\n",crc,str,sizeof(str)-1,v); \ + ok(expected == my_crc32c(crc, str, sizeof(str)-1),"crc32c '%s'",str); \ + }while(0) + + +#define LONG_STR "1234567890234568900212345678901231213123321212123123123123123"\ + "............................................................................." \ + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ + "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" \ + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" + +int main(int argc __attribute__((unused)),char *argv[]) +{ + MY_INIT(argv[0]); + plan(14); + printf("%s\n",my_crc32c_implementation()); + DO_TEST_CRC32(0,""); + DO_TEST_CRC32(1,""); + DO_TEST_CRC32(0,"12345"); + DO_TEST_CRC32(1,"12345"); + DO_TEST_CRC32(0,"1234567890123456789"); + DO_TEST_CRC32(0, LONG_STR); + ok(0 == my_checksum(0, NULL, 0) , "crc32 data = NULL, length = 0"); + + DO_TEST_CRC32C(0,"", 0); + DO_TEST_CRC32C(1,"", 1); + DO_TEST_CRC32C(0, "12345", 416359221); + DO_TEST_CRC32C(1, "12345", 549473433); + DO_TEST_CRC32C(0, "1234567890123456789", 2366987449); + DO_TEST_CRC32C(0, LONG_STR, 3009234172); + ok(0 == my_crc32c(0, NULL, 0), "crc32c data = NULL, length = 0"); + + my_end(0); + return exit_status(); +} |