From 209e44c1a2921423acc51eae888aa16293153619 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 14 May 2003 13:49:43 +0300 Subject: [PATCH 01/40] Fixed documentation for mysql_fix_privilege_tables man page. Bug ID: 384 --- man/mysql_fix_privilege_tables.1 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/man/mysql_fix_privilege_tables.1 b/man/mysql_fix_privilege_tables.1 index bf4e0e15dfa..4ed81368098 100644 --- a/man/mysql_fix_privilege_tables.1 +++ b/man/mysql_fix_privilege_tables.1 @@ -2,7 +2,7 @@ .SH NAME mysql_fix_privilege_tables \- Fixes MySQL privilege tables. .SH SYNOPSIS -mysql_fix_privilege_tables [options] +mysql_fix_privilege_tables [mysql_root_password] .SH DESCRIPTION This scripts updates the mysql.user, mysql.db, mysql.host and the mysql.func tables to MySQL 3.22.14 and above. @@ -10,10 +10,9 @@ mysql.func tables to MySQL 3.22.14 and above. This is needed if you want to use the new GRANT functions, CREATE AGGREGATE FUNCTION or want to use the more secure passwords in 3.23 -If you get 'Access denied' errors, you should run this script again -and give the MySQL root user password as an argument! +If you get 'Access denied' errors, run the script again +and give the MySQL root user password as an argument. -For more information start the program with '--help'. .SH "SEE ALSO" mysql (1), mysqld (1) .SH AUTHOR From 8b87a1aa0e6328a67c2c72f11612134ed5eb7597 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 14 May 2003 16:47:55 +0300 Subject: [PATCH 02/40] Fixed a bug with having comments after options in config files. Bug ID: 235 --- mysys/default.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/mysys/default.c b/mysys/default.c index c47d2719ab5..3ff240da3a1 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -72,6 +72,7 @@ static my_bool search_default_file(DYNAMIC_ARRAY *args,MEM_ROOT *alloc, const char *dir, const char *config_file, const char *ext, TYPELIB *group); +static char *remove_end_comment(char *ptr); void load_defaults(const char *conf_file, const char **groups, int *argc, char ***argv) @@ -297,9 +298,11 @@ static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, } if (!read_values) continue; - if (!(end=value=strchr(ptr,'='))) - end=strend(ptr); /* Option without argument */ + end= remove_end_comment(ptr); + if ((value= strchr(ptr, '='))) + end= value; /* Option without argument */ for ( ; isspace(end[-1]) ; end--) ; + if (!value) { if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3))) @@ -368,6 +371,29 @@ static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, } +static char *remove_end_comment(char *ptr) +{ + char quote= 0; + + for (; *ptr; ptr++) + { + if (*ptr == '\'' || *ptr == '\"') + { + if (!quote) + quote= *ptr; + else if (quote == *ptr) + quote= 0; + } + if (!quote && *ptr == '#') /* We are not inside a comment */ + { + *ptr= 0; + return ptr; + } + } + return ptr; +} + + void print_defaults(const char *conf_file, const char **groups) { #ifdef __WIN__ From 32592ab8c1a331f3bbd52dbd62f738ba82d29ea6 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 19 May 2003 16:36:50 +0200 Subject: [PATCH 03/40] - Tagged ChangeSet 1.1497 as "mysql-4.0.13" - Updated version number in configure.in to 4.0.14 now that 4.0.13 has been tagged configure.in: - Updated version number to 4.0.14 now that 4.0.13 has been tagged --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index c7cf4f66b70..df83f7e715e 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! -AM_INIT_AUTOMAKE(mysql, 4.0.13) +AM_INIT_AUTOMAKE(mysql, 4.0.14) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 From 530accbaae6d243885d5bcc5b04d55b61bd87ce7 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 21 May 2003 14:54:02 -0400 Subject: [PATCH 04/40] fixed 'STARTING BY' in replication mysql-test/r/rpl_loaddata.result: added test for 'STARTING BY' mysql-test/std_data/rpl_loaddata2.dat: added test for 'STARTING BY' mysql-test/t/rpl_loaddata.test: added test for 'STARTING BY' sql/log_event.cc: fixed 'STARTING BY' --- mysql-test/r/rpl_loaddata.result | 2 +- mysql-test/std_data/rpl_loaddata2.dat | 8 ++++---- mysql-test/t/rpl_loaddata.test | 3 +-- sql/log_event.cc | 12 ++++++++++-- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/rpl_loaddata.result b/mysql-test/r/rpl_loaddata.result index c1518e8e29a..62071a07d0c 100644 --- a/mysql-test/r/rpl_loaddata.result +++ b/mysql-test/r/rpl_loaddata.result @@ -7,7 +7,7 @@ slave start; create table t1(a int not null auto_increment, b int, primary key(a) ); load data infile '../../std_data/rpl_loaddata.dat' into table t1; create temporary table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60)); -load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' ignore 1 lines; +load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' starting by '>' ignore 1 lines; create table t3 (day date,id int(9),category enum('a','b','c'),name varchar(60)); insert into t3 select * from t2; select * from t1; diff --git a/mysql-test/std_data/rpl_loaddata2.dat b/mysql-test/std_data/rpl_loaddata2.dat index 7a3d4ea7695..b883d9dcd58 100644 --- a/mysql-test/std_data/rpl_loaddata2.dat +++ b/mysql-test/std_data/rpl_loaddata2.dat @@ -1,8 +1,8 @@ -2003-01-21,6328,%a%,%aaaaa% +>2003-01-21,6328,%a%,%aaaaa% ## -2003-02-22,2461,b,%a a a @@ @% @b ' " a% +>2003-02-22,2461,b,%a a a @@ @% @b ' " a% ## -2003-03-22,2161,%c%,%asdf% +>2003-03-22,2161,%c%,%asdf% ## -2003-04-22,2416,%a%,%bbbbb% +>2003-04-22,2416,%a%,%bbbbb% ## diff --git a/mysql-test/t/rpl_loaddata.test b/mysql-test/t/rpl_loaddata.test index 2acb67dfce2..1f34aa9d3f9 100644 --- a/mysql-test/t/rpl_loaddata.test +++ b/mysql-test/t/rpl_loaddata.test @@ -10,8 +10,7 @@ create table t1(a int not null auto_increment, b int, primary key(a) ); load data infile '../../std_data/rpl_loaddata.dat' into table t1; create temporary table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60)); -#load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionaly enclosed by '%' escaped by '@' lines terminated by '\n%%\n' ignore 1 lines; - load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' ignore 1 lines; +load data infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' starting by '>' ignore 1 lines; create table t3 (day date,id int(9),category enum('a','b','c'),name varchar(60)); insert into t3 select * from t2; diff --git a/sql/log_event.cc b/sql/log_event.cc index 3b499b8d502..dfa44e19ffc 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -309,15 +309,19 @@ void Load_log_event::pack_info(String* packet) pretty_print_str(&tmp, sql_ex.escaped, sql_ex.escaped_len); } + bool line_lexem_added= false; if (sql_ex.line_term_len) { tmp.append(" LINES TERMINATED BY "); pretty_print_str(&tmp, sql_ex.line_term, sql_ex.line_term_len); + line_lexem_added= true; } if (sql_ex.line_start_len) { - tmp.append(" LINES STARTING BY "); + if (!line_lexem_added) + tmp.append(" LINES"); + tmp.append(" STARTING BY "); pretty_print_str(&tmp, sql_ex.line_start, sql_ex.line_start_len); } @@ -1299,15 +1303,19 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db) pretty_print_str(file, sql_ex.escaped, sql_ex.escaped_len); } + bool line_lexem_added= false; if (sql_ex.line_term) { fprintf(file," LINES TERMINATED BY "); pretty_print_str(file, sql_ex.line_term, sql_ex.line_term_len); + line_lexem_added= true; } if (sql_ex.line_start) { - fprintf(file," LINES STARTING BY "); + if (!line_lexem_added) + fprintf(file," LINES"); + fprintf(file," STARTING BY "); pretty_print_str(file, sql_ex.line_start, sql_ex.line_start_len); } From b76adc62fbccc85f08563bffc5e2d91b21adf1d0 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 21 May 2003 21:58:12 +0300 Subject: [PATCH 05/40] repair_part2 is made repeatable --- mysql-test/mysql-test-run.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 7ce6ffe14af..65f40c5dc73 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -19,6 +19,8 @@ TZ=GMT-3; export TZ # for UNIX_TIMESTAMP tests to work # Program Definitions #-- +LC_COLLATE=C +export LC_COLLATE PATH=/bin:/usr/bin:/usr/local/bin:/usr/bsd:/usr/X11R6/bin:/usr/openwin/bin:/usr/bin/X11:$PATH MASTER_40_ARGS="--rpl-recovery-rank=1 --init-rpl-role=master" From bddd75d28eba0c5dade8facd7484d0ad67f20176 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 21 May 2003 15:16:56 -0400 Subject: [PATCH 06/40] fixed "LINES STARTING" in load data replication BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted --- BitKeeper/etc/logging_ok | 1 + sql/log_event.cc | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index a6699f7c515..705b336440b 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -35,5 +35,6 @@ serg@build.mysql2.com serg@serg.mysql.com serg@sergbook.mysql.com sinisa@rhols221.adsl.netsonic.fi +vva@eagle.mysql.r18.ru walrus@mysql.com zak@balfor.local diff --git a/sql/log_event.cc b/sql/log_event.cc index 7c4c893a823..9cf67e78029 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -697,15 +697,19 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db) pretty_print_char(file, sql_ex.escaped); } + bool line_lexem_added= false; if(!(sql_ex.empty_flags & LINE_TERM_EMPTY)) { fprintf(file," LINES TERMINATED BY "); pretty_print_char(file, sql_ex.line_term); + line_lexem_added= true; } if(!(sql_ex.empty_flags & LINE_START_EMPTY)) { - fprintf(file," LINES STARTING BY "); + if (!line_lexem_added) + fprintf(file," LINES"); + fprintf(file," STARTING BY "); pretty_print_char(file, sql_ex.line_start); } From eb4755c90e6f112277083fedbbe53faf922e65b3 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 22 May 2003 00:05:33 +0300 Subject: [PATCH 07/40] row0ins.c: Disable UNIQU KEY error reporting in SHOW INNODB STATUS until we know if it slows down REPLACE significantly innobase/row/row0ins.c: Disable UNIQU KEY error reporting in SHOW INNODB STATUS until we know if it slows down REPLACE significantly --- innobase/row/row0ins.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 3af9e1b752b..e96c08a715b 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -1275,6 +1275,10 @@ row_ins_unique_report_err( dtuple_t* entry, /* in: index entry to insert in the index */ dict_index_t* index) /* in: index */ { +#ifdef notdefined + /* Disable reporting to test if the slowdown of REPLACE in 4.0.13 was + caused by this! */ + char* buf = dict_unique_err_buf; /* The foreign err mutex protects also dict_unique_err_buf */ @@ -1303,6 +1307,7 @@ row_ins_unique_report_err( ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); mutex_exit(&dict_foreign_err_mutex); +#endif } /******************************************************************* From f985f468ef02549ad512ff0eccdc170900f6d0cd Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 May 2003 11:38:37 +0200 Subject: [PATCH 08/40] - Portability fix: FreeBSD 4.8-STABLE (480101) and 5.0-CURRENT (500110) now have a thread safe realpath(3) implementation - added check to only define -DHAVE_BROKEN_REALPATH where required (thanks to Martin Blapp from the FreeBSD team for the patch) configure.in: - FreeBSD 4.8-STABLE (480101) and 5.0-CURRENT (500110) now have a thread safe realpath(3) implementation - added check to only define -DHAVE_BROKEN_REALPATH where required --- configure.in | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index df83f7e715e..8a5ab75a494 100644 --- a/configure.in +++ b/configure.in @@ -1025,8 +1025,16 @@ case $SYSTEM_TYPE in ;; *freebsd*) echo "Adding fix for interrupted reads" - CFLAGS="$CFLAGS -DHAVE_BROKEN_REALPATH" - CXXFLAGS="$CXXFLAGS -DMYSQLD_NET_RETRY_COUNT=1000000 -DHAVE_BROKEN_REALPATH" + OSVERSION=`sysctl -a | grep osreldate | awk '{ print $2 }'` + if test "$OSVERSION" -gt "480100" && \ + test "$OSVERSION" -lt "500000" || \ + test "$OSVERSION" -gt "500109" + then + CXXFLAGS="$CXXFLAGS -DMYSQLD_NET_RETRY_COUNT=1000000" + else + CFLAGS="$CFLAGS -DHAVE_BROKEN_REALPATH" + CXXFLAGS="$CXXFLAGS -DMYSQLD_NET_RETRY_COUNT=1000000 -DHAVE_BROKEN_REALPATH" + fi ;; *netbsd*) echo "Adding flag -Dunix" From 7dcf24a3a49802897cc75ca37191d8dc0db1bdd6 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 May 2003 16:40:21 +0200 Subject: [PATCH 09/40] Fix for #468 [Ver]: SHOW VARIABLES trims innodb_data_file_path (this bug was already fixed in 4.0, I just copied and pasted two lines). --- sql/ha_innobase.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc index b8a794a61a0..34ad45bfb18 100644 --- a/sql/ha_innobase.cc +++ b/sql/ha_innobase.cc @@ -107,6 +107,8 @@ my_bool innobase_log_archive = FALSE; my_bool innobase_use_native_aio = FALSE; my_bool innobase_fast_shutdown = TRUE; +static char *internal_innobase_data_file_path = NULL; + /* innodb_flush_log_at_trx_commit can now have 3 values: 0 : write to the log file once per second and flush it to disk; 1 : write to the log file at each commit and flush it to disk; @@ -522,8 +524,14 @@ innobase_init(void) srv_arch_dir = (innobase_log_arch_dir ? innobase_log_arch_dir : current_dir); - ret = (bool) - srv_parse_data_file_paths_and_sizes(innobase_data_file_path, + /* Since InnoDB edits the argument in the next call, we make another + copy of it: */ + + internal_innobase_data_file_path = my_strdup(innobase_data_file_path, + MYF(MY_WME)); + + ret = (bool) srv_parse_data_file_paths_and_sizes( + internal_innobase_data_file_path, &srv_data_file_names, &srv_data_file_sizes, &srv_data_file_is_raw_partition, From 4198322bef9550577d317046b642ccaa6f0f0702 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 May 2003 18:20:57 +0200 Subject: [PATCH 10/40] Outcome of discussions with Lenz and Monty about handling ccache in the build commands. BUILD/SETUP.sh: Quote $CXX to make a test work even if CXX had spaces in it. Automatically add ccache to CC and CXX if ccache is present. configure.in: Accept "ccache gcc" in the test. --- BUILD/SETUP.sh | 18 +++++++++++++++++- configure.in | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 55b82e38d63..150f9e28b41 100644 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -71,6 +71,22 @@ else make=make fi -if test -z $CXX ; then +if test -z "$CXX" ; then CXX=gcc fi + +# If ccache (a compiler cache which reduces build time) +# (http://samba.org/ccache) is installed, use it. +# We use 'grep' and hope 'grep' will work as expected +# (returns 0 if finds lines) +if ccache -V > /dev/null 2>&1 +then + if ! (echo "$CC" | grep "ccache" > /dev/null) + then + CC="ccache $CC" + fi + if ! (echo "$CXX" | grep "ccache" > /dev/null) + then + CXX="ccache $CXX" + fi +fi diff --git a/configure.in b/configure.in index c7cf4f66b70..5c794714889 100644 --- a/configure.in +++ b/configure.in @@ -361,7 +361,7 @@ then # we will gets some problems when linking static programs. # The following code is used to fix this problem. - if test "$CXX" = "gcc" + if test "$CXX" = "gcc" -o "$CXX" = "ccache gcc" then if $CXX -v 2>&1 | grep 'version 3' > /dev/null 2>&1 then From 73e80314aa17b13d8bb0a6f0f230b99c439bee8a Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 24 May 2003 16:43:53 +0200 Subject: [PATCH 11/40] Fix for bug #490 and #491 (see details below) mysql-test/r/insert_select.result: Result update. mysql-test/r/rpl_insert_id.result: Test update mysql-test/t/insert_select.test: Check if a partly completed INSERT SELECT (failing because of "Duplicate key" after successfully inserting other rows) is written to the binlog if the table is not transactional and at least one row has been inserted (bug #491) mysql-test/t/rpl_insert_id.test: Test for bug #490 (INSERT SELECT in auto_increment) sql/sql_insert.cc: - In INSERT ... SELECT, if it fails with error but one row has been inserted and the table is not transactional, we must write to the binlog (the slave will stop because of the error code in the binlog event, this is normal). bug 491. - we must set INSERT_ID before writing to the binlog (bug 490 accidentally introduced by another dev in 4.0.13). --- mysql-test/r/insert_select.result | 14 +++++++++++++ mysql-test/r/rpl_insert_id.result | 28 ++++++++++++++++++++++++++ mysql-test/t/insert_select.test | 19 ++++++++++++++++++ mysql-test/t/rpl_insert_id.test | 33 +++++++++++++++++++++++++------ sql/sql_insert.cc | 24 +++++++++++++++++++--- 5 files changed, 109 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index e24c3179a0c..b49ca3a6c2f 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -66,3 +66,17 @@ INSERT INTO crash1 (numeropost,icone,contenu,pseudo,date,signature,ip) SELECT 1718,icone,contenu,pseudo,date,signature,ip FROM crash2 WHERE numeropost=9 ORDER BY numreponse ASC; DROP TABLE IF EXISTS crash1,crash2; +drop table if exists t1; +drop table if exists t2; +create table t1(a int, unique(a)); +insert into t1 values(2); +create table t2(a int); +insert into t2 values(1),(2); +reset master; +insert into t1 select * from t2; +Duplicate entry '2' for key 1 +show binlog events; +Log_name Pos Event_type Server_id Orig_log_pos Info +master-bin.001 4 Start 1 4 Server ver: VERSION, Binlog ver: 3 +master-bin.001 79 Query 1 79 use test; insert into t1 select * from t2 +drop table t1, t2; diff --git a/mysql-test/r/rpl_insert_id.result b/mysql-test/r/rpl_insert_id.result index d524818985e..6d996481a5c 100644 --- a/mysql-test/r/rpl_insert_id.result +++ b/mysql-test/r/rpl_insert_id.result @@ -39,3 +39,31 @@ b c 6 11 drop table t1; drop table t2; +create table t1(a int auto_increment, key(a)); +create table t2(b int auto_increment, c int, key(b)); +insert into t1 values (10); +insert into t1 values (null),(null),(null); +insert into t2 values (5,0); +insert into t2 (c) select * from t1; +select * from t2; +b c +5 0 +6 10 +7 11 +8 12 +9 13 +select * from t1; +a +10 +11 +12 +13 +select * from t2; +b c +5 0 +6 10 +7 11 +8 12 +9 13 +drop table t1; +drop table t2; diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index 42f65858d77..695f891f678 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -68,3 +68,22 @@ WHERE numeropost=9 ORDER BY numreponse ASC; DROP TABLE IF EXISTS crash1,crash2; + +# Addendum by Guilhem: +# Check if a partly-completed INSERT SELECT in a MyISAM table goes +# into the binlog +drop table if exists t1; +drop table if exists t2; +create table t1(a int, unique(a)); +insert into t1 values(2); +create table t2(a int); +insert into t2 values(1),(2); +reset master; +--error 1062 +insert into t1 select * from t2; +# The above should produce an error, but still be in the binlog; +# verify the binlog : +let $VERSION=`select version()`; +--replace_result $VERSION VERSION +show binlog events; +drop table t1, t2; diff --git a/mysql-test/t/rpl_insert_id.test b/mysql-test/t/rpl_insert_id.test index 3f3636d3082..3478aedf3eb 100644 --- a/mysql-test/t/rpl_insert_id.test +++ b/mysql-test/t/rpl_insert_id.test @@ -1,6 +1,7 @@ -#see if queries that use both -#auto_increment and LAST_INSERT_ID() -#are replicated well +# see if queries that use both +# auto_increment and LAST_INSERT_ID() +# are replicated well + source include/master-slave.inc; connection master; drop table if exists t1; @@ -15,9 +16,11 @@ sync_with_master; select * from t1; select * from t2; connection master; -#check if multi-line inserts, -#which set last_insert_id to the first id inserted, -#are replicated the same way + +# check if multi-line inserts, +# which set last_insert_id to the first id inserted, +# are replicated the same way + drop table t1; drop table t2; create table t1(a int auto_increment, key(a)); @@ -32,6 +35,24 @@ sync_with_master; select * from t1; select * from t2; connection master; + +# check if INSERT SELECT in auto_increment is well replicated (bug #490) + +drop table t1; +drop table t2; +create table t1(a int auto_increment, key(a)); +create table t2(b int auto_increment, c int, key(b)); +insert into t1 values (10); +insert into t1 values (null),(null),(null); +insert into t2 values (5,0); +insert into t2 (c) select * from t1; +select * from t2; +save_master_pos; +connection slave; +sync_with_master; +select * from t1; +select * from t2; +connection master; drop table t1; drop table t2; save_master_pos; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 33a13fabdc6..167ccf974c7 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1350,6 +1350,24 @@ void select_insert::send_error(uint errcode,const char *err) ::send_error(&thd->net,errcode,err); table->file->extra(HA_EXTRA_NO_CACHE); table->file->activate_all_index(thd); + /* + If at least one row has been inserted/modified and will stay in the table + (the table doesn't have transactions) (example: we got a duplicate key + error while inserting into a MyISAM table) we must write to the binlog (and + the error code will make the slave stop). + */ + if ((info.copied || info.deleted) && !table->file->has_transactions()) + { + if (last_insert_id) + thd->insert_id(last_insert_id); // For binary log + mysql_update_log.write(thd,thd->query,thd->query_length); + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query, thd->query_length, + table->file->has_transactions()); + mysql_bin_log.write(&qinfo); + } + } ha_rollback_stmt(thd); if (info.copied || info.deleted) { @@ -1365,7 +1383,10 @@ bool select_insert::send_eof() error=table->file->activate_all_index(thd); table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); + if (last_insert_id) + thd->insert_id(last_insert_id); // For binary log /* Write to binlog before commiting transaction */ + mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, thd->query, thd->query_length, @@ -1393,10 +1414,7 @@ bool select_insert::send_eof() else sprintf(buff,ER(ER_INSERT_INFO),info.records,info.deleted, thd->cuted_fields); - if (last_insert_id) - thd->insert_id(last_insert_id); // For update log ::send_ok(&thd->net,info.copied+info.deleted,last_insert_id,buff); - mysql_update_log.write(thd,thd->query,thd->query_length); return 0; } } From dc90f5ccd798c411a85b7fbc98768728fb1bc888 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 25 May 2003 23:37:32 +0300 Subject: [PATCH 12/40] log.cc: If FOREIGN_KEY_CHECKS=0, wrap in binlog SQL statements inside SET FOREIGN_...=0; ... ; SET FOREIGN_...=1 sql/log.cc: If FOREIGN_KEY_CHECKS=0, wrap in binlog SQL statements inside SET FOREIGN_...=0; ... ; SET FOREIGN_...=1 --- sql/log.cc | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/sql/log.cc b/sql/log.cc index 79ee59eedf8..8bf51100147 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1071,6 +1071,12 @@ bool MYSQL_LOG::write(Log_event* event_info) No check for auto events flag here - this write method should never be called if auto-events are enabled */ + + /* + 1. Write first log events which describe the 'run environment' + of the SQL command + */ + if (thd) { if (thd->last_insert_id_used) @@ -1109,11 +1115,50 @@ bool MYSQL_LOG::write(Log_event* event_info) if (e.write(file)) goto err; } + + /* If the user has set FOREIGN_KEY_CHECKS=0 we wrap every SQL + command in the binlog inside: + SET FOREIGN_KEY_CHECKS=0; + ; + SET FOREIGN_KEY_CHECKS=1; */ + + if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) + { + char buf[256], *p; + p= strmov(buf, "SET FOREIGN_KEY_CHECKS=0"); + Query_log_event e(thd, buf, (ulong) (p - buf), 0); + e.set_log_pos(this); + if (e.write(file)) + goto err; + } } + + /* + 2. Write the SQL command + */ + event_info->set_log_pos(this); if (event_info->write(file) || - file == &log_file && flush_io_cache(file)) + file == &log_file && flush_io_cache(file)) goto err; + + /* + 3. Write log events to reset the 'run environment' of the SQL command + */ + + if (thd && thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) + { + char buf[256], *p; + + p= strmov(buf, "SET FOREIGN_KEY_CHECKS=1"); + Query_log_event e(thd, buf, (ulong) (p - buf), 0); + e.set_log_pos(this); + + if (e.write(file) || + file == &log_file && flush_io_cache(file)) + goto err; + } + error=0; /* From 2917fdb9d38c798cdc8e9341bec667ce4cb3c281 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 25 May 2003 23:09:46 +0200 Subject: [PATCH 13/40] - Fix for memory leak if the SQL slave thread is killed just after reading an event. - A few more mutex locks and unlocks of rli.log_space_lock for doing clean reads of rli.ignore_log_space_limit - Broadcast after unlock, not before (small speed optimisation). --- sql/slave.cc | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/sql/slave.cc b/sql/slave.cc index e6215356ad1..b620603dc63 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1322,6 +1322,8 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli) !rli->ignore_log_space_limit) { pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock); + /* Re-acquire the mutex as pthread_cond_wait released it */ + pthread_mutex_lock(&rli->log_space_lock); } thd->proc_info = save_proc_info; pthread_mutex_unlock(&rli->log_space_lock); @@ -2028,7 +2030,11 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) Log_event * ev = next_event(rli); DBUG_ASSERT(rli->sql_thd==thd); if (sql_slave_killed(thd,rli)) + { + /* do not forget to free ev ! */ + if (ev) delete ev; return 1; + } if (ev) { int type_code = ev->get_type_code(); @@ -2302,6 +2308,18 @@ reconnect done to recover from failed read"); goto err; } flush_master_info(mi); + /* + See if the relay logs take too much space. + We don't lock mi->rli.log_space_lock here; this dirty read saves time + and does not introduce any problem: + - if mi->rli.ignore_log_space_limit is 1 but becomes 0 just after (so + the clean value is 0), then we are reading only one more event as we + should, and we'll block only at the next event. No big deal. + - if mi->rli.ignore_log_space_limit is 0 but becomes 1 just after (so + the clean value is 1), then we are going into wait_for_relay_log_space() + for no reason, but this function will do a clean read, notice the clean + value and exit immediately. + */ if (mi->rli.log_space_limit && mi->rli.log_space_limit < mi->rli.log_space_total && !mi->rli.ignore_log_space_limit) @@ -2416,7 +2434,9 @@ slave_begin: rli->pending = 0; //tell the I/O thread to take relay_log_space_limit into account from now on + pthread_mutex_lock(&rli->log_space_lock); rli->ignore_log_space_limit= 0; + pthread_mutex_unlock(&rli->log_space_lock); if (init_relay_log_pos(rli, rli->relay_log_name, @@ -3122,9 +3142,14 @@ Log_event* next_event(RELAY_LOG_INFO* rli) pthread_mutex_lock(&rli->log_space_lock); // prevent the I/O thread from blocking next times rli->ignore_log_space_limit= 1; - // If the I/O thread is blocked, unblock it - pthread_cond_broadcast(&rli->log_space_cond); + /* + If the I/O thread is blocked, unblock it. + Ok to broadcast after unlock, because the mutex is only destroyed in + ~st_relay_log_info(), i.e. when rli is destroyed, and rli will not be + destroyed before we exit the present function. + */ pthread_mutex_unlock(&rli->log_space_lock); + pthread_cond_broadcast(&rli->log_space_cond); // Note that wait_for_update unlocks lock_log ! rli->relay_log.wait_for_update(rli->sql_thd); // re-acquire data lock since we released it earlier From 069141f2295297923c25d8b732d468ef1578c118 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 May 2003 05:57:27 +0300 Subject: [PATCH 14/40] Remove not used flag --- include/mysql_com.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/mysql_com.h b/include/mysql_com.h index fcc9abc5bcd..4ea1a77c836 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -86,7 +86,6 @@ enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY, #define CLIENT_ODBC 64 /* Odbc client */ #define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */ #define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */ -#define CLIENT_CHANGE_USER 512 /* Support the mysql_change_user() */ #define CLIENT_INTERACTIVE 1024 /* This is an interactive client */ #define CLIENT_SSL 2048 /* Switch to SSL after handshake */ #define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */ From ea99087e8843a80948edd98df09474118b7e31d2 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 May 2003 06:16:50 +0300 Subject: [PATCH 15/40] Added missing free for last patch --- sql/ha_innobase.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc index 34ad45bfb18..d1db50dfa89 100644 --- a/sql/ha_innobase.cc +++ b/sql/ha_innobase.cc @@ -637,6 +637,7 @@ innobase_end(void) err = innobase_shutdown_for_mysql(); hash_free(&innobase_open_tables); + my_free(internal_innobase_data_file_path,MYF(MY_ALLOW_ZERO_PTR)); if (err != DB_SUCCESS) { From e864f2592de68f04891d9611b0debfb123e8fd88 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 May 2003 11:47:03 +0300 Subject: [PATCH 16/40] Added testing of LOAD DATA ... STARTING BY Added read_only variable mysql-test/r/loaddata.result: Added testing of STARTING BY mysql-test/t/loaddata.test: Added testing of STARTING BY sql/log_event.cc: Code cleanup sql/set_var.cc: Added read_only variable sql/sql_update.cc: Remove not used variable --- mysql-test/r/loaddata.result | 7 +++++++ mysql-test/t/loaddata.test | 8 ++++++++ sql/log_event.cc | 3 +-- sql/set_var.cc | 5 ++--- sql/sql_update.cc | 1 - 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result index d121a4e6c40..59153f3353a 100644 --- a/mysql-test/r/loaddata.result +++ b/mysql-test/r/loaddata.result @@ -8,4 +8,11 @@ a b c d 0000-00-00 0000-00-00 0000-00-00 0000-00-00 2003-03-03 2003-03-03 2003-03-03 NULL 2003-03-03 2003-03-03 2003-03-03 NULL +truncate table t1; +load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ',' LINES STARTING BY ',' (b,c,d); +SELECT * from t1; +a b c d +NULL NULL 0000-00-00 0000-00-00 +NULL 0000-00-00 0000-00-00 0000-00-00 +NULL 2003-03-03 2003-03-03 NULL drop table t1; diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test index ceb5c47af11..e63f0780e3e 100644 --- a/mysql-test/t/loaddata.test +++ b/mysql-test/t/loaddata.test @@ -8,4 +8,12 @@ create table t1 (a date, b date, c date not null, d date); load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ','; load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ',' IGNORE 2 LINES; SELECT * from t1; +truncate table t1; + +load data infile '../../std_data/loaddata1.dat' into table t1 fields terminated by ',' LINES STARTING BY ',' (b,c,d); +SELECT * from t1; drop table t1; + + + + diff --git a/sql/log_event.cc b/sql/log_event.cc index bbea89bfd3f..76151026590 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1946,8 +1946,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, sql_error= ER_UNKNOWN_ERROR; slave_print_error(rli,sql_error, "Error '%s' running load data infile", - sql_error ? thd->net.last_error : - ER_SAFE(ER_UNKNOWN_ERROR)); + ER_SAFE(sql_error)); free_root(&thd->mem_root,0); return 1; } diff --git a/sql/set_var.cc b/sql/set_var.cc index 2ca12cdb802..1da187598c4 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -185,6 +185,7 @@ sys_var_thd_ulong sys_net_retry_count("net_retry_count", sys_var_thd_bool sys_new_mode("new", &SV::new_mode); sys_var_thd_ulong sys_read_buff_size("read_buffer_size", &SV::read_buff_size); +sys_var_bool_ptr sys_readonly("read_only", &opt_readonly); sys_var_thd_ulong sys_read_rnd_buff_size("read_rnd_buffer_size", &SV::read_rnd_buff_size); sys_var_long_ptr sys_rpl_recovery_rank("rpl_recovery_rank", @@ -204,8 +205,6 @@ sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol", &opt_slave_compressed_protocol); sys_var_long_ptr sys_slave_net_timeout("slave_net_timeout", &slave_net_timeout); -sys_var_bool_ptr sys_readonly("read_only", - &opt_readonly); sys_var_long_ptr sys_slow_launch_time("slow_launch_time", &slow_launch_time); sys_var_thd_ulong sys_sort_buffer("sort_buffer_size", @@ -516,6 +515,7 @@ struct show_var_st init_vars[]= { {"port", (char*) &mysql_port, SHOW_INT}, {"protocol_version", (char*) &protocol_version, SHOW_INT}, {sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS}, + {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS}, {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS}, {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS}, #ifdef HAVE_QUERY_CACHE @@ -525,7 +525,6 @@ struct show_var_st init_vars[]= { #endif /* HAVE_QUERY_CACHE */ {sys_server_id.name, (char*) &sys_server_id, SHOW_SYS}, {sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout, SHOW_SYS}, - {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS}, {"skip_external_locking", (char*) &my_disable_locking, SHOW_MY_BOOL}, {"skip_networking", (char*) &opt_disable_networking, SHOW_BOOL}, {"skip_show_database", (char*) &opt_skip_show_db, SHOW_BOOL}, diff --git a/sql/sql_update.cc b/sql/sql_update.cc index ed4d6fd9b81..b4e7750addf 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -182,7 +182,6 @@ int mysql_update(THD *thd, */ uint length; SORT_FIELD *sortorder; - List fields; ha_rows examined_rows; table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE), From 306b74fcc86b946577aa0a87231d43aac0b20395 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 May 2003 13:10:08 +0300 Subject: [PATCH 17/40] Fixed core dump bug when shuting down mysqld --- include/thr_alarm.h | 2 +- mysys/thr_alarm.c | 75 ++++++++++++++++++++++++++++----------------- sql/mysqld.cc | 7 +++-- 3 files changed, 52 insertions(+), 32 deletions(-) diff --git a/include/thr_alarm.h b/include/thr_alarm.h index 30825d49158..439f046252f 100644 --- a/include/thr_alarm.h +++ b/include/thr_alarm.h @@ -103,7 +103,7 @@ void init_thr_alarm(uint max_alarm); bool thr_alarm(thr_alarm_t *alarmed, uint sec, ALARM *buff); void thr_alarm_kill(pthread_t thread_id); void thr_end_alarm(thr_alarm_t *alarmed); -void end_thr_alarm(void); +void end_thr_alarm(my_bool free_structures); sig_handler process_alarm(int); #ifndef thr_got_alarm bool thr_got_alarm(thr_alarm_t *alrm); diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index add5335a7af..1b58a0274ff 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -27,6 +27,7 @@ #include #include #include "thr_alarm.h" +#include #ifdef HAVE_SYS_SELECT_H #include /* AIX needs this for fd_set */ @@ -36,7 +37,7 @@ #define ETIME ETIMEDOUT #endif -static my_bool alarm_aborted=1; +static int alarm_aborted=1; /* No alarm thread */ my_bool thr_alarm_inited=0; static sig_handler process_alarm_part2(int sig); @@ -136,19 +137,24 @@ bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) now=(ulong) time((time_t*) 0); pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask); pthread_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */ - if (alarm_aborted) + if (alarm_aborted > 0) { /* No signal thread */ DBUG_PRINT("info", ("alarm aborted")); + *alrm= 0; /* No alarm */ pthread_mutex_unlock(&LOCK_alarm); pthread_sigmask(SIG_SETMASK,&old_mask,NULL); DBUG_RETURN(1); } + if (alarm_aborted < 0) + sec= 1; /* Abort mode */ + if (alarm_queue.elements >= max_used_alarms) { if (alarm_queue.elements == alarm_queue.max_elements) { DBUG_PRINT("info", ("alarm queue full")); fprintf(stderr,"Warning: thr_alarm queue is full\n"); + *alrm= 0; /* No alarm */ pthread_mutex_unlock(&LOCK_alarm); pthread_sigmask(SIG_SETMASK,&old_mask,NULL); DBUG_RETURN(1); @@ -219,6 +225,7 @@ void thr_end_alarm(thr_alarm_t *alarmed) break; } } + DBUG_ASSERT(!*alarmed || found); if (!found) { #ifdef MAIN @@ -228,14 +235,7 @@ void thr_end_alarm(thr_alarm_t *alarmed) DBUG_PRINT("warning",("Didn't find alarm %lx in queue\n", (long) *alarmed)); } - if (alarm_aborted && !alarm_queue.elements) - { - delete_queue(&alarm_queue); - pthread_mutex_unlock(&LOCK_alarm); - pthread_mutex_destroy(&LOCK_alarm); - } - else - pthread_mutex_unlock(&LOCK_alarm); + pthread_mutex_unlock(&LOCK_alarm); pthread_sigmask(SIG_SETMASK,&old_mask,NULL); DBUG_VOID_RETURN; } @@ -365,31 +365,49 @@ static sig_handler process_alarm_part2(int sig __attribute__((unused))) /* - Shedule all alarms now. - When all alarms are given, Free alarm memory and don't allow more alarms. + Schedule all alarms now and optionally free all structures + + SYNPOSIS + end_thr_alarm() + free_structures Set to 1 if we should free memory used for + the alarm queue. + When we call this we should KNOW that there + is no active alarms + IMPLEMENTATION + Set alarm_abort to -1 which will change the behavior of alarms as follows: + - All old alarms will be rescheduled at once + - All new alarms will be rescheduled to one second */ -void end_thr_alarm(void) +void end_thr_alarm(my_bool free_structures) { DBUG_ENTER("end_thr_alarm"); - if (!alarm_aborted) + if (alarm_aborted != 1) { - my_bool deleted=0; pthread_mutex_lock(&LOCK_alarm); DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements)); - alarm_aborted=1; /* mark aborted */ - if (!alarm_queue.elements) - { - deleted= 1; - delete_queue(&alarm_queue); - } + alarm_aborted= -1; /* mark aborted */ if (pthread_equal(pthread_self(),alarm_thread)) alarm(1); /* Shut down everything soon */ else reschedule_alarms(); - pthread_mutex_unlock(&LOCK_alarm); - if (deleted) - pthread_mutex_destroy(&LOCK_alarm); + if (free_structures) + { + /* + The following test is just for safety, the caller should not + depend on this + */ + DBUG_ASSERT(!alarm_queue.elements); + if (!alarm_queue.elements) + { + delete_queue(&alarm_queue); + alarm_aborted= 1; + pthread_mutex_unlock(&LOCK_alarm); + pthread_mutex_destroy(&LOCK_alarm); + } + } + else + pthread_mutex_unlock(&LOCK_alarm); } DBUG_VOID_RETURN; } @@ -629,7 +647,7 @@ void thr_end_alarm(thr_alarm_t *alrm_ptr) } } -void end_thr_alarm(void) +void end_thr_alarm(my_bool free_structures) { DBUG_ENTER("end_thr_alarm"); alarm_aborted=1; /* No more alarms */ @@ -708,7 +726,7 @@ void thr_end_alarm(thr_alarm_t *alrm_ptr) } } -void end_thr_alarm(void) +void end_thr_alarm(my_bool free_structures) { DBUG_ENTER("end_thr_alarm"); alarm_aborted=1; /* No more alarms */ @@ -907,7 +925,7 @@ static void *signal_hand(void *arg __attribute__((unused))) case SIGHUP: #endif printf("Aborting nicely\n"); - end_thr_alarm(); + end_thr_alarm(0); break; #ifdef SIGTSTP case SIGTSTP: @@ -1004,10 +1022,11 @@ int main(int argc __attribute__((unused)),char **argv __attribute__((unused))) if (thread_count == 1) { printf("Calling end_thr_alarm. This should cancel the last thread\n"); - end_thr_alarm(); + end_thr_alarm(0); } } pthread_mutex_unlock(&LOCK_thread_count); + end_thr_alarm(1); thr_alarm_info(&alarm_info); printf("Main_thread: Alarms: %u max_alarms: %u next_alarm_time: %lu\n", alarm_info.active_alarms, alarm_info.max_used_alarms, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 67fb7798ebd..2992fcfd908 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -596,7 +596,7 @@ static void close_connections(void) unix_sock= INVALID_SOCKET; } #endif - end_thr_alarm(); // Don't allow alarms + end_thr_alarm(0); // Abort old alarms. end_slave(); /* First signal all threads that it's time to die */ @@ -905,6 +905,7 @@ void clean_up(bool print_message) #endif (void) ha_panic(HA_PANIC_CLOSE); /* close all tables and logs */ end_key_cache(); + end_thr_alarm(1); /* Free allocated memory */ #ifdef USE_RAID end_raid(); #endif @@ -2313,14 +2314,14 @@ The server will not act as a slave."); if (opt_bootstrap) { int error=bootstrap(stdin); - end_thr_alarm(); // Don't allow alarms + end_thr_alarm(1); // Don't allow alarms unireg_abort(error ? 1 : 0); } if (opt_init_file) { if (read_init_file(opt_init_file)) { - end_thr_alarm(); // Don't allow alarms + end_thr_alarm(1); // Don't allow alarms unireg_abort(1); } } From ecdd47a72fe49738549e3e0b2cccec776a6fba26 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 May 2003 15:08:17 +0300 Subject: [PATCH 18/40] code cleanup mysql-test/r/rpl_insert_id.result: Test logging of FOREIGN_KEY_CHECKS mysql-test/t/rpl_insert_id.test: Test logging of FOREIGN_KEY_CHECKS sql/log.cc: Code cleanup --- mysql-test/r/rpl_insert_id.result | 2 ++ mysql-test/t/rpl_insert_id.test | 10 ++++-- sql/log.cc | 57 ++++++++++++++----------------- 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/mysql-test/r/rpl_insert_id.result b/mysql-test/r/rpl_insert_id.result index d524818985e..70f9ff0de0f 100644 --- a/mysql-test/r/rpl_insert_id.result +++ b/mysql-test/r/rpl_insert_id.result @@ -23,10 +23,12 @@ drop table t1; drop table t2; create table t1(a int auto_increment, key(a)); create table t2(b int auto_increment, c int, key(b)); +SET FOREIGN_KEY_CHECKS=0; insert into t1 values (10); insert into t1 values (null),(null),(null); insert into t2 values (5,0); insert into t2 values (null,last_insert_id()); +SET FOREIGN_KEY_CHECKS=1; select * from t1; a 10 diff --git a/mysql-test/t/rpl_insert_id.test b/mysql-test/t/rpl_insert_id.test index 3f3636d3082..a9e4de21e5c 100644 --- a/mysql-test/t/rpl_insert_id.test +++ b/mysql-test/t/rpl_insert_id.test @@ -1,6 +1,8 @@ -#see if queries that use both -#auto_increment and LAST_INSERT_ID() -#are replicated well +# See if queries that use both auto_increment and LAST_INSERT_ID() +# are replicated well + +# We also check how the foreign_key_check variable is replicated + source include/master-slave.inc; connection master; drop table if exists t1; @@ -22,10 +24,12 @@ drop table t1; drop table t2; create table t1(a int auto_increment, key(a)); create table t2(b int auto_increment, c int, key(b)); +SET FOREIGN_KEY_CHECKS=0; insert into t1 values (10); insert into t1 values (null),(null),(null); insert into t2 values (5,0); insert into t2 values (null,last_insert_id()); +SET FOREIGN_KEY_CHECKS=1; save_master_pos; connection slave; sync_with_master; diff --git a/sql/log.cc b/sql/log.cc index 8bf51100147..99bc6ee32b4 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1116,50 +1116,38 @@ bool MYSQL_LOG::write(Log_event* event_info) goto err; } - /* If the user has set FOREIGN_KEY_CHECKS=0 we wrap every SQL - command in the binlog inside: - SET FOREIGN_KEY_CHECKS=0; - ; - SET FOREIGN_KEY_CHECKS=1; */ + /* + If the user has set FOREIGN_KEY_CHECKS=0 we wrap every SQL + command in the binlog inside: + SET FOREIGN_KEY_CHECKS=0; + ; + SET FOREIGN_KEY_CHECKS=1; + */ if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { - char buf[256], *p; - p= strmov(buf, "SET FOREIGN_KEY_CHECKS=0"); - Query_log_event e(thd, buf, (ulong) (p - buf), 0); + Query_log_event e(thd, "SET FOREIGN_KEY_CHECKS=0", 24, 0); e.set_log_pos(this); if (e.write(file)) goto err; } } - /* - 2. Write the SQL command - */ + /* Write the SQL command */ event_info->set_log_pos(this); - if (event_info->write(file) || - file == &log_file && flush_io_cache(file)) + if (event_info->write(file)) goto err; - /* - 3. Write log events to reset the 'run environment' of the SQL command - */ + /* Write log events to reset the 'run environment' of the SQL command */ if (thd && thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { - char buf[256], *p; - - p= strmov(buf, "SET FOREIGN_KEY_CHECKS=1"); - Query_log_event e(thd, buf, (ulong) (p - buf), 0); + Query_log_event e(thd, "SET FOREIGN_KEY_CHECKS=1", 24, 0); e.set_log_pos(this); - - if (e.write(file) || - file == &log_file && flush_io_cache(file)) + if (e.write(file)) goto err; } - - error=0; /* Tell for transactional table handlers up to which position in the @@ -1180,6 +1168,9 @@ bool MYSQL_LOG::write(Log_event* event_info) if (file == &log_file) // we are writing to the real log (disk) { + if (flush_io_cache(file)) + goto err; + if (opt_using_transactions && !my_b_tell(&thd->transaction.trans_log)) { /* @@ -1189,8 +1180,8 @@ bool MYSQL_LOG::write(Log_event* event_info) handler if the log event type is appropriate. */ - if (event_info->get_type_code() == QUERY_EVENT - || event_info->get_type_code() == EXEC_LOAD_EVENT) + if (event_info->get_type_code() == QUERY_EVENT || + event_info->get_type_code() == EXEC_LOAD_EVENT) { error = ha_report_binlog_offset_and_commit(thd, log_file_name, file->pos_in_file); @@ -1200,6 +1191,7 @@ bool MYSQL_LOG::write(Log_event* event_info) /* we wrote to the real log, check automatic rotation */ should_rotate= (my_b_tell(file) >= (my_off_t) max_binlog_size); } + error=0; err: if (error) @@ -1222,13 +1214,14 @@ err: pthread_mutex_unlock(&LOCK_log); - /* Flush the transactional handler log file now that we have released - LOCK_log; the flush is placed here to eliminate the bottleneck on the - group commit */ + /* + Flush the transactional handler log file now that we have released + LOCK_log; the flush is placed here to eliminate the bottleneck on the + group commit + */ - if (called_handler_commit) { + if (called_handler_commit) ha_commit_complete(thd); - } DBUG_RETURN(error); } From 1ed4e006bd7e70f50d29950c03024d09aaec64f0 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 May 2003 17:24:16 +0300 Subject: [PATCH 19/40] Fixed problem with 'kill pid-of-mysqld' on Mac OS X --- sql/mysqld.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 4e88a6fcb32..f729dcfd17a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1346,6 +1346,7 @@ information that should help you find out what is causing the crash\n"); static void init_signals(void) { sigset_t set; + struct sigaction sa; DBUG_ENTER("init_signals"); sigset(THR_KILL_SIGNAL,end_thread_signal); @@ -1353,7 +1354,6 @@ static void init_signals(void) if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL)) { - struct sigaction sa; sa.sa_flags = SA_RESETHAND | SA_NODEFER; sigemptyset(&sa.sa_mask); sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL); @@ -1378,15 +1378,22 @@ static void init_signals(void) sigaddset(&set,SIGQUIT); sigaddset(&set,SIGTERM); sigaddset(&set,SIGHUP); - sigset(SIGTERM,print_signal_warning); // If it's blocked by parent - signal(SIGHUP,print_signal_warning); // If it's blocked by parent + + /* Fix signals if blocked by parents (can happen on Mac OS X) */ + sa.sa_flags = 0; + sa.sa_handler = print_signal_warning; + sigaction(SIGTERM, &sa, (struct sigaction*) 0); + sa.sa_flags = 0; + sa.sa_handler = print_signal_warning; + sigaction(SIGHUP, &sa, (struct sigaction*) 0); #ifdef SIGTSTP sigaddset(&set,SIGTSTP); #endif sigaddset(&set,THR_SERVER_ALARM); sigdelset(&set,THR_KILL_SIGNAL); // May be SIGINT sigdelset(&set,THR_CLIENT_ALARM); // For alarms - (void) pthread_sigmask(SIG_SETMASK,&set,NULL); + sigprocmask(SIG_SETMASK,&set,NULL); + pthread_sigmask(SIG_SETMASK,&set,NULL); DBUG_VOID_RETURN; } From 6f8e0d13642a43f35f4deb15437be029df023b45 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 May 2003 19:11:22 +0300 Subject: [PATCH 20/40] Fix for 64 bit machines (To remove warnings on Itanium) mysys/thr_alarm.c: Safety fix --- include/my_global.h | 5 +++++ mysys/thr_alarm.c | 1 + 2 files changed, 6 insertions(+) diff --git a/include/my_global.h b/include/my_global.h index 15495c60dd7..ca24c21c688 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -634,7 +634,12 @@ extern double my_atof(const char*); Max size that must be added to a so that we know Size to make adressable obj. */ +#if SIZEOF_CHARP == 4 typedef long my_ptrdiff_t; +#else +typedef long long my_ptrdiff_t; +#endif + #define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1)) #define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double)) /* Size to make adressable obj. */ diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index 1b58a0274ff..ca8e4e8bcb6 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -169,6 +169,7 @@ bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data) if (!(alarm_data=(ALARM*) my_malloc(sizeof(ALARM),MYF(MY_WME)))) { DBUG_PRINT("info", ("failed my_malloc()")); + *alrm= 0; /* No alarm */ pthread_mutex_unlock(&LOCK_alarm); pthread_sigmask(SIG_SETMASK,&old_mask,NULL); DBUG_RETURN(1); From cd554e9ed61f3140cf213f62b8ce17bdf197467b Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 26 May 2003 20:09:53 +0300 Subject: [PATCH 21/40] Fixed bug when installing mysqld as a service with 2 arguments (option + service-name) --- sql/mysqld.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f729dcfd17a..b0b9837dff3 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2230,9 +2230,12 @@ int main(int argc, char **argv) return 0; if (Service.IsService(argv[2])) { - /* start an optional service */ + /* + mysqld was started as + mysqld --defaults-file=my_path\my.ini service-name + */ use_opt_args=1; - opt_argc=argc; + opt_argc= 2; // Skip service-name opt_argv=argv; start_mode= 1; Service.Init(argv[2], mysql_service); From 4920a3326fc96be2cfa661232b6fe5f731b22eae Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 May 2003 16:40:14 +0300 Subject: [PATCH 22/40] Fixed problem with mysql prompt when server disconnect. (Bug 356) Fixed problem with localtime -> gmt where some times resulted in different (but correct) timestamps. Now MySQL should use the smallest possible timestamp value in this case. (Bug 316) client/mysql.cc: Fixed problem with prompt when server disconnect. (Bug 356) client/mysqltest.c: More debug information mysql-test/mysql-test-run.sh: Added support for --timezone in -master.opt mysql-test/t/raid.test: Fixed test if raid is enabled sql/field.cc: New my_gmt_sec() parameters sql/mysql_priv.h: New my_gmt_sec() parameters sql/mysqld.cc: Remove LOCK_timezone. Code cleanup sql/time.cc: Fixed problem with localtime -> gmt where some times resulted in different (but correct) timestamps. Now MySQL should use the smallest possible timestamp value in this case. (Bug 316) --- client/mysql.cc | 19 ++++++--- client/mysqltest.c | 6 ++- mysql-test/mysql-test-run.sh | 12 +++++- mysql-test/r/have_mest_timezone.require | 2 + mysql-test/r/timezone.result | 25 +++++++++++ mysql-test/t/raid.test | 2 + mysql-test/t/timezone-master.opt | 1 + mysql-test/t/timezone.test | 28 +++++++++++++ sql/field.cc | 3 +- sql/mysql_priv.h | 2 +- sql/mysqld.cc | 10 ----- sql/time.cc | 56 +++++++++++++++---------- 12 files changed, 126 insertions(+), 40 deletions(-) create mode 100644 mysql-test/r/have_mest_timezone.require create mode 100644 mysql-test/r/timezone.result create mode 100644 mysql-test/t/timezone-master.opt create mode 100644 mysql-test/t/timezone.test diff --git a/client/mysql.cc b/client/mysql.cc index a237561d83d..9b0e85aa41a 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -40,7 +40,7 @@ #include #include -const char *VER= "12.20"; +const char *VER= "12.21"; /* Don't try to make a nice table if the data is too big */ #define MAX_COLUMN_LENGTH 1024 @@ -2613,14 +2613,18 @@ static const char* construct_prompt() add_int_to_prompt(++prompt_counter); break; case 'v': - processed_prompt.append(mysql_get_server_info(&mysql)); + if (connected) + processed_prompt.append(mysql_get_server_info(&mysql)); + else + processed_prompt.append("not_connected"); break; case 'd': processed_prompt.append(current_db ? current_db : "(none)"); break; case 'h': { - const char *prompt=mysql_get_host_info(&mysql); + const char *prompt; + prompt= connected ? mysql_get_host_info(&mysql) : "not_connected"; if (strstr(prompt, "Localhost")) processed_prompt.append("localhost"); else @@ -2631,8 +2635,13 @@ static const char* construct_prompt() break; } case 'p': - if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || - ! mysql.unix_socket) + if (!connected) + { + processed_prompt.append("not_connected"); + break; + } + if (strstr(mysql_get_host_info(&mysql),"TCP/IP") || ! + mysql.unix_socket) add_int_to_prompt(mysql.port); else { diff --git a/client/mysqltest.c b/client/mysqltest.c index 4bc941e8b56..f6c999b18e4 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -515,8 +515,12 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char* fname) if (!my_stat(eval_file, &stat_info, MYF(MY_WME))) die(NullS); - if (!eval_result && stat_info.st_size != ds->length) + if (!eval_result && (uint) stat_info.st_size != ds->length) + { + DBUG_PRINT("info",("Size differs: result size: %u file size: %u", + ds->length, stat_info.st_size)); DBUG_RETURN(2); + } if (!(tmp = (char*) my_malloc(stat_info.st_size + 1, MYF(MY_WME)))) die(NullS); diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 65f40c5dc73..ab4a5354dae 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -13,7 +13,8 @@ DB=test DBPASSWD= VERBOSE="" USE_MANAGER=0 -TZ=GMT-3; export TZ # for UNIX_TIMESTAMP tests to work +MY_TZ=GMT-3 +TZ=$MY_TZ; export TZ # for UNIX_TIMESTAMP tests to work #++ # Program Definitions @@ -1161,9 +1162,18 @@ run_testcase () if [ -f $master_opt_file ] ; then EXTRA_MASTER_OPT=`$CAT $master_opt_file | $SED -e "s;\\$MYSQL_TEST_DIR;$MYSQL_TEST_DIR;"` + case "$EXTRA_MASTER_OPT" in + --timezone=*) + TZ=`$ECHO "$EXTRA_MASTER_OPT" | $SED -e "s;--timezone=;;"` + export TZ + # Note that this must be set to space, not "" for test-reset to work + EXTRA_MASTER_OPT=" " + ;; + esac stop_master echo "CURRENT_TEST: $tname" >> $MASTER_MYERR start_master + TZ=$MY_TZ; export TZ else if [ ! -z "$EXTRA_MASTER_OPT" ] || [ x$MASTER_RUNNING != x1 ] || [ -f $master_init_script ] then diff --git a/mysql-test/r/have_mest_timezone.require b/mysql-test/r/have_mest_timezone.require new file mode 100644 index 00000000000..2a219f39b7e --- /dev/null +++ b/mysql-test/r/have_mest_timezone.require @@ -0,0 +1,2 @@ +Variable_name Value +timezone MEST diff --git a/mysql-test/r/timezone.result b/mysql-test/r/timezone.result new file mode 100644 index 00000000000..b82b39da262 --- /dev/null +++ b/mysql-test/r/timezone.result @@ -0,0 +1,25 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (ts int); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 01:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 02:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 03:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 02:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 01:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 02:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 02:59:59')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 03:00:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 03:59:59')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 04:00:01')); +SELECT ts,from_unixtime(ts) FROM t1; +ts from_unixtime(ts) +1035673200 2002-10-27 01:00:00 +1035680400 2002-10-27 02:00:00 +1035684000 2002-10-27 03:00:00 +1035680400 2002-10-27 02:00:00 +1035673200 2002-10-27 01:00:00 +1035680400 2002-10-27 02:00:00 +1048986000 2003-03-30 03:00:00 +1048986000 2003-03-30 03:00:00 +1048989599 2003-03-30 03:59:59 +1048989601 2003-03-30 04:00:01 +DROP TABLE t1; diff --git a/mysql-test/t/raid.test b/mysql-test/t/raid.test index 4dbaf84a836..4032993f2da 100644 --- a/mysql-test/t/raid.test +++ b/mysql-test/t/raid.test @@ -1,5 +1,7 @@ -- require r/have_raid.require +disable_query_log; show variables like "have_raid"; +enable_query_log; # # Test of raided tables diff --git a/mysql-test/t/timezone-master.opt b/mysql-test/t/timezone-master.opt new file mode 100644 index 00000000000..0477f941e9d --- /dev/null +++ b/mysql-test/t/timezone-master.opt @@ -0,0 +1 @@ +--timezone=MET diff --git a/mysql-test/t/timezone.test b/mysql-test/t/timezone.test new file mode 100644 index 00000000000..14facc0374a --- /dev/null +++ b/mysql-test/t/timezone.test @@ -0,0 +1,28 @@ +# +# Test of timezone handling. This script must be run with TZ=MEST + +-- require r/have_mest_timezone.require +disable_query_log; +show variables like "timezone"; +enable_query_log; + +# Initialization +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + + +CREATE TABLE t1 (ts int); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 01:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 02:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 03:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 02:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 01:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2002-10-27 02:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 02:59:59')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 03:00:00')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 03:59:59')); +INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 04:00:01')); + +SELECT ts,from_unixtime(ts) FROM t1; +DROP TABLE t1; diff --git a/sql/field.cc b/sql/field.cc index a2663626723..9babe069300 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2552,6 +2552,7 @@ void Field_timestamp::store(longlong nr) if ((nr=fix_datetime(nr))) { + long not_used; part1=(long) (nr/LL(1000000)); part2=(long) (nr - (longlong) part1*LL(1000000)); l_time.year= (int) (part1/10000L); part1%=10000L; @@ -2560,7 +2561,7 @@ void Field_timestamp::store(longlong nr) l_time.hour= (int) (part2/10000L); part2%=10000L; l_time.minute=(int) part2 / 100; l_time.second=(int) part2 % 100; - timestamp=my_gmt_sec(&l_time); + timestamp=my_gmt_sec(&l_time, ¬_used); } else timestamp=0; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2c28fcf03bb..614cb8cadf6 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -755,7 +755,7 @@ uint calc_days_in_year(uint year); void get_date_from_daynr(long daynr,uint *year, uint *month, uint *day); void init_time(void); -long my_gmt_sec(TIME *); +long my_gmt_sec(TIME *, long *current_timezone); time_t str_to_timestamp(const char *str,uint length); bool str_to_time(const char *str,uint length,TIME *l_time); longlong str_to_datetime(const char *str,uint length,bool fuzzy_date); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e4f86a1818c..c2ee940af49 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -968,7 +968,6 @@ static void clean_up_mutexes() (void) pthread_mutex_destroy(&LOCK_crypt); (void) pthread_mutex_destroy(&LOCK_bytes_sent); (void) pthread_mutex_destroy(&LOCK_bytes_received); - (void) pthread_mutex_destroy(&LOCK_timezone); (void) pthread_mutex_destroy(&LOCK_user_conn); (void) pthread_mutex_destroy(&LOCK_rpl_status); (void) pthread_mutex_destroy(&LOCK_active_mi); @@ -1998,19 +1997,11 @@ int main(int argc, char **argv) } #endif #ifdef HAVE_TZNAME -#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT) { struct tm tm_tmp; localtime_r(&start_time,&tm_tmp); strmov(time_zone,tzname[tm_tmp.tm_isdst != 0 ? 1 : 0]); } -#else - { - struct tm *start_tm; - start_tm=localtime(&start_time); - strmov(time_zone,tzname[start_tm->tm_isdst != 0 ? 1 : 0]); - } -#endif #endif if (gethostname(glob_hostname,sizeof(glob_hostname)-4) < 0) @@ -2067,7 +2058,6 @@ int main(int argc, char **argv) (void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST); - (void) pthread_mutex_init(&LOCK_timezone,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST); diff --git a/sql/time.cc b/sql/time.cc index cc8cd4fbcf9..321a8ba16e5 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -28,7 +28,6 @@ uchar *days_in_month= (uchar*) "\037\034\037\036\037\036\037\037\036\037\036\037 /* Currently only my_time_zone is inited */ static long my_time_zone=0; -pthread_mutex_t LOCK_timezone; void init_time(void) { @@ -39,14 +38,14 @@ void init_time(void) seconds= (time_t) time((time_t*) 0); localtime_r(&seconds,&tm_tmp); l_time= &tm_tmp; - my_time_zone=0; + my_time_zone= 3600; /* Comp. for -3600 in my_gmt_sec */ my_time.year= (uint) l_time->tm_year+1900; my_time.month= (uint) l_time->tm_mon+1; my_time.day= (uint) l_time->tm_mday; my_time.hour= (uint) l_time->tm_hour; my_time.minute= (uint) l_time->tm_min; - my_time.second= (uint) l_time->tm_sec; - VOID(my_gmt_sec(&my_time)); /* Init my_time_zone */ + my_time.second= (uint) l_time->tm_sec; + my_gmt_sec(&my_time, &my_time_zone); /* Init my_time_zone */ } /* @@ -57,26 +56,39 @@ void init_time(void) */ -long my_gmt_sec(TIME *t) +long my_gmt_sec(TIME *t, long *my_timezone) { uint loop; time_t tmp; struct tm *l_time,tm_tmp; - long diff; + long diff, current_timezone; if (t->hour >= 24) { /* Fix for time-loop */ t->day+=t->hour/24; t->hour%=24; } - pthread_mutex_lock(&LOCK_timezone); - tmp=(time_t) ((calc_daynr((uint) t->year,(uint) t->month,(uint) t->day) - - (long) days_at_timestart)*86400L + (long) t->hour*3600L + - (long) (t->minute*60 + t->second)) + (time_t) my_time_zone; + + /* + Calculate the gmt time based on current time and timezone + The -1 on the end is to ensure that if have a date that exists twice + (like 2002-10-27 02:00:0 MET), we will find the initial date. + + By doing -3600 we will have to call localtime_r() several times, but + I couldn't come up with a better way to get a repeatable result :( + + We can't use mktime() as it's buggy on many platforms and not thread safe. + */ + tmp=(time_t) (((calc_daynr((uint) t->year,(uint) t->month,(uint) t->day) - + (long) days_at_timestart)*86400L + (long) t->hour*3600L + + (long) (t->minute*60 + t->second)) + (time_t) my_time_zone - + 3600); + current_timezone= my_time_zone; + localtime_r(&tmp,&tm_tmp); l_time=&tm_tmp; for (loop=0; - loop < 3 && + loop < 2 && (t->hour != (uint) l_time->tm_hour || t->minute != (uint) l_time->tm_min); loop++) @@ -89,14 +101,16 @@ long my_gmt_sec(TIME *t) days= -1; diff=(3600L*(long) (days*24+((int) t->hour - (int) l_time->tm_hour)) + (long) (60*((int) t->minute - (int) l_time->tm_min))); - my_time_zone+=diff; - tmp+=(time_t) diff; + current_timezone+= diff+3600; // Compensate for -3600 above + tmp+= (time_t) diff; localtime_r(&tmp,&tm_tmp); l_time=&tm_tmp; } - /* Fix that if we are in the not existing daylight saving time hour - we move the start of the next real hour */ - if (loop == 3 && t->hour != (uint) l_time->tm_hour) + /* + Fix that if we are in the not existing daylight saving time hour + we move the start of the next real hour + */ + if (loop == 2 && t->hour != (uint) l_time->tm_hour) { int days= t->day - l_time->tm_mday; if (days < -1) @@ -108,11 +122,9 @@ long my_gmt_sec(TIME *t) if (diff == 3600) tmp+=3600 - t->minute*60 - t->second; // Move to next hour else if (diff == -3600) - tmp-=t->minute*60 + t->second; // Move to next hour + tmp-=t->minute*60 + t->second; // Move to previous hour } - if ((my_time_zone >=0 ? my_time_zone: -my_time_zone) > 3600L*12) - my_time_zone=0; /* Wrong date */ - pthread_mutex_unlock(&LOCK_timezone); + *my_timezone= current_timezone; return (long) tmp; } /* my_gmt_sec */ @@ -399,6 +411,8 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) time_t str_to_timestamp(const char *str,uint length) { TIME l_time; + long not_used; + if (str_to_TIME(str,length,&l_time,0) == TIMESTAMP_NONE) return(0); if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR) @@ -406,7 +420,7 @@ time_t str_to_timestamp(const char *str,uint length) current_thd->cuted_fields++; return(0); } - return(my_gmt_sec(&l_time)); + return(my_gmt_sec(&l_time, ¬_used)); } From c1607401de71e400b5d2c1e1e1351edbe428cd4e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 May 2003 18:16:50 +0200 Subject: [PATCH 23/40] Removed bad mutex locking --- sql/slave.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sql/slave.cc b/sql/slave.cc index b620603dc63..b655b17c258 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1320,11 +1320,7 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli) while (rli->log_space_limit < rli->log_space_total && !(slave_killed=io_slave_killed(thd,mi)) && !rli->ignore_log_space_limit) - { pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock); - /* Re-acquire the mutex as pthread_cond_wait released it */ - pthread_mutex_lock(&rli->log_space_lock); - } thd->proc_info = save_proc_info; pthread_mutex_unlock(&rli->log_space_lock); DBUG_RETURN(slave_killed); From 8e20fc57ed1ee05dbb47114186e99ecfec509422 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 May 2003 18:34:03 +0200 Subject: [PATCH 24/40] - removed internals.texi (has been moved to the "mysqldoc" BK tree) BitKeeper/deleted/.del-internals.texi~62b6f580a41c2a43: Delete: Docs/internals.texi --- Docs/internals.texi | 694 -------------------------------------------- 1 file changed, 694 deletions(-) delete mode 100644 Docs/internals.texi diff --git a/Docs/internals.texi b/Docs/internals.texi deleted file mode 100644 index 2195b42d9a0..00000000000 --- a/Docs/internals.texi +++ /dev/null @@ -1,694 +0,0 @@ -\input texinfo @c -*-texinfo-*- -@c Copyright 1998 TcX AB, Detron HB and Monty Program KB -@c -@c %**start of header -@setfilename internals.info -@c We want the types in the same index -@c @synindex tp fn cp -@synindex cp fn -@iftex -@c Well this is normal in Europe. Maybe this should go into the include.texi? -@afourpaper -@end iftex -@c Get version and other info -@include include.texi -@ifclear tex-debug -@c This removes the black squares in the right margin -@finalout -@end ifclear -@c Set background for HTML -@set _body_tags BGCOLOR=#FFFFFF TEXT=#000000 LINK=#101090 VLINK=#7030B0 -@settitle @strong{MySQL} internals Manual for version @value{mysql_version}. -@setchapternewpage off -@paragraphindent 0 -@c %**end of header - -@ifinfo -@format -START-INFO-DIR-ENTRY -* mysql-internals: (mysql-internals). @strong{MySQL} internals. -END-INFO-DIR-ENTRY -@end format -@end ifinfo - -@titlepage -@sp 10 -@center @titlefont{@strong{MySQL} Internals Manual} -@sp 10 -@center Copyright @copyright{} 1998 TcX AB, Detron HB and Monty Program KB -@end titlepage - -@node Top, Introduction, (dir), (dir) - -@ifinfo -This is a manual about @strong{MySQL} internals. -@end ifinfo - -@menu -@end menu - -@node caching,,, -@chapter How MySQL handles caching - -@strong{MySQL} has the following caches: -(Note that the some of the filename have a wrong spelling of cache. :) - -@itemize @bullet - -@item Key cache -A shared cache for all B-tree index blocks in the different NISAM -files. Uses hashing and reverse linked lists for quick caching of the -last used blocks and quick flushing of changed entries for a specific -table. (@file{mysys/mf_keycash.c}) - -@item Record cache -This is used for quick scanning of all records in a table. -(@file{mysys/mf_iocash.c} and @file{isam/_cash.c}) - -@item Table cache -This holds the last used tables. (@file{sql/sql_base.cc}) - -@item Hostname cache -For quick lookup (with reverse name resolving). Is a must when one has a -slow DNS. -(@file{sql/hostname.cc}) - -@item Privilege cache -To allow quick change between databases the last used privileges are -cached for each user/database combination. -(@file{sql/sql_acl.cc}) - -@item Heap table cache -Many use of GROUP BY or DISTINCT caches all found -rows in a HEAP table (this is a very quick in-memory table with hash index) - -@item Join row cache. -For every full join in a SELECT statement (a full join here means there -were no keys that one could use to find the next table in a list), the -found rows are cached in a join cache. One SELECT query can use many -join caches in the worst case. -@end itemize - -@node flush tables,,, -@chapter How MySQL handles flush tables - -@itemize @bullet - -@item -Flush tables is handled in @code{sql/sql_base.cc::close_cached_tables()}. - -@item -The idea of flush tables is to force all tables to be closed. This -is mainly to ensure that if someone adds a new table outside of -@strong{MySQL} (for example with @code{cp}) all threads will start using -the new table. This will also ensure that all table changes are flushed -to disk (but of course not as optimally as simple calling a sync on -all tables)! - -@item -When one does a @code{FLUSH TABLES}, the variable @code{refresh_version} -will be incremented. Every time a thread releases a table it checks if -the refresh version of the table (updated at open) is the same as -the current refresh_version. If not it will close it and broadcast -a signal on COND_refresh (to wait any thread that is waiting for -all instanses of a table to be closed). - -@item -The current @code{refresh_version} is also compared to the open -@code{refresh_version} after a thread gets a lock on a table. If the -refresh version is different the thread will free all locks, reopen the -table and try to get the locks again; This is just to quickly get all -tables to use the newest version. This is handled by -@code{sql/lock.cc::mysql_lock_tables()} and -@code{sql/sql_base.cc::wait_for_tables()}. - -@item -When all tables has been closed @code{FLUSH TABLES} will return an ok -to client. - -@item -If the thread that is doing @code{FLUSH TABLES} has a lock on some tables, -it will first close the locked tables, then wait until all other threads -have also closed them, and then reopen them and get the locks. -After this it will give other threads a chance to open the same tables. - -@end itemize - -@node Filesort,,, -@chapter How MySQL does sorting (filesort) - -@itemize @bullet - -@item -Read all rows according to key or by table scanning. - -@item -Store the sort-key in a buffer (@code{sort_buffer}). - -@item -When the buffer gets full, run a qsort on it and store the result -in a temporary file. Save a pointer to the sorted block. - -@item -Repeat the above until all rows have been read. - -@item -Repeat the following until there is less than @code{MERGEBUFF2} (15) -blocks left. - -@item -Do a multi-merge of up to @code{MERGEBUFF} (7) regions to one block in -another temporary file. Repeat until all blocks from the first file -are in the second file. - -@item -On the last multi-merge, only the pointer to the row (last part of -the sort-key) is written to a result file. - -@item -Now the code in @file{sql/records.cc} will be used to read through them -in sorted order by using the row pointers in the result file. -To optimize this, we read in a big block of row pointers, sort these -and then we read the rows in the sorted order into a row buffer -(@code{record_buffer}) . - -@end itemize - -@node Coding guidelines,,, -@chapter Coding guidelines - -@itemize @bullet - -@item -We are using @uref{http://www.bitkeeper.com/, BitKeeper} for source management. - -@item -You should use the @strong{MySQL} 3.23 or 4.0 source for all developments. - -@item -If you have any questions about the @strong{MySQL} source, you can post these -to @email{developers@@mysql.com} and we will answer them. -Note that we will shortly change the name of this list to -@email{internals@@mysql.com}, to more accurately reflect what should be -posted to this list. - -@item -Try to write code in a lot of black boxes that can be reused or at -least have a clean interface. - -@item -Reuse code; There is already a lot of algorithms in MySQL for list handling, -queues, dynamic and hashed arrays, sorting, etc. that can be reused. - -@item -Try to always write optimized code, so that you don't have to -go back and rewrite it a couple of months later. It's better to -spend 3 times as much time designing and writing an optimal function than -having to do it all over again later on. - -@item -Avoid CPU wasteful code, even where it does not matter, so that -you will not develop sloppy coding habits. - -@item -If you can write it in fewer lines, do it (as long as the code will not -be slower or much harder to read). - -@item -Don't use two commands on the same line. - -@item -Do not check the same pointer for @code{NULL} more than once. - -@item -Use long function and variable names in English; This makes your code -easier to read. Use the 'varible_name' style instead of 'VariableName'. - -@item -Think assembly - make it easier for the compiler to optimize your code. - -@item -Comment your code when you do something that someone else may think -is not ''trivial''. - -@item -Use the @code{my_*} functions like @code{my_read()}/@code{my_write()}/ -@code{my_malloc()} that you can find in the @code{mysys} library instead -of the direct system calls; This will make your code easier to debug and -more portable. - -@item -Use @code{libstring} functions instead of standard libc string functions -whenever possible. - -@item -Avoid using @code{malloc()} (its REAL slow); For memory allocations -that only need to live for the lifetime of one thread, one should use -@code{sql_alloc()} instead. - -@item -Before making big design decisions, please first post a summary of -what you want to do, why you want to do it, and how you plan to do -it. This way we can easily provide you with feedback and also -easily discuss it thoroughly if some other developer thinks there is better -way to do the same thing! - -@item -Use my_var as opposed to myVar or MyVar (@samp{_} rather than dancing SHIFT -to seperate words in identifiers). - -@item -Class names start with a capital letter. - -@item -Structure types are @code{typedef}'ed to an all-caps identifier. - -@item -Any @code{#define}'s are in all-caps. - -@item -Matching @samp{@{} are in the same column. - -@item -Put the @samp{@{} after a 'switch' on the same line - -@example -switch (arg) { -@end example - -Because this gives better overall indentation for the switch statement. - -@item -In all other cases, @{ and @} should be on their own line, except -if there is nothing inside @{ @}. - -@item -Have a space after 'if' - -@item -Put a space after ',' for function arguments - -@item -Functions return 0 on success, and non-zero on error, so you can do: - -@example -if(a() || b() || c()) { error("something went wrong"); } -@end example - -@item -Using @code{goto} is okay if not abused. - -@item -Avoid default variable initalizations, use @code{LINT_INIT()} if the -compiler complains after making sure that there is really no way -the variable can be used uninitialized. - -@item -Do not instantiate a class if you do not have to. - -@item -Use pointers rather than array indexing when operating on strings. - -@end itemize - -Suggested mode in emacs: - -@example -(load "cc-mode") -(setq c-mode-common-hook '(lambda () - (turn-on-font-lock) - (setq comment-column 48))) -(setq c-style-alist - (cons - '("MY" - (c-basic-offset . 2) - (c-comment-only-line-offset . 0) - (c-offsets-alist . ((statement-block-intro . +) - (knr-argdecl-intro . 0) - (substatement-open . 0) - (label . -) - (statement-cont . +) - (arglist-intro . c-lineup-arglist-intro-after-paren) - (arglist-close . c-lineup-arglist) - )) - ) - c-style-alist)) -(c-set-style "MY") -(setq c-default-style "MY") -@end example - -@node mysys functions,,, -@chapter mysys functions - -Functions i mysys: (For flags se my_sys.h) - - int my_copy _A((const char *from,const char *to,myf MyFlags)); - - Copy file - - int my_delete _A((const char *name,myf MyFlags)); - - Delete file - - int my_getwd _A((string buf,uint size,myf MyFlags)); - int my_setwd _A((const char *dir,myf MyFlags)); - - Get and set working directory - - string my_tempnam _A((const char *pfx,myf MyFlags)); - - Make a uniq temp file name by using dir and adding something after - pfx to make name uniq. Name is made by adding a uniq 6 length-string - and TMP_EXT after pfx. - Returns pointer to malloced area for filename. Should be freed by - free(). - - File my_open _A((const char *FileName,int Flags,myf MyFlags)); - File my_create _A((const char *FileName,int CreateFlags, - int AccsesFlags, myf MyFlags)); - int my_close _A((File Filedes,myf MyFlags)); - uint my_read _A((File Filedes,byte *Buffer,uint Count,myf MyFlags)); - uint my_write _A((File Filedes,const byte *Buffer,uint Count, - myf MyFlags)); - ulong my_seek _A((File fd,ulong pos,int whence,myf MyFlags)); - ulong my_tell _A((File fd,myf MyFlags)); - - Use instead of open,open-with-create-flag, close read and write - to get automatic error-messages (flag: MYF_WME) and only have - to test for != 0 if error (flag: MY_NABP). - - int my_rename _A((const char *from,const char *to,myf MyFlags)); - - Rename file - - FILE *my_fopen _A((const char *FileName,int Flags,myf MyFlags)); - FILE *my_fdopen _A((File Filedes,int Flags,myf MyFlags)); - int my_fclose _A((FILE *fd,myf MyFlags)); - uint my_fread _A((FILE *stream,byte *Buffer,uint Count,myf MyFlags)); - uint my_fwrite _A((FILE *stream,const byte *Buffer,uint Count, - myf MyFlags)); - ulong my_fseek _A((FILE *stream,ulong pos,int whence,myf MyFlags)); - ulong my_ftell _A((FILE *stream,myf MyFlags)); - - Same read-interface for streams as for files - - gptr _mymalloc _A((uint uSize,const char *sFile, - uint uLine, myf MyFlag)); - gptr _myrealloc _A((string pPtr,uint uSize,const char *sFile, - uint uLine, myf MyFlag)); - void _myfree _A((gptr pPtr,const char *sFile,uint uLine)); - int _sanity _A((const char *sFile,unsigned int uLine)); - gptr _myget_copy_of_memory _A((const byte *from,uint length, - const char *sFile, uint uLine, - myf MyFlag)); - - malloc(size,myflag) is mapped to this functions if not compiled - with -DSAFEMALLOC - - void TERMINATE _A((void)); - - Writes malloc-info on stdout if compiled with -DSAFEMALLOC. - - int my_chsize _A((File fd,ulong newlength,myf MyFlags)); - - Change size of file - - void my_error _D((int nr,myf MyFlags, ...)); - - Writes message using error number (se mysys/errors.h) on - stdout or curses if MYSYS_PROGRAM_USES_CURSES() is called. - - void my_message _A((const char *str,myf MyFlags)); - - Writes message-string on - stdout or curses if MYSYS_PROGRAM_USES_CURSES() is called. - - void my_init _A((void )); - - Start each program (in main) with this. - void my_end _A((int infoflag)); - - Gives info about program. - - If infoflag & MY_CHECK_ERROR prints if some files are left open - - If infoflag & MY_GIVE_INFO prints timing info and malloc info - about prog. - - int my_redel _A((const char *from, const char *to, int MyFlags)); - - Delete from before rename of to to from. Copyes state from old - file to new file. If MY_COPY_TIME is set sets old time. - - int my_copystat _A((const char *from, const char *to, int MyFlags)); - - Copye state from old file to new file. - If MY_COPY_TIME is set sets copy also time. - - string my_filename _A((File fd)); - - Give filename of open file. - - int dirname _A((string to,const char *name)); - - Copy name of directory from filename. - - int test_if_hard_path _A((const char *dir_name)); - - Test if dirname is a hard path (Starts from root) - - void convert_dirname _A((string name)); - - Convert dirname acording to system. - - In MSDOS changes all caracters to capitals and changes '/' to - '\' - string fn_ext _A((const char *name)); - - Returns pointer to extension in filename - string fn_format _A((string to,const char *name,const char *dsk, - const char *form,int flag)); - format a filename with replace of library and extension and - converts between different systems. - params to and name may be identicall - function dosn't change name if name != to - Flag may be: 1 force replace filnames library with 'dsk' - 2 force replace extension with 'form' */ - 4 force Unpack filename (replace ~ with home) - 8 Pack filename as short as possibly for output to - user. - All open requests should allways use at least: - "open(fn_format(temp_buffe,name,"","",4),...)" to unpack home and - convert filename to system-form. - - string fn_same _A((string toname,const char *name,int flag)); - - Copys directory and extension from name to toname if neaded. - copy can be forced by same flags that in fn_format. - - int wild_compare _A((const char *str,const char *wildstr)); - - Compare if str matches wildstr. Wildstr can contain "*" and "?" - as match-characters. - Returns 0 if match. - - void get_date _A((string to,int timeflag)); - - Get current date in a form ready for printing. - - void soundex _A((string out_pntr, string in_pntr)) - - Makes in_pntr to a 5 chars long string. All words that sounds - alike have the same string. - - int init_key_cache _A((ulong use_mem,ulong leave_this_much_mem)); - - Use cacheing of keys in MISAM, PISAM, and ISAM. - KEY_CACHE_SIZE is a good size. - - Remember to lock databases for optimal cacheing - - void end_key_cache _A((void)); - - End key-cacheing. - -@node protocol,,, -@chapter MySQL client/server protocol - -Raw packet without compression -============================== -------------------------------------------------- -| Packet Length | Packet no | Data | -| 3 Bytes | 1 Byte | n Bytes | -------------------------------------------------- - -3 Byte packet length - The length is calculated with int3store - See include/global.h for details. - The max packetsize can be 16 MB. -1 Byte packet no - -If no compression is used the first 4 bytes of each paket -is the header of the paket. -The packet number is incremented for each sent packet. The first -packet starts with 0 - -n Byte data - -The packet length can be recalculated with: -length = byte1 + (256 * byte2) + (256 * 256 * byte3) - -Raw packet with compression -=========================== ------------------------------------------------------ -| Packet Length | Packet no | Uncomp. Packet Length | -| 3 Bytes | 1 Byte | 3 Bytes | ------------------------------------------------------ - -3 Byte packet length - The length is calculated with int3store - See include/global.h for details. - The max packetsize can be 16 MB. -1 Byte packet no -3 Byte uncompressed packet length - -If compression is used the first 7 bytes of each paket -is the header of the paket. - -Basic packets -============== -OK-packet - For details see sql/net_pkg.cc - function send_ok - ------------------------------------------------- - | Header | No of Rows | Affected Rows | - | | 1 Byte | 1-8 Byte | - ------------------------------------------------- - | ID (last_insert_id) | Status | Length | - | 1-8 Byte | 2 Byte | 1-8 Byte | - ------------------------------------------------- - | Messagetext | - | n Byte | - ------------------------------------------------- - - Header - 1 byte number of rows ? (always 0 ?) - 1-8 bytes affected rows - 1-8 byte id (last_insert_id) - 2 byte Status (usually 0) - If the OK-packege includes a message: - 1-8 bytes length of message - n bytes messagetext - -Error-packet - ------------------------------------------------- - | Header | Statuscode | Error no | - | | 1 Byte | 2 Byte | - ------------------------------------------------- - | Messagetext | 0x00 | - | n Byte | 1 Byte | - ------------------------------------------------- - - Header - 1 byte status code (0xFF = ERROR) - 2 byte error number (is only sent to new 3.23 clients. - n byte errortext - 1 byte 0x00 - - - -The communication -================= - -> Packet from server to client -< Paket from client tor server - - Login - ------ - > 1. packet - Header - 1 byte protocolversion - n byte serverversion - 1 byte 0x00 - 4 byte threadnumber - 8 byte crypt seed - 1 byte 0x00 - 2 byte CLIENT_xxx options (see include/mysql_com.h - that is supported by the server - 1 byte number of current server charset - 2 byte server status variables (SERVER_STATUS_xxx flags) - 13 byte 0x00 (not used yet). - - < 2. packet - Header - 2 byte CLIENT_xxx options - 3 byte max_allowed_packet for the client - n byte username - 1 byte 0x00 - 8 byte crypted password - 1 byte 0x00 - n byte databasename - 1 byte 0x00 - - > 3. packet - OK-packet - - - Command - -------- - < 1. packet - Header - 1 byte command type (e.g.0x03 = query) - n byte query - - Result set (after command) - -------------------------- - > 2. packet - Header - 1-8 byte field_count (packed with net_store_length()) - - If field_count == 0 (command): - 1-8 byte affected rows - 1-8 byte insert id - 2 bytes server_status (SERVER_STATUS_xx) - - If field_count == NULL_LENGTH (251) - LOAD DATA LOCAL INFILE - - If field_count > 0 Result Set: - - > n packets - Header Info - Column description: 5 data object /column - (See code in unpack_fields()) - - Columninfo for each column: - 1 data block table_name - 1 byte length of block - n byte data - 1 data block field_name - 1 byte length of block... - n byte data - 1 data block display length of field - 1 byte length of block - 3 bytes display length of filed - 1 data block type field of type (enum_field_types) - 1 byte length of block - 1 bytexs field of type - 1 data block flags - 1 byte length of block - 2 byte flags for the columns (NOT_NULL_FLAG, ZEROFILL_FLAG....) - 1 byte decimals - - if table definition: - 1 data block default value - - Actual result (one packet per row): - 4 byte header - 1-8 byte length of data - n data - - -Fieldtype Codes: -================ - - display_length |enum_field_type |flags - ---------------------------------------------------- -Blob 03 FF FF 00 |01 FC |03 90 00 00 -Mediumblob 03 FF FF FF |01 FC |03 90 00 00 -Tinyblob 03 FF 00 00 |01 FC |03 90 00 00 -Text 03 FF FF 00 |01 FC |03 10 00 00 -Mediumtext 03 FF FF FF |01 FC |03 10 00 00 -Tinytext 03 FF 00 00 |01 FC |03 10 00 00 -Integer 03 0B 00 00 |01 03 |03 03 42 00 -Mediumint 03 09 00 00 |01 09 |03 00 00 00 -Smallint 03 06 00 00 |01 02 |03 00 00 00 -Tinyint 03 04 00 00 |01 01 |03 00 00 00 -Varchar 03 XX 00 00 |01 FD |03 00 00 00 -Enum 03 05 00 00 |01 FE |03 00 01 00 -Datetime 03 13 00 00 |01 0C |03 00 00 00 -Timestamp 03 0E 00 00 |01 07 |03 61 04 00 -Time 03 08 00 00 |01 0B |03 00 00 00 -Date 03 0A 00 00 |01 0A |03 00 00 00 - - -@c The Index was empty, and ugly, so I removed it. (jcole, Sep 7, 2000) - -@c @node Index -@c @unnumbered Index - -@c @printindex fn - -@summarycontents -@contents - -@bye From 546b2221a23e122550b6b1bacf22781b54eaf55d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 May 2003 23:07:32 +0200 Subject: [PATCH 25/40] A trick (a useless update) to force the slave to wait for TWO rotate events before stopping. This is to make the test's result predictable (depending on the machine the results could formerly be slightly different, though everything is sane in the code; it's not a bug). mysql-test/r/rpl_log.result: result update --- mysql-test/r/rpl_log.result | 22 ++++++++++++++-------- mysql-test/t/rpl_log.test | 22 ++++++++++++++++++++++ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/rpl_log.result b/mysql-test/r/rpl_log.result index 5415a153a98..425c376af1e 100644 --- a/mysql-test/r/rpl_log.result +++ b/mysql-test/r/rpl_log.result @@ -36,6 +36,8 @@ show binlog events from 79 limit 2,1; Log_name Pos Event_type Server_id Orig_log_pos Info master-bin.001 200 Query 1 200 use test; insert into t1 values (NULL) flush logs; +create table t5 (a int); +drop table t5; slave start; flush logs; slave stop; @@ -56,9 +58,11 @@ master-bin.001 1079 Query 1 1079 use test; drop table t1 master-bin.001 1127 Rotate 1 1127 master-bin.002;pos=4 show binlog events in 'master-bin.002'; Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.002 4 Query 1 4 use test; create table t1 (n int) -master-bin.002 62 Query 1 62 use test; insert into t1 values (1) -master-bin.002 122 Query 1 122 use test; drop table t1 +master-bin.002 4 Query 1 4 use test; create table t5 (a int) +master-bin.002 62 Query 1 62 use test; drop table t5 +master-bin.002 110 Query 1 110 use test; create table t1 (n int) +master-bin.002 168 Query 1 168 use test; insert into t1 values (1) +master-bin.002 228 Query 1 228 use test; drop table t1 show master logs; Log_name master-bin.001 @@ -79,14 +83,16 @@ slave-bin.001 311 Query 1 311 use test; create table t1 (word char(20) not null) slave-bin.001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=581 slave-bin.001 1065 Exec_load 1 1056 ;file_id=1 slave-bin.001 1088 Query 1 1079 use test; drop table t1 -slave-bin.001 1136 Rotate 2 1136 slave-bin.002;pos=4 +slave-bin.001 1136 Query 1 4 use test; create table t5 (a int) +slave-bin.001 1194 Query 1 62 use test; drop table t5 +slave-bin.001 1242 Rotate 2 1242 slave-bin.002;pos=4 show binlog events in 'slave-bin.002' from 4; Log_name Pos Event_type Server_id Orig_log_pos Info -slave-bin.002 4 Query 1 4 use test; create table t1 (n int) -slave-bin.002 62 Query 1 62 use test; insert into t1 values (1) -slave-bin.002 122 Query 1 122 use test; drop table t1 +slave-bin.002 4 Query 1 110 use test; create table t1 (n int) +slave-bin.002 62 Query 1 168 use test; insert into t1 values (1) +slave-bin.002 122 Query 1 228 use test; drop table t1 show slave status; Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos Relay_log_space -127.0.0.1 root MASTER_PORT 1 master-bin.002 170 slave-relay-bin.002 1457 master-bin.002 Yes Yes 0 0 170 1461 +127.0.0.1 root MASTER_PORT 1 master-bin.002 276 slave-relay-bin.002 1522 master-bin.002 Yes Yes 0 0 276 1526 show binlog events in 'slave-bin.005' from 4; Error when executing command SHOW BINLOG EVENTS: Could not find target log diff --git a/mysql-test/t/rpl_log.test b/mysql-test/t/rpl_log.test index 85782e78142..8cd9d21a087 100644 --- a/mysql-test/t/rpl_log.test +++ b/mysql-test/t/rpl_log.test @@ -22,10 +22,32 @@ show binlog events from 79 limit 2; show binlog events from 79 limit 2,1; flush logs; +# We need an extra update before doing save_master_pos. +# Otherwise, an unlikely scenario may occur: +# * When the master's binlog_dump thread reads the end of master-bin.001, +# it send the rotate event which is at this end, plus a fake rotate event +# because it's starting to read a new binlog. +# save_master_pos will record the position of the first of the two rotate +# (because the fake one is not in the master's binlog anyway). +# * Later the slave waits for the position of the first rotate event, +# and it may quickly stop (in 'slave stop') without having received the fake +# one. +# So, depending on a few milliseconds, we end up with 2 rotate events in the +# relay log or one, which influences the output of SHOW SLAVE STATUS, making +# it not predictable and causing random test failures. +# To make it predictable, we do a useless update now, but which has the interest +# of making the slave catch both rotate events. + +create table t5 (a int); +drop table t5; + # Sync slave and force it to start on another binary log save_master_pos; connection slave; +# Note that the above 'slave start' will cause a 3rd rotate event (a fake one) +# to go into the relay log (the master always sends a fake one when replication +# starts). slave start; sync_with_master; flush logs; From 838c616397d33ac0e8e03d28403f03f32d728794 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 28 May 2003 03:36:44 +0300 Subject: [PATCH 26/40] Removed not used variable --- libmysqld/lib_sql.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 83f398ca50b..7682d60d991 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -436,7 +436,6 @@ int STDCALL mysql_server_init(int argc, char **argv, char **groups) (void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST); - (void) pthread_mutex_init(&LOCK_timezone,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST); From 99d306b77e9502aa14bcb6d76af724ce6ab28b34 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 28 May 2003 11:24:48 +0500 Subject: [PATCH 27/40] item_cmpfunc.cc: Fix for multibyte charsets sql/item_cmpfunc.cc: Fix for multibyte charsets --- sql/item_cmpfunc.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index d96069a17aa..3344f2bc01d 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1454,7 +1454,11 @@ bool Item_func_like::fix_fields(THD *thd,struct st_table_list *tlist) { const char* tmp = first + 1; for (; *tmp != wild_many && *tmp != wild_one && *tmp != escape; tmp++) ; +#ifdef USE_MB + canDoTurboBM = (tmp == last) && !use_mb(default_charset_info); +#else canDoTurboBM = tmp == last; +#endif } if (canDoTurboBM) From 936a8aecd55b7c672401794d0fabb85ca95157a4 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 28 May 2003 20:31:33 +0300 Subject: [PATCH 28/40] srv0srv.c: Prevent the InnoDB main thread from hogging CPU if a table lingers in the background drop queue (though it is essentially a bug if a table end up there at all) innobase/srv/srv0srv.c: Prevent the InnoDB main thread from hogging CPU if a table lingers in the background drop queue (though it is essentially a bug if a table end up there at all) --- innobase/srv/srv0srv.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index 84d48bebf97..ac2622df78a 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -2790,6 +2790,15 @@ background_loop: n_tables_to_drop = row_drop_tables_for_mysql_in_background(); + if (n_tables_to_drop > 0) { + /* Do not monopolize the CPU even if there are tables waiting + in the background drop queue. (It is essentially a bug if + MySQL tries to drop a table while there are still open handles + to it and we had to put it to the background drop queue.) */ + + os_thread_sleep(100000); + } + srv_main_thread_op_info = (char*)""; srv_main_thread_op_info = (char*)"flushing buffer pool pages"; From 0829e8706dd7d3ebb415865493ea71297d5d8781 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 29 May 2003 14:52:25 +0500 Subject: [PATCH 29/40] Fix for bug #529 ("x509" no allowed as field name) --- sql/sql_yacc.yy | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 340fbc1b3dc..c79750c8014 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3397,6 +3397,7 @@ keyword: | USE_FRM {} | VARIABLES {} | WORK_SYM {} + | X509_SYM {} | YEAR_SYM {}; /* Option functions */ From fadfa46796576b5566ee3f45920b07e2f2326552 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 30 May 2003 18:41:19 +0500 Subject: [PATCH 30/40] Fix for compiling MySQL-4.0.13 with SSL support on OpenBSD --- include/my_global.h | 2 +- sql/mysql_priv.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/my_global.h b/include/my_global.h index ca24c21c688..d892d843edc 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -246,7 +246,7 @@ C_MODE_END # endif #endif /* TIME_WITH_SYS_TIME */ #ifdef HAVE_UNISTD_H -#if defined(HAVE_OPENSSL) && !defined(__FreeBSD__) && !defined(NeXT) +#if defined(HAVE_OPENSSL) && !defined(__FreeBSD__) && !defined(NeXT) && !defined(__OpenBSD__) #define crypt unistd_crypt #endif #include diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 614cb8cadf6..b191a702efe 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -458,6 +458,7 @@ Field *find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables); Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, bool check_grant,bool allow_rowid); #ifdef HAVE_OPENSSL +#include struct st_des_keyblock { des_cblock key1, key2, key3; From d9711e32b966610af3969c76f7e96f18478dffca Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 30 May 2003 22:44:37 +0300 Subject: [PATCH 31/40] Many files: Exit all threads created by innoDB at shutdown innobase/os/os0file.c: Exit all threads created by innoDB at shutdown innobase/os/os0sync.c: Exit all threads created by innoDB at shutdown innobase/os/os0thread.c: Exit all threads created by innoDB at shutdown innobase/include/os0file.h: Exit all threads created by innoDB at shutdown innobase/include/os0sync.h: Exit all threads created by innoDB at shutdown innobase/include/os0thread.h: Exit all threads created by innoDB at shutdown innobase/log/log0log.c: Exit all threads created by innoDB at shutdown innobase/srv/srv0srv.c: Exit all threads created by innoDB at shutdown innobase/srv/srv0start.c: Exit all threads created by innoDB at shutdown --- innobase/include/os0file.h | 7 +++++ innobase/include/os0sync.h | 12 +++++++- innobase/include/os0thread.h | 8 ++--- innobase/log/log0log.c | 27 +++++++++-------- innobase/os/os0file.c | 45 +++++++++++++++++++++++++++- innobase/os/os0sync.c | 27 +++++++++++++++-- innobase/os/os0thread.c | 30 +++++++++++++++++-- innobase/srv/srv0srv.c | 13 ++++++++ innobase/srv/srv0start.c | 58 ++++++++++++++++++++++++++++++++++++ 9 files changed, 205 insertions(+), 22 deletions(-) diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index a7624a90d5e..86f27a2d3eb 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -301,6 +301,13 @@ os_aio( are ignored */ void* message2); /**************************************************************************** +Wakes up all async i/o threads so that they know to exit themselves in +shutdown. */ + +void +os_aio_wake_all_threads_at_shutdown(void); +/*=====================================*/ +/**************************************************************************** Waits until there are no pending writes in os_aio_write_array. There can be other, synchronous, pending writes. */ diff --git a/innobase/include/os0sync.h b/innobase/include/os0sync.h index b2d613c4619..d52444d02ec 100644 --- a/innobase/include/os0sync.h +++ b/innobase/include/os0sync.h @@ -38,6 +38,13 @@ typedef os_mutex_str_t* os_mutex_t; #define OS_SYNC_TIME_EXCEEDED 1 +/* Mutex protecting the thread count */ +extern os_mutex_t os_thread_count_mutex; + +/* This is incremented by 1 in os_thread_create and decremented by 1 in +os_thread_exit */ +extern ulint os_thread_count; + /************************************************************* Creates an event semaphore, i.e., a semaphore which may just have two states: signaled and nonsignaled. @@ -85,7 +92,10 @@ os_event_free( /*==========*/ os_event_t event); /* in: event to free */ /************************************************************** -Waits for an event object until it is in the signaled state. */ +Waits for an event object until it is in the signaled state. If +srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the +waiting thread when the event becomes signaled (or immediately if the +event is already in the signaled state). */ void os_event_wait( diff --git a/innobase/include/os0thread.h b/innobase/include/os0thread.h index 629cfef23a8..29154a9e7cf 100644 --- a/innobase/include/os0thread.h +++ b/innobase/include/os0thread.h @@ -11,6 +11,7 @@ Created 9/8/1995 Heikki Tuuri #define os0thread_h #include "univ.i" +#include "os0sync.h" /* Maximum number of threads which can be created in the program; this is also the size of the wait slot array for MySQL threads which @@ -41,7 +42,6 @@ typedef os_thread_t os_thread_id_t; /* In Unix we use the thread the thread */ #endif - /* Define a function pointer type to use in a typecast */ typedef void* (*os_posix_f_t) (void*); @@ -83,12 +83,13 @@ os_thread_create( os_thread_id_t* thread_id); /* out: id of the created thread */ /********************************************************************* -A thread calling this function ends its execution. */ +Exits the current thread. */ void os_thread_exit( /*===========*/ - ulint code); /* in: exit code */ + void* exit_value); /* in: exit value; in Windows this void* + is cast as a DWORD */ /********************************************************************* Returns the thread identifier of current thread. */ @@ -144,7 +145,6 @@ ulint os_thread_get_last_error(void); /*==========================*/ - #ifndef UNIV_NONINL #include "os0thread.ic" #endif diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c index 25cc666e802..e15812e03af 100644 --- a/innobase/log/log0log.c +++ b/innobase/log/log0log.c @@ -375,7 +375,7 @@ log_pad_current_log_block(void) log_close(); log_release(); - ut_a((ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE) + ut_ad((ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE) == LOG_BLOCK_HDR_SIZE); } @@ -998,6 +998,8 @@ log_group_file_header_flush( { byte* buf; ulint dest_offset; + + UT_NOT_USED(type); ut_ad(mutex_own(&(log_sys->mutex))); @@ -1068,8 +1070,8 @@ log_group_write_buf( ulint i; ut_ad(mutex_own(&(log_sys->mutex))); - ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0); - ut_a(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_ad(len % OS_FILE_LOG_BLOCK_SIZE == 0); + ut_ad(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); if (new_data_offset == 0) { write_header = TRUE; @@ -2901,10 +2903,9 @@ logs_empty_and_mark_files_at_shutdown(void) dulint lsn; ulint arch_log_no; - if (srv_print_verbose_log) - { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Starting shutdown...\n"); + if (srv_print_verbose_log) { + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Starting shutdown...\n"); } /* Wait until the master thread and all other operations are idle: our algorithm only works if the server is idle at shutdown */ @@ -3006,15 +3007,17 @@ loop: goto loop; } + /* Make some checks that the server really is quiet */ + ut_a(buf_all_freed()); + ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn)); + fil_write_flushed_lsn_to_data_files(lsn, arch_log_no); fil_flush_file_spaces(FIL_TABLESPACE); - if (srv_print_verbose_log) - { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Shutdown completed\n"); - } + /* Make some checks that the server really is quiet */ + ut_a(buf_all_freed()); + ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn)); } /********************************************************** diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index c7f95d79104..640ffec122f 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -1295,7 +1295,6 @@ os_aio_array_create( #endif ut_a(n > 0); ut_a(n_segments > 0); - ut_a(n % n_segments == 0); array = ut_malloc(sizeof(os_aio_array_t)); @@ -1404,6 +1403,50 @@ os_aio_init( pthread_sigmask(SIG_BLOCK, &sigset, NULL); */ #endif } + +#ifdef WIN_ASYNC_IO +/**************************************************************************** +Wakes up all async i/o threads in the array in Windows async i/o at +shutdown. */ +static +void +os_aio_array_wake_win_aio_at_shutdown( +/*==================================*/ + os_aio_array_t* array) /* in: aio array */ +{ + ulint i; + + for (i = 0; i < array->n_slots; i++) { + + os_event_set(*(array->events + i)); + } +} +#endif + +/**************************************************************************** +Wakes up all async i/o threads so that they know to exit themselves in +shutdown. */ + +void +os_aio_wake_all_threads_at_shutdown(void) +/*=====================================*/ +{ + ulint i; + +#ifdef WIN_ASYNC_IO + /* This code wakes up all ai/o threads in Windows native aio */ + os_aio_array_wake_win_aio_at_shutdown(os_aio_read_array); + os_aio_array_wake_win_aio_at_shutdown(os_aio_write_array); + os_aio_array_wake_win_aio_at_shutdown(os_aio_ibuf_array); + os_aio_array_wake_win_aio_at_shutdown(os_aio_log_array); +#endif + /* This loop wakes up all simulated ai/o threads */ + + for (i = 0; i < os_aio_n_segments; i++) { + + os_event_set(os_aio_segment_wait_events[i]); + } +} /**************************************************************************** Waits until there are no pending writes in os_aio_write_array. There can diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index 407b280f805..abcfa254710 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -17,6 +17,7 @@ Created 9/6/1995 Heikki Tuuri #endif #include "ut0mem.h" +#include "srv0start.h" /* Type definition for an operating system mutex struct */ struct os_mutex_struct{ @@ -26,9 +27,16 @@ struct os_mutex_struct{ recursively lock the mutex: we do not assume that the OS mutex supports recursive locking, though - NT seems to do that */ + NT seems to do that */ }; +/* Mutex protecting the thread count */ +os_mutex_t os_thread_count_mutex; + +/* This is incremented by 1 in os_thread_create and decremented by 1 in +os_thread_exit */ +ulint os_thread_count = 0; + /************************************************************* Creates an event semaphore, i.e., a semaphore which may just have two states: signaled and nonsignaled. @@ -190,7 +198,10 @@ os_event_free( } /************************************************************** -Waits for an event object until it is in the signaled state. */ +Waits for an event object until it is in the signaled state. If +srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the +waiting thread when the event becomes signaled (or immediately if the +event is already in the signaled state). */ void os_event_wait( @@ -206,12 +217,20 @@ os_event_wait( err = WaitForSingleObject(event, INFINITE); ut_a(err == WAIT_OBJECT_0); + + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + os_thread_exit(NULL); + } #else os_fast_mutex_lock(&(event->os_mutex)); loop: if (event->is_set == TRUE) { os_fast_mutex_unlock(&(event->os_mutex)); + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + + os_thread_exit(NULL); + } /* Ok, we may return */ return; @@ -299,6 +318,10 @@ os_event_wait_multiple( ut_a(index >= WAIT_OBJECT_0); ut_a(index < WAIT_OBJECT_0 + n); + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + os_thread_exit(NULL); + } + return(index - WAIT_OBJECT_0); #else ut_a(n == 0); diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index b0076921e43..a68f6a3b8bc 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -1,6 +1,5 @@ /****************************************************** -The interface to the operating system -process and thread control primitives +The interface to the operating system thread control primitives (c) 1995 Innobase Oy @@ -102,6 +101,10 @@ os_thread_create( os_thread_t thread; ulint win_thread_id; + os_mutex_enter(os_thread_count_mutex); + os_thread_count++; + os_mutex_exit(os_thread_count_mutex); + thread = CreateThread(NULL, /* no security attributes */ 0, /* default size stack */ (LPTHREAD_START_ROUTINE)start_f, @@ -144,6 +147,9 @@ os_thread_create( exit(1); } #endif + os_mutex_enter(os_thread_count_mutex); + os_thread_count++; + os_mutex_exit(os_thread_count_mutex); #if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10) ret = pthread_create(&pthread, pthread_attr_default, start_f, arg); @@ -170,6 +176,26 @@ os_thread_create( #endif } +/********************************************************************* +Exits the current thread. */ + +void +os_thread_exit( +/*===========*/ + void* exit_value) /* in: exit value; in Windows this void* + is cast as a DWORD */ +{ + os_mutex_enter(os_thread_count_mutex); + os_thread_count--; + os_mutex_exit(os_thread_count_mutex); + +#ifdef __WIN__ + ExitThread((DWORD)exit_value); +#else + pthread_exit(exit_value); +#endif +} + /********************************************************************* Returns handle to the current thread. */ diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index ef50a4ca261..a44bc0147e4 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -1702,6 +1702,8 @@ void srv_general_init(void) /*==================*/ { + os_thread_count_mutex = os_mutex_create(NULL); + sync_init(); mem_init(srv_mem_pool_size); thr_local_init(); @@ -1720,6 +1722,8 @@ srv_general_free(void) /*==================*/ { sync_close(); + + os_mutex_free(os_thread_count_mutex); } #endif /* __NETWARE__ */ @@ -2700,6 +2704,8 @@ loop: srv_error_monitor_active = FALSE; + os_thread_exit(NULL); + #ifndef __WIN__ return(NULL); #else @@ -3139,6 +3145,13 @@ suspend_thread: os_event_wait(event); + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + /* This is only extra safety, the thread should exit + already when the event wait ends */ + + os_thread_exit(NULL); + } + /* When there is user activity, InnoDB will set the event and the main thread goes back to loop: */ diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index d47af68d663..3d98e116905 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1470,6 +1470,8 @@ innobase_shutdown_for_mysql(void) /*=============================*/ /* out: DB_SUCCESS or error code */ { + ulint i; + if (!srv_was_started) { if (srv_is_being_started) { ut_print_timestamp(stderr); @@ -1494,6 +1496,58 @@ innobase_shutdown_for_mysql(void) srv_conc_n_threads); } + /* Now we will exit all threads InnoDB created */ + + srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS; + + /* All threads end up waiting for certain events. Put those events + to the signaled state. Then the threads will exit themselves in + os_thread_event_wait(). */ + + for (i = 0; i < 1000; i++) { + /* NOTE: IF YOU CREATE THREADS IN INNODB, YOU MUST EXIT THEM + HERE OR EARLIER */ + + /* 1. Let the lock timeout thread exit */ + os_event_set(srv_lock_timeout_thread_event); + + /* 2. srv error monitor thread exits automatically, no need + to do anything here */ + + /* 3. We wake the master thread so that it exits */ + srv_wake_master_thread(); + + /* 4. Exit the i/o threads */ + + os_aio_wake_all_threads_at_shutdown(); + + os_mutex_enter(os_thread_count_mutex); + + if (os_thread_count == 0) { + /* All the threads have exited or are just exiting; + NOTE that the threads may not have completed their + exit yet. Should we use pthread_join() to make sure + they have exited? Now we just sleep 0.1 seconds and + hope that is enough! */ + + os_mutex_exit(os_thread_count_mutex); + + os_thread_sleep(100000); + + break; + } + + os_mutex_exit(os_thread_count_mutex); + + os_thread_sleep(100000); + } + + if (i == 1000) { + fprintf(stderr, +"InnoDB: Warning: %lu threads created by InnoDB had not exited at shutdown!\n", + os_thread_count); + } + #if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) /* TODO: Fix this temporary solution @@ -1518,6 +1572,10 @@ innobase_shutdown_for_mysql(void) /* NetWare requires this free */ ut_free_all_mem(); #endif + if (srv_print_verbose_log) { + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Shutdown completed\n"); + } return((int) DB_SUCCESS); } From 5d1171c024089093d6274dd9d18b480c93516109 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 30 May 2003 23:00:37 +0300 Subject: [PATCH 32/40] srv0start.c: Cleanup innobase/srv/srv0start.c: Cleanup --- innobase/srv/srv0start.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 3d98e116905..d34c18b1a25 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1549,13 +1549,6 @@ innobase_shutdown_for_mysql(void) } #if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) - /* - TODO: Fix this temporary solution - We are having a race condition occure with io_handler_thread threads. - When they yield in os_aio_simulated_handle during shutdown, this - thread was able to free the memory early. - */ - os_thread_yield(); /* TODO: Where should this be called? */ srv_free(); @@ -1563,11 +1556,7 @@ innobase_shutdown_for_mysql(void) /* TODO: Where should this be called? */ srv_general_free(); #endif - /* - TODO: We should exit the i/o-handler and other utility threads - before freeing all memory. Now this can potentially cause a seg - fault! - */ + #if defined(NOT_WORKING_YET) || defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) /* NetWare requires this free */ ut_free_all_mem(); From 185f0092bc8b8ee558a2bad15308168623e94b42 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 31 May 2003 01:41:11 +0300 Subject: [PATCH 33/40] fixed bug 549 - incorect query cache memory formating on very small query cache sizes mysql-test/r/query_cache.result: test of 2 parts of bug 549 mysql-test/t/query_cache.test: test of 2 parts of bug 549 sql/sql_cache.cc: fixed query cache size showing fixed query cache low memory detection --- mysql-test/r/query_cache.result | 60 +++++++++++++++++++++++++++------ mysql-test/t/query_cache.test | 35 ++++++++++++++----- sql/sql_cache.cc | 16 ++++----- 3 files changed, 83 insertions(+), 28 deletions(-) diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index a55e05578e0..6abd572b3d9 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -501,22 +501,62 @@ drop table t1; show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 0 +create table t1 (a int); set GLOBAL query_cache_size=1000; show global variables like "query_cache_size"; Variable_name Value query_cache_size 0 -set GLOBAL query_cache_size=1100; -set GLOBAL query_cache_size=1200; -set GLOBAL query_cache_size=1300; -set GLOBAL query_cache_size=1400; -set GLOBAL query_cache_size=1500; -set GLOBAL query_cache_size=1600; -set GLOBAL query_cache_size=1700; -set GLOBAL query_cache_size=1800; -set GLOBAL query_cache_size=1900; +select * from t1; +a +set GLOBAL query_cache_size=1024; show global variables like "query_cache_size"; Variable_name Value -query_cache_size 1024 +query_cache_size 0 +select * from t1; +a +set GLOBAL query_cache_size=10240; +show global variables like "query_cache_size"; +Variable_name Value +query_cache_size 0 +select * from t1; +a +set GLOBAL query_cache_size=20480; +show global variables like "query_cache_size"; +Variable_name Value +query_cache_size 0 +select * from t1; +a +set GLOBAL query_cache_size=40960; +show global variables like "query_cache_size"; +Variable_name Value +query_cache_size 0 +select * from t1; +a +set GLOBAL query_cache_size=51200; +show global variables like "query_cache_size"; +Variable_name Value +query_cache_size 51200 +select * from t1; +a +set GLOBAL query_cache_size=61440; +show global variables like "query_cache_size"; +Variable_name Value +query_cache_size 61440 +select * from t1; +a +set GLOBAL query_cache_size=81920; +show global variables like "query_cache_size"; +Variable_name Value +query_cache_size 81920 +select * from t1; +a +set GLOBAL query_cache_size=102400; +show global variables like "query_cache_size"; +Variable_name Value +query_cache_size 102400 +select * from t1; +a +drop table t1; set GLOBAL query_cache_size=1048576; create table t1 (i int not null); create table t2 (i int not null); diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 33f226f9253..f0f3063c00d 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -343,18 +343,35 @@ show status like "Qcache_queries_in_cache"; # # Test of query cache resizing # +create table t1 (a int); set GLOBAL query_cache_size=1000; show global variables like "query_cache_size"; -set GLOBAL query_cache_size=1100; -set GLOBAL query_cache_size=1200; -set GLOBAL query_cache_size=1300; -set GLOBAL query_cache_size=1400; -set GLOBAL query_cache_size=1500; -set GLOBAL query_cache_size=1600; -set GLOBAL query_cache_size=1700; -set GLOBAL query_cache_size=1800; -set GLOBAL query_cache_size=1900; +select * from t1; +set GLOBAL query_cache_size=1024; show global variables like "query_cache_size"; +select * from t1; +set GLOBAL query_cache_size=10240; +show global variables like "query_cache_size"; +select * from t1; +set GLOBAL query_cache_size=20480; +show global variables like "query_cache_size"; +select * from t1; +set GLOBAL query_cache_size=40960; +show global variables like "query_cache_size"; +select * from t1; +set GLOBAL query_cache_size=51200; +show global variables like "query_cache_size"; +select * from t1; +set GLOBAL query_cache_size=61440; +show global variables like "query_cache_size"; +select * from t1; +set GLOBAL query_cache_size=81920; +show global variables like "query_cache_size"; +select * from t1; +set GLOBAL query_cache_size=102400; +show global variables like "query_cache_size"; +select * from t1; +drop table t1; # # Temporary tables diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 59430d6a486..1fcd0d1456b 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -731,7 +731,7 @@ ulong Query_cache::resize(ulong query_cache_size_arg) query_cache_size_arg)); free_cache(0); query_cache_size= query_cache_size_arg; - DBUG_RETURN(init_cache()); + DBUG_RETURN(::query_cache_size= init_cache()); } @@ -1282,6 +1282,12 @@ ulong Query_cache::init_cache() mem_bin_steps = 1; mem_bin_size = max_mem_bin_size >> QUERY_CACHE_MEM_BIN_STEP_PWR2; prev_size = 0; + if (mem_bin_size <= min_allocation_unit) + { + DBUG_PRINT("qcache", ("too small query cache => query cache disabled")); + // TODO here (and above) should be warning in 4.1 + goto err; + } while (mem_bin_size > min_allocation_unit) { mem_bin_num += mem_bin_count; @@ -1308,14 +1314,6 @@ ulong Query_cache::init_cache() query_cache_size -= additional_data_size; STRUCT_LOCK(&structure_guard_mutex); - if (max_mem_bin_size <= min_allocation_unit) - { - DBUG_PRINT("qcache", - (" max bin size (%lu) <= min_allocation_unit => cache disabled", - max_mem_bin_size)); - STRUCT_UNLOCK(&structure_guard_mutex); - goto err; - } if (!(cache = (byte *) my_malloc_lock(query_cache_size+additional_data_size, MYF(0)))) From 3cba21f9f5abdaea110f40155467cab2899b5461 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 31 May 2003 03:12:03 +0300 Subject: [PATCH 34/40] Many files: Free all OS sync primitives and allocated memory in InnoDB shutdown innobase/os/os0sync.c: Free all OS sync primitives and allocated memory in InnoDB shutdown innobase/os/os0thread.c: Free all OS sync primitives and allocated memory in InnoDB shutdown innobase/include/os0sync.h: Free all OS sync primitives and allocated memory in InnoDB shutdown innobase/include/srv0srv.h: Free all OS sync primitives and allocated memory in InnoDB shutdown innobase/include/srv0start.h: Free all OS sync primitives and allocated memory in InnoDB shutdown innobase/ibuf/ibuf0ibuf.c: Free all OS sync primitives and allocated memory in InnoDB shutdown innobase/srv/srv0srv.c: Free all OS sync primitives and allocated memory in InnoDB shutdown innobase/srv/srv0start.c: Free all OS sync primitives and allocated memory in InnoDB shutdown innobase/sync/sync0sync.c: Free all OS sync primitives and allocated memory in InnoDB shutdown innobase/ut/ut0mem.c: Free all OS sync primitives and allocated memory in InnoDB shutdown --- innobase/include/os0sync.h | 36 +++++++--- innobase/include/srv0srv.h | 6 ++ innobase/include/srv0start.h | 7 +- innobase/os/os0sync.c | 128 ++++++++++++++++++++++++++++++++--- innobase/os/os0thread.c | 12 ++-- innobase/srv/srv0srv.c | 71 ++++--------------- innobase/srv/srv0start.c | 32 ++++----- innobase/sync/sync0sync.c | 27 ++++++-- innobase/ut/ut0mem.c | 2 + 9 files changed, 214 insertions(+), 107 deletions(-) diff --git a/innobase/include/os0sync.h b/innobase/include/os0sync.h index d52444d02ec..3096c9256ed 100644 --- a/innobase/include/os0sync.h +++ b/innobase/include/os0sync.h @@ -10,15 +10,16 @@ Created 9/6/1995 Heikki Tuuri #define os0sync_h #include "univ.i" +#include "ut0lst.h" #ifdef __WIN__ - #define os_fast_mutex_t CRITICAL_SECTION -typedef void* os_event_t; - +typedef HANDLE os_event_t; #else - typedef pthread_mutex_t os_fast_mutex_t; + +typedef struct os_event_struct os_event_struct_t; +typedef os_event_struct_t* os_event_t; struct os_event_struct { os_fast_mutex_t os_mutex; /* this mutex protects the next fields */ @@ -26,9 +27,9 @@ struct os_event_struct { not reserved */ pthread_cond_t cond_var; /* condition variable is used in waiting for the event */ + UT_LIST_NODE_T(os_event_struct_t) os_event_list; + /* list of all created events */ }; -typedef struct os_event_struct os_event_struct_t; -typedef os_event_struct_t* os_event_t; #endif typedef struct os_mutex_struct os_mutex_str_t; @@ -38,13 +39,30 @@ typedef os_mutex_str_t* os_mutex_t; #define OS_SYNC_TIME_EXCEEDED 1 -/* Mutex protecting the thread count */ -extern os_mutex_t os_thread_count_mutex; +/* Mutex protecting the thread count and event and OS 'slow' mutex lists */ +extern os_mutex_t os_sync_mutex; /* This is incremented by 1 in os_thread_create and decremented by 1 in os_thread_exit */ -extern ulint os_thread_count; +extern ulint os_thread_count; +/* The following are approximate counters for debugging in Unix */ +extern ulint os_event_count; +extern ulint os_mutex_count; + +/************************************************************* +Initializes global event and OS 'slow' mutex lists. */ + +void +os_sync_init(void); +/*==============*/ +/************************************************************* +Frees created events (not in Windows) and OS 'slow' mutexes. OS 'fast' +mutexes must be freed with sync_free() before this. */ + +void +os_sync_free(void); +/*==============*/ /************************************************************* Creates an event semaphore, i.e., a semaphore which may just have two states: signaled and nonsignaled. diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index 8355496762c..24e692dedab 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -209,6 +209,12 @@ void srv_init(void); /*==========*/ /************************************************************************* +Frees the OS fast mutex created in srv_init(). */ + +void +srv_free(void); +/*==========*/ +/************************************************************************* Initializes the synchronization primitives, memory system, and the thread local storage. */ diff --git a/innobase/include/srv0start.h b/innobase/include/srv0start.h index aec3ebfeea9..8d2c3fa12c5 100644 --- a/innobase/include/srv0start.h +++ b/innobase/include/srv0start.h @@ -86,11 +86,12 @@ extern ibool srv_startup_is_before_trx_rollback_phase; extern ibool srv_is_being_shut_down; /* At a shutdown the value first climbs from 0 to SRV_SHUTDOWN_CLEANUP -and then to SRV_SHUTDOWN_LAST_PHASE */ +and then to SRV_SHUTDOWN_LAST_PHASE, and so on */ extern ulint srv_shutdown_state; -#define SRV_SHUTDOWN_CLEANUP 1 -#define SRV_SHUTDOWN_LAST_PHASE 2 +#define SRV_SHUTDOWN_CLEANUP 1 +#define SRV_SHUTDOWN_LAST_PHASE 2 +#define SRV_SHUTDOWN_EXIT_THREADS 3 #endif diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index abcfa254710..ce9f21ec9a1 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -28,14 +28,74 @@ struct os_mutex_struct{ do not assume that the OS mutex supports recursive locking, though NT seems to do that */ + UT_LIST_NODE_T(os_mutex_str_t) os_mutex_list; + /* list of all 'slow' OS mutexes created */ }; -/* Mutex protecting the thread count */ -os_mutex_t os_thread_count_mutex; +/* Mutex protecting the thread count and the lists of OS mutexes +and events */ +os_mutex_t os_sync_mutex; +ibool os_sync_mutex_inited = FALSE; /* This is incremented by 1 in os_thread_create and decremented by 1 in os_thread_exit */ -ulint os_thread_count = 0; +ulint os_thread_count = 0; + +/* The list of all events created (not in Windows) */ +UT_LIST_BASE_NODE_T(os_event_struct_t) os_event_list; + +/* The list of all OS 'slow' mutexes */ +UT_LIST_BASE_NODE_T(os_mutex_str_t) os_mutex_list; + +/* The following are approximate counters for debugging in Unix */ +ulint os_event_count = 0; +ulint os_mutex_count = 0; + + +/************************************************************* +Initializes global event and OS 'slow' mutex lists. */ + +void +os_sync_init(void) +/*==============*/ +{ + UT_LIST_INIT(os_event_list); + UT_LIST_INIT(os_mutex_list); + + os_sync_mutex = os_mutex_create(NULL); + + os_sync_mutex_inited = TRUE; +} + +/************************************************************* +Frees created events (not in Windows) and OS 'slow' mutexes. OS 'fast' +mutexes must be freed with sync_free() before this. */ + +void +os_sync_free(void) +/*==============*/ +{ + os_event_t event; + os_mutex_t mutex; + + event = UT_LIST_GET_FIRST(os_event_list); + + while (event) { + + os_event_free(event); + + event = UT_LIST_GET_FIRST(os_event_list); + } + + mutex = UT_LIST_GET_FIRST(os_mutex_list); + + while (mutex) { + + os_mutex_free(mutex); + + mutex = UT_LIST_GET_FIRST(os_mutex_list); + } +} /************************************************************* Creates an event semaphore, i.e., a semaphore which may @@ -51,8 +111,8 @@ os_event_create( the event is created without a name */ { #ifdef __WIN__ - HANDLE event; - + os_event_t event; + event = CreateEvent(NULL, /* No security attributes */ TRUE, /* Manual reset */ FALSE, /* Initial state nonsignaled */ @@ -83,6 +143,14 @@ os_event_create( #endif event->is_set = FALSE; + os_mutex_enter(os_sync_mutex); + + UT_LIST_ADD_FIRST(os_event_list, os_event_list, event); + + os_event_count++; + + os_mutex_exit(os_sync_mutex); + return(event); #endif } @@ -100,7 +168,7 @@ os_event_create_auto( the event is created without a name */ { #ifdef __WIN__ - HANDLE event; + os_event_t event; event = CreateEvent(NULL, /* No security attributes */ FALSE, /* Auto-reset */ @@ -114,6 +182,8 @@ os_event_create_auto( UT_NOT_USED(name); + ut_a(0); + return(NULL); #endif } @@ -193,6 +263,14 @@ os_event_free( os_fast_mutex_free(&(event->os_mutex)); ut_a(0 == pthread_cond_destroy(&(event->cond_var))); + os_mutex_enter(os_sync_mutex); + + UT_LIST_REMOVE(os_event_list, os_event_list, event); + + os_event_count--; + + os_mutex_exit(os_sync_mutex); + ut_free(event); #endif } @@ -310,8 +388,7 @@ os_event_wait_multiple( ut_a(event_array); ut_a(n > 0); - index = WaitForMultipleObjects(n, - event_array, + index = WaitForMultipleObjects(n, event_array, FALSE, /* Wait for any 1 event */ INFINITE); /* Infinite wait time limit */ @@ -360,6 +437,16 @@ os_mutex_create( mutex_str->handle = mutex; mutex_str->count = 0; + if (os_sync_mutex_inited) { + os_mutex_enter(os_sync_mutex); + } + + UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str); + + if (os_sync_mutex_inited) { + os_mutex_exit(os_sync_mutex); + } + return(mutex_str); #else os_fast_mutex_t* os_mutex; @@ -376,6 +463,16 @@ os_mutex_create( mutex_str->handle = os_mutex; mutex_str->count = 0; + if (os_sync_mutex_inited) { + os_mutex_enter(os_sync_mutex); + } + + UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str); + + if (os_sync_mutex_inited) { + os_mutex_exit(os_sync_mutex); + } + return(mutex_str); #endif } @@ -447,9 +544,22 @@ os_mutex_free( #ifdef __WIN__ ut_a(mutex); + os_mutex_enter(os_sync_mutex); + + UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex); + + os_mutex_exit(os_sync_mutex); + ut_a(CloseHandle(mutex->handle)); + ut_free(mutex); #else + os_mutex_enter(os_sync_mutex); + + UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex); + + os_mutex_exit(os_sync_mutex); + os_fast_mutex_free(mutex->handle); ut_free(mutex->handle); ut_free(mutex); @@ -474,6 +584,7 @@ os_fast_mutex_init( #else ut_a(0 == pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST)); #endif + os_mutex_count++; #endif } @@ -521,5 +632,6 @@ os_fast_mutex_free( DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex); #else ut_a(0 == pthread_mutex_destroy(fast_mutex)); + os_mutex_count--; #endif } diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index a68f6a3b8bc..1722051a841 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -101,9 +101,9 @@ os_thread_create( os_thread_t thread; ulint win_thread_id; - os_mutex_enter(os_thread_count_mutex); + os_mutex_enter(os_sync_mutex); os_thread_count++; - os_mutex_exit(os_thread_count_mutex); + os_mutex_exit(os_sync_mutex); thread = CreateThread(NULL, /* no security attributes */ 0, /* default size stack */ @@ -147,9 +147,9 @@ os_thread_create( exit(1); } #endif - os_mutex_enter(os_thread_count_mutex); + os_mutex_enter(os_sync_mutex); os_thread_count++; - os_mutex_exit(os_thread_count_mutex); + os_mutex_exit(os_sync_mutex); #if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10) ret = pthread_create(&pthread, pthread_attr_default, start_f, arg); @@ -185,9 +185,9 @@ os_thread_exit( void* exit_value) /* in: exit value; in Windows this void* is cast as a DWORD */ { - os_mutex_enter(os_thread_count_mutex); + os_mutex_enter(os_sync_mutex); os_thread_count--; - os_mutex_exit(os_thread_count_mutex); + os_mutex_exit(os_sync_mutex); #ifdef __WIN__ ExitThread((DWORD)exit_value); diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index a44bc0147e4..da2966a7124 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -1693,7 +1693,17 @@ srv_init(void) ut_a(conc_slot->event); } } - + +/************************************************************************* +Frees the OS fast mutex created in srv_init(). */ + +void +srv_free(void) +/*==========*/ +{ + os_fast_mutex_free(&srv_conc_mutex); +} + /************************************************************************* Initializes the synchronization primitives, memory system, and the thread local storage. */ @@ -1702,71 +1712,14 @@ void srv_general_init(void) /*==================*/ { - os_thread_count_mutex = os_mutex_create(NULL); - + os_sync_init(); sync_init(); mem_init(srv_mem_pool_size); thr_local_init(); } - -#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) -/* NetWare requires some cleanup of mutexes */ - -/************************************************************************* -Deinitializes the synchronization primitives, memory system, and the thread -local storage. */ - -void -srv_general_free(void) -/*==================*/ -{ - sync_close(); - - os_mutex_free(os_thread_count_mutex); -} -#endif /* __NETWARE__ */ - - /*======================= InnoDB Server FIFO queue =======================*/ -#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) -/* NetWare requires some cleanup of mutexes */ - -/************************************************************************* -Deinitializes the server. */ - -void -srv_free(void) -/*==========*/ -{ - srv_conc_slot_t* conc_slot; - srv_slot_t* slot; - ulint i; - - for (i = 0; i < OS_THREAD_MAX_N; i++) - { - slot = srv_table_get_nth_slot(i); - os_event_free(slot->event); - } - - /* TODO: free(srv_sys->threads); */ - - for (i = 0; i < OS_THREAD_MAX_N; i++) - { - slot = srv_mysql_table + i; - os_event_free(slot->event); - } - - /* TODO: free(srv_mysql_table); */ - - for (i = 0; i < OS_THREAD_MAX_N; i++) - { - conc_slot = srv_conc_slots + i; - os_event_free(conc_slot->event); - } -} -#endif /* __NETWARE__ */ /************************************************************************* Puts an OS thread to wait if there are too many concurrent threads diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index d34c18b1a25..f03355b825c 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1442,9 +1442,7 @@ innobase_start_or_create_for_mysql(void) os_fast_mutex_unlock(&srv_os_test_mutex); -#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) - os_fast_mutex_free(&srv_os_test_mutex); /* all platforms? */ -#endif /* __NETWARE__ */ + os_fast_mutex_free(&srv_os_test_mutex); if (srv_print_verbose_log) { ut_print_timestamp(stderr); @@ -1484,7 +1482,7 @@ innobase_shutdown_for_mysql(void) return(DB_SUCCESS); } - /* Flush buffer pool to disk, write the current lsn to + /* 1. Flush buffer pool to disk, write the current lsn to the tablespace header(s), and copy all log data to archive */ logs_empty_and_mark_files_at_shutdown(); @@ -1496,7 +1494,7 @@ innobase_shutdown_for_mysql(void) srv_conc_n_threads); } - /* Now we will exit all threads InnoDB created */ + /* 2. Make all threads created by InnoDB to exit */ srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS; @@ -1521,7 +1519,7 @@ innobase_shutdown_for_mysql(void) os_aio_wake_all_threads_at_shutdown(); - os_mutex_enter(os_thread_count_mutex); + os_mutex_enter(os_sync_mutex); if (os_thread_count == 0) { /* All the threads have exited or are just exiting; @@ -1530,14 +1528,14 @@ innobase_shutdown_for_mysql(void) they have exited? Now we just sleep 0.1 seconds and hope that is enough! */ - os_mutex_exit(os_thread_count_mutex); + os_mutex_exit(os_sync_mutex); os_thread_sleep(100000); break; } - os_mutex_exit(os_thread_count_mutex); + os_mutex_exit(os_sync_mutex); os_thread_sleep(100000); } @@ -1548,19 +1546,21 @@ innobase_shutdown_for_mysql(void) os_thread_count); } -#if defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) + /* 3. Free all InnoDB's own mutexes */ + + sync_close(); + + /* 4. Free all OS synchronization primitives (in Windows currently + events are not freed) */ - /* TODO: Where should this be called? */ srv_free(); + os_sync_free(); - /* TODO: Where should this be called? */ - srv_general_free(); -#endif + /* 5. Free all allocated memory (and the os_fast_mutex created in + ut0mem.c */ -#if defined(NOT_WORKING_YET) || defined(__NETWARE__) || defined(SAFE_MUTEX_DETECT_DESTROY) - /* NetWare requires this free */ ut_free_all_mem(); -#endif + if (srv_print_verbose_log) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Shutdown completed\n"); diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c index 20d68ba5a9f..32615ce88ac 100644 --- a/innobase/sync/sync0sync.c +++ b/innobase/sync/sync0sync.c @@ -235,8 +235,7 @@ mutex_create_func( mutex->cline = cline; /* Check that lock_word is aligned; this is important on Intel */ - - ut_a(((ulint)(&(mutex->lock_word))) % 4 == 0); + ut_ad(((ulint)(&(mutex->lock_word))) % 4 == 0); /* NOTE! The very first mutexes are not put to the mutex list */ @@ -266,11 +265,14 @@ mutex_free( ut_a(mutex_get_lock_word(mutex) == 0); ut_a(mutex_get_waiters(mutex) == 0); - mutex_enter(&mutex_list_mutex); + if (mutex != &mutex_list_mutex && mutex != &sync_thread_mutex) { - UT_LIST_REMOVE(list, mutex_list, mutex); + mutex_enter(&mutex_list_mutex); - mutex_exit(&mutex_list_mutex); + UT_LIST_REMOVE(list, mutex_list, mutex); + + mutex_exit(&mutex_list_mutex); + } #if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER) os_fast_mutex_free(&(mutex->os_fast_mutex)); @@ -1230,13 +1232,26 @@ sync_init(void) } /********************************************************************** -Frees the resources in synchronization data structures. */ +Frees the resources in InnoDB's own synchronization data structures. Use +os_sync_free() after calling this. */ void sync_close(void) /*===========*/ { + mutex_t* mutex; + sync_array_free(sync_primary_wait_array); + + mutex = UT_LIST_GET_FIRST(mutex_list); + + while (mutex) { + mutex_free(mutex); + mutex = UT_LIST_GET_FIRST(mutex_list); + } + + mutex_free(&mutex_list_mutex); + mutex_free(&sync_thread_mutex); } /*********************************************************************** diff --git a/innobase/ut/ut0mem.c b/innobase/ut/ut0mem.c index dbd3e7e4737..174ae4cc6bb 100644 --- a/innobase/ut/ut0mem.c +++ b/innobase/ut/ut0mem.c @@ -190,6 +190,8 @@ ut_free_all_mem(void) os_fast_mutex_unlock(&ut_list_mutex); ut_a(ut_total_allocated_memory == 0); + + os_fast_mutex_free(&ut_list_mutex); } /************************************************************************** From c01bcf473e3cf215e41a77da6acde0f284ab60a8 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 31 May 2003 03:23:42 +0300 Subject: [PATCH 35/40] os0thread.c, os0thread.h, os0sync.h: Cleanup os0sync.c: Free all OS sync primitives and allocated memory in InnoDB shutdown innobase/os/os0sync.c: Free all OS sync primitives and allocated memory in InnoDB shutdown innobase/include/os0sync.h: Cleanup innobase/include/os0thread.h: Cleanup innobase/os/os0thread.c: Cleanup --- innobase/include/os0sync.h | 3 +-- innobase/include/os0thread.h | 1 - innobase/os/os0sync.c | 3 +-- innobase/os/os0thread.c | 1 + 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/innobase/include/os0sync.h b/innobase/include/os0sync.h index 3096c9256ed..bad8e6e120a 100644 --- a/innobase/include/os0sync.h +++ b/innobase/include/os0sync.h @@ -57,8 +57,7 @@ void os_sync_init(void); /*==============*/ /************************************************************* -Frees created events (not in Windows) and OS 'slow' mutexes. OS 'fast' -mutexes must be freed with sync_free() before this. */ +Frees created events (not in Windows) and OS 'slow' mutexes. */ void os_sync_free(void); diff --git a/innobase/include/os0thread.h b/innobase/include/os0thread.h index 29154a9e7cf..92187f315c2 100644 --- a/innobase/include/os0thread.h +++ b/innobase/include/os0thread.h @@ -11,7 +11,6 @@ Created 9/8/1995 Heikki Tuuri #define os0thread_h #include "univ.i" -#include "os0sync.h" /* Maximum number of threads which can be created in the program; this is also the size of the wait slot array for MySQL threads which diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index ce9f21ec9a1..4f322ee82b2 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -68,8 +68,7 @@ os_sync_init(void) } /************************************************************* -Frees created events (not in Windows) and OS 'slow' mutexes. OS 'fast' -mutexes must be freed with sync_free() before this. */ +Frees created events (not in Windows) and OS 'slow' mutexes. */ void os_sync_free(void) diff --git a/innobase/os/os0thread.c b/innobase/os/os0thread.c index 1722051a841..02ea2c227a7 100644 --- a/innobase/os/os0thread.c +++ b/innobase/os/os0thread.c @@ -16,6 +16,7 @@ Created 9/8/1995 Heikki Tuuri #endif #include "srv0srv.h" +#include "os0sync.h" /******************************************************************* Compares two thread ids for equality. */ From b5965dbded30dcd3e6cae0368b31c3341e00d32d Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 31 May 2003 18:44:37 +0300 Subject: [PATCH 36/40] Fixed compiler optimization problem with doubleget() (Casused problems in GIS functions in 4.1) include/global.h: Fixed compiler optimization problem with doubleget() --- include/global.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/global.h b/include/global.h index 1737c60db30..94b0f5bab03 100644 --- a/include/global.h +++ b/include/global.h @@ -795,8 +795,11 @@ typedef union { double v; long m[2]; } doubleget_union; -#define doubleget(V,M) { ((doubleget_union *)&V)->m[0] = *((long*) M); \ - ((doubleget_union *)&V)->m[1] = *(((long*) M)+1); } +#define doubleget(V,M) \ +{ doubleget_union _tmp; \ + _tmp.m[0] = *((long*)(M)); \ + _tmp.m[1] = *(((long*) (M))+1); \ + (V) = _tmp.v; } #define doublestore(T,V) { *((long *) T) = ((doubleget_union *)&V)->m[0]; \ *(((long *) T)+1) = ((doubleget_union *)&V)->m[1]; } #define float4get(V,M) { *((long *) &(V)) = *((long*) (M)); } From 2ef52d46a4f5b0c34bee26b0f70d672b6ee9325e Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 1 Jun 2003 12:32:53 +0300 Subject: [PATCH 37/40] Fixed bug in ALTER TABLE DISABLE KEYS and INSERT DELAYED. Bug #478 mysql-test/r/alter_table.result: new results mysql-test/r/lowercase_table.result: new results mysql-test/t/alter_table.test: Test of ALTER TABLE DISABLE KEYS + INSERT DELAYED mysql-test/t/lowercase_table.test: Added test of alias name comparison sql/mysql_priv.h: Made closed_cached_table local sql/sql_table.cc: Fixed bug in ALTER TABLE DISABLE KEYS and INSERT DELAYED --- mysql-test/r/alter_table.result | 5 ++ mysql-test/r/lowercase_table.result | 12 +++ mysql-test/t/alter_table.test | 9 ++ mysql-test/t/lowercase_table.test | 11 +++ sql/mysql_priv.h | 1 - sql/sql_table.cc | 133 +++++++++++++++++----------- 6 files changed, 118 insertions(+), 53 deletions(-) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index cfbc46bc78f..e2d9cc30ad9 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -276,3 +276,8 @@ t1 0 a 1 a A 3 NULL NULL YES BTREE t1 0 a 2 b A 300 NULL NULL YES BTREE t1 1 b 1 b A 100 NULL NULL YES BTREE drop table t1; +CREATE TABLE t1 (i int(10), index(i) ); +ALTER TABLE t1 DISABLE KEYS; +INSERT DELAYED INTO t1 VALUES(1),(2),(3); +ALTER TABLE t1 ENABLE KEYS; +drop table t1; diff --git a/mysql-test/r/lowercase_table.result b/mysql-test/r/lowercase_table.result index 1caaf317c96..d32228216b8 100644 --- a/mysql-test/r/lowercase_table.result +++ b/mysql-test/r/lowercase_table.result @@ -13,3 +13,15 @@ show tables like 't_'; Tables_in_test (t_) t3 drop table t3; +create table t1 (a int); +select count(*) from T1; +count(*) +0 +select count(*) from t1; +count(*) +0 +select count(T1.a) from t1; +Unknown table 'T1' in field list +select count(bags.a) from t1 as Bags; +Unknown table 'bags' in field list +drop table t1; diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 96f969c8776..a3ab62afc69 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -133,3 +133,12 @@ analyze table t1; show keys from t1; drop table t1; +# +# Test of ALTER TABLE DELAYED +# + +CREATE TABLE t1 (i int(10), index(i) ); +ALTER TABLE t1 DISABLE KEYS; +INSERT DELAYED INTO t1 VALUES(1),(2),(3); +ALTER TABLE t1 ENABLE KEYS; +drop table t1; diff --git a/mysql-test/t/lowercase_table.test b/mysql-test/t/lowercase_table.test index 0d04e6c7df7..b3453dfd3c4 100644 --- a/mysql-test/t/lowercase_table.test +++ b/mysql-test/t/lowercase_table.test @@ -12,3 +12,14 @@ ALTER TABLE T2 RENAME T3; show tables like 't_'; drop table t3; +# +# Test alias +# +create table t1 (a int); +select count(*) from T1; +select count(*) from t1; +--error 1109 +select count(T1.a) from t1; +--error 1109 +select count(bags.a) from t1 as Bags; +drop table t1; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 614cb8cadf6..41a39f0d24c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -422,7 +422,6 @@ bool mysql_rename_table(enum db_type base, const char * old_name, const char *new_db, const char * new_name); -bool close_cached_table(THD *thd,TABLE *table); int mysql_create_index(THD *thd, TABLE_LIST *table_list, List &keys); int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List &drop_list); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 07ec1d67538..f3620b860a7 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -912,58 +912,76 @@ mysql_rename_table(enum db_type base, } /* - close table in this thread and force close + reopen in other threads - This assumes that the calling thread has lock on LOCK_open - Win32 clients must also have a WRITE LOCK on the table ! + Force all other threads to stop using the table + + SYNOPSIS + wait_while_table_is_used() + thd Thread handler + table Table to remove from cache + + NOTES + When returning, the table will be unusable for other threads until + the table is closed. + + PREREQUISITES + Lock on LOCK_open + Win32 clients must also have a WRITE LOCK on the table ! */ -static void safe_remove_from_cache(THD *thd,TABLE *table) +static void wait_while_table_is_used(THD *thd,TABLE *table) { - DBUG_ENTER("safe_remove_from_cache"); - if (table) - { - DBUG_PRINT("enter",("table: %s", table->real_name)); - VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Close all data files - /* Mark all tables that are in use as 'old' */ - mysql_lock_abort(thd,table); // end threads waiting on lock + DBUG_PRINT("enter",("table: %s", table->real_name)); + DBUG_ENTER("wait_while_table_is_used"); + safe_mutex_assert_owner(&LOCK_open); -#if defined(USING_TRANSACTIONS) || defined( __WIN__) || defined( __EMX__) || !defined(OS2) - /* Wait until all there are no other threads that has this table open */ - while (remove_table_from_cache(thd,table->table_cache_key, - table->real_name)) - { - dropping_tables++; - (void) pthread_cond_wait(&COND_refresh,&LOCK_open); - dropping_tables--; - } -#else - (void) remove_table_from_cache(thd,table->table_cache_key, - table->real_name); -#endif - /* When lock on LOCK_open is freed other threads can continue */ - pthread_cond_broadcast(&COND_refresh); + VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Close all data files + /* Mark all tables that are in use as 'old' */ + mysql_lock_abort(thd, table); // end threads waiting on lock + + /* Wait until all there are no other threads that has this table open */ + while (remove_table_from_cache(thd,table->table_cache_key, + table->real_name)) + { + dropping_tables++; + (void) pthread_cond_wait(&COND_refresh,&LOCK_open); + dropping_tables--; } DBUG_VOID_RETURN; } +/* + Close a cached table -bool close_cached_table(THD *thd,TABLE *table) + SYNOPSIS + clsoe_cached_table() + thd Thread handler + table Table to remove from cache + + NOTES + Function ends by signaling threads waiting for the table to try to + reopen the table. + + PREREQUISITES + Lock on LOCK_open + Win32 clients must also have a WRITE LOCK on the table ! +*/ + +static bool close_cached_table(THD *thd, TABLE *table) { DBUG_ENTER("close_cached_table"); - safe_mutex_assert_owner(&LOCK_open); - - if (table) + + wait_while_table_is_used(thd,table); + /* Close lock if this is not got with LOCK TABLES */ + if (thd->lock) { - safe_remove_from_cache(thd,table); - /* Close lock if this is not got with LOCK TABLES */ - if (thd->lock) - { - mysql_unlock_tables(thd, thd->lock); - thd->lock=0; // Start locked threads - } - /* Close all copies of 'table'. This also frees all LOCK TABLES lock */ - thd->open_tables=unlink_open_table(thd,thd->open_tables,table); + mysql_unlock_tables(thd, thd->lock); + thd->lock=0; // Start locked threads } + /* Close all copies of 'table'. This also frees all LOCK TABLES lock */ + thd->open_tables=unlink_open_table(thd,thd->open_tables,table); + + /* When lock on LOCK_open is freed other threads can continue */ + pthread_cond_broadcast(&COND_refresh); DBUG_RETURN(0); } @@ -1094,10 +1112,13 @@ static int prepare_for_repair(THD* thd, TABLE_LIST *table_list, sprintf(tmp,"%s-%lx_%lx", from, current_pid, thd->thread_id); - pthread_mutex_lock(&LOCK_open); - close_cached_table(thd,table_list->table); - pthread_mutex_unlock(&LOCK_open); - + /* If we could open the table, close it */ + if (table_list->table) + { + pthread_mutex_lock(&LOCK_open); + close_cached_table(thd, table); + pthread_mutex_unlock(&LOCK_open); + } if (lock_and_wait_for_table_name(thd,table_list)) { error= -1; @@ -1494,11 +1515,10 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, else { *fn_ext(new_name)=0; - close_cached_table(thd,table); + close_cached_table(thd, table); if (mysql_rename_table(old_db_type,db,table_name,new_db,new_name)) error= -1; } - VOID(pthread_cond_broadcast(&COND_refresh)); VOID(pthread_mutex_unlock(&LOCK_open)); } if (!error) @@ -1507,12 +1527,18 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, case LEAVE_AS_IS: break; case ENABLE: - safe_remove_from_cache(thd,table); - error= table->file->activate_all_index(thd); + VOID(pthread_mutex_lock(&LOCK_open)); + wait_while_table_is_used(thd, table); + VOID(pthread_mutex_unlock(&LOCK_open)); + error= table->file->activate_all_index(thd); + /* COND_refresh will be signaled in close_thread_tables() */ break; case DISABLE: - safe_remove_from_cache(thd,table); + VOID(pthread_mutex_lock(&LOCK_open)); + wait_while_table_is_used(thd, table); + VOID(pthread_mutex_unlock(&LOCK_open)); table->file->deactivate_non_unique_index(HA_POS_ERROR); + /* COND_refresh will be signaled in close_thread_tables() */ break; } } @@ -1936,7 +1962,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, close the original table at before doing the rename */ table_name=thd->strdup(table_name); // must be saved - if (close_cached_table(thd,table)) + if (close_cached_table(thd, table)) { // Aborted VOID(quick_rm_table(new_db_type,new_db,tmp_name)); VOID(pthread_mutex_unlock(&LOCK_open)); @@ -1970,7 +1996,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, This shouldn't happen. We solve this the safe way by closing the locked table. */ - close_cached_table(thd,table); + if (table) + close_cached_table(thd,table); VOID(pthread_mutex_unlock(&LOCK_open)); goto err; } @@ -1980,7 +2007,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, Not table locking or alter table with rename free locks and remove old table */ - close_cached_table(thd,table); + if (table) + close_cached_table(thd,table); VOID(quick_rm_table(old_db_type,db,old_name)); } else @@ -2000,7 +2028,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, if (close_data_tables(thd,db,table_name) || reopen_tables(thd,1,0)) { // This shouldn't happen - close_cached_table(thd,table); // Remove lock for table + if (table) + close_cached_table(thd,table); // Remove lock for table VOID(pthread_mutex_unlock(&LOCK_open)); goto err; } From 3f7dfc4df3a9bdfc01e5b84c3297fff61b791f9b Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 1 Jun 2003 23:40:01 +0300 Subject: [PATCH 38/40] Small fixes (nothing nameworthy) mysql-test/r/errors.result: Rename: mysql-test/r/err000001.result -> mysql-test/r/errors.result include/my_global.h: typedef for future functions that needs string length as an argument innobase/os/os0file.c: Added operation to error messages mysql-test/t/errors.test: Cleaned up file to new error number standard mysys/thr_alarm.c: Made end_thr_alarm() work also with internal alarm thread. (Not critical for MySQL) sql/mysqld.cc: Added sigemptyset() (bug found by valgrind) Removed some wrong usage of thd when writing variable values --- include/my_global.h | 5 ++- innobase/os/os0file.c | 37 +++++++++++------ .../r/{err000001.result => errors.result} | 0 mysql-test/t/err000001.test | 19 --------- mysql-test/t/errors.test | 32 +++++++++++++++ mysys/thr_alarm.c | 41 ++++++++++++++----- sql/mysqld.cc | 14 ++----- 7 files changed, 95 insertions(+), 53 deletions(-) rename mysql-test/r/{err000001.result => errors.result} (100%) delete mode 100644 mysql-test/t/err000001.test create mode 100644 mysql-test/t/errors.test diff --git a/include/my_global.h b/include/my_global.h index d892d843edc..90c4801e807 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB 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 @@ -640,6 +640,9 @@ typedef long my_ptrdiff_t; typedef long long my_ptrdiff_t; #endif +/* typedef used for length of string; Should be unsigned! */ +typedef ulong size_str; + #define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1)) #define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double)) /* Size to make adressable obj. */ diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 640ffec122f..00e29121ece 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -295,7 +295,8 @@ os_file_handle_error( /* out: TRUE if we should retry the operation */ os_file_t file, /* in: file pointer */ - char* name) /* in: name of a file or NULL */ + char* name, /* in: name of a file or NULL */ + const char* operation) /* in: type of operation */ { ulint err; @@ -337,7 +338,8 @@ os_file_handle_error( if (name) { fprintf(stderr, "InnoDB: File name %s\n", name); } - + fprintf(stderr, "InnoDB: system call %s\n", operation); + fprintf(stderr, "InnoDB: Cannot continue operation.\n"); fflush(stderr); @@ -419,7 +421,9 @@ try_again: if (file == INVALID_HANDLE_VALUE) { *success = FALSE; - retry = os_file_handle_error(file, name); + retry = os_file_handle_error(file, name, + create_mode == OS_FILE_OPEN ? + "open" : "create"); if (retry) { goto try_again; @@ -460,7 +464,10 @@ try_again: if (file == -1) { *success = FALSE; - retry = os_file_handle_error(file, name); + retry = os_file_handle_error(file, name, + create_mode == OS_FILE_OPEN ? + "open" : "create"); + if (retry) { goto try_again; @@ -568,7 +575,9 @@ try_again: if (file == INVALID_HANDLE_VALUE) { *success = FALSE; - retry = os_file_handle_error(file, name); + retry = os_file_handle_error(file, name, + create_mode == OS_FILE_OPEN ? + "open" : "create"); if (retry) { goto try_again; @@ -615,7 +624,9 @@ try_again: if (file == -1) { *success = FALSE; - retry = os_file_handle_error(file, name); + retry = os_file_handle_error(file, name, + create_mode == OS_FILE_OPEN ? + "open" : "create"); if (retry) { goto try_again; @@ -649,7 +660,7 @@ os_file_close( return(TRUE); } - os_file_handle_error(file, NULL); + os_file_handle_error(file, NULL, "close"); return(FALSE); #else int ret; @@ -657,7 +668,7 @@ os_file_close( ret = close(file); if (ret == -1) { - os_file_handle_error(file, NULL); + os_file_handle_error(file, NULL, "close"); return(FALSE); } @@ -825,7 +836,7 @@ os_file_flush( return(TRUE); } - os_file_handle_error(file, NULL); + os_file_handle_error(file, NULL, "flush"); /* It is a fatal error if a file flush does not succeed, because then the database can get corrupt on disk */ @@ -858,7 +869,7 @@ os_file_flush( fprintf(stderr, " InnoDB: Error: the OS said file flush did not succeed\n"); - os_file_handle_error(file, NULL); + os_file_handle_error(file, NULL, "flush"); /* It is a fatal error if a file flush does not succeed, because then the database can get corrupt on disk */ @@ -1099,7 +1110,7 @@ try_again: #ifdef __WIN__ error_handling: #endif - retry = os_file_handle_error(file, NULL); + retry = os_file_handle_error(file, NULL, "read"); if (retry) { goto try_again; @@ -2014,7 +2025,7 @@ try_again: os_aio_array_free_slot(array, slot); - retry = os_file_handle_error(file, name); + retry = os_file_handle_error(file, name, "aio"); if (retry) { @@ -2113,7 +2124,7 @@ os_aio_windows_handle( ut_a(TRUE == os_file_flush(slot->file)); } } else { - os_file_handle_error(slot->file, slot->name); + os_file_handle_error(slot->file, slot->name, "aio"); ret_val = FALSE; } diff --git a/mysql-test/r/err000001.result b/mysql-test/r/errors.result similarity index 100% rename from mysql-test/r/err000001.result rename to mysql-test/r/errors.result diff --git a/mysql-test/t/err000001.test b/mysql-test/t/err000001.test deleted file mode 100644 index d9898054a83..00000000000 --- a/mysql-test/t/err000001.test +++ /dev/null @@ -1,19 +0,0 @@ -# -# Test some error conditions -# - -drop table if exists t1; -!$1146 insert into t1 values(1); -!$1146 delete from t1; -!$1146 update t1 set a=1; -create table t1 (a int); -!$1054 select count(test.t1.b) from t1; -!$1109 select count(not_existing_database.t1) from t1; -!$1109 select count(not_existing_database.t1.a) from t1; ---error 1044,1146 -select count(not_existing_database.t1.a) from not_existing_database.t1; -!$1054 select 1 from t1 order by 2; -!$1054 select 1 from t1 group by 2; -!$1054 select 1 from t1 order by t1.b; -!$1054 select count(*),b from t1; -drop table t1; diff --git a/mysql-test/t/errors.test b/mysql-test/t/errors.test new file mode 100644 index 00000000000..afb0cce9005 --- /dev/null +++ b/mysql-test/t/errors.test @@ -0,0 +1,32 @@ +# +# Test some error conditions +# + +drop table if exists t1; +--error 1146 +insert into t1 values(1); +--error 1146 +delete from t1; +--error 1146 +update t1 set a=1; + +# + +create table t1 (a int); +--error 1054 +select count(test.t1.b) from t1; +--error 1109 +select count(not_existing_database.t1) from t1; +--error 1109 + select count(not_existing_database.t1.a) from t1; +--error 1044,1146 +select count(not_existing_database.t1.a) from not_existing_database.t1; +--error 1054 +select 1 from t1 order by 2; +--error 1054 +select 1 from t1 group by 2; +--error 1054 +select 1 from t1 order by t1.b; +--error 1054 +select count(*),b from t1; +drop table t1; diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index ca8e4e8bcb6..a2647ec7399 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -38,20 +38,21 @@ #endif static int alarm_aborted=1; /* No alarm thread */ -my_bool thr_alarm_inited=0; +my_bool thr_alarm_inited= 0; +volatile my_bool alarm_thread_running= 0; static sig_handler process_alarm_part2(int sig); #if !defined(__WIN__) && !defined(__EMX__) && !defined(OS2) static pthread_mutex_t LOCK_alarm; +static pthread_cond_t COND_alarm; static sigset_t full_signal_set; static QUEUE alarm_queue; static uint max_used_alarms=0; pthread_t alarm_thread; #ifdef USE_ALARM_THREAD -static pthread_cond_t COND_alarm; static void *alarm_handler(void *arg); #define reschedule_alarms() pthread_cond_signal(&COND_alarm) #else @@ -78,6 +79,7 @@ void init_thr_alarm(uint max_alarms) compare_ulong,NullS); sigfillset(&full_signal_set); /* Neaded to block signals */ pthread_mutex_init(&LOCK_alarm,MY_MUTEX_INIT_FAST); + pthread_cond_init(&COND_alarm,NULL); #if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD) #if defined(HAVE_mit_thread) sigset(THR_CLIENT_ALARM,thread_alarm); /* int. thread system calls */ @@ -97,7 +99,6 @@ void init_thr_alarm(uint max_alarms) { pthread_attr_t thr_attr; pthread_attr_init(&thr_attr); - pthread_cond_init(&COND_alarm,NULL); pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS); pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); pthread_attr_setstacksize(&thr_attr,8196); @@ -383,28 +384,45 @@ static sig_handler process_alarm_part2(int sig __attribute__((unused))) void end_thr_alarm(my_bool free_structures) { DBUG_ENTER("end_thr_alarm"); - if (alarm_aborted != 1) + if (alarm_aborted != 1) /* If memory not freed */ { pthread_mutex_lock(&LOCK_alarm); DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements)); alarm_aborted= -1; /* mark aborted */ - if (pthread_equal(pthread_self(),alarm_thread)) - alarm(1); /* Shut down everything soon */ - else - reschedule_alarms(); + if (alarm_queue.elements || (alarm_thread_running && free_structures)) + { + if (pthread_equal(pthread_self(),alarm_thread)) + alarm(1); /* Shut down everything soon */ + else + reschedule_alarms(); + } if (free_structures) { + struct timespec abstime; /* The following test is just for safety, the caller should not depend on this */ DBUG_ASSERT(!alarm_queue.elements); + /* Wait until alarm thread dies */ + + set_timespec(abstime, 10); /* Wait up to 10 seconds */ + while (alarm_thread_running) + { + int error= pthread_cond_timedwait(&COND_alarm, &LOCK_alarm, &abstime); + if (error == ETIME || error == ETIMEDOUT) + break; /* Don't wait forever */ + } if (!alarm_queue.elements) { delete_queue(&alarm_queue); alarm_aborted= 1; pthread_mutex_unlock(&LOCK_alarm); - pthread_mutex_destroy(&LOCK_alarm); + if (!alarm_thread_running) /* Safety */ + { + pthread_mutex_destroy(&LOCK_alarm); + pthread_cond_destroy(&COND_alarm); + } } } else @@ -490,6 +508,7 @@ static void *alarm_handler(void *arg __attribute__((unused))) puts("Starting alarm thread"); #endif my_thread_init(); + alarm_thread_running= 1; pthread_mutex_lock(&LOCK_alarm); for (;;) { @@ -514,7 +533,7 @@ static void *alarm_handler(void *arg __attribute__((unused))) } } } - else if (alarm_aborted) + else if (alarm_aborted == -1) break; else if ((error=pthread_cond_wait(&COND_alarm,&LOCK_alarm))) { @@ -526,6 +545,8 @@ static void *alarm_handler(void *arg __attribute__((unused))) process_alarm(0); } bzero((char*) &alarm_thread,sizeof(alarm_thread)); /* For easy debugging */ + alarm_thread_running= 0; + pthread_cond_signal(&COND_alarm); pthread_mutex_unlock(&LOCK_alarm); pthread_exit(0); return 0; /* Impossible */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c2ee940af49..1492d6ddb68 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1520,7 +1520,6 @@ the problem, but since we have already crashed, something is definitely wrong\n\ and this may fail.\n\n"); fprintf(stderr, "key_buffer_size=%lu\n", (ulong) keybuff_size); fprintf(stderr, "read_buffer_size=%ld\n", global_system_variables.read_buff_size); - fprintf(stderr, "sort_buffer_size=%ld\n", thd->variables.sortbuff_size); fprintf(stderr, "max_used_connections=%ld\n", max_used_connections); fprintf(stderr, "max_connections=%ld\n", max_connections); fprintf(stderr, "threads_connected=%d\n", thread_count); @@ -1528,7 +1527,7 @@ and this may fail.\n\n"); key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %ld K\n\ bytes of memory\n", ((ulong) keybuff_size + (global_system_variables.read_buff_size + - thd->variables.sortbuff_size) * + global_system_variables.sortbuff_size) * max_connections)/ 1024); fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n"); @@ -1557,14 +1556,9 @@ the thread stack. Please read http://www.mysql.com/doc/L/i/Linux.html\n\n", Some pointers may be invalid and cause the dump to abort...\n"); safe_print_str("thd->query", thd->query, 1024); fprintf(stderr, "thd->thread_id=%ld\n", thd->thread_id); - fprintf(stderr, "\n\ -Successfully dumped variables, if you ran with --log, take a look at the\n\ -details of what thread %ld did to cause the crash. In some cases of really\n\ -bad corruption, the values shown above may be invalid.\n\n", - thd->thread_id); } fprintf(stderr, "\ -The manual page at http://www.mysql.com/doc/C/r/Crashing.html contains\n\ +The manual page at http://www.mysql.com/doc/en/Crashing.html contains\n\ information that should help you find out what is causing the crash.\n"); fflush(stderr); #endif /* HAVE_STACKTRACE */ @@ -1639,6 +1633,7 @@ static void init_signals(void) sigaddset(&set,SIGHUP); /* Fix signals if blocked by parents (can happen on Mac OS X) */ + sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = print_signal_warning; sigaction(SIGTERM, &sa, (struct sigaction*) 0); @@ -2279,7 +2274,7 @@ int main(int argc, char **argv) #endif /* init_slave() must be called after the thread keys are created */ init_slave(); - + DBUG_ASSERT(current_thd == 0); if (opt_bin_log && !server_id) { @@ -2307,7 +2302,6 @@ The server will not act as a slave."); using_update_log=1; } - if (opt_bootstrap) { int error=bootstrap(stdin); From a91d2fcbd9d927deb8808c10a32f1baa192a4e26 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Jun 2003 16:05:27 +0300 Subject: [PATCH 39/40] Added [mysqld-base-version] as a default group for the mysqld server Portability fix for Windows 64 include/config-win.h: Portability fix for Windows 64 include/my_global.h: Portability fix for Windows 64 include/mysql_version.h.in: Added [mysqld-base-version] as a default group for the mysqld server innobase/include/univ.i: Portability fix for Windows 64 sql/mysqld.cc: Added [mysqld-base-version] as a default group for the mysqld server --- include/config-win.h | 8 +++++++- include/my_global.h | 2 +- include/mysql_version.h.in | 1 + innobase/include/univ.i | 4 ++++ sql/mysqld.cc | 2 +- 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/include/config-win.h b/include/config-win.h index 9931d2c4b95..096c00e4574 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -130,6 +130,11 @@ typedef uint rf_SetTimer; #define SIZEOF_LONG 4 #define SIZEOF_LONG_LONG 8 #define SIZEOF_OFF_T 8 +#ifdef _WIN64 +#define SIZEOF_CHARP 8 +#else +#define SIZEOF_CHARP 4 +#endif #define HAVE_BROKEN_NETINET_INCLUDES #ifdef __NT__ #define HAVE_NAMED_PIPE /* We can only create pipes on NT */ @@ -196,6 +201,7 @@ inline double ulonglong2double(ulonglong value) /* Optimized store functions for Intel x86 */ +#ifndef _WIN64 #define sint2korr(A) (*((int16 *) (A))) #define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ (((uint32) 255L << 24) | \ @@ -236,7 +242,7 @@ inline double ulonglong2double(ulonglong value) #define float8get(V,M) doubleget((V),(M)) #define float4store(V,M) memcpy((byte*) V,(byte*) (&M),sizeof(float)) #define float8store(V,M) doublestore((V),(M)) - +#endif /* _WIN64 */ #define HAVE_PERROR #define HAVE_VFPRINT diff --git a/include/my_global.h b/include/my_global.h index 90c4801e807..1026e8e3940 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -848,7 +848,7 @@ typedef char bool; /* Ordinary boolean values 0 1 */ */ /* Optimized store functions for Intel x86 */ -#ifdef __i386__ +#if defined(__i386__) && !defined(_WIN64) #define sint2korr(A) (*((int16 *) (A))) #define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ (((uint32) 255L << 24) | \ diff --git a/include/mysql_version.h.in b/include/mysql_version.h.in index 793bf36e9fe..da184665f6e 100644 --- a/include/mysql_version.h.in +++ b/include/mysql_version.h.in @@ -10,6 +10,7 @@ #else #define PROTOCOL_VERSION @PROTOCOL_VERSION@ #define MYSQL_SERVER_VERSION "@VERSION@" +#define MYSQL_BASE_VERSION "mysqld-@MYSQL_BASE_VERSION@" #ifndef MYSQL_SERVER_SUFFIX #define MYSQL_SERVER_SUFFIX "@MYSQL_SERVER_SUFFIX@" #endif diff --git a/innobase/include/univ.i b/innobase/include/univ.i index e29f3ec92e1..4854e5a7b78 100644 --- a/innobase/include/univ.i +++ b/innobase/include/univ.i @@ -187,7 +187,11 @@ management to ensure correct alignment for doubles etc. */ /* Another basic type we use is unsigned long integer which is intended to be equal to the word size of the machine. */ +#ifdef _WIN64 +typedef unsigned __int64 ulint; +#else typedef unsigned long int ulint; +#endif typedef long int lint; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1492d6ddb68..7289d0e72cf 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1923,7 +1923,7 @@ extern "C" pthread_handler_decl(handle_shutdown,arg) #endif -const char *load_default_groups[]= { "mysqld","server",0 }; +const char *load_default_groups[]= { "mysqld","server",MYSQL_BASE_VERSION,0 }; bool open_log(MYSQL_LOG *log, const char *hostname, const char *opt_name, const char *extension, From b5860aed7b1d11f2d3ac909cde1438c86af26cb5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 4 Jun 2003 18:22:48 +0300 Subject: [PATCH 40/40] Fixed (not fatal) buffer overflow --- libmysql/libmysql.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index af74182eb22..c008d625900 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1646,7 +1646,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE); bzero((char*) &UNIXaddr,sizeof(UNIXaddr)); UNIXaddr.sun_family = AF_UNIX; - strmov(UNIXaddr.sun_path, unix_socket); + strmake(UNIXaddr.sun_path, unix_socket, sizeof(UNIXaddr.sun_path)-1); if (my_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr), mysql->options.connect_timeout) <0) {