diff --git a/include/my_sys.h b/include/my_sys.h index 6545077df72..f1b4841adb3 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -293,6 +293,14 @@ extern struct my_file_info #endif } my_file_info[MY_NFILE]; +typedef struct st_my_tmpdir +{ + char **list; + uint cur, max; +#ifdef THREAD + pthread_mutex_t mutex; +#endif +} MY_TMPDIR; typedef struct st_dynamic_array { @@ -582,6 +590,10 @@ extern void allow_break(void); #define allow_break() #endif +extern my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist); +extern char *my_tmpdir(MY_TMPDIR *tmpdir); +extern void free_tmpdir(MY_TMPDIR *tmpdir); + extern void my_remember_signal(int signal_number,sig_handler (*func)(int)); extern uint dirname_part(my_string to,const char *name); extern uint dirname_length(const char *name); diff --git a/include/myisam.h b/include/myisam.h index eac517eb28a..acaf8bb7618 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -329,7 +329,8 @@ typedef struct st_mi_check_param uint8 language; my_bool using_global_keycache, opt_lock_memory, opt_follow_links; my_bool retry_repair, force_sort, calc_checksum; - char temp_filename[FN_REFLEN],*isam_file_name,*tmpdir; + char temp_filename[FN_REFLEN],*isam_file_name; + MY_TMPDIR *tmpdir; int tmpfile_createflag; myf myf_rw; IO_CACHE read_cache; @@ -376,7 +377,7 @@ typedef struct st_mi_sort_param byte *rec_buff; void *wordlist, *wordptr; char *record; - char *tmpdir; + MY_TMPDIR *tmpdir; int (*key_cmp)(struct st_mi_sort_param *, const void *, const void *); int (*key_read)(struct st_mi_sort_param *,void *); int (*key_write)(struct st_mi_sort_param *, const void *); diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index 3e8377fc8c0..440c84dc64d 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -41,9 +41,10 @@ SET_STACK_SIZE(9000) /* Minimum stack size for program */ static uint decode_bits; static char **default_argv; static const char *load_default_groups[]= { "myisamchk", 0 }; -static const char *set_charset_name; +static const char *set_charset_name, *opt_tmpdir; static CHARSET_INFO *set_charset; static long opt_myisam_block_size; +static MY_TMPDIR myisamchk_tmpdir; static const char *type_names[]= { "?","char","binary", "short", "long", "float", @@ -257,7 +258,7 @@ static struct my_option my_long_options[] = 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"tmpdir", 't', "Path for temporary files.", - (gptr*) &check_param.tmpdir, + (gptr*) &opt_tmpdir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"update-state", 'U', "Mark tables as crashed if any errors were found.", @@ -338,7 +339,9 @@ static void usage(void) Change the value of a variable. Please note that\n\ this option is deprecated; you can set variables\n\ directly with '--variable-name=value'.\n\ - -t, --tmpdir=path Path for temporary files\n\ + -t, --tmpdir=path Path for temporary files. Multiple paths can be\n\ + specified, separated by colon (:), they will be used\n\ + in a round-robin fashion.\n\ -s, --silent Only print errors. One can use two -s to make\n\ myisamchk very silent\n\ -v, --verbose Print more information. This can be used with\n\ @@ -693,6 +696,11 @@ static void get_options(register int *argc,register char ***argv) exit(1); } + if (init_tmpdir(&myisamchk_tmpdir, opt_tmpdir)) + exit(1); + + check_param.tmpdir=&myisamchk_tmpdir; + if (set_charset_name) if (!(set_charset=get_charset_by_name(set_charset_name, MYF(MY_WME)))) exit(1); diff --git a/myisam/sort.c b/myisam/sort.c index 79d31147bfc..5819fb7b493 100644 --- a/myisam/sort.c +++ b/myisam/sort.c @@ -553,8 +553,8 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys, qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp, info); if (!my_b_inited(tempfile) && - open_cached_file(tempfile, info->tmpdir, "ST", DISK_BUFFER_SIZE, - info->sort_info->param->myf_rw)) + open_cached_file(tempfile, my_tmpdir(info->tmpdir), "ST", + DISK_BUFFER_SIZE, info->sort_info->param->myf_rw)) DBUG_RETURN(1); /* purecov: inspected */ buffpek->file_pos=my_b_tell(tempfile); @@ -576,8 +576,8 @@ static int NEAR_F write_key(MI_SORT_PARAM *info, uchar *key, DBUG_ENTER("write_key"); if (!my_b_inited(tempfile) && - open_cached_file(tempfile, info->tmpdir, "ST", DISK_BUFFER_SIZE, - info->sort_info->param->myf_rw)) + open_cached_file(tempfile, my_tmpdir(info->tmpdir), "ST", + DISK_BUFFER_SIZE, info->sort_info->param->myf_rw)) DBUG_RETURN(1); if (my_b_write(tempfile,(byte*)&key_length,sizeof(key_length)) || @@ -619,8 +619,8 @@ static int NEAR_F merge_many_buff(MI_SORT_PARAM *info, uint keys, if (*maxbuffer < MERGEBUFF2) DBUG_RETURN(0); /* purecov: inspected */ if (flush_io_cache(t_file) || - open_cached_file(&t_file2,info->tmpdir,"ST",DISK_BUFFER_SIZE, - info->sort_info->param->myf_rw)) + open_cached_file(&t_file2,my_tmpdir(info->tmpdir),"ST", + DISK_BUFFER_SIZE, info->sort_info->param->myf_rw)) DBUG_RETURN(1); /* purecov: inspected */ from_file= t_file ; to_file= &t_file2; diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 192b5e7fe37..46f419c561b 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -31,7 +31,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\ my_pread.c my_write.c \ mf_keycache.c \ mf_iocache.c mf_iocache2.c mf_cache.c mf_tempfile.c \ - my_lock.c mf_brkhant.c my_alarm.c \ + mf_tempdir.c my_lock.c mf_brkhant.c my_alarm.c \ my_malloc.c my_realloc.c my_once.c mulalloc.c \ my_alloc.c safemalloc.c my_new.cc \ my_fopen.c my_fstream.c \ diff --git a/mysys/mf_tempdir.c b/mysys/mf_tempdir.c new file mode 100644 index 00000000000..13b170ceee7 --- /dev/null +++ b/mysys/mf_tempdir.c @@ -0,0 +1,78 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "mysys_priv.h" +#include + +#define DELIM ':' +my_bool init_tmpdir(MY_TMPDIR *tmpdir, const char *pathlist) +{ + char *end, *copy; + char buff[FN_REFLEN]; + DYNAMIC_ARRAY t_arr; + pthread_mutex_init(&tmpdir->mutex, MY_MUTEX_INIT_FAST); + if (my_init_dynamic_array(&t_arr, sizeof(char*), 1, 5)) + return TRUE; + if (!pathlist || !pathlist[0]) + { + /* Get default temporary directory */ + pathlist=getenv("TMPDIR"); /* Use this if possible */ +#if defined( __WIN__) || defined(OS2) + if (!pathlist) + pathlist=getenv("TEMP"); + if (!pathlist) + pathlist=getenv("TMP"); +#endif + if (!pathlist || !pathlist[0]) + pathlist=(char*) P_tmpdir; + } + do + { + end=strcend(pathlist, DELIM); + convert_dirname(buff, pathlist, end); + if (!(copy=my_strdup(buff, MYF(MY_WME)))) + return TRUE; + if (insert_dynamic(&t_arr, ©)) + return TRUE; + pathlist=end+1; + } + while (*end); + freeze_size(&t_arr); + tmpdir->list=t_arr.buffer; + tmpdir->max=t_arr.elements-1; + tmpdir->cur=0; + return FALSE; +} + +char *my_tmpdir(MY_TMPDIR *tmpdir) +{ + char *dir; + pthread_mutex_lock(&tmpdir->mutex); + dir=tmpdir->list[tmpdir->cur]; + tmpdir->cur= (tmpdir->cur == tmpdir->max) ? 0 : tmpdir->cur+1; + pthread_mutex_unlock(&tmpdir->mutex); + return dir; +} + +void free_tmpdir(MY_TMPDIR *tmpdir) +{ + uint i; + for (i=0; i<=tmpdir->max; i++) + my_free(tmpdir->list[i], MYF(0)); + my_free(tmpdir->list, MYF(0)); + pthread_mutex_destroy(&tmpdir->mutex); +} + diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 4aae044148b..e02252e711f 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -559,7 +559,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) param.tmpfile_createflag = O_RDWR | O_TRUNC; param.using_global_keycache = 1; param.thd=thd; - param.tmpdir=mysql_tmpdir; + param.tmpdir=&mysql_tmpdir_list; param.out_flag=0; strmov(fixed_name,file->filename); @@ -718,7 +718,7 @@ bool ha_myisam::activate_all_index(THD *thd) T_CREATE_MISSING_KEYS); param.myf_rw&= ~MY_WAIT_IF_FULL; param.sort_buffer_length= thd->variables.myisam_sort_buff_size; - param.tmpdir=mysql_tmpdir; + param.tmpdir=&mysql_tmpdir_list; error=repair(thd,param,0) != HA_ADMIN_OK; thd->proc_info=save_proc_info; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b74a2da5f6d..d8281af6bd1 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -640,8 +640,9 @@ bool open_log(MYSQL_LOG *log, const char *hostname, extern time_t start_time; extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH], - mysql_real_data_home[], *charsets_list; -extern my_string mysql_tmpdir; + mysql_real_data_home[], *charsets_list, *opt_mysql_tmpdir; +#define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list)) +extern MY_TMPDIR mysql_tmpdir_list; extern const char *command_name[]; extern const char *first_keyword, *localhost, *delayed_user; extern const char **errmesg; /* Error messages */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a3a82d96b2e..1b4713706fb 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -395,7 +395,8 @@ const char *myisam_recover_options_str="OFF"; const char *sql_mode_str="OFF"; ulong rpl_recovery_rank=0; -my_string mysql_unix_port=NULL, opt_mysql_tmpdir=NULL, mysql_tmpdir=NULL; +my_string mysql_unix_port=NULL, opt_mysql_tmpdir=NULL; +MY_TMPDIR mysql_tmpdir_list; ulong my_bind_addr; /* the address we bind to */ char *my_bind_addr_str; DATE_FORMAT dayord; @@ -852,7 +853,7 @@ void clean_up(bool print_message) if (defaults_argv) free_defaults(defaults_argv); my_free(charsets_list, MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql_tmpdir,MYF(MY_ALLOW_ZERO_PTR)); + free_tmpdir(&mysql_tmpdir_list); my_free(slave_load_tmpdir,MYF(MY_ALLOW_ZERO_PTR)); x_free(opt_bin_logname); x_free(opt_relay_logname); @@ -1834,17 +1835,6 @@ int main(int argc, char **argv) load_defaults(MYSQL_CONFIG_NAME,load_default_groups,&argc,&argv); defaults_argv=argv; - /* Get default temporary directory */ - opt_mysql_tmpdir=getenv("TMPDIR"); /* Use this if possible */ -#if defined( __WIN__) || defined(OS2) - if (!opt_mysql_tmpdir) - opt_mysql_tmpdir=getenv("TEMP"); - if (!opt_mysql_tmpdir) - opt_mysql_tmpdir=getenv("TMP"); -#endif - if (!opt_mysql_tmpdir || !opt_mysql_tmpdir[0]) - opt_mysql_tmpdir=(char*) P_tmpdir; /* purecov: inspected */ - set_options(); get_options(argc,argv); if (opt_log || opt_update_log || opt_slow_log || opt_bin_log) @@ -3320,12 +3310,13 @@ struct my_option my_long_options[] = "Using this option will cause most temporary files created to use a small set of names, rather than a unique name for each new file.", (gptr*) &use_temp_pool, (gptr*) &use_temp_pool, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, - {"tmpdir", 't', "Path for temporary files", (gptr*) &opt_mysql_tmpdir, + {"tmpdir", 't', + "Path for temporary files. Several paths may be specified, separated by a colon (:), in this case they are used in a round-robin fashion.", + (gptr*) &opt_mysql_tmpdir, (gptr*) &opt_mysql_tmpdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"transaction-isolation", OPT_TX_ISOLATION, "Default transaction isolation level", 0, 0, 0, GET_NO_ARG, REQUIRED_ARG, 0, - 0, 0, 0, - 0, 0}, + 0, 0, 0, 0, 0}, {"external-locking", OPT_USE_LOCKING, "Use system (external) locking. With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running", (gptr*) &opt_external_locking, (gptr*) &opt_external_locking, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -4498,9 +4489,7 @@ static void fix_paths(void) charsets_dir=mysql_charsets_dir; } - char *end=convert_dirname(buff, opt_mysql_tmpdir, NullS); - if (!(mysql_tmpdir= my_memdup((byte*) buff,(uint) (end-buff)+1, - MYF(MY_FAE)))) + if (init_tmpdir(&mysql_tmpdir_list, opt_mysql_tmpdir)) exit(1); if (!slave_load_tmpdir) { diff --git a/sql/set_var.cc b/sql/set_var.cc index b221a3f98ff..72579664a3e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -541,7 +541,7 @@ struct show_var_st init_vars[]= { {"timezone", time_zone, SHOW_CHAR}, #endif {sys_tmp_table_size.name, (char*) &sys_tmp_table_size, SHOW_SYS}, - {"tmpdir", (char*) &mysql_tmpdir, SHOW_CHAR_PTR}, + {"tmpdir", (char*) &opt_mysql_tmpdir, SHOW_CHAR_PTR}, {"version", server_version, SHOW_CHAR}, {sys_net_wait_timeout.name, (char*) &sys_net_wait_timeout, SHOW_SYS}, {NullS, NullS, SHOW_LONG} diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 78774b376b1..46afddf0967 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2286,30 +2286,32 @@ fill_record(Field **ptr,List &values) static void mysql_rm_tmp_tables(void) { - uint idx; - char filePath[FN_REFLEN]; + uint i, idx; + char filePath[FN_REFLEN], *tmpdir; MY_DIR *dirp; FILEINFO *file; DBUG_ENTER("mysql_rm_tmp_tables"); + for (i=0; i<=mysql_tmpdir_list.max; i++) + { + tmpdir=mysql_tmpdir_list.list[i]; /* See if the directory exists */ - if (!(dirp = my_dir(mysql_tmpdir,MYF(MY_WME | MY_DONT_SORT)))) - DBUG_VOID_RETURN; /* purecov: inspected */ + if (!(dirp = my_dir(tmpdir,MYF(MY_WME | MY_DONT_SORT)))) + continue; - /* - ** Remove all SQLxxx tables from directory - */ + /* Remove all SQLxxx tables from directory */ for (idx=2 ; idx < (uint) dirp->number_off_files ; idx++) { file=dirp->dir_entry+idx; if (!bcmp(file->name,tmp_file_prefix,tmp_file_prefix_length)) { - sprintf(filePath,"%s%s",mysql_tmpdir,file->name); /* purecov: inspected */ - VOID(my_delete(filePath,MYF(MY_WME))); /* purecov: inspected */ + sprintf(filePath,"%s%s",tmpdir,file->name); + VOID(my_delete(filePath,MYF(MY_WME))); } } my_dirend(dirp); + } DBUG_VOID_RETURN; }