From: Andrei Elkin Date: December 10 2010 4:25pm Subject: bzr commit into mysql-next-mr-wl5569 branch (andrei.elkin:3240) List-Archive: http://lists.mysql.com/commits/126541 Message-Id: <201012101625.oBAGPfXX026873@mysql1000.dsl.inet.fi> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0102318253==" --===============0102318253== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/andrei/MySQL/BZR/2a-23May/WL/mysql-next-mr-wl5569/ based on revid:andrei.elkin@stripped 3240 Andrei Elkin 2010-12-10 [merge] merge from wl5569 repo to a local branch modified: mysql-test/r/mysqld--help-notwin.result mysql-test/r/mysqld--help-win.result mysql-test/suite/rpl/t/rpl_parallel_start_stop.test sql/dynamic_ids.cc sql/dynamic_ids.h sql/mysqld.cc sql/mysqld.h sql/rpl_rli.cc sql/rpl_rli.h sql/rpl_rli_pdb.h sql/rpl_slave.cc sql/sys_vars.cc === modified file 'mysql-test/r/mysqld--help-notwin.result' --- a/mysql-test/r/mysqld--help-notwin.result 2010-12-09 13:23:19 +0000 +++ b/mysql-test/r/mysqld--help-notwin.result 2010-12-10 12:10:20 +0000 @@ -339,6 +339,10 @@ The following options may be given as th --min-examined-row-limit=# Don't write queries to slow log that examine fewer rows than that + --mts-checkpoint-period=# + Gather workers' activities and synchronously flush relay + log info to disk after every #th mili-seconds. Use 0 + (default) to disable checkpoint --mts-partition-hash-soft-max=# Number of records in the mts partition hash below which entries with zero usage are tolerated @@ -883,6 +887,7 @@ max-user-connections 0 max-write-lock-count 18446744073709551615 memlock FALSE min-examined-row-limit 0 +mts-checkpoint-period 0 mts-partition-hash-soft-max 16 mts-pending-jobs-size-max 16777216 mts-slave-worker-queue-len-max 40000 === modified file 'mysql-test/r/mysqld--help-win.result' --- a/mysql-test/r/mysqld--help-win.result 2010-12-09 13:23:19 +0000 +++ b/mysql-test/r/mysqld--help-win.result 2010-12-10 12:10:20 +0000 @@ -338,6 +338,10 @@ The following options may be given as th --min-examined-row-limit=# Don't write queries to slow log that examine fewer rows than that + --mts-checkpoint-period=# + Gather workers' activities and synchronously flush relay + log info to disk after every #th mili-seconds. Use 0 + (default) to disable checkpoint --mts-partition-hash-soft-max=# Number of records in the mts partition hash below which entries with zero usage are tolerated @@ -886,6 +890,7 @@ max-user-connections 0 max-write-lock-count 18446744073709551615 memlock FALSE min-examined-row-limit 0 +mts-checkpoint-period 0 mts-partition-hash-soft-max 16 mts-pending-jobs-size-max 16777216 mts-slave-worker-queue-len-max 40000 === modified file 'mysql-test/suite/rpl/t/rpl_parallel_start_stop.test' --- a/mysql-test/suite/rpl/t/rpl_parallel_start_stop.test 2010-12-07 17:35:16 +0000 +++ b/mysql-test/suite/rpl/t/rpl_parallel_start_stop.test 2010-12-10 12:10:20 +0000 @@ -6,6 +6,7 @@ # source include/master-slave.inc; +source include/have_binlog_format_row.inc; connection slave; === modified file 'sql/dynamic_ids.cc' --- a/sql/dynamic_ids.cc 2010-12-08 12:59:07 +0000 +++ b/sql/dynamic_ids.cc 2010-12-10 12:10:20 +0000 @@ -1,6 +1,16 @@ #include "dynamic_ids.h" -Dynamic_ids::Dynamic_ids(size_t size) +int cmp_string(const void *id1, const void *id2) +{ + return strcmp((char *) id1, (char *) id2); +} + +int cmp_ulong(const void *id1, const void *id2) +{ + return ((*(ulong *) id1) - (* (ulong *)id2)); +} + +Dynamic_ids::Dynamic_ids(size_t param_size): size(param_size) { my_init_dynamic_array(&dynamic_ids, size, 16, 16); } @@ -58,6 +68,15 @@ bool Server_ids::do_pack_dynamic_ids(Str DBUG_RETURN(FALSE); } +bool Server_ids::do_search_id(const void *id) +{ + return (bsearch((ulong *) id, dynamic_ids.buffer, + dynamic_ids.elements, size, + (int (*) (const void*, const void*)) + cmp_ulong) != NULL); +} + + bool Database_ids::do_unpack_dynamic_ids(char *param_dynamic_ids) { char *token= NULL, *last= NULL; @@ -115,3 +134,11 @@ bool Database_ids::do_pack_dynamic_ids(S DBUG_RETURN(FALSE); } + +bool Database_ids::do_search_id(const void *id) +{ + return (bsearch((const char *) id, dynamic_ids.buffer, + dynamic_ids.elements, size, + (int (*) (const void*, const void*)) + cmp_string) != NULL); +} === modified file 'sql/dynamic_ids.h' --- a/sql/dynamic_ids.h 2010-12-08 12:59:07 +0000 +++ b/sql/dynamic_ids.h 2010-12-10 12:10:20 +0000 @@ -25,7 +25,7 @@ class Dynamic_ids public: DYNAMIC_ARRAY dynamic_ids; - Dynamic_ids(size_t size); + Dynamic_ids(size_t param_size); virtual ~Dynamic_ids(); bool pack_dynamic_ids(String *buffer) @@ -38,9 +38,18 @@ public: return(do_unpack_dynamic_ids(param_dynamic_ids)); } + bool search_id(const void *id) + { + return (do_search_id(id)); + } + +protected: + size_t size; + private: virtual bool do_pack_dynamic_ids(String *buffer)= 0; virtual bool do_unpack_dynamic_ids(char *param_dynamic_ids)= 0; + virtual bool do_search_id(const void *id)= 0; }; class Server_ids : public Dynamic_ids @@ -52,6 +61,7 @@ public: private: bool do_pack_dynamic_ids(String *buffer); bool do_unpack_dynamic_ids(char *param_dynamic_ids); + bool do_search_id(const void *id); }; class Database_ids : public Dynamic_ids @@ -63,5 +73,6 @@ public: private: bool do_pack_dynamic_ids(String *buffer); bool do_unpack_dynamic_ids(char *param_dynamic_ids); + bool do_search_id(const void *id); }; #endif === modified file 'sql/mysqld.cc' --- a/sql/mysqld.cc 2010-12-08 00:33:48 +0000 +++ b/sql/mysqld.cc 2010-12-10 12:10:20 +0000 @@ -503,7 +503,8 @@ ulong prepared_stmt_count=0; ulong thread_id=1L,current_pid; ulong slow_launch_threads = 0; uint sync_binlog_period= 0, sync_relaylog_period= 0, - sync_relayloginfo_period= 0, sync_masterinfo_period= 0; + sync_relayloginfo_period= 0, sync_masterinfo_period= 0, + mts_checkpoint_period= 0; ulong expire_logs_days = 0; const double log_10[] = { === modified file 'sql/mysqld.h' --- a/sql/mysqld.h 2010-12-08 00:33:48 +0000 +++ b/sql/mysqld.h 2010-12-10 12:10:20 +0000 @@ -129,7 +129,8 @@ extern ulong current_pid; extern ulong expire_logs_days; extern my_bool relay_log_recovery; extern uint sync_binlog_period, sync_relaylog_period, - sync_relayloginfo_period, sync_masterinfo_period; + sync_relayloginfo_period, sync_masterinfo_period, + mts_checkpoint_period; extern ulong opt_tc_log_size, tc_log_max_pages_used, tc_log_page_size; extern ulong tc_log_page_waits; extern my_bool relay_log_purge, opt_innodb_safe_binlog, opt_innodb; === modified file 'sql/rpl_rli.cc' --- a/sql/rpl_rli.cc 2010-12-09 17:45:02 +0000 +++ b/sql/rpl_rli.cc 2010-12-10 16:25:27 +0000 @@ -78,13 +78,6 @@ Relay_log_info::Relay_log_info(bool is_s group_master_log_name[0]= 0; until_log_name[0]= ign_master_log_name_end[0]= 0; - /* - We need to decide if you are going to use an - option and store it in a storage. - - 500 msec. - */ - lwm_period= 0.500; set_timespec_nsec(last_clock, 0); bzero((char*) &cache_buf, sizeof(cache_buf)); @@ -96,52 +89,6 @@ Relay_log_info::Relay_log_info(bool is_s mysql_cond_init(key_checkpoint_stop_cond, &checkpoint_stop_cond, NULL); relay_log.init_pthread_objects(); -#if 0 - - /* - Parallel slave parameters initialization is done regardless - whether the feature is or going to be active or not. - */ - trans_jobs= stmt_jobs= pending_jobs= wait_jobs= 0; - /* - parallel slave parameter to pospone Crdr reading when the number - of non-processed yet jobs becomes bigger than the limit's value - MHS_todo: consider a memory-size based param - */ - mts_slave_worker_queue_len_max= ::opt_mts_slave_worker_queue_len_max; - - // - // TODO -- ANDREI --- You need to take care of possible failures related to - // allocation. - // - uint wi= 0; - key_mutex_slave_parallel_worker= new PSI_mutex_key[slave_parallel_workers]; - key_cond_slave_parallel_worker= new PSI_cond_key[slave_parallel_workers]; - worker_mutexes= new PSI_mutex_info[slave_parallel_workers]; - worker_conds= new PSI_cond_info[slave_parallel_workers]; - for (wi= 0; wi < slave_parallel_workers; wi++) - { - worker_mutexes[wi].m_key= (PSI_mutex_key *) &(key_mutex_slave_parallel_worker[wi]); - worker_mutexes[wi].m_name= "Slave_worker::jobs_lock"; - worker_mutexes[wi].m_flags= 0; - worker_conds[wi].m_key= (PSI_cond_key *) &(key_cond_slave_parallel_worker[wi]); - worker_conds[wi].m_name= "Slave_worker::jobs_cond"; - worker_conds[wi].m_flags= 0; - } - if (PSI_server) - { - PSI_server->register_mutex("worker", worker_mutexes, - slave_parallel_workers); - PSI_server->register_cond("worker", worker_conds, - slave_parallel_workers); - } - mysql_mutex_init(key_mutex_slave_parallel_pend_jobs, &pending_jobs_lock, - MY_MUTEX_INIT_FAST); - mysql_cond_init(key_cond_slave_parallel_pend_jobs, &pending_jobs_cond, NULL); - my_init_dynamic_array(&workers, sizeof(Slave_worker *), slave_parallel_workers, 4); - -#endif - DBUG_VOID_RETURN; } @@ -207,16 +154,6 @@ Relay_log_info::~Relay_log_info() mysql_cond_destroy(&log_space_cond); relay_log.cleanup(); -#if 0 - - mysql_mutex_destroy(&pending_jobs_lock); - mysql_cond_destroy(&pending_jobs_cond); - - if (!this_worker) - delete_dynamic(&workers); - -#endif - DBUG_VOID_RETURN; } === modified file 'sql/rpl_rli.h' --- a/sql/rpl_rli.h 2010-12-09 17:45:02 +0000 +++ b/sql/rpl_rli.h 2010-12-10 16:25:27 +0000 @@ -344,7 +344,6 @@ public: size_t slave_patternload_file_size; struct timespec last_clock; - float lwm_period; Relay_log_info(bool is_slave_recovery); virtual ~Relay_log_info(); === modified file 'sql/rpl_rli_pdb.h' --- a/sql/rpl_rli_pdb.h 2010-12-10 15:50:03 +0000 +++ b/sql/rpl_rli_pdb.h 2010-12-10 16:25:27 +0000 @@ -125,41 +125,13 @@ typedef struct st_slave_job_group do \ { \ to.worker_id= from->id; \ - fprintf(stderr, "DEBUGGING Worker-Id %lu Worker-Id %lu\n", \ - to.worker_id, from->id); \ to.group_relay_log_pos= from->group_relay_log_pos; \ - fprintf(stderr, "DEBUGGING group_relay_log_pos %lu group_relay_log_pos %lu\n", \ - (ulong) to.group_relay_log_pos, (ulong) from->group_relay_log_pos); \ to.group_relay_log_name= from->group_relay_log_name; \ - fprintf(stderr, "DEBUGGING group_relay_log_name %s group_relay_log_name %s\n", \ - to.group_relay_log_name, from->group_relay_log_name); \ to.group_master_log_pos= from->group_master_log_pos; \ - fprintf(stderr, "DEBUGGING to group_master_log_pos %lu group_master_log_pos %lu\n", \ - (ulong) to.group_master_log_pos, (ulong) from->group_master_log_pos); \ to.group_master_log_name= from->group_master_log_name; \ - fprintf(stderr, "DEBUGGING to group_master_log_name %s group_master_log_pos %s\n", \ - to.group_master_log_name, from->group_master_log_name); \ to.db_ids= from->curr_group_exec_parts; \ } while (0) -#define debug_jobs(jobs) \ - do \ - { \ - Slave_job_group job; \ - for (uint pos= 0; pos < jobs.elements; pos++) \ - { \ - get_dynamic(&jobs, (uchar *) &job, pos); \ - fprintf(stderr, "DEBUGGING Worker-Id %lu, " \ - "group_relay_log_name %s, group_relay_log_pos %lu, " \ - "group_master_log_name %s, group_master_lo_pos %lu\n", \ - job.worker_id, \ - job.group_relay_log_name, \ - (ulong) job.group_relay_log_pos, \ - job.group_master_log_name, \ - (ulong) job.group_master_log_pos); \ - } \ - } while (0) - /** Group Assigned Queue whose first element identifies first gap in committed sequence. The head of the queue is therefore next to === modified file 'sql/rpl_slave.cc' --- a/sql/rpl_slave.cc 2010-12-10 15:50:03 +0000 +++ b/sql/rpl_slave.cc 2010-12-10 16:25:27 +0000 @@ -171,7 +171,7 @@ static int terminate_slave_thread(THD *t bool skip_lock); static bool check_io_slave_killed(THD *thd, Master_info *mi, const char *info); int slave_worker_exec_job(Slave_worker * w, Relay_log_info *rli); -static bool mts_checkpoint_routine(Relay_log_info *rli, ulong period, bool locked); +static bool mts_checkpoint_routine(Relay_log_info *rli, ulonglong period, bool locked); bool mts_recovery_routine(Relay_log_info *rli); /* @@ -3796,17 +3796,23 @@ err: DBUG_RETURN(0); } -int mts_jobs_cmp(Slave_job_group *id1, Slave_job_group *id2) +int mts_recovery_cmp(Slave_job_group *id1, Slave_job_group *id2) { return id1->group_relay_log_pos < id2->group_relay_log_pos ? -1 : (id1->group_relay_log_pos > id2->group_relay_log_pos ? 1 : 0); } - bool mts_recovery_routine(Relay_log_info *rli) { + Log_event *ev= NULL, *desc= NULL; + char *log_name= NULL; + const char *errmsg= NULL; + bool error= TRUE; DYNAMIC_ARRAY jobs; Slave_job_group job; + IO_CACHE log; + File file; + MY_STAT s; DBUG_ENTER("mts_recovery_routine"); DBUG_ASSERT(rli->workers.elements > 0); @@ -3821,16 +3827,157 @@ bool mts_recovery_routine(Relay_log_info get_job(worker, job); insert_dynamic(&jobs, (uchar*) &job); } - sort_dynamic(&jobs, (qsort_cmp) change_master_server_id_cmp); + sort_dynamic(&jobs, (qsort_cmp) mts_recovery_cmp); DBUG_ASSERT(rli->workers.elements == jobs.elements); - debug_jobs(jobs); - // TODO -- ALFRANIO CORE OF RECOVERY + Format_description_log_event fdle(BINLOG_VERSION); + if (!fdle.is_valid()) + goto end; + + for (uint pos= 0; pos < jobs.elements; pos++) + { + String buffer; + get_dynamic(&jobs, (uchar *) &job, pos); + + job.db_ids->pack_dynamic_ids(&buffer); + sql_print_information("Recoverying relay log info based on Worker-Id %lu, partitions %s, " + "group_relay_log_name %s, group_relay_log_pos %lu, " + "group_master_log_name %s, group_master_lo_pos %lu", + job.worker_id, + buffer.c_ptr_safe(), + job.group_relay_log_name, + (ulong) job.group_relay_log_pos, + job.group_master_log_name, + (ulong) job.group_master_log_pos); + + if (job.group_relay_log_name == NULL || job.group_relay_log_pos == 0 || + rli->get_group_relay_log_pos() >= job.group_relay_log_pos) + continue; + + if (log_name == NULL || strcmp(log_name, job.group_relay_log_name)) + { + if (ev) + { + delete ev; + ev= NULL; + } + + if (desc) + { + delete desc; + desc= NULL; + } + + if (log_name) + { + end_io_cache(&log); + mysql_file_close(file, MYF(MY_WME)); + log_name= NULL; + } + + if ((file= open_binlog(&log, job.group_relay_log_name, &errmsg)) < 0) + { + sql_print_error("%s", errmsg); + goto end; + } + log_name= job.group_relay_log_name; + + my_stat(log_name, &s, MYF(0)); + + if (!((desc= Log_event::read_log_event(&log, 0, &fdle, + opt_master_verify_checksum)) && + desc->get_type_code() == FORMAT_DESCRIPTION_EVENT)) + { + goto end; + } + } + my_b_seek(&log, job.group_relay_log_pos); + sql_print_information("Recoverying relay log info. Checking relay log name " + "%s from pos %lu, maxsize %lu.", log_name, + (ulong) job.group_relay_log_pos, (ulong) s.st_size); + + bool found= FALSE; + int res= 0; + while ((ev= Log_event::read_log_event(&log, 0, &fdle, + opt_master_verify_checksum))) + { + DBUG_ASSERT(ev->is_valid()); + + String buffer; + const char *db= ev->get_db(); + + if (db != NULL) + { + buffer.set_int(strlen(db), FALSE, &my_charset_bin); + buffer.append(db); + found= job.db_ids->search_id(buffer.c_ptr_safe()); + } + sql_print_information("Recovery relay log info. Event %s on db %s " + "sets cursor to pos %lu and was handled by worker(%d).", + ev->get_type_str(), db, (ulong) my_b_tell(&log), + found); + if (!found) + { + delete ev; + ev= NULL; + break; + } + + res= ev->apply_event(rli); + delete ev; + ev= NULL; + + if (res) + goto end; + } + if (!found) + { + sql_print_information("Before updating RLI " + "group_relay_log_name %s, " + "group_relay_log_pos %lu, " + "group_master_log_name %s, " + "group_master_lo_pos %lu.", + rli->get_group_relay_log_name(), + (ulong) rli->get_group_relay_log_pos(), + rli->get_group_master_log_name(), + (ulong) rli->get_group_master_log_pos()); + + rli->set_group_relay_log_pos(job.group_relay_log_pos); + rli->set_group_relay_log_name(job.group_relay_log_name); + rli->set_group_master_log_pos(job.group_master_log_pos); + rli->set_group_master_log_name(job.group_master_log_name); + + sql_print_information("After updating RLI " + "group_relay_log_name %s, " + "group_relay_log_pos %lu, " + "group_master_log_name %s, " + "group_master_lo_pos %lu.", + rli->get_group_relay_log_name(), + (ulong) rli->get_group_relay_log_pos(), + rli->get_group_master_log_name(), + (ulong) rli->get_group_master_log_pos()); + } + } + error= FALSE; + +end: + if (desc) + { + delete desc; + desc= NULL; + } + + if (log_name) + { + end_io_cache(&log); + mysql_file_close(file, MYF(MY_WME)); + log_name= NULL; + } delete_dynamic(&jobs); - - DBUG_RETURN(rli->flush_info(TRUE)); + + DBUG_RETURN(error ? error : rli->flush_info(TRUE)); } /** @@ -3840,7 +3987,7 @@ bool mts_recovery_routine(Relay_log_info @return FALSE success, TRUE otherwise */ -bool mts_checkpoint_routine(Relay_log_info *rli, ulong period, bool locked) +bool mts_checkpoint_routine(Relay_log_info *rli, ulonglong period, bool locked) { ulong cnt; bool error= FALSE; @@ -5659,9 +5806,9 @@ static Log_event* next_event(Relay_log_i /* MTS checkpoint in the successful read branch */ - if (rli->is_parallel_exec() && rli->lwm_period != 0.0) + if (rli->is_parallel_exec() && mts_checkpoint_period != 0) { - ulong period= static_cast(rli->lwm_period * 1000000000UL); + ulonglong period= static_cast(mts_checkpoint_period * 1000000ULL); mts_checkpoint_routine(rli, period, TRUE); // ALFRANIO --- WHAT TO DO with ERRORS? } @@ -5784,11 +5931,11 @@ static Log_event* next_event(Relay_log_i const char* old_msg= thd->proc_info; - if (rli->is_parallel_exec() && rli->lwm_period != 0.0) + if (rli->is_parallel_exec() && mts_checkpoint_period != 0) { int ret= 0; struct timespec waittime; - ulong period= static_cast(rli->lwm_period * 1000000000UL); + ulonglong period= static_cast(mts_checkpoint_period * 1000000ULL); do { mts_checkpoint_routine(rli, period, FALSE); // ALFRANIO ERROR === modified file 'sql/sys_vars.cc' --- a/sql/sys_vars.cc 2010-12-10 15:50:03 +0000 +++ b/sql/sys_vars.cc 2010-12-10 16:25:27 +0000 @@ -3104,6 +3104,13 @@ static Sys_var_uint Sys_sync_relayloginf "synchronous flushing", GLOBAL_VAR(sync_relayloginfo_period), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1)); + +static Sys_var_uint Sys_checkpoint_mts_period( + "mts_checkpoint_period", "Gather workers' activities and synchronously " + "flush relay log info to disk after every #th mili-seconds. Use 0 " + "(default) to disable checkpoint", + GLOBAL_VAR(mts_checkpoint_period), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1)); #endif static Sys_var_uint Sys_sync_binlog_period( --===============0102318253== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/andrei.elkin@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: andrei.elkin@stripped # target_branch: file:///home/andrei/MySQL/BZR/2a-23May/WL/mysql-next-\ # mr-wl5569/ # testament_sha1: d4dc3af87969d4557dd13841d20675b67af82335 # timestamp: 2010-12-10 18:25:41 +0200 # base_revision_id: andrei.elkin@stripped\ # pknsk1xyuov5y54c # # Begin bundle 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 --===============0102318253==--