diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2021-09-24 15:32:39 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2021-09-24 15:32:39 +0300 |
commit | 79185bd0564794db91572c9d557b61fed143c6aa (patch) | |
tree | 1924273235f4dec40db4499d04a3e59b52a886de | |
parent | 359c286499e3d3bd82dd6b0d15f664d62f3e2f57 (diff) | |
parent | d95361107c07b6e8257a7a82c41b18af64ab8d89 (diff) | |
download | mariadb-git-79185bd0564794db91572c9d557b61fed143c6aa.tar.gz |
Merge 10.6 into 10.7
64 files changed, 1365 insertions, 987 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 64af450d29f..37899f37958 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,8 +8,7 @@ MariaDB Server has a vibrant community contributing in a wide range of areas. Th - [maria-developers mailing list](http://launchpad.net/~maria-developers) - [maria-discuss mailing list](http://launchpad.net/~maria-discuss) - [maria-docs mailing list](http://launchpad.net/~maria-docs) -- ircs://chat.freenode.net/maria ([see the IRC page on the Knowledge Base](https://mariadb.com/kb/en/meta/irc-chat-servers-and-zulip-instance/) for help with IRC). -- The MariaDB Foundation and MariaDB Corporation have a presence on Reddit, Twitter, Facebook and Google Plus. See the [social media page](https://mariadb.com/kb/en/mariadb/social-media/). +- The MariaDB Foundation and MariaDB Corporation have a presence on Reddit, Twitter and Facebook. See the [social media page](https://mariadb.com/kb/en/mariadb/social-media/). ### Help document MariaDB ---- @@ -36,7 +35,7 @@ You’re very welcome to support MariaDB Server as an individual, or talk your c ### Live QA for beginner contributors ---- -MariaDB has a dedicated time each week when we answer new contributor questions live on Zulip and IRC. +MariaDB has a dedicated time each week when we answer new contributor questions live on Zulip. From 8:00 to 10:00 UTC on Mondays, and 10:00 to 12:00 UTC on Thursdays, anyone can ask any questions they’d like, and a live developer will be available to assist. New contributors can ask questions any time, but we will provide immediate feedback during that interval. diff --git a/README.md b/README.md index f17a882d66e..58dbf105fb9 100644 --- a/README.md +++ b/README.md @@ -39,11 +39,10 @@ Help More help is available from the Maria Discuss mailing list https://launchpad.net/~maria-discuss, MariaDB's Zulip instance, https://mariadb.zulipchat.com/ -and the #maria IRC channel on Freenode. Live QA for beginner contributors ---- -MariaDB has a dedicated time each week when we answer new contributor questions live on Zulip and IRC. +MariaDB has a dedicated time each week when we answer new contributor questions live on Zulip. From 8:00 to 10:00 UTC on Mondays, and 10:00 to 12:00 UTC on Thursdays, anyone can ask any questions they’d like, and a live developer will be available to assist. diff --git a/cmake/cpack_rpm.cmake b/cmake/cpack_rpm.cmake index 5f954c7a1fe..bba9238664b 100644 --- a/cmake/cpack_rpm.cmake +++ b/cmake/cpack_rpm.cmake @@ -245,6 +245,7 @@ ELSEIF(RPM MATCHES "(rhel|centos)8") ALTERNATIVE_NAME("server" "mariadb-server-utils") ALTERNATIVE_NAME("shared" "mariadb-connector-c" ${MARIADB_CONNECTOR_C_VERSION}-1) ALTERNATIVE_NAME("shared" "mariadb-connector-c-config" ${MARIADB_CONNECTOR_C_VERSION}-1) + ALTERNATIVE_NAME("devel" "mariadb-connector-c-devel" ${MARIADB_CONNECTOR_C_VERSION}-1) SETA(CPACK_RPM_client_PACKAGE_PROVIDES "mariadb-galera = 3:%{version}-%{release}") SETA(CPACK_RPM_common_PACKAGE_PROVIDES "mariadb-galera-common = 3:%{version}-%{release}") SETA(CPACK_RPM_common_PACKAGE_REQUIRES "MariaDB-shared") @@ -257,6 +258,12 @@ ELSEIF(RPM MATCHES "sles") "mariadb-server = %{version}-%{release}" ) ENDIF() + +# MDEV-24629, we need it outside of ELSIFs +IF(RPM MATCHES "fedora3[234]") + ALTERNATIVE_NAME("common" "mariadb-connector-c-config" ${MARIADB_CONNECTOR_C_VERSION}-1) +ENDIF() + SET(PYTHON_SHEBANG "/usr/bin/python3" CACHE STRING "python shebang") # If we want to build build MariaDB-shared-compat, diff --git a/extra/mariabackup/datasink.cc b/extra/mariabackup/datasink.cc index 29bdc061014..a576526d7ff 100644 --- a/extra/mariabackup/datasink.cc +++ b/extra/mariabackup/datasink.cc @@ -23,7 +23,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA #include "common.h" #include "datasink.h" #include "ds_compress.h" -#include "ds_archive.h" #include "ds_xbstream.h" #include "ds_local.h" #include "ds_stdout.h" @@ -45,13 +44,6 @@ ds_create(const char *root, ds_type_t type) case DS_TYPE_LOCAL: ds = &datasink_local; break; - case DS_TYPE_ARCHIVE: -#ifdef HAVE_LIBARCHIVE - ds = &datasink_archive; -#else - die("mariabackup was built without libarchive support"); -#endif - break; case DS_TYPE_XBSTREAM: ds = &datasink_xbstream; break; diff --git a/extra/mariabackup/datasink.h b/extra/mariabackup/datasink.h index 5c82556b9ba..4bede4ec9e7 100644 --- a/extra/mariabackup/datasink.h +++ b/extra/mariabackup/datasink.h @@ -63,7 +63,6 @@ static inline int dummy_remove(const char *) { typedef enum { DS_TYPE_STDOUT, DS_TYPE_LOCAL, - DS_TYPE_ARCHIVE, DS_TYPE_XBSTREAM, DS_TYPE_COMPRESS, DS_TYPE_ENCRYPT, diff --git a/extra/mariabackup/ds_archive.cc b/extra/mariabackup/ds_archive.cc deleted file mode 100644 index 3a5081119b3..00000000000 --- a/extra/mariabackup/ds_archive.cc +++ /dev/null @@ -1,282 +0,0 @@ -/****************************************************** -Copyright (c) 2013 Percona LLC and/or its affiliates. - -Streaming implementation for XtraBackup. - -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 - -*******************************************************/ - -#include <my_global.h> -#include <my_base.h> -#include <archive.h> -#include <archive_entry.h> -#include "common.h" -#include "datasink.h" - -#if ARCHIVE_VERSION_NUMBER < 3000000 -#define archive_write_add_filter_none(X) archive_write_set_compression_none(X) -#define archive_write_free(X) archive_write_finish(X) -#endif - -typedef struct { - struct archive *archive; - ds_file_t *dest_file; - pthread_mutex_t mutex; -} ds_archive_ctxt_t; - -typedef struct { - struct archive_entry *entry; - ds_archive_ctxt_t *archive_ctxt; -} ds_archive_file_t; - - -/*********************************************************************** -General archive interface */ - -static ds_ctxt_t *archive_init(const char *root); -static ds_file_t *archive_open(ds_ctxt_t *ctxt, const char *path, - MY_STAT *mystat); -static int archive_write(ds_file_t *file, const void *buf, size_t len); -static int archive_close(ds_file_t *file); -static void archive_deinit(ds_ctxt_t *ctxt); - -datasink_t datasink_archive = { - &archive_init, - &archive_open, - &archive_write, - &archive_close, - &dummy_remove, - &archive_deinit -}; - -static -int -my_archive_open_callback(struct archive *a __attribute__((unused)), - void *data __attribute__((unused))) -{ - return ARCHIVE_OK; -} - -static -ssize_t -my_archive_write_callback(struct archive *a __attribute__((unused)), - void *data, const void *buffer, size_t length) -{ - ds_archive_ctxt_t *archive_ctxt; - - archive_ctxt = (ds_archive_ctxt_t *) data; - - xb_ad(archive_ctxt != NULL); - xb_ad(archive_ctxt->dest_file != NULL); - - if (!ds_write(archive_ctxt->dest_file, buffer, length)) { - return length; - } - return -1; -} - -static -int -my_archive_close_callback(struct archive *a __attribute__((unused)), - void *data __attribute__((unused))) -{ - return ARCHIVE_OK; -} - -static -ds_ctxt_t * -archive_init(const char *root __attribute__((unused))) -{ - ds_ctxt_t *ctxt; - ds_archive_ctxt_t *archive_ctxt; - struct archive *a; - - ctxt = my_malloc(sizeof(ds_ctxt_t) + sizeof(ds_archive_ctxt_t), - MYF(MY_FAE)); - archive_ctxt = (ds_archive_ctxt_t *)(ctxt + 1); - - if (pthread_mutex_init(&archive_ctxt->mutex, NULL)) { - msg("archive_init: pthread_mutex_init() failed.\n"); - goto err; - } - - a = archive_write_new(); - if (a == NULL) { - msg("archive_write_new() failed.\n"); - goto err; - } - - archive_ctxt->archive = a; - archive_ctxt->dest_file = NULL; - - if(archive_write_add_filter_none(a) != ARCHIVE_OK || - archive_write_set_format_pax_restricted(a) != ARCHIVE_OK || - /* disable internal buffering so we don't have to flush the - output in xtrabackup */ - archive_write_set_bytes_per_block(a, 0) != ARCHIVE_OK) { - msg("failed to set libarchive archive options: %s\n", - archive_error_string(a)); - archive_write_free(a); - goto err; - } - - if (archive_write_open(a, archive_ctxt, my_archive_open_callback, - my_archive_write_callback, - my_archive_close_callback) != ARCHIVE_OK) { - msg("cannot open output archive.\n"); - return NULL; - } - - ctxt->ptr = archive_ctxt; - - return ctxt; - -err: - my_free(ctxt); - return NULL; -} - -static -ds_file_t * -archive_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) -{ - ds_archive_ctxt_t *archive_ctxt; - ds_ctxt_t *dest_ctxt; - ds_file_t *file; - ds_archive_file_t *archive_file; - - struct archive *a; - struct archive_entry *entry; - - xb_ad(ctxt->pipe_ctxt != NULL); - dest_ctxt = ctxt->pipe_ctxt; - - archive_ctxt = (ds_archive_ctxt_t *) ctxt->ptr; - - pthread_mutex_lock(&archive_ctxt->mutex); - if (archive_ctxt->dest_file == NULL) { - archive_ctxt->dest_file = ds_open(dest_ctxt, path, mystat); - if (archive_ctxt->dest_file == NULL) { - return NULL; - } - } - pthread_mutex_unlock(&archive_ctxt->mutex); - - file = (ds_file_t *) my_malloc(sizeof(ds_file_t) + - sizeof(ds_archive_file_t), - MYF(MY_FAE)); - - archive_file = (ds_archive_file_t *) (file + 1); - - a = archive_ctxt->archive; - - entry = archive_entry_new(); - if (entry == NULL) { - msg("archive_entry_new() failed.\n"); - goto err; - } - - archive_entry_set_size(entry, mystat->st_size); - archive_entry_set_mode(entry, 0660); - archive_entry_set_filetype(entry, AE_IFREG); - archive_entry_set_pathname(entry, path); - archive_entry_set_mtime(entry, mystat->st_mtime, 0); - - archive_file->entry = entry; - archive_file->archive_ctxt = archive_ctxt; - - if (archive_write_header(a, entry) != ARCHIVE_OK) { - msg("archive_write_header() failed.\n"); - archive_entry_free(entry); - goto err; - } - - file->ptr = archive_file; - file->path = archive_ctxt->dest_file->path; - - return file; - -err: - if (archive_ctxt->dest_file) { - ds_close(archive_ctxt->dest_file); - archive_ctxt->dest_file = NULL; - } - my_free(file); - - return NULL; -} - -static -int -archive_write(ds_file_t *file, const void *buf, size_t len) -{ - ds_archive_file_t *archive_file; - struct archive *a; - - archive_file = (ds_archive_file_t *) file->ptr; - - a = archive_file->archive_ctxt->archive; - - xb_ad(archive_file->archive_ctxt->dest_file != NULL); - if (archive_write_data(a, buf, len) < 0) { - msg("archive_write_data() failed: %s (errno = %d)\n", - archive_error_string(a), archive_errno(a)); - return 1; - } - - return 0; -} - -static -int -archive_close(ds_file_t *file) -{ - ds_archive_file_t *archive_file; - int rc = 0; - - archive_file = (ds_archive_file_t *)file->ptr; - - archive_entry_free(archive_file->entry); - - my_free(file); - - return rc; -} - -static -void -archive_deinit(ds_ctxt_t *ctxt) -{ - struct archive *a; - ds_archive_ctxt_t *archive_ctxt; - - archive_ctxt = (ds_archive_ctxt_t *) ctxt->ptr; - - a = archive_ctxt->archive; - - if (archive_write_close(a) != ARCHIVE_OK) { - msg("archive_write_close() failed.\n"); - } - archive_write_free(a); - - if (archive_ctxt->dest_file) { - ds_close(archive_ctxt->dest_file); - archive_ctxt->dest_file = NULL; - } - - pthread_mutex_destroy(&archive_ctxt->mutex); - - my_free(ctxt); -} diff --git a/extra/mariabackup/ds_archive.h b/extra/mariabackup/ds_archive.h deleted file mode 100644 index f419fca0c9f..00000000000 --- a/extra/mariabackup/ds_archive.h +++ /dev/null @@ -1,28 +0,0 @@ -/****************************************************** -Copyright (c) 2013 Percona LLC and/or its affiliates. - -Streaming interface for XtraBackup. - -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 - -*******************************************************/ - -#ifndef DS_ARCHIVE_H -#define DS_ARCHIVE_H - -#include "datasink.h" - -extern datasink_t datasink_archive; - -#endif diff --git a/extra/mariabackup/ds_xbstream.cc b/extra/mariabackup/ds_xbstream.cc index 4d165ad11d9..3bf8bd086c2 100644 --- a/extra/mariabackup/ds_xbstream.cc +++ b/extra/mariabackup/ds_xbstream.cc @@ -126,14 +126,20 @@ xbstream_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) pthread_mutex_lock(&stream_ctxt->mutex); if (stream_ctxt->dest_file == NULL) { stream_ctxt->dest_file = ds_open(dest_ctxt, path, mystat); - if (stream_ctxt->dest_file == NULL) { - return NULL; - } } pthread_mutex_unlock(&stream_ctxt->mutex); + if (stream_ctxt->dest_file == NULL) { + return NULL; + } file = (ds_file_t *) my_malloc(PSI_NOT_INSTRUMENTED, - sizeof(ds_file_t) + sizeof(ds_stream_file_t), MYF(MY_FAE)); + sizeof(ds_file_t) + + sizeof(ds_stream_file_t), + MYF(MY_FAE)); + if (!file) { + msg("my_malloc() failed."); + goto err; + } stream_file = (ds_stream_file_t *) (file + 1); xbstream = stream_ctxt->xbstream; diff --git a/libmariadb b/libmariadb -Subproject 2ca0c22fd36c1b34115352e22c5f6b7d23c2c04 +Subproject ffa3451fa511ad27164356bd8c620032eba6551 diff --git a/libmysqld/libmysql.c b/libmysqld/libmysql.c index 7a0843d32e5..6c7e0b3b812 100644 --- a/libmysqld/libmysql.c +++ b/libmysqld/libmysql.c @@ -3966,6 +3966,7 @@ static my_bool is_binary_compatible(enum enum_field_types type1, static my_bool setup_one_fetch_function(MYSQL_BIND *param, MYSQL_FIELD *field) { + my_bool field_is_unsigned; DBUG_ENTER("setup_one_fetch_function"); /* Setup data copy functions for the different supported types */ @@ -4042,6 +4043,7 @@ static my_bool setup_one_fetch_function(MYSQL_BIND *param, MYSQL_FIELD *field) /* Setup skip_result functions (to calculate max_length) */ param->skip_result= skip_result_fixed; + field_is_unsigned= MY_TEST(field->flags & UNSIGNED_FLAG); switch (field->type) { case MYSQL_TYPE_NULL: /* for dummy binds */ param->pack_length= 0; @@ -4049,23 +4051,23 @@ static my_bool setup_one_fetch_function(MYSQL_BIND *param, MYSQL_FIELD *field) break; case MYSQL_TYPE_TINY: param->pack_length= 1; - field->max_length= 4; /* as in '-127' */ + field->max_length= field_is_unsigned ? 3 : 4; /* '255' and '-127' */ break; case MYSQL_TYPE_YEAR: case MYSQL_TYPE_SHORT: param->pack_length= 2; - field->max_length= 6; /* as in '-32767' */ + field->max_length= field_is_unsigned ? 5 : 6; /* 65536 and '-32767' */ break; case MYSQL_TYPE_INT24: - field->max_length= 9; /* as in '16777216' or in '-8388607' */ + field->max_length= 8; /* '16777216' or in '-8388607' */ param->pack_length= 4; break; case MYSQL_TYPE_LONG: - field->max_length= 11; /* '-2147483647' */ + field->max_length= field_is_unsigned ? 10 : 11; /* '4294967295' and '-2147483647' */ param->pack_length= 4; break; case MYSQL_TYPE_LONGLONG: - field->max_length= 21; /* '18446744073709551616' */ + field->max_length= 20; /* '18446744073709551616' or -9223372036854775808 */ param->pack_length= 8; break; case MYSQL_TYPE_FLOAT: diff --git a/man/mysqldump.1 b/man/mysqldump.1 index e3206e612f7..ad4b167c7b8 100644 --- a/man/mysqldump.1 +++ b/man/mysqldump.1 @@ -2279,7 +2279,7 @@ servers \- remote (federated) servers as \fBCREATE SERVER\fR\&. .sp -1 .IP \(bu 2.3 .\} -stats \- statistics tables, InnoDB and Engine Independent Table Statistics (EITS), are dumped as \fBREPLACE INTO\fR (or \fBINSERT IGNORE\fR if \fB\-\-insert\-into\fR is specified) statements without (re)creating tables\&. +stats \- statistics tables, InnoDB and Engine Independent Table Statistics (EITS), are dumped as \fBREPLACE INTO\fR (or \fBINSERT IGNORE\fR if \fB\-\-insert\-ignore\fR is specified) statements without (re)creating tables\&. .RE .RS 4 .ie n \{\ @@ -2289,17 +2289,17 @@ stats \- statistics tables, InnoDB and Engine Independent Table Statistics (EITS .sp -1 .IP \(bu 2.3 .\} -timezones \- timezone related system tables dumped as \fBREPLACE INTO\fR (or \fBINSERT IGNORE\fR if \fB\-\-insert\-into\fR is specified) statements without (re)creating tables\&. +timezones \- timezone related system tables dumped as \fBREPLACE INTO\fR (or \fBINSERT IGNORE\fR if \fB\-\-insert\-ignore\fR is specified) statements without (re)creating tables\&. .RE .sp -The format of the output is affected by \fB\-\-replace\fR and \fB\-\-insert\-into\fR\&. The \fB\-\-replace\fR option will output \fBCREATE OR REPLACE\fR +The format of the output is affected by \fB\-\-replace\fR and \fB\-\-insert\-ignore\fR\&. The \fB\-\-replace\fR option will output \fBCREATE OR REPLACE\fR forms of SQL, and also \fBDROP IF EXISTS\fR prior to \fBCREATE\fR, if a \fBCREATE OR REPLACE\fR option isn't available. .sp With \fB\-\-system=user\fR (or \fBall\fR), and \fB\-\-replace\fR, SQL is generated to generate an error if attempting to import the dump with a connection user that is being replaced within the dump\&. .sp -The \fB\-\-insert\-into\fR option will cause \fBCREATE IF NOT EXIST\fR forms of SQL to generated if available. +The \fB\-\-insert\-ignore\fR option will cause \fBCREATE IF NOT EXIST\fR forms of SQL to generated if available. .sp -For stats, and timezones, \fB\-\-replace\fR and \fB\-\-insert\-into\fR have the usual effects. +For stats, and timezones, \fB\-\-replace\fR and \fB\-\-insert\-ignore\fR have the usual effects. .sp Enabling specific options here will cause the relevant tables in the mysql database to be ignored when dumping the mysql database or \fB\-\-all\-databases\fR\&. .sp diff --git a/mysql-test/main/alias.result b/mysql-test/main/alias.result index 0d14607f613..266991afbec 100644 --- a/mysql-test/main/alias.result +++ b/mysql-test/main/alias.result @@ -223,16 +223,16 @@ disconnect c1; # create or replace table t1 (a int); create or replace table t2 (b int); -insert into t1 values(1<<30),(1<<29); +insert into t1 values(111111111),(-2147483648); insert into t2 values(1),(2); select t1.a as a1 from t1 as t1,t2 order by t2.b,t1.a; Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr -def test t1 t1 a a1 3 11 10 Y 32768 0 63 +def test t1 t1 a a1 3 11 11 Y 32768 0 63 a1 -536870912 -1073741824 -536870912 -1073741824 +-2147483648 +111111111 +-2147483648 +111111111 drop table t1,t2; # # End of 10.4 tests diff --git a/mysql-test/main/alias.test b/mysql-test/main/alias.test index 2408509ba10..881cc34d6c6 100644 --- a/mysql-test/main/alias.test +++ b/mysql-test/main/alias.test @@ -231,7 +231,7 @@ disconnect c1; --echo # create or replace table t1 (a int); create or replace table t2 (b int); -insert into t1 values(1<<30),(1<<29); +insert into t1 values(111111111),(-2147483648); insert into t2 values(1),(2); --enable_metadata select t1.a as a1 from t1 as t1,t2 order by t2.b,t1.a; diff --git a/mysql-test/main/mdev-504.result b/mysql-test/main/mdev-504.result deleted file mode 100644 index e34e57be6ed..00000000000 --- a/mysql-test/main/mdev-504.result +++ /dev/null @@ -1,25 +0,0 @@ -set @save_use_stat_tables=@@global.use_stat_tables; -SET GLOBAL net_write_timeout = 900; -CREATE TABLE A ( -pk INTEGER AUTO_INCREMENT PRIMARY KEY, -fdate DATE -) ENGINE=MyISAM; -CREATE PROCEDURE p_analyze() -BEGIN -DECLARE attempts INTEGER DEFAULT 100; -wl_loop: WHILE attempts > 0 DO -ANALYZE TABLE A; -SET attempts = attempts - 1; -END WHILE wl_loop; -END | -CREATE FUNCTION rnd3() RETURNS INT -BEGIN -RETURN ROUND(3 * RAND() + 0.5); -END | -SET GLOBAL use_stat_tables = PREFERABLY; -connection default; -DROP TABLE A; -DROP PROCEDURE p_analyze; -DROP FUNCTION rnd3; -SET GLOBAL use_stat_tables = @save_use_stat_tables; -SET GLOBAL net_write_timeout = DEFAULT; diff --git a/mysql-test/main/mdev-504.test b/mysql-test/main/mdev-504.test deleted file mode 100644 index 277b5a038a0..00000000000 --- a/mysql-test/main/mdev-504.test +++ /dev/null @@ -1,82 +0,0 @@ ---source include/not_valgrind.inc ---source include/no_protocol.inc - -set @save_use_stat_tables=@@global.use_stat_tables; - -SET GLOBAL net_write_timeout = 900; - -CREATE TABLE A ( - pk INTEGER AUTO_INCREMENT PRIMARY KEY, - fdate DATE -) ENGINE=MyISAM; - ---delimiter | - -CREATE PROCEDURE p_analyze() -BEGIN - DECLARE attempts INTEGER DEFAULT 100; - wl_loop: WHILE attempts > 0 DO - ANALYZE TABLE A; - SET attempts = attempts - 1; - END WHILE wl_loop; -END | - -CREATE FUNCTION rnd3() RETURNS INT -BEGIN - RETURN ROUND(3 * RAND() + 0.5); -END | - ---delimiter ; - -SET GLOBAL use_stat_tables = PREFERABLY; - ---let $trial = 100 - ---disable_query_log ---disable_result_log ---disable_warnings -while ($trial) -{ - - --connect (con1,localhost,root,,) - --send CALL p_analyze() - - --connect (con2,localhost,root,,) - --send CALL p_analyze() - - --let $run = 100 - - while ($run) - { - --connect (con3,localhost,root,,) - - let $query = `SELECT CASE rnd3() - WHEN 1 THEN 'INSERT INTO A (pk) VALUES (NULL)' - WHEN 2 THEN 'DELETE FROM A LIMIT 1' - ELSE 'UPDATE IGNORE A SET fdate = 2 LIMIT 1' END`; - --eval $query - --disconnect con3 - --dec $run - } - - --connection con2 - --reap - --disconnect con2 - --connection con1 - --reap - --disconnect con1 - - --dec $trial -} - ---enable_query_log ---enable_result_log ---enable_warnings - -# Cleanup ---connection default -DROP TABLE A; -DROP PROCEDURE p_analyze; -DROP FUNCTION rnd3; -SET GLOBAL use_stat_tables = @save_use_stat_tables; -SET GLOBAL net_write_timeout = DEFAULT; diff --git a/mysql-test/suite/encryption/r/innodb_encryption.result b/mysql-test/suite/encryption/r/innodb_encryption.result index 4ede82ebd38..3b1552be4be 100644 --- a/mysql-test/suite/encryption/r/innodb_encryption.result +++ b/mysql-test/suite/encryption/r/innodb_encryption.result @@ -19,7 +19,7 @@ innodb_system # Success! # Now turn off encryption and wait for threads to decrypt everything SET GLOBAL innodb_encrypt_tables = off; -# Wait max 10 min for key encryption threads to encrypt all spaces +# Wait max 10 min for key encryption threads to decrypt all spaces SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NAME NOT LIKE 'mysql/transaction_registry'; NAME diff --git a/mysql-test/suite/encryption/t/innodb_encryption.test b/mysql-test/suite/encryption/t/innodb_encryption.test index 1c8d200458a..2b0b2b8d7fb 100644 --- a/mysql-test/suite/encryption/t/innodb_encryption.test +++ b/mysql-test/suite/encryption/t/innodb_encryption.test @@ -33,7 +33,7 @@ AND NAME NOT LIKE 'innodb_undo%' AND NAME NOT LIKE 'mysql/innodb_%_stats' AND NA --echo # Now turn off encryption and wait for threads to decrypt everything SET GLOBAL innodb_encrypt_tables = off; ---echo # Wait max 10 min for key encryption threads to encrypt all spaces +--echo # Wait max 10 min for key encryption threads to decrypt all spaces --let $wait_timeout= 600 --let $wait_condition=SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; --source include/wait_condition.inc diff --git a/mysql-test/suite/galera/r/galera_schema.result b/mysql-test/suite/galera/r/galera_schema.result new file mode 100644 index 00000000000..24a4099c94d --- /dev/null +++ b/mysql-test/suite/galera/r/galera_schema.result @@ -0,0 +1,114 @@ +connection node_2; +connection node_1; +CREATE TABLE IF NOT EXISTS wsrep_cluster +( +cluster_uuid CHAR(36) PRIMARY KEY, +view_id BIGINT NOT NULL, +view_seqno BIGINT NOT NULL, +protocol_version INT NOT NULL, +capabilities INT NOT NULL +) ENGINE=InnoDB; +CREATE TABLE IF NOT EXISTS wsrep_cluster_members +( +node_uuid CHAR(36) PRIMARY KEY, +cluster_uuid CHAR(36) NOT NULL, +node_name CHAR(32) NOT NULL, +node_incoming_address VARCHAR(256) NOT NULL +) ENGINE=InnoDB; +CREATE TABLE IF NOT EXISTS wsrep_cluster_members_history +( +node_uuid CHAR(36) PRIMARY KEY, +cluster_uuid CHAR(36) NOT NULL, +last_view_id BIGINT NOT NULL, +last_view_seqno BIGINT NOT NULL, +node_name CHAR(32) NOT NULL, +node_incoming_address VARCHAR(256) NOT NULL +) ENGINE=InnoDB; +CREATE TABLE IF NOT EXISTS wsrep_streaming_log +( +node_uuid CHAR(36), +trx_id BIGINT, +seqno BIGINT, +flags INT NOT NULL, +frag LONGBLOB NOT NULL, +PRIMARY KEY (node_uuid, trx_id, seqno) +) ENGINE=InnoDB; +DELETE FROM wsrep_cluster; +DELETE FROM wsrep_cluster_members; +ALTER TABLE wsrep_cluster STATS_PERSISTENT=0; +ALTER TABLE wsrep_cluster_members STATS_PERSISTENT=0; +ALTER TABLE wsrep_cluster_members_history STATS_PERSISTENT=0; +ALTER TABLE wsrep_streaming_log STATS_PERSISTENT=0; +SHOW CREATE TABLE wsrep_cluster; +Table Create Table +wsrep_cluster CREATE TABLE `wsrep_cluster` ( + `cluster_uuid` char(36) NOT NULL, + `view_id` bigint(20) NOT NULL, + `view_seqno` bigint(20) NOT NULL, + `protocol_version` int(11) NOT NULL, + `capabilities` int(11) NOT NULL, + PRIMARY KEY (`cluster_uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 STATS_PERSISTENT=0 +SHOW CREATE TABLE wsrep_cluster_members; +Table Create Table +wsrep_cluster_members CREATE TABLE `wsrep_cluster_members` ( + `node_uuid` char(36) NOT NULL, + `cluster_uuid` char(36) NOT NULL, + `node_name` char(32) NOT NULL, + `node_incoming_address` varchar(256) NOT NULL, + PRIMARY KEY (`node_uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 STATS_PERSISTENT=0 +SHOW CREATE TABLE wsrep_cluster_members_history; +Table Create Table +wsrep_cluster_members_history CREATE TABLE `wsrep_cluster_members_history` ( + `node_uuid` char(36) NOT NULL, + `cluster_uuid` char(36) NOT NULL, + `last_view_id` bigint(20) NOT NULL, + `last_view_seqno` bigint(20) NOT NULL, + `node_name` char(32) NOT NULL, + `node_incoming_address` varchar(256) NOT NULL, + PRIMARY KEY (`node_uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 STATS_PERSISTENT=0 +SHOW CREATE TABLE wsrep_streaming_log; +Table Create Table +wsrep_streaming_log CREATE TABLE `wsrep_streaming_log` ( + `node_uuid` char(36) NOT NULL, + `trx_id` bigint(20) NOT NULL, + `seqno` bigint(20) NOT NULL, + `flags` int(11) NOT NULL, + `frag` longblob NOT NULL, + PRIMARY KEY (`node_uuid`,`trx_id`,`seqno`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 STATS_PERSISTENT=0 +SHOW CREATE TABLE mysql.wsrep_cluster; +Table Create Table +wsrep_cluster CREATE TABLE `wsrep_cluster` ( + `cluster_uuid` char(36) NOT NULL, + `view_id` bigint(20) NOT NULL, + `view_seqno` bigint(20) NOT NULL, + `protocol_version` int(11) NOT NULL, + `capabilities` int(11) NOT NULL, + PRIMARY KEY (`cluster_uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 STATS_PERSISTENT=0 +SHOW CREATE TABLE mysql.wsrep_cluster_members; +Table Create Table +wsrep_cluster_members CREATE TABLE `wsrep_cluster_members` ( + `node_uuid` char(36) NOT NULL, + `cluster_uuid` char(36) NOT NULL, + `node_name` char(32) NOT NULL, + `node_incoming_address` varchar(256) NOT NULL, + PRIMARY KEY (`node_uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 STATS_PERSISTENT=0 +SHOW CREATE TABLE mysql.wsrep_streaming_log; +Table Create Table +wsrep_streaming_log CREATE TABLE `wsrep_streaming_log` ( + `node_uuid` char(36) NOT NULL, + `trx_id` bigint(20) NOT NULL, + `seqno` bigint(20) NOT NULL, + `flags` int(11) NOT NULL, + `frag` longblob NOT NULL, + PRIMARY KEY (`node_uuid`,`trx_id`,`seqno`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 STATS_PERSISTENT=0 +DROP TABLE wsrep_cluster; +DROP TABLE wsrep_cluster_members; +DROP TABLE wsrep_cluster_members_history; +DROP TABLE wsrep_streaming_log; diff --git a/mysql-test/suite/galera/t/galera_schema.test b/mysql-test/suite/galera/t/galera_schema.test new file mode 100644 index 00000000000..a3ee814c393 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_schema.test @@ -0,0 +1,61 @@ +--source include/galera_cluster.inc + +CREATE TABLE IF NOT EXISTS wsrep_cluster +( + cluster_uuid CHAR(36) PRIMARY KEY, + view_id BIGINT NOT NULL, + view_seqno BIGINT NOT NULL, + protocol_version INT NOT NULL, + capabilities INT NOT NULL +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS wsrep_cluster_members +( + node_uuid CHAR(36) PRIMARY KEY, + cluster_uuid CHAR(36) NOT NULL, + node_name CHAR(32) NOT NULL, + node_incoming_address VARCHAR(256) NOT NULL +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS wsrep_cluster_members_history +( + node_uuid CHAR(36) PRIMARY KEY, + cluster_uuid CHAR(36) NOT NULL, + last_view_id BIGINT NOT NULL, + last_view_seqno BIGINT NOT NULL, + node_name CHAR(32) NOT NULL, + node_incoming_address VARCHAR(256) NOT NULL +) ENGINE=InnoDB; + +CREATE TABLE IF NOT EXISTS wsrep_streaming_log +( + node_uuid CHAR(36), + trx_id BIGINT, + seqno BIGINT, + flags INT NOT NULL, + frag LONGBLOB NOT NULL, + PRIMARY KEY (node_uuid, trx_id, seqno) +) ENGINE=InnoDB; + +DELETE FROM wsrep_cluster; +DELETE FROM wsrep_cluster_members; + +ALTER TABLE wsrep_cluster STATS_PERSISTENT=0; +ALTER TABLE wsrep_cluster_members STATS_PERSISTENT=0; +ALTER TABLE wsrep_cluster_members_history STATS_PERSISTENT=0; +ALTER TABLE wsrep_streaming_log STATS_PERSISTENT=0; + +SHOW CREATE TABLE wsrep_cluster; +SHOW CREATE TABLE wsrep_cluster_members; +SHOW CREATE TABLE wsrep_cluster_members_history; +SHOW CREATE TABLE wsrep_streaming_log; + +SHOW CREATE TABLE mysql.wsrep_cluster; +SHOW CREATE TABLE mysql.wsrep_cluster_members; +#SHOW CREATE TABLE mysql.wsrep_cluster_members_history; +SHOW CREATE TABLE mysql.wsrep_streaming_log; + +DROP TABLE wsrep_cluster; +DROP TABLE wsrep_cluster_members; +DROP TABLE wsrep_cluster_members_history; +DROP TABLE wsrep_streaming_log; diff --git a/mysql-test/suite/galera_3nodes/r/galera_wsrep_schema.result b/mysql-test/suite/galera_3nodes/r/galera_wsrep_schema.result index ba01eab0e26..f51eb815cd5 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_wsrep_schema.result +++ b/mysql-test/suite/galera_3nodes/r/galera_wsrep_schema.result @@ -14,7 +14,7 @@ wsrep_cluster CREATE TABLE `wsrep_cluster` ( `protocol_version` int(11) NOT NULL, `capabilities` int(11) NOT NULL, PRIMARY KEY (`cluster_uuid`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 +) ENGINE=InnoDB DEFAULT CHARSET=latin1 STATS_PERSISTENT=0 SHOW CREATE TABLE mysql.wsrep_cluster_members; Table Create Table wsrep_cluster_members CREATE TABLE `wsrep_cluster_members` ( @@ -23,7 +23,7 @@ wsrep_cluster_members CREATE TABLE `wsrep_cluster_members` ( `node_name` char(32) NOT NULL, `node_incoming_address` varchar(256) NOT NULL, PRIMARY KEY (`node_uuid`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 +) ENGINE=InnoDB DEFAULT CHARSET=latin1 STATS_PERSISTENT=0 SELECT COUNT(*) AS EXPECT_1 FROM mysql.wsrep_cluster; EXPECT_1 1 diff --git a/mysql-test/suite/galera_3nodes/r/galera_wsrep_schema_init.result b/mysql-test/suite/galera_3nodes/r/galera_wsrep_schema_init.result index 2a29afd62be..d9d3e817bed 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_wsrep_schema_init.result +++ b/mysql-test/suite/galera_3nodes/r/galera_wsrep_schema_init.result @@ -14,7 +14,7 @@ wsrep_cluster CREATE TABLE `wsrep_cluster` ( `protocol_version` int(11) NOT NULL, `capabilities` int(11) NOT NULL, PRIMARY KEY (`cluster_uuid`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 +) ENGINE=InnoDB DEFAULT CHARSET=latin1 STATS_PERSISTENT=0 SHOW CREATE TABLE mysql.wsrep_cluster_members; Table Create Table wsrep_cluster_members CREATE TABLE `wsrep_cluster_members` ( @@ -23,7 +23,7 @@ wsrep_cluster_members CREATE TABLE `wsrep_cluster_members` ( `node_name` char(32) NOT NULL, `node_incoming_address` varchar(256) NOT NULL, PRIMARY KEY (`node_uuid`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 +) ENGINE=InnoDB DEFAULT CHARSET=latin1 STATS_PERSISTENT=0 SELECT @@sql_safe_updates; @@sql_safe_updates 1 diff --git a/mysql-test/suite/galera_sr/r/GCF-627.result b/mysql-test/suite/galera_sr/r/GCF-627.result index 65d8c95ad08..7cd2ab63ff3 100644 --- a/mysql-test/suite/galera_sr/r/GCF-627.result +++ b/mysql-test/suite/galera_sr/r/GCF-627.result @@ -2,7 +2,6 @@ connection node_2; connection node_1; connection node_1; CREATE TABLE t1 (f1 INTEGER, f2 VARCHAR(10)) ENGINE=InnoDB; -CREATE TABLE t2 (f1 INTEGER); SET SESSION wsrep_trx_fragment_size = 1; SET AUTOCOMMIT=OFF; START TRANSACTION; @@ -16,9 +15,10 @@ connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; INSERT INTO t1 VALUES (2); ERROR 42S02: Table 'test.t1' doesn't exist connection node_1; -SELECT * FROM mysql.wsrep_streaming_log; -node_uuid trx_id seqno flags frag +SELECT COUNT(*) FROM mysql.wsrep_streaming_log; +COUNT(*) +0 connection node_2; -SELECT * FROM mysql.wsrep_streaming_log; -node_uuid trx_id seqno flags frag -DROP TABLE t2; +SELECT COUNT(*) FROM mysql.wsrep_streaming_log; +COUNT(*) +0 diff --git a/mysql-test/suite/galera_sr/t/GCF-627.test b/mysql-test/suite/galera_sr/t/GCF-627.test index ad351eb9da6..6990c12314d 100644 --- a/mysql-test/suite/galera_sr/t/GCF-627.test +++ b/mysql-test/suite/galera_sr/t/GCF-627.test @@ -1,9 +1,7 @@ --source include/galera_cluster.inc ---source include/have_innodb.inc --connection node_1 CREATE TABLE t1 (f1 INTEGER, f2 VARCHAR(10)) ENGINE=InnoDB; -CREATE TABLE t2 (f1 INTEGER); SET SESSION wsrep_trx_fragment_size = 1; SET AUTOCOMMIT=OFF; @@ -25,11 +23,9 @@ INSERT INTO t1 VALUES (2); --let $wait_condition = SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log --source include/wait_condition.inc -SELECT * FROM mysql.wsrep_streaming_log; +SELECT COUNT(*) FROM mysql.wsrep_streaming_log; --connection node_2 --let $wait_condition = SELECT COUNT(*) = 0 FROM mysql.wsrep_streaming_log --source include/wait_condition.inc -SELECT * FROM mysql.wsrep_streaming_log; - -DROP TABLE t2; +SELECT COUNT(*) FROM mysql.wsrep_streaming_log; diff --git a/mysql-test/suite/innodb/r/innodb_defrag_stats.result b/mysql-test/suite/innodb/r/innodb_defrag_stats.result index 4fdcf42faa1..2e7a2ba5197 100644 --- a/mysql-test/suite/innodb/r/innodb_defrag_stats.result +++ b/mysql-test/suite/innodb/r/innodb_defrag_stats.result @@ -1,25 +1,32 @@ -select @@global.innodb_stats_persistent; -@@global.innodb_stats_persistent -1 -set global innodb_defragment_stats_accuracy = 20; -CREATE TABLE t1(a INT PRIMARY KEY, b VARCHAR(256), KEY SECOND(a, b)) -ENGINE=INNODB; +SET GLOBAL innodb_defragment_stats_accuracy = 20; +DELETE FROM mysql.innodb_index_stats; +# Create table. +CREATE TABLE t1 (a INT PRIMARY KEY AUTO_INCREMENT, b VARCHAR(256), +KEY SECOND(a, b)) ENGINE=INNODB STATS_PERSISTENT=0; INSERT INTO t1 SELECT seq, REPEAT('A', 256) FROM seq_1_to_1024; # Not enough page splits to trigger persistent stats write yet. -select * from mysql.innodb_index_stats where table_name='t1' -and stat_name in ('n_page_split','n_pages_freed,n_leaf_pages_defrag'); -database_name table_name index_name last_update stat_name stat_value sample_size stat_description +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) = 0 +1 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) = 0 +1 INSERT INTO t1 SELECT seq, REPEAT('A', 256) FROM seq_1025_to_2048; # Persistent stats recorded. -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_page_split'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); count(stat_value) > 0 1 -select * from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_pages_freed'); -database_name table_name index_name last_update stat_name stat_value sample_size stat_description -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_leaf_pages_defrag'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) = 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); count(stat_value) > 0 1 # Delete some rows. +BEGIN; delete from t1 where a between 100 * 20 and 100 * 20 + 30; delete from t1 where a between 100 * 19 and 100 * 19 + 30; delete from t1 where a between 100 * 18 and 100 * 18 + 30; @@ -40,82 +47,93 @@ delete from t1 where a between 100 * 4 and 100 * 4 + 30; delete from t1 where a between 100 * 3 and 100 * 3 + 30; delete from t1 where a between 100 * 2 and 100 * 2 + 30; delete from t1 where a between 100 * 1 and 100 * 1 + 30; -# restart -# Server Restarted -# Confirm persistent stats still there after restart. -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_page_split'); +COMMIT; +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); count(stat_value) > 0 1 -select * from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_pages_freed'); -database_name table_name index_name last_update stat_name stat_value sample_size stat_description -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_leaf_pages_defrag'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) = 0 +1 +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); count(stat_value) > 0 1 optimize table t1; Table Op Msg_type Msg_text test.t1 optimize status OK -select sleep(2); -sleep(2) -0 -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_page_split'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); count(stat_value) > 0 1 -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); count(stat_value) > 0 1 -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_leaf_pages_defrag'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); count(stat_value) > 0 1 set global innodb_defragment_stats_accuracy = 40; -INSERT INTO t1 SELECT seq, REPEAT('A', 256) FROM seq_2049_to_4096; -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_page_split'); +INSERT INTO t1 (b) SELECT b from t1; +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); count(stat_value) > 0 1 -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); count(stat_value) > 0 1 -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_leaf_pages_defrag'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); count(stat_value) > 0 1 -INSERT INTO t1 SELECT seq, REPEAT('A', 256) FROM seq_4097_to_8192; -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_page_split'); +INSERT INTO t1 (b) SELECT b from t1; +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); count(stat_value) > 0 1 -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); count(stat_value) > 0 1 -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_leaf_pages_defrag'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); count(stat_value) > 0 1 # Table rename should cause stats rename. rename table t1 to t2; -select * from mysql.innodb_index_stats where table_name = 't1'; -database_name table_name index_name last_update stat_name stat_value sample_size stat_description -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't2' and stat_name in ('n_page_split'); -count(stat_value) > 0 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +count(stat_value) = 0 1 -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't2' and stat_name in ('n_pages_freed'); -count(stat_value) > 0 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +count(stat_value) = 0 1 -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't2' and stat_name in ('n_leaf_pages_defrag'); -count(stat_value) > 0 +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); +count(stat_value) = 0 1 -# Drop index should cause stats drop. -drop index SECOND on t2; -select * from mysql.innodb_index_stats where table_name = 't2' and index_name = 'SECOND'; -database_name table_name index_name last_update stat_name stat_value sample_size stat_description -# restart -Server Restarted -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't2' and stat_name in ('n_page_split'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_page_split'); count(stat_value) > 0 1 -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't2' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed'); count(stat_value) > 0 1 -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't2' and stat_name in ('n_leaf_pages_defrag'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag'); count(stat_value) > 0 1 +# Drop index should cause stats drop, but will not. +drop index SECOND on t2; +SELECT stat_name, stat_value>0 FROM mysql.innodb_index_stats +WHERE table_name like '%t2%' AND index_name='SECOND'; +stat_name stat_value>0 +# +# MDEV-26636: Statistics must not be written for temporary tables +# +SET GLOBAL innodb_defragment_stats_accuracy = 1; +CREATE TEMPORARY TABLE t (a INT PRIMARY KEY, c CHAR(255) NOT NULL) +ENGINE=InnoDB; +INSERT INTO t SELECT seq, '' FROM seq_1_to_100; +# restart +SELECT * FROM mysql.innodb_index_stats where table_name like '%t1%'; +database_name table_name index_name last_update stat_name stat_value sample_size stat_description +SELECT table_name, index_name, stat_name, stat_value>0 +FROM mysql.innodb_index_stats; +table_name index_name stat_name stat_value>0 +t2 PRIMARY n_leaf_pages_defrag 1 +t2 PRIMARY n_leaf_pages_reserved 1 +t2 PRIMARY n_page_split 1 +t2 PRIMARY n_pages_freed 0 # Clean up +ALTER TABLE t2 STATS_PERSISTENT=1; DROP TABLE t2; -select * from mysql.innodb_index_stats where table_name = 't2'; +SELECT * FROM mysql.innodb_index_stats; database_name table_name index_name last_update stat_name stat_value sample_size stat_description diff --git a/mysql-test/suite/innodb/r/undo_truncate.result b/mysql-test/suite/innodb/r/undo_truncate.result index ad236bdecd4..fbfd061c9cc 100644 --- a/mysql-test/suite/innodb/r/undo_truncate.result +++ b/mysql-test/suite/innodb/r/undo_truncate.result @@ -1,34 +1,13 @@ -SET @save_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; -SET @save_truncate = @@GLOBAL.innodb_undo_log_truncate; SET GLOBAL innodb_undo_log_truncate = 0; SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; -SET @trunc_start= -(SELECT variable_value FROM information_schema.global_status -WHERE variable_name = 'innodb_undo_truncations'); create table t1(keyc int primary key, c char(100)) engine = innodb; create table t2(keyc int primary key, c char(100)) engine = innodb; -CREATE PROCEDURE populate_t1() -BEGIN -DECLARE i INT DEFAULT 1; -while (i <= 20000) DO -insert into t1 values (i, 'a'); -SET i = i + 1; -END WHILE; -END | -CREATE PROCEDURE populate_t2() -BEGIN -DECLARE i INT DEFAULT 1; -while (i <= 20000) DO -insert into t2 values (i, 'a'); -SET i = i + 1; -END WHILE; -END | connect con1,localhost,root,,; begin; -call populate_t1(); +insert into t1 select seq,'a' from seq_1_to_20000; connect con2,localhost,root,,; begin; -call populate_t2(); +insert into t2 select seq,'a' from seq_1_to_20000; connection con1; update t1 set c = 'mysql'; connection con2; @@ -49,9 +28,6 @@ connection con2; commit; disconnect con2; connection default; +set global innodb_fast_shutdown=0; +# restart drop table t1, t2; -drop PROCEDURE populate_t1; -drop PROCEDURE populate_t2; -InnoDB 0 transactions not purged -SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; -SET GLOBAL innodb_undo_log_truncate = @save_truncate; diff --git a/mysql-test/suite/innodb/t/innodb_defrag_stats.test b/mysql-test/suite/innodb/t/innodb_defrag_stats.test index 248fd24f0c8..13e4579d3d8 100644 --- a/mysql-test/suite/innodb/t/innodb_defrag_stats.test +++ b/mysql-test/suite/innodb/t/innodb_defrag_stats.test @@ -1,28 +1,32 @@ --source include/have_innodb.inc ---source include/have_sequence.inc ---source include/big_test.inc --source include/not_valgrind.inc --source include/not_embedded.inc +--source include/have_sequence.inc + +SET GLOBAL innodb_defragment_stats_accuracy = 20; -select @@global.innodb_stats_persistent; -set global innodb_defragment_stats_accuracy = 20; +DELETE FROM mysql.innodb_index_stats; + +--echo # Create table. +CREATE TABLE t1 (a INT PRIMARY KEY AUTO_INCREMENT, b VARCHAR(256), + KEY SECOND(a, b)) ENGINE=INNODB STATS_PERSISTENT=0; -CREATE TABLE t1(a INT PRIMARY KEY, b VARCHAR(256), KEY SECOND(a, b)) -ENGINE=INNODB; INSERT INTO t1 SELECT seq, REPEAT('A', 256) FROM seq_1_to_1024; --echo # Not enough page splits to trigger persistent stats write yet. -select * from mysql.innodb_index_stats where table_name='t1' -and stat_name in ('n_page_split','n_pages_freed,n_leaf_pages_defrag'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); INSERT INTO t1 SELECT seq, REPEAT('A', 256) FROM seq_1025_to_2048; --echo # Persistent stats recorded. -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_page_split'); -select * from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_pages_freed'); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_leaf_pages_defrag'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); --echo # Delete some rows. +BEGIN; let $num_delete = 20; while ($num_delete) { @@ -30,58 +34,71 @@ while ($num_delete) eval delete from t1 where a between $j and $j + 30; dec $num_delete; } +COMMIT; ---source include/restart_mysqld.inc ---echo # Server Restarted - ---echo # Confirm persistent stats still there after restart. -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_page_split'); -select * from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_pages_freed'); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_leaf_pages_defrag'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); optimize table t1; -select sleep(2); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_page_split'); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_pages_freed'); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_leaf_pages_defrag'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); set global innodb_defragment_stats_accuracy = 40; -INSERT INTO t1 SELECT seq, REPEAT('A', 256) FROM seq_2049_to_4096; +INSERT INTO t1 (b) SELECT b from t1; + +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_page_split'); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_pages_freed'); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_leaf_pages_defrag'); -INSERT INTO t1 SELECT seq, REPEAT('A', 256) FROM seq_4097_to_8192; +INSERT INTO t1 (b) SELECT b from t1; -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_page_split'); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_pages_freed'); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't1' and stat_name in ('n_leaf_pages_defrag'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); --echo # Table rename should cause stats rename. rename table t1 to t2; -select * from mysql.innodb_index_stats where table_name = 't1'; -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't2' and stat_name in ('n_page_split'); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't2' and stat_name in ('n_pages_freed'); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't2' and stat_name in ('n_leaf_pages_defrag'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_page_split'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_pages_freed'); +select count(stat_value) = 0 from mysql.innodb_index_stats where table_name like '%t1%' and stat_name in ('n_leaf_pages_defrag'); + +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_page_split'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_pages_freed'); +select count(stat_value) > 0 from mysql.innodb_index_stats where table_name like '%t2%' and stat_name in ('n_leaf_pages_defrag'); ---echo # Drop index should cause stats drop. +--echo # Drop index should cause stats drop, but will not. drop index SECOND on t2; -select * from mysql.innodb_index_stats where table_name = 't2' and index_name = 'SECOND'; +--sorted_result +SELECT stat_name, stat_value>0 FROM mysql.innodb_index_stats +WHERE table_name like '%t2%' AND index_name='SECOND'; + +--echo # +--echo # MDEV-26636: Statistics must not be written for temporary tables +--echo # +SET GLOBAL innodb_defragment_stats_accuracy = 1; +CREATE TEMPORARY TABLE t (a INT PRIMARY KEY, c CHAR(255) NOT NULL) +ENGINE=InnoDB; +INSERT INTO t SELECT seq, '' FROM seq_1_to_100; --source include/restart_mysqld.inc ---echo Server Restarted -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't2' and stat_name in ('n_page_split'); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't2' and stat_name in ('n_pages_freed'); -select count(stat_value) > 0 from mysql.innodb_index_stats where table_name = 't2' and stat_name in ('n_leaf_pages_defrag'); +SELECT * FROM mysql.innodb_index_stats where table_name like '%t1%'; + +--sorted_result +SELECT table_name, index_name, stat_name, stat_value>0 +FROM mysql.innodb_index_stats; --echo # Clean up +# DROP TABLE will not touch persistent statistics if the table has none! +ALTER TABLE t2 STATS_PERSISTENT=1; DROP TABLE t2; -select * from mysql.innodb_index_stats where table_name = 't2'; +SELECT * FROM mysql.innodb_index_stats; diff --git a/mysql-test/suite/innodb/t/undo_truncate.opt b/mysql-test/suite/innodb/t/undo_truncate.opt new file mode 100644 index 00000000000..f4d78725c6e --- /dev/null +++ b/mysql-test/suite/innodb/t/undo_truncate.opt @@ -0,0 +1 @@ +--innodb-buffer-pool-size=24M diff --git a/mysql-test/suite/innodb/t/undo_truncate.test b/mysql-test/suite/innodb/t/undo_truncate.test index d2a4e287305..9601de482b3 100644 --- a/mysql-test/suite/innodb/t/undo_truncate.test +++ b/mysql-test/suite/innodb/t/undo_truncate.test @@ -1,16 +1,16 @@ --source include/have_innodb.inc --source include/innodb_page_size.inc --source include/have_undo_tablespaces.inc +--source include/not_embedded.inc +--source include/have_sequence.inc + +--disable_query_log +call mtr.add_suppression("InnoDB: Difficult to find free blocks in the buffer pool"); +--enable_query_log -SET @save_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; -SET @save_truncate = @@GLOBAL.innodb_undo_log_truncate; SET GLOBAL innodb_undo_log_truncate = 0; SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; -SET @trunc_start= -(SELECT variable_value FROM information_schema.global_status -WHERE variable_name = 'innodb_undo_truncations'); - #----------------------------------------------------------------------------- # # Perform DML action using multiple clients and multiple undo tablespace. @@ -19,37 +19,14 @@ WHERE variable_name = 'innodb_undo_truncations'); create table t1(keyc int primary key, c char(100)) engine = innodb; create table t2(keyc int primary key, c char(100)) engine = innodb; # -delimiter |; -CREATE PROCEDURE populate_t1() -BEGIN - DECLARE i INT DEFAULT 1; - while (i <= 20000) DO - insert into t1 values (i, 'a'); - SET i = i + 1; - END WHILE; -END | -delimiter ;| -# -delimiter |; -CREATE PROCEDURE populate_t2() -BEGIN - DECLARE i INT DEFAULT 1; - while (i <= 20000) DO - insert into t2 values (i, 'a'); - SET i = i + 1; - END WHILE; -END | -delimiter ;| -# -# let DATADIR = `select @@datadir`; connect (con1,localhost,root,,); begin; -send call populate_t1(); +send insert into t1 select seq,'a' from seq_1_to_20000; connect (con2,localhost,root,,); begin; -send call populate_t2(); +send insert into t2 select seq,'a' from seq_1_to_20000; connection con1; reap; send update t1 set c = 'mysql'; connection con2; reap; send update t2 set c = 'mysql'; @@ -59,62 +36,25 @@ connection con1; reap; send delete from t1; connection con2; reap; delete from t2; connection con1; reap; -let CHECKFILE = $MYSQL_TMP_DIR/check.txt; -perl; -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size1) - = stat("$ENV{DATADIR}/undo001"); -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size2) - = stat("$ENV{DATADIR}/undo002"); -open(OUT, ">$ENV{CHECKFILE}") || die; -print OUT "let \$size1='$size1,$size2';\n"; -close(OUT); -EOF - SET GLOBAL innodb_undo_log_truncate = 1; commit; disconnect con1; connection con2; commit; disconnect con2; connection default; -drop table t1, t2; -drop PROCEDURE populate_t1; -drop PROCEDURE populate_t2; - ---source include/wait_all_purged.inc -# 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. -# 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 - WHERE variable_name = 'innodb_undo_truncations'); - source include/wait_condition.inc; -} +--replace_regex /.*Trx id counter ([0-9]+).*/\1/ +let $trx_before= `SHOW ENGINE INNODB STATUS`; +let $trx_before= `select substr('$trx_before',9)+2`; ---source $CHECKFILE -perl; -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size1) - = stat("$ENV{DATADIR}/undo001"); -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size2) - = stat("$ENV{DATADIR}/undo002"); -open(OUT, ">$ENV{CHECKFILE}") || die; -print OUT "let \$size2='$size1,$size2';\n"; -close(OUT); -EOF +set global innodb_fast_shutdown=0; +--source include/restart_mysqld.inc +--replace_regex /.*Trx id counter ([0-9]+).*/\1/ +let $trx_after= `SHOW ENGINE INNODB STATUS`; +let $trx_after= `select substr('$trx_after',9)`; ---source $CHECKFILE ---remove_file $CHECKFILE +drop table t1, t2; -if ($size1 == $size2) +if ($trx_before != $trx_after) { - # This fails for innodb_page_size=64k, occasionally also for 32k. - if (`select @@innodb_page_size IN (8192,16384)`) - { - echo Truncation did not happen: $size1; - } + echo Transaction sequence mismatch: $trx_before != $trx_after; } - -SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; -SET GLOBAL innodb_undo_log_truncate = @save_truncate; diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh index 562b9b929f2..54632e5f79b 100644 --- a/scripts/wsrep_sst_mariabackup.sh +++ b/scripts/wsrep_sst_mariabackup.sh @@ -949,8 +949,10 @@ then tmpdir=$(parse_cnf "$encgroups" 'tmpdir') if [ -z "$tmpdir" ]; then xtmpdir="$(mktemp -d)" - else + elif [ "$OS" = 'Linux' ]; then xtmpdir=$(mktemp '-d' "--tmpdir=$tmpdir") + else + xtmpdir=$(TMPDIR="$tmpdir"; mktemp '-d') fi wsrep_log_info "Using '$xtmpdir' as mariabackup temporary directory" diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index d90e87b68f2..e16ed75cb16 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -725,8 +725,10 @@ EOF tmpdir=$(parse_cnf '--mysqld|sst' 'tmpdir') if [ -z "$tmpdir" ]; then tmpfile="$(mktemp)" - else + elif [ "$OS" = 'Linux' ]; then tmpfile=$(mktemp "--tmpdir=$tmpdir") + else + tmpfile=$(TMPDIR="$tmpdir"; mktemp '-d') fi wsrep_log_info "Extracting binlog files:" diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 8b86ec425d4..5a8ea9ea2d2 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -1,5 +1,5 @@ # Copyright (c) 2006, 2014, Oracle and/or its affiliates. -# Copyright (c) 2010, 2020, MariaDB Corporation. +# Copyright (c) 2010, 2021, 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 @@ -65,6 +65,8 @@ ADD_CUSTOM_COMMAND( DEPENDS gen_lex_token ) +FIND_PACKAGE(BISON 2.4) + ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/yy_mariadb.yy ${CMAKE_CURRENT_BINARY_DIR}/yy_oracle.yy @@ -72,6 +74,7 @@ ADD_CUSTOM_COMMAND( "-DOUT1=${CMAKE_CURRENT_BINARY_DIR}/yy_oracle.yy" "-DOUT2=${CMAKE_CURRENT_BINARY_DIR}/yy_mariadb.yy" "-DIN=${CMAKE_CURRENT_SOURCE_DIR}/sql_yacc.yy" + "-DBISON_VERSION=${BISON_VERSION}" -P ${CMAKE_CURRENT_SOURCE_DIR}/gen_yy_files.cmake COMMENT "Building yy_mariadb.yy and yy_oracle.yy from sql_yacc.yy" DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/sql_yacc.yy @@ -325,9 +328,6 @@ IF(WITH_MYSQLD_LDFLAGS) ENDIF() -FIND_PACKAGE(BISON 2.4) - - # Handle out-of-source build from source package with possibly broken # bison. Copy bison output to from source to build directory, if not already # there diff --git a/sql/gen_yy_files.cmake b/sql/gen_yy_files.cmake index da63c72c37c..3ceb60a95de 100644 --- a/sql/gen_yy_files.cmake +++ b/sql/gen_yy_files.cmake @@ -5,6 +5,9 @@ file(READ "${IN}" data) file(WRITE "${OUT1}" "") file(WRITE "${OUT2}" "") set(where 0) +if(NOT(BISON_VERSION VERSION_LESS "3.0.0")) + string(REPLACE "\n%pure-parser" "\n%define api.pure" data "${data}") +endif() string(REGEX REPLACE "/\\* sql_yacc\\.yy \\*/" "/* DON'T EDIT THIS FILE. IT'S GENERATED. EDIT sql_yacc.yy INSTEAD */" data "${data}") while(NOT data STREQUAL "") string(REGEX MATCH "^(%[ie][^\n]*\n)|((%[^ie\n]|[^%\n])[^\n]*\n)+|\n+" line "${data}") diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c88bfc4c484..31f5faa72ed 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4928,6 +4928,9 @@ MYSQL_THD create_background_thd() thd->set_command(COM_DAEMON); thd->system_thread= SYSTEM_THREAD_GENERIC; thd->security_ctx->host_or_ip= ""; + thd->real_id= 0; + thd->thread_id= 0; + thd->query_id= 0; return thd; } diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 0a2db2ea93a..e35cf17b182 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -631,14 +631,18 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (!table->check_virtual_columns_marked_for_read()) { DBUG_PRINT("info", ("Trying direct delete")); - if (select && select->cond && - (select->cond->used_tables() == table->map)) + bool use_direct_delete= !select || !select->cond; + if (!use_direct_delete && + (select->cond->used_tables() & ~RAND_TABLE_BIT) == table->map) { DBUG_ASSERT(!table->file->pushed_cond); if (!table->file->cond_push(select->cond)) + { + use_direct_delete= TRUE; table->file->pushed_cond= select->cond; + } } - if (!table->file->direct_delete_rows_init()) + if (use_direct_delete && !table->file->direct_delete_rows_init()) { /* Direct deleting is supported */ DBUG_PRINT("info", ("Using direct delete")); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 8daf4b703ba..76b07284a37 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -754,15 +754,20 @@ int mysql_update(THD *thd, !table->check_virtual_columns_marked_for_write()) { DBUG_PRINT("info", ("Trying direct update")); - if (select && select->cond && - (select->cond->used_tables() == table->map)) + bool use_direct_update= !select || !select->cond; + if (!use_direct_update && + (select->cond->used_tables() & ~RAND_TABLE_BIT) == table->map) { DBUG_ASSERT(!table->file->pushed_cond); if (!table->file->cond_push(select->cond)) + { + use_direct_update= TRUE; table->file->pushed_cond= select->cond; + } } - if (!table->file->info_push(INFO_KIND_UPDATE_FIELDS, &fields) && + if (use_direct_update && + !table->file->info_push(INFO_KIND_UPDATE_FIELDS, &fields) && !table->file->info_push(INFO_KIND_UPDATE_VALUES, &values) && !table->file->direct_update_rows_init(&fields)) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 87c95616107..b0685871311 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -75,6 +75,9 @@ /* warning C4065: switch statement contains 'default' but no 'case' labels */ #pragma warning (disable : 4065) #endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wunused-label" /* yyexhaustedlab: */ +#endif int yylex(void *yylval, void *yythd); diff --git a/sql/wsrep_schema.cc b/sql/wsrep_schema.cc index 9d77577ed42..cc8ec7a5af4 100644 --- a/sql/wsrep_schema.cc +++ b/sql/wsrep_schema.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2015-2019 Codership Oy <info@codership.com> +/* Copyright (C) 2015-2021 Codership Oy <info@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,7 @@ static const std::string create_cluster_table_str= "view_seqno BIGINT NOT NULL," "protocol_version INT NOT NULL," "capabilities INT NOT NULL" - ") ENGINE=InnoDB"; + ") ENGINE=InnoDB STATS_PERSISTENT=0"; static const std::string create_members_table_str= "CREATE TABLE IF NOT EXISTS " + wsrep_schema_str + "." + members_table_str + @@ -63,7 +63,7 @@ static const std::string create_members_table_str= "cluster_uuid CHAR(36) NOT NULL," "node_name CHAR(32) NOT NULL," "node_incoming_address VARCHAR(256) NOT NULL" - ") ENGINE=InnoDB"; + ") ENGINE=InnoDB STATS_PERSISTENT=0"; #ifdef WSREP_SCHEMA_MEMBERS_HISTORY static const std::string cluster_member_history_table_str= "wsrep_cluster_member_history"; @@ -76,7 +76,7 @@ static const std::string create_members_history_table_str= "last_view_seqno BIGINT NOT NULL," "node_name CHAR(32) NOT NULL," "node_incoming_address VARCHAR(256) NOT NULL" - ") ENGINE=InnoDB"; + ") ENGINE=InnoDB STATS_PERSISTENT=0"; #endif /* WSREP_SCHEMA_MEMBERS_HISTORY */ static const std::string create_frag_table_str= @@ -88,7 +88,7 @@ static const std::string create_frag_table_str= "flags INT NOT NULL, " "frag LONGBLOB NOT NULL, " "PRIMARY KEY (node_uuid, trx_id, seqno)" - ") ENGINE=InnoDB"; + ") ENGINE=InnoDB STATS_PERSISTENT=0"; static const std::string delete_from_cluster_table= "DELETE FROM " + wsrep_schema_str + "." + cluster_table_str; @@ -96,6 +96,26 @@ static const std::string delete_from_cluster_table= static const std::string delete_from_members_table= "DELETE FROM " + wsrep_schema_str + "." + members_table_str; +/* For rolling upgrade we need to use ALTER. We do not want +persistent statistics to be collected from these tables. */ +static const std::string alter_cluster_table= + "ALTER TABLE " + wsrep_schema_str + "." + cluster_table_str + + " STATS_PERSISTENT=0"; + +static const std::string alter_members_table= + "ALTER TABLE " + wsrep_schema_str + "." + members_table_str + + " STATS_PERSISTENT=0"; + +#ifdef WSREP_SCHEMA_MEMBERS_HISTORY +static const std::string alter_members_history_table= + "ALTER TABLE " + wsrep_schema_str + "." + members_history_table_str + + " STATS_PERSISTENT=0"; +#endif + +static const std::string alter_frag_table= + "ALTER TABLE " + wsrep_schema_str + "." + sr_table_str + + " STATS_PERSISTENT=0"; + namespace Wsrep_schema_impl { @@ -675,13 +695,27 @@ int Wsrep_schema::init() Wsrep_schema_impl::execute_SQL(thd, create_members_history_table_str.c_str(), create_members_history_table_str.size()) || + Wsrep_schema_impl::execute_SQL(thd, + alter_members_history_table.c_str(), + alter_members_history_table.size()) || #endif /* WSREP_SCHEMA_MEMBERS_HISTORY */ Wsrep_schema_impl::execute_SQL(thd, create_frag_table_str.c_str(), - create_frag_table_str.size())) { + create_frag_table_str.size()) || + Wsrep_schema_impl::execute_SQL(thd, + alter_cluster_table.c_str(), + alter_cluster_table.size()) || + Wsrep_schema_impl::execute_SQL(thd, + alter_members_table.c_str(), + alter_members_table.size()) || + Wsrep_schema_impl::execute_SQL(thd, + alter_frag_table.c_str(), + alter_frag_table.size())) + { ret= 1; } - else { + else + { ret= 0; } diff --git a/storage/innobase/btr/btr0defragment.cc b/storage/innobase/btr/btr0defragment.cc index 0e21acb4fda..19f6edc7ec7 100644 --- a/storage/innobase/btr/btr0defragment.cc +++ b/storage/innobase/btr/btr0defragment.cc @@ -225,6 +225,7 @@ void btr_defragment_save_defrag_stats_if_needed(dict_index_t *index) { if (srv_defragment_stats_accuracy != 0 // stats tracking disabled && index->table->space_id != 0 // do not track system tables + && !index->table->is_temporary() && index->stat_defrag_modified_counter >= srv_defragment_stats_accuracy) { dict_stats_defrag_pool_add(index); diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 47ca3cdf23b..cd5b3a1843a 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -3387,6 +3387,7 @@ loop: /* Delete possible entries for the page from the insert buffer: such can exist if the page belonged to an index which was dropped */ if (page_id < page_id_t{SRV_SPACE_ID_UPPER_BOUND, 0} && + !srv_is_undo_tablespace(page_id.space()) && !recv_recovery_is_on()) ibuf_merge_or_delete_for_page(nullptr, page_id, zip_size); diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index fe156c14b2f..ab0b0986010 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -366,10 +366,12 @@ void buf_page_write_complete(const IORequest &request) const bool temp= fsp_is_system_temporary(bpage->id().space()); mysql_mutex_lock(&buf_pool.mutex); + mysql_mutex_assert_not_owner(&buf_pool.flush_list_mutex); buf_pool.stat.n_pages_written++; /* While we do not need any mutex for clearing oldest_modification here, we hope that it will be in the same cache line with io_fix, whose changes must be protected by buf_pool.mutex. */ + ut_ad(temp || bpage->oldest_modification() > 2); bpage->clear_oldest_modification(temp); ut_ad(bpage->io_fix() == BUF_IO_WRITE); bpage->set_io_fix(BUF_IO_NONE); @@ -2234,7 +2236,9 @@ unemployed: mysql_mutex_unlock(&buf_pool.flush_list_mutex); - if (!recv_recovery_is_on() && srv_operation == SRV_OPERATION_NORMAL) + if (!recv_recovery_is_on() && + !srv_startup_is_before_trx_rollback_phase && + srv_operation == SRV_OPERATION_NORMAL) log_checkpoint(); mysql_mutex_lock(&buf_pool.flush_list_mutex); diff --git a/storage/innobase/dict/dict0defrag_bg.cc b/storage/innobase/dict/dict0defrag_bg.cc index 8dd1a8601aa..35ffee7e0d0 100644 --- a/storage/innobase/dict/dict0defrag_bg.cc +++ b/storage/innobase/dict/dict0defrag_bg.cc @@ -173,10 +173,10 @@ dict_stats_defrag_pool_del( /*****************************************************************//** Get the first index that has been added for updating persistent defrag stats and eventually save its stats. */ -static void dict_stats_process_entry_from_defrag_pool() +static void dict_stats_process_entry_from_defrag_pool(THD *thd) { - table_id_t table_id; - index_id_t index_id; + table_id_t table_id; + index_id_t index_id; ut_ad(!srv_read_only_mode); @@ -185,31 +185,28 @@ static void dict_stats_process_entry_from_defrag_pool() /* no index in defrag pool */ return; - dict_sys.freeze(SRW_LOCK_CALL); - /* If the table is no longer cached, we've already lost the in memory stats so there's nothing really to write to disk. */ - dict_table_t *table= dict_sys.find_table(table_id); - dict_index_t *index= table && table->corrupted - ? nullptr : dict_table_find_index_on_id(table, index_id); - const bool save= index && !index->is_corrupted(); - if (save) - table->acquire(); - dict_sys.unfreeze(); - if (save) + MDL_ticket *mdl= nullptr; + if (dict_table_t *table= + dict_table_open_on_id(table_id, false, DICT_TABLE_OP_OPEN_ONLY_IF_CACHED, + thd, &mdl)) { - dict_stats_save_defrag_stats(index); - table->release(); + if (dict_index_t *index= !table->corrupted + ? dict_table_find_index_on_id(table, index_id) : nullptr) + if (!index->is_corrupted()) + dict_stats_save_defrag_stats(index); + dict_table_close(table, false, thd, mdl); } } /** Get the first index that has been added for updating persistent defrag stats and eventually save its stats. */ -void dict_defrag_process_entries_from_defrag_pool() +void dict_defrag_process_entries_from_defrag_pool(THD *thd) { while (!defrag_pool.empty()) - dict_stats_process_entry_from_defrag_pool(); + dict_stats_process_entry_from_defrag_pool(thd); } /*********************************************************************//** diff --git a/storage/innobase/dict/dict0stats_bg.cc b/storage/innobase/dict/dict0stats_bg.cc index 91c18c95851..676656122a3 100644 --- a/storage/innobase/dict/dict0stats_bg.cc +++ b/storage/innobase/dict/dict0stats_bg.cc @@ -391,7 +391,7 @@ static void dict_stats_func(void*) THD *thd= innobase_create_background_thd("InnoDB statistics"); set_current_thd(thd); while (dict_stats_process_entry_from_recalc_pool(thd)) {} - dict_defrag_process_entries_from_defrag_pool(); + dict_defrag_process_entries_from_defrag_pool(thd); set_current_thd(nullptr); innobase_destroy_background_thd(thd); } diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index 7eb5611bb75..620b5a0e49b 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -564,7 +564,7 @@ void fsp_header_init(fil_space_t* space, uint32_t size, mtr_t* mtr) in order to avoid optimizing away any unchanged most significant bytes of FSP_SIZE. */ mtr->write<4,mtr_t::FORCED>(*block, FSP_HEADER_OFFSET + FSP_SIZE - + block->frame, size); + + block->frame, size); ut_ad(0 == mach_read_from_4(FSP_HEADER_OFFSET + FSP_FREE_LIMIT + block->frame)); if (auto f = space->flags & ~FSP_FLAGS_MEM_MASK) { @@ -758,10 +758,12 @@ fsp_try_extend_data_file(fil_space_t *space, buf_block_t *header, mtr_t *mtr) return(0); } - /* We ignore any fragments of a full megabyte when storing the size - to the space header */ + /* For the system tablespace, we ignore any fragments of a + full megabyte when storing the size to the space header */ - space->size_in_header = ut_2pow_round(space->size, (1024 * 1024) / ps); + space->size_in_header = space->id + ? space->size + : ut_2pow_round(space->size, (1024 * 1024) / ps); /* recv_sys_t::parse() expects to find a WRITE record that covers all 4 bytes. Therefore, we must specify mtr_t::FORCED @@ -1045,11 +1047,36 @@ static buf_block_t* fsp_page_create(fil_space_t *space, page_no_t offset, mtr_t *mtr) { - buf_block_t *free_block= buf_LRU_get_free_block(false); - buf_block_t *block= buf_page_create(space, static_cast<uint32_t>(offset), - space->zip_size(), mtr, free_block); + buf_block_t *block, *free_block; + + if (UNIV_UNLIKELY(space->is_being_truncated)) + { + const page_id_t page_id{space->id, offset}; + const ulint fold= page_id.fold(); + mysql_mutex_lock(&buf_pool.mutex); + block= reinterpret_cast<buf_block_t*> + (buf_pool.page_hash_get_low(page_id, fold)); + if (block && block->page.oldest_modification() <= 1) + block= nullptr; + mysql_mutex_unlock(&buf_pool.mutex); + + if (block) + { + ut_ad(block->page.buf_fix_count() >= 1); + ut_ad(block->lock.x_lock_count() == 1); + ut_ad(mtr->have_x_latch(*block)); + free_block= block; + goto got_free_block; + } + } + + free_block= buf_LRU_get_free_block(false); +got_free_block: + block= buf_page_create(space, static_cast<uint32_t>(offset), + space->zip_size(), mtr, free_block); if (UNIV_UNLIKELY(block != free_block)) buf_pool.free_block(free_block); + fsp_init_file_page(space, block, mtr); return block; } @@ -1753,7 +1780,10 @@ fseg_create(fil_space_t *space, ulint byte_offset, mtr_t *mtr, goto funct_exit; } - ut_ad(block->lock.not_recursive()); + ut_d(const auto x = block->lock.x_lock_count()); + ut_ad(x || block->lock.not_recursive()); + ut_ad(x == 1 || space->is_being_truncated); + ut_ad(x <= 2); ut_ad(!fil_page_get_type(block->frame)); mtr->write<1>(*block, FIL_PAGE_TYPE + 1 + block->frame, FIL_PAGE_TYPE_SYS); @@ -2179,14 +2209,14 @@ take_hinted_page: return(NULL); } - if (space->size <= ret_page && !is_system_tablespace(space_id)) { + if (space->size <= ret_page && !is_predefined_tablespace(space_id)) { /* It must be that we are extending a single-table tablespace whose size is still < 64 pages */ if (ret_page >= FSP_EXTENT_SIZE) { - ib::error() << "Error (2): trying to extend" - " a single-table tablespace " << space_id - << " by single page(s) though the" + ib::error() << "Trying to extend '" + << space->chain.start->name + << "' by single page(s) though the" << " space size " << space->size << ". Page no " << ret_page << "."; ut_ad(!has_done_reservation); diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index d7e10405853..a99bada12f9 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -2138,9 +2138,7 @@ inline void buf_page_t::clear_oldest_modification() it from buf_pool.flush_list */ inline void buf_page_t::clear_oldest_modification(bool temporary) { - mysql_mutex_assert_not_owner(&buf_pool.flush_list_mutex); ut_ad(temporary == fsp_is_system_temporary(id().space())); - ut_ad(io_fix_ == BUF_IO_WRITE); if (temporary) { ut_ad(oldest_modification() == 2); diff --git a/storage/innobase/include/dict0defrag_bg.h b/storage/innobase/include/dict0defrag_bg.h index 0edc6304788..679484ad64e 100644 --- a/storage/innobase/include/dict0defrag_bg.h +++ b/storage/innobase/include/dict0defrag_bg.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2016, 2020, MariaDB Corporation. +Copyright (c) 2016, 2021, 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 @@ -80,12 +80,10 @@ dict_stats_defrag_pool_del( all entries for the table */ const dict_index_t* index); /*!< in: index to remove */ -/*****************************************************************//** +/** Get the first index that has been added for updating persistent defrag stats and eventually save its stats. */ -void -dict_defrag_process_entries_from_defrag_pool(); -/*===========================================*/ +void dict_defrag_process_entries_from_defrag_pool(THD *thd); /*********************************************************************//** Save defragmentation result. diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index a651a56e8a0..be28528adb0 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -113,12 +113,16 @@ struct completion_callback; void log_write_up_to(lsn_t lsn, bool flush_to_disk, bool rotate_key = false, const completion_callback* cb=nullptr); -/** write to the log file up to the last log entry. -@param[in] sync whether we want the written log -also to be flushed to disk. */ -void -log_buffer_flush_to_disk( - bool sync = true); +/** Write to the log file up to the last log entry. +@param sync whether to wait for a durable write to complete */ +void log_buffer_flush_to_disk(bool sync= true); + + +/** Prepare to invoke log_write_and_flush(), before acquiring log_sys.mutex. */ +ATTRIBUTE_COLD void log_write_and_flush_prepare(); + +/** Durably write the log up to log_sys.lsn() and release log_sys.mutex. */ +ATTRIBUTE_COLD void log_write_and_flush(); /** Make a checkpoint */ ATTRIBUTE_COLD void log_make_checkpoint(); diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 0085008707e..f72a94d4a39 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -101,6 +101,10 @@ struct mtr_t { /** Commit the mini-transaction. */ void commit(); + /** Commit a mini-transaction that is shrinking a tablespace. + @param space tablespace that is being shrunk */ + ATTRIBUTE_COLD void commit_shrink(fil_space_t &space); + /** Commit a mini-transaction that did not modify any pages, but generated some redo log on a higher level, such as FILE_MODIFY records and an optional FILE_CHECKPOINT marker. diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic index 3896f2f6715..f1b2f9aba83 100644 --- a/storage/innobase/include/mtr0mtr.ic +++ b/storage/innobase/include/mtr0mtr.ic @@ -48,8 +48,8 @@ mtr_t::memo_push(void* object, mtr_memo_type_t type) /* If this mtr has x-fixed a clean page then we set the made_dirty flag. This tells us if we need to - grab log_flush_order_mutex at mtr_commit so that we - can insert the dirtied page to the flush list. */ + grab log_sys.flush_order_mutex at mtr_t::commit() so that we + can insert the dirtied page into the flush list. */ if ((type == MTR_MEMO_PAGE_X_FIX || type == MTR_MEMO_PAGE_SX_FIX) && !m_made_dirty) { diff --git a/storage/innobase/include/sux_lock.h b/storage/innobase/include/sux_lock.h index c09915cf6de..6d2ddadb9c3 100644 --- a/storage/innobase/include/sux_lock.h +++ b/storage/innobase/include/sux_lock.h @@ -98,6 +98,9 @@ public: ut_ad(recursive); return recursive == RECURSIVE_X || recursive == RECURSIVE_U; } + + /** @return the number of X locks being held (by any thread) */ + unsigned x_lock_count() const { return recursive & RECURSIVE_MAX; } #endif /** Acquire a recursive lock */ diff --git a/storage/innobase/include/trx0rseg.h b/storage/innobase/include/trx0rseg.h index bf1d7b7efab..0cfa5d734be 100644 --- a/storage/innobase/include/trx0rseg.h +++ b/storage/innobase/include/trx0rseg.h @@ -43,6 +43,7 @@ trx_rsegf_get(fil_space_t* space, uint32_t page_no, mtr_t* mtr); /** Create a rollback segment header. @param[in,out] space system, undo, or temporary tablespace @param[in] rseg_id rollback segment identifier +@param[in] max_trx_id new value of TRX_RSEG_MAX_TRX_ID @param[in,out] sys_header the TRX_SYS page (NULL for temporary rseg) @param[in,out] mtr mini-transaction @return the created rollback segment @@ -51,6 +52,7 @@ buf_block_t* trx_rseg_header_create( fil_space_t* space, ulint rseg_id, + trx_id_t max_trx_id, buf_block_t* sys_header, mtr_t* mtr); diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 2757571b52c..4d927227944 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -833,15 +833,41 @@ void log_write_up_to(lsn_t lsn, bool flush_to_disk, bool rotate_key, DBUG_EXECUTE_IF("crash_after_log_write_upto", DBUG_SUICIDE();); } -/** write to the log file up to the last log entry. -@param[in] sync whether we want the written log -also to be flushed to disk. */ +/** Write to the log file up to the last log entry. +@param sync whether to wait for a durable write to complete */ void log_buffer_flush_to_disk(bool sync) { ut_ad(!srv_read_only_mode); log_write_up_to(log_sys.get_lsn(std::memory_order_acquire), sync); } +/** Prepare to invoke log_write_and_flush(), before acquiring log_sys.mutex. */ +ATTRIBUTE_COLD void log_write_and_flush_prepare() +{ + mysql_mutex_assert_not_owner(&log_sys.mutex); + + while (flush_lock.acquire(log_sys.get_lsn() + 1, nullptr) != + group_commit_lock::ACQUIRED); + while (write_lock.acquire(log_sys.get_lsn() + 1, nullptr) != + group_commit_lock::ACQUIRED); +} + +/** Durably write the log and release log_sys.mutex */ +ATTRIBUTE_COLD void log_write_and_flush() +{ + ut_ad(!srv_read_only_mode); + auto lsn= log_sys.get_lsn(); + write_lock.set_pending(lsn); + log_write(false); + ut_a(log_sys.write_lsn == lsn); + write_lock.release(lsn); + + lsn= write_lock.value(); + flush_lock.set_pending(lsn); + log_write_flush_to_disk_low(lsn); + flush_lock.release(lsn); +} + /******************************************************************** Tries to establish a big enough margin of free space in the log buffer, such diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index 3ed547e57bc..3a63749695a 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -461,6 +461,114 @@ void mtr_t::commit() release_resources(); } +/** Shrink a tablespace. */ +struct Shrink +{ + /** the first non-existing page in the tablespace */ + const page_id_t high; + + Shrink(const fil_space_t &space) : high({space.id, space.size}) {} + + bool operator()(mtr_memo_slot_t *slot) const + { + if (!slot->object) + return true; + switch (slot->type) { + default: + ut_ad("invalid type" == 0); + return false; + case MTR_MEMO_SPACE_X_LOCK: + ut_ad(high.space() == static_cast<fil_space_t*>(slot->object)->id); + return true; + case MTR_MEMO_PAGE_X_MODIFY: + case MTR_MEMO_PAGE_SX_MODIFY: + case MTR_MEMO_PAGE_X_FIX: + case MTR_MEMO_PAGE_SX_FIX: + auto &bpage= static_cast<buf_block_t*>(slot->object)->page; + ut_ad(bpage.io_fix() == BUF_IO_NONE); + const auto id= bpage.id(); + if (id < high) + { + ut_ad(id.space() == high.space() || + (id == page_id_t{0, TRX_SYS_PAGE_NO} && + srv_is_undo_tablespace(high.space()))); + break; + } + ut_ad(id.space() == high.space()); + ut_ad(bpage.state() == BUF_BLOCK_FILE_PAGE); + if (bpage.oldest_modification() > 1) + bpage.clear_oldest_modification(false); + slot->type= static_cast<mtr_memo_type_t>(slot->type & ~MTR_MEMO_MODIFY); + } + return true; + } +}; + +/** Commit a mini-transaction that is shrinking a tablespace. +@param space tablespace that is being shrunk */ +void mtr_t::commit_shrink(fil_space_t &space) +{ + ut_ad(is_active()); + ut_ad(!is_inside_ibuf()); + ut_ad(!high_level_read_only); + ut_ad(m_modifications); + ut_ad(m_made_dirty); + ut_ad(!recv_recovery_is_on()); + ut_ad(m_log_mode == MTR_LOG_ALL); + ut_ad(UT_LIST_GET_LEN(space.chain) == 1); + + log_write_and_flush_prepare(); + + const lsn_t start_lsn= finish_write(prepare_write()).first; + + mysql_mutex_lock(&log_sys.flush_order_mutex); + /* Durably write the reduced FSP_SIZE before truncating the data file. */ + log_write_and_flush(); + + os_file_truncate(space.chain.start->name, space.chain.start->handle, + os_offset_t{space.size} << srv_page_size_shift, true); + + if (m_freed_pages) + { + ut_ad(!m_freed_pages->empty()); + ut_ad(m_freed_space == &space); + ut_ad(memo_contains(*m_freed_space)); + ut_ad(is_named_space(m_freed_space)); + m_freed_space->update_last_freed_lsn(m_commit_lsn); + + if (!is_trim_pages()) + for (const auto &range : *m_freed_pages) + m_freed_space->add_free_range(range); + else + m_freed_space->clear_freed_ranges(); + delete m_freed_pages; + m_freed_pages= nullptr; + m_freed_space= nullptr; + /* mtr_t::start() will reset m_trim_pages */ + } + else + ut_ad(!m_freed_space); + + m_memo.for_each_block_in_reverse(CIterate<Shrink>{space}); + + m_memo.for_each_block_in_reverse(CIterate<const ReleaseBlocks> + (ReleaseBlocks(start_lsn, m_commit_lsn, + m_memo))); + mysql_mutex_unlock(&log_sys.flush_order_mutex); + + mysql_mutex_lock(&fil_system.mutex); + ut_ad(space.is_being_truncated); + ut_ad(space.is_stopping()); + space.clear_stopping(); + space.is_being_truncated= false; + mysql_mutex_unlock(&fil_system.mutex); + + m_memo.for_each_block_in_reverse(CIterate<ReleaseLatches>()); + srv_stats.log_write_requests.inc(); + + release_resources(); +} + /** Commit a mini-transaction that did not modify any pages, but generated some redo log on a higher level, such as FILE_MODIFY records and an optional FILE_CHECKPOINT marker. diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index 792a9b46e8a..e116c9efc98 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -1637,7 +1637,6 @@ row_fts_merge_insert( aux_table = dict_table_open_on_name(aux_table_name, false, DICT_ERR_IGNORE_NONE); ut_ad(aux_table != NULL); - aux_table->release(); aux_index = dict_table_get_first_index(aux_table); ut_ad(!aux_index->is_instant()); @@ -1762,6 +1761,8 @@ row_fts_merge_insert( } exit: + aux_table->release(); + fts_sql_commit(trx); trx->op_info = ""; diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index a22d75033c6..15f7796e0da 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -1809,7 +1809,9 @@ fewer_threads: if (history_size && trx_purge(n_use_threads, !(++count % srv_purge_rseg_truncate_frequency) || - purge_sys.truncate.current)) + purge_sys.truncate.current || + (srv_shutdown_state != SRV_SHUTDOWN_NONE && + srv_fast_shutdown == 0))) continue; if (m_running == sigcount) diff --git a/storage/innobase/sync/srw_lock.cc b/storage/innobase/sync/srw_lock.cc index 4cd4b56bdd0..f3c0afd64e3 100644 --- a/storage/innobase/sync/srw_lock.cc +++ b/storage/innobase/sync/srw_lock.cc @@ -223,6 +223,14 @@ template void ssux_lock_impl<false>::destroy(); template void ssux_lock_impl<false>::rd_unlock(); template void ssux_lock_impl<false>::u_unlock(); template void ssux_lock_impl<false>::wr_unlock(); +template void ssux_lock_impl<true>::init(); +template void ssux_lock_impl<true>::destroy(); +template void ssux_lock_impl<true>::read_lock(uint32_t); +template void ssux_lock_impl<true>::rd_unlock(); +template void ssux_lock_impl<true>::u_unlock(); +template void ssux_lock_impl<true>::wr_unlock(); +template void ssux_lock_impl<true>::write_lock(bool); +template void ssux_lock_impl<true>::update_lock(uint32_t); #else /* SUX_LOCK_GENERIC */ static_assert(4 == sizeof(rw_lock), "ABI"); # ifdef _WIN32 diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 866c6db4b7f..b2d602ad5b5 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -546,251 +546,255 @@ function is called, the caller must not have any latches on undo log pages! */ static void trx_purge_truncate_history() { - ut_ad(purge_sys.head <= purge_sys.tail); - purge_sys_t::iterator& head = purge_sys.head.trx_no - ? purge_sys.head : purge_sys.tail; - - if (head.trx_no >= purge_sys.low_limit_no()) { - /* This is sometimes necessary. TODO: find out why. */ - head.trx_no = purge_sys.low_limit_no(); - head.undo_no = 0; - } - - for (auto& rseg : trx_sys.rseg_array) { - if (rseg.space) { - trx_purge_truncate_rseg_history(rseg, head); - } - } - - if (srv_undo_tablespaces_active < 2) { - return; - } - - while (srv_undo_log_truncate) { - if (!purge_sys.truncate.current) { - const ulint threshold = ulint(srv_max_undo_log_size - >> srv_page_size_shift); - for (uint32_t i = purge_sys.truncate.last - ? purge_sys.truncate.last->id - - srv_undo_space_id_start - : 0, j = i;; ) { - uint32_t space_id = srv_undo_space_id_start - + i; - ut_ad(srv_is_undo_tablespace(space_id)); - fil_space_t* space= fil_space_get(space_id); - - if (space && space->get_size() > threshold) { - purge_sys.truncate.current = space; - break; - } - - ++i; - i %= srv_undo_tablespaces_active; - if (i == j) { - break; - } - } - } - - if (!purge_sys.truncate.current) { - return; - } - - fil_space_t& space = *purge_sys.truncate.current; - /* Undo tablespace always are a single file. */ - ut_a(UT_LIST_GET_LEN(space.chain) == 1); - fil_node_t* file = UT_LIST_GET_FIRST(space.chain); - /* The undo tablespace files are never closed. */ - ut_ad(file->is_open()); - - DBUG_LOG("undo", "marking for truncate: " << file->name); - - for (auto& rseg : trx_sys.rseg_array) { - if (rseg.space == &space) { - /* Once set, this rseg will - not be allocated to subsequent - transactions, but we will wait - for existing active - transactions to finish. */ - rseg.set_skip_allocation(); - } - } + ut_ad(purge_sys.head <= purge_sys.tail); + purge_sys_t::iterator &head= purge_sys.head.trx_no + ? purge_sys.head : purge_sys.tail; + + if (head.trx_no >= purge_sys.low_limit_no()) + { + /* This is sometimes necessary. TODO: find out why. */ + head.trx_no= purge_sys.low_limit_no(); + head.undo_no= 0; + } + + for (auto &rseg : trx_sys.rseg_array) + if (rseg.space) + trx_purge_truncate_rseg_history(rseg, head); + + if (srv_undo_tablespaces_active < 2) + return; - for (auto& rseg : trx_sys.rseg_array) { - if (rseg.space != &space) { - continue; - } - ut_ad(rseg.skip_allocation()); - if (rseg.is_referenced()) { - return; - } - rseg.latch.rd_lock(); - ut_ad(rseg.skip_allocation()); - if (rseg.is_referenced()) { + while (srv_undo_log_truncate) + { + if (!purge_sys.truncate.current) + { + const ulint threshold= + ulint(srv_max_undo_log_size >> srv_page_size_shift); + for (uint32_t i= purge_sys.truncate.last + ? purge_sys.truncate.last->id - srv_undo_space_id_start : 0, + j= i;; ) + { + const uint32_t space_id= srv_undo_space_id_start + i; + ut_ad(srv_is_undo_tablespace(space_id)); + fil_space_t *space= fil_space_get(space_id); + ut_a(UT_LIST_GET_LEN(space->chain) == 1); + + if (space && space->get_size() > threshold) + { + purge_sys.truncate.current= space; + break; + } + + ++i; + i %= srv_undo_tablespaces_active; + if (i == j) + return; + } + } + + fil_space_t &space= *purge_sys.truncate.current; + /* Undo tablespace always are a single file. */ + fil_node_t *file= UT_LIST_GET_FIRST(space.chain); + /* The undo tablespace files are never closed. */ + ut_ad(file->is_open()); + + DBUG_LOG("undo", "marking for truncate: " << file->name); + + for (auto &rseg : trx_sys.rseg_array) + if (rseg.space == &space) + /* Once set, this rseg will not be allocated to subsequent + transactions, but we will wait for existing active + transactions to finish. */ + rseg.set_skip_allocation(); + + for (auto &rseg : trx_sys.rseg_array) + { + if (rseg.space != &space) + continue; + rseg.latch.rd_lock(); + ut_ad(rseg.skip_allocation()); + if (rseg.is_referenced()) + { not_free: - rseg.latch.rd_unlock(); - return; - } - - if (rseg.curr_size != 1) { - /* Check if all segments are - cached and safe to remove. */ - ulint cached = 0; - - for (trx_undo_t* undo = UT_LIST_GET_FIRST( - rseg.undo_cached); - undo; - undo = UT_LIST_GET_NEXT(undo_list, - undo)) { - if (head.trx_no < undo->trx_id) { - goto not_free; - } else { - cached += undo->size; - } - } - - ut_ad(rseg.curr_size > cached); - - if (rseg.curr_size > cached + 1) { - goto not_free; - } - } - - rseg.latch.rd_unlock(); - } - - ib::info() << "Truncating " << file->name; - trx_purge_cleanse_purge_queue(space); - - /* Flush all to-be-discarded pages of the tablespace. - - During truncation, we do not want any writes to the - to-be-discarded area, because we must set the space.size - early in order to have deterministic page allocation. - - If a log checkpoint was completed at LSN earlier than our - mini-transaction commit and the server was killed, then - discarding the to-be-trimmed pages without flushing would - break crash recovery. So, we cannot avoid the write. */ - while (buf_flush_list_space(&space)); - - log_free_check(); - - /* Re-initialize tablespace, in a single mini-transaction. */ - mtr_t mtr; - const ulint size = SRV_UNDO_TABLESPACE_SIZE_IN_PAGES; - mtr.start(); - mtr.x_lock_space(&space); - - /* Adjust the tablespace metadata. */ - mysql_mutex_lock(&fil_system.mutex); - ut_d(bool stopped=) space.set_stopping(); - ut_ad(!stopped); - space.is_being_truncated = true; - if (space.crypt_data) { - space.reacquire(); - mysql_mutex_unlock(&fil_system.mutex); - fil_space_crypt_close_tablespace(&space); - space.release(); - } else { - mysql_mutex_unlock(&fil_system.mutex); - } - - uint i = 60; - - while (space.referenced()) { - if (!--i) { - mtr.commit(); - ib::error() << "Failed to freeze" - " UNDO tablespace " - << file->name; - return; - } - - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - - /* Associate the undo tablespace with mtr. - During mtr::commit(), InnoDB can use the undo - tablespace object to clear all freed ranges */ - mtr.set_named_space(&space); - mtr.trim_pages(page_id_t(space.id, size)); - fsp_header_init(&space, size, &mtr); - mysql_mutex_lock(&fil_system.mutex); - space.size = file->size = size; - mysql_mutex_unlock(&fil_system.mutex); - - buf_block_t* sys_header = trx_sysf_get(&mtr); - - for (auto& rseg : trx_sys.rseg_array) { - if (rseg.space != &space) { - continue; - } - - buf_block_t* rblock = trx_rseg_header_create( - purge_sys.truncate.current, - i, sys_header, &mtr); - ut_ad(rblock); - /* These were written by trx_rseg_header_create(). */ - ut_ad(!mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT - + rblock->frame)); - ut_ad(!mach_read_from_4(TRX_RSEG + TRX_RSEG_HISTORY_SIZE - + rblock->frame)); - rseg.reinit(rblock - ? rblock->page.id().page_no() : FIL_NULL); - } - - mtr.commit(); - /* Write-ahead the redo log record. */ - log_write_up_to(mtr.commit_lsn(), true); - - /* Trim the file size. */ - os_file_truncate(file->name, file->handle, - os_offset_t(size) << srv_page_size_shift, - true); - - /* This is only executed by srv_purge_coordinator_thread. */ - export_vars.innodb_undo_truncations++; - - /* In MDEV-8319 (10.5) we will PUNCH_HOLE the garbage - (with write-ahead logging). */ - mysql_mutex_lock(&fil_system.mutex); - ut_ad(&space == purge_sys.truncate.current); - ut_ad(space.is_being_truncated); - purge_sys.truncate.current->clear_stopping(); - purge_sys.truncate.current->is_being_truncated = false; - mysql_mutex_unlock(&fil_system.mutex); - - if (purge_sys.rseg != NULL - && purge_sys.rseg->last_page_no == FIL_NULL) { - /* If purge_sys.rseg is pointing to rseg that - was recently truncated then move to next rseg - element. Note: Ideally purge_sys.rseg should - be NULL because purge should complete - processing of all the records but there is - purge_batch_size that can force the purge loop - to exit before all the records are purged and - in this case purge_sys.rseg could point to a - valid rseg waiting for next purge cycle. */ - purge_sys.next_stored = false; - purge_sys.rseg = NULL; - } - - DBUG_EXECUTE_IF("ib_undo_trunc", - ib::info() << "ib_undo_trunc"; - log_buffer_flush_to_disk(); - DBUG_SUICIDE();); - - for (auto& rseg : trx_sys.rseg_array) { - if (rseg.space == &space) { - rseg.clear_skip_allocation(); - } - } - - ib::info() << "Truncated " << file->name; - purge_sys.truncate.last = purge_sys.truncate.current; - purge_sys.truncate.current = NULL; - } + rseg.latch.rd_unlock(); + return; + } + + if (rseg.curr_size != 1) + { + /* Check if all segments are cached and safe to remove. */ + ulint cached= 0; + for (trx_undo_t *undo= UT_LIST_GET_FIRST(rseg.undo_cached); undo; + undo= UT_LIST_GET_NEXT(undo_list, undo)) + { + if (head.trx_no < undo->trx_id) + goto not_free; + else + cached+= undo->size; + } + + ut_ad(rseg.curr_size > cached); + + if (rseg.curr_size > cached + 1) + goto not_free; + } + + rseg.latch.rd_unlock(); + } + + ib::info() << "Truncating " << file->name; + trx_purge_cleanse_purge_queue(space); + + log_free_check(); + + mtr_t mtr; + mtr.start(); + mtr.x_lock_space(&space); + + /* Lock all modified pages of the tablespace. + + During truncation, we do not want any writes to the file. + + If a log checkpoint was completed at LSN earlier than our + mini-transaction commit and the server was killed, then + discarding the to-be-trimmed pages without flushing would + break crash recovery. */ + mysql_mutex_lock(&buf_pool.flush_list_mutex); + + for (buf_page_t *bpage= UT_LIST_GET_LAST(buf_pool.flush_list); bpage; ) + { + ut_ad(bpage->oldest_modification()); + ut_ad(bpage->in_file()); + + buf_page_t *prev= UT_LIST_GET_PREV(list, bpage); + + if (bpage->id().space() == space.id && + bpage->oldest_modification() != 1) + { + ut_ad(bpage->state() == BUF_BLOCK_FILE_PAGE); + auto block= reinterpret_cast<buf_block_t*>(bpage); + block->fix(); + buf_pool.flush_hp.set(prev); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + +#ifdef BTR_CUR_HASH_ADAPT + ut_ad(!block->index); /* There is no AHI on undo tablespaces. */ +#endif + block->lock.x_lock(); + mysql_mutex_lock(&buf_pool.flush_list_mutex); + ut_ad(bpage->io_fix() == BUF_IO_NONE); + + if (bpage->oldest_modification() > 1) + { + bpage->clear_oldest_modification(false); + mtr.memo_push(block, MTR_MEMO_PAGE_X_FIX); + } + else + { + block->lock.x_unlock(); + block->unfix(); + } + + if (prev != buf_pool.flush_hp.get()) + { + /* Rescan, because we may have lost the position. */ + bpage= UT_LIST_GET_LAST(buf_pool.flush_list); + continue; + } + } + + bpage= prev; + } + + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + + /* Re-initialize tablespace, in a single mini-transaction. */ + const ulint size= SRV_UNDO_TABLESPACE_SIZE_IN_PAGES; + + /* Adjust the tablespace metadata. */ + mysql_mutex_lock(&fil_system.mutex); + space.set_stopping(); + space.is_being_truncated= true; + if (space.crypt_data) + { + space.reacquire(); + mysql_mutex_unlock(&fil_system.mutex); + fil_space_crypt_close_tablespace(&space); + space.release(); + } + else + mysql_mutex_unlock(&fil_system.mutex); + + for (auto i= 6000; space.referenced(); + std::this_thread::sleep_for(std::chrono::milliseconds(10))) + { + if (!--i) + { + mtr.commit(); + ib::error() << "Failed to freeze UNDO tablespace " << file->name; + return; + } + } + + /* Associate the undo tablespace with mtr. + During mtr::commit_shrink(), InnoDB can use the undo + tablespace object to clear all freed ranges */ + mtr.set_named_space(&space); + mtr.trim_pages(page_id_t(space.id, size)); + fsp_header_init(&space, size, &mtr); + mysql_mutex_lock(&fil_system.mutex); + space.size= file->size= size; + mysql_mutex_unlock(&fil_system.mutex); + + buf_block_t *sys_header= trx_sysf_get(&mtr); + + for (auto &rseg : trx_sys.rseg_array) + { + if (rseg.space != &space) + continue; + + buf_block_t *rblock= trx_rseg_header_create(&space, + &rseg - trx_sys.rseg_array, + trx_sys.get_max_trx_id(), + sys_header, &mtr); + ut_ad(rblock); + /* These were written by trx_rseg_header_create(). */ + ut_ad(!mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT + rblock->frame)); + ut_ad(!mach_read_from_4(TRX_RSEG + TRX_RSEG_HISTORY_SIZE + + rblock->frame)); + rseg.reinit(rblock ? rblock->page.id().page_no() : FIL_NULL); + } + + mtr.commit_shrink(space); + + /* No mutex; this is only updated by the purge coordinator. */ + export_vars.innodb_undo_truncations++; + + if (purge_sys.rseg && purge_sys.rseg->last_page_no == FIL_NULL) + { + /* If purge_sys.rseg is pointing to rseg that was recently + truncated then move to next rseg element. + + Note: Ideally purge_sys.rseg should be NULL because purge should + complete processing of all the records but srv_purge_batch_size + can force the purge loop to exit before all the records are purged. */ + purge_sys.rseg= nullptr; + purge_sys.next_stored= false; + } + + DBUG_EXECUTE_IF("ib_undo_trunc", ib::info() << "ib_undo_trunc"; + log_buffer_flush_to_disk(); + DBUG_SUICIDE();); + + for (auto &rseg : trx_sys.rseg_array) + if (rseg.space == &space) + rseg.clear_skip_allocation(); + + ib::info() << "Truncated " << file->name; + purge_sys.truncate.last= purge_sys.truncate.current; + ut_ad(&space == purge_sys.truncate.current); + purge_sys.truncate.current= nullptr; + } } /***********************************************************************//** diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc index 50ffbe0a138..3e392e1df48 100644 --- a/storage/innobase/trx/trx0rseg.cc +++ b/storage/innobase/trx/trx0rseg.cc @@ -316,6 +316,7 @@ void trx_rseg_format_upgrade(buf_block_t *rseg_header, mtr_t *mtr) /** Create a rollback segment header. @param[in,out] space system, undo, or temporary tablespace @param[in] rseg_id rollback segment identifier +@param[in] max_trx_id new value of TRX_RSEG_MAX_TRX_ID @param[in,out] sys_header the TRX_SYS page (NULL for temporary rseg) @param[in,out] mtr mini-transaction @return the created rollback segment @@ -324,6 +325,7 @@ buf_block_t* trx_rseg_header_create( fil_space_t* space, ulint rseg_id, + trx_id_t max_trx_id, buf_block_t* sys_header, mtr_t* mtr) { @@ -344,10 +346,16 @@ trx_rseg_header_create( + block->frame)); ut_ad(0 == mach_read_from_4(TRX_RSEG_HISTORY_SIZE + TRX_RSEG + block->frame)); + ut_ad(0 == mach_read_from_4(TRX_RSEG_MAX_TRX_ID + TRX_RSEG + + block->frame)); /* Initialize the history list */ flst_init(block, TRX_RSEG_HISTORY + TRX_RSEG, mtr); + mtr->write<8,mtr_t::MAYBE_NOP>(*block, + TRX_RSEG + TRX_RSEG_MAX_TRX_ID + + block->frame, max_trx_id); + /* Reset the undo log slots */ mtr->memset(block, TRX_RSEG_UNDO_SLOTS + TRX_RSEG, TRX_RSEG_N_SLOTS * 4, 0xff); @@ -695,7 +703,7 @@ void trx_temp_rseg_create() mtr.x_lock_space(fil_system.temp_space); buf_block_t* rblock = trx_rseg_header_create( - fil_system.temp_space, i, NULL, &mtr); + fil_system.temp_space, i, 0, NULL, &mtr); trx_sys.temp_rsegs[i].init(fil_system.temp_space, rblock->page.id().page_no()); mtr.commit(); diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index 10991ce3f39..65ac991bb68 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -191,7 +191,7 @@ trx_sysf_create( /* Create the first rollback segment in the SYSTEM tablespace */ slot_no = trx_sys_rseg_find_free(block); buf_block_t* rblock = trx_rseg_header_create(fil_system.sys_space, - slot_no, block, mtr); + slot_no, 0, block, mtr); ut_a(slot_no == TRX_SYS_SYSTEM_RSEG_ID); ut_a(rblock->page.id() == page_id_t(0, FSP_FIRST_RSEG_PAGE_NO)); @@ -293,7 +293,7 @@ static trx_rseg_t *trx_rseg_create(uint32_t space_id) { ulint rseg_id= trx_sys_rseg_find_free(sys_header); if (buf_block_t *rblock= rseg_id == ULINT_UNDEFINED - ? nullptr : trx_rseg_header_create(space, rseg_id, sys_header, + ? nullptr : trx_rseg_header_create(space, rseg_id, 0, sys_header, &mtr)) { ut_ad(trx_sysf_rseg_get_space(sys_header, rseg_id) == space_id); diff --git a/storage/spider/mysql-test/spider/r/udf_pushdown.result b/storage/spider/mysql-test/spider/r/udf_pushdown.result new file mode 100644 index 00000000000..4ca734165e7 --- /dev/null +++ b/storage/spider/mysql-test/spider/r/udf_pushdown.result @@ -0,0 +1,218 @@ +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 +child3_1 +child3_2 +child3_3 +# +# MDEV-26545 Spider does not correctly handle UDF and stored function in where conds +# + +##### enable general_log ##### +connection child2_1; +SET @general_log_backup = @@global.general_log; +SET @log_output_backup = @@global.log_output; +SET @@global.general_log = 1; +SET @@global.log_output = "TABLE"; +TRUNCATE TABLE mysql.general_log; + +##### create databases ##### +connection master_1; +CREATE DATABASE auto_test_local; +USE auto_test_local; +connection child2_1; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; + +##### create tables ##### +connection child2_1; +CHILD_CREATE_TABLE +connection master_1; +MASTER_CREATE_TABLE +CREATE TABLE ta_l ( +id INT NOT NULL, +a INT, +PRIMARY KEY(id) +) MASTER_1_ENGINE MASTER_1_CHARSET MASTER_1_COMMENT_2_1 +INSERT INTO ta_l VALUES +(1, 11), +(2, 22), +(3, 33), +(4, 44), +(5, 55); + +##### create functions ##### +connection master_1; +CREATE FUNCTION `plusone`( param INT ) RETURNS INT +BEGIN +RETURN param + 1; +END // +connection child2_1; +CREATE FUNCTION `plusone`( param INT ) RETURNS INT +BEGIN +RETURN param + 1; +END // + +########## spider_use_pushdown_udf=0 ########## +connection master_1; +SET @@spider_use_pushdown_udf = 0; + +##### test SELECTs ##### +connection master_1; +SELECT * FROM ta_l WHERE id = plusone(1); +id a +2 22 +SELECT * FROM ta_l WHERE id IN (plusone(1), plusone(2)) AND a = plusone(32); +id a +3 33 +connection child2_1; +SELECT argument FROM mysql.general_log WHERE argument LIKE "%select%" AND argument NOT LIKE "%argument%"; +argument +select `id`,`a` from `auto_test_remote`.`ta_r` +select `id`,`a` from `auto_test_remote`.`ta_r` + +##### test UPDATEs ##### +connection master_1; +UPDATE ta_l SET a = plusone(221) WHERE id = plusone(1); +SELECT * FROM ta_l; +id a +1 11 +2 222 +3 33 +4 44 +5 55 +UPDATE ta_l SET a = plusone(332) WHERE id IN (plusone(1), plusone(2)) AND a = plusone(32); +SELECT * FROM ta_l; +id a +1 11 +2 222 +3 333 +4 44 +5 55 +connection child2_1; +SELECT argument FROM mysql.general_log WHERE argument LIKE "%update%" AND argument NOT LIKE "%argument%"; +argument +select `id`,`a` from `auto_test_remote`.`ta_r` for update +update `auto_test_remote`.`ta_r` set `a` = 222 where `id` = 2 limit 1 +select `id`,`a` from `auto_test_remote`.`ta_r` for update +update `auto_test_remote`.`ta_r` set `a` = 333 where `id` = 3 and `a` = 33 limit 1 + +##### test DELETEs ##### +connection master_1; +DELETE FROM ta_l WHERE id = plusone(1); +SELECT * FROM ta_l; +id a +1 11 +3 333 +4 44 +5 55 +DELETE FROM ta_l WHERE id IN (plusone(1), plusone(2), plusone(3)) AND a = plusone(43); +SELECT * FROM ta_l; +id a +1 11 +3 333 +5 55 +connection child2_1; +SELECT argument FROM mysql.general_log WHERE (argument LIKE "%delete%" OR argument LIKE "%update%") AND argument NOT LIKE "%argument%"; +argument +select `id` from `auto_test_remote`.`ta_r` for update +delete from `auto_test_remote`.`ta_r` where `id` = 2 limit 1 +select `id`,`a` from `auto_test_remote`.`ta_r` for update +delete from `auto_test_remote`.`ta_r` where `id` = 4 and `a` = 44 limit 1 + +##### reset records ##### +connection master_1; +TRUNCATE TABLE ta_l; +INSERT INTO ta_l VALUES +(1, 11), +(2, 22), +(3, 33), +(4, 44), +(5, 55); + +########## spider_use_pushdown_udf=1 ########## +connection master_1; +SET @@spider_use_pushdown_udf = 1; + +##### test SELECTs ##### +connection master_1; +SELECT * FROM ta_l WHERE id = plusone(1); +id a +2 22 +SELECT * FROM ta_l WHERE id IN (plusone(1), plusone(2)) AND a = plusone(32); +id a +3 33 +connection child2_1; +SELECT argument FROM mysql.general_log WHERE argument LIKE "%select%" AND argument NOT LIKE "%argument%"; +argument +select t0.`id` `id`,t0.`a` `a` from `auto_test_remote`.`ta_r` t0 where (t0.`id` = (`plusone`(1))) +select t0.`id` `id`,t0.`a` `a` from `auto_test_remote`.`ta_r` t0 where ((t0.`id` in( (`plusone`(1)) , (`plusone`(2)))) and (t0.`a` = (`plusone`(32)))) + +##### test UPDATEs ##### +connection master_1; +UPDATE ta_l SET a = plusone(221) WHERE id = plusone(1); +SELECT * FROM ta_l; +id a +1 11 +2 222 +3 33 +4 44 +5 55 +UPDATE ta_l SET a = plusone(332) WHERE id IN (plusone(1), plusone(2)) AND a = plusone(32); +SELECT * FROM ta_l; +id a +1 11 +2 222 +3 333 +4 44 +5 55 +connection child2_1; +SELECT argument FROM mysql.general_log WHERE argument LIKE "%update%" AND argument NOT LIKE "%argument%"; +argument +update `auto_test_remote`.`ta_r` set `a` = (`plusone`(221)) where (`id` = (`plusone`(1))) +update `auto_test_remote`.`ta_r` set `a` = (`plusone`(332)) where ((`id` in( (`plusone`(1)) , (`plusone`(2)))) and (`a` = (`plusone`(32)))) + +##### test DELETEs ##### +connection master_1; +DELETE FROM ta_l WHERE id = plusone(1); +SELECT * FROM ta_l; +id a +1 11 +3 333 +4 44 +5 55 +DELETE FROM ta_l WHERE id IN (plusone(1), plusone(2), plusone(3)) AND a = plusone(43); +SELECT * FROM ta_l; +id a +1 11 +3 333 +5 55 +connection child2_1; +SELECT argument FROM mysql.general_log WHERE (argument LIKE "%delete%" OR argument LIKE "%update%") AND argument NOT LIKE "%argument%"; +argument +delete from `auto_test_remote`.`ta_r` where (`id` = (`plusone`(1))) +delete from `auto_test_remote`.`ta_r` where ((`id` in( (`plusone`(1)) , (`plusone`(2)) , (`plusone`(3)))) and (`a` = (`plusone`(43)))) + +deinit +connection master_1; +DROP FUNCTION `plusone`; +DROP DATABASE IF EXISTS auto_test_local; +connection child2_1; +SET @@global.general_log = @general_log_backup; +SET @@global.log_output = @log_output_backup; +DROP FUNCTION `plusone`; +DROP DATABASE IF EXISTS auto_test_remote; +for master_1 +for child2 +child2_1 +child2_2 +child2_3 +for child3 +child3_1 +child3_2 +child3_3 + +end of test diff --git a/storage/spider/mysql-test/spider/t/udf_pushdown.inc b/storage/spider/mysql-test/spider/t/udf_pushdown.inc new file mode 100644 index 00000000000..160e8af21b2 --- /dev/null +++ b/storage/spider/mysql-test/spider/t/udf_pushdown.inc @@ -0,0 +1,48 @@ +--echo +--echo ##### test SELECTs ##### +--connection master_1 +SELECT * FROM ta_l WHERE id = plusone(1); +SELECT * FROM ta_l WHERE id IN (plusone(1), plusone(2)) AND a = plusone(32); + +if ($USE_CHILD_GROUP2) +{ + --connection child2_1 + SELECT argument FROM mysql.general_log WHERE argument LIKE "%select%" AND argument NOT LIKE "%argument%"; + --disable_query_log + TRUNCATE TABLE mysql.general_log; + --enable_query_log +} + +--echo +--echo ##### test UPDATEs ##### +--connection master_1 +UPDATE ta_l SET a = plusone(221) WHERE id = plusone(1); +SELECT * FROM ta_l; +UPDATE ta_l SET a = plusone(332) WHERE id IN (plusone(1), plusone(2)) AND a = plusone(32); +SELECT * FROM ta_l; + +if ($USE_CHILD_GROUP2) +{ + --connection child2_1 + SELECT argument FROM mysql.general_log WHERE argument LIKE "%update%" AND argument NOT LIKE "%argument%"; + --disable_query_log + TRUNCATE TABLE mysql.general_log; + --enable_query_log +} + +--echo +--echo ##### test DELETEs ##### +--connection master_1 +DELETE FROM ta_l WHERE id = plusone(1); +SELECT * FROM ta_l; +DELETE FROM ta_l WHERE id IN (plusone(1), plusone(2), plusone(3)) AND a = plusone(43); +SELECT * FROM ta_l; + +if ($USE_CHILD_GROUP2) +{ + --connection child2_1 + SELECT argument FROM mysql.general_log WHERE (argument LIKE "%delete%" OR argument LIKE "%update%") AND argument NOT LIKE "%argument%"; + --disable_query_log + TRUNCATE TABLE mysql.general_log; + --enable_query_log +} diff --git a/storage/spider/mysql-test/spider/t/udf_pushdown.test b/storage/spider/mysql-test/spider/t/udf_pushdown.test new file mode 100644 index 00000000000..2eadbbbb40b --- /dev/null +++ b/storage/spider/mysql-test/spider/t/udf_pushdown.test @@ -0,0 +1,141 @@ +--disable_warnings +--disable_query_log +--disable_result_log +--source test_init.inc +--enable_result_log +--enable_query_log + +--echo # +--echo # MDEV-26545 Spider does not correctly handle UDF and stored function in where conds +--echo # + +let $CHILD_CREATE_TABLE= + CREATE TABLE ta_r ( + id INT NOT NULL, + a INT, + PRIMARY KEY(id) + ) $CHILD2_1_ENGINE $CHILD2_1_CHARSET; + +let $MASTER_CREATE_TABLE_OUTPUT= + CREATE TABLE ta_l ( + id INT NOT NULL, + a INT, + PRIMARY KEY(id) + ) MASTER_1_ENGINE MASTER_1_CHARSET MASTER_1_COMMENT_2_1; + +let $MASTER_CREATE_TABLE= + CREATE TABLE ta_l ( + id INT NOT NULL, + a INT, + PRIMARY KEY(id) + ) $MASTER_1_ENGINE $MASTER_1_CHARSET $MASTER_1_COMMENT_2_1; + +--echo +--echo ##### enable general_log ##### +--connection child2_1 +SET @general_log_backup = @@global.general_log; +SET @log_output_backup = @@global.log_output; +SET @@global.general_log = 1; +SET @@global.log_output = "TABLE"; +TRUNCATE TABLE mysql.general_log; + +--echo +--echo ##### create databases ##### +--connection master_1 +CREATE DATABASE auto_test_local; +USE auto_test_local; +if ($USE_CHILD_GROUP2) +{ + --connection child2_1 + CREATE DATABASE auto_test_remote; + USE auto_test_remote; +} + +--echo +--echo ##### create tables ##### +if ($USE_CHILD_GROUP2) +{ + --connection child2_1 + --disable_query_log + echo CHILD_CREATE_TABLE; + eval $CHILD_CREATE_TABLE; + --enable_query_log +} + +--connection master_1 +--disable_query_log +echo MASTER_CREATE_TABLE; +echo $MASTER_CREATE_TABLE_OUTPUT; +eval $MASTER_CREATE_TABLE; +--enable_query_log + +INSERT INTO ta_l VALUES + (1, 11), + (2, 22), + (3, 33), + (4, 44), + (5, 55); + +--echo +--echo ##### create functions ##### +--connection master_1 +DELIMITER //; +CREATE FUNCTION `plusone`( param INT ) RETURNS INT +BEGIN + RETURN param + 1; +END // +DELIMITER ;// + +--connection child2_1 +DELIMITER //; +CREATE FUNCTION `plusone`( param INT ) RETURNS INT +BEGIN + RETURN param + 1; +END // +DELIMITER ;// + +--echo +--echo ########## spider_use_pushdown_udf=0 ########## +--connection master_1 +SET @@spider_use_pushdown_udf = 0; +--source udf_pushdown.inc + +--echo +--echo ##### reset records ##### +--connection master_1 +TRUNCATE TABLE ta_l; +INSERT INTO ta_l VALUES + (1, 11), + (2, 22), + (3, 33), + (4, 44), + (5, 55); + +--echo +--echo ########## spider_use_pushdown_udf=1 ########## +--connection master_1 +SET @@spider_use_pushdown_udf = 1; +--source udf_pushdown.inc + +--echo +--echo deinit +--disable_warnings +--connection master_1 +DROP FUNCTION `plusone`; +DROP DATABASE IF EXISTS auto_test_local; +if ($USE_CHILD_GROUP2) +{ + --connection child2_1 + SET @@global.general_log = @general_log_backup; + SET @@global.log_output = @log_output_backup; + DROP FUNCTION `plusone`; + DROP DATABASE IF EXISTS auto_test_remote; +} +--disable_query_log +--disable_result_log +--source test_deinit.inc +--enable_result_log +--enable_query_log +--enable_warnings +--echo +--echo end of test diff --git a/storage/spider/spd_db_mysql.cc b/storage/spider/spd_db_mysql.cc index 10b4fb7cee4..62e6e2f1245 100644 --- a/storage/spider/spd_db_mysql.cc +++ b/storage/spider/spd_db_mysql.cc @@ -6676,11 +6676,17 @@ int spider_db_mbase_util::open_item_func( separator_str_length = SPIDER_SQL_AND_LEN; } break; + case Item_func::FUNC_SP: case Item_func::UDF_FUNC: use_pushdown_udf = spider_param_use_pushdown_udf( spider->wide_handler->trx->thd, spider->share->use_pushdown_udf); if (!use_pushdown_udf) + /* + This is the default behavior because the remote nodes may deal with + the function in an unexpected way (e.g. not having the same + definition). Users can turn it on if they know what they are doing. + */ DBUG_RETURN(ER_SPIDER_COND_SKIP_NUM); if (str) { diff --git a/storage/spider/spd_param.cc b/storage/spider/spd_param.cc index ec0949b579f..b23877ca92a 100644 --- a/storage/spider/spd_param.cc +++ b/storage/spider/spd_param.cc @@ -2005,7 +2005,7 @@ static MYSQL_THDVAR_INT( "Remote server transmission existence when UDF is used at condition and \"engine_condition_pushdown=1\"", /* comment */ NULL, /* check */ NULL, /* update */ - -1, /* def */ + 0, /* def */ -1, /* min */ 1, /* max */ 0 /* blk */ diff --git a/wsrep-lib b/wsrep-lib -Subproject 4f1c201c9d8ba96f9f43e9aafe8bb6a6c8aeceb +Subproject efb4aab090cb9c1b57b9e7f9988ae1c41f48344 |