Merge lp:~laurynas-biveinis/percona-server/bug951588-5.1 into lp:percona-server/5.1

Proposed by Laurynas Biveinis
Status: Merged
Approved by: Alexey Kopytov
Approved revision: no longer in the source branch.
Merged at revision: 452
Proposed branch: lp:~laurynas-biveinis/percona-server/bug951588-5.1
Merge into: lp:percona-server/5.1
Diff against target: 113 lines (+53/-4)
4 files modified
Percona-Server/mysql-test/suite/innodb_plugin/r/percona_bug_951588.result (+12/-0)
Percona-Server/mysql-test/suite/innodb_plugin/t/percona_bug_951588.test (+29/-0)
Percona-Server/sql/handler.cc (+2/-0)
Percona-Server/sql/sql_show.cc (+10/-4)
To merge this branch: bzr merge lp:~laurynas-biveinis/percona-server/bug951588-5.1
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Approve
Review via email: mp+109272@code.launchpad.net

This proposal supersedes a proposal from 2012-06-06.

Description of the change

Fix bug 951588 (Querying I_S.GLOBAL_TEMPORARY_TABLES or
TEMPORARY_TABLES crashes threads working with temp tables)

The issue is caused by fill_global_temporary_tables() in sql_show.cc
enumerating existing temp table handler objects that are possibly in
use by other threads. Then for each object the handler::info() method
is called in store_temporary_table_record() that proceeds to overwrite
current_thd, prebuilt->trx and possibly other fields of any operation
in progress for that temp table handler.

The fix is to not invoke handler::info() method on the existing handler
objects in order not to interfere with their state. Instead we use
handler::clone() method first to get an independent handler pointing
to the same table and use it to invoke the handler::info() method and
read the stats.

Also simplify the code to get rid of "handle" local variable that
aliases already existing "file". Fix the type of "engineType" to
const char* and remove unnecessary cast.

For testing add new debug sync point "start_ha_write_row" at the start
of handler::ha_write_row.

Add new test percona_bug_951988 that crashes without the fix and
passes with it.

Alexey's review comments have been addressed.

Jenkins: http://jenkins.percona.com/job/percona-server-5.1-param/326/
Issue #23438.

To post a comment you must log in.
Revision history for this message
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal

Laurynas,

This looks good from a functional perspective. But the code in store_temporary_table_record() is a bit messy, and the patch even adds a bit to that mess instead of cleaning it up.

There are 2 copies of the temp. table handler:

- 'handle' which was only used to get the storage engine type, and now, to clone file_handle_2
- 'file' which was used to get the actual stat values, and is now unused.

What about making 'file' a pointer to the cloned handler object. That would result in a bit cleaner code and less lines to touch?

review: Needs Fixing
Revision history for this message
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal

(and nothing prevents us from using the same 'file' pointer to the cloned handler object to get the storage engine name, and get rid of 'handle' completely).

Revision history for this message
Alexey Kopytov (akopytov) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'Percona-Server/mysql-test/suite/innodb_plugin/r/percona_bug_951588.result'
2--- Percona-Server/mysql-test/suite/innodb_plugin/r/percona_bug_951588.result 1970-01-01 00:00:00 +0000
3+++ Percona-Server/mysql-test/suite/innodb_plugin/r/percona_bug_951588.result 2012-06-08 03:54:21 +0000
4@@ -0,0 +1,12 @@
5+DROP TABLE IF EXISTS t1;
6+CREATE TEMPORARY TABLE t1 (a INT) ENGINE=InnoDB;
7+INSERT INTO t1 VALUES (1), (2), (3);
8+SET DEBUG_SYNC= 'start_ha_write_row SIGNAL write_in_progress WAIT_FOR i_s_completed';
9+ALTER TABLE t1 ADD COLUMN b VARCHAR(10);
10+SET DEBUG_SYNC= 'now WAIT_FOR write_in_progress';
11+SELECT COUNT(*) FROM INFORMATION_SCHEMA.GLOBAL_TEMPORARY_TABLES;
12+COUNT(*)
13+2
14+SET DEBUG_SYNC= 'now SIGNAL i_s_completed';
15+DROP TABLE t1;
16+SET DEBUG_SYNC='reset';
17
18=== added file 'Percona-Server/mysql-test/suite/innodb_plugin/t/percona_bug_951588.test'
19--- Percona-Server/mysql-test/suite/innodb_plugin/t/percona_bug_951588.test 1970-01-01 00:00:00 +0000
20+++ Percona-Server/mysql-test/suite/innodb_plugin/t/percona_bug_951588.test 2012-06-08 03:54:21 +0000
21@@ -0,0 +1,29 @@
22+# Test for bug 951588 (Querying I_S.TEMPORARY_TABLES crashes parallel threads working on temp tables)
23+
24+--source include/have_innodb_plugin.inc
25+--source include/have_debug_sync.inc
26+
27+--disable_warnings
28+DROP TABLE IF EXISTS t1;
29+--enable_warnings
30+
31+CREATE TEMPORARY TABLE t1 (a INT) ENGINE=InnoDB;
32+INSERT INTO t1 VALUES (1), (2), (3);
33+
34+SET DEBUG_SYNC= 'start_ha_write_row SIGNAL write_in_progress WAIT_FOR i_s_completed';
35+send ALTER TABLE t1 ADD COLUMN b VARCHAR(10);
36+
37+connect (conn2,localhost,root,,);
38+connection conn2;
39+
40+SET DEBUG_SYNC= 'now WAIT_FOR write_in_progress';
41+SELECT COUNT(*) FROM INFORMATION_SCHEMA.GLOBAL_TEMPORARY_TABLES;
42+SET DEBUG_SYNC= 'now SIGNAL i_s_completed';
43+
44+disconnect conn2;
45+connection default;
46+reap;
47+
48+DROP TABLE t1;
49+
50+SET DEBUG_SYNC='reset';
51
52=== modified file 'Percona-Server/sql/handler.cc'
53--- Percona-Server/sql/handler.cc 2012-05-09 04:14:12 +0000
54+++ Percona-Server/sql/handler.cc 2012-06-08 03:54:21 +0000
55@@ -27,6 +27,7 @@
56 #include "rpl_filter.h"
57 #include <myisampack.h>
58 #include <errno.h>
59+#include "debug_sync.h" // DEBUG_SYNC
60
61 #ifdef WITH_PARTITION_STORAGE_ENGINE
62 #include "ha_partition.h"
63@@ -4795,6 +4796,7 @@
64 int error;
65 Log_func *log_func= Write_rows_log_event::binlog_row_logging_function;
66 DBUG_ENTER("handler::ha_write_row");
67+ DEBUG_SYNC(ha_thd(), "start_ha_write_row");
68
69 mark_trx_read_write();
70
71
72=== modified file 'Percona-Server/sql/sql_show.cc'
73--- Percona-Server/sql/sql_show.cc 2012-05-09 04:14:12 +0000
74+++ Percona-Server/sql/sql_show.cc 2012-06-08 03:54:21 +0000
75@@ -3694,8 +3694,9 @@
76 DBUG_RETURN(schema_table_store_record(thd, table));
77
78 //engine
79- handler *handle= tmp_table->file;
80- char *engineType = (char *)(handle ? handle->table_type() : "UNKNOWN");
81+ handler *file= tmp_table->file;
82+ // Assume that invoking handler::table_type() on a shared handler is safe
83+ const char *engineType = (file) ? file->table_type() : "UNKNOWN";
84 table->field[3]->store(engineType, strlen(engineType), cs);
85
86 //name
87@@ -3706,12 +3707,15 @@
88 }
89
90 // file stats
91- handler *file= tmp_table->file;
92-
93 if (file) {
94
95 MYSQL_TIME time;
96
97+ /* We have only one handler object for a temp table globally and it might
98+ be in use by other thread. Do not trash it by invoking handler methods on
99+ it but rather clone it. */
100+ file = file->clone(tmp_table->s->normalized_path.str, thd->mem_root);
101+
102 /**
103 TODO: InnoDB stat(file) checks file on short names within data dictionary
104 rather than using full path, because of that, temp files created in
105@@ -3741,6 +3745,8 @@
106 table->field[10]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
107 table->field[10]->set_notnull();
108 }
109+
110+ file->close();
111 }
112
113 DBUG_RETURN(schema_table_store_record(thd, table));

Subscribers

People subscribed via source and target branches