From 4bf11aacd039dc6f7554681b846251af241ca701 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 29 Sep 2004 23:25:32 +0400 Subject: [PATCH 01/19] Fix for BUG#4785 part two: * If at least one of indexes is disabled, use data file size as an estimate for key file size. * Added handling for joined tables. --- myisam/myisampack.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/myisam/myisampack.c b/myisam/myisampack.c index 4b784641266..5efd6b3a7fd 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -111,6 +111,8 @@ typedef struct st_isam_mrg { uint ref_length; uint max_blob_length; my_off_t records; + /* true if at least one source file has at least one disabled index */ + my_bool src_file_has_indexes_disabled; } PACK_MRG_INFO; @@ -413,9 +415,16 @@ static bool open_isam_files(PACK_MRG_INFO *mrg,char **names,uint count) mrg->current=0; mrg->file=(MI_INFO**) my_malloc(sizeof(MI_INFO*)*count,MYF(MY_FAE)); mrg->free_file=1; + mrg->src_file_has_indexes_disabled= 0; for (i=0; i < count ; i++) { - if (!(mrg->file[i]=open_isam_file(names[i],O_RDONLY))) + if ((mrg->file[i]=open_isam_file(names[i],O_RDONLY))) + { + mrg->src_file_has_indexes_disabled |= + (mrg->file[i]->s->state.key_map != + (1ULL << mrg->file[i]->s->base.keys) - 1); + } + else goto error; } /* Check that files are identical */ @@ -2040,12 +2049,21 @@ static int save_state(MI_INFO *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length, share->state.dellink= HA_OFFSET_ERROR; share->state.split=(ha_rows) mrg->records; share->state.version=(ulong) time((time_t*) 0); - share->state.key_map=0; + if (share->state.key_map != (1ULL << share->base.keys) - 1) + { + /* + Some indexes are disabled, cannot use current key_file_length value + as an estimate of upper bound of index file size. Use packed data file + size instead. + */ + share->state.state.key_file_length= new_length; + } /* - Don't save key_file_length here, keep key_file_length of original file - so "myisamchk -rq" can use this value (this is necessary because index - size cannot be easily calculated for fulltext keys) + If there are no disabled indexes, keep key_file_length value from + original file so "myisamchk -rq" can use this value (this is necessary + because index size cannot be easily calculated for fulltext keys) */ + share->state.key_map=0; for (key=0 ; key < share->base.keys ; key++) share->state.key_root[key]= HA_OFFSET_ERROR; for (key=0 ; key < share->state.header.max_block_size ; key++) @@ -2054,8 +2072,7 @@ static int save_state(MI_INFO *isam_file,PACK_MRG_INFO *mrg,my_off_t new_length, share->changed=1; /* Force write of header */ share->state.open_count=0; share->global_changed=0; - VOID(my_chsize(share->kfile, share->state.state.key_file_length, 0, - MYF(0))); + VOID(my_chsize(share->kfile, share->base.keystart, 0, MYF(0))); if (share->base.keys) isamchk_neaded=1; DBUG_RETURN(mi_state_info_write(share->kfile,&share->state,1+2)); @@ -2078,7 +2095,12 @@ static int save_state_mrg(File file,PACK_MRG_INFO *mrg,my_off_t new_length, state.state.del=0; state.state.empty=0; state.state.records=state.split=(ha_rows) mrg->records; - state.state.key_file_length=isam_file->s->base.keystart; + /* See comment above in save_state about key_file_length handling. */ + if (mrg->src_file_has_indexes_disabled) + { + isam_file->s->state.state.key_file_length= + max(isam_file->s->state.state.key_file_length, new_length); + } state.dellink= HA_OFFSET_ERROR; state.version=(ulong) time((time_t*) 0); state.key_map=0; From 06a393083f76e1b4106ad657ac469283e522a312 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 3 Oct 2004 10:00:26 -0500 Subject: [PATCH 02/19] mysqld.cc: BUG #5731 Restrict key_buffer_size to 4GB on 64 bit platforms sql/mysqld.cc: BUG #5731 Restrict key_buffer_size to 4GB on 64 bit platforms BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted --- BitKeeper/etc/logging_ok | 1 + sql/mysqld.cc | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 8f9c0f60122..66002912edf 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -24,6 +24,7 @@ bk@admin.bk brian@brian-akers-computer.local carsten@tsort.bitbybit.dk davida@isil.mysql.com +dellis@goetia.(none) dlenev@brandersnatch.localdomain dlenev@build.mysql.com dlenev@mysql.com diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 834cff0d869..c256c335399 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4144,7 +4144,7 @@ replicating a LOAD DATA INFILE command", {"key_buffer_size", OPT_KEY_BUFFER_SIZE, "The size of the buffer used for index blocks. Increase this to get better index handling (for all reads and multiple writes) to as much as you can afford; 64M on a 256M machine that mainly runs MySQL is quite common.", (gptr*) &keybuff_size, (gptr*) &keybuff_size, 0, GET_ULL, - REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, + REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, (uint32) ~0, MALLOC_OVERHEAD, IO_SIZE, 0}, {"long_query_time", OPT_LONG_QUERY_TIME, "Log all queries that have taken more than long_query_time seconds to execute to file.", From 7949ffc86aa4789a8c3fe886721db974d9914c79 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Oct 2004 15:58:47 +0300 Subject: [PATCH 03/19] InnoDB: tolerate system clock glitches a little better in the error monitor thread. (Bug #5898) innobase/include/sync0arr.h: sync_array_print_long_waits(): return error status innobase/srv/srv0srv.c: srv_error_monitor_thread(): Keep track on successive fatal timeouts, and crash the server only if the timeouts have been exceeded for several times in succession. innobase/sync/sync0arr.c: sync_array_print_long_waits(): return error status --- innobase/include/sync0arr.h | 4 +++- innobase/srv/srv0srv.c | 20 ++++++++++++++++---- innobase/sync/sync0arr.c | 15 +++++++-------- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/innobase/include/sync0arr.h b/innobase/include/sync0arr.h index 4324f2d3f2c..73496a2ea84 100644 --- a/innobase/include/sync0arr.h +++ b/innobase/include/sync0arr.h @@ -97,9 +97,11 @@ sync_arr_wake_threads_if_sema_free(void); /************************************************************************** Prints warnings of long semaphore waits to stderr. */ -void +ibool sync_array_print_long_waits(void); /*=============================*/ + /* out: TRUE if fatal semaphore wait threshold + was exceeded */ /************************************************************************ Validates the integrity of the wait array. Checks that the number of reserved cells equals the count variable. */ diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index d799ada1e20..0643ab96c1d 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -1754,7 +1754,8 @@ srv_error_monitor_thread( /* in: a dummy parameter required by os_thread_create */ { - ulint cnt = 0; + /* number of successive fatal timeouts observed */ + ulint fatal_cnt = 0; #ifdef UNIV_DEBUG_THREAD_CREATION fprintf(stderr, "Error monitor thread starts, id %lu\n", @@ -1763,8 +1764,6 @@ srv_error_monitor_thread( loop: srv_error_monitor_active = TRUE; - cnt++; - os_thread_sleep(2000000); if (difftime(time(NULL), srv_last_monitor_time) > 60) { @@ -1774,7 +1773,20 @@ loop: srv_refresh_innodb_monitor_stats(); } - sync_array_print_long_waits(); + if (sync_array_print_long_waits()) { + fatal_cnt++; + if (fatal_cnt > 5) { + + fprintf(stderr, +"InnoDB: Error: semaphore wait has lasted > %lu seconds\n" +"InnoDB: We intentionally crash the server, because it appears to be hung.\n", + srv_fatal_semaphore_wait_threshold); + + ut_error; + } + } else { + fatal_cnt = 0; + } /* Flush stderr so that a database user gets the output to possible MySQL error file */ diff --git a/innobase/sync/sync0arr.c b/innobase/sync/sync0arr.c index 09ddfd1d309..a443d630425 100644 --- a/innobase/sync/sync0arr.c +++ b/innobase/sync/sync0arr.c @@ -889,15 +889,18 @@ sync_arr_wake_threads_if_sema_free(void) /************************************************************************** Prints warnings of long semaphore waits to stderr. */ -void +ibool sync_array_print_long_waits(void) /*=============================*/ + /* out: TRUE if fatal semaphore wait threshold + was exceeded */ { sync_cell_t* cell; ibool old_val; ibool noticed = FALSE; ulint i; ulint fatal_timeout = srv_fatal_semaphore_wait_threshold; + ibool fatal = FALSE; for (i = 0; i < sync_primary_wait_array->n_cells; i++) { @@ -914,13 +917,7 @@ sync_array_print_long_waits(void) if (cell->wait_object != NULL && difftime(time(NULL), cell->reservation_time) > fatal_timeout) { - - fprintf(stderr, -"InnoDB: Error: semaphore wait has lasted > %lu seconds\n" -"InnoDB: We intentionally crash the server, because it appears to be hung.\n", - fatal_timeout); - - ut_error; + fatal = TRUE; } } @@ -948,6 +945,8 @@ sync_array_print_long_waits(void) fprintf(stderr, "InnoDB: ###### Diagnostic info printed to the standard error stream\n"); } + + return(fatal); } /************************************************************************** From 66bdcf8439c3397856d028b13a6f0bb09769434d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Oct 2004 20:30:30 +0300 Subject: [PATCH 04/19] Fixed Bug#5575, mysqlhotcopy is broken when using --noindices BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted --- BitKeeper/etc/logging_ok | 1 + scripts/mysqlhotcopy.sh | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 8f9c0f60122..8347685b9b2 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -47,6 +47,7 @@ igor@hundin.mysql.fi igor@rurik.mysql.com ingo@mysql.com jani@a80-186-24-72.elisa-laajakaista.fi +jani@a80-186-41-201.elisa-laajakaista.fi jani@dsl-jkl1657.dial.inet.fi jani@hynda.(none) jani@hynda.mysql.fi diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index b90ca4dc7c0..f9e29e33195 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -8,7 +8,7 @@ use File::Path; use DBI; use Sys::Hostname; use File::Copy; -use File::Temp; +use File::Temp qw(tempfile); =head1 NAME @@ -39,7 +39,7 @@ WARNING: THIS PROGRAM IS STILL IN BETA. Comments/patches welcome. # Documentation continued at end of file -my $VERSION = "1.21"; +my $VERSION = "1.22"; my $opt_tmpdir = $ENV{TMPDIR} || "/tmp"; @@ -654,8 +654,8 @@ sub copy_index } elsif ($opt{method} =~ /^scp\b/) { - my ($fh, $tmp)=tempfile('mysqlhotcopy-XXXXXX', DIR => $opt_tmpdir); - die "Can\'t create/open file in $opt_tmpdir\n"; + my ($fh, $tmp)= tempfile('mysqlhotcopy-XXXXXX', DIR => $opt_tmpdir) or + die "Can\'t create/open file in $opt_tmpdir\n"; if (syswrite($fh,$buff) != length($buff)) { die "Error when writing data to $tmp: $!\n"; From e98bd143a74d6f6743c15b3f5ba866c09558f8c9 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 8 Oct 2004 16:32:56 +0300 Subject: [PATCH 05/19] Using MySQL 4.0 with privilege tables from 5.0 caused a crash. (Fixed this by backporting some logic from 4.1) --- sql/sql_acl.cc | 56 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 6e782f81ae5..b3bc5a1e4f2 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -106,7 +106,7 @@ static HASH acl_check_hosts, hash_tables; static DYNAMIC_ARRAY acl_wild_hosts; static hash_filo *acl_cache; static uint grant_version=0; -static ulong get_access(TABLE *form,uint fieldnr); +static ulong get_access(TABLE *form, uint fieldnr, uint *next_field); static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b); static ulong get_sort(uint count,...); static void init_check_host(void); @@ -191,7 +191,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) ACL_HOST host; update_hostname(&host.host,get_field(&mem, table,0)); host.db= get_field(&mem, table,1); - host.access= get_access(table,2); + host.access= get_access(table,2,0); host.access= fix_rights_for_db(host.access); host.sort= get_sort(2,host.host.hostname,host.db); #ifndef TO_BE_REMOVED @@ -241,14 +241,15 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) user.host.hostname ? user.host.hostname : ""); /* purecov: tested */ continue; /* purecov: tested */ } + uint next_field; get_salt_from_password(user.salt,user.password); - user.access=get_access(table,3) & GLOBAL_ACLS; + user.access=get_access(table,3,&next_field) & GLOBAL_ACLS; user.sort=get_sort(2,user.host.hostname,user.user); user.hostname_length= (user.host.hostname ? (uint) strlen(user.host.hostname) : 0); if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */ { - char *ssl_type=get_field(&mem, table, 24); + char *ssl_type=get_field(&mem, table, next_field++); if (!ssl_type) user.ssl_type=SSL_TYPE_NONE; else if (!strcmp(ssl_type, "ANY")) @@ -258,16 +259,16 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) else /* !strcmp(ssl_type, "SPECIFIED") */ user.ssl_type=SSL_TYPE_SPECIFIED; - user.ssl_cipher= get_field(&mem, table, 25); - user.x509_issuer= get_field(&mem, table, 26); - user.x509_subject= get_field(&mem, table, 27); + user.ssl_cipher= get_field(&mem, table, next_field++); + user.x509_issuer= get_field(&mem, table, next_field++); + user.x509_subject= get_field(&mem, table, next_field++); - char *ptr = get_field(&mem, table, 28); - user.user_resource.questions=atoi(ptr); - ptr = get_field(&mem, table, 29); - user.user_resource.updates=atoi(ptr); - ptr = get_field(&mem, table, 30); - user.user_resource.connections=atoi(ptr); + char *ptr = get_field(&mem, table, next_field++); + user.user_resource.questions= ptr ? atoi(ptr) : 0; + ptr = get_field(&mem, table, next_field++); + user.user_resource.updates= ptr ? atoi(ptr): 0; + ptr = get_field(&mem, table, next_field++); + user.user_resource.connections=ptr ? atoi(ptr) : 0; if (user.user_resource.questions || user.user_resource.updates || user.user_resource.connections) mqh_used=1; @@ -313,7 +314,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) continue; } db.user=get_field(&mem, table,2); - db.access=get_access(table,3); + db.access=get_access(table,3,0); db.access=fix_rights_for_db(db.access); db.sort=get_sort(3,db.host.hostname,db.db,db.user); #ifndef TO_BE_REMOVED @@ -423,11 +424,24 @@ void acl_reload(THD *thd) /* Get all access bits from table after fieldnr - We know that the access privileges ends when there is no more fields - or the field is not an enum with two elements. + + IMPLEMENTATION + We know that the access privileges ends when there is no more fields + or the field is not an enum with two elements. + + SYNOPSIS + get_access() + form an open table to read privileges from. + The record should be already read in table->record[0] + fieldnr number of the first privilege (that is ENUM('N','Y') field + next_field on return - number of the field next to the last ENUM + (unless next_field == 0) + + RETURN VALUE + privilege mask */ -static ulong get_access(TABLE *form, uint fieldnr) +static ulong get_access(TABLE *form, uint fieldnr, uint *next_field) { ulong access_bits=0,bit; char buff[2]; @@ -437,12 +451,14 @@ static ulong get_access(TABLE *form, uint fieldnr) for (pos=form->field+fieldnr, bit=1; *pos && (*pos)->real_type() == FIELD_TYPE_ENUM && ((Field_enum*) (*pos))->typelib->count == 2 ; - pos++ , bit<<=1) + pos++, fieldnr++, bit<<=1) { (*pos)->val_str(&res,&res); if (toupper(res[0]) == 'Y') access_bits|= bit; } + if (next_field) + *next_field=fieldnr; return access_bits; } @@ -1395,7 +1411,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, if (priv & rights) // set requested privileges (*tmp_field)->store(&what,1); } - rights=get_access(table,3); + rights=get_access(table,3,0); DBUG_PRINT("info",("table->fields: %d",table->fields)); if (table->fields >= 31) /* From 4.0.0 we have more fields */ { @@ -1554,7 +1570,7 @@ static int replace_db_table(TABLE *table, const char *db, if (priv & store_rights) // do it if priv is chosen table->field [i]->store(&what,1); // set requested privileges } - rights=get_access(table,3); + rights=get_access(table,3,0); rights=fix_rights_for_db(rights); if (old_row_exists) From 2763d893ea81632b9320ec66258f46e5c380b3b8 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 9 Oct 2004 14:13:40 +0300 Subject: [PATCH 06/19] trx0rec.c: Fix bug #5960: if one updated a column so that its size changed, or updated it to an externally stored (TEXT or BLOB) value, then ANOTHER externally stored column would show up as 512 bytes of good data + 20 bytes of garbage in a consistent read that fetched the old version of the row innobase/trx/trx0rec.c: Fix bug #5960: if one updated a column so that its size changed, or updated it to an externally stored (TEXT or BLOB) value, then ANOTHER externally stored column would show up as 512 bytes of good data + 20 bytes of garbage in a consistent read that fetched the old version of the row --- innobase/trx/trx0rec.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/innobase/trx/trx0rec.c b/innobase/trx/trx0rec.c index 79fad312e8e..0e1842ef4a0 100644 --- a/innobase/trx/trx0rec.c +++ b/innobase/trx/trx0rec.c @@ -1257,7 +1257,7 @@ trx_undo_prev_version_build( ibool dummy_extern; byte* buf; ulint err; - ulint i; + #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED)); #endif /* UNIV_SYNC_DEBUG */ @@ -1367,7 +1367,18 @@ trx_undo_prev_version_build( } if (row_upd_changes_field_size_or_external(rec, index, update)) { + ulint* ext_vect; + ulint n_ext_vect; + /* We have to set the appropriate extern storage bits in the + old version of the record: the extern bits in rec for those + fields that update does NOT update, as well as the the bits for + those fields that update updates to become externally stored + fields. Store the info to ext_vect: */ + + ext_vect = mem_alloc(sizeof(ulint) * rec_get_n_fields(rec)); + n_ext_vect = btr_push_update_extern_fields(ext_vect, rec, + update); entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); row_upd_index_replace_new_col_vals(entry, index, update, heap); @@ -1375,6 +1386,11 @@ trx_undo_prev_version_build( buf = mem_heap_alloc(heap, rec_get_converted_size(entry)); *old_vers = rec_convert_dtuple_to_rec(buf, entry); + + /* Now set the extern bits in the old version of the record */ + rec_set_field_extern_bits(*old_vers, ext_vect, n_ext_vect, + NULL); + mem_free(ext_vect); } else { buf = mem_heap_alloc(heap, rec_get_size(rec)); @@ -1383,15 +1399,5 @@ trx_undo_prev_version_build( row_upd_rec_in_place(*old_vers, update); } - for (i = 0; i < upd_get_n_fields(update); i++) { - - if (upd_get_nth_field(update, i)->extern_storage) { - - rec_set_nth_field_extern_bit(*old_vers, - upd_get_nth_field(update, i)->field_no, - TRUE, NULL); - } - } - return(DB_SUCCESS); } From c5f9a412cebd01a8501465688943fe57fe601275 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 11 Oct 2004 11:01:38 +0200 Subject: [PATCH 07/19] Fix for BUG#5949 "error code 1223 in binlog when using innobackup": when one connection had done FLUSH TABLES WITH READ LOCK, some updates, and then COMMIT, it was accepted but my_error() was called and so, while client got no error, error was logged in binlog. We now don't call my_error() in this case; we assume the connection know what it does. This problem was specific to 4.0.21. The change is needed to make replication work with existing versions of innobackup. sql/lock.cc: If a connection has done FLUSH TABLES WITH READ LOCK and now is doing COMMIT, don't give error (applies only if it's the same connection; others' COMMITs are still blocked). --- mysql-test/r/rpl_commit_after_flush.result | 13 +++++++++++++ mysql-test/t/rpl_commit_after_flush.test | 17 +++++++++++++++++ sql/lock.cc | 10 ++++++++-- 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 mysql-test/r/rpl_commit_after_flush.result create mode 100644 mysql-test/t/rpl_commit_after_flush.test diff --git a/mysql-test/r/rpl_commit_after_flush.result b/mysql-test/r/rpl_commit_after_flush.result new file mode 100644 index 00000000000..8cdc7e986ab --- /dev/null +++ b/mysql-test/r/rpl_commit_after_flush.result @@ -0,0 +1,13 @@ +slave stop; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +slave start; +create table t1 (a int) type=innodb; +begin; +insert into t1 values(1); +flush tables with read lock; +commit; +unlock tables; +drop table t1; diff --git a/mysql-test/t/rpl_commit_after_flush.test b/mysql-test/t/rpl_commit_after_flush.test new file mode 100644 index 00000000000..edbbd1bfad6 --- /dev/null +++ b/mysql-test/t/rpl_commit_after_flush.test @@ -0,0 +1,17 @@ +source include/master-slave.inc; +source include/have_innodb.inc; +create table t1 (a int) type=innodb; +begin; +insert into t1 values(1); +flush tables with read lock; +commit; +save_master_pos; +connection slave; +sync_with_master; +# cleanup +connection master; +unlock tables; +drop table t1; +save_master_pos; +connection slave; +sync_with_master; diff --git a/sql/lock.cc b/sql/lock.cc index dd2b61b65d2..bf0160291f8 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -751,9 +751,15 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, bool is_not_commi { if (thd->global_read_lock) // This thread had the read locks { - my_error(ER_CANT_UPDATE_WITH_READLOCK,MYF(0)); + if (is_not_commit) + my_error(ER_CANT_UPDATE_WITH_READLOCK,MYF(0)); (void) pthread_mutex_unlock(&LOCK_open); - DBUG_RETURN(1); + /* + We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does. + This allowance is needed to not break existing versions of innobackup + which do a BEGIN; INSERT; FLUSH TABLES WITH READ LOCK; COMMIT. + */ + DBUG_RETURN(is_not_commit); } old_message=thd->enter_cond(&COND_refresh, &LOCK_open, "Waiting for release of readlock"); From eb3b0480002d257d9beb5262fd51619cc4b50a1f Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 12 Oct 2004 18:12:00 +0300 Subject: [PATCH 08/19] ha_innodb.cc: Change error code to HA_ERR_ROW_IS_REFERENCED if we cannot DROP a parent table referenced by a FOREIGN KEY constraint; this error number is less misleading than the previous value HA_ERR_CANNOT_ADD_FOREIGN, but misleading still; we should introduce to 5.0 a proper MySQL error code sql/ha_innodb.cc: Change error code to HA_ERR_ROW_IS_REFERENCED if we cannot DROP a parent table referenced by a FOREIGN KEY constraint; this error number is less misleading than the previous value HA_ERR_CANNOT_ADD_FOREIGN, but misleading still; we should introduce to 5.0 a proper MySQL error code --- sql/ha_innodb.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index f149af85b3f..fa9537b3217 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -285,7 +285,7 @@ convert_error_code_to_mysql( } else if (error == (int) DB_CANNOT_DROP_CONSTRAINT) { - return(HA_ERR_CANNOT_ADD_FOREIGN); /* TODO: This is a bit + return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit misleading, a new MySQL error code should be introduced */ } else if (error == (int) DB_COL_APPEARS_TWICE_IN_INDEX) { From f0ed73d874d92bd6e21333bcba4b1097db069213 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 13 Oct 2004 22:54:21 +0300 Subject: [PATCH 09/19] Added startup option and settable session variable innodb_table_locks_old_behavior: do not acquire an InnoDB table lock for LOCK TABLES, as in mysql-4.0.18 and earlier. sql/ha_innodb.cc: Do not acquire an InnoDB table lock for LOCK TABLES if innodb_table_locks_old_behavior is enabled. sql/mysqld.cc: Added innodb_table_locks_old_behavior sql/set_var.cc: Added innodb_table_locks_old_behavior sql/sql_class.h: Added innodb_table_locks_old_behavior --- sql/ha_innodb.cc | 3 ++- sql/mysqld.cc | 7 ++++++- sql/set_var.cc | 4 ++++ sql/sql_class.h | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index fa9537b3217..44d050d14aa 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4693,7 +4693,8 @@ ha_innobase::external_lock( } if (prebuilt->select_lock_type != LOCK_NONE) { - if (thd->in_lock_tables) { + if (thd->in_lock_tables && + !thd->variables.innodb_table_locks_old_behavior) { ulint error; error = row_lock_table_for_mysql(prebuilt); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 89d71ecbfa2..8b478882451 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3526,6 +3526,7 @@ enum options_mysqld { OPT_INNODB_FORCE_RECOVERY, OPT_INNODB_STATUS_FILE, OPT_INNODB_MAX_DIRTY_PAGES_PCT, + OPT_INNODB_TABLE_LOCKS_OLD_BEHAVIOR, OPT_BDB_CACHE_SIZE, OPT_BDB_LOG_BUFFER_SIZE, OPT_BDB_MAX_LOCK, @@ -3699,7 +3700,11 @@ struct my_option my_long_options[] = {"innodb_max_dirty_pages_pct", OPT_INNODB_MAX_DIRTY_PAGES_PCT, "Percentage of dirty pages allowed in bufferpool", (gptr*) &srv_max_buf_pool_modified_pct, (gptr*) &srv_max_buf_pool_modified_pct, 0, GET_ULONG, REQUIRED_ARG, 90, 0, 100, 0, 0, 0}, - + {"innodb_table_locks_old_behavior", OPT_INNODB_TABLE_LOCKS_OLD_BEHAVIOR, + "Disable InnoDB locking in LOCK TABLES", + (gptr*) &global_system_variables.innodb_table_locks_old_behavior, + (gptr*) &global_system_variables.innodb_table_locks_old_behavior, + 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif /* End HAVE_INNOBASE_DB */ {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, diff --git a/sql/set_var.cc b/sql/set_var.cc index 4b66a621f62..9b2db7a0802 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -263,6 +263,8 @@ sys_var_thd_ulong sys_net_wait_timeout("wait_timeout", #ifdef HAVE_INNOBASE_DB sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_pct", &srv_max_buf_pool_modified_pct); +sys_var_thd_bool sys_innodb_table_locks_old_behavior("innodb_table_locks_old_behavior", + &SV::innodb_table_locks_old_behavior); #endif @@ -449,6 +451,7 @@ sys_var *sys_variables[]= &sys_os, #ifdef HAVE_INNOBASE_DB &sys_innodb_max_dirty_pages_pct, + &sys_innodb_table_locks_old_behavior, #endif &sys_unique_checks }; @@ -520,6 +523,7 @@ struct show_var_st init_vars[]= { {"innodb_log_group_home_dir", (char*) &innobase_log_group_home_dir, SHOW_CHAR_PTR}, {"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG}, {sys_innodb_max_dirty_pages_pct.name, (char*) &sys_innodb_max_dirty_pages_pct, SHOW_SYS}, + {sys_innodb_table_locks_old_behavior.name, (char*) &sys_innodb_table_locks_old_behavior, SHOW_SYS}, #endif {sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS}, {sys_join_buffer_size.name, (char*) &sys_join_buffer_size, SHOW_SYS}, diff --git a/sql/sql_class.h b/sql/sql_class.h index af53574eeaf..8c383d5848d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -338,6 +338,9 @@ struct system_variables my_bool low_priority_updates; my_bool new_mode; my_bool query_cache_wlock_invalidate; +#ifdef HAVE_INNOBASE_DB + my_bool innodb_table_locks_old_behavior; +#endif /* HAVE_INNOBASE_DB */ CONVERT *convert_set; }; From fc27da0879c477eba748d1412978afa4032b54ab Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 14 Oct 2004 20:02:56 +0200 Subject: [PATCH 10/19] BUG#5625 - MyISAM Index corruption on ALTER TABLE x ENABLE KEYS due to full tmpdir. Added a try to a normal repair() if repair_by_sort() failed. This was not done with ENABLE KEYS and OPTIMIZE TABLE. Fixed error code handling in mysql_alter_table(). sql/ha_myisam.cc: BUG#5625 - MyISAM Index corruption on ALTER TABLE x ENABLE KEYS due to full tmpdir. Added a try to a normal repair() if repair_by_sort() failed. This was not done with ENABLE KEYS and OPTIMIZE TABLE. sql/sql_table.cc: BUG#5625 - MyISAM Index corruption on ALTER TABLE x ENABLE KEYS due to full tmpdir. Added a translation from 'bool' return value to '< 0' error indication, which is used within mysql_execute_command() and must as such be handed over by mysql_alter_table(). A returncode >= 0 is interpreted as 'I have already called send_ok()'. --- sql/ha_myisam.cc | 18 ++++++++++++++++-- sql/sql_table.cc | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 2b7b8f436b1..71623238bd9 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -525,6 +525,7 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt) int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt) { + int error; if (!file) return HA_ADMIN_INTERNAL_ERROR; MI_CHECK param; @@ -534,7 +535,14 @@ int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt) param.testflag = (check_opt->flags | T_SILENT | T_FORCE_CREATE | T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX); param.sort_buffer_length= check_opt->sort_buffer_size; - return repair(thd,param,1); + if ((error= repair(thd,param,1)) && param.retry_repair) + { + sql_print_warning("Warning: Optimize table got errno %d, retrying", + my_errno); + param.testflag&= ~T_REP_BY_SORT; + error= repair(thd,param,1); + } + return error; } @@ -744,7 +752,13 @@ bool ha_myisam::activate_all_index(THD *thd) param.myf_rw&= ~MY_WAIT_IF_FULL; param.sort_buffer_length= thd->variables.myisam_sort_buff_size; param.tmpdir=mysql_tmpdir; - error=repair(thd,param,0) != HA_ADMIN_OK; + if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair) + { + sql_print_warning("Warning: Enabling keys got errno %d, retrying", + my_errno); + param.testflag&= ~(T_REP_BY_SORT | T_QUICK); + error= (repair(thd,param,0) != HA_ADMIN_OK); + } info(HA_STATUS_CONST); thd->proc_info=save_proc_info; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a15f8b65006..0f2116dbcdb 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1614,7 +1614,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, VOID(pthread_mutex_lock(&LOCK_open)); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); VOID(pthread_mutex_unlock(&LOCK_open)); - error= table->file->activate_all_index(thd); + error= (table->file->activate_all_index(thd) ? -1 : 0); /* COND_refresh will be signaled in close_thread_tables() */ break; case DISABLE: From 9f4d19f99580b439a3edfb3e736797041bf18ee8 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Oct 2004 15:33:30 +0200 Subject: [PATCH 11/19] the $^ directive is a GNU make extension and not really needed here so lets get rid of it (Bug #6112) --- configure.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 37b0432b98d..d4073ea441b 100644 --- a/configure.in +++ b/configure.in @@ -40,12 +40,12 @@ do case $host_os in netware* | modesto*) echo "$i/errmsg.sys: $i/errmsg.txt - \$(top_builddir)/extra/comp_err.linux \$^ $i/errmsg.sys" \ + \$(top_builddir)/extra/comp_err.linux $i/errmsg.txt $i/errmsg.sys" \ >> $AVAILABLE_LANGUAGES_ERRORS_RULES ;; *) echo "$i/errmsg.sys: $i/errmsg.txt - \$(top_builddir)/extra/comp_err \$^ $i/errmsg.sys" \ + \$(top_builddir)/extra/comp_err $i/errmsg.txt $i/errmsg.sys" \ >> $AVAILABLE_LANGUAGES_ERRORS_RULES ;; esac From 842e7231868cef88f12a761772a42789d6ecfbf5 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Oct 2004 23:16:02 -0500 Subject: [PATCH 12/19] texi2html: Change parsing of @image argument. Docs/Support/texi2html: Change parsing of @image argument. --- Docs/Support/texi2html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Docs/Support/texi2html b/Docs/Support/texi2html index 5dda7c8bbd5..8067d8f72ce 100755 --- a/Docs/Support/texi2html +++ b/Docs/Support/texi2html @@ -1811,7 +1811,7 @@ sub fix_image { my($text) = @_; my($arg1, $ext); - $text =~ /^([^,]*)$/; + $text =~ /^([^,]*)/; die "error in image: '$text'" unless defined($1); $arg1 = $1; $arg1 =~ s/@@/@/g; From 5dfa8d859be85f14e60771fb31693c68d8eee26c Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 17 Oct 2004 18:44:51 -0500 Subject: [PATCH 13/19] mysqld.cc: BUG #5731 key_buffer_size not properly restricted to 4GB; use UINT_MAX32 for clarity. sql/mysqld.cc: BUG #5731 key_buffer_size not properly restricted to 4GB; use UINT_MAX32 for clarity. --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c256c335399..ff867b010b0 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4144,7 +4144,7 @@ replicating a LOAD DATA INFILE command", {"key_buffer_size", OPT_KEY_BUFFER_SIZE, "The size of the buffer used for index blocks. Increase this to get better index handling (for all reads and multiple writes) to as much as you can afford; 64M on a 256M machine that mainly runs MySQL is quite common.", (gptr*) &keybuff_size, (gptr*) &keybuff_size, 0, GET_ULL, - REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, (uint32) ~0, MALLOC_OVERHEAD, + REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, UINT_MAX32, MALLOC_OVERHEAD, IO_SIZE, 0}, {"long_query_time", OPT_LONG_QUERY_TIME, "Log all queries that have taken more than long_query_time seconds to execute to file.", From 2428fb5c2b01aba74fb3cb49bca9d690c203b715 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Oct 2004 09:50:47 +0500 Subject: [PATCH 14/19] libmysql.c: New function mysql_hex_string() libmysql/libmysql.c: New function mysql_hex_string() --- libmysql/libmysql.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index a591ad9317d..9257bf0efd0 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -3153,6 +3153,39 @@ void my_net_local_init(NET *net) net->max_packet_size= max(net_buffer_length, max_allowed_packet); } +/* + This function is used to create HEX string that you + can use in a SQL statement in of the either ways: + INSERT INTO blob_column VALUES (0xAABBCC); (any MySQL version) + INSERT INTO blob_column VALUES (X'AABBCC'); (4.1 and higher) + + The string in "from" is encoded to a HEX string. + The result is placed in "to" and a terminating null byte is appended. + + The string pointed to by "from" must be "length" bytes long. + You must allocate the "to" buffer to be at least length*2+1 bytes long. + Each character needs two bytes, and you need room for the terminating + null byte. When mysql_hex_string() returns, the contents of "to" will + be a null-terminated string. The return value is the length of the + encoded string, not including the terminating null character. +*/ + +unsigned long +mysql_hex_string(char *to, const char *from, unsigned long length) +{ + char *to0= to; + const char *end; + static char hex[]= "0123456789ABCDEF"; + + for (end= from + length; from < end; from++) + { + *to++= hex[((unsigned char) *from) >> 4]; + *to++= hex[((unsigned char) *from) & 0x0F]; + } + *to= '\0'; + return to-to0; +} + /* Add escape characters to a string (blob?) to make it suitable for a insert to should at least have place for length*2+1 chars From 30d33c7132f44b3f6fefd2c4eae1f7279c977037 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Oct 2004 07:44:20 -0500 Subject: [PATCH 15/19] libmysql.c: Add note to mysql_hex_string() comment. libmysql/libmysql.c: Add note to mysql_hex_string() comment. --- libmysql/libmysql.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 9257bf0efd0..73f8f8f8b0b 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -3168,6 +3168,9 @@ void my_net_local_init(NET *net) null byte. When mysql_hex_string() returns, the contents of "to" will be a null-terminated string. The return value is the length of the encoded string, not including the terminating null character. + + The return value does not contain any leading 0x or a leading X' and + trailing '. The caller must supply whichever of those is desired. */ unsigned long From 0e0c9af593367797d844058bfff0534b53c7fe12 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Oct 2004 18:58:53 +0300 Subject: [PATCH 16/19] trx0rec.c: test innobase/trx/trx0rec.c: test --- innobase/trx/trx0rec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/innobase/trx/trx0rec.c b/innobase/trx/trx0rec.c index 0e1842ef4a0..a5623b4d0c7 100644 --- a/innobase/trx/trx0rec.c +++ b/innobase/trx/trx0rec.c @@ -1377,7 +1377,7 @@ trx_undo_prev_version_build( fields. Store the info to ext_vect: */ ext_vect = mem_alloc(sizeof(ulint) * rec_get_n_fields(rec)); - n_ext_vect = btr_push_update_extern_fields(ext_vect, rec, + n_ext_vect = btr_push_update_extern_fields(ext_vect, rec, update); entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap); From ed8ec2cf1613e1bb57705698b8962e767fd89320 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Oct 2004 11:24:08 +0300 Subject: [PATCH 17/19] Code cleanups (done during review of new code) Rename innodb_table_locks_old_behavior -> innodb_table_locks Set innodb_table_locks to off by default to get same behaviour as in MySQL 4.0.20 (This means that Innodb ignore table locks by default, which makes it easier to combine MyISAM and InnoDB to simulate a transaction) libmysql/libmysql.c: Use ulong instead of unsigned long Reuse _dig_vec() myisam/myisampack.c: Simplify code mysql-test/r/innodb-lock.result: new test case mysql-test/t/innodb-lock.test: new test case sql/ha_innodb.cc: Rename innodb_table_locks_old_behavior -> innodb_table_locks sql/mysqld.cc: Rename innodb_table_locks_old_behavior -> innodb_table_locks Set this off by default to get same behaviour as in MySQL 4.0.20 sql/set_var.cc: Rename innodb_table_locks_old_behavior -> innodb_table_locks sql/sql_class.h: Rename innodb_table_locks_old_behavior -> innodb_table_locks --- libmysql/libmysql.c | 10 +++---- myisam/myisampack.c | 12 ++++----- mysql-test/r/innodb-lock.result | 26 +++++++++++++++++++ mysql-test/t/innodb-lock.test | 46 ++++++++++++++++++++++++++++++++- sql/ha_innodb.cc | 2 +- sql/mysqld.cc | 10 +++---- sql/set_var.cc | 8 +++--- sql/sql_class.h | 2 +- 8 files changed, 91 insertions(+), 25 deletions(-) diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 9257bf0efd0..09675bc7fab 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -3170,20 +3170,18 @@ void my_net_local_init(NET *net) encoded string, not including the terminating null character. */ -unsigned long -mysql_hex_string(char *to, const char *from, unsigned long length) +ulong mysql_hex_string(char *to, const char *from, ulong length) { char *to0= to; const char *end; - static char hex[]= "0123456789ABCDEF"; for (end= from + length; from < end; from++) { - *to++= hex[((unsigned char) *from) >> 4]; - *to++= hex[((unsigned char) *from) & 0x0F]; + *to++= _dig_vec[((unsigned char) *from) >> 4]; + *to++= _dig_vec[((unsigned char) *from) & 0x0F]; } *to= '\0'; - return to-to0; + return (ulong) (to-to0); } /* diff --git a/myisam/myisampack.c b/myisam/myisampack.c index 5efd6b3a7fd..0dde1916f03 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -418,14 +418,12 @@ static bool open_isam_files(PACK_MRG_INFO *mrg,char **names,uint count) mrg->src_file_has_indexes_disabled= 0; for (i=0; i < count ; i++) { - if ((mrg->file[i]=open_isam_file(names[i],O_RDONLY))) - { - mrg->src_file_has_indexes_disabled |= - (mrg->file[i]->s->state.key_map != - (1ULL << mrg->file[i]->s->base.keys) - 1); - } - else + if (!(mrg->file[i]=open_isam_file(names[i],O_RDONLY))) goto error; + + mrg->src_file_has_indexes_disabled|= ((mrg->file[i]->s->state.key_map != + (((ulonglong) 1) << + mrg->file[i]->s->base. keys) - 1)); } /* Check that files are identical */ for (j=0 ; j < count-1 ; j++) diff --git a/mysql-test/r/innodb-lock.result b/mysql-test/r/innodb-lock.result index cf00adb30ae..f87f221ea66 100644 --- a/mysql-test/r/innodb-lock.result +++ b/mysql-test/r/innodb-lock.result @@ -1,4 +1,30 @@ drop table if exists t1; +select @@innodb_table_locks; +@@innodb_table_locks +0 +set @@innodb_table_locks=1; +create table t1 (id integer, x integer) engine=INNODB; +insert into t1 values(0, 0); +set autocommit=0; +SELECT * from t1 where id = 0 FOR UPDATE; +id x +0 0 +set autocommit=0; +lock table t1 write; +update t1 set x=1 where id = 0; +select * from t1; +id x +0 1 +commit; +update t1 set x=2 where id = 0; +commit; +unlock tables; +select * from t1; +id x +0 2 +commit; +drop table t1; +set @@innodb_table_locks=0; create table t1 (id integer, x integer) engine=INNODB; insert into t1 values(0, 0); set autocommit=0; diff --git a/mysql-test/t/innodb-lock.test b/mysql-test/t/innodb-lock.test index 43a175508b4..11395b301c4 100644 --- a/mysql-test/t/innodb-lock.test +++ b/mysql-test/t/innodb-lock.test @@ -5,9 +5,17 @@ connect (con2,localhost,root,,); drop table if exists t1; # -# Testing of explicit table locks +# Check and select innodb lock type # +select @@innodb_table_locks; + +# +# Testing of explicit table locks with enforced table locks +# + +set @@innodb_table_locks=1; + connection con1; create table t1 (id integer, x integer) engine=INNODB; insert into t1 values(0, 0); @@ -38,3 +46,39 @@ select * from t1; commit; drop table t1; + +# +# Try with old lock method (where LOCK TABLE is ignored) +# + +set @@innodb_table_locks=0; + +create table t1 (id integer, x integer) engine=INNODB; +insert into t1 values(0, 0); +set autocommit=0; +SELECT * from t1 where id = 0 FOR UPDATE; + +connection con2; +set autocommit=0; + +# The following statement should hang because con1 is locking the page +--send +lock table t1 write; +--sleep 2; + +connection con1; +update t1 set x=1 where id = 0; +select * from t1; +commit; + +connection con2; +reap; +update t1 set x=2 where id = 0; +commit; +unlock tables; + +connection con1; +select * from t1; +commit; + +drop table t1; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 44d050d14aa..e747ff3210c 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4694,7 +4694,7 @@ ha_innobase::external_lock( if (prebuilt->select_lock_type != LOCK_NONE) { if (thd->in_lock_tables && - !thd->variables.innodb_table_locks_old_behavior) { + thd->variables.innodb_table_locks) { ulint error; error = row_lock_table_for_mysql(prebuilt); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 226d4c113a5..b7eafcbcc14 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3526,7 +3526,7 @@ enum options_mysqld { OPT_INNODB_FORCE_RECOVERY, OPT_INNODB_STATUS_FILE, OPT_INNODB_MAX_DIRTY_PAGES_PCT, - OPT_INNODB_TABLE_LOCKS_OLD_BEHAVIOR, + OPT_INNODB_TABLE_LOCKS, OPT_BDB_CACHE_SIZE, OPT_BDB_LOG_BUFFER_SIZE, OPT_BDB_MAX_LOCK, @@ -3700,10 +3700,10 @@ struct my_option my_long_options[] = {"innodb_max_dirty_pages_pct", OPT_INNODB_MAX_DIRTY_PAGES_PCT, "Percentage of dirty pages allowed in bufferpool", (gptr*) &srv_max_buf_pool_modified_pct, (gptr*) &srv_max_buf_pool_modified_pct, 0, GET_ULONG, REQUIRED_ARG, 90, 0, 100, 0, 0, 0}, - {"innodb_table_locks_old_behavior", OPT_INNODB_TABLE_LOCKS_OLD_BEHAVIOR, - "Disable InnoDB locking in LOCK TABLES", - (gptr*) &global_system_variables.innodb_table_locks_old_behavior, - (gptr*) &global_system_variables.innodb_table_locks_old_behavior, + {"innodb_table_locks", OPT_INNODB_TABLE_LOCKS, + "If Innodb should enforce LOCK TABLE", + (gptr*) &global_system_variables.innodb_table_locks, + (gptr*) &global_system_variables.innodb_table_locks, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif /* End HAVE_INNOBASE_DB */ {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, diff --git a/sql/set_var.cc b/sql/set_var.cc index 9b2db7a0802..a6a5ea72c71 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -263,8 +263,8 @@ sys_var_thd_ulong sys_net_wait_timeout("wait_timeout", #ifdef HAVE_INNOBASE_DB sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_pct", &srv_max_buf_pool_modified_pct); -sys_var_thd_bool sys_innodb_table_locks_old_behavior("innodb_table_locks_old_behavior", - &SV::innodb_table_locks_old_behavior); +sys_var_thd_bool sys_innodb_table_locks("innodb_table_locks", + &SV::innodb_table_locks); #endif @@ -451,7 +451,7 @@ sys_var *sys_variables[]= &sys_os, #ifdef HAVE_INNOBASE_DB &sys_innodb_max_dirty_pages_pct, - &sys_innodb_table_locks_old_behavior, + &sys_innodb_table_locks, #endif &sys_unique_checks }; @@ -523,7 +523,7 @@ struct show_var_st init_vars[]= { {"innodb_log_group_home_dir", (char*) &innobase_log_group_home_dir, SHOW_CHAR_PTR}, {"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG}, {sys_innodb_max_dirty_pages_pct.name, (char*) &sys_innodb_max_dirty_pages_pct, SHOW_SYS}, - {sys_innodb_table_locks_old_behavior.name, (char*) &sys_innodb_table_locks_old_behavior, SHOW_SYS}, + {sys_innodb_table_locks.name, (char*) &sys_innodb_table_locks, SHOW_SYS}, #endif {sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS}, {sys_join_buffer_size.name, (char*) &sys_join_buffer_size, SHOW_SYS}, diff --git a/sql/sql_class.h b/sql/sql_class.h index 8c383d5848d..4250ebdd568 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -339,7 +339,7 @@ struct system_variables my_bool new_mode; my_bool query_cache_wlock_invalidate; #ifdef HAVE_INNOBASE_DB - my_bool innodb_table_locks_old_behavior; + my_bool innodb_table_locks; #endif /* HAVE_INNOBASE_DB */ CONVERT *convert_set; From ec8779e95a46b3dfff492196ad004cb2716df3c3 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Oct 2004 16:04:28 +0300 Subject: [PATCH 18/19] Fix test case for innodb-lock mysql-test/r/innodb-lock.result: Fix test case (old one didn't test things correctly) mysql-test/t/innodb-lock.test: Fix test case (old one didn't test things correctly) mysys/thr_lock.c: More debugging information sql/mysqld.cc: Enable innodb_table_locks as default, as otherwise there is a possibility for deadlocks sql/sql_base.cc: More debug information --- mysql-test/r/innodb-lock.result | 30 +++++++++++------- mysql-test/t/innodb-lock-master.opt | 1 + mysql-test/t/innodb-lock.test | 47 ++++++++++++++++++----------- mysys/thr_lock.c | 12 ++++++-- sql/mysqld.cc | 2 +- sql/sql_base.cc | 2 ++ 6 files changed, 62 insertions(+), 32 deletions(-) create mode 100644 mysql-test/t/innodb-lock-master.opt diff --git a/mysql-test/r/innodb-lock.result b/mysql-test/r/innodb-lock.result index f87f221ea66..407a85ed038 100644 --- a/mysql-test/r/innodb-lock.result +++ b/mysql-test/r/innodb-lock.result @@ -1,7 +1,7 @@ -drop table if exists t1; select @@innodb_table_locks; @@innodb_table_locks -0 +1 +drop table if exists t1; set @@innodb_table_locks=1; create table t1 (id integer, x integer) engine=INNODB; insert into t1 values(0, 0); @@ -25,24 +25,32 @@ id x commit; drop table t1; set @@innodb_table_locks=0; -create table t1 (id integer, x integer) engine=INNODB; -insert into t1 values(0, 0); -set autocommit=0; +create table t1 (id integer primary key, x integer) engine=INNODB; +insert into t1 values(0, 0),(1,1),(2,2); +commit; SELECT * from t1 where id = 0 FOR UPDATE; id x 0 0 set autocommit=0; +set @@innodb_table_locks=0; lock table t1 write; -update t1 set x=1 where id = 0; -select * from t1; +update t1 set x=10 where id = 2; +SELECT * from t1 where id = 2; id x -0 1 +2 2 +UPDATE t1 set x=3 where id = 2; commit; -update t1 set x=2 where id = 0; +SELECT * from t1; +id x +0 0 +1 1 +2 3 commit; unlock tables; +commit; select * from t1; id x -0 2 -commit; +0 0 +1 1 +2 10 drop table t1; diff --git a/mysql-test/t/innodb-lock-master.opt b/mysql-test/t/innodb-lock-master.opt new file mode 100644 index 00000000000..403fcde87ed --- /dev/null +++ b/mysql-test/t/innodb-lock-master.opt @@ -0,0 +1 @@ +--innodb-table-lock=1 diff --git a/mysql-test/t/innodb-lock.test b/mysql-test/t/innodb-lock.test index 11395b301c4..430369f4fda 100644 --- a/mysql-test/t/innodb-lock.test +++ b/mysql-test/t/innodb-lock.test @@ -1,9 +1,5 @@ -- source include/have_innodb.inc -connect (con1,localhost,root,,); -connect (con2,localhost,root,,); -drop table if exists t1; - # # Check and select innodb lock type # @@ -14,6 +10,14 @@ select @@innodb_table_locks; # Testing of explicit table locks with enforced table locks # +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); +drop table if exists t1; + +# +# Testing of explicit table locks with enforced table locks +# + set @@innodb_table_locks=1; connection con1; @@ -48,37 +52,44 @@ commit; drop table t1; # -# Try with old lock method (where LOCK TABLE is ignored) +# Try with old lock method (where LOCK TABLE is ignored by InnoDB) # set @@innodb_table_locks=0; -create table t1 (id integer, x integer) engine=INNODB; -insert into t1 values(0, 0); -set autocommit=0; +create table t1 (id integer primary key, x integer) engine=INNODB; +insert into t1 values(0, 0),(1,1),(2,2); +commit; SELECT * from t1 where id = 0 FOR UPDATE; connection con2; set autocommit=0; +set @@innodb_table_locks=0; -# The following statement should hang because con1 is locking the page ---send +# The following statement should work becase innodb doesn't check table locks lock table t1 write; ---sleep 2; connection con1; -update t1 set x=1 where id = 0; -select * from t1; -commit; + +# This will be locked by MySQL +--send +update t1 set x=10 where id = 2; +--sleep 2 connection con2; -reap; -update t1 set x=2 where id = 0; + +# Note that we will get a deadlock if we try to select any rows marked +# for update by con1 ! + +SELECT * from t1 where id = 2; +UPDATE t1 set x=3 where id = 2; +commit; +SELECT * from t1; commit; unlock tables; connection con1; -select * from t1; +reap; commit; - +select * from t1; drop table t1; diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index d5236cb1ef9..935ed4ea282 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -552,8 +552,14 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) !lock->write_wait.data && lock->write.data->type == TL_WRITE_ALLOW_WRITE)) { - /* We have already got a write lock or all locks are - TL_WRITE_ALLOW_WRITE */ + /* + We have already got a write lock or all locks are + TL_WRITE_ALLOW_WRITE + */ + DBUG_PRINT("info", ("write_wait.data: 0x%lx old_type: %d", + (ulong) lock->write_wait.data, + lock->write.data->type)); + (*lock->write.last)=data; /* Add to running fifo */ data->prev=lock->write.last; lock->write.last= &data->next; @@ -568,6 +574,8 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) } else { + DBUG_PRINT("info", ("write_wait.data: 0x%lx", + (ulong) lock->write_wait.data)); if (!lock->write_wait.data) { /* no scheduled write locks */ if (lock_type == TL_WRITE_CONCURRENT_INSERT && diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b7eafcbcc14..5838bd909dd 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3704,7 +3704,7 @@ struct my_option my_long_options[] = "If Innodb should enforce LOCK TABLE", (gptr*) &global_system_variables.innodb_table_locks, (gptr*) &global_system_variables.innodb_table_locks, - 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, + 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, #endif /* End HAVE_INNOBASE_DB */ {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 9810ec6c3d6..72400bf0abb 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -826,6 +826,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, DBUG_RETURN(0); } table->query_id=thd->query_id; + DBUG_PRINT("info",("Using temporary table")); goto reset; } } @@ -840,6 +841,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, table->query_id != thd->query_id) { table->query_id=thd->query_id; + DBUG_PRINT("info",("Using locked table")); goto reset; } } From 4ba94cc3f9f3d3916e235ce8b15a36b501fe61ce Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Oct 2004 17:28:40 +0300 Subject: [PATCH 19/19] After merge fixes --- libmysql/libmysql.c | 4 ++-- mysql-test/r/rpl_commit_after_flush.result | 6 +++--- mysql-test/t/rpl_commit_after_flush.test | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index fb405a7b868..9b97c52acec 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1570,8 +1570,8 @@ ulong mysql_hex_string(char *to, const char *from, ulong length) for (end= from + length; from < end; from++) { - *to++= _dig_vec[((unsigned char) *from) >> 4]; - *to++= _dig_vec[((unsigned char) *from) & 0x0F]; + *to++= _dig_vec_upper[((unsigned char) *from) >> 4]; + *to++= _dig_vec_upper[((unsigned char) *from) & 0x0F]; } *to= '\0'; return (ulong) (to-to0); diff --git a/mysql-test/r/rpl_commit_after_flush.result b/mysql-test/r/rpl_commit_after_flush.result index 8cdc7e986ab..d3aba779219 100644 --- a/mysql-test/r/rpl_commit_after_flush.result +++ b/mysql-test/r/rpl_commit_after_flush.result @@ -1,10 +1,10 @@ -slave stop; +stop slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -slave start; -create table t1 (a int) type=innodb; +start slave; +create table t1 (a int) engine=innodb; begin; insert into t1 values(1); flush tables with read lock; diff --git a/mysql-test/t/rpl_commit_after_flush.test b/mysql-test/t/rpl_commit_after_flush.test index edbbd1bfad6..62c89b3aae6 100644 --- a/mysql-test/t/rpl_commit_after_flush.test +++ b/mysql-test/t/rpl_commit_after_flush.test @@ -1,6 +1,6 @@ source include/master-slave.inc; source include/have_innodb.inc; -create table t1 (a int) type=innodb; +create table t1 (a int) engine=innodb; begin; insert into t1 values(1); flush tables with read lock;