From 312e5e82c0b17983bc3ac43b50fac891cccf0ea2 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 Nov 2001 02:50:20 +0200 Subject: [PATCH 1/3] Fixed bug when joining with caching. Fixed race condition when using the binary log and INSERT DELAYED which could cause the binary log to have rows that was not yet written to MyISAM tables. Docs/manual.texi: Changelog mysql-test/r/null_key.result: Fix of testcase after changing optimizer to only use range keys if it would use a long part of the SAME key. sql/sql_insert.cc: Fixed race condition with binary log and INSERT DELAYED sql/sql_select.cc: Fixed bug when joining with caching --- Docs/manual.texi | 8 +++- mysql-test/r/null_key.result | 2 +- sql/sql_insert.cc | 15 +++++-- sql/sql_select.cc | 84 ++++++++++++++++++++---------------- 4 files changed, 65 insertions(+), 44 deletions(-) diff --git a/Docs/manual.texi b/Docs/manual.texi index 9eff296b7e6..e67e1dc0468 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -46785,7 +46785,7 @@ users use this code as the rest of the code and because of this we are not yet 100% confident in this code. @menu -* News-3.23.46:: +* News-3.23.46:: Changes in release 3.23.46 * News-3.23.45:: Changes in release 3.23.45 * News-3.23.44:: Changes in release 3.23.44 * News-3.23.43:: Changes in release 3.23.43 @@ -46846,6 +46846,12 @@ One can now kill @code{ANALYZE},@code{REPAIR} and @code{OPTIMIZE TABLE} when the thread is waiting to get a lock on the table. @item Fixed race condition in @code{ANALYZE TABLE}. +@item +Fixed bug when joining with caching (unlikely to happen). +@item +Fixed race condition when using the binary log and @code{INSERT DELAYED} +which could cause the binary log to have rows that was not yet written +to MyISAM tables. @end itemize @node News-3.23.45, News-3.23.44, News-3.23.46, News-3.23.x diff --git a/mysql-test/r/null_key.result b/mysql-test/r/null_key.result index d0d59cdebf8..ead1dc29326 100644 --- a/mysql-test/r/null_key.result +++ b/mysql-test/r/null_key.result @@ -11,7 +11,7 @@ t1 index NULL a 9 NULL 12 where used; Using index table type possible_keys key key_len ref rows Extra t1 range a,b a 9 NULL 3 where used; Using index table type possible_keys key key_len ref rows Extra -t1 range a,b a 9 NULL 2 where used; Using index +t1 ref a,b b 4 const 2 where used table type possible_keys key key_len ref rows Extra t1 ref a,b a 5 const 3 where used; Using index table type possible_keys key key_len ref rows Extra diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f7ff3ed159c..d8861390d87 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1099,7 +1099,7 @@ bool delayed_insert::handle_inserts(void) { int error; uint max_rows; - bool using_ignore=0; + bool using_ignore=0, using_bin_log=mysql_bin_log.is_open(); delayed_row *row; DBUG_ENTER("handle_inserts"); @@ -1124,7 +1124,13 @@ bool delayed_insert::handle_inserts(void) max_rows= ~0; // Do as much as possible } - table->file->extra(HA_EXTRA_WRITE_CACHE); + /* + We can't use row caching when using the binary log because if + we get a crash, then binary log will contain rows that are not yet + written to disk, which will cause problems in replication. + */ + if (!using_bin_log) + table->file->extra(HA_EXTRA_WRITE_CACHE); pthread_mutex_lock(&mutex); while ((row=rows.get())) { @@ -1161,7 +1167,7 @@ bool delayed_insert::handle_inserts(void) if (row->query && row->log_query) { mysql_update_log.write(&thd,row->query, row->query_length); - if (mysql_bin_log.is_open()) + if (using_bin_log) { thd.query_length = row->query_length; Query_log_event qinfo(&thd, row->query); @@ -1197,7 +1203,8 @@ bool delayed_insert::handle_inserts(void) /* This should never happen */ sql_print_error(ER(ER_DELAYED_CANT_CHANGE_LOCK),table->real_name); } - table->file->extra(HA_EXTRA_WRITE_CACHE); + if (!using_bin_log) + table->file->extra(HA_EXTRA_WRITE_CACHE); pthread_mutex_lock(&mutex); thd.proc_info="insert"; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 777a10503f6..774be3679a2 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1881,52 +1881,55 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, ** Find how much space the prevous read not const tables takes in cache */ +static void calc_used_field_length(THD *thd, JOIN_TAB *join_tab) +{ + uint null_fields,blobs,fields,rec_length; + null_fields=blobs=fields=rec_length=0; + + Field **f_ptr,*field; + for (f_ptr=join_tab->table->field ; (field= *f_ptr) ; f_ptr++) + { + if (field->query_id == thd->query_id) + { + uint flags=field->flags; + fields++; + rec_length+=field->pack_length(); + if (flags & BLOB_FLAG) + blobs++; + if (!(flags & NOT_NULL_FLAG)) + null_fields++; + } + } + if (null_fields) + rec_length+=(join_tab->table->null_fields+7)/8; + if (join_tab->table->maybe_null) + rec_length+=sizeof(my_bool); + if (blobs) + { + uint blob_length=(uint) (join_tab->table->file->mean_rec_length- + (join_tab->table->reclength- rec_length)); + rec_length+=(uint) max(4,blob_length); + } + join_tab->used_fields=fields; + join_tab->used_fieldlength=rec_length; + join_tab->used_blobs=blobs; +} + + static uint cache_record_length(JOIN *join,uint idx) { - uint length; + uint length=0; JOIN_TAB **pos,**end; THD *thd=join->thd; - length=0; for (pos=join->best_ref+join->const_tables,end=join->best_ref+idx ; pos != end ; pos++) { JOIN_TAB *join_tab= *pos; - if (!join_tab->used_fieldlength) - { /* Not calced yet */ - uint null_fields,blobs,fields,rec_length; - null_fields=blobs=fields=rec_length=0; - - Field **f_ptr,*field; - for (f_ptr=join_tab->table->field ; (field= *f_ptr) ; f_ptr++) - { - if (field->query_id == thd->query_id) - { - uint flags=field->flags; - fields++; - rec_length+=field->pack_length(); - if (flags & BLOB_FLAG) - blobs++; - if (!(flags & NOT_NULL_FLAG)) - null_fields++; - } - } - if (null_fields) - rec_length+=(join_tab->table->null_fields+7)/8; - if (join_tab->table->maybe_null) - rec_length+=sizeof(my_bool); - if (blobs) - { - uint blob_length=(uint) (join_tab->table->file->mean_rec_length- - (join_tab->table->reclength- rec_length)); - rec_length+=(uint) max(4,blob_length); - } - join_tab->used_fields=fields; - join_tab->used_fieldlength=rec_length; - join_tab->used_blobs=blobs; - } + if (!join_tab->used_fieldlength) /* Not calced yet */ + calc_used_field_length(thd, join_tab); length+=join_tab->used_fieldlength; } return length; @@ -2248,6 +2251,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) used_tables|=current_map; if (tab->type == JT_REF && tab->quick && + tab->ref.key == tab->quick->index && tab->ref.key_length < tab->quick->max_used_key_length) { /* Range uses longer key; Use this instead of ref on key */ @@ -5631,15 +5635,19 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count) uint length,blobs,size; CACHE_FIELD *copy,**blob_ptr; JOIN_CACHE *cache; + JOIN_TAB *join_tab; DBUG_ENTER("join_init_cache"); cache= &tables[table_count].cache; cache->fields=blobs=0; - for (i=0 ; i < table_count ; i++) + join_tab=tables; + for (i=0 ; i < table_count ; i++,join_tab++) { - cache->fields+=tables[i].used_fields; - blobs+=tables[i].used_blobs; + if (!join_tab->used_fieldlength) /* Not calced yet */ + calc_used_field_length(thd, join_tab); + cache->fields+=join_tab->used_fields; + blobs+=join_tab->used_blobs; } if (!(cache->field=(CACHE_FIELD*) sql_alloc(sizeof(CACHE_FIELD)*(cache->fields+table_count*2)+(blobs+1)* From aaed141aa6d8d80011c56c12abe7ddfeefc285cf Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 28 Nov 2001 02:24:22 +0200 Subject: [PATCH 2/3] Small safety fix Docs/manual.texi: Cleanup extra/resolveip.c: Portability fix man/safe_mysqld.1: Cleanup mysys/mf_iocache2.c: Safety fix scripts/make_binary_distribution.sh: Add mysqlbinlog --- Docs/manual.texi | 3 +-- extra/resolveip.c | 2 ++ man/safe_mysqld.1 | 8 +++++--- mysys/mf_iocache2.c | 6 ++++-- scripts/make_binary_distribution.sh | 2 +- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Docs/manual.texi b/Docs/manual.texi index e67e1dc0468..deac65945f7 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -41178,8 +41178,7 @@ of the following flags in very special circumstances: A @code{MYSQL*} connection handle if the connection was successful, @code{NULL} if the connection was unsuccessful. For a successful connection, -the return value is the same as the value of the first parameter, unless you -pass @code{NULL} for that parameter. +the return value is the same as the value of the first parameter. @subsubheading Errors diff --git a/extra/resolveip.c b/extra/resolveip.c index a75c7ecc97a..4856bead200 100644 --- a/extra/resolveip.c +++ b/extra/resolveip.c @@ -22,7 +22,9 @@ #include #include #include +#ifndef SCO #include +#endif #include #include #ifndef HAVE_BROKEN_NETINET_INCLUDES diff --git a/man/safe_mysqld.1 b/man/safe_mysqld.1 index 30abf04ae6b..3874801be3b 100755 --- a/man/safe_mysqld.1 +++ b/man/safe_mysqld.1 @@ -1,7 +1,6 @@ -.TH SAFE_MYSQLD 1 "19 December 2000" +.TH SAFE_MYSQLD 1 "19 December 2000" "safe_mysqld (mysql)" mysql.com .SH NAME -.BR safe_mysqld -is the recommended way to start a mysqld daemon on Unix. safe_mysqld adds some safety features such as restarting the server when an error occurs and logging run-time information to a log file. +safe_mysqld \- start the mysqld daemon on Unix. .SH SYNOPSIS .B safe_mysqld .RB [ \-\-basedir=\fP\fIpath\fP ] @@ -21,6 +20,9 @@ is the recommended way to start a mysqld daemon on Unix. safe_mysqld adds some s .RB [ \-\-timezone=# ] .RB [ \-\-user=# ] .SH DESCRIPTION +safe_mysqld adds some safety features such as restarting the server when an +error occurs and logging run-time information to a log file. +.BR .TP .BR \-\-basedir=\fP\fIpath \fP .TP diff --git a/mysys/mf_iocache2.c b/mysys/mf_iocache2.c index 1397c14515b..9c0f99aea82 100644 --- a/mysys/mf_iocache2.c +++ b/mysys/mf_iocache2.c @@ -41,9 +41,11 @@ void my_b_seek(IO_CACHE *info,my_off_t pos) byte* try_rc_pos; try_rc_pos = info->rc_pos + (pos - info->pos_in_file); if (try_rc_pos >= info->buffer && try_rc_pos <= info->rc_end) + { info->rc_pos = try_rc_pos; - else - flush_io_cache(info); + return; + } + flush_io_cache(info); } info->pos_in_file=pos; info->seek_not_done=1; diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh index c49ea91a4fc..99eb9e42967 100644 --- a/scripts/make_binary_distribution.sh +++ b/scripts/make_binary_distribution.sh @@ -68,7 +68,7 @@ for i in extra/comp_err extra/replace extra/perror extra/resolveip \ client/mysqladmin client/mysqldump client/mysqlimport client/mysqltest \ client/.libs/mysql client/.libs/mysqlshow client/.libs/mysqladmin \ client/.libs/mysqldump client/.libs/mysqlimport client/.libs/mysqltest \ - client/.libs/mysqlcheck + client/.libs/mysqlcheck client/.libs/mysqlbinlog do if [ -f $i ] then From 08fc358542509a63e04eb544885d03f10c576a22 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 Nov 2001 18:20:24 -0700 Subject: [PATCH 3/3] fixed alias drop bug in binlog fixed skip counter to do the RightThing (TM) when the user messes up. Still do RightThing when he gets it right. mysql-test/r/rpl000016.result: updated test result mysql-test/t/rpl000013.test: test alias bug mysql-test/t/rpl000016.test: test for proper skip when the user messes up sql/slave.cc: proper skip even when the user goofs up sql/sql_base.cc: drop real name, not last used alias in the log --- mysql-test/r/rpl000016.result | 2 +- mysql-test/t/rpl000013.test | 2 +- mysql-test/t/rpl000016.test | 5 +++-- sql/slave.cc | 7 ++++++- sql/sql_base.cc | 4 ++-- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/rpl000016.result b/mysql-test/r/rpl000016.result index abe4275a124..1390291f1e8 100644 --- a/mysql-test/r/rpl000016.result +++ b/mysql-test/r/rpl000016.result @@ -10,7 +10,7 @@ master-bin.003 Log_name master-bin.003 Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter -127.0.0.1 root 9999 60 master-bin.003 184 Yes 0 0 +127.0.0.1 root 9999 60 master-bin.003 206 Yes 0 0 m 34 65 diff --git a/mysql-test/t/rpl000013.test b/mysql-test/t/rpl000013.test index af693a720d4..a190d5324ae 100644 --- a/mysql-test/t/rpl000013.test +++ b/mysql-test/t/rpl000013.test @@ -12,7 +12,7 @@ insert into t2 select * from t1; connection master1; create temporary table t1 (n int); insert into t1 values (4),(5); -insert into t2 select * from t1; +insert into t2 select * from t1 as t10; save_master_pos; disconnect master; connection slave; diff --git a/mysql-test/t/rpl000016.test b/mysql-test/t/rpl000016.test index 7b46bc75498..c9b6ccabcd2 100644 --- a/mysql-test/t/rpl000016.test +++ b/mysql-test/t/rpl000016.test @@ -28,7 +28,7 @@ select * from t1; connection master; flush logs; drop table if exists t2; -create table t2(m int not null primary key); +create table t2(m int not null auto_increment primary key); insert into t2 values (34),(67),(123); save_master_pos; flush logs; @@ -44,7 +44,8 @@ insert into t2 values(1234); #same value on the master connection master; save_master_pos; -insert into t2 values(1234); +set insert_id=1234; +insert into t2 values(NULL); connection slave; sync_with_master; diff --git a/sql/slave.cc b/sql/slave.cc index 958ea0f1e18..5fdbab7c7c6 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -885,7 +885,12 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len) mi->inc_pos(event_len); flush_master_info(mi); - if(slave_skip_counter) + if(slave_skip_counter && /* protect against common user error of + setting the counter to 1 instead of 2 + while recovering from an failed + auto-increment insert */ + !(type_code == INTVAR_EVENT && + slave_skip_counter == 1)) --slave_skip_counter; delete ev; return 0; // avoid infinite update loops diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 70dc2ed058d..656758623bc 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -527,10 +527,10 @@ void close_temporary_tables(THD *thd) if (query) // we might be out of memory, but this is not fatal { // skip temporary tables not created directly by the user - if (table->table_name[0] != '#') + if (table->real_name[0] != '#') { end = strxmov(end,table->table_cache_key,".", - table->table_name,",", NullS); + table->real_name,",", NullS); // here we assume table_cache_key always starts // with \0 terminated db name found_user_tables = 1;