summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSatya B <satya.bn@sun.com>2009-04-07 18:42:51 +0530
committerSatya B <satya.bn@sun.com>2009-04-07 18:42:51 +0530
commit87bedb59ab38b9fd67e74980fc366e47d90ed727 (patch)
tree604e968f72d064e604ff2a554d8216fe737d14e8
parentb9bdc35d537a6db1a6f27b6921aa8e77d8c93700 (diff)
parentc045d1dcea0b2582b38ee5476b090097182c7144 (diff)
downloadmariadb-git-87bedb59ab38b9fd67e74980fc366e47d90ed727.tar.gz
merge to latest 5.0-bugteam
-rw-r--r--myisam/mi_packrec.c36
-rw-r--r--mysql-test/r/lock_multi.result55
-rw-r--r--mysql-test/r/myisampack.result22
-rw-r--r--mysql-test/t/lock_multi.test128
-rw-r--r--mysql-test/t/myisampack.test25
-rw-r--r--scripts/mysqld_multi.sh5
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h16
-rw-r--r--sql/sql_parse.cc26
-rw-r--r--sql/sql_yacc.yy7
10 files changed, 287 insertions, 34 deletions
diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c
index df9a4d18a6c..68911d7f129 100644
--- a/myisam/mi_packrec.c
+++ b/myisam/mi_packrec.c
@@ -208,10 +208,17 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys)
This segment will be reallocated after construction of the tables.
*/
length=(uint) (elements*2+trees*(1 << myisam_quick_table_bits));
+ /*
+ To keep some algorithms simpler, we accept that they access
+ bytes beyond the end of the input data. This can affect up to
+ one byte less than the "word size" size used in this file,
+ which is BITS_SAVED / 8. To avoid accessing non-allocated
+ data, we add (BITS_SAVED / 8) - 1 bytes to the buffer size.
+ */
if (!(share->decode_tables=(uint16*)
my_malloc((length + OFFSET_TABLE_SIZE) * sizeof(uint16) +
- (uint) (share->pack.header_length - sizeof(header)),
- MYF(MY_WME | MY_ZEROFILL))))
+ (uint) (share->pack.header_length - sizeof(header) +
+ (BITS_SAVED / 8) - 1), MYF(MY_WME | MY_ZEROFILL))))
goto err1;
tmp_buff=share->decode_tables+length;
disk_cache=(byte*) (tmp_buff+OFFSET_TABLE_SIZE);
@@ -1430,31 +1437,6 @@ static void fill_buffer(MI_BIT_BUFF *bit_buff)
bit_buff->current_byte=0;
return;
}
- else
- {
- uint len= 0;
- uint i= 0;
- /*
- Check if the remaining buffer/record to read is less than the word size.
- If so read byte by byte
-
- Note: if this branch becomes a bottleneck it can be removed, assuming
- that the second memory segment allocates 7 extra bytes (see
- _mi_read_pack_info()).
- */
- len= bit_buff->end - bit_buff->pos;
- if (len < (BITS_SAVED / 8))
- {
- bit_buff->current_byte= 0;
- for (i=0 ; i < len ; i++)
- {
- bit_buff->current_byte+= (((uint) ((uchar) bit_buff->pos[len - i - 1]))
- << (8 * i));
- }
- bit_buff->pos= bit_buff->end;
- return;
- }
- }
#if BITS_SAVED == 64
bit_buff->current_byte= ((((uint) ((uchar) bit_buff->pos[7]))) +
diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result
index d1b50a0080c..037b375fe0b 100644
--- a/mysql-test/r/lock_multi.result
+++ b/mysql-test/r/lock_multi.result
@@ -133,3 +133,58 @@ ALTER TABLE t1 ADD COLUMN a INT;
# 2.2.1. normal mode
# 2.2.2. PS mode
DROP TABLE t1;
+create table t1 (a int);
+create table t2 like t1;
+# con1
+lock tables t1 write;
+# con2
+flush tables with read lock;
+# con5
+# global read lock is taken
+# con3
+select * from t2 for update;
+# waiting for release of read lock
+# con4
+# would hang and later cause a deadlock
+flush tables t2;
+# clean up
+unlock tables;
+unlock tables;
+a
+drop table t1,t2;
+#
+# Lightweight version:
+# Ensure that the wait for a GRL is done before opening tables.
+#
+create table t1 (a int);
+create table t2 like t1;
+#
+# UPDATE
+#
+# default
+flush tables with read lock;
+# con1
+update t2 set a = 1;
+# default
+# statement is waiting for release of read lock
+# con2
+flush table t2;
+# default
+unlock tables;
+# con1
+#
+# LOCK TABLES .. WRITE
+#
+# default
+flush tables with read lock;
+# con1
+lock tables t2 write;
+# default
+# statement is waiting for release of read lock
+# con2
+flush table t2;
+# default
+unlock tables;
+# con1
+unlock tables;
+drop table t1,t2;
diff --git a/mysql-test/r/myisampack.result b/mysql-test/r/myisampack.result
index b4b200549a5..736a550e32b 100644
--- a/mysql-test/r/myisampack.result
+++ b/mysql-test/r/myisampack.result
@@ -38,3 +38,25 @@ SELECT COUNT(*) FROM t1;
COUNT(*)
1024
DROP TABLE t1;
+#
+# Bug #43973 - backup_myisam.test fails on 6.0-bugteam
+#
+CREATE DATABASE mysql_db1;
+CREATE TABLE mysql_db1.t1 (c1 VARCHAR(5), c2 int);
+CREATE INDEX i1 ON mysql_db1.t1 (c1, c2);
+INSERT INTO mysql_db1.t1 VALUES ('A',1);
+INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1;
+INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1;
+INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1;
+INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1;
+INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1;
+INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1;
+INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1;
+FLUSH TABLE mysql_db1.t1;
+# Compress the table using MYISAMPACK tool
+# Run MYISAMCHK tool on the compressed table
+SELECT COUNT(*) FROM mysql_db1.t1 WHERE c2 < 5;
+COUNT(*)
+128
+DROP TABLE mysql_db1.t1;
+DROP DATABASE mysql_db1;
diff --git a/mysql-test/t/lock_multi.test b/mysql-test/t/lock_multi.test
index 6c3c942b046..fa6af85f29c 100644
--- a/mysql-test/t/lock_multi.test
+++ b/mysql-test/t/lock_multi.test
@@ -683,6 +683,134 @@ DROP TABLE t1;
--disconnect locker
--disconnect writer
+#
+# Bug#43230: SELECT ... FOR UPDATE can hang with FLUSH TABLES WITH READ LOCK indefinitely
+#
+
+connect (con1,localhost,root,,);
+connect (con2,localhost,root,,);
+connect (con3,localhost,root,,);
+connect (con4,localhost,root,,);
+connect (con5,localhost,root,,);
+
+create table t1 (a int);
+create table t2 like t1;
+
+connection con1;
+--echo # con1
+lock tables t1 write;
+connection con2;
+--echo # con2
+send flush tables with read lock;
+connection con5;
+--echo # con5
+let $show_statement= SHOW PROCESSLIST;
+let $field= State;
+let $condition= = 'Flushing tables';
+--source include/wait_show_condition.inc
+--echo # global read lock is taken
+connection con3;
+--echo # con3
+send select * from t2 for update;
+connection con5;
+let $show_statement= SHOW PROCESSLIST;
+let $field= State;
+let $condition= = 'Waiting for release of readlock';
+--source include/wait_show_condition.inc
+--echo # waiting for release of read lock
+connection con4;
+--echo # con4
+--echo # would hang and later cause a deadlock
+flush tables t2;
+connection con1;
+--echo # clean up
+unlock tables;
+connection con2;
+--reap
+unlock tables;
+connection con3;
+--reap
+connection default;
+disconnect con5;
+disconnect con4;
+disconnect con3;
+disconnect con2;
+disconnect con1;
+
+drop table t1,t2;
+
+--echo #
+--echo # Lightweight version:
+--echo # Ensure that the wait for a GRL is done before opening tables.
+--echo #
+
+connect (con1,localhost,root,,);
+connect (con2,localhost,root,,);
+
+create table t1 (a int);
+create table t2 like t1;
+
+--echo #
+--echo # UPDATE
+--echo #
+
+connection default;
+--echo # default
+flush tables with read lock;
+connection con1;
+--echo # con1
+send update t2 set a = 1;
+connection default;
+--echo # default
+let $show_statement= SHOW PROCESSLIST;
+let $field= State;
+let $condition= = 'Waiting for release of readlock';
+--source include/wait_show_condition.inc
+--echo # statement is waiting for release of read lock
+connection con2;
+--echo # con2
+flush table t2;
+connection default;
+--echo # default
+unlock tables;
+connection con1;
+--echo # con1
+--reap
+
+--echo #
+--echo # LOCK TABLES .. WRITE
+--echo #
+
+connection default;
+--echo # default
+flush tables with read lock;
+connection con1;
+--echo # con1
+send lock tables t2 write;
+connection default;
+--echo # default
+let $show_statement= SHOW PROCESSLIST;
+let $field= State;
+let $condition= = 'Waiting for release of readlock';
+--source include/wait_show_condition.inc
+--echo # statement is waiting for release of read lock
+connection con2;
+--echo # con2
+flush table t2;
+connection default;
+--echo # default
+unlock tables;
+connection con1;
+--echo # con1
+--reap
+unlock tables;
+
+connection default;
+disconnect con2;
+disconnect con1;
+
+drop table t1,t2;
+
# End of 5.0 tests
# Wait till all disconnects are completed
diff --git a/mysql-test/t/myisampack.test b/mysql-test/t/myisampack.test
index ace7afce88a..ce27071bcf8 100644
--- a/mysql-test/t/myisampack.test
+++ b/mysql-test/t/myisampack.test
@@ -50,3 +50,28 @@ FLUSH TABLE t1;
--exec $MYISAMPACK $MYSQLTEST_VARDIR/master-data/test/t1
SELECT COUNT(*) FROM t1;
DROP TABLE t1;
+
+--echo #
+--echo # Bug #43973 - backup_myisam.test fails on 6.0-bugteam
+--echo #
+CREATE DATABASE mysql_db1;
+CREATE TABLE mysql_db1.t1 (c1 VARCHAR(5), c2 int);
+CREATE INDEX i1 ON mysql_db1.t1 (c1, c2);
+INSERT INTO mysql_db1.t1 VALUES ('A',1);
+INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1;
+INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1;
+INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1;
+INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1;
+INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1;
+INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1;
+INSERT INTO mysql_db1.t1 SELECT * FROM mysql_db1.t1;
+FLUSH TABLE mysql_db1.t1;
+#
+--echo # Compress the table using MYISAMPACK tool
+--exec $MYISAMPACK -s $MYSQLTEST_VARDIR/master-data/mysql_db1/t1
+--echo # Run MYISAMCHK tool on the compressed table
+--exec $MYISAMCHK -srq $MYSQLTEST_VARDIR/master-data/mysql_db1/t1
+SELECT COUNT(*) FROM mysql_db1.t1 WHERE c2 < 5;
+#
+DROP TABLE mysql_db1.t1;
+DROP DATABASE mysql_db1;
diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh
index 631e1e38cc7..3cb4665eb1c 100644
--- a/scripts/mysqld_multi.sh
+++ b/scripts/mysqld_multi.sh
@@ -293,12 +293,7 @@ sub start_mysqlds()
@groups = &find_groups($groupids);
for ($i = 0; defined($groups[$i]); $i++)
{
- # Defaults are made explicit parameters to server execution...
@options = defaults_for_group($groups[$i]);
- # ...so server MUST NOT try to read again from some config file, especially
- # as the "right" file may be unknown to the server if we are using
- # --defaults-file=... params in here.
- unshift(@options,"--no-defaults");
$mysqld_found= 1; # The default
$mysqld_found= 0 if (!length($mysqld));
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 4c53772bc25..da31106648a 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -204,6 +204,7 @@ void lex_start(THD *thd)
lex->nest_level=0 ;
lex->allow_sum_func= 0;
lex->in_sum_func= NULL;
+ lex->protect_against_global_read_lock= FALSE;
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 9f020f4adc5..3e762581e04 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1176,6 +1176,22 @@ typedef struct st_lex : public Query_tables_list
bool escape_used;
+ /*
+ Special case for SELECT .. FOR UPDATE and LOCK TABLES .. WRITE.
+
+ Protect from a impending GRL as otherwise the thread might deadlock
+ if it starts waiting for the GRL in mysql_lock_tables.
+
+ The protection is needed because there is a race between setting
+ the global read lock and waiting for all open tables to be closed.
+ The problem is a circular wait where a thread holding "old" open
+ tables will wait for the global read lock to be released while the
+ thread holding the global read lock will wait for all "old" open
+ tables to be closed -- the flush part of flush tables with read
+ lock.
+ */
+ bool protect_against_global_read_lock;
+
st_lex();
virtual ~st_lex()
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index ba887486aa1..02030ac2e19 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2800,6 +2800,10 @@ mysql_execute_command(THD *thd)
if (res)
goto error;
+ if (!thd->locked_tables && lex->protect_against_global_read_lock &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ goto error;
+
if (!(res= open_and_lock_tables(thd, all_tables)))
{
if (lex->describe)
@@ -3660,6 +3664,9 @@ end_with_restore_list:
DBUG_ASSERT(first_table == all_tables && first_table != 0);
if (update_precheck(thd, all_tables))
break;
+ if (!thd->locked_tables &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ goto error;
DBUG_ASSERT(select_lex->offset_limit == 0);
unit->set_limit(select_lex);
res= (up_result= mysql_update(thd, all_tables,
@@ -3686,6 +3693,15 @@ end_with_restore_list:
else
res= 0;
+ /*
+ Protection might have already been risen if its a fall through
+ from the SQLCOM_UPDATE case above.
+ */
+ if (!thd->locked_tables &&
+ lex->sql_command == SQLCOM_UPDATE_MULTI &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ goto error;
+
res= mysql_multi_update_prepare(thd);
#ifdef HAVE_REPLICATION
@@ -3853,7 +3869,8 @@ end_with_restore_list:
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
goto error;
}
-
+ if (!(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ goto error;
res= mysql_truncate(thd, first_table, 0);
break;
case SQLCOM_DELETE:
@@ -4027,6 +4044,10 @@ end_with_restore_list:
if (check_one_table_access(thd, privilege, all_tables))
goto error;
+ if (!thd->locked_tables &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ goto error;
+
res= mysql_load(thd, lex->exchange, first_table, lex->field_list,
lex->update_list, lex->value_list, lex->duplicates,
lex->ignore, (bool) lex->local_file);
@@ -4082,6 +4103,9 @@ end_with_restore_list:
goto error;
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0))
goto error;
+ if (lex->protect_against_global_read_lock &&
+ !(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
+ goto error;
thd->in_lock_tables=1;
thd->options|= OPTION_TABLE_LOCK;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 51fb5dbdfe4..b36c65854d7 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4522,6 +4522,7 @@ select_lock_type:
LEX *lex=Lex;
lex->current_select->set_lock_for_tables(TL_WRITE);
lex->safe_to_cache_query=0;
+ lex->protect_against_global_read_lock= TRUE;
}
| LOCK_SYM IN_SYM SHARE_SYM MODE_SYM
{
@@ -10058,8 +10059,12 @@ table_lock_list:
table_lock:
table_ident opt_table_alias lock_option
{
- if (!Select->add_table_to_list(YYTHD, $1, $2, 0, (thr_lock_type) $3))
+ thr_lock_type lock_type= (thr_lock_type) $3;
+ if (!Select->add_table_to_list(YYTHD, $1, $2, 0, lock_type))
MYSQL_YYABORT;
+ /* If table is to be write locked, protect from a impending GRL. */
+ if (lock_type >= TL_WRITE_ALLOW_WRITE)
+ Lex->protect_against_global_read_lock= TRUE;
}
;