diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/client_priv.h | 1 | ||||
-rw-r--r-- | client/mysqlbinlog.cc | 149 | ||||
-rw-r--r-- | client/mysqldump.c | 119 |
3 files changed, 232 insertions, 37 deletions
diff --git a/client/client_priv.h b/client/client_priv.h index f6bde7a594c..0b617c564df 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -95,5 +95,6 @@ enum options_client OPT_REWRITE_DB, OPT_PLUGIN_DIR, OPT_DEFAULT_PLUGIN, + OPT_SKIP_ANNOTATE_ROWS_EVENTS, OPT_MAX_CLIENT_OPTION /* should be always the last */ }; diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 266160890f6..9e4ef2a4c2d 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -107,6 +107,7 @@ static ulonglong rec_count= 0; static short binlog_flags = 0; static MYSQL* mysql = NULL; static const char* dirname_for_local_load= 0; +static bool opt_skip_annotate_rows_events= 0; /** Pointer to the Format_description_log_event of the currently active binlog. @@ -128,6 +129,70 @@ enum Exit_status { OK_STOP }; +/** + Pointer to the last read Annotate_rows_log_event. Having read an + Annotate_rows event, we should not print it immediatedly because all + subsequent rbr events can be filtered away, and have to keep it for a while. + Also because of that when reading a remote Annotate event we have to keep + its binary log representation in a separately allocated buffer. +*/ +static Annotate_rows_log_event *annotate_event= NULL; + +void free_annotate_event() +{ + if (annotate_event) + { + delete annotate_event; + annotate_event= 0; + } +} + +Log_event* read_remote_annotate_event(uchar* net_buf, ulong event_len, + const char **error_msg) +{ + uchar *event_buf; + Log_event* event; + + if (!(event_buf= (uchar*) my_malloc(event_len + 1, MYF(MY_WME)))) + { + error("Out of memory"); + return 0; + } + + memcpy(event_buf, net_buf, event_len); + event_buf[event_len]= 0; + + if (!(event= Log_event::read_log_event((const char*) event_buf, event_len, + error_msg, glob_description_event))) + { + my_free(event_buf, MYF(0)); + return 0; + } + /* + Ensure the event->temp_buf is pointing to the allocated buffer. + (TRUE = free temp_buf on the event deletion) + */ + event->register_temp_buf((char*)event_buf, TRUE); + + return event; +} + +void keep_annotate_event(Annotate_rows_log_event* event) +{ + free_annotate_event(); + annotate_event= event; +} + +void print_annotate_event(PRINT_EVENT_INFO *print_event_info) +{ + if (annotate_event) + { + annotate_event->print(result_file, print_event_info); + delete annotate_event; // the event should not be printed more than once + annotate_event= 0; + } +} + static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info, const char* logname); static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info, @@ -782,8 +847,19 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, case QUERY_EVENT: { Query_log_event *qe= (Query_log_event*)ev; - if (!qe->is_trans_keyword() && shall_skip_database(qe->db)) - goto end; + if (!qe->is_trans_keyword()) + { + if (shall_skip_database(qe->db)) + goto end; + } + else + { + /* + In case the event for one of these statements is obtained + from binary log 5.0, make it compatible with 5.1 + */ + qe->flags|= LOG_EVENT_SUPPRESS_USE_F; + } print_use_stmt(print_event_info, qe); if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS) { @@ -932,6 +1008,19 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, my_free(fname, MYF(MY_WME)); break; } + case ANNOTATE_ROWS_EVENT: + if (!opt_skip_annotate_rows_events) + { + /* + We don't print Annotate event just now because all subsequent + rbr-events can be filtered away. Instead we'll keep the event + till it will be printed together with the first not filtered + away Table map or the last rbr will be processed. + */ + keep_annotate_event((Annotate_rows_log_event*) ev); + destroy_evt= FALSE; + } + break; case TABLE_MAP_EVENT: { Table_map_log_event *map= ((Table_map_log_event *)ev); @@ -941,6 +1030,13 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, destroy_evt= FALSE; goto end; } + /* + The Table map is to be printed, so it's just the time when we may + print the kept Annotate event (if there is any). + print_annotate_event() also deletes the kept Annotate event. + */ + print_annotate_event(print_event_info); + size_t len_to= 0; const char* db_to= binlog_filter->get_rewrite_db(map->get_db_name(), &len_to); if (len_to && map->rewrite_db(db_to, len_to, glob_description_event)) @@ -977,6 +1073,13 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, if (print_event_info->m_table_map_ignored.count() > 0) print_event_info->m_table_map_ignored.clear_tables(); + /* + If there is a kept Annotate event and all corresponding + rbr-events were filtered away, the Annotate event was not + freed and it is just the time to do it. + */ + free_annotate_event(); + /* One needs to take into account an event that gets filtered but was last event in the statement. If this is @@ -1211,6 +1314,11 @@ that may lead to an endless loop.", "Updates to a database with a different name than the original. \ Example: rewrite-db='from->to'.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"skip-annotate-rows-events", OPT_SKIP_ANNOTATE_ROWS_EVENTS, + "Don't print Annotate_rows events stored in the binary log.", + (uchar**) &opt_skip_annotate_rows_events, + (uchar**) &opt_skip_annotate_rows_events, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -1682,6 +1790,8 @@ static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info, cast to uint32. */ int4store(buf, (uint32)start_position); + if (!opt_skip_annotate_rows_events) + binlog_flags|= BINLOG_SEND_ANNOTATE_ROWS_EVENT; int2store(buf + BIN_LOG_HEADER_SIZE, binlog_flags); size_t tlen = strlen(logname); @@ -1714,18 +1824,30 @@ static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info, break; // end of data DBUG_PRINT("info",( "len: %lu net->read_pos[5]: %d\n", len, net->read_pos[5])); - if (!(ev= Log_event::read_log_event((const char*) net->read_pos + 1 , - len - 1, &error_msg, - glob_description_event))) + if (net->read_pos[5] == ANNOTATE_ROWS_EVENT) { - error("Could not construct log event object: %s", error_msg); - DBUG_RETURN(ERROR_STOP); - } - /* - If reading from a remote host, ensure the temp_buf for the - Log_event class is pointing to the incoming stream. - */ - ev->register_temp_buf((char *) net->read_pos + 1, FALSE); + if (!(ev= read_remote_annotate_event(net->read_pos + 1, len - 1, + &error_msg))) + { + error("Could not construct annotate event object: %s", error_msg); + DBUG_RETURN(ERROR_STOP); + } + } + else + { + if (!(ev= Log_event::read_log_event((const char*) net->read_pos + 1 , + len - 1, &error_msg, + glob_description_event))) + { + error("Could not construct log event object: %s", error_msg); + DBUG_RETURN(ERROR_STOP); + } + /* + If reading from a remote host, ensure the temp_buf for the + Log_event class is pointing to the incoming stream. + */ + ev->register_temp_buf((char *) net->read_pos + 1, FALSE); + } Log_event_type type= ev->get_type_code(); if (glob_description_event->binlog_version >= 3 || @@ -2235,6 +2357,7 @@ int main(int argc, char** argv) if (result_file != stdout) my_fclose(result_file, MYF(0)); cleanup(); + free_annotate_event(); delete binlog_filter; free_root(&s_mem_root, MYF(0)); free_defaults(defaults_argv); diff --git a/client/mysqldump.c b/client/mysqldump.c index bb09af4a3c2..1c968553329 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -77,6 +77,9 @@ #define IGNORE_DATA 0x01 /* don't dump data for this table */ #define IGNORE_INSERT_DELAYED 0x02 /* table doesn't support INSERT DELAYED */ +/* Chars needed to store LONGLONG, excluding trailing '\0'. */ +#define LONGLONG_LEN 20 + static void add_load_option(DYNAMIC_STRING *str, const char *option, const char *option_value); static ulong find_set(TYPELIB *lib, const char *x, uint length, @@ -344,9 +347,9 @@ static struct my_option my_long_options[] = "This causes the binary log position and filename to be appended to the " "output. If equal to 1, will print it as a CHANGE MASTER command; if equal" " to 2, that command will be prefixed with a comment symbol. " - "This option will turn --lock-all-tables on, unless " - "--single-transaction is specified too (in which case a " - "global read lock is only taken a short time at the beginning of the dump; " + "This option will turn --lock-all-tables on, unless --single-transaction " + "is specified too (on servers before MariaDB 5.3 this will still take a " + "global read lock for a short time at the beginning of the dump; " "don't forget to read about --single-transaction below). In all cases, " "any action on logs will happen at the exact moment of the dump. " "Option automatically turns --lock-tables off.", @@ -1109,6 +1112,44 @@ static int fetch_db_collation(const char *db_name, } +/* + Check if server supports non-blocking binlog position using the + binlog_snapshot_file and binlog_snapshot_position status variables. If it + does, also return the position obtained if output pointers are non-NULL. + Returns 1 if position available, 0 if not. +*/ +static int +check_consistent_binlog_pos(char *binlog_pos_file, char *binlog_pos_offset) +{ + MYSQL_RES *res; + MYSQL_ROW row; + int found; + + if (mysql_query_with_error_report(mysql, &res, + "SHOW STATUS LIKE 'binlog_snapshot_%'")) + return 1; + + found= 0; + while ((row= mysql_fetch_row(res))) + { + if (0 == strcmp(row[0], "binlog_snapshot_file")) + { + if (binlog_pos_file) + strmake(binlog_pos_file, row[1], FN_REFLEN-1); + found++; + } + else if (0 == strcmp(row[0], "binlog_snapshot_position")) + { + if (binlog_pos_offset) + strmake(binlog_pos_offset, row[1], LONGLONG_LEN); + found++; + } + } + mysql_free_result(res); + + return (found == 2); +} + static char *my_case_str(const char *str, uint str_len, const char *token, @@ -4351,42 +4392,65 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } /* dump_selected_tables */ -static int do_show_master_status(MYSQL *mysql_con) +static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos) { MYSQL_ROW row; MYSQL_RES *master; + char binlog_pos_file[FN_REFLEN]; + char binlog_pos_offset[LONGLONG_LEN+1]; + char *file, *offset; const char *comment_prefix= (opt_master_data == MYSQL_OPT_MASTER_DATA_COMMENTED_SQL) ? "-- " : ""; - if (mysql_query_with_error_report(mysql_con, &master, "SHOW MASTER STATUS")) + + if (consistent_binlog_pos) { - return 1; + if(!check_consistent_binlog_pos(binlog_pos_file, binlog_pos_offset)) + return 1; + file= binlog_pos_file; + offset= binlog_pos_offset; } else { + if (mysql_query_with_error_report(mysql_con, &master, "SHOW MASTER STATUS")) + return 1; + row= mysql_fetch_row(master); if (row && row[0] && row[1]) { - /* SHOW MASTER STATUS reports file and position */ - if (opt_comments) - fprintf(md_result_file, - "\n--\n-- Position to start replication or point-in-time " - "recovery from\n--\n\n"); - fprintf(md_result_file, - "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n", - comment_prefix, row[0], row[1]); - check_io(md_result_file); + file= row[0]; + offset= row[1]; } - else if (!ignore_errors) + else { - /* SHOW MASTER STATUS reports nothing and --force is not enabled */ - my_printf_error(0, "Error: Binlogging on server not active", - MYF(0)); mysql_free_result(master); - maybe_exit(EX_MYSQLERR); - return 1; + if (!ignore_errors) + { + /* SHOW MASTER STATUS reports nothing and --force is not enabled */ + my_printf_error(0, "Error: Binlogging on server not active", + MYF(0)); + maybe_exit(EX_MYSQLERR); + return 1; + } + else + { + return 0; + } } - mysql_free_result(master); } + + /* SHOW MASTER STATUS reports file and position */ + if (opt_comments) + fprintf(md_result_file, + "\n--\n-- Position to start replication or point-in-time " + "recovery from\n--\n\n"); + fprintf(md_result_file, + "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n", + comment_prefix, file, offset); + check_io(md_result_file); + + if (!consistent_binlog_pos) + mysql_free_result(master); + return 0; } @@ -5025,6 +5089,7 @@ int main(int argc, char **argv) { char bin_log_name[FN_REFLEN]; int exit_code; + int consistent_binlog_pos= 0; MY_INIT("mysqldump"); compatible_mode_normal_str[0]= 0; @@ -5055,7 +5120,13 @@ int main(int argc, char **argv) if (!path) write_header(md_result_file, *argv); - if ((opt_lock_all_tables || opt_master_data) && + if (opt_single_transaction && opt_master_data) + { + /* See if we can avoid FLUSH TABLES WITH READ LOCK (MariaDB 5.3+). */ + consistent_binlog_pos= check_consistent_binlog_pos(NULL, NULL); + } + + if ((opt_lock_all_tables || (opt_master_data && !consistent_binlog_pos)) && do_flush_tables_read_lock(mysql)) goto err; if (opt_single_transaction && start_transaction(mysql)) @@ -5073,7 +5144,7 @@ int main(int argc, char **argv) goto err; flush_logs= 0; /* not anymore; that would not be sensible */ } - if (opt_master_data && do_show_master_status(mysql)) + if (opt_master_data && do_show_master_status(mysql, consistent_binlog_pos)) goto err; if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */ goto err; |