Skip to content

Commit da1787c

Browse files
Bug #19183565 CREATE DYNAMIC INNODB_TMPDIR VARIABLE TO CONTROL WHERE
INNODB WRITES TEMP FILES Problem: InnoDB creates temporary files for online ALTER statements in the tmpdir. In some cases, the tmpdir is too small, or for other reasons, not the best choice. Solution: Create a new dynamic session variable "innodb_tmpdir" that would determine where the temp files should create during alter operation. Behaviour of innodb_tmpdir : ---------------------------- 1) Default value is Empty String. 2) Valid inputs are String ,NULL and Empty String. 3) Directory Permission or existence checked while using innodb_tmpdir not during initialization of variable.     (in this case alter table when trying to create temp file). 4) If value is set to NULL or Empty String, then temporary file is creating in the location of mysql server variable(--tmpdir). 5) ONLINE ALTER TABLE operation will report error when innodb_tmpdir is set to invalid location. 6) Both innodb_tmpdir and --tmpdir values are set by the user. innodb_tmpdir will overrides the value of --tmpdir during ONLINE ALTER TABLE only. Approved by Marko [rb 6724]
1 parent c3cb2ea commit da1787c

22 files changed

Lines changed: 330 additions & 64 deletions

include/mysql/plugin.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,23 @@ int thd_allow_batch(MYSQL_THD thd);
578578
*/
579579
int mysql_tmpfile(const char *prefix);
580580

581+
/**
582+
Create a temporary file.
583+
584+
@details
585+
The temporary file is created in a location specified by the parameter
586+
path. if path is null, then it will be created on the location given
587+
by the mysql server configuration (--tmpdir option). The caller
588+
does not need to delete the file, it will be deleted automatically.
589+
590+
@param path location for creating temporary file
591+
@param prefix prefix for temporary file name
592+
@retval -1 error
593+
@retval >= 0 a file handle that can be passed to dup or my_close
594+
*/
595+
int mysql_tmpfile_path(const char *path, const char *prefix);
596+
597+
581598
/**
582599
Check the killed state of a connection
583600

include/mysql/plugin_audit.h.pp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@
235235
void thd_inc_row_count(void* thd);
236236
int thd_allow_batch(void* thd);
237237
int mysql_tmpfile(const char *prefix);
238+
int mysql_tmpfile_path(const char *path, const char *prefix);
238239
int thd_killed(const void* thd);
239240
void thd_binlog_pos(const void* thd,
240241
const char **file_var,

include/mysql/plugin_auth.h.pp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@
235235
void thd_inc_row_count(void* thd);
236236
int thd_allow_batch(void* thd);
237237
int mysql_tmpfile(const char *prefix);
238+
int mysql_tmpfile_path(const char *path, const char *prefix);
238239
int thd_killed(const void* thd);
239240
void thd_binlog_pos(const void* thd,
240241
const char **file_var,

include/mysql/plugin_ftparser.h.pp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@
188188
void thd_inc_row_count(void* thd);
189189
int thd_allow_batch(void* thd);
190190
int mysql_tmpfile(const char *prefix);
191+
int mysql_tmpfile_path(const char *path, const char *prefix);
191192
int thd_killed(const void* thd);
192193
void thd_binlog_pos(const void* thd,
193194
const char **file_var,
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#
2+
# Bug #19183565 CREATE DYNAMIC INNODB_TMPDIR VARIABLE TO CONTROL
3+
# WHERE INNODB WRITES TEMP FILES
4+
#
5+
# If innodb_tmpdir is NULL or "", temporary file will be created in
6+
# server configuration variable location(--tmpdir)
7+
create table t1(a int primary key)engine=innodb;
8+
show session variables like 'innodb_tmpdir';
9+
Variable_name Value
10+
innodb_tmpdir
11+
alter table t1 add column b int not null;
12+
set global innodb_tmpdir=NULL;
13+
# Connection con1
14+
show session variables like 'innodb_tmpdir';
15+
Variable_name Value
16+
innodb_tmpdir
17+
alter table t1 add key(b);
18+
drop table t1;
19+
# Alter table fails due to invalid location specified in innodb_tmpdir.
20+
create table t1(a int primary key)engine=innodb;
21+
set global innodb_tmpdir='wrong_value';
22+
show session variables like 'innodb_tmpdir';
23+
Variable_name Value
24+
innodb_tmpdir
25+
# Connection con2
26+
show session variables like 'innodb_tmpdir';
27+
Variable_name Value
28+
innodb_tmpdir wrong_value
29+
call mtr.add_suppression("\\[ERROR\\] InnoDB: Cannot create temporary merge file");
30+
alter table t1 add column b int not null;
31+
ERROR HY000: Can't create/write to file '' (Errcode: 2 - No such file or directory)
32+
set global innodb_tmpdir=NULL;
33+
drop table t1;
34+
# innodb_tmpdir with valid location.
35+
create table t1(a text, b text, fulltext(a,b))engine=innodb;
36+
insert into t1 values('test1', 'test2');
37+
insert into t1 values('text1', 'text2');
38+
set @tmpdir = @@global.tmpdir;
39+
set global innodb_tmpdir = @tmpdir;
40+
show session variables like 'innodb_tmpdir';
41+
Variable_name Value
42+
innodb_tmpdir
43+
# Connection con3
44+
show session variables like 'innodb_tmpdir';
45+
Variable_name Value
46+
innodb_tmpdir MYSQL_TMP_DIR/mysqld.1
47+
alter table t1 add fulltext(b);
48+
set global innodb_tmpdir=NULL;
49+
drop table t1;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--source include/have_innodb.inc
2+
--source include/count_sessions.inc
3+
4+
--echo #
5+
--echo # Bug #19183565 CREATE DYNAMIC INNODB_TMPDIR VARIABLE TO CONTROL
6+
--echo # WHERE INNODB WRITES TEMP FILES
7+
--echo #
8+
9+
--echo # If innodb_tmpdir is NULL or "", temporary file will be created in
10+
--echo # server configuration variable location(--tmpdir)
11+
12+
create table t1(a int primary key)engine=innodb;
13+
show session variables like 'innodb_tmpdir';
14+
alter table t1 add column b int not null;
15+
set global innodb_tmpdir=NULL;
16+
--echo # Connection con1
17+
connect (con1,localhost,root);
18+
show session variables like 'innodb_tmpdir';
19+
alter table t1 add key(b);
20+
connection default;
21+
disconnect con1;
22+
drop table t1;
23+
24+
--echo # Alter table fails due to invalid location specified in innodb_tmpdir.
25+
26+
create table t1(a int primary key)engine=innodb;
27+
set global innodb_tmpdir='wrong_value';
28+
show session variables like 'innodb_tmpdir';
29+
--echo # Connection con2
30+
connect (con2,localhost,root);
31+
show session variables like 'innodb_tmpdir';
32+
call mtr.add_suppression("\\[ERROR\\] InnoDB: Cannot create temporary merge file");
33+
--replace_regex /wrong_value\/[A-Za-z0-9_]*//
34+
--error 1
35+
alter table t1 add column b int not null;
36+
disconnect con2;
37+
connection default;
38+
set global innodb_tmpdir=NULL;
39+
drop table t1;
40+
41+
--echo # innodb_tmpdir with valid location.
42+
43+
create table t1(a text, b text, fulltext(a,b))engine=innodb;
44+
insert into t1 values('test1', 'test2');
45+
insert into t1 values('text1', 'text2');
46+
set @tmpdir = @@global.tmpdir;
47+
set global innodb_tmpdir = @tmpdir;
48+
show session variables like 'innodb_tmpdir';
49+
--echo # Connection con3
50+
connect (con3,localhost,root);
51+
--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
52+
show session variables like 'innodb_tmpdir';
53+
alter table t1 add fulltext(b);
54+
disconnect con3;
55+
connection default;
56+
set global innodb_tmpdir=NULL;
57+
drop table t1;
58+
--source include/wait_until_count_sessions.inc
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
SET @start_global_value = @@global.innodb_tmpdir;
2+
SELECT @start_global_value;
3+
@start_global_value
4+
5+
select @@session.innodb_tmpdir;
6+
@@session.innodb_tmpdir
7+
8+
show global variables like 'innodb_tmpdir';
9+
Variable_name Value
10+
innodb_tmpdir
11+
show session variables like 'innodb_tmpdir';
12+
Variable_name Value
13+
innodb_tmpdir
14+
select * from information_schema.global_variables where variable_name='innodb_tmpdir';
15+
VARIABLE_NAME VARIABLE_VALUE
16+
INNODB_TMPDIR
17+
select * from information_schema.session_variables where variable_name='innodb_tmpdir';
18+
VARIABLE_NAME VARIABLE_VALUE
19+
INNODB_TMPDIR
20+
set global innodb_tmpdir='value';
21+
set session innodb_tmpdir='value';
22+
set global innodb_tmpdir=1.1;
23+
ERROR 42000: Incorrect argument type to variable 'innodb_tmpdir'
24+
set global innodb_tmpdir=1e1;
25+
ERROR 42000: Incorrect argument type to variable 'innodb_tmpdir'
26+
SET @@global.innodb_tmpdir = @start_global_value;
27+
SELECT @@global.innodb_tmpdir;
28+
@@global.innodb_tmpdir
29+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--source include/have_innodb.inc
2+
3+
SET @start_global_value = @@global.innodb_tmpdir;
4+
SELECT @start_global_value;
5+
6+
#
7+
# exists as global and session
8+
#
9+
select @@session.innodb_tmpdir;
10+
11+
show global variables like 'innodb_tmpdir';
12+
show session variables like 'innodb_tmpdir';
13+
14+
select * from information_schema.global_variables where variable_name='innodb_tmpdir';
15+
select * from information_schema.session_variables where variable_name='innodb_tmpdir';
16+
#
17+
# Show that it is writable
18+
#
19+
20+
set global innodb_tmpdir='value';
21+
set session innodb_tmpdir='value';
22+
23+
#
24+
# incorrect types
25+
#
26+
--error ER_WRONG_TYPE_FOR_VAR
27+
set global innodb_tmpdir=1.1;
28+
--error ER_WRONG_TYPE_FOR_VAR
29+
set global innodb_tmpdir=1e1;
30+
31+
#
32+
# Cleanup
33+
#
34+
35+
SET @@global.innodb_tmpdir = @start_global_value;
36+
SELECT @@global.innodb_tmpdir;

sql/sql_class.cc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -527,8 +527,16 @@ ulong get_max_connections(void)
527527

528528
extern "C" int mysql_tmpfile(const char *prefix)
529529
{
530+
return mysql_tmpfile_path(mysql_tmpdir, prefix);
531+
}
532+
533+
int mysql_tmpfile_path(const char *path, const char *prefix)
534+
{
535+
DBUG_ASSERT(path != NULL);
536+
DBUG_ASSERT((strlen(path) + strlen(prefix)) <= FN_REFLEN);
537+
530538
char filename[FN_REFLEN];
531-
File fd = create_temp_file(filename, mysql_tmpdir, prefix,
539+
File fd = create_temp_file(filename, path, prefix,
532540
#ifdef __WIN__
533541
O_BINARY | O_TRUNC | O_SEQUENTIAL |
534542
O_SHORT_LIVED |
@@ -549,7 +557,6 @@ extern "C" int mysql_tmpfile(const char *prefix)
549557
return fd;
550558
}
551559

552-
553560
extern "C"
554561
int thd_in_lock_tables(const THD *thd)
555562
{

storage/innobase/dict/dict0dict.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -983,7 +983,7 @@ dict_init(void)
983983
&dict_operation_lock, SYNC_DICT_OPERATION);
984984

985985
if (!srv_read_only_mode) {
986-
dict_foreign_err_file = os_file_create_tmpfile();
986+
dict_foreign_err_file = os_file_create_tmpfile(NULL);
987987
ut_a(dict_foreign_err_file);
988988

989989
mutex_create(dict_foreign_err_mutex_key,

0 commit comments

Comments
 (0)