diff options
author | unknown <tsmith@ramayana.hindu.god> | 2008-02-05 16:04:07 -0700 |
---|---|---|
committer | unknown <tsmith@ramayana.hindu.god> | 2008-02-05 16:04:07 -0700 |
commit | f328142cdb9f01dab47bb72df3df1ade57ee4ade (patch) | |
tree | 9ab45576cbc8bbff42e4bab3bd57abcd6af3fbb0 /sql | |
parent | fb9c0158b2328d326acb9e9af9a2e85a72840afe (diff) | |
parent | 74bd1b0faf78929e0aaa7ba85bbf5a5800f75cba (diff) | |
download | mariadb-git-f328142cdb9f01dab47bb72df3df1ade57ee4ade.tar.gz |
Merge ramayana.hindu.god:/home/tsmith/m/bk/50
into ramayana.hindu.god:/home/tsmith/m/bk/build/50
Diffstat (limited to 'sql')
-rw-r--r-- | sql/log.cc | 100 | ||||
-rw-r--r-- | sql/log_event.cc | 7 | ||||
-rw-r--r-- | sql/set_var.cc | 1 | ||||
-rw-r--r-- | sql/slave.cc | 5 | ||||
-rw-r--r-- | sql/sql_acl.cc | 24 | ||||
-rw-r--r-- | sql/sql_parse.cc | 1 | ||||
-rw-r--r-- | sql/sql_repl.cc | 75 | ||||
-rw-r--r-- | sql/sql_string.cc | 4 | ||||
-rw-r--r-- | sql/sql_view.cc | 32 |
9 files changed, 164 insertions, 85 deletions
diff --git a/sql/log.cc b/sql/log.cc index e66d965c613..0376facb473 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -122,6 +122,20 @@ static int binlog_prepare(THD *thd, bool all) return 0; } +/** + This function is called once after each statement. + + It has the responsibility to flush the transaction cache to the + binlog file on commits. + + @param thd The client thread that executes the transaction. + @param all true if this is the last statement before a COMMIT + statement; false if either this is a statement in a + transaction but not the last, or if this is a statement + not inside a BEGIN block and autocommit is on. + + @see handlerton::commit +*/ static int binlog_commit(THD *thd, bool all) { IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot]; @@ -134,7 +148,15 @@ static int binlog_commit(THD *thd, bool all) // we're here because trans_log was flushed in MYSQL_LOG::log_xid() DBUG_RETURN(0); } - if (all) + /* + Write commit event if at least one of the following holds: + - the user sends an explicit COMMIT; or + - the autocommit flag is on, and we are not inside a BEGIN. + However, if the user has not sent an explicit COMMIT, and we are + either inside a BEGIN or run with autocommit off, then this is not + the end of a transaction and we should not write a commit event. + */ + if (all || !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE); qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE) @@ -144,6 +166,22 @@ static int binlog_commit(THD *thd, bool all) DBUG_RETURN(binlog_end_trans(thd, trans_log, &invisible_commit)); } +/** + This function is called when a transaction involving a transactional + table is rolled back. + + It has the responsibility to flush the transaction cache to the + binlog file. However, if the transaction does not involve + non-transactional tables, nothing needs to be logged. + + @param thd The client thread that executes the transaction. + @param all true if this is the last statement before a COMMIT + statement; false if either this is a statement in a + transaction but not the last, or if this is a statement + not inside a BEGIN block and autocommit is on. + + @see handlerton::rollback +*/ static int binlog_rollback(THD *thd, bool all) { int error=0; @@ -1817,9 +1855,11 @@ uint MYSQL_LOG::next_file_id() IMPLEMENTATION - To support transaction over replication, we wrap the transaction with BEGIN/COMMIT or BEGIN/ROLLBACK in the binary log. - We want to write a BEGIN/ROLLBACK block when a non-transactional table - was updated in a transaction which was rolled back. This is to ensure - that the same updates are run on the slave. + If a transaction that only involves transactional tables is + rolled back, we do not binlog it. However, we write a + BEGIN/ROLLBACK block when a non-transactional table was updated + in a transaction which was rolled back. This is to ensure that + the same updates are run on the slave. */ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) @@ -1837,32 +1877,34 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) byte header[LOG_EVENT_HEADER_LEN]; /* - Log "BEGIN" at the beginning of the transaction. - which may contain more than 1 SQL statement. + Log "BEGIN" at the beginning of every transaction. Here, a + transaction is either a BEGIN..COMMIT block or a single + statement in autocommit mode. */ - if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) - { - Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE); - /* - Imagine this is rollback due to net timeout, after all statements of - the transaction succeeded. Then we want a zero-error code in BEGIN. - In other words, if there was a really serious error code it's already - in the statement's events, there is no need to put it also in this - internally generated event, and as this event is generated late it - would lead to false alarms. - This is safer than thd->clear_error() against kills at shutdown. - */ - qinfo.error_code= 0; - /* - Now this Query_log_event has artificial log_pos 0. It must be adjusted - to reflect the real position in the log. Not doing it would confuse the - slave: it would prevent this one from knowing where he is in the - master's binlog, which would result in wrong positions being shown to - the user, MASTER_POS_WAIT undue waiting etc. - */ - if (qinfo.write(&log_file)) - goto err; - } + Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE); + /* + Imagine this is rollback due to net timeout, after all + statements of the transaction succeeded. Then we want a + zero-error code in BEGIN. In other words, if there was a + really serious error code it's already in the statement's + events, there is no need to put it also in this internally + generated event, and as this event is generated late it would + lead to false alarms. + + This is safer than thd->clear_error() against kills at shutdown. + */ + qinfo.error_code= 0; + /* + Now this Query_log_event has artificial log_pos 0. It must be + adjusted to reflect the real position in the log. Not doing it + would confuse the slave: it would prevent this one from + knowing where he is in the master's binlog, which would result + in wrong positions being shown to the user, MASTER_POS_WAIT + undue waiting etc. + */ + 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)) goto err; diff --git a/sql/log_event.cc b/sql/log_event.cc index d22973d12a3..a950094a018 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1862,7 +1862,7 @@ void Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) { print_query_header(file, print_event_info); my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME)); - fprintf(file, "%s\n", print_event_info->delimiter); + fprintf(file, "\n%s\n", print_event_info->delimiter); } #endif /* MYSQL_CLIENT */ @@ -3793,6 +3793,7 @@ Xid_log_event(const char* buf, #ifndef MYSQL_CLIENT bool Xid_log_event::write(IO_CACHE* file) { + DBUG_EXECUTE_IF("do_not_write_xid", return 0;); return write_header(file, sizeof(xid)) || my_b_safe_write(file, (byte*) &xid, sizeof(xid)); } @@ -5180,12 +5181,12 @@ void Execute_load_query_log_event::print(FILE* file, fprintf(file, " INTO"); my_fwrite(file, (byte*) query + fn_pos_end, q_len-fn_pos_end, MYF(MY_NABP | MY_WME)); - fprintf(file, "%s\n", print_event_info->delimiter); + fprintf(file, "\n%s\n", print_event_info->delimiter); } else { my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME)); - fprintf(file, "%s\n", print_event_info->delimiter); + fprintf(file, "\n%s\n", print_event_info->delimiter); } if (!print_event_info->short_form) diff --git a/sql/set_var.cc b/sql/set_var.cc index fe57b46745a..a99b063a97e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1448,6 +1448,7 @@ static void fix_trans_mem_root(THD *thd, enum_var_type type) static void fix_server_id(THD *thd, enum_var_type type) { server_id_supplied = 1; + thd->server_id= server_id; } diff --git a/sql/slave.cc b/sql/slave.cc index 1509916fe91..4a65e9aaa85 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3348,7 +3348,10 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) if (rli->slave_skip_counter && !((type_code == INTVAR_EVENT || type_code == RAND_EVENT || - type_code == USER_VAR_EVENT) && + type_code == USER_VAR_EVENT || + type_code == BEGIN_LOAD_QUERY_EVENT || + type_code == APPEND_BLOCK_EVENT || + type_code == CREATE_FILE_EVENT) && rli->slave_skip_counter == 1) && #if MYSQL_VERSION_ID < 50100 /* diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 134541368e9..8fdd054eb39 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -5333,6 +5333,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) LEX_USER *user_name, *tmp_user_name; List_iterator <LEX_USER> user_list(list); TABLE_LIST tables[GRANT_TABLES]; + bool some_users_created= FALSE; DBUG_ENTER("mysql_create_user"); /* CREATE USER may be skipped on replication client. */ @@ -5361,6 +5362,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) continue; } + some_users_created= TRUE; sql_mode= thd->variables.sql_mode; if (replace_user_table(thd, tables[0].table, *user_name, 0, 0, 1, 0)) { @@ -5371,7 +5373,10 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) VOID(pthread_mutex_unlock(&acl_cache->lock)); - if (mysql_bin_log.is_open()) + if (result) + my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe()); + + if (some_users_created && mysql_bin_log.is_open()) { Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); mysql_bin_log.write(&qinfo); @@ -5379,8 +5384,6 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) rw_unlock(&LOCK_grant); close_thread_tables(thd); - if (result) - my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe()); DBUG_RETURN(result); } @@ -5405,6 +5408,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) LEX_USER *user_name, *tmp_user_name; List_iterator <LEX_USER> user_list(list); TABLE_LIST tables[GRANT_TABLES]; + bool some_users_deleted= FALSE; DBUG_ENTER("mysql_drop_user"); /* DROP USER may be skipped on replication client. */ @@ -5426,7 +5430,9 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) { append_user(&wrong_users, user_name); result= TRUE; + continue; } + some_users_deleted= TRUE; } /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */ @@ -5440,7 +5446,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) DBUG_PRINT("info", ("thd->net.last_errno: %d", thd->net.last_errno)); DBUG_PRINT("info", ("thd->net.last_error: %s", thd->net.last_error)); - if (mysql_bin_log.is_open()) + if (some_users_deleted && mysql_bin_log.is_open()) { Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); mysql_bin_log.write(&qinfo); @@ -5473,6 +5479,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) LEX_USER *user_to, *tmp_user_to; List_iterator <LEX_USER> user_list(list); TABLE_LIST tables[GRANT_TABLES]; + bool some_users_renamed= FALSE; DBUG_ENTER("mysql_rename_user"); /* RENAME USER may be skipped on replication client. */ @@ -5506,7 +5513,9 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) { append_user(&wrong_users, user_from); result= TRUE; + continue; } + some_users_renamed= TRUE; } /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */ @@ -5514,7 +5523,10 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) VOID(pthread_mutex_unlock(&acl_cache->lock)); - if (mysql_bin_log.is_open()) + if (result) + my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe()); + + if (some_users_renamed && mysql_bin_log.is_open()) { Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); mysql_bin_log.write(&qinfo); @@ -5522,8 +5534,6 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) rw_unlock(&LOCK_grant); close_thread_tables(thd); - if (result) - my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe()); DBUG_RETURN(result); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8af79d77fa1..45dac4d5127 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2067,7 +2067,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, unregister_slave(thd,1,1); /* fake COM_QUIT -- if we get here, the thread needs to terminate */ error = TRUE; - net->error = 0; break; } #endif diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 903d254db8f..5bbff69f197 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1229,9 +1229,6 @@ bool change_master(THD* thd, MASTER_INFO* mi) DBUG_RETURN(TRUE); } } - mi->rli.group_master_log_pos = mi->master_log_pos; - DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos)); - /* Coordinates in rli were spoilt by the 'if (need_relay_log_purge)' block, so restore them to good values. If we left them to ''/0, that would work; @@ -1243,6 +1240,7 @@ bool change_master(THD* thd, MASTER_INFO* mi) That's why we always save good coords in rli. */ mi->rli.group_master_log_pos= mi->master_log_pos; + DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos)); strmake(mi->rli.group_master_log_name,mi->master_log_name, sizeof(mi->rli.group_master_log_name)-1); @@ -1355,6 +1353,11 @@ bool mysql_show_binlog_events(THD* thd) if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0) goto err; + /* + to account binlog event header size + */ + thd->variables.max_allowed_packet += MAX_LOG_EVENT_HEADER; + pthread_mutex_lock(log_lock); /* @@ -1365,7 +1368,6 @@ bool mysql_show_binlog_events(THD* thd) This code will fail on a mixed relay log (one which has Format_desc then Rotate then Format_desc). */ - ev = Log_event::read_log_event(&log,(pthread_mutex_t*)0,description_event); if (ev) { @@ -1556,37 +1558,52 @@ err: DBUG_RETURN(TRUE); } - +/** + Load data's io cache specific hook to be executed + before a chunk of data is being read into the cache's buffer + The fuction instantianates and writes into the binlog + replication events along LOAD DATA processing. + + @param file pointer to io-cache + @return 0 +*/ int log_loaded_block(IO_CACHE* file) { + DBUG_ENTER("log_loaded_block"); LOAD_FILE_INFO *lf_info; - uint block_len ; - - /* file->request_pos contains position where we started last read */ - char* buffer = (char*) file->request_pos; - if (!(block_len = (char*) file->read_end - (char*) buffer)) - return 0; - lf_info = (LOAD_FILE_INFO*) file->arg; + uint block_len; + /* buffer contains position where we started last read */ + char* buffer= (char*) my_b_get_buffer_start(file); + uint max_event_size= current_thd->variables.max_allowed_packet; + lf_info= (LOAD_FILE_INFO*) file->arg; if (lf_info->last_pos_in_file != HA_POS_ERROR && - lf_info->last_pos_in_file >= file->pos_in_file) - return 0; - lf_info->last_pos_in_file = file->pos_in_file; - if (lf_info->wrote_create_file) - { - Append_block_log_event a(lf_info->thd, lf_info->thd->db, buffer, - block_len, lf_info->log_delayed); - mysql_bin_log.write(&a); - } - else + lf_info->last_pos_in_file >= my_b_get_pos_in_file(file)) + DBUG_RETURN(0); + + for (block_len= my_b_get_bytes_in_buffer(file); block_len > 0; + buffer += min(block_len, max_event_size), + block_len -= min(block_len, max_event_size)) { - Begin_load_query_log_event b(lf_info->thd, lf_info->thd->db, - buffer, block_len, - lf_info->log_delayed); - mysql_bin_log.write(&b); - lf_info->wrote_create_file = 1; - DBUG_SYNC_POINT("debug_lock.created_file_event",10); + lf_info->last_pos_in_file= my_b_get_pos_in_file(file); + if (lf_info->wrote_create_file) + { + Append_block_log_event a(lf_info->thd, lf_info->thd->db, buffer, + min(block_len, max_event_size), + lf_info->log_delayed); + mysql_bin_log.write(&a); + } + else + { + Begin_load_query_log_event b(lf_info->thd, lf_info->thd->db, + buffer, + min(block_len, max_event_size), + lf_info->log_delayed); + mysql_bin_log.write(&b); + lf_info->wrote_create_file= 1; + DBUG_SYNC_POINT("debug_lock.created_file_event",10); + } } - return 0; + DBUG_RETURN(0); } #endif /* HAVE_REPLICATION */ diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 606a9ddb26d..75e47dd0c8e 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -307,8 +307,8 @@ bool String::copy_aligned(const char *str,uint32 arg_length, uint32 offset, return TRUE; /* - Note, this is only safe for little-endian UCS-2. - If we add big-endian UCS-2 sometimes, this code + Note, this is only safe for big-endian UCS-2. + If we add little-endian UCS-2 sometimes, this code will be more complicated. But it's OK for now. */ bzero((char*) Ptr, offset); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 297edd0d90d..dd0b92a06f8 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1424,6 +1424,8 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) String non_existant_views; char *wrong_object_db= NULL, *wrong_object_name= NULL; bool error= FALSE; + bool some_views_deleted= FALSE; + bool something_wrong= FALSE; VOID(pthread_mutex_lock(&LOCK_open)); for (view= views; view; view= view->next_local) @@ -1462,33 +1464,37 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) } if (my_delete(path, MYF(MY_WME))) error= TRUE; + some_views_deleted= TRUE; query_cache_invalidate3(thd, view, 0); sp_cache_invalidate(); } - if (mysql_bin_log.is_open()) - { - thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); - mysql_bin_log.write(&qinfo); - } - - VOID(pthread_mutex_unlock(&LOCK_open)); - if (error) - { - DBUG_RETURN(TRUE); - } if (wrong_object_name) { my_error(ER_WRONG_OBJECT, MYF(0), wrong_object_db, wrong_object_name, "VIEW"); - DBUG_RETURN(TRUE); } if (non_existant_views.length()) { my_error(ER_BAD_TABLE_ERROR, MYF(0), non_existant_views.c_ptr()); + } + + something_wrong= error || wrong_object_name || non_existant_views.length(); + if (some_views_deleted || !something_wrong) + { + if (!something_wrong) + thd->clear_error(); + Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + mysql_bin_log.write(&qinfo); + } + + VOID(pthread_mutex_unlock(&LOCK_open)); + + if (something_wrong) + { DBUG_RETURN(TRUE); } + send_ok(thd); DBUG_RETURN(FALSE); } |