diff options
Diffstat (limited to 'sql')
38 files changed, 1485 insertions, 1071 deletions
diff --git a/sql/field.h b/sql/field.h index 656dd9a592d..eb96304c1f3 100644 --- a/sql/field.h +++ b/sql/field.h @@ -73,6 +73,9 @@ public: virtual void set_default() { memcpy(ptr, ptr + table->rec_buff_length, pack_length()); + if (null_ptr) + *null_ptr= ((*null_ptr & (uchar) ~null_bit) | + null_ptr[table->rec_buff_length] & null_bit); } virtual bool binary() const { return 1; } virtual bool zero_pack() const { return 1; } @@ -93,12 +96,12 @@ public: virtual int key_cmp(const byte *str, uint length) { return cmp(ptr,(char*) str); } virtual uint decimals() const { return 0; } - virtual void sql_type(String &str) const =0; /* Caller beware: sql_type can change str.Ptr, so check ptr() to see if it changed if you are using your own buffer in str and restore it with set() if needed */ + virtual void sql_type(String &str) const =0; virtual uint size_of() const =0; /* For new field */ inline bool is_null(uint row_offset=0) { return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : table->null_row; } diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h index ae425421c70..198664d0c06 100644 --- a/sql/ha_berkeley.h +++ b/sql/ha_berkeley.h @@ -167,7 +167,6 @@ class ha_berkeley: public handler }; extern bool berkeley_skip, berkeley_shared_data; -extern SHOW_COMP_OPTION have_berkeley_db; extern u_int32_t berkeley_init_flags,berkeley_env_flags, berkeley_lock_type, berkeley_lock_types[]; extern ulong berkeley_cache_size, berkeley_max_lock, berkeley_log_buffer_size; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 11ebc108874..c82b4faf3f5 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -284,10 +284,9 @@ innobase_mysql_print_thd( thd = (THD*) input_thd; /* We can't use value of sprintf() as this is not portable */ - sprintf(buf, "MySQL thread id %lu, query id %lu", - thd->thread_id, thd->query_id); - buf=strend(buf); - + buf+= my_sprintf(buf, + (buf, "MySQL thread id %lu, query id %lu", + thd->thread_id, thd->query_id)); if (thd->host) { *buf++=' '; @@ -309,7 +308,7 @@ innobase_mysql_print_thd( if (thd->proc_info) { *buf++=' '; - buf=strnmov(buf, thd->procinfo, 50); + buf=strnmov(buf, thd->proc_info, 50); } if (thd->query) @@ -610,17 +609,20 @@ innobase_commit_low( /*================*/ trx_t* trx) /* in: transaction handle */ { - if (current_thd->slave_thread) { - - /* Update the replication position info inside InnoDB */ - - trx->mysql_master_log_file_name = glob_mi.log_file_name; - trx->mysql_master_log_pos = (ib_longlong) - (glob_mi.pos + glob_mi.event_len - + glob_mi.pending); - } - - trx_commit_for_mysql(trx); + if (current_thd->slave_thread) + { + /* Update the replication position info inside InnoDB */ +#ifdef NEED_TO_BE_FIXED + trx->mysql_relay_log_file_name= active_mi->rli.log_file_name; + trx->mysql_relay_log_pos= active_mi->rli.relay_log_pos; +#endif + trx->mysql_master_log_file_name= active_mi->rli.master_log_name; + trx->mysql_master_log_pos= ((ib_longlong) + (active_mi->rli.master_log_pos + + active_mi->rli.event_len + + active_mi->rli.pending)); + } + trx_commit_for_mysql(trx); } /********************************************************************* @@ -3176,8 +3178,9 @@ ha_innobase::update_table_comment( *pos++=' '; } - pos += sprintf(pos, "InnoDB free: %lu kB", - (ulong) innobase_get_free_space()); + pos += my_sprintf(pos, + (pos,"InnoDB free: %lu kB", + (ulong) innobase_get_free_space())); /* We assume 450 - length bytes of space to print info */ diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 7ea297cc362..a9a7c9997ad 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -169,7 +169,6 @@ class ha_innobase: public handler }; extern bool innodb_skip; -extern SHOW_COMP_OPTION have_innodb; extern uint innobase_init_flags, innobase_lock_type; extern ulong innobase_cache_size; extern char *innobase_home, *innobase_tmpdir, *innobase_logdir; diff --git a/sql/handler.cc b/sql/handler.cc index 4180d98245c..7aba6817eca 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -275,40 +275,11 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans) { bool operation_done= 0; bool transaction_commited= 0; + /* Update the binary log if we have cached some queries */ if (trans == &thd->transaction.all && mysql_bin_log.is_open() && my_b_tell(&thd->transaction.trans_log)) { - /* We write the command "COMMIT" as the last SQL command in the - binlog segment cached for this transaction */ - - int save_query_length = thd->query_length; - - thd->query_length = 6; /* length of 'COMMIT'; note that we may come - here because a DROP TABLE, for instance, - makes an implicit commit, and then - thd->query is not 'COMMIT'! */ - - Query_log_event qinfo(thd, "COMMIT", TRUE); - - /* When we come here, and the user wrapped the transaction into - BEGIN and COMMIT, then qinfo got above the field cache_stmt - erroneously set to 0. Let us set it to 1: */ - - qinfo.cache_stmt = 1; - - /* Write the 'COMMIT' entry to the cache */ - - if (mysql_bin_log.write(&qinfo)) { - my_error(ER_ERROR_DURING_COMMIT, MYF(0), 5000); - error=1; - } - - thd->query_length = save_query_length; - - /* Now we write the binlog segment cached for this transaction to - the real binlog */ - mysql_bin_log.write(thd, &thd->transaction.trans_log); reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE, (my_off_t) 0, 0, 1); diff --git a/sql/item_func.cc b/sql/item_func.cc index 45b9b473934..6cc50d57cf2 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1437,20 +1437,15 @@ void item_user_lock_release(ULL *ull) ull->locked=0; if (mysql_bin_log.is_open()) { - THD *thd = current_thd; - uint save_query_length; char buf[256]; String tmp(buf,sizeof(buf)); tmp.length(0); tmp.append("DO RELEASE_LOCK(\""); tmp.append(ull->key,ull->key_length); tmp.append("\")"); - save_query_length=thd->query_length; - thd->query_length=tmp.length(); - Query_log_event qev(thd,tmp.ptr()); + Query_log_event qev(current_thd,tmp.ptr(), tmp.length()); qev.error_code=0; // this query is always safe to run on slave mysql_bin_log.write(&qev); - thd->query_length=save_query_length; } if (--ull->count) pthread_cond_signal(&ull->cond); diff --git a/sql/item_func.h b/sql/item_func.h index 846d99a29d2..25a3ecb519f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -208,9 +208,14 @@ public: void fix_length_and_dec() {} Field *tmp_table_field(TABLE *t_arg) { - if (!t_arg) return result_field; - return (max_length > 11) ? (Field *)new Field_longlong(max_length,maybe_null,name, t_arg,unsigned_flag) : (Field *)new Field_long(max_length,maybe_null,name, t_arg,unsigned_flag); - } + if (!t_arg) + return result_field; + return ((max_length > 11) ? + (Field *)new Field_longlong(max_length, maybe_null, name, t_arg, + unsigned_flag) : + (Field *)new Field_long(max_length, maybe_null, name, t_arg, + unsigned_flag)); + } }; class Item_func_signed :public Item_int_func diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 482bf499757..835b1c7547d 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -37,12 +37,18 @@ public: void left_right_max_length(); Field *tmp_table_field(TABLE *t_arg) { - if (!t_arg) return result_field; - return (max_length > 255) ? (Field *)new Field_blob(max_length,maybe_null, name,t_arg, binary) : (Field *) new Field_string(max_length,maybe_null, name,t_arg, binary); - } + if (!t_arg) + return result_field; + return ((max_length > 255) ? + (Field *) new Field_blob(max_length, maybe_null, name, t_arg, + binary) : + (Field *) new Field_string(max_length, maybe_null, name, t_arg, + binary)); + } unsigned int size_of() { return sizeof(*this);} }; + class Item_func_md5 :public Item_str_func { String tmp_value; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 6b0d1850d8c..0fc8f1a3d0c 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -237,8 +237,7 @@ public: } Field *tmp_table_field(TABLE *t_arg) { - if (!t_arg) return result_field; - return new Field_date(maybe_null, name, t_arg); + return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg); } unsigned int size_of() { return sizeof(*this);} }; @@ -256,9 +255,9 @@ public: } Field *tmp_table_field(TABLE *t_arg) { - if (!t_arg) return result_field; - return new Field_datetime(maybe_null, name, t_arg); - } + return (!t_arg) ? result_field : new Field_datetime(maybe_null, name, + t_arg); + } unsigned int size_of() { return sizeof(*this);} }; @@ -284,8 +283,7 @@ public: } Field *tmp_table_field(TABLE *t_arg) { - if (!t_arg) return result_field; - return new Field_time(maybe_null, name, t_arg); + return (!t_arg) ? result_field : new Field_time(maybe_null, name, t_arg); } unsigned int size_of() { return sizeof(*this);} }; @@ -381,11 +379,11 @@ public: } Field *tmp_table_field(TABLE *t_arg) { - if (!t_arg) return result_field; - return new Field_time(maybe_null, name, t_arg); - } + return (!t_arg) ? result_field : new Field_time(maybe_null, name, t_arg); + } }; + enum interval_type { INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY, INTERVAL_HOUR, INTERVAL_MINUTE, INTERVAL_SECOND, INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, @@ -447,8 +445,7 @@ public: } Field *tmp_table_field(TABLE *t_arg) { - if (!t_arg) return result_field; - return new Field_date(maybe_null, name, t_arg); + return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg); } }; @@ -463,9 +460,8 @@ public: } Field *tmp_table_field(TABLE *t_arg) { - if (!t_arg) return result_field; - return new Field_time(maybe_null, name, t_arg); - } + return (!t_arg) ? result_field : new Field_time(maybe_null, name, t_arg); + } }; class Item_datetime_typecast :public Item_typecast @@ -479,7 +475,7 @@ public: } Field *tmp_table_field(TABLE *t_arg) { - if (!t_arg) return result_field; - return new Field_datetime(maybe_null, name, t_arg); - } + return (!t_arg) ? result_field : new Field_datetime(maybe_null, name, + t_arg); + } }; diff --git a/sql/lock.cc b/sql/lock.cc index 93c826f2528..056ed0fec8f 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -28,6 +28,7 @@ TODO: #include "mysql_priv.h" #include <hash.h> +#include <assert.h> extern HASH open_cache; @@ -427,6 +428,7 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list) char key[MAX_DBKEY_LENGTH]; uint key_length; DBUG_ENTER("lock_table_name"); + safe_mutex_assert_owner(&LOCK_open); key_length=(uint) (strmov(strmov(key,table_list->db)+1,table_list->name) -key)+ 1; @@ -486,6 +488,7 @@ bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list) { bool result=0; DBUG_ENTER("wait_for_locked_table_names"); + safe_mutex_assert_owner(&LOCK_open); while (locked_named_table(thd,table_list)) { diff --git a/sql/log.cc b/sql/log.cc index 6d9e8215105..19f2db8403b 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -80,8 +80,9 @@ static int find_uniq_filename(char *name) DBUG_RETURN(0); } + MYSQL_LOG::MYSQL_LOG() - :bytes_written(0), last_time(0), query_start(0), index_file(-1), name(0), + :bytes_written(0), last_time(0), query_start(0), name(0), file_id(1), open_count(1), log_type(LOG_CLOSED), write_error(0), inited(0), no_rotate(0), need_start_event(1) { @@ -91,8 +92,10 @@ MYSQL_LOG::MYSQL_LOG() */ index_file_name[0] = 0; bzero((char*) &log_file,sizeof(log_file)); + bzero((char*) &index_file, sizeof(index_file)); } + MYSQL_LOG::~MYSQL_LOG() { if (inited) @@ -103,15 +106,6 @@ MYSQL_LOG::~MYSQL_LOG() } } -void MYSQL_LOG::set_index_file_name(const char* index_file_name) -{ - if (index_file_name) - fn_format(this->index_file_name,index_file_name,mysql_data_home,".index", - 4); - else - this->index_file_name[0] = 0; -} - int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name) { @@ -132,12 +126,6 @@ int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name) return 0; } -bool MYSQL_LOG::open_index( int options) -{ - return (index_file < 0 && - (index_file = my_open(index_file_name, options | O_BINARY , - MYF(MY_WME))) < 0); -} void MYSQL_LOG::init(enum_log_type log_type_arg, enum cache_type io_cache_type_arg, @@ -148,32 +136,41 @@ void MYSQL_LOG::init(enum_log_type log_type_arg, no_auto_events = no_auto_events_arg; if (!inited) { - inited=1; + inited= 1; (void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW); (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW); (void) pthread_cond_init(&update_cond, 0); } } -void MYSQL_LOG::close_index() -{ - if (index_file >= 0) - { - my_close(index_file, MYF(0)); - index_file = -1; - } -} -void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, - const char *new_name, enum cache_type io_cache_type_arg, +/* + Open a (new) log file. + + DESCRIPTION + - If binary logs, also open the index file and register the new + file name in it + - When calling this when the file is in use, you must have a locks + on LOCK_log and LOCK_index. + + RETURN VALUES + 0 ok + 1 error +*/ + +bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, + const char *new_name, const char *index_file_name_arg, + enum cache_type io_cache_type_arg, bool no_auto_events_arg) { - MY_STAT tmp_stat; char buff[512]; - File file= -1; - bool do_magic; + File file= -1, index_file_nr= -1; int open_flags = O_CREAT | O_APPEND | O_BINARY; DBUG_ENTER("MYSQL_LOG::open"); + DBUG_PRINT("enter",("log_type: %d",(int) log_type)); + + last_time=query_start=0; + write_error=0; if (!inited && log_type_arg == LOG_BIN && *fn_ext(log_name)) no_rotate = 1; @@ -191,13 +188,7 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, else open_flags |= O_WRONLY; - if (log_type == LOG_BIN && !index_file_name[0]) - fn_format(index_file_name, name, mysql_data_home, ".index", 6); - db[0]=0; - do_magic = ((log_type == LOG_BIN) && !my_stat(log_file_name, - &tmp_stat, MYF(0))); - open_count++; if ((file=my_open(log_file_name,open_flags, MYF(MY_WME | ME_WAITTANG))) < 0 || @@ -205,7 +196,8 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, my_tell(file,MYF(MY_WME)), 0, MYF(MY_WME | MY_NABP))) goto err; - if (log_type == LOG_NORMAL) + switch (log_type) { + case LOG_NORMAL: { char *end; #ifdef __NT__ @@ -217,8 +209,9 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, if (my_b_write(&log_file, (byte*) buff,(uint) (end-buff)) || flush_io_cache(&log_file)) goto err; + break; } - else if (log_type == LOG_NEW) + case LOG_NEW: { time_t skr=time(NULL); struct tm tm_tmp; @@ -234,49 +227,98 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, if (my_b_write(&log_file, (byte*) buff,(uint) strlen(buff)) || flush_io_cache(&log_file)) goto err; + break; } - else if (log_type == LOG_BIN) + case LOG_BIN: { - bool error; - if (do_magic) + bool write_file_name_to_index_file=0; + + myf opt= MY_UNPACK_FILENAME; + if (!index_file_name_arg) { - if (my_b_write(&log_file, (byte*) BINLOG_MAGIC, BIN_LOG_HEADER_SIZE) || - open_index(O_APPEND | O_RDWR | O_CREAT)) + index_file_name_arg= name; // Use same basename for index file + opt= MY_UNPACK_FILENAME | MY_REPLACE_EXT; + } + + if (!my_b_filelength(&log_file)) + { + /* + The binary log file was empty (probably newly created) + This is the normal case and happens when the user doesn't specify + an extension for the binary log files. + In this case we write a standard header to it. + */ + if (my_b_write(&log_file, (byte*) BINLOG_MAGIC, BIN_LOG_HEADER_SIZE)) goto err; bytes_written += BIN_LOG_HEADER_SIZE; + write_file_name_to_index_file=1; } + if (!my_b_inited(&index_file)) + { + /* + First open of this class instance + Create an index file that will hold all file names uses for logging. + Add new entries to the end of it. + */ + fn_format(index_file_name, index_file_name_arg, mysql_data_home, + ".index", opt); + if ((index_file_nr= my_open(index_file_name, + O_RDWR | O_CREAT | O_BINARY , + MYF(MY_WME))) < 0 || + init_io_cache(&index_file, index_file_nr, + IO_SIZE, WRITE_CACHE, + my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)), + 0, MYF(MY_WME))) + goto err; + } + else + { + safe_mutex_assert_owner(&LOCK_index); + reinit_io_cache(&index_file, WRITE_CACHE, my_b_filelength(&index_file), + 0, 0); + } if (need_start_event && !no_auto_events) { + need_start_event=0; Start_log_event s; s.set_log_pos(this); s.write(&log_file); - need_start_event=0; } - flush_io_cache(&log_file); - pthread_mutex_lock(&LOCK_index); - error=(my_write(index_file, (byte*) log_file_name, strlen(log_file_name), - MYF(MY_NABP | MY_WME)) || - my_write(index_file, (byte*) "\n", 1, MYF(MY_NABP | MY_WME))); - pthread_mutex_unlock(&LOCK_index); - if (error) - { - close_index(); + if (flush_io_cache(&log_file)) goto err; + + if (write_file_name_to_index_file) + { + /* As this is a new log file, we write the file name to the index file */ + if (my_b_write(&index_file, (byte*) log_file_name, + strlen(log_file_name)) || + my_b_write(&index_file, (byte*) "\n", 1) || + flush_io_cache(&index_file)) + goto err; } + break; } - DBUG_VOID_RETURN; + case LOG_CLOSED: // Impossible + DBUG_ASSERT(1); + break; + } + DBUG_RETURN(0); err: - sql_print_error("Could not use %s for logging (error %d)", log_name,errno); + sql_print_error("Could not use %s for logging (error %d)", log_name, errno); if (file >= 0) my_close(file,MYF(0)); + if (index_file_nr >= 0) + my_close(index_file_nr,MYF(0)); end_io_cache(&log_file); - x_free(name); name=0; + end_io_cache(&index_file); + safeFree(name); log_type=LOG_CLOSED; - DBUG_VOID_RETURN; + DBUG_RETURN(1); } + int MYSQL_LOG::get_current_log(LOG_INFO* linfo) { pthread_mutex_lock(&LOCK_log); @@ -286,107 +328,231 @@ int MYSQL_LOG::get_current_log(LOG_INFO* linfo) return 0; } -// if log_name is "" we stop at the first entry -int MYSQL_LOG::find_first_log(LOG_INFO* linfo, const char* log_name, - bool need_mutex) +/* + Move all data up in a file in an filename index file + + SYNOPSIS + copy_up_file_and_fill() + index_file File to move + offset Move everything from here to beginning + + NOTE + File will be truncated to be 'offset' shorter or filled up with + newlines + + IMPLEMENTATION + We do the copy outside of the IO_CACHE as the cache buffers would just + make things slower and more complicated. + In most cases the copy loop should only do one read. + + RETURN VALUES + 0 ok +*/ + +static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset) +{ + int bytes_read; + my_off_t init_offset= offset; + File file= index_file->file; + byte io_buf[IO_SIZE*2]; + DBUG_ENTER("copy_up_file_and_fill"); + + for (;; offset+= bytes_read) + { + (void) my_seek(file, offset, MY_SEEK_SET, MYF(0)); + if ((bytes_read= (int) my_read(file, io_buf, sizeof(io_buf), MYF(MY_WME))) + < 0) + goto err; + if (!bytes_read) + break; // end of file + (void) my_seek(file, offset-init_offset, MY_SEEK_SET, MYF(0)); + if (my_write(file, (byte*) io_buf, bytes_read, MYF(MY_WME | MY_NABP))) + goto err; + } + /* The following will either truncate the file or fill the end with \n' */ + if (my_chsize(file, offset - init_offset, '\n', MYF(MY_WME))) + goto err; + + /* Reset data in old index cache */ + reinit_io_cache(index_file, READ_CACHE, (my_off_t) 0, 0, 1); + DBUG_RETURN(0); + +err: + DBUG_RETURN(1); +} + + +/* + Find the position in the log-index-file for the given log name + + SYNOPSIS + find_log_pos() + linfo Store here the found log file name and position to + the NEXT log file name in the index file. + log_name Filename to find in the index file. + Is a null pointer if we want to read the first entry + need_mutex Set this to 1 if the parent doesn't already have a + lock on LOCK_index + + NOTE + On systems without the truncate function the file will end with one ore + more empty lines + + RETURN VALUES + 0 ok + LOG_INFO_EOF End of log-index-file found + LOG_INFO_IO Got IO error while reading file +*/ + +int MYSQL_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name, + bool need_lock) { - if (index_file < 0) - return LOG_INFO_INVALID; - int error = 0; - char* fname = linfo->log_file_name; - uint log_name_len = (uint) strlen(log_name); - IO_CACHE io_cache; + int error= 0; + char *fname= linfo->log_file_name; + uint log_name_len= log_name ? (uint) strlen(log_name) : 0; + DBUG_ENTER("find_log_pos"); + DBUG_PRINT("enter",("log_name: %s", log_name ? log_name : "NULL")); /* Mutex needed because we need to make sure the file pointer does not move from under our feet */ - if (need_mutex) + if (need_lock) pthread_mutex_lock(&LOCK_index); - if (init_io_cache(&io_cache, index_file, IO_SIZE, READ_CACHE, (my_off_t) 0, - 0, MYF(MY_WME))) - { - error = LOG_INFO_SEEK; - goto err; - } + safe_mutex_assert_owner(&LOCK_index); + + /* As the file is flushed, we can't get an error here */ + (void) reinit_io_cache(&index_file, READ_CACHE, (my_off_t) 0, 0, 0); + for (;;) { uint length; - if (!(length=my_b_gets(&io_cache, fname, FN_REFLEN-1))) + my_off_t offset= my_b_tell(&index_file); + /* If we get 0 or 1 characters, this is the end of the file */ + + if ((length= my_b_gets(&index_file, fname, FN_REFLEN)) <= 1) { - error = !io_cache.error ? LOG_INFO_EOF : LOG_INFO_IO; - goto err; + /* Did not find the given entry; Return not found or error */ + error= !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO; + break; } - // if the log entry matches, empty string matching anything - if (!log_name_len || + // if the log entry matches, null string matching anything + if (!log_name || (log_name_len == length-1 && fname[log_name_len] == '\n' && !memcmp(fname, log_name, log_name_len))) { + DBUG_PRINT("info",("Found log file entry")); fname[length-1]=0; // remove last \n - linfo->index_file_offset = my_b_tell(&io_cache); + linfo->index_file_start_offset= offset; + linfo->index_file_offset = my_b_tell(&index_file); break; } } - error = 0; err: - if (need_mutex) + if (need_lock) pthread_mutex_unlock(&LOCK_index); - end_io_cache(&io_cache); - return error; - + DBUG_RETURN(error); } +/* + Find the position in the log-index-file for the given log name + + SYNOPSIS + find_next_log() + linfo Store here the next log file name and position to + the file name after that. + need_lock Set this to 1 if the parent doesn't already have a + lock on LOCK_index + + NOTE + - Before calling this function, one has to call find_log_pos() + to set up 'linfo' + - Mutex needed because we need to make sure the file pointer does not move + from under our feet + + RETURN VALUES + 0 ok + LOG_INFO_EOF End of log-index-file found + LOG_INFO_SEEK Could not allocate IO cache + LOG_INFO_IO Got IO error while reading file +*/ + int MYSQL_LOG::find_next_log(LOG_INFO* linfo, bool need_lock) { - /* - Mutex needed because we need to make sure the file pointer does not move - from under our feet - */ - if (index_file < 0) - return LOG_INFO_INVALID; - int error = 0; - char* fname = linfo->log_file_name; - IO_CACHE io_cache; + int error= 0; uint length; + char *fname= linfo->log_file_name; + if (need_lock) pthread_mutex_lock(&LOCK_index); - if (init_io_cache(&io_cache, index_file, IO_SIZE, - READ_CACHE, (my_off_t) linfo->index_file_offset, 0, - MYF(MY_WME))) - { - error = LOG_INFO_SEEK; - goto err; - } - if (!(length=my_b_gets(&io_cache, fname, FN_REFLEN))) + safe_mutex_assert_owner(&LOCK_index); + + /* As the file is flushed, we can't get an error here */ + (void) reinit_io_cache(&index_file, READ_CACHE, linfo->index_file_offset, 0, + 0); + + linfo->index_file_start_offset= linfo->index_file_offset; + if ((length=my_b_gets(&index_file, fname, FN_REFLEN)) <= 1) { - error = !io_cache.error ? LOG_INFO_EOF : LOG_INFO_IO; + error = !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO; goto err; } fname[length-1]=0; // kill /n - linfo->index_file_offset = my_b_tell(&io_cache); - error = 0; + linfo->index_file_offset = my_b_tell(&index_file); err: if (need_lock) pthread_mutex_unlock(&LOCK_index); - end_io_cache(&io_cache); return error; } -int MYSQL_LOG::reset_logs(THD* thd) +/* + Delete all logs refered to in the index file + Start writing to a new log file. The new index file will only contain + this file. + + SYNOPSIS + reset_logs() + thd Thread + + NOTE + If not called from slave thread, write start event to new log + + + RETURN VALUES + 0 ok + 1 error +*/ + +bool MYSQL_LOG::reset_logs(THD* thd) { LOG_INFO linfo; - int error=0; + bool error=0; const char* save_name; enum_log_type save_log_type; + DBUG_ENTER("reset_logs"); + /* + We need to get both locks to be sure that no one is trying to + write to the index log file. + */ pthread_mutex_lock(&LOCK_log); - if (find_first_log(&linfo,"")) + pthread_mutex_lock(&LOCK_index); + + /* Save variables so that we can reopen the log */ + save_name=name; + name=0; // Protect against free + save_log_type=log_type; + close(0); // Don't close the index file + + /* First delete all old log files */ + + if (find_log_pos(&linfo, NullS, 0)) { error=1; goto err; @@ -395,27 +561,58 @@ int MYSQL_LOG::reset_logs(THD* thd) for (;;) { my_delete(linfo.log_file_name, MYF(MY_WME)); - if (find_next_log(&linfo)) + if (find_next_log(&linfo, 0)) break; } - save_name=name; - name=0; - save_log_type=log_type; - close(1); - my_delete(index_file_name, MYF(MY_WME)); - if (thd && !thd->slave_thread) + + /* Start logging with a new file */ + close(1); // Close index file + my_delete(index_file_name, MYF(MY_WME)); // Reset (open will update) + if (!thd->slave_thread) need_start_event=1; - open(save_name,save_log_type,0,io_cache_type,no_auto_events); - my_free((gptr)save_name,MYF(0)); + open(save_name, save_log_type, 0, index_file_name, + io_cache_type, no_auto_events); + my_free((gptr) save_name, MYF(0)); err: + pthread_mutex_unlock(&LOCK_index); pthread_mutex_unlock(&LOCK_log); - return error; + DBUG_RETURN(error); } +/* + Delete the current log file, remove it from index file and start on next + + SYNOPSIS + purge_first_log() + rli Relay log information + + NOTE + - This is only called from the slave-execute thread when it has read + all commands from a log and want to switch to a new log. + - When this happens, we should never be in an active transaction as + a transaction is always written as a single block to the binary log. + + IMPLEMENTATION + - Protects index file with LOCK_index + - Delete first log file, + - Copy all file names after this one to the front of the index file + - If the OS has truncate, truncate the file, else fill it with \n' + - Read the first file name from the index file and store in rli->linfo + + RETURN VALUES + 0 ok + 1 error +*/ + int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli) { + File file; + bool error= 1; + my_off_t offset, init_offset; + DBUG_ENTER("purge_first_log"); + /* Test pre-conditions. @@ -423,330 +620,248 @@ int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli) stored it in rli->relay_log_name */ DBUG_ASSERT(is_open()); - DBUG_ASSERT(index_file >= 0); DBUG_ASSERT(rli->slave_running == 1); DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->relay_log_name)); DBUG_ASSERT(rli->linfo.index_file_offset == strlen(rli->relay_log_name) + 1); - int tmp_fd; - char* fname, *io_buf; - int error = 0; - - if (!(fname= (char*) my_malloc(IO_SIZE+FN_REFLEN, MYF(MY_WME)))) - return 1; + /* We have already processed the relay log, so it's safe to delete it */ + my_delete(rli->relay_log_name, MYF(0)); pthread_mutex_lock(&LOCK_index); - my_seek(index_file,rli->linfo.index_file_offset, - MY_SEEK_SET, MYF(MY_WME)); - io_buf = fname + FN_REFLEN; - strxmov(fname,rli->relay_log_name,".tmp",NullS); - - if ((tmp_fd = my_open(fname,O_CREAT|O_BINARY|O_RDWR, MYF(MY_WME))) < 0) + if (copy_up_file_and_fill(&index_file, rli->linfo.index_file_offset)) { - error = 1; + error= LOG_INFO_IO; goto err; } - for (;;) - { - int bytes_read; - bytes_read = my_read(index_file, (byte*) io_buf, IO_SIZE, MYF(0)); - if (bytes_read < 0) // error - { - error=1; - goto err; - } - if (!bytes_read) - break; // end of file - // otherwise, we've read something and need to write it out - if (my_write(tmp_fd, (byte*) io_buf, bytes_read, MYF(MY_WME|MY_NABP))) - { - error=1; - goto err; - } - } -err: - if (tmp_fd) - my_close(tmp_fd, MYF(MY_WME)); - if (error) - my_delete(fname, MYF(0)); // do not report error if the file is not there - else - { - MY_STAT s; - my_close(index_file, MYF(MY_WME)); - if (!my_stat(rli->relay_log_name,&s,MYF(0))) - { - sql_print_error("The first log %s failed to stat during purge", - rli->relay_log_name); - error=1; - goto err; - } - if (my_rename(fname,index_file_name,MYF(MY_WME)) || - (index_file=my_open(index_file_name,O_BINARY|O_RDWR|O_APPEND, - MYF(MY_WME)))<0 || - my_delete(rli->relay_log_name, MYF(MY_WME))) - error=1; - - pthread_mutex_lock(&rli->log_space_lock); - rli->log_space_total -= s.st_size; - pthread_mutex_unlock(&rli->log_space_lock); - /* - Ok to broadcast after the critical region as there is no risk of - the mutex being destroyed by this thread later - this helps save - context switches - */ - pthread_cond_broadcast(&rli->log_space_cond); - - if ((error=find_first_log(&rli->linfo,"",0/*no mutex*/))) - { - char buff[22]; - sql_print_error("next log error=%d,offset=%s,log=%s",error, - llstr(rli->linfo.index_file_offset,buff), - rli->linfo.log_file_name); - goto err2; - } - rli->relay_log_pos = BIN_LOG_HEADER_SIZE; - strmake(rli->relay_log_name,rli->linfo.log_file_name, - sizeof(rli->relay_log_name)-1); - flush_relay_log_info(rli); - } /* - No need to free io_buf because we allocated both fname and io_buf in - one malloc() + Update the space counter used by all relay logs + Ok to broadcast after the critical region as there is no risk of + the mutex being destroyed by this thread later - this helps save + context switches */ + pthread_mutex_lock(&rli->log_space_lock); + rli->log_space_total -= rli->relay_log_pos; + pthread_mutex_unlock(&rli->log_space_lock); + pthread_cond_broadcast(&rli->log_space_cond); + + /* + Read the next log file name from the index file and pass it back to + the caller + */ + if ((error=find_log_pos(&rli->linfo, NullS, 0 /*no mutex*/))) + { + char buff[22]; + sql_print_error("next log error: %d offset: %s log: %s", + error, + llstr(rli->linfo.index_file_offset,buff), + rli->linfo.log_file_name); + goto err; + } + rli->relay_log_pos = BIN_LOG_HEADER_SIZE; + strmake(rli->relay_log_name,rli->linfo.log_file_name, + sizeof(rli->relay_log_name)-1); + + /* Store where we are in the new file for the execution thread */ + flush_relay_log_info(rli); -err2: +err: pthread_mutex_unlock(&LOCK_index); - my_free(fname, MYF(MY_WME)); - return error; + DBUG_RETURN(error); } +/* + Remove all logs before the given log from disk and from the index file. + + SYNOPSIS + purge_logs() + thd Thread pointer + to_log Delete all log file name before this file. This file is not + deleted + + NOTES + If any of the logs before the deleted one is in use, + only purge logs up to this one. + + RETURN VALUES + 0 ok + LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated + LOG_INFO_EOF to_log not found +*/ + int MYSQL_LOG::purge_logs(THD* thd, const char* to_log) { int error; - char fname[FN_REFLEN]; - char *p; - uint fname_len, i; - bool logs_to_purge_inited = 0, logs_to_keep_inited = 0, found_log = 0; - DYNAMIC_ARRAY logs_to_purge, logs_to_keep; - my_off_t purge_offset ; - LINT_INIT(purge_offset); - IO_CACHE io_cache; - - if (index_file < 0) - return LOG_INFO_INVALID; + LOG_INFO log_info; + DBUG_ENTER("purge_logs"); + if (no_rotate) - return LOG_INFO_PURGE_NO_ROTATE; + DBUG_RETURN(LOG_INFO_PURGE_NO_ROTATE); + pthread_mutex_lock(&LOCK_index); - - if (init_io_cache(&io_cache,index_file, IO_SIZE*2, READ_CACHE, (my_off_t) 0, - 0, MYF(MY_WME))) - { - error = LOG_INFO_MEM; - goto err; - } - if (my_init_dynamic_array(&logs_to_purge, sizeof(char*), 1024, 1024)) - { - error = LOG_INFO_MEM; - goto err; - } - logs_to_purge_inited = 1; - - if (my_init_dynamic_array(&logs_to_keep, sizeof(char*), 1024, 1024)) - { - error = LOG_INFO_MEM; + if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/))) goto err; - } - logs_to_keep_inited = 1; - - for (;;) - { - my_off_t init_purge_offset= my_b_tell(&io_cache); - if (!(fname_len=my_b_gets(&io_cache, fname, FN_REFLEN))) - { - if (!io_cache.error) - break; - error = LOG_INFO_IO; - goto err; - } - fname[--fname_len]=0; // kill \n - if (!memcmp(fname, to_log, fname_len + 1 )) - { - found_log = 1; - purge_offset = init_purge_offset; - } - - // if one of the logs before the target is in use - if (!found_log && log_in_use(fname)) - { - error = LOG_INFO_IN_USE; - goto err; - } - - if (!(p = sql_memdup(fname, fname_len+1)) || - insert_dynamic(found_log ? &logs_to_keep : &logs_to_purge, - (gptr) &p)) - { - error = LOG_INFO_MEM; - goto err; - } - } - - end_io_cache(&io_cache); - if (!found_log) - { - error = LOG_INFO_EOF; + /* + File name exists in index file; Delete until we find this file + or a file that is used. + */ + if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/))) goto err; - } - - for (i = 0; i < logs_to_purge.elements; i++) + while (strcmp(to_log,log_info.log_file_name) && + !log_in_use(log_info.log_file_name)) { - char* l; - get_dynamic(&logs_to_purge, (gptr)&l, i); - if (my_delete(l, MYF(MY_WME))) - sql_print_error("Error deleting %s during purge", l); + /* It's not fatal even if we can't delete a log file */ + my_delete(log_info.log_file_name, MYF(0)); + if (find_next_log(&log_info, 0)) + break; } - + /* If we get killed -9 here, the sysadmin would have to edit the log index file after restart - otherwise, this should be safe */ -#ifdef HAVE_FTRUNCATE - if (ftruncate(index_file,0)) - { - sql_print_error( -"Could not truncate the binlog index file during log purge for write"); - error = LOG_INFO_FATAL; - goto err; - } - my_seek(index_file, 0, MY_SEEK_CUR,MYF(MY_WME)); -#else - my_close(index_file, MYF(MY_WME)); - my_delete(index_file_name, MYF(MY_WME)); - if ((index_file = my_open(index_file_name, - O_CREAT | O_BINARY | O_RDWR | O_APPEND, - MYF(MY_WME)))<0) + + if (copy_up_file_and_fill(&index_file, log_info.index_file_start_offset)) { - sql_print_error( -"Could not re-open the binlog index file during log purge for write"); - error = LOG_INFO_FATAL; + error= LOG_INFO_IO; goto err; } -#endif - - for (i = 0; i < logs_to_keep.elements; i++) - { - char* l; - get_dynamic(&logs_to_keep, (gptr)&l, i); - if (my_write(index_file, (byte*) l, strlen(l), MYF(MY_WME|MY_NABP)) || - my_write(index_file, (byte*) "\n", 1, MYF(MY_WME|MY_NABP))) - { - error = LOG_INFO_FATAL; - goto err; - } - } - // now update offsets - adjust_linfo_offsets(purge_offset); - error = 0; + // now update offsets in index file for running threads + adjust_linfo_offsets(log_info.index_file_start_offset); err: pthread_mutex_unlock(&LOCK_index); - if (logs_to_purge_inited) - delete_dynamic(&logs_to_purge); - if (logs_to_keep_inited) - delete_dynamic(&logs_to_keep); - end_io_cache(&io_cache); - return error; + DBUG_RETURN(error); } -// we assume that buf has at least FN_REFLEN bytes alloced + +/* + Create a new log file name + + SYNOPSIS + make_log_name() + buf buf of at least FN_REFLEN where new name is stored + + NOTE + If file name will be longer then FN_REFLEN it will be truncated +*/ + void MYSQL_LOG::make_log_name(char* buf, const char* log_ident) { - buf[0] = 0; // In case of error - if (inited) + if (inited) // QQ When is this not true ? { - int dir_len = dirname_length(log_file_name); - int ident_len = (uint) strlen(log_ident); - if (dir_len + ident_len + 1 > FN_REFLEN) - return; // protection agains malicious buffer overflow - - memcpy(buf, log_file_name, dir_len); - // copy filename + end null - memcpy(buf + dir_len, log_ident, ident_len + 1); + uint dir_len = dirname_length(log_file_name); + if (dir_len > FN_REFLEN) + dir_len=FN_REFLEN-1; + strnmov(buf, log_file_name, dir_len); + strmake(buf+dir_len, log_ident, FN_REFLEN - dir_len); } } -bool MYSQL_LOG::is_active(const char* log_file_name) + +/* + Check if we are writing/reading to the given log file +*/ + +bool MYSQL_LOG::is_active(const char *log_file_name_arg) { - return inited && !strcmp(log_file_name, this->log_file_name); + return inited && !strcmp(log_file_name, log_file_name_arg); } -void MYSQL_LOG::new_file(bool inside_mutex) + +/* + Start writing to a new log file or reopen the old file + + SYNOPSIS + new_file() + need_lock Set to 1 (default) if caller has not locked + LOCK_log and LOCK_index + + NOTE + The new file name is stored last in the index file +*/ + +void MYSQL_LOG::new_file(bool need_lock) { - if (is_open()) + char new_name[FN_REFLEN], *new_name_ptr, *old_name; + enum_log_type save_log_type; + + if (!is_open()) + return; // Should never happen + + if (need_lock) { - char new_name[FN_REFLEN], *old_name=name; - if (!inside_mutex) - VOID(pthread_mutex_lock(&LOCK_log)); + pthread_mutex_lock(&LOCK_log); + pthread_mutex_lock(&LOCK_index); + } + safe_mutex_assert_owner(&LOCK_log); + safe_mutex_assert_owner(&LOCK_index); + + new_name_ptr= name; // Reuse old name if not binlog - if (!no_rotate) + /* + Only rotate open logs that are marked non-rotatable + (binlog with constant name are non-rotatable) + */ + if (!no_rotate) + { + if (log_type == LOG_BIN) { - /* - Only rotate open logs that are marked non-rotatable - (binlog with constant name are non-rotatable) - */ if (generate_new_name(new_name, name)) { - if (!inside_mutex) + /* Error; Continue using old log file */ + if (need_lock) VOID(pthread_mutex_unlock(&LOCK_log)); return; // Something went wrong } - if (log_type == LOG_BIN) + new_name_ptr=new_name; + if (!no_auto_events) { - if (!no_auto_events) - { - /* - We log the whole file name for log file as the user may decide - to change base names at some point. - */ - THD* thd = current_thd; - Rotate_log_event r(thd,new_name+dirname_length(new_name)); - r.set_log_pos(this); - - /* - This log rotation could have been initiated by a master of - the slave running with log-bin we set the flag on rotate - event to prevent inifinite log rotation loop - */ - if (thd && thd->slave_thread) - r.flags |= LOG_EVENT_FORCED_ROTATE_F; - r.write(&log_file); - bytes_written += r.get_event_len(); - } /* - Update needs to be signaled even if there is no rotate event - log rotation should give the waiting thread a signal to - discover EOF and move on to the next log. + We log the whole file name for log file as the user may decide + to change base names at some point. */ - signal_update(); + THD* thd = current_thd; + Rotate_log_event r(thd,new_name+dirname_length(new_name)); + r.set_log_pos(this); + + /* + Becasue this log rotation could have been initiated by a master of + the slave running with log-bin, we set the flag on rotate + event to prevent inifinite log rotation loop + */ + if (thd->slave_thread) + r.flags|= LOG_EVENT_FORCED_ROTATE_F; + r.write(&log_file); + bytes_written += r.get_event_len(); } - else - strmov(new_name, old_name); // Reopen old file name + /* + Update needs to be signaled even if there is no rotate event + log rotation should give the waiting thread a signal to + discover EOF and move on to the next log. + */ + signal_update(); } - name=0; - close(); - open(old_name, log_type, new_name, io_cache_type, no_auto_events); - my_free(old_name,MYF(0)); - last_time=query_start=0; - write_error=0; - if (!inside_mutex) - VOID(pthread_mutex_unlock(&LOCK_log)); + } + old_name=name; + save_log_type=log_type; + name=0; // Don't free name + close(); + open(old_name, save_log_type, new_name_ptr, index_file_name, io_cache_type, + no_auto_events); + my_free(old_name,MYF(0)); + + if (need_lock) + { + pthread_mutex_unlock(&LOCK_index); + pthread_mutex_unlock(&LOCK_log); } } + bool MYSQL_LOG::append(Log_event* ev) { bool error = 0; @@ -763,21 +878,23 @@ bool MYSQL_LOG::append(Log_event* ev) goto err; } bytes_written += ev->get_event_len(); - if ((uint)my_b_append_tell(&log_file) > max_binlog_size) + if ((uint) my_b_append_tell(&log_file) > max_binlog_size) { - new_file(1); + pthread_mutex_lock(&LOCK_index); + new_file(0); + pthread_mutex_unlock(&LOCK_index); } - signal_update(); err: pthread_mutex_unlock(&LOCK_log); + signal_update(); // Safe as we don't call close return error; } bool MYSQL_LOG::appendv(const char* buf, uint len,...) { - bool error = 0; + bool error= 0; va_list(args); va_start(args,len); @@ -788,24 +905,32 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...) { if (my_b_append(&log_file,(byte*) buf,len)) { - error = 1; - break; + error= 1; + goto err; } bytes_written += len; } while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint))); if ((uint) my_b_append_tell(&log_file) > max_binlog_size) { - new_file(1); + pthread_mutex_lock(&LOCK_index); + new_file(0); + pthread_mutex_unlock(&LOCK_index); } - + +err: + pthread_mutex_unlock(&LOCK_log); if (!error) signal_update(); - pthread_mutex_unlock(&LOCK_log); return error; } +/* + Write to normal (not rotable) log + This is the format for the 'normal', 'slow' and 'update' logs. +*/ + bool MYSQL_LOG::write(THD *thd,enum enum_server_command command, const char *format,...) { @@ -886,13 +1011,18 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command, } +/* + Write an event to the binary log +*/ + bool MYSQL_LOG::write(Log_event* event_info) { bool error=0; if (!inited) // Can't use mutex if not init return 0; - VOID(pthread_mutex_lock(&LOCK_log)); + pthread_mutex_lock(&LOCK_log); + /* In most cases this is only called if 'is_open()' is true */ if (is_open()) { @@ -900,7 +1030,7 @@ bool MYSQL_LOG::write(Log_event* event_info) THD *thd=event_info->thd; const char* db = event_info->get_db(); #ifdef USING_TRANSACTIONS - IO_CACHE *file = ((event_info->get_cache_stmt() && thd) ? + IO_CACHE *file = ((event_info->get_cache_stmt()) ? &thd->transaction.trans_log : &log_file); #else @@ -915,38 +1045,6 @@ bool MYSQL_LOG::write(Log_event* event_info) } error=1; - if (file == &thd->transaction.trans_log - && !my_b_tell(&thd->transaction.trans_log)) { - - /* Add the "BEGIN" and "COMMIT" in the binlog around transactions - which may contain more than 1 SQL statement. If we run with - AUTOCOMMIT=1, then MySQL immediately writes each SQL statement to - the binlog when the statement has been completed. No need to add - "BEGIN" ... "COMMIT" around such statements. Otherwise, MySQL uses - thd->transaction.trans_log to cache the SQL statements until the - explicit commit, and at the commit writes the contents in .trans_log - to the binlog. - - We write the "BEGIN" mark first in the buffer (.trans_log) where we - store the SQL statements for a transaction. At the transaction commit - we will add the "COMMIT mark and write the buffer to the binlog. - The function my_b_tell above returns != 0 if there already is data - in the buffer. */ - - int save_query_length = thd->query_length; - - thd->query_length = 5; /* length of string BEGIN */ - - Query_log_event qinfo(thd, "BEGIN", TRUE); - - error = ((&qinfo)->write(file)); - - thd->query_length = save_query_length; - - if (error) - goto err; - } - /* No check for auto events flag here - this write method should never be called if auto-events are enabled @@ -974,14 +1072,10 @@ bool MYSQL_LOG::write(Log_event* event_info) char buf[1024] = "SET CHARACTER SET "; char* p = strend(buf); p = strmov(p, thd->variables.convert_set->name); - int save_query_length = thd->query_length; - // just in case somebody wants it later - thd->query_length = (uint)(p - buf); - Query_log_event e(thd, buf); + Query_log_event e(thd, buf, (ulong)(p - buf)); e.set_log_pos(this); if (e.write(file)) goto err; - thd->query_length = save_query_length; // clean up } event_info->set_log_pos(this); if (event_info->write(file) || @@ -1018,12 +1112,18 @@ err: if (file == &log_file) signal_update(); if (should_rotate) - new_file(1); // inside mutex + { + pthread_mutex_lock(&LOCK_index); + new_file(0); // inside mutex + pthread_mutex_unlock(&LOCK_index); + } } - VOID(pthread_mutex_unlock(&LOCK_log)); + + pthread_mutex_unlock(&LOCK_log); return error; } + uint MYSQL_LOG::next_file_id() { uint res; @@ -1033,74 +1133,102 @@ uint MYSQL_LOG::next_file_id() return res; } + /* Write a cached log entry to the binary log - We only come here if there is something in the cache. - 'cache' needs to be reinitialized after this functions returns. + + NOTE + - We only come here if there is something in the cache. + - The thing in the cache is always a complete transcation + - 'cache' needs to be reinitialized after this functions returns. + + IMPLEMENTATION + - To support transaction over replication, we wrap the transaction + with BEGIN/COMMIT in the binary log. */ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache) { VOID(pthread_mutex_lock(&LOCK_log)); - bool error=1; - if (is_open()) + if (is_open()) // Should always be true { + uint length; + /* - We come here when the queries to be logged could not fit into memory - and part of the queries are stored in a log file on disk. - */ + Add the "BEGIN" and "COMMIT" in the binlog around transactions + which may contain more than 1 SQL statement. If we run with + AUTOCOMMIT=1, then MySQL immediately writes each SQL statement to + the binlog when the statement has been completed. No need to add + "BEGIN" ... "COMMIT" around such statements. Otherwise, MySQL uses + thd->transaction.trans_log to cache the SQL statements until the + explicit commit, and at the commit writes the contents in .trans_log + to the binlog. - uint length; + We write the "BEGIN" mark first in the buffer (.trans_log) where we + store the SQL statements for a transaction. At the transaction commit + we will add the "COMMIT mark and write the buffer to the binlog. + */ + { + Query_log_event qinfo(thd, "BEGIN", 5, TRUE); + if (qinfo.write(&log_file)) + goto err; + } /* Read from the file used to cache the queries .*/ if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) - { - sql_print_error(ER(ER_ERROR_ON_WRITE), cache->file_name, errno); goto err; - } length=my_b_bytes_in_cache(cache); do { /* Write data to the binary log file */ if (my_b_write(&log_file, cache->read_pos, length)) - { - if (!write_error) - sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno); goto err; - } cache->read_pos=cache->read_end; // Mark buffer used up } while ((length=my_b_fill(cache))); - if (flush_io_cache(&log_file)) + + /* + We write the command "COMMIT" as the last SQL command in the + binlog segment cached for this transaction + */ + { - if (!write_error) - sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno); - goto err; + Query_log_event qinfo(thd, "COMMIT", 6, TRUE); + if (qinfo.write(&log_file) || flush_io_cache(&log_file)) + goto err; } if (cache->error) // Error on read { sql_print_error(ER(ER_ERROR_ON_READ), cache->file_name, errno); + write_error=1; // Don't give more errors goto err; } - error = ha_report_binlog_offset_and_commit(thd, log_file_name, - log_file.pos_in_file); - if (error) + if ((ha_report_binlog_offset_and_commit(thd, log_file_name, + log_file.pos_in_file))) goto err; + signal_update(); } - error=0; + VOID(pthread_mutex_unlock(&LOCK_log)); + return 0; err: - if (error) - write_error=1; - else - signal_update(); - + if (!write_error) + { + write_error= 1; + sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno); + } VOID(pthread_mutex_unlock(&LOCK_log)); - - return error; + return 1; } -/* Write update log in a format suitable for incremental backup */ +/* + Write update log in a format suitable for incremental backup + + NOTE + - This code should be deleted in MySQL 5,0 as the binary log + is a full replacement for the update log. + +*/ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, time_t query_start) @@ -1222,30 +1350,42 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, return error; } +/* + Wait until we get a signal that the binary log has been updated + + SYNOPSIS + wait_for_update() + thd Thread variable + + NOTES + One must have a lock on LOCK_log before calling this function. +*/ + + void MYSQL_LOG:: wait_for_update(THD* thd) { const char* old_msg = thd->enter_cond(&update_cond, &LOCK_log, "Slave: waiting for binlog update"); pthread_cond_wait(&update_cond, &LOCK_log); - /* - This is not a bug: - We unlock the mutex for the caller, and expect him to lock it and - then not unlock it upon return. This is a rather odd way of doing - things, but this is the cleanest way I could think of to solve the - race deadlock caused by THD::awake() first acquiring mysys_var - mutex and then the current mutex, while wait_for_update being - called with the current mutex already aquired and THD::exit_cond() - trying to acquire mysys_var mutex. We do need the mutex to be - acquired prior to the invocation of wait_for_update in all cases, - so mutex acquisition inside wait_for_update() is not an option. - */ - pthread_mutex_unlock(&LOCK_log); thd->exit_cond(old_msg); } +/* + Close the log file + + SYNOPSIS + close() + exiting Set to 1 if we should also close the index file + This can be set to 0 if we are going to do call open + at once after close, in which case we don't want to + close the index file. +*/ + void MYSQL_LOG::close(bool exiting) { // One can't set log_type here! + DBUG_ENTER("MYSQL_LOG::close"); + DBUG_PRINT("enter",("exiting: %d", (int) exiting)); if (is_open()) { if (log_type == LOG_BIN && !no_auto_events) @@ -1259,28 +1399,46 @@ void MYSQL_LOG::close(bool exiting) if (my_close(log_file.file,MYF(0)) < 0 && ! write_error) { write_error=1; - sql_print_error(ER(ER_ERROR_ON_WRITE),name,errno); + sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno); } } - if (exiting && index_file >= 0) + + /* + The following test is needed even if is_open() is not set, as we may have + called a not complete close earlier and the index file is still open. + */ + + if (exiting && my_b_inited(&index_file)) { - if (my_close(index_file,MYF(0)) < 0 && ! write_error) + end_io_cache(&index_file); + if (my_close(index_file.file, MYF(0)) < 0 && ! write_error) { - write_error=1; - sql_print_error(ER(ER_ERROR_ON_WRITE),name,errno); + write_error= 1; + sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno); } - index_file=-1; - log_type=LOG_CLOSED; } + log_type= LOG_CLOSED; safeFree(name); + DBUG_VOID_RETURN; } /* Check if a string is a valid number - Return: - TRUE String is a number - FALSE Error + + SYNOPSIS + test_if_number() + str String to test + res Store value here + allow_wildcards Set to 1 if we should ignore '%' and '_' + + NOTE + For the moment the allow_wildcards argument is not used + Should be move to some other file. + + RETURN VALUES + 1 String is a number + 0 Error */ static bool test_if_number(register const char *str, @@ -1352,7 +1510,6 @@ void sql_print_error(const char *format,...) } - void sql_perror(const char *message) { #ifdef HAVE_STRERROR diff --git a/sql/log_event.cc b/sql/log_event.cc index 52e97310d75..afa821d0bb1 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -149,6 +149,14 @@ Log_event::Log_event(THD* thd_arg, uint16 flags_arg) } } +/* + Delete all temporary files used for SQL_LOAD. + + TODO + - When we get a 'server start' event, we should only remove + the files associated with the server id that just started. + Easily fixable by adding server_id as a prefix to the log files. +*/ static void cleanup_load_tmpdir() { @@ -195,7 +203,7 @@ Log_event::Log_event(const char* buf, bool old_format) int Log_event::exec_event(struct st_relay_log_info* rli) { - if (rli) + if (rli) // QQ When is this not true ? { rli->inc_pos(get_event_len(),log_pos); DBUG_ASSERT(rli->sql_thd != 0); @@ -749,9 +757,9 @@ int Rotate_log_event::write_data(IO_CACHE* file) #ifndef MYSQL_CLIENT Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, - bool using_trans) + ulong query_length, bool using_trans) :Log_event(thd_arg), data_buf(0), query(query_arg), db(thd_arg->db), - q_len(thd_arg->query_length), + q_len((uint32) query_length), error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno), thread_id(thd_arg->thread_id), cache_stmt(using_trans && @@ -1267,7 +1275,7 @@ Slave_log_event::Slave_log_event(THD* thd_arg, Log_event(thd_arg),mem_pool(0),master_host(0) { DBUG_ENTER("Slave_log_event"); - if (!rli->inited) + if (!rli->inited) // QQ When can this happen ? DBUG_VOID_RETURN; MASTER_INFO* mi = rli->mi; @@ -1605,6 +1613,14 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) init_sql_alloc(&thd->mem_root, 8192,0); thd->db = rewrite_db((char*)db); DBUG_ASSERT(q_len == strlen(query)); + + /* + InnoDB internally stores the master log position it has processed so far; + position to store is really pos + pending + event_len + since we must store the pos of the END of the current log event + */ + rli->event_len= get_event_len(); + if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) { thd->query = (char*)query; @@ -1783,14 +1799,26 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) } +/* + The master started + + IMPLEMENTATION + - To handle the case where the master died without a stop event, + we clean up all temporary tables + locks that we got. + + TODO + - Remove all active user locks + - If we have an active transaction at this point, the master died + in the middle while writing the transaction to the binary log. + In this case we should stop the slave. +*/ + int Start_log_event::exec_event(struct st_relay_log_info* rli) { + /* All temporary tables was deleted on the master */ close_temporary_tables(thd); /* If we have old format, load_tmpdir is cleaned up by the I/O thread - - TODO: cleanup_load_tmpdir() needs to remove only the files associated - with the server id that has just started */ if (!rli->mi->old_format) cleanup_load_tmpdir(); @@ -1798,6 +1826,14 @@ int Start_log_event::exec_event(struct st_relay_log_info* rli) } +/* + The master stopped. Clean up all temporary tables + locks that the + master may have set. + + TODO + - Remove all active user locks +*/ + int Stop_log_event::exec_event(struct st_relay_log_info* rli) { // do not clean up immediately after rotate event @@ -1808,16 +1844,35 @@ int Stop_log_event::exec_event(struct st_relay_log_info* rli) } /* We do not want to update master_log pos because we get a rotate event - before stop, so by now master_log_name is set to the next log - if we updated it, we will have incorrect master coordinates and this + before stop, so by now master_log_name is set to the next log. + If we updated it, we will have incorrect master coordinates and this could give false triggers in MASTER_POS_WAIT() that we have reached - the targed position when in fact we have not + the target position when in fact we have not. */ rli->inc_pos(get_event_len(), 0); flush_relay_log_info(rli); return 0; } + +/* + Got a rotate log even from the master + + IMPLEMENTATION + - Rotate the log file if the name of the log file changed + (In practice this should always be the case) + + TODO + - Investigate/Test if we can't ignore all rotate log events + that we get from the master (and not even write it to the local + binary log). + + RETURN VALUES + 0 ok + 1 Impossible new log file name (rotate log event is ignored) +*/ + + int Rotate_log_event::exec_event(struct st_relay_log_info* rli) { bool rotate_binlog = 0, write_slave_event = 0; @@ -1829,18 +1884,19 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) TODO: probably needs re-write rotate local binlog only if the name of remote has changed */ - if (!*log_name || !(log_name[ident_len] == 0 && - !memcmp(log_name, new_log_ident, ident_len))) + if (!*log_name || (memcmp(log_name, new_log_ident, ident_len) || + log_name[ident_len] != 0)) { - write_slave_event = (!(flags & LOG_EVENT_FORCED_ROTATE_F) - && mysql_bin_log.is_open()); + write_slave_event = (!(flags & LOG_EVENT_FORCED_ROTATE_F) && + mysql_bin_log.is_open()); rotate_binlog = (*log_name && write_slave_event); if (ident_len >= sizeof(rli->master_log_name)) { + // This should be impossible pthread_mutex_unlock(&rli->data_lock); DBUG_RETURN(1); } - memcpy(log_name, new_log_ident,ident_len); + memcpy(log_name, new_log_ident, ident_len); log_name[ident_len] = 0; } rli->master_log_pos = pos; @@ -1848,7 +1904,7 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) if (rotate_binlog) { mysql_bin_log.new_file(); - rli->master_log_pos = 4; + rli->master_log_pos = BIN_LOG_HEADER_SIZE; } DBUG_PRINT("info", ("master_log_pos: %d", (ulong) rli->master_log_pos)); pthread_cond_broadcast(&rli->data_cond); diff --git a/sql/log_event.h b/sql/log_event.h index 9b8145f14b0..b69643c366a 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -317,8 +317,8 @@ public: #ifndef MYSQL_CLIENT bool cache_stmt; - Query_log_event(THD* thd_arg, const char* query_arg, - bool using_trans=0); + Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length, + bool using_trans=0); const char* get_db() { return db; } void pack_info(String* packet); int exec_event(struct st_relay_log_info* rli); diff --git a/sql/mini_client.cc b/sql/mini_client.cc index f6a5d6af8ae..2b58430ef08 100644 --- a/sql/mini_client.cc +++ b/sql/mini_client.cc @@ -199,7 +199,7 @@ MYSQL *mc_mysql_init(MYSQL *mysql) #ifdef __WIN__ mysql->options.connect_timeout=20; #endif - mysql->net.timeout = slave_net_timeout; + mysql->net.read_timeout = slave_net_timeout; return mysql; } @@ -416,7 +416,9 @@ my_bool mc_mysql_reconnect(MYSQL *mysql) mysql->client_flag, mysql->net.read_timeout)) { tmp_mysql.reconnect=0; - mc_mysql_close(&tmp_mysql); + mc_mysql_close(&tmp_mysql); + mysql->net.last_errno=CR_SERVER_GONE_ERROR; + strmov(mysql->net.last_error,ER(mysql->net.last_errno)); DBUG_RETURN(1); } tmp_mysql.free_me=mysql->free_me; @@ -507,11 +509,12 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user, struct sockaddr_un UNIXaddr; #endif DBUG_ENTER("mc_mysql_connect"); - - DBUG_PRINT("enter",("host: %s db: %s user: %s", + DBUG_PRINT("enter",("host: %s db: %s user: %s connect_time_out: %u read_timeout: %u", host ? host : "(Null)", db ? db : "(Null)", - user ? user : "(Null)")); + user ? user : "(Null)", + net_read_timeout, + (uint) slave_net_timeout)); thr_alarm_init(&alarmed); thr_alarm(&alarmed, net_read_timeout, &alarm_buff); @@ -655,7 +658,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user, goto error; } vio_keepalive(net->vio,TRUE); - net->timeout=slave_net_timeout; + net->read_timeout=slave_net_timeout; /* Get version info */ mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */ if ((pkt_length=mc_net_safe_read(mysql)) == packet_error) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 712107a0074..fcb2016993e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -580,8 +580,9 @@ void sql_print_error(const char *format,...) __attribute__ ((format (printf, 1, 2))); bool fn_format_relative_to_data_home(my_string to, const char *name, const char *dir, const char *extension); -void open_log(MYSQL_LOG *log, const char *hostname, - const char *opt_name, const char *extension, +bool open_log(MYSQL_LOG *log, const char *hostname, + const char *opt_name, const char *extension, + const char *index_file_name, enum_log_type type, bool read_append = 0, bool no_auto_events = 0); @@ -616,7 +617,7 @@ extern ulong select_range_check_count, select_range_count, select_scan_count; extern ulong select_full_range_join_count,select_full_join_count; extern ulong slave_open_temp_tables, query_cache_size; extern ulong thd_startup_options, slow_launch_threads, slow_launch_time; -extern ulong server_id; +extern ulong server_id, concurrency; extern ulong ha_read_count, ha_write_count, ha_delete_count, ha_update_count; extern ulong ha_read_key_count, ha_read_next_count, ha_read_prev_count; extern ulong ha_read_first_count, ha_read_last_count; @@ -643,6 +644,7 @@ extern bool opt_disable_networking, opt_skip_show_db; extern bool volatile abort_loop, shutdown_in_progress, grant_option; extern uint volatile thread_count, thread_running, global_read_lock; extern my_bool opt_safe_show_db, opt_local_infile, lower_case_table_names; +extern my_bool opt_slave_compressed_protocol; extern char f_fyllchar; extern MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log; @@ -666,7 +668,8 @@ extern struct system_variables global_system_variables; extern struct system_variables max_system_variables; extern SHOW_COMP_OPTION have_isam, have_raid, have_openssl, have_symlink; -extern SHOW_COMP_OPTION have_query_cache; +extern SHOW_COMP_OPTION have_query_cache, have_berkeley_db, have_innodb; + #ifndef __WIN__ extern pthread_t signal_thread; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 6c9e934071d..e1c32878d77 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -252,15 +252,15 @@ bool opt_skip_slave_start = 0; // If set, slave is not autostarted */ bool opt_reckless_slave = 0; -ulong back_log, connect_timeout; +ulong back_log, connect_timeout, concurrency; char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], time_zone[30]; bool opt_log, opt_update_log, opt_bin_log, opt_slow_log; bool opt_disable_networking=0, opt_skip_show_db=0; -my_bool opt_local_infile, opt_external_locking; +my_bool opt_local_infile, opt_external_locking, opt_slave_compressed_protocol; static bool opt_do_pstack = 0; static ulong opt_specialflag=SPECIAL_ENGLISH; -static ulong concurrency; + static ulong opt_myisam_block_size; static my_socket unix_sock= INVALID_SOCKET,ip_sock= INVALID_SOCKET; static my_string opt_logname=0,opt_update_logname=0, @@ -1428,6 +1428,17 @@ static void init_signals(void) sigaction(SIGILL, &sa, NULL); sigaction(SIGFPE, &sa, NULL); } + +#ifdef HAVE_GETRLIMIT + if (test_flags & TEST_CORE_ON_SIGNAL) + { + /* Change limits so that we will get a core file */ + struct rlimit rl; + rl.rlim_cur = rl.rlim_max = RLIM_INFINITY; + if (setrlimit(RLIMIT_CORE, &rl)) + sql_print_error("Warning: setrlimit could not change the size of core files to 'infinity'; We may not be able to generate a core file on signals"); + } +#endif (void) sigemptyset(&set); #ifdef THREAD_SPECIFIC_SIGPIPE sigset(SIGPIPE,abort_thread); @@ -1701,10 +1712,11 @@ const char *load_default_groups[]= { "mysqld","server",0 }; char *libwrapName=NULL; #endif -void open_log(MYSQL_LOG *log, const char *hostname, - const char *opt_name, const char *extension, - enum_log_type type, bool read_append, - bool no_auto_events) +bool open_log(MYSQL_LOG *log, const char *hostname, + const char *opt_name, const char *extension, + const char *index_file_name, + enum_log_type type, bool read_append, + bool no_auto_events) { char tmp[FN_REFLEN]; if (!opt_name || !opt_name[0]) @@ -1728,8 +1740,9 @@ void open_log(MYSQL_LOG *log, const char *hostname, opt_name=tmp; } } - log->open(opt_name,type,0,(read_append) ? SEQ_READ_APPEND : WRITE_CACHE, - no_auto_events); + return log->open(opt_name, type, 0, index_file_name, + (read_append) ? SEQ_READ_APPEND : WRITE_CACHE, + no_auto_events); } @@ -1939,17 +1952,18 @@ int main(int argc, char **argv) /* Setup log files */ if (opt_log) - open_log(&mysql_log, glob_hostname, opt_logname, ".log", LOG_NORMAL); + open_log(&mysql_log, glob_hostname, opt_logname, ".log", NullS, + LOG_NORMAL); if (opt_update_log) { open_log(&mysql_update_log, glob_hostname, opt_update_logname, "", - LOG_NEW); + NullS, LOG_NEW); using_update_log=1; } if (opt_slow_log) open_log(&mysql_slow_log, glob_hostname, opt_slow_logname, "-slow.log", - LOG_NORMAL); + NullS, LOG_NORMAL); #ifdef __WIN__ #define MYSQL_ERR_FILE "mysql.err" if (!opt_console) @@ -2051,9 +2065,8 @@ The server will not act as a slave."); strmov(strcend(tmp,'.'),"-bin"); opt_bin_logname=my_strdup(tmp,MYF(MY_WME)); } - mysql_bin_log.set_index_file_name(opt_binlog_index_name); open_log(&mysql_bin_log, glob_hostname, opt_bin_logname, "-bin", - LOG_BIN); + opt_binlog_index_name,LOG_BIN); using_update_log=1; } @@ -2353,13 +2366,7 @@ static void create_new_thread(THD *thd) delete thd; DBUG_VOID_RETURN; } - if (pthread_mutex_lock(&LOCK_thread_count)) - { - DBUG_PRINT("error",("Can't lock LOCK_thread_count")); - close_connection(net,ER_OUT_OF_RESOURCES); - delete thd; - DBUG_VOID_RETURN; - } + pthread_mutex_lock(&LOCK_thread_count); if (thread_count-delayed_insert_threads > max_used_connections) max_used_connections=thread_count-delayed_insert_threads; thd->thread_id=thread_id++; @@ -2818,7 +2825,7 @@ enum options { OPT_QUERY_CACHE_LIMIT, OPT_QUERY_CACHE_SIZE, OPT_QUERY_CACHE_TYPE, OPT_RECORD_BUFFER, OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT, - OPT_SLAVE_NET_TIMEOUT, OPT_SLOW_LAUNCH_TIME, + OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME, OPT_SORT_BUFFER, OPT_TABLE_CACHE, OPT_THREAD_CONCURRENCY, OPT_THREAD_CACHE_SIZE, OPT_TMP_TABLE_SIZE, OPT_THREAD_STACK, @@ -2968,8 +2975,9 @@ struct my_option my_long_options[] = 0, 0, 0, 0, 0, 0}, {"innodb_flush_log_at_trx_commit", OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT, "Set to 0 if you don't want to flush logs", - &innobase_flush_log_at_trx_commit, &innobase_flush_log_at_trx_commit, - 0, GET_LONG, OPT_ARG, 0, 0, 10, 0, 0, 0}, + (gptr*) &innobase_flush_log_at_trx_commit, + (gptr*) &innobase_flush_log_at_trx_commit, + 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"innodb_flush_method", OPT_INNODB_FLUSH_METHOD, "With which method to flush data", (gptr*) &innobase_unix_file_flush_method, (gptr*) &innobase_unix_file_flush_method, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, @@ -3047,7 +3055,7 @@ struct my_option my_long_options[] = {"master-retry-count", OPT_MASTER_RETRY_COUNT, "The number of tries the slave will make to connect to the master before giving up.", (gptr*) &master_retry_count, (gptr*) &master_retry_count, 0, GET_ULONG, - REQUIRED_ARG, 60, 0, 0, 0, 0, 0}, + REQUIRED_ARG, 3600*24, 0, 0, 0, 0, 0}, {"master-info-file", OPT_MASTER_INFO_FILE, "The location of the file that remembers where we left off on the master during the replication process. The default is `master.info' in the data directory. You should not need to change this.", (gptr*) &master_info_file, (gptr*) &master_info_file, 0, GET_STR, @@ -3330,7 +3338,7 @@ struct my_option my_long_options[] = { "ft_min_word_len", OPT_FT_MIN_WORD_LEN, "The minimum length of the word to be included in a FULLTEXT index. Note: FULLTEXT indexes must be rebuilt after changing this variable.", (gptr*) &ft_min_word_len, (gptr*) &ft_min_word_len, 0, GET_ULONG, - REQUIRED_ARG, 4, 1, HA_FT_MAXLEN, 0, 1, 0}, + REQUIRED_ARG, 4, 2, HA_FT_MAXLEN, 0, 1, 0}, { "ft_max_word_len", OPT_FT_MAX_WORD_LEN, "The maximum length of the word to be included in a FULLTEXT index. Note: FULLTEXT indexes must be rebuilt after changing this variable.", (gptr*) &ft_max_word_len, (gptr*) &ft_max_word_len, 0, GET_ULONG, @@ -3548,6 +3556,11 @@ struct my_option my_long_options[] = "Undocumented", (gptr*) &relay_log_space_limit, (gptr*) &relay_log_space_limit, 0, GET_ULONG, REQUIRED_ARG, 0L, 0L, (longlong) ULONG_MAX, 0, 1, 0}, + {"slave_compressed_protocol", OPT_SLAVE_COMPRESSED_PROTOCOL, + "Use compression on master/slave protocol", + (gptr*) &opt_slave_compressed_protocol, + (gptr*) &opt_slave_compressed_protocol, + 0, GET_BOOL, REQUIRED_ARG, 0, 0, 1, 0, 1, 0}, {"slave_net_timeout", OPT_SLAVE_NET_TIMEOUT, "Number of seconds to wait for more data from a master/slave connection before aborting the read.", (gptr*) &slave_net_timeout, (gptr*) &slave_net_timeout, 0, diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 5ff040003d5..0eb3e1d6a75 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -107,7 +107,10 @@ int my_net_init(NET *net, Vio* vio) net->fd = vio_fd(vio); /* For perl DBI/DBD */ #if defined(MYSQL_SERVER) && !defined(___WIN__) && !defined(__EMX__) && !defined(OS2) if (!(test_flags & TEST_BLOCKING)) - vio_blocking(vio, FALSE); + { + my_bool old_mode; + vio_blocking(vio, FALSE, &old_mode); + } #endif vio_fastsend(vio); } @@ -161,17 +164,14 @@ void net_clear(NET *net) { #if !defined(EXTRA_DEBUG) && !defined(EMBEDDED_LIBRARY) int count; /* One may get 'unused' warn */ - bool is_blocking=vio_is_blocking(net->vio); - if (is_blocking) - vio_blocking(net->vio, FALSE); - if (!vio_is_blocking(net->vio)) /* Safety if SSL */ + my_bool old_mode; + if (!vio_blocking(net->vio, FALSE, &old_mode)) { while ( (count = vio_read(net->vio, (char*) (net->buff), (uint32) net->max_packet)) > 0) DBUG_PRINT("info",("skipped %d bytes from file: %s", count,vio_description(net->vio))); - if (is_blocking) - vio_blocking(net->vio, TRUE); + vio_blocking(net->vio, TRUE, &old_mode); } #endif /* EXTRA_DEBUG */ net->pkt_nr=net->compress_pkt_nr=0; /* Ready for new command */ @@ -382,20 +382,18 @@ net_real_write(NET *net,const char *packet,ulong len) { if (!thr_alarm(&alarmed,(uint) net->write_timeout,&alarm_buff)) { /* Always true for client */ - if (!vio_is_blocking(net->vio)) + my_bool old_mode; + while (vio_blocking(net->vio, TRUE, &old_mode) < 0) { - while (vio_blocking(net->vio, TRUE) < 0) - { - if (vio_should_retry(net->vio) && retry_count++ < RETRY_COUNT) - continue; + if (vio_should_retry(net->vio) && retry_count++ < RETRY_COUNT) + continue; #ifdef EXTRA_DEBUG - fprintf(stderr, - "%s: my_net_write: fcntl returned error %d, aborting thread\n", - my_progname,vio_errno(net->vio)); + fprintf(stderr, + "%s: my_net_write: fcntl returned error %d, aborting thread\n", + my_progname,vio_errno(net->vio)); #endif /* EXTRA_DEBUG */ - net->error=2; /* Close socket */ - goto end; - } + net->error=2; /* Close socket */ + goto end; } retry_count=0; continue; @@ -439,8 +437,9 @@ net_real_write(NET *net,const char *packet,ulong len) #endif if (thr_alarm_in_use(&alarmed)) { + my_bool old_mode; thr_end_alarm(&alarmed); - vio_blocking(net->vio, net_blocking); + vio_blocking(net->vio, net_blocking, &old_mode); } net->reading_or_writing=0; DBUG_RETURN(((int) (pos != end))); @@ -461,10 +460,12 @@ static void my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed) { ALARM alarm_buff; uint retry_count=0; + my_bool old_mode; + if (!thr_alarm_in_use(&alarmed)) { if (!thr_alarm(alarmed,net->read_timeout,&alarm_buff) || - (!vio_is_blocking(net->vio) && vio_blocking(net->vio,TRUE) < 0)) + vio_blocking(net->vio, TRUE, &old_mode) < 0) return; /* Can't setup, abort */ } while (remain > 0) @@ -538,29 +539,27 @@ my_real_read(NET *net, ulong *complen) { if (!thr_alarm(&alarmed,net->read_timeout,&alarm_buff)) /* Don't wait too long */ { - if (!vio_is_blocking(net->vio)) - { - while (vio_blocking(net->vio,TRUE) < 0) - { - if (vio_should_retry(net->vio) && - retry_count++ < RETRY_COUNT) - continue; - DBUG_PRINT("error", - ("fcntl returned error %d, aborting thread", - vio_errno(net->vio))); + my_bool old_mode; + while (vio_blocking(net->vio, TRUE, &old_mode) < 0) + { + if (vio_should_retry(net->vio) && + retry_count++ < RETRY_COUNT) + continue; + DBUG_PRINT("error", + ("fcntl returned error %d, aborting thread", + vio_errno(net->vio))); #ifdef EXTRA_DEBUG - fprintf(stderr, - "%s: read: fcntl returned error %d, aborting thread\n", - my_progname,vio_errno(net->vio)); + fprintf(stderr, + "%s: read: fcntl returned error %d, aborting thread\n", + my_progname,vio_errno(net->vio)); #endif /* EXTRA_DEBUG */ - len= packet_error; - net->error=2; /* Close socket */ + len= packet_error; + net->error=2; /* Close socket */ #ifdef MYSQL_SERVER - net->last_errno=ER_NET_FCNTL_ERROR; + net->last_errno=ER_NET_FCNTL_ERROR; #endif - goto end; - } - } + goto end; + } retry_count=0; continue; } @@ -583,7 +582,9 @@ my_real_read(NET *net, ulong *complen) continue; } #endif - DBUG_PRINT("error",("Couldn't read packet: remain: %lu errno: %d length: %ld alarmed: %d", remain,vio_errno(net->vio),length,alarmed)); + DBUG_PRINT("error",("Couldn't read packet: remain: %lu errno: %d length: %ld alarmed: %d", + remain,vio_errno(net->vio), length, + thr_got_alarm(&alarmed))); len= packet_error; net->error=2; /* Close socket */ #ifdef MYSQL_SERVER @@ -653,8 +654,9 @@ my_real_read(NET *net, ulong *complen) end: if (thr_alarm_in_use(&alarmed)) { + my_bool old_mode; thr_end_alarm(&alarmed); - vio_blocking(net->vio, net_blocking); + vio_blocking(net->vio, net_blocking, &old_mode); } net->reading_or_writing=0; return(len); diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index f5f5b2de9fc..54843f1dfa4 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -240,7 +240,7 @@ static int find_target_pos(LEX_MASTER_INFO *mi, IO_CACHE *log, char *errmsg) int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg) { LOG_INFO linfo; - char search_file_name[FN_REFLEN],last_log_name[FN_REFLEN]; + char last_log_name[FN_REFLEN]; IO_CACHE log; File file = -1, last_file = -1; pthread_mutex_t *log_lock; @@ -264,9 +264,8 @@ int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg) } linfo.index_file_offset = 0; - search_file_name[0] = 0; - if (mysql_bin_log.find_first_log(&linfo, search_file_name)) + if (mysql_bin_log.find_log_pos(&linfo, NullS)) { strmov(errmsg,"Could not find first log"); return 1; @@ -619,18 +618,22 @@ int show_slave_hosts(THD* thd) int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi) { - if (!mi->host || !*mi->host) /* empty host */ - return 1; + DBUG_ENTER("connect_to_master"); + if (!mi->host || !*mi->host) /* empty host */ + { + DBUG_PRINT("error",("empty hostname")); + DBUG_RETURN(1); + } if (!mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0, mi->port, 0, 0, slave_net_timeout)) { sql_print_error("Connection to master failed: %s", mc_mysql_error(mysql)); - return 1; + DBUG_RETURN(1); } - return 0; + DBUG_RETURN(0); } @@ -671,12 +674,17 @@ static inline int fetch_db_tables(THD* thd, MYSQL* mysql, const char* db, return 0; } +/* + Load all MyISAM tables from master to this slave. + + REQUIREMENTS + - No active transaction (flush_relay_log_info would not work in this case) +*/ int load_master_data(THD* thd) { MYSQL mysql; MYSQL_RES* master_status_res = 0; - bool slave_was_running = 0; int error = 0; const char* errmsg=0; int restart_thread_mask; @@ -840,7 +848,8 @@ int load_master_data(THD* thd) } } thd->proc_info="purging old relay logs"; - if (purge_relay_logs(&active_mi->rli,0 /* not only reset, but also reinit */, + if (purge_relay_logs(&active_mi->rli,thd, + 0 /* not only reset, but also reinit */, &errmsg)) { send_error(&thd->net, 0, "Failed purging old relay logs"); diff --git a/sql/set_var.cc b/sql/set_var.cc index ec8a9e83ed3..3569af0a0ca 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -186,6 +186,8 @@ sys_var_thd_enum sys_query_cache_type("query_cache_type", sys_var_bool_ptr sys_safe_show_db("safe_show_database", &opt_safe_show_db); sys_var_long_ptr sys_server_id("server_id",&server_id); +sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol", + &opt_slave_compressed_protocol); sys_var_long_ptr sys_slave_net_timeout("slave_net_timeout", &slave_net_timeout); sys_var_long_ptr sys_slow_launch_time("slow_launch_time", @@ -251,6 +253,15 @@ static sys_var_thd_bit sys_buffer_results("sql_buffer_result", static sys_var_thd_bit sys_quote_show_create("sql_quote_show_create", set_option_bit, OPTION_QUOTE_SHOW_CREATE); +static sys_var_thd_bit sys_foreign_key_checks("foreign_key_checks", + set_option_bit, + OPTION_NO_FOREIGN_KEY_CHECKS, + 1); +static sys_var_thd_bit sys_unique_checks("unique_checks", + set_option_bit, + OPTION_RELAXED_UNIQUE_CHECKS, + 1); + /* Local state variables */ @@ -290,6 +301,7 @@ sys_var *sys_variables[]= &sys_delayed_queue_size, &sys_flush, &sys_flush_time, + &sys_foreign_key_checks, &sys_identity, &sys_insert_id, &sys_interactive_timeout, @@ -326,7 +338,7 @@ sys_var *sys_variables[]= #ifdef HAVE_QUERY_CACHE &sys_query_cache_limit, &sys_query_cache_type, -#endif HAVE_QUERY_CACHE +#endif /* HAVE_QUERY_CACHE */ &sys_quote_show_create, &sys_read_buff_size, &sys_read_rnd_buff_size, @@ -335,6 +347,7 @@ sys_var *sys_variables[]= &sys_safe_updates, &sys_select_limit, &sys_server_id, + &sys_slave_compressed_protocol, &sys_slave_net_timeout, &sys_slave_skip_counter, &sys_slow_launch_time, @@ -349,6 +362,7 @@ sys_var *sys_variables[]= &sys_timestamp, &sys_tmp_table_size, &sys_tx_isolation, + &sys_unique_checks }; @@ -403,7 +417,7 @@ struct show_var_st init_vars[]= { {"innodb_file_io_threads", (char*) &innobase_file_io_threads, SHOW_LONG }, {"innodb_force_recovery", (char*) &innobase_force_recovery, SHOW_LONG }, {"innodb_thread_concurrency", (char*) &innobase_thread_concurrency, SHOW_LONG }, - {"innodb_flush_log_at_trx_commit", (char*) &innobase_flush_log_at_trx_commit, SHOW_MY_BOOL}, + {"innodb_flush_log_at_trx_commit", (char*) &innobase_flush_log_at_trx_commit, SHOW_LONG}, {"innodb_fast_shutdown", (char*) &innobase_fast_shutdown, SHOW_MY_BOOL}, {"innodb_flush_method", (char*) &innobase_unix_file_flush_method, SHOW_CHAR_PTR}, {"innodb_lock_wait_timeout", (char*) &innobase_lock_wait_timeout, SHOW_LONG }, @@ -988,10 +1002,11 @@ bool sys_var_slave_skip_counter::update(THD *thd, set_var *var) static bool set_option_bit(THD *thd, set_var *var) { - if (var->save_result.ulong_value == 0) - thd->options&= ~((sys_var_thd_bit*) var->var)->bit_flag; + sys_var_thd_bit *sys_var= ((sys_var_thd_bit*) var->var); + if ((var->save_result.ulong_value != 0) == sys_var->reverse) + thd->options&= ~sys_var->bit_flag; else - thd->options|= ((sys_var_thd_bit*) var->var)->bit_flag; + thd->options|= sys_var->bit_flag; return 0; } @@ -1142,7 +1157,7 @@ void set_var_free() 0 Unknown variable (error message is given) */ -sys_var *find_sys_var(const char *str, uint length=0) +sys_var *find_sys_var(const char *str, uint length) { sys_var *var= (sys_var*) hash_search(&system_variable_hash, str, length ? length : diff --git a/sql/set_var.h b/sql/set_var.h index 607e44d2ef3..46463089b03 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -128,7 +128,7 @@ public: } void set_default(THD *thd, enum_var_type type) { - return (*set_default_func)(thd, type); + (*set_default_func)(thd, type); } SHOW_TYPE type() { return SHOW_CHAR; } byte *value_ptr(THD *thd, enum_var_type type) { return (byte*) value; } diff --git a/sql/slave.cc b/sql/slave.cc index 7871f536320..84e0f6dd236 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -23,7 +23,6 @@ #include "sql_repl.h" #include "repl_failsafe.h" #include <thr_alarm.h> -#include <my_dir.h> #include <assert.h> bool use_slave_mask = 0; @@ -80,9 +79,15 @@ static int request_table_dump(MYSQL* mysql, const char* db, const char* table); static int create_table_from_dump(THD* thd, NET* net, const char* db, const char* table_name); static int check_master_version(MYSQL* mysql, MASTER_INFO* mi); - char* rewrite_db(char* db); + +/* + Get a bit mask for which threads are running so that we later can + restart these threads +*/ + + void init_thread_mask(int* mask,MASTER_INFO* mi,bool inverse) { bool set_io = mi->slave_running, set_sql = mi->rli.slave_running; @@ -104,6 +109,7 @@ void init_thread_mask(int* mask,MASTER_INFO* mi,bool inverse) *mask = tmp_mask; } + void lock_slave_threads(MASTER_INFO* mi) { //TODO: see if we can do this without dual mutex @@ -118,46 +124,45 @@ void unlock_slave_threads(MASTER_INFO* mi) pthread_mutex_unlock(&mi->run_lock); } + int init_slave() { DBUG_ENTER("init_slave"); - // TODO (multi-master): replace this with list initialization + + /* + TODO: re-write this to interate through the list of files + for multi-master + */ active_mi = &main_mi; - // TODO: the code below is a copy-paste mess - clean it up /* - make sure slave thread gets started if server_id is set, - valid master.info is present, and master_host has not been specified + If master_host is not specified, try to read it from the master_info file. + If master_host is specified, create the master_info file if it doesn't + exists. */ - if (server_id && !master_host) + if (init_master_info(active_mi,master_info_file,relay_log_info_file, + !master_host)) { - /* - TODO: re-write this to interate through the list of files - for multi-master - */ - char fname[FN_REFLEN+128]; - MY_STAT stat_area; - fn_format(fname, master_info_file, mysql_data_home, "", 4+16+32); - if (my_stat(fname, &stat_area, MYF(0)) && - !init_master_info(active_mi,master_info_file,relay_log_info_file)) - master_host = active_mi->host; + sql_print_error("Warning: failed to initialized master info"); + DBUG_RETURN(0); } - // slave thread - if (master_host) + + /* + make sure slave thread gets started if server_id is set, + valid master.info is present, and master_host has not been specified + */ + if (server_id && !master_host && active_mi->host[0]) + master_host= active_mi->host; + + if (master_host && !opt_skip_slave_start) { - if (!opt_skip_slave_start) - { - if (start_slave_threads(1 /* need mutex */, - 0 /* no wait for start*/, - active_mi, - master_info_file, - relay_log_info_file, - SLAVE_IO | SLAVE_SQL)) - sql_print_error("Warning: Can't create threads to handle slave"); - } - else if (init_master_info(active_mi, master_info_file, - relay_log_info_file)) - sql_print_error("Warning: failed to initialized master info"); + if (start_slave_threads(1 /* need mutex */, + 0 /* no wait for start*/, + active_mi, + master_info_file, + relay_log_info_file, + SLAVE_IO | SLAVE_SQL)) + sql_print_error("Warning: Can't create threads to handle slave"); } DBUG_RETURN(0); } @@ -175,7 +180,35 @@ static byte* get_table_key(TABLE_RULE_ENT* e, uint* len, return (byte*)e->db; } -// TODO: check proper initialization of master_log_name/master_log_pos + +/* + Open the given relay log + + SYNOPSIS + init_relay_log_pos() + rli Relay information (will be initialized) + log Name of relay log file to read from. NULL = First log + pos Position in relay log file + need_data_lock Set to 1 if this functions should do mutex locks + errmsg Store pointer to error message here + + DESCRIPTION + - Close old open relay log files. + - If we are using the same relay log as the running IO-thread, then set + rli->cur_log to point to the same IO_CACHE entry. + - If not, open the 'log' binary file. + + TODO + - check proper initialization of master_log_name/master_log_pos + - We may always want to delete all logs before 'log'. + Currently if we are not calling this with 'log' as NULL or the first + log we will never delete relay logs. + If we want this we should not set skip_log_purge to 1. + + RETURN VALUES + 0 ok + 1 error. errmsg is set to point to the error message +*/ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log, ulonglong pos, bool need_data_lock, @@ -184,13 +217,14 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log, DBUG_ENTER("init_relay_log_pos"); *errmsg=0; - if (rli->log_pos_current) + if (rli->log_pos_current) // TODO: When can this happen ? DBUG_RETURN(0); pthread_mutex_t *log_lock=rli->relay_log.get_log_lock(); pthread_mutex_lock(log_lock); if (need_data_lock) pthread_mutex_lock(&rli->data_lock); + /* Close log file and free buffers if it's already open */ if (rli->cur_log_fd >= 0) { end_io_cache(&rli->cache_buf); @@ -198,37 +232,37 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log, rli->cur_log_fd = -1; } - if (!log) - log = rli->relay_log_name; // already inited - if (!pos) - pos = rli->relay_log_pos; // already inited - else - rli->relay_log_pos = pos; + rli->relay_log_pos = pos; /* Test to see if the previous run was with the skip of purging If yes, we do not purge when we restart */ - if (rli->relay_log.find_first_log(&rli->linfo,"")) + if (rli->relay_log.find_log_pos(&rli->linfo,NullS)) { *errmsg="Could not find first log during relay log initialization"; goto err; } - if (strcmp(log,rli->linfo.log_file_name)) - rli->skip_log_purge=1; - - if (rli->relay_log.find_first_log(&rli->linfo,log)) + + if (log) // If not first log { - *errmsg="Could not find target log during relay log initialization"; - goto err; + if (strcmp(log, rli->linfo.log_file_name)) + rli->skip_log_purge=1; // Different name; Don't purge + if (rli->relay_log.find_log_pos(&rli->linfo, log)) + { + *errmsg="Could not find target log during relay log initialization"; + goto err; + } } strmake(rli->relay_log_name,rli->linfo.log_file_name, sizeof(rli->relay_log_name)-1); - // to make end_io_cache(&rli->cache_buf) safe in all cases - if (!rli->inited) - bzero((char*) &rli->cache_buf, sizeof(IO_CACHE)); if (rli->relay_log.is_active(rli->linfo.log_file_name)) { + /* + The IO thread is using this log file. + In this case, we will use the same IO_CACHE pointer to + read data as the IO thread is using to write data. + */ if (my_b_tell((rli->cur_log=rli->relay_log.get_log_file())) == 0 && check_binlog_magic(rli->cur_log,errmsg)) goto err; @@ -236,10 +270,9 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log, } else { - if (rli->inited) - end_io_cache(&rli->cache_buf); - if (rli->cur_log_fd >= 0) - my_close(rli->cur_log_fd,MYF(MY_WME)); + /* + Open the relay log and set rli->cur_log to point at this one + */ if ((rli->cur_log_fd=open_binlog(&rli->cache_buf, rli->linfo.log_file_name,errmsg)) < 0) goto err; @@ -257,6 +290,7 @@ err: DBUG_RETURN ((*errmsg) ? 1 : 0); } + /* called from get_options() in mysqld.cc on start-up */ void init_slave_skip_errors(const char* arg) @@ -294,12 +328,13 @@ void init_slave_skip_errors(const char* arg) are not running */ -int purge_relay_logs(RELAY_LOG_INFO* rli, bool just_reset, const char** errmsg) +int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset, + const char** errmsg) { + int error=0; DBUG_ENTER("purge_relay_logs"); if (!rli->inited) DBUG_RETURN(0); /* successfully do nothing */ - int error=0; DBUG_ASSERT(rli->slave_running == 0); DBUG_ASSERT(rli->mi->slave_running == 0); @@ -309,14 +344,14 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, bool just_reset, const char** errmsg) rli->pending=0; rli->master_log_name[0]=0; rli->master_log_pos=0; // 0 means uninitialized - if (rli->relay_log.reset_logs(rli->sql_thd) || - rli->relay_log.find_first_log(&rli->linfo,"")) + if (rli->relay_log.reset_logs(thd)) { *errmsg = "Failed during log reset"; error=1; goto err; } - strmake(rli->relay_log_name,rli->linfo.log_file_name, + /* Save name of used relay log file */ + strmake(rli->relay_log_name, rli->relay_log.get_log_fname(), sizeof(rli->relay_log_name)-1); // Just first log with magic number and nothing else rli->log_space_total= BIN_LOG_HEADER_SIZE; @@ -324,7 +359,8 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, bool just_reset, const char** errmsg) rli->relay_log.reset_bytes_written(); rli->log_pos_current=0; if (!just_reset) - error = init_relay_log_pos(rli,0,0,0 /* do not need data lock */,errmsg); + error= init_relay_log_pos(rli, rli->relay_log_name, rli->relay_log_pos, + 0 /* do not need data lock */, errmsg); err: #ifndef DBUG_OFF @@ -335,6 +371,7 @@ err: DBUG_RETURN(error); } + int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock) { if (!mi->inited) @@ -374,6 +411,7 @@ int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock) return 0; } + int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, pthread_mutex_t *cond_lock, pthread_cond_t* term_cond, @@ -417,6 +455,7 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, return 0; } + int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock, pthread_mutex_t *cond_lock, pthread_cond_t* start_cond, @@ -438,13 +477,13 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock, } if (*slave_running) - { - if (start_cond) - pthread_cond_broadcast(start_cond); - if (start_lock) - pthread_mutex_unlock(start_lock); - return ER_SLAVE_MUST_STOP; - } + { + if (start_cond) + pthread_cond_broadcast(start_cond); + if (start_lock) + pthread_mutex_unlock(start_lock); + return ER_SLAVE_MUST_STOP; + } if (pthread_create(&th, &connection_attrib, h_func, (void*)mi)) { if (start_lock) @@ -457,7 +496,7 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock, while (!*slave_running) { const char* old_msg = thd->enter_cond(start_cond,cond_lock, - "Waiting for slave thread to start"); + "Waiting for slave thread to start"); pthread_cond_wait(start_cond,cond_lock); thd->exit_cond(old_msg); /* @@ -506,8 +545,6 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start, lock_cond_io = &mi->run_lock; lock_cond_sql = &mi->rli.run_lock; } - if (init_master_info(mi,master_info_fname,slave_info_fname)) - DBUG_RETURN(ER_MASTER_INFO); if (thread_mask & SLAVE_IO) error=start_slave_thread(handle_slave_io,lock_io,lock_cond_io, @@ -660,6 +697,7 @@ void end_slave() free_string_array(&replicate_wild_ignore_table); } + static bool io_slave_killed(THD* thd, MASTER_INFO* mi) { DBUG_ASSERT(mi->io_thd == thd); @@ -667,6 +705,7 @@ static bool io_slave_killed(THD* thd, MASTER_INFO* mi) return mi->abort_slave || abort_loop || thd->killed; } + static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli) { DBUG_ASSERT(rli->sql_thd == thd); @@ -674,6 +713,7 @@ static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli) return rli->abort_slave || abort_loop || thd->killed; } + void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...) { va_list args; @@ -685,6 +725,7 @@ void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...) rli->last_slave_errno = err_code; } + void skip_load_data_infile(NET* net) { (void)my_net_write(net, "\xfb/dev/null", 10); @@ -693,6 +734,7 @@ void skip_load_data_infile(NET* net) send_ok(net); // the master expects it } + char* rewrite_db(char* db) { if (replicate_rewrite_db.is_empty() || !db) @@ -744,11 +786,11 @@ int db_ok(const char* db, I_List<i_string> &do_list, if (!strcmp(tmp->ptr, db)) return 0; // match } - return 1; } } + static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, const char *default_val) { @@ -777,6 +819,7 @@ static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, return 1; } + static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val) { char buf[32]; @@ -794,32 +837,12 @@ static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val) return 1; } + static int check_master_version(MYSQL* mysql, MASTER_INFO* mi) { - MYSQL_RES* res; - MYSQL_ROW row; - const char* version; - const char* errmsg = 0; + const char* errmsg= 0; - if (mc_mysql_query(mysql, "SELECT VERSION()", 0) - || !(res = mc_mysql_store_result(mysql))) - { - sql_print_error("Error checking master version: %s", - mc_mysql_error(mysql)); - return 1; - } - if (!(row = mc_mysql_fetch_row(res))) - { - errmsg = "Master returned no rows for SELECT VERSION()"; - goto err; - } - if (!(version = row[0])) - { - errmsg = "Master reported NULL for the version"; - goto err; - } - - switch (*version) { + switch (*mysql->server_version) { case '3': mi->old_format = 1; break; @@ -829,11 +852,9 @@ static int check_master_version(MYSQL* mysql, MASTER_INFO* mi) break; default: errmsg = "Master reported unrecognized MySQL version"; - goto err; + break; } err: - if (res) - mc_mysql_free_result(res); if (errmsg) { sql_print_error(errmsg); @@ -986,30 +1007,36 @@ int fetch_master_table(THD* thd, const char* db_name, const char* table_name, return error; } + void end_master_info(MASTER_INFO* mi) { + DBUG_ENTER("end_master_info"); + if (!mi->inited) - return; + DBUG_VOID_RETURN; end_relay_log_info(&mi->rli); if (mi->fd >= 0) - { - end_io_cache(&mi->file); - (void)my_close(mi->fd, MYF(MY_WME)); - mi->fd = -1; - } + { + end_io_cache(&mi->file); + (void)my_close(mi->fd, MYF(MY_WME)); + mi->fd = -1; + } mi->inited = 0; + + DBUG_VOID_RETURN; } + int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname) { - DBUG_ENTER("init_relay_log_info"); MY_STAT stat_area; char fname[FN_REFLEN+128]; int info_fd; const char* msg = 0; int error = 0; + DBUG_ENTER("init_relay_log_info"); - if (rli->inited) + if (rli->inited) // Set if this function called DBUG_RETURN(0); fn_format(fname, info_fname, mysql_data_home, "", 4+32); pthread_mutex_lock(&rli->data_lock); @@ -1022,6 +1049,7 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname) rli->skip_log_purge=0; rli->log_space_limit = relay_log_space_limit; rli->log_space_total = 0; + // TODO: make this work with multi-master if (!opt_relay_logname) { @@ -1034,11 +1062,12 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname) strmov(strcend(tmp,'.'),"-relay-bin"); opt_relay_logname=my_strdup(tmp,MYF(MY_WME)); } - rli->relay_log.set_index_file_name(opt_relaylog_index_name); - open_log(&rli->relay_log, glob_hostname, opt_relay_logname, "-relay-bin", - LOG_BIN, 1 /* read_append cache */, - 1 /* no auto events */); - + if (open_log(&rli->relay_log, glob_hostname, opt_relay_logname, + "-relay-bin", opt_relaylog_index_name, + LOG_BIN, 1 /* read_append cache */, + 1 /* no auto events */)) + DBUG_RETURN(1); + /* if file does not exist */ if (!my_stat(fname, &stat_area, MYF(0))) { @@ -1052,13 +1081,12 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname) init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0, MYF(MY_WME))) { - if (info_fd >= 0) - my_close(info_fd, MYF(0)); - rli->info_fd= -1; - pthread_mutex_unlock(&rli->data_lock); - DBUG_RETURN(1); + msg= current_thd->net.last_error; + goto err; } - if (init_relay_log_pos(rli,"",BIN_LOG_HEADER_SIZE,0 /*no data mutex*/, + + /* Init relay log with first entry in the relay index file */ + if (init_relay_log_pos(rli,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */, &msg)) goto err; rli->master_log_pos = 0; // uninitialized @@ -1075,6 +1103,7 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname) if (info_fd >= 0) my_close(info_fd, MYF(0)); rli->info_fd= -1; + rli->relay_log.close(1); pthread_mutex_unlock(&rli->data_lock); DBUG_RETURN(1); } @@ -1097,38 +1126,42 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname) rli->relay_log_pos= relay_log_pos; rli->master_log_pos= master_log_pos; - if (init_relay_log_pos(rli,0 /* log already inited */, - 0 /* pos already inited */, + if (init_relay_log_pos(rli, + rli->relay_log_name, + rli->relay_log_pos, 0 /* no data lock*/, &msg)) - goto err; + goto err; } DBUG_ASSERT(rli->relay_log_pos >= BIN_LOG_HEADER_SIZE); DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->relay_log_pos); - rli->inited = 1; /* Now change the cache from READ to WRITE - must do this before flush_relay_log_info */ reinit_io_cache(&rli->info_file, WRITE_CACHE,0L,0,1); - error=test(flush_relay_log_info(rli)); + error= flush_relay_log_info(rli); if (count_relay_log_space(rli)) { msg="Error counting relay log space"; goto err; } + rli->inited= 1; pthread_mutex_unlock(&rli->data_lock); DBUG_RETURN(error); err: sql_print_error(msg); end_io_cache(&rli->info_file); - my_close(info_fd, MYF(0)); + if (info_fd >= 0) + my_close(info_fd, MYF(0)); rli->info_fd= -1; + rli->relay_log.close(1); pthread_mutex_unlock(&rli->data_lock); DBUG_RETURN(1); } + static inline int add_relay_log(RELAY_LOG_INFO* rli,LOG_INFO* linfo) { MY_STAT s; @@ -1142,11 +1175,12 @@ static inline int add_relay_log(RELAY_LOG_INFO* rli,LOG_INFO* linfo) rli->log_space_total += s.st_size; #ifndef DBUG_OFF char buf[22]; -#endif DBUG_PRINT("info",("log_space_total: %s", llstr(rli->log_space_total,buf))); +#endif DBUG_RETURN(0); } + static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli) { bool slave_killed=0; @@ -1174,7 +1208,7 @@ static int count_relay_log_space(RELAY_LOG_INFO* rli) LOG_INFO linfo; DBUG_ENTER("count_relay_log_space"); rli->log_space_total = 0; - if (rli->relay_log.find_first_log(&linfo,"")) + if (rli->relay_log.find_log_pos(&linfo, NullS)) { sql_print_error("Could not find first log while counting relay log space"); DBUG_RETURN(1); @@ -1189,18 +1223,15 @@ static int count_relay_log_space(RELAY_LOG_INFO* rli) int init_master_info(MASTER_INFO* mi, const char* master_info_fname, - const char* slave_info_fname) + const char* slave_info_fname, + bool abort_if_no_master_info_file) { int fd,error; - MY_STAT stat_area; char fname[FN_REFLEN+128]; DBUG_ENTER("init_master_info"); if (mi->inited) DBUG_RETURN(0); - if (init_relay_log_info(&mi->rli, slave_info_fname)) - DBUG_RETURN(1); - mi->rli.mi = mi; mi->mysql=0; mi->file_id=1; mi->ignore_stop_event=0; @@ -1214,9 +1245,13 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, pthread_mutex_lock(&mi->data_lock); fd = mi->fd; - // we do not want any messages if the file does not exist - if (!my_stat(fname, &stat_area, MYF(0))) + if (access(fname,F_OK)) { + if (abort_if_no_master_info_file) + { + pthread_mutex_unlock(&mi->data_lock); + DBUG_RETURN(0); + } /* if someone removed the file from underneath our feet, just close the old descriptor and re-create the old file @@ -1281,6 +1316,11 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, DBUG_PRINT("master_info",("log_file_name: %s position: %ld", mi->master_log_name, (ulong) mi->master_log_pos)); + + if (init_relay_log_info(&mi->rli, slave_info_fname)) + goto err; + mi->rli.mi = mi; + mi->inited = 1; // now change cache READ -> WRITE - must do this before flush_master_info reinit_io_cache(&mi->file, WRITE_CACHE,0L,0,1); @@ -1289,7 +1329,6 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, DBUG_RETURN(error); err: - end_relay_log_info(&mi->rli); if (fd >= 0) { my_close(fd, MYF(0)); @@ -1300,6 +1339,7 @@ err: DBUG_RETURN(1); } + int register_slave_on_master(MYSQL* mysql) { String packet; @@ -1405,7 +1445,8 @@ int show_master_info(THD* thd, MASTER_INFO* mi) DBUG_RETURN(0); } -int flush_master_info(MASTER_INFO* mi) + +bool flush_master_info(MASTER_INFO* mi) { IO_CACHE* file = &mi->file; char lbuf[22]; @@ -1422,14 +1463,17 @@ int flush_master_info(MASTER_INFO* mi) DBUG_RETURN(0); } + int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, ulonglong log_pos) { - if (!inited) return -1; + if (!inited) + return -1; bool pos_reached = 0; int event_count = 0; pthread_mutex_lock(&data_lock); abort_pos_wait=0; // abort only if master info changes during wait + while (!thd->killed || !abort_pos_wait) { int cmp_result; @@ -1471,6 +1515,7 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, return thd->killed ? -1 : event_count; } + static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) { DBUG_ENTER("init_slave_thread"); @@ -1529,7 +1574,7 @@ static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed, { int nap_time = (int) (end_time - start_time); /* - the only reason we are asking for alarm is so that + The only reason we are asking for alarm is so that we will be woken up in case of murder, so if we do not get killed, set the alarm so it goes off after we wake up naturally */ @@ -1580,6 +1625,7 @@ static int request_dump(MYSQL* mysql, MASTER_INFO* mi, return 0; } + static int request_table_dump(MYSQL* mysql, const char* db, const char* table) { char buf[1024]; @@ -1608,6 +1654,7 @@ command"); return 0; } + /* read one event from the master @@ -1619,6 +1666,7 @@ command"); try a reconnect. We do not want to print anything to the error log in this case because this a anormal event in an idle server. + RETURN VALUES 'packet_error' Error number Length of packet @@ -1627,20 +1675,21 @@ command"); static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings) { - ulong len = packet_error; + ulong len; + *suppress_warnings= 0; /* my_real_read() will time us out We check if we were told to die, and if not, try reading again + + TODO: Move 'events_till_disconnect' to the MASTER_INFO structure */ #ifndef DBUG_OFF if (disconnect_slave_event_count && !(events_till_disconnect--)) return packet_error; #endif - *suppress_warnings= 0; len = mc_net_safe_read(mysql); - if (len == packet_error || (long) len < 1) { if (mc_mysql_errno(mysql) == ER_NET_READ_INTERRUPTED) @@ -1694,6 +1743,7 @@ point. If you are sure that your master is ok, run this query manually on the\ } } + static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) { DBUG_ASSERT(rli->sql_thd==thd); @@ -1706,7 +1756,15 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) int type_code = ev->get_type_code(); int exec_res; pthread_mutex_lock(&rli->data_lock); - if (ev->server_id == ::server_id || + + /* + Skip queries originating from this server or number of + queries specified by the user in slave_skip_counter + We can't however skip event's that has something to do with the + log files themselves. + */ + + if (ev->server_id == (uint32) ::server_id || (rli->slave_skip_counter && type_code != ROTATE_EVENT)) { /* TODO: I/O thread should not even log events with the same server id */ @@ -1750,6 +1808,7 @@ This may also be a network problem, or just a bug in the master or slave code.\ } } + /* slave I/O thread */ pthread_handler_decl(handle_slave_io,arg) { @@ -1760,7 +1819,7 @@ slave_begin: MYSQL *mysql = NULL ; MASTER_INFO* mi = (MASTER_INFO*)arg; char llbuff[22]; - bool retried_once = 0; + uint retry_count= 0; ulonglong last_failed_pos = 0; // TODO: see if last_failed_pos is needed DBUG_ASSERT(mi->inited); @@ -1771,7 +1830,7 @@ slave_begin: // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff my_thread_init(); - thd = new THD; // note that contructor of THD uses DBUG_ ! + thd= new THD; // note that contructor of THD uses DBUG_ ! DBUG_ENTER("handle_slave_io"); THD_CHECK_SENTRY(thd); @@ -1785,12 +1844,13 @@ slave_begin: } mi->io_thd = thd; thd->thread_stack = (char*)&thd; // remember where our stack is - thd->store_globals(); + pthread_mutex_lock(&LOCK_thread_count); threads.append(thd); + pthread_mutex_unlock(&LOCK_thread_count); mi->slave_running = 1; mi->abort_slave = 0; - pthread_cond_broadcast(&mi->start_cond); pthread_mutex_unlock(&mi->run_lock); + pthread_cond_broadcast(&mi->start_cond); DBUG_PRINT("master_info",("log_file_name: '%s' position: %s", mi->master_log_name, @@ -1804,9 +1864,6 @@ slave_begin: thd->proc_info = "connecting to master"; -#ifndef DBUG_OFF - sql_print_error("Slave I/O thread initialized"); -#endif // we can get killed during safe_connect if (!safe_connect(thd, mysql, mi)) sql_print_error("Slave I/O thread: connected to master '%s@%s:%d',\ @@ -1859,12 +1916,13 @@ dump"); right away - if first time fails, sleep between re-tries hopefuly the admin can fix the problem sometime */ - if (retried_once) + if (retry_count++) + { + if (retry_count > master_retry_count) + goto err; // Don't retry forever safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed, (void*)mi); - else - retried_once = 1; - + } if (io_slave_killed(thd,mi)) { sql_print_error("Slave I/O thread killed while retrying master \ @@ -1895,7 +1953,8 @@ after reconnect"); ulong event_len = read_event(mysql, mi, &suppress_warnings); if (io_slave_killed(thd,mi)) { - sql_print_error("Slave I/O thread killed while reading event"); + if (global_system_variables.log_warnings) + sql_print_error("Slave I/O thread killed while reading event"); goto err; } @@ -1903,24 +1962,27 @@ after reconnect"); { if (mc_mysql_errno(mysql) == ER_NET_PACKET_TOO_LARGE) { - sql_print_error("Log entry on master is longer than \ -max_allowed_packet (%ld) on slave. Slave thread will be aborted. If the entry \ -is correct, restart the server with a higher value of max_allowed_packet", + sql_print_error("\ +Log entry on master is longer than max_allowed_packet (%ld) on \ +slave. If the entry is correct, restart the server with a higher value of \ +max_allowed_packet", thd->variables.max_allowed_packet); goto err; } thd->proc_info = "Waiting to reconnect after a failed read"; mc_end_server(mysql); - if (retried_once) // punish repeat offender with sleep + if (retry_count++) + { + if (retry_count > master_retry_count) + goto err; // Don't retry forever safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed, - (void*)mi); - else - retried_once = 1; - + (void*) mi); + } if (io_slave_killed(thd,mi)) { - sql_print_error("Slave I/O thread killed while waiting to \ + if (global_system_variables.log_warnings) + sql_print_error("Slave I/O thread killed while waiting to \ reconnect after a failed read"); goto err; } @@ -1932,19 +1994,20 @@ reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME, if (safe_reconnect(thd, mysql, mi, suppress_warnings) || io_slave_killed(thd,mi)) { - sql_print_error("Slave I/O thread killed during or after a \ + if (global_system_variables.log_warnings) + sql_print_error("Slave I/O thread killed during or after a \ reconnect done to recover from failed read"); goto err; } goto connected; } // if (event_len == packet_error) + retry_count=0; // ok event, reset retry counter thd->proc_info = "Queueing event from master"; if (queue_event(mi,(const char*)mysql->net.read_pos + 1, event_len)) { - sql_print_error("Slave I/O thread could not queue event \ -from master"); + sql_print_error("Slave I/O thread could not queue event from master"); goto err; } flush_master_info(mi); @@ -1963,9 +2026,9 @@ log space"); sql_print_error("Slave I/O thread: debugging abort"); goto err; } -#endif +#endif } - } + } // error = 0; err: @@ -2010,7 +2073,7 @@ pthread_handler_decl(handle_slave_sql,arg) #ifndef DBUG_OFF slave_begin: #endif - THD *thd; /* needs to be first for thread_stack */ + THD *thd; /* needs to be first for thread_stack */ MYSQL *mysql = NULL ; bool retried_once = 0; ulonglong last_failed_pos = 0; // TODO: see if this can be removed @@ -2024,13 +2087,12 @@ slave_begin: rli->events_till_abort = abort_slave_event_count; #endif - // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff my_thread_init(); thd = new THD; // note that contructor of THD uses DBUG_ ! DBUG_ENTER("handle_slave_sql"); + THD_CHECK_SENTRY(thd); - pthread_detach_this_thread(); if (init_slave_thread(thd, SLAVE_THD_SQL)) { @@ -2043,24 +2105,28 @@ slave_begin: sql_print_error("Failed during slave thread initialization"); goto err; } - THD_CHECK_SENTRY(thd); - thd->thread_stack = (char*)&thd; // remember where our stack is + rli->sql_thd= thd; thd->temporary_tables = rli->save_temporary_tables; // restore temp tables - thd->store_globals(); + thd->thread_stack = (char*)&thd; // remember where our stack is + pthread_mutex_lock(&LOCK_thread_count); threads.append(thd); - rli->sql_thd = thd; + pthread_mutex_unlock(&LOCK_thread_count); rli->slave_running = 1; rli->abort_slave = 0; - pthread_cond_broadcast(&rli->start_cond); pthread_mutex_unlock(&rli->run_lock); + pthread_cond_broadcast(&rli->start_cond); // This should always be set to 0 when the slave thread is started rli->pending = 0; - if (init_relay_log_pos(rli,0,0,1 /*need data lock*/, &errmsg)) + if (init_relay_log_pos(rli, + rli->relay_log_name, + rli->relay_log_pos, + 1 /*need data lock*/, &errmsg)) { sql_print_error("Error initializing relay log position: %s", errmsg); goto err; } + THD_CHECK_SENTRY(thd); DBUG_ASSERT(rli->relay_log_pos >= BIN_LOG_HEADER_SIZE); DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->relay_log_pos); DBUG_ASSERT(rli->sql_thd == thd); @@ -2068,11 +2134,14 @@ slave_begin: DBUG_PRINT("master_info",("log_file_name: %s position: %s", rli->master_log_name, llstr(rli->master_log_pos,llbuff))); - - sql_print_error("Slave SQL thread initialized, starting replication in \ + if (global_system_variables.log_warnings) + sql_print_error("Slave SQL thread initialized, starting replication in \ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME, - llstr(rli->master_log_pos,llbuff),rli->relay_log_name, - llstr(rli->relay_log_pos,llbuff1)); + llstr(rli->master_log_pos,llbuff),rli->relay_log_name, + llstr(rli->relay_log_pos,llbuff1)); + + /* Read queries from the IO/THREAD until this thread is killed */ + while (!sql_slave_killed(thd,rli)) { thd->proc_info = "Processing master log event"; @@ -2089,14 +2158,14 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ RPL_LOG_NAME, llstr(rli->master_log_pos, llbuff)); goto err; } - } // while (!sql_slave_killed(thd,rli)) - read/exec loop + } - // error = 0; - err: - // print the current replication position + /* Thread stopped. Print the current replication position to the log */ sql_print_error("Slave SQL thread exiting, replication stopped in log \ '%s' at position %s", RPL_LOG_NAME, llstr(rli->master_log_pos,llbuff)); + + err: thd->query = thd->db = 0; // extra safety thd->proc_info = "Waiting for slave mutex on exit"; pthread_mutex_lock(&rli->run_lock); @@ -2114,7 +2183,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ net_end(&thd->net); // destructor will not free it, because we are weird DBUG_ASSERT(rli->sql_thd == thd); THD_CHECK_SENTRY(thd); - rli->sql_thd = 0; + rli->sql_thd= 0; pthread_mutex_lock(&LOCK_thread_count); THD_CHECK_SENTRY(thd); delete thd; @@ -2403,12 +2472,14 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len) void end_relay_log_info(RELAY_LOG_INFO* rli) { + DBUG_ENTER("end_relay_log_info"); + if (!rli->inited) - return; + DBUG_VOID_RETURN; if (rli->info_fd >= 0) { end_io_cache(&rli->info_file); - (void)my_close(rli->info_fd, MYF(MY_WME)); + (void) my_close(rli->info_fd, MYF(MY_WME)); rli->info_fd = -1; } if (rli->cur_log_fd >= 0) @@ -2420,6 +2491,7 @@ void end_relay_log_info(RELAY_LOG_INFO* rli) rli->inited = 0; rli->log_pos_current=0; rli->relay_log.close(1); + DBUG_VOID_RETURN; } /* try to connect until successful or slave killed */ @@ -2441,48 +2513,54 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi, int last_errno= -2; // impossible error ulong err_count=0; char llbuff[22]; + DBUG_ENTER("connect_to_master"); #ifndef DBUG_OFF events_till_disconnect = disconnect_slave_event_count; #endif + uint client_flag=0; + if (opt_slave_compressed_protocol) + client_flag=CLIENT_COMPRESS; /* We will use compression */ + while (!(slave_was_killed = io_slave_killed(thd,mi)) && - (reconnect ? mc_mysql_reconnect(mysql) != 0 : + (reconnect ? mc_mysql_reconnect(mysql) != 0: !mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0, - mi->port, 0, 0, + mi->port, 0, client_flag, thd->variables.net_read_timeout))) { /* Don't repeat last error */ if (mc_mysql_errno(mysql) != last_errno) { + last_errno=mc_mysql_errno(mysql); suppress_warnings= 0; sql_print_error("Slave I/O thread: error connecting to master \ '%s@%s:%d': \ -%s, last_errno=%d, retry in %d sec",mi->user,mi->host,mi->port, - mc_mysql_error(mysql), last_errno=mc_mysql_errno(mysql), +Error: '%s' errno: %d retry-time: %d",mi->user,mi->host,mi->port, + mc_mysql_error(mysql), last_errno, mi->connect_retry); } - safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed, - (void*)mi); /* By default we try forever. The reason is that failure will trigger master election, so if the user did not set master_retry_count we - do not want to have electioin triggered on the first failure to + do not want to have election triggered on the first failure to connect */ - if (master_retry_count && err_count++ == master_retry_count) + if (++err_count == master_retry_count) { slave_was_killed=1; if (reconnect) change_rpl_status(RPL_ACTIVE_SLAVE,RPL_LOST_SOLDIER); break; } + safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed, + (void*)mi); } if (!slave_was_killed) { if (reconnect) { - if (!suppress_warnings) + if (!suppress_warnings && global_system_variables.log_warnings) sql_print_error("Slave: connected to master '%s@%s:%d',\ replication resumed in log '%s' at position %s", mi->user, mi->host, mi->port, @@ -2499,8 +2577,8 @@ replication resumed in log '%s' at position %s", mi->user, thd->set_active_vio(mysql->net.vio); #endif } - - return slave_was_killed; + DBUG_PRINT("exit",("slave_was_killed: %d", slave_was_killed)); + DBUG_RETURN(slave_was_killed); } @@ -2516,19 +2594,61 @@ static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi, } -int flush_relay_log_info(RELAY_LOG_INFO* rli) +/* + Store the file and position where the execute-slave thread are in the + relay log. + + SYNOPSIS + flush_relay_log_info() + rli Relay log information + + NOTES + - As this is only called by the slave thread, we don't need to + have a lock on this. + - If there is an active transaction, then we don't update the position + in the relay log. This is to ensure that we re-execute statements + if we die in the middle of an transaction that was rolled back. + - As a transaction never spans binary logs, we don't have to handle the + case where we do a relay-log-rotation in the middle of the transaction. + If this would not be the case, we would have to ensure that we + don't delete the relay log file where the transaction started when + we switch to a new relay log file. + + TODO + - Change the log file information to a binary format to avoid calling + longlong2str. + + RETURN VALUES + 0 ok + 1 write error +*/ + +bool flush_relay_log_info(RELAY_LOG_INFO* rli) { - register IO_CACHE* file = &rli->info_file; - char lbuf[22],lbuf1[22]; - + bool error=0; + IO_CACHE *file = &rli->info_file; + char buff[FN_REFLEN*2+22*2+4], *pos; + + /* sql_thd is not set when calling from init_slave() */ + if ((rli->sql_thd && rli->sql_thd->options & OPTION_BEGIN)) + return 0; // Wait for COMMIT + my_b_seek(file, 0L); - my_b_printf(file, "%s\n%s\n%s\n%s\n", - rli->relay_log_name, llstr(rli->relay_log_pos, lbuf), - rli->master_log_name, llstr(rli->master_log_pos, lbuf1) - ); - flush_io_cache(file); - flush_io_cache(rli->cur_log); - return 0; + pos=strmov(buff, rli->relay_log_name); + *pos++='\n'; + pos=longlong2str(rli->relay_log_pos, pos, 10); + *pos++='\n'; + pos=strmov(pos, rli->master_log_name); + *pos++='\n'; + pos=longlong2str(rli->master_log_pos, pos, 10); + *pos='\n'; + if (my_b_write(file, buff, (ulong) (pos-buff)+1)) + error=1; + if (flush_io_cache(file)) + error=1; + if (flush_io_cache(rli->cur_log)) // QQ Why this call ? + error=1; + return error; } @@ -2644,12 +2764,8 @@ Log_event* next_event(RELAY_LOG_INFO* rli) update. If we do not, show slave status will block */ pthread_mutex_unlock(&rli->data_lock); - - /* - IMPORTANT: note that wait_for_update will unlock lock_log, but - expects the caller to lock it - */ rli->relay_log.wait_for_update(rli->sql_thd); + pthread_mutex_unlock(log_lock); // re-acquire data lock since we released it earlier pthread_mutex_lock(&rli->data_lock); @@ -2681,13 +2797,13 @@ Log_event* next_event(RELAY_LOG_INFO* rli) else { /* - TODO: verify that no lock is ok here. At this point, if we - get this wrong, this is actually no big deal - the only time - this code will ever be executed is if we are recovering from - a bug when a full reload of the slave is not feasible or - desirable. + If hot_log is set, then we already have a lock on + LOCK_log. If not, we have to get the lock. + + According to Sasha, the only time this code will ever be executed + is if we are recovering from a bug. */ - if (rli->relay_log.find_next_log(&rli->linfo,0/*no lock*/)) + if (rli->relay_log.find_next_log(&rli->linfo, !hot_log)) { errmsg = "error switching to the next log"; goto err; @@ -2746,16 +2862,16 @@ event(errno: %d cur_log->error: %d)", my_b_seek(cur_log,rli->relay_log_pos+rli->pending); /* otherwise, we have had a partial read */ errmsg = "Aborting slave SQL thread because of partial event read"; - /* TODO; see if there is a way to do this without this goto */ - goto err; + break; // To end of function } } - if (!errmsg && was_killed) + if (!errmsg && global_system_variables.log_warnings) errmsg = "slave SQL thread was killed"; err: pthread_mutex_unlock(&rli->data_lock); - sql_print_error("Error reading relay log event: %s", errmsg); + if (errmsg) + sql_print_error("Error reading relay log event: %s", errmsg); DBUG_RETURN(0); } diff --git a/sql/slave.h b/sql/slave.h index e6a5e86bb10..c59ab03c275 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -139,6 +139,14 @@ typedef struct st_relay_log_info ulonglong log_space_limit,log_space_total; /* + InnoDB internally stores the master log position it has processed + so far; the position to store is really the sum of + pos + pending + event_len here since we must store the pos of the + END of the current log event + */ + int event_len; + + /* Needed for problems when slave stops and we want to restart it skipping one or more events in the master log that have caused errors, and have been manually applied by DBA already. @@ -167,6 +175,7 @@ typedef struct st_relay_log_info { relay_log_name[0] = master_log_name[0] = 0; bzero(&info_file,sizeof(info_file)); + bzero(&cache_buf, sizeof(cache_buf)); pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST); pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST); pthread_mutex_init(&log_space_lock, MY_MUTEX_INIT_FAST); @@ -204,7 +213,7 @@ typedef struct st_relay_log_info } /* thread safe read of position - not needed if we are in the slave thread, - but required otherwise + but required otherwise as var is a longlong */ inline void read_pos(ulonglong& var) { @@ -216,6 +225,7 @@ typedef struct st_relay_log_info int wait_for_pos(THD* thd, String* log_name, ulonglong log_pos); } RELAY_LOG_INFO; + Log_event* next_event(RELAY_LOG_INFO* rli); /* @@ -251,16 +261,7 @@ typedef struct st_master_info char master_log_name[FN_REFLEN]; my_off_t master_log_pos; - File fd; - - /* - InnoDB internally stores the master log position it has processed - so far; the position to store is really the sum of - pos + pending + event_len here since we must store the pos of the - END of the current log event -*/ - int event_len; - File fd; + File fd; // we keep the file open, so we need to remember the file pointer IO_CACHE file; /* the variables below are needed because we can change masters on the fly */ @@ -288,7 +289,7 @@ typedef struct st_master_info slave_running(0) { host[0] = 0; user[0] = 0; password[0] = 0; - bzero(&file,sizeof(file)); + bzero(&file, sizeof(file)); pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST); pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST); pthread_cond_init(&data_cond, NULL); @@ -337,8 +338,8 @@ typedef struct st_table_rule_ent int init_slave(); void init_slave_skip_errors(const char* arg); -int flush_master_info(MASTER_INFO* mi); -int flush_relay_log_info(RELAY_LOG_INFO* rli); +bool flush_master_info(MASTER_INFO* mi); +bool flush_relay_log_info(RELAY_LOG_INFO* rli); int register_slave_on_master(MYSQL* mysql); int terminate_slave_threads(MASTER_INFO* mi, int thread_mask, bool skip_lock = 0); @@ -393,7 +394,8 @@ void slave_print_error(RELAY_LOG_INFO* rli,int err_code, const char* msg, ...); void end_slave(); /* clean up */ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, - const char* slave_info_fname); + const char* slave_info_fname, + bool abort_if_no_master_info_file); void end_master_info(MASTER_INFO* mi); int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname); void end_relay_log_info(RELAY_LOG_INFO* rli); @@ -403,7 +405,8 @@ void init_thread_mask(int* mask,MASTER_INFO* mi,bool inverse); int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,ulonglong pos, bool need_data_lock, const char** errmsg); -int purge_relay_logs(RELAY_LOG_INFO* rli,bool just_reset,const char** errmsg); +int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset, + const char** errmsg); extern bool opt_log_slave_updates ; pthread_handler_decl(handle_slave_io,arg); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 0b02935e96c..e2d462aa73c 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -497,10 +497,14 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, ulong user_access=NO_ACCESS; *priv_user=(char*) user; char *ptr=0; + DBUG_ENTER("acl_getroot"); bzero(mqh,sizeof(USER_RESOURCES)); if (!initialized) - return (ulong) ~NO_ACCESS; // If no data allow anything /* purecov: tested */ + { + // If no data allow anything + DBUG_RETURN((ulong) ~NO_ACCESS); /* purecov: tested */ + } VOID(pthread_mutex_lock(&acl_cache->lock)); /* @@ -616,7 +620,7 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, } } VOID(pthread_mutex_unlock(&acl_cache->lock)); - return user_access; + DBUG_RETURN(user_access); } @@ -1053,15 +1057,14 @@ bool change_password(THD *thd, const char *host, const char *user, VOID(pthread_mutex_unlock(&acl_cache->lock)); char buff[460]; - - Query_log_event qinfo(thd, buff); - qinfo.q_len = + ulong query_length= my_sprintf(buff, (buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"", acl_user->user ? acl_user->user : "", acl_user->host.hostname ? acl_user->host.hostname : "", new_password)); - mysql_update_log.write(thd,buff,qinfo.q_len); + mysql_update_log.write(thd, buff, query_length); + Query_log_event qinfo(thd, buff, query_length); mysql_bin_log.write(&qinfo); DBUG_RETURN(0); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 29cc925218f..58d251162ff 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -279,6 +279,7 @@ void intern_close_table(TABLE *table) static void free_cache_entry(TABLE *table) { DBUG_ENTER("free_cache_entry"); + safe_mutex_assert_owner(&LOCK_open); intern_close_table(table); if (!table->in_use) @@ -425,6 +426,7 @@ void close_thread_tables(THD *thd, bool locked) /* VOID(pthread_sigmask(SIG_SETMASK,&thd->block_signals,NULL)); */ if (!locked) VOID(pthread_mutex_lock(&LOCK_open)); + safe_mutex_assert_owner(&LOCK_open); DBUG_PRINT("info", ("thd->open_tables=%p", thd->open_tables)); @@ -550,13 +552,10 @@ void close_temporary_tables(THD *thd) } if (query && found_user_tables && mysql_bin_log.is_open()) { - uint save_query_len = thd->query_length; - *--end = 0; // Remove last ',' - thd->query_length = (uint)(end-query); - Query_log_event qinfo(thd, query); + /* The -1 is to remove last ',' */ + Query_log_event qinfo(thd, query, (ulong)(end-query)-1); qinfo.error_code=0; mysql_bin_log.write(&qinfo); - thd->query_length = save_query_len; } thd->temporary_tables=0; } @@ -669,11 +668,13 @@ TABLE *unlink_open_table(THD *thd, TABLE *list, TABLE *find) /* When we call the following function we must have a lock on - LOCK_OPEN ; This lock will be unlocked on return. + LOCK_open ; This lock will be unlocked on return. */ void wait_for_refresh(THD *thd) { + safe_mutex_assert_owner(&LOCK_open); + /* Wait until the current table is up to date */ const char *proc_info; thd->mysys_var->current_mutex= &LOCK_open; @@ -931,6 +932,7 @@ bool reopen_table(TABLE *table,bool locked) #endif if (!locked) VOID(pthread_mutex_lock(&LOCK_open)); + safe_mutex_assert_owner(&LOCK_open); if (open_unireg_entry(current_thd,&tmp,db,table_name,table->table_name, locked)) @@ -1022,6 +1024,8 @@ bool close_data_tables(THD *thd,const char *db, const char *table_name) bool reopen_tables(THD *thd,bool get_locks,bool in_refresh) { DBUG_ENTER("reopen_tables"); + safe_mutex_assert_owner(&LOCK_open); + if (!thd->open_tables) DBUG_RETURN(0); @@ -1259,6 +1263,8 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, table_list.next=0; if (!locked) pthread_mutex_lock(&LOCK_open); + safe_mutex_assert_owner(&LOCK_open); + if ((error=lock_table_name(thd,&table_list))) { if (error < 0) diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index cba9f17359a..0c8716120da 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -873,10 +873,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) || thd->variables.query_cache_type == 0) - { - DBUG_PRINT("qcache", ("query cache disabled or not in autocommit mode")); goto err; - } /* Check that we haven't forgot to reset the query cache variables */ DBUG_ASSERT(thd->net.query_cache_query == 0); @@ -1021,6 +1018,7 @@ err: DBUG_RETURN(0); // Query was not cached } + /* Remove all cached queries that uses any of the tables in the list */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 633f7a4aa76..6a3daae6274 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -47,7 +47,7 @@ struct st_relay_log_info; typedef struct st_log_info { char log_file_name[FN_REFLEN]; - my_off_t index_file_offset; + my_off_t index_file_offset, index_file_start_offset; my_off_t pos; bool fatal; // if the purge happens to give us a negative offset pthread_mutex_t lock; @@ -64,7 +64,7 @@ class MYSQL_LOG { ulonglong bytes_written; time_t last_time,query_start; IO_CACHE log_file; - File index_file; + IO_CACHE index_file; char *name; char time_buff[20],db[NAME_LEN+1]; char log_file_name[FN_REFLEN],index_file_name[FN_REFLEN]; @@ -106,16 +106,14 @@ public: void signal_update() { pthread_cond_broadcast(&update_cond);} void wait_for_update(THD* thd); void set_need_start_event() { need_start_event = 1; } - void set_index_file_name(const char* index_file_name = 0); void init(enum_log_type log_type_arg, enum cache_type io_cache_type_arg = WRITE_CACHE, bool no_auto_events_arg = 0); - void open(const char *log_name,enum_log_type log_type, - const char *new_name, enum cache_type io_cache_type_arg, + bool open(const char *log_name,enum_log_type log_type, + const char *new_name, const char *index_file_name_arg, + enum cache_type io_cache_type_arg, bool no_auto_events_arg); - void new_file(bool inside_mutex = 0); - bool open_index(int options); - void close_index(); + void new_file(bool need_lock= 1); bool write(THD *thd, enum enum_server_command command, const char *format,...); bool write(THD *thd, const char *query, uint query_length, @@ -135,13 +133,13 @@ public: bool is_active(const char* log_file_name); int purge_logs(THD* thd, const char* to_log); int purge_first_log(struct st_relay_log_info* rli); - int reset_logs(THD* thd); + bool reset_logs(THD* thd); // if we are exiting, we also want to close the index file void close(bool exiting = 0); // iterating through the log index file - int find_first_log(LOG_INFO* linfo, const char* log_name, - bool need_mutex=1); + int find_log_pos(LOG_INFO* linfo, const char* log_name, + bool need_mutex=1); int find_next_log(LOG_INFO* linfo, bool need_mutex=1); int get_current_log(LOG_INFO* linfo); uint next_file_id(); @@ -154,7 +152,7 @@ public: inline void lock_index() { pthread_mutex_lock(&LOCK_index);} inline void unlock_index() { pthread_mutex_unlock(&LOCK_index);} - inline File get_index_file() { return index_file;} + inline IO_CACHE *get_index_file() { return &index_file;} inline uint32 get_open_count() { return open_count; } }; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 87926d0612c..0e2cfba1b30 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -85,7 +85,7 @@ int mysql_create_db(THD *thd, char *db, uint create_options, bool silent) mysql_update_log.write(thd,thd->query, thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query); + Query_log_event qinfo(thd, thd->query, thd->query_length); mysql_bin_log.write(&qinfo); } } @@ -153,7 +153,9 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) send_ok(&thd->net,0); goto exit; } + pthread_mutex_lock(&LOCK_open); remove_db_from_cache(db); + pthread_mutex_unlock(&LOCK_open); error = -1; if ((deleted=mysql_rm_known_files(thd, dirp, db, path,0)) >= 0 && thd) @@ -171,7 +173,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) mysql_update_log.write(thd, thd->query, thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query); + Query_log_event qinfo(thd, thd->query, thd->query_length); mysql_bin_log.write(&qinfo); } if (thd->query == path) diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 8788a1576dc..86a1c2bbdfc 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -167,7 +167,8 @@ cleanup: mysql_update_log.write(thd,thd->query, thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, using_transactions); + Query_log_event qinfo(thd, thd->query, thd->query_length, + using_transactions); if (mysql_bin_log.write(&qinfo) && using_transactions) error=1; } @@ -468,7 +469,7 @@ bool multi_delete::send_eof() mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query); + Query_log_event qinfo(thd, thd->query, thd->query_length); if (mysql_bin_log.write(&qinfo) && !not_trans_safe) error=1; // Log write failed: roll back the SQL statement @@ -570,7 +571,7 @@ end: mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query); + Query_log_event qinfo(thd, thd->query, thd->query_length); mysql_bin_log.write(&qinfo); } send_ok(&thd->net); // This should return record count diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 053e96c5fdd..61d3544bfe0 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -301,7 +301,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, mysql_update_log.write(thd, thd->query, thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, using_transactions); + Query_log_event qinfo(thd, thd->query, thd->query_length, + using_transactions); if (mysql_bin_log.write(&qinfo) && using_transactions) error=1; } @@ -1196,8 +1197,7 @@ bool delayed_insert::handle_inserts(void) mysql_update_log.write(&thd,row->query, row->query_length); if (using_bin_log) { - thd.query_length = row->query_length; - Query_log_event qinfo(&thd, row->query); + Query_log_event qinfo(&thd, row->query, row->query_length); mysql_bin_log.write(&qinfo); } } @@ -1377,7 +1377,7 @@ bool select_insert::send_eof() mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, + Query_log_event qinfo(thd, thd->query, thd->query_length, table->file->has_transactions()); mysql_bin_log.write(&qinfo); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 46ef9e90b7d..63ba886d86f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -24,7 +24,7 @@ #include <assert.h> #ifdef HAVE_INNOBASE_DB -#include "ha_innobase.h" +#include "ha_innodb.h" #endif #ifdef HAVE_OPENSSL @@ -1428,13 +1428,16 @@ mysql_execute_command(void) case SQLCOM_LOAD_MASTER_DATA: // sync with master if (check_global_access(thd, SUPER_ACL)) goto error; - res = load_master_data(thd); + if (end_active_trans(thd)) + res= -1; + else + res = load_master_data(thd); break; #ifdef HAVE_INNOBASE_DB case SQLCOM_SHOW_INNODB_STATUS: { - if (check_process_priv(thd)) + if (check_global_access(thd, SUPER_ACL)) goto error; res = innodb_show_status(thd); break; @@ -2319,7 +2322,7 @@ mysql_execute_command(void) mysql_update_log.write(thd, thd->query, thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query); + Query_log_event qinfo(thd, thd->query, thd->query_length); mysql_bin_log.write(&qinfo); } } @@ -2339,7 +2342,7 @@ mysql_execute_command(void) mysql_update_log.write(thd, thd->query, thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query); + Query_log_event qinfo(thd, thd->query, thd->query_length); mysql_bin_log.write(&qinfo); } if (mqh_used && lex->sql_command == SQLCOM_GRANT) @@ -3325,8 +3328,6 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables) bool result=0; select_errors=0; /* Write if more errors */ - // TODO: figure out what's up with the commented out line below - // mysql_log.flush(); // Flush log if (options & REFRESH_GRANT) { acl_reload(); @@ -3382,7 +3383,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables) if (options & REFRESH_SLAVE) { LOCK_ACTIVE_MI; - if (reset_slave(active_mi)) + if (reset_slave(thd, active_mi)) result=1; UNLOCK_ACTIVE_MI; } diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 305491c7346..049690eb318 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -94,7 +94,7 @@ end: mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query); + Query_log_event qinfo(thd, thd->query, thd->query_length); mysql_bin_log.write(&qinfo); } send_ok(&thd->net); diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 3e652a4d5a6..9cc596f9bb5 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -180,6 +180,27 @@ err: } +/* + Adjust the position pointer in the binary log file for all running slaves + + SYNOPSIS + adjust_linfo_offsets() + purge_offset Number of bytes removed from start of log index file + + NOTES + - This is called when doing a PURGE when we delete lines from the + index log file + + REQUIREMENTS + - Before calling this function, we have to ensure that no threads are + using any binary log file before purge_offset.a + + TODO + - Inform the slave threads that they should sync the position + in the binary log file with flush_relay_log_info. + Now they sync is done for next read. +*/ + void adjust_linfo_offsets(my_off_t purge_offset) { THD *tmp; @@ -193,9 +214,10 @@ void adjust_linfo_offsets(my_off_t purge_offset) if ((linfo = tmp->current_linfo)) { pthread_mutex_lock(&linfo->lock); - /* index file offset can be less that purge offset - only if we just started reading the index file. In that case - we have nothing to adjust + /* + Index file offset can be less that purge offset only if + we just started reading the index file. In that case + we have nothing to adjust */ if (linfo->index_file_offset < purge_offset) linfo->fatal = (linfo->index_file_offset != 0); @@ -274,7 +296,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) { LOG_INFO linfo; char *log_file_name = linfo.log_file_name; - char search_file_name[FN_REFLEN]; + char search_file_name[FN_REFLEN], *name; IO_CACHE log; File file = -1; String* packet = &thd->packet; @@ -295,7 +317,6 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) } #endif - if (!mysql_bin_log.is_open()) { errmsg = "Binary log is not open"; @@ -307,17 +328,18 @@ void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags) goto err; } + name=search_file_name; if (log_ident[0]) mysql_bin_log.make_log_name(search_file_name, log_ident); else - search_file_name[0] = 0; + name=0; // Find first log linfo.index_file_offset = 0; thd->current_linfo = &linfo; - if (mysql_bin_log.find_first_log(&linfo, search_file_name)) + if (mysql_bin_log.find_log_pos(&linfo, name)) { - errmsg = "Could not find first log"; + errmsg = "Could not find first log file name in binary log index file"; goto err; } @@ -332,19 +354,19 @@ impossible position"; } my_b_seek(&log, pos); // Seek will done on next read - packet->length(0); - // we need to start a packet with something other than 255 - // to distiquish it from error - packet->append("\0", 1); + /* + We need to start a packet with something other than 255 + to distiquish it from error + */ + packet->set("\0", 1); // if we are at the start of the log - if (pos == 4) + if (pos == BIN_LOG_HEADER_SIZE) { // tell the client log name with a fake rotate_event if (fake_rotate_event(net, packet, log_file_name, &errmsg)) goto err; - packet->length(0); - packet->append("\0", 1); + packet->set("\0", 1); } while (!net->error && net->vio != 0 && !thd->killed) @@ -376,20 +398,21 @@ impossible position"; goto err; } } - packet->length(0); - packet->append("\0",1); + packet->set("\0", 1); } - // TODO: now that we are logging the offset, check to make sure - // the recorded offset and the actual match + /* + TODO: now that we are logging the offset, check to make sure + the recorded offset and the actual match + */ if (error != LOG_READ_EOF) { - switch(error) { + switch (error) { case LOG_READ_BOGUS: errmsg = "bogus data in log event"; break; case LOG_READ_TOO_LARGE: - errmsg = "log event entry exceeded max_allowed_packet -\ - increase max_allowed_packet on master"; + errmsg = "log event entry exceeded max_allowed_packet; \ +Increase max_allowed_packet on master"; break; case LOG_READ_IO: errmsg = "I/O error reading log event"; @@ -410,18 +433,21 @@ impossible position"; if (!(flags & BINLOG_DUMP_NON_BLOCK) && mysql_bin_log.is_active(log_file_name)) { - // block until there is more data in the log - // unless non-blocking mode requested + /* + Block until there is more data in the log + */ if (net_flush(net)) { errmsg = "failed on net_flush()"; goto err; } - // we may have missed the update broadcast from the log - // that has just happened, let's try to catch it if it did - // if we did not miss anything, we just wait for other threads - // to signal us + /* + We may have missed the update broadcast from the log + that has just happened, let's try to catch it if it did. + If we did not miss anything, we just wait for other threads + to signal us. + */ { log.error=0; bool read_packet = 0, fatal_error = 0; @@ -435,32 +461,32 @@ impossible position"; } #endif - // no one will update the log while we are reading - // now, but we'll be quick and just read one record + /* + No one will update the log while we are reading + now, but we'll be quick and just read one record + + To be able to handle EOF properly, we have to have the + pthread_mutex_unlock() statements in the case statements. + */ pthread_mutex_lock(log_lock); - switch (Log_event::read_log_event(&log, packet, (pthread_mutex_t*)0)) - { + switch (Log_event::read_log_event(&log, packet, (pthread_mutex_t*)0)) { case 0: - pthread_mutex_unlock(log_lock); + /* we read successfully, so we'll need to send it to the slave */ read_packet = 1; - // we read successfully, so we'll need to send it to the - // slave break; + case LOG_READ_EOF: DBUG_PRINT("wait",("waiting for data in binary log")); - // wait_for_update unlocks the log lock - needed to avoid race if (!thd->killed) mysql_bin_log.wait_for_update(thd); - else - pthread_mutex_unlock(log_lock); DBUG_PRINT("wait",("binary log received update")); break; default: - pthread_mutex_unlock(log_lock); fatal_error = 1; break; } + pthread_mutex_unlock(log_lock); if (read_packet) { @@ -479,10 +505,11 @@ impossible position"; goto err; } } - packet->length(0); - packet->append("\0",1); - // no need to net_flush because we will get to flush later when - // we hit EOF pretty quick + packet->set("\0", 1); + /* + No need to net_flush because we will get to flush later when + we hit EOF pretty quick + */ } if (fatal_error) @@ -539,7 +566,6 @@ impossible position"; err: thd->proc_info = "waiting to finalize termination"; end_io_cache(&log); - pthread_mutex_lock(&LOCK_thread_count); /* Exclude iteration through thread list this is needed for purge_logs() - it will iterate through @@ -547,6 +573,7 @@ impossible position"; this mutex will make sure that it never tried to update our linfo after we return from this stack frame */ + pthread_mutex_lock(&LOCK_thread_count); thd->current_linfo = 0; pthread_mutex_unlock(&LOCK_thread_count); if (file >= 0) @@ -561,16 +588,19 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report) if (!thd) thd = current_thd; NET* net = &thd->net; int thread_mask; + DBUG_ENTER("start_slave"); if (check_access(thd, SUPER_ACL, any_db)) - return 1; + DBUG_RETURN(1); lock_slave_threads(mi); // this allows us to cleanly read slave_running init_thread_mask(&thread_mask,mi,1 /* inverse */); if (thd->lex.slave_thd_opt) thread_mask &= thd->lex.slave_thd_opt; if (thread_mask) { - if (server_id_supplied && (!mi->inited || (mi->inited && *mi->host))) + if (init_master_info(mi,master_info_file,relay_log_info_file, 0)) + slave_errno=ER_MASTER_INFO; + else if (server_id_supplied && *mi->host) slave_errno = start_slave_threads(0 /*no mutex */, 1 /* wait for start */, mi, @@ -588,12 +618,12 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report) { if (net_report) send_error(net, slave_errno); - return 1; + DBUG_RETURN(1); } else if (net_report) send_ok(net); - return 0; + DBUG_RETURN(0); } int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report ) @@ -628,7 +658,7 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report ) return 0; } -int reset_slave(MASTER_INFO* mi) +int reset_slave(THD *thd, MASTER_INFO* mi) { MY_STAT stat_area; char fname[FN_REFLEN]; @@ -639,7 +669,9 @@ int reset_slave(MASTER_INFO* mi) lock_slave_threads(mi); init_thread_mask(&restart_thread_mask,mi,0 /* not inverse */); if ((error=terminate_slave_threads(mi,restart_thread_mask,1 /*skip lock*/)) - || (error=purge_relay_logs(&mi->rli,1 /*just reset*/,&errmsg))) + || (error=purge_relay_logs(&mi->rli, thd, + 1 /* just reset */, + &errmsg))) goto err; end_master_info(mi); @@ -713,16 +745,17 @@ int change_master(THD* thd, MASTER_INFO* mi) thd->proc_info = "changing master"; LEX_MASTER_INFO* lex_mi = &thd->lex.mi; // TODO: see if needs re-write - if (init_master_info(mi,master_info_file,relay_log_info_file)) + if (init_master_info(mi, master_info_file, relay_log_info_file, 0)) { send_error(&thd->net, 0, "Could not initialize master info"); unlock_slave_threads(mi); DBUG_RETURN(1); } - /* data lock not needed since we have already stopped the running threads, - and we have the hold on the run locks which will keep all threads that - could possibly modify the data structures from running + /* + Data lock not needed since we have already stopped the running threads, + and we have the hold on the run locks which will keep all threads that + could possibly modify the data structures from running */ if ((lex_mi->host || lex_mi->port) && !lex_mi->log_file_name && !lex_mi->pos) { @@ -772,7 +805,8 @@ int change_master(THD* thd, MASTER_INFO* mi) { mi->rli.skip_log_purge=0; thd->proc_info="purging old relay logs"; - if (purge_relay_logs(&mi->rli,0 /* not only reset, but also reinit*/, + if (purge_relay_logs(&mi->rli, thd, + 0 /* not only reset, but also reinit */, &errmsg)) { net_printf(&thd->net, 0, "Failed purging old relay logs: %s",errmsg); @@ -782,12 +816,13 @@ int change_master(THD* thd, MASTER_INFO* mi) else { const char* msg; - if (init_relay_log_pos(&mi->rli,0/*log already inited*/, - 0 /*pos already inited*/, + /* Relay log is already initialized */ + if (init_relay_log_pos(&mi->rli, + mi->rli.relay_log_name, + mi->rli.relay_log_pos, 0 /*no data lock*/, &msg)) { - //Sasha: note that I had to change net_printf() to make this work net_printf(&thd->net,0,"Failed initializing relay log position: %s",msg); unlock_slave_threads(mi); DBUG_RETURN(1); @@ -857,26 +892,27 @@ int show_binlog_events(THD* thd) if (mysql_bin_log.is_open()) { - LOG_INFO linfo; - char search_file_name[FN_REFLEN]; - LEX_MASTER_INFO* lex_mi = &thd->lex.mi; + LEX_MASTER_INFO *lex_mi = &thd->lex.mi; uint event_count, limit_start, limit_end; - const char* log_file_name = lex_mi->log_file_name; - Log_event* ev; my_off_t pos = lex_mi->pos; + char search_file_name[FN_REFLEN], *name; + const char *log_file_name = lex_mi->log_file_name; + LOG_INFO linfo; + Log_event* ev; limit_start = thd->lex.select->offset_limit; limit_end = thd->lex.select->select_limit + limit_start; + name= search_file_name; if (log_file_name) mysql_bin_log.make_log_name(search_file_name, log_file_name); else - search_file_name[0] = 0; + name=0; // Find first log linfo.index_file_offset = 0; thd->current_linfo = &linfo; - if (mysql_bin_log.find_first_log(&linfo, search_file_name)) + if (mysql_bin_log.find_log_pos(&linfo, name)) { errmsg = "Could not find target log"; goto err; @@ -981,71 +1017,65 @@ int show_binlog_info(THD* thd) } +/* + Send a lost of all binary logs to client + + SYNOPSIS + show_binlogs() + thd Thread specific variable + + RETURN VALUES + 0 ok + 1 error (Error message sent to client) +*/ + int show_binlogs(THD* thd) { - const char* errmsg = 0; - File index_file; + const char *errmsg; + IO_CACHE *index_file; char fname[FN_REFLEN]; NET* net = &thd->net; List<Item> field_list; - String* packet = &thd->packet; - IO_CACHE io_cache; + String *packet = &thd->packet; uint length; if (!mysql_bin_log.is_open()) { - errmsg = "binlog is not open"; - goto err; + //TODO: Replace with ER() error message + errmsg= "You are not using binary logging"; + goto err_with_msg; } - field_list.push_back(new Item_empty_string("Log_name", 128)); + field_list.push_back(new Item_empty_string("Log_name", 255)); if (send_fields(thd, field_list, 1)) - { - sql_print_error("Failed in send_fields"); return 1; - } - mysql_bin_log.lock_index(); - index_file = mysql_bin_log.get_index_file(); - if (index_file < 0) - { - errmsg = "Uninitialized index file pointer"; - goto err2; - } - if (init_io_cache(&io_cache, index_file, IO_SIZE, READ_CACHE, 0, 0, - MYF(MY_WME))) - { - errmsg = "Failed on init_io_cache()"; - goto err2; - } - while ((length=my_b_gets(&io_cache, fname, sizeof(fname)))) + index_file=mysql_bin_log.get_index_file(); + + reinit_io_cache(index_file, READ_CACHE, (my_off_t) 0, 0, 0); + + /* The file ends with EOF or empty line */ + while ((length=my_b_gets(index_file, fname, sizeof(fname))) > 1) { - fname[--length]=0; int dir_len = dirname_length(fname); packet->length(0); - net_store_data(packet, fname + dir_len, length-dir_len); + /* The -1 is for removing newline from fname */ + net_store_data(packet, fname + dir_len, length-1-dir_len); if (my_net_write(net, (char*) packet->ptr(), packet->length())) - { - sql_print_error("Failed in my_net_write"); - end_io_cache(&io_cache); - mysql_bin_log.unlock_index(); - return 1; - } + goto err; } - mysql_bin_log.unlock_index(); - end_io_cache(&io_cache); send_eof(net); return 0; -err2: - mysql_bin_log.unlock_index(); - end_io_cache(&io_cache); -err: +err_with_msg: send_error(net, 0, errmsg); +err: + mysql_bin_log.unlock_index(); return 1; } + int log_loaded_block(IO_CACHE* file) { LOAD_FILE_INFO* lf_info; diff --git a/sql/sql_repl.h b/sql/sql_repl.h index 6770f8aa01a..af4fb33c9ef 100644 --- a/sql/sql_repl.h +++ b/sql/sql_repl.h @@ -31,7 +31,7 @@ int change_master(THD* thd, MASTER_INFO* mi); int show_binlog_events(THD* thd); int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1, const char* log_file_name2, ulonglong log_pos2); -int reset_slave(MASTER_INFO* mi); +int reset_slave(THD *thd, MASTER_INFO* mi); int reset_master(THD* thd); int purge_master_logs(THD* thd, const char* to_log); bool log_in_use(const char* log_name); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2f12d7d1012..0f0118be1fe 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5781,7 +5781,6 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having) ulong reclength,offset; uint field_count; THD *thd= current_thd; - DBUG_ENTER("remove_duplicates"); entry->reginfo.lock_type=TL_WRITE; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index ef2bb807efd..df84bff0adc 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -20,6 +20,7 @@ #include "mysql_priv.h" #include <hash.h> #include <myisam.h> +#include <assert.h> #ifdef __WIN__ #include <io.h> @@ -181,7 +182,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, mysql_update_log.write(thd, thd->query,thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query); + Query_log_event qinfo(thd, thd->query, thd->query_length); mysql_bin_log.write(&qinfo); } } @@ -670,7 +671,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, mysql_update_log.write(thd,thd->query, thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query); + Query_log_event qinfo(thd, thd->query, thd->query_length); mysql_bin_log.write(&qinfo); } } @@ -834,6 +835,8 @@ bool close_cached_table(THD *thd,TABLE *table) { bool result=0; DBUG_ENTER("close_cached_table"); + safe_mutex_assert_owner(&LOCK_open); + if (table) { DBUG_PRINT("enter",("table: %s", table->table_name)); @@ -918,13 +921,17 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table, fn_format(dst_path, dst_path,"", reg_ext, 4), MYF(MY_WME))) { + pthread_mutex_lock(&LOCK_open); unlock_table_name(thd, table); + pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(send_check_errmsg(thd, table, "restore", "Failed copying .frm file")); } if (mysql_truncate(thd, table, 1)) { + pthread_mutex_lock(&LOCK_open); unlock_table_name(thd, table); + pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(send_check_errmsg(thd, table, "restore", "Failed generating table from .frm file")); } @@ -935,7 +942,11 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table, to finish the restore in the handler later on */ if (!(table->table = reopen_name_locked_table(thd, table))) + { + pthread_mutex_lock(&LOCK_open); unlock_table_name(thd, table); + pthread_mutex_unlock(&LOCK_open); + } DBUG_RETURN(0); } @@ -1000,7 +1011,8 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, thr_lock_type lock_type, bool open_for_modify, uint extra_open_options, - int (*prepare_func)(THD *, TABLE_LIST *, HA_CHECK_OPT *), + int (*prepare_func)(THD *, TABLE_LIST *, + HA_CHECK_OPT *), int (handler::*operator_func) (THD *, HA_CHECK_OPT *)) { @@ -1141,8 +1153,10 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, table->table->version=0; // Force close of table else if (open_for_modify) { + pthread_mutex_lock(&LOCK_open); remove_table_from_cache(thd, table->table->table_cache_key, table->table->real_name); + pthread_mutex_unlock(&LOCK_open); /* May be something modified consequently we have to invalidate cache */ query_cache_invalidate3(thd, table->table, 0); } @@ -1171,6 +1185,7 @@ int mysql_backup_table(THD* thd, TABLE_LIST* table_list) &handler::backup)); } + int mysql_restore_table(THD* thd, TABLE_LIST* table_list) { DBUG_ENTER("mysql_restore_table"); @@ -1180,6 +1195,7 @@ int mysql_restore_table(THD* thd, TABLE_LIST* table_list) &handler::restore)); } + int mysql_repair_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt) { DBUG_ENTER("mysql_repair_table"); @@ -1189,6 +1205,7 @@ int mysql_repair_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt) &handler::repair)); } + int mysql_optimize_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt) { DBUG_ENTER("mysql_optimize_table"); @@ -1352,7 +1369,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, mysql_update_log.write(thd, thd->query, thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query); + Query_log_event qinfo(thd, thd->query, thd->query_length); mysql_bin_log.write(&qinfo); } send_ok(&thd->net); @@ -1717,7 +1734,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, mysql_update_log.write(thd, thd->query,thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query); + Query_log_event qinfo(thd, thd->query, thd->query_length); mysql_bin_log.write(&qinfo); } goto end_temporary; @@ -1851,7 +1868,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, mysql_update_log.write(thd, thd->query,thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query); + Query_log_event qinfo(thd, thd->query, thd->query_length); mysql_bin_log.write(&qinfo); } VOID(pthread_cond_broadcast(&COND_refresh)); diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 9c458c27b95..b226bc1300a 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -242,6 +242,7 @@ Open streams: %10lu\n", (ulong) my_stream_opened); ALARM_INFO alarm_info; +#ifndef DONT_USE_THR_ALARM thr_alarm_info(&alarm_info); printf("\nAlarm status:\n\ Active alarms: %u\n\ @@ -250,7 +251,7 @@ Next alarm time: %lu\n", alarm_info.active_alarms, alarm_info.max_used_alarms, alarm_info.next_alarm_time); - +#endif fflush(stdout); if (thd) thd->proc_info="malloc"; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index fda07721da8..ab6a0b72fe5 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -307,7 +307,8 @@ int mysql_update(THD *thd, mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, using_transactions); + Query_log_event qinfo(thd, thd->query, thd->query_length, + using_transactions); if (mysql_bin_log.write(&qinfo) && using_transactions) error=1; } @@ -781,7 +782,7 @@ bool multi_update::send_eof() if (updated || not_trans_safe) { mysql_update_log.write(thd,thd->query,thd->query_length); - Query_log_event qinfo(thd, thd->query); + Query_log_event qinfo(thd, thd->query, thd->query_length); /* mysql_bin_log is not open if binlogging or replication diff --git a/sql/table.cc b/sql/table.cc index 2a284d4c027..cc5666ff5fb 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -776,7 +776,7 @@ ulong make_new_entry(File file, uchar *fileinfo, TYPELIB *formnames, int2store(fileinfo+8,names+1); int2store(fileinfo+4,n_length+length); - VOID(my_chsize(file,newpos,MYF(MY_WME))); /* Append file with '\0' */ + VOID(my_chsize(file, newpos, 0, MYF(MY_WME)));/* Append file with '\0' */ DBUG_RETURN(newpos); } /* make_new_entry */ |