| 1 | /* Copyright (c) 2006, 2012, Oracle and/or its affiliates. |
| 2 | |
| 3 | This program is free software; you can redistribute it and/or modify |
| 4 | it under the terms of the GNU General Public License as published by |
| 5 | the Free Software Foundation; version 2 of the License. |
| 6 | |
| 7 | This program is distributed in the hope that it will be useful, |
| 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 10 | GNU General Public License for more details. |
| 11 | |
| 12 | You should have received a copy of the GNU General Public License |
| 13 | along with this program; if not, write to the Free Software |
| 14 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
| 15 | |
| 16 | #ifndef RPL_MI_H |
| 17 | #define RPL_MI_H |
| 18 | |
| 19 | #ifdef HAVE_REPLICATION |
| 20 | |
| 21 | #include "rpl_rli.h" |
| 22 | #include "rpl_reporting.h" |
| 23 | #include <my_sys.h> |
| 24 | #include "rpl_filter.h" |
| 25 | #include "keycaches.h" |
| 26 | |
| 27 | typedef struct st_mysql MYSQL; |
| 28 | |
| 29 | /** |
| 30 | Domain id based filter to handle DO_DOMAIN_IDS and IGNORE_DOMAIN_IDS used to |
| 31 | set filtering on replication slave based on event's GTID domain_id. |
| 32 | */ |
| 33 | class Domain_id_filter |
| 34 | { |
| 35 | private: |
| 36 | /* |
| 37 | Flag to tell whether the events in the current GTID group get written to |
| 38 | the relay log. It is set according to the domain_id based filtering rule |
| 39 | on every GTID_EVENT and reset at the end of current GTID event group. |
| 40 | */ |
| 41 | bool m_filter; |
| 42 | |
| 43 | /* |
| 44 | DO_DOMAIN_IDS (0): |
| 45 | Ignore all the events which do not belong to any of the domain ids in the |
| 46 | list. |
| 47 | |
| 48 | IGNORE_DOMAIN_IDS (1): |
| 49 | Ignore the events which belong to one of the domain ids in the list. |
| 50 | */ |
| 51 | DYNAMIC_ARRAY m_domain_ids[2]; |
| 52 | |
| 53 | public: |
| 54 | /* domain id list types */ |
| 55 | enum enum_list_type { |
| 56 | DO_DOMAIN_IDS= 0, |
| 57 | IGNORE_DOMAIN_IDS |
| 58 | }; |
| 59 | |
| 60 | Domain_id_filter(); |
| 61 | |
| 62 | ~Domain_id_filter(); |
| 63 | |
| 64 | /* |
| 65 | Returns whether the current group needs to be filtered. |
| 66 | */ |
| 67 | bool is_group_filtered() { return m_filter; } |
| 68 | |
| 69 | /* |
| 70 | Checks whether the group with the specified domain_id needs to be |
| 71 | filtered and updates m_filter flag accordingly. |
| 72 | */ |
| 73 | void do_filter(ulong domain_id); |
| 74 | |
| 75 | /* |
| 76 | Reset m_filter. It should be called when IO thread receives COMMIT_EVENT or |
| 77 | XID_EVENT. |
| 78 | */ |
| 79 | void reset_filter(); |
| 80 | |
| 81 | /* |
| 82 | Update the do/ignore domain id filter lists. |
| 83 | |
| 84 | @param do_ids [IN] domain ids to be kept |
| 85 | @param ignore_ids [IN] domain ids to be filtered out |
| 86 | @param using_gtid [IN] use GTID? |
| 87 | |
| 88 | @retval false Success |
| 89 | true Error |
| 90 | */ |
| 91 | bool update_ids(DYNAMIC_ARRAY *do_ids, DYNAMIC_ARRAY *ignore_ids, |
| 92 | bool using_gtid); |
| 93 | |
| 94 | /* |
| 95 | Serialize and store the ids from domain id lists into the thd's protocol |
| 96 | buffer. |
| 97 | |
| 98 | @param thd [IN] thread handler |
| 99 | |
| 100 | @retval void |
| 101 | */ |
| 102 | void store_ids(THD *thd); |
| 103 | |
| 104 | /* |
| 105 | Initialize the given domain id list (DYNAMIC_ARRAY) with the |
| 106 | space-separated list of numbers from the specified IO_CACHE where |
| 107 | the first number is the total number of entries to follows. |
| 108 | |
| 109 | @param f [IN] IO_CACHE file |
| 110 | @param type [IN] domain id list type |
| 111 | |
| 112 | @retval false Success |
| 113 | true Error |
| 114 | */ |
| 115 | bool init_ids(IO_CACHE *f, enum_list_type type); |
| 116 | |
| 117 | /* |
| 118 | Return the elements of the give domain id list type as string. |
| 119 | |
| 120 | @param type [IN] domain id list type |
| 121 | |
| 122 | @retval a string buffer storing the total number |
| 123 | of elements followed by the individual |
| 124 | elements (space-separated) in the |
| 125 | specified list. |
| 126 | |
| 127 | Note: Its caller's responsibility to free the returned string buffer. |
| 128 | */ |
| 129 | char *as_string(enum_list_type type); |
| 130 | |
| 131 | }; |
| 132 | |
| 133 | |
| 134 | extern TYPELIB slave_parallel_mode_typelib; |
| 135 | |
| 136 | typedef struct st_rows_event_tracker |
| 137 | { |
| 138 | char binlog_file_name[FN_REFLEN]; |
| 139 | my_off_t first_seen; |
| 140 | my_off_t last_seen; |
| 141 | bool stmt_end_seen; |
| 142 | void update(const char* file_name, my_off_t pos, |
| 143 | const char* buf, |
| 144 | const Format_description_log_event *fdle); |
| 145 | void reset(); |
| 146 | bool check_and_report(const char* file_name, my_off_t pos); |
| 147 | } Rows_event_tracker; |
| 148 | |
| 149 | /***************************************************************************** |
| 150 | Replication IO Thread |
| 151 | |
| 152 | Master_info contains: |
| 153 | - information about how to connect to a master |
| 154 | - current master log name |
| 155 | - current master log offset |
| 156 | - misc control variables |
| 157 | |
| 158 | Master_info is initialized once from the master.info file if such |
| 159 | exists. Otherwise, data members corresponding to master.info fields |
| 160 | are initialized with defaults specified by master-* options. The |
| 161 | initialization is done through init_master_info() call. |
| 162 | |
| 163 | The format of master.info file: |
| 164 | |
| 165 | log_name |
| 166 | log_pos |
| 167 | master_host |
| 168 | master_user |
| 169 | master_pass |
| 170 | master_port |
| 171 | master_connect_retry |
| 172 | |
| 173 | To write out the contents of master.info file to disk ( needed every |
| 174 | time we read and queue data from the master ), a call to |
| 175 | flush_master_info() is required. |
| 176 | |
| 177 | To clean up, call end_master_info() |
| 178 | |
| 179 | *****************************************************************************/ |
| 180 | |
| 181 | class Master_info : public Slave_reporting_capability |
| 182 | { |
| 183 | public: |
| 184 | enum enum_using_gtid { |
| 185 | USE_GTID_NO= 0, USE_GTID_CURRENT_POS= 1, USE_GTID_SLAVE_POS= 2 |
| 186 | }; |
| 187 | |
| 188 | Master_info(LEX_CSTRING *connection_name, bool is_slave_recovery); |
| 189 | ~Master_info(); |
| 190 | bool shall_ignore_server_id(ulong s_id); |
| 191 | void clear_in_memory_info(bool all); |
| 192 | bool error() |
| 193 | { |
| 194 | /* If malloc() in initialization failed */ |
| 195 | return connection_name.str == 0; |
| 196 | } |
| 197 | static const char *using_gtid_astext(enum enum_using_gtid arg); |
| 198 | bool using_parallel() |
| 199 | { |
| 200 | return opt_slave_parallel_threads > 0 && |
| 201 | parallel_mode > SLAVE_PARALLEL_NONE; |
| 202 | } |
| 203 | void release(); |
| 204 | void wait_until_free(); |
| 205 | void lock_slave_threads(); |
| 206 | void unlock_slave_threads(); |
| 207 | |
| 208 | /* the variables below are needed because we can change masters on the fly */ |
| 209 | char master_log_name[FN_REFLEN+6]; /* Room for multi-*/ |
| 210 | char host[HOSTNAME_LENGTH*SYSTEM_CHARSET_MBMAXLEN+1]; |
| 211 | char user[USERNAME_LENGTH+1]; |
| 212 | char password[MAX_PASSWORD_LENGTH*SYSTEM_CHARSET_MBMAXLEN+1]; |
| 213 | LEX_CSTRING connection_name; /* User supplied connection name */ |
| 214 | LEX_CSTRING cmp_connection_name; /* Connection name in lower case */ |
| 215 | bool ssl; // enables use of SSL connection if true |
| 216 | char ssl_ca[FN_REFLEN], ssl_capath[FN_REFLEN], ssl_cert[FN_REFLEN]; |
| 217 | char ssl_cipher[FN_REFLEN], ssl_key[FN_REFLEN]; |
| 218 | char ssl_crl[FN_REFLEN], ssl_crlpath[FN_REFLEN]; |
| 219 | bool ssl_verify_server_cert; |
| 220 | |
| 221 | my_off_t master_log_pos; |
| 222 | File fd; // we keep the file open, so we need to remember the file pointer |
| 223 | IO_CACHE file; |
| 224 | |
| 225 | mysql_mutex_t data_lock, run_lock, sleep_lock, start_stop_lock; |
| 226 | mysql_cond_t data_cond, start_cond, stop_cond, sleep_cond; |
| 227 | THD *io_thd; |
| 228 | MYSQL* mysql; |
| 229 | uint32 file_id; /* for 3.23 load data infile */ |
| 230 | Relay_log_info rli; |
| 231 | uint port; |
| 232 | Rpl_filter* rpl_filter; /* Each replication can set its filter rule*/ |
| 233 | /* |
| 234 | to hold checksum alg in use until IO thread has received FD. |
| 235 | Initialized to novalue, then set to the queried from master |
| 236 | @@global.binlog_checksum and deactivated once FD has been received. |
| 237 | */ |
| 238 | enum enum_binlog_checksum_alg checksum_alg_before_fd; |
| 239 | uint connect_retry; |
| 240 | #ifndef DBUG_OFF |
| 241 | int events_till_disconnect; |
| 242 | |
| 243 | /* |
| 244 | The following are auxiliary DBUG variables used to kill IO thread in the |
| 245 | middle of a group/transaction (see "kill_slave_io_after_2_events"). |
| 246 | */ |
| 247 | bool dbug_do_disconnect; |
| 248 | int dbug_event_counter; |
| 249 | #endif |
| 250 | bool inited; |
| 251 | volatile bool abort_slave; |
| 252 | volatile uint slave_running; |
| 253 | volatile ulong slave_run_id; |
| 254 | /* |
| 255 | The difference in seconds between the clock of the master and the clock of |
| 256 | the slave (second - first). It must be signed as it may be <0 or >0. |
| 257 | clock_diff_with_master is computed when the I/O thread starts; for this the |
| 258 | I/O thread does a SELECT UNIX_TIMESTAMP() on the master. |
| 259 | "how late the slave is compared to the master" is computed like this: |
| 260 | clock_of_slave - last_timestamp_executed_by_SQL_thread - clock_diff_with_master |
| 261 | |
| 262 | */ |
| 263 | long clock_diff_with_master; |
| 264 | /* |
| 265 | Keeps track of the number of events before fsyncing. |
| 266 | The option --sync-master-info determines how many |
| 267 | events should happen before fsyncing. |
| 268 | */ |
| 269 | uint sync_counter; |
| 270 | float heartbeat_period; // interface with CHANGE MASTER or master.info |
| 271 | ulonglong received_heartbeats; // counter of received heartbeat events |
| 272 | DYNAMIC_ARRAY ignore_server_ids; |
| 273 | ulong master_id; |
| 274 | /* |
| 275 | At reconnect and until the first rotate event is seen, prev_master_id is |
| 276 | the value of master_id during the previous connection, used to detect |
| 277 | silent change of master server during reconnects. |
| 278 | */ |
| 279 | ulong prev_master_id; |
| 280 | /* |
| 281 | Which kind of GTID position (if any) is used when connecting to master. |
| 282 | |
| 283 | Note that you can not change the numeric values of these, they are used |
| 284 | in master.info. |
| 285 | */ |
| 286 | enum enum_using_gtid using_gtid; |
| 287 | |
| 288 | /* |
| 289 | This GTID position records how far we have fetched into the relay logs. |
| 290 | This is used to continue fetching when the IO thread reconnects to the |
| 291 | master. |
| 292 | |
| 293 | (Full slave stop/start does not use it, as it resets the relay logs). |
| 294 | */ |
| 295 | slave_connection_state gtid_current_pos; |
| 296 | /* |
| 297 | If events_queued_since_last_gtid is non-zero, it is the number of events |
| 298 | queued so far in the relaylog of a GTID-prefixed event group. |
| 299 | It is zero when no partial event group has been queued at the moment. |
| 300 | */ |
| 301 | uint64 events_queued_since_last_gtid; |
| 302 | /* |
| 303 | The GTID of the partially-queued event group, when |
| 304 | events_queued_since_last_gtid is non-zero. |
| 305 | */ |
| 306 | rpl_gtid last_queued_gtid; |
| 307 | /* Whether last_queued_gtid had the FL_STANDALONE flag set. */ |
| 308 | bool last_queued_gtid_standalone; |
| 309 | /* |
| 310 | When slave IO thread needs to reconnect, gtid_reconnect_event_skip_count |
| 311 | counts number of events to skip from the first GTID-prefixed event group, |
| 312 | to avoid duplicating events in the relay log. |
| 313 | */ |
| 314 | uint64 gtid_reconnect_event_skip_count; |
| 315 | /* gtid_event_seen is false until we receive first GTID event from master. */ |
| 316 | bool gtid_event_seen; |
| 317 | /** |
| 318 | The struct holds some history of Rows- log-event reading/queuing |
| 319 | by the receiver thread. Its fields are updated per each such event |
| 320 | at time of queue_event(), and they are checked to detect |
| 321 | the Rows- event group integrity violation at time of first non-Rows- |
| 322 | event gets handled. |
| 323 | */ |
| 324 | Rows_event_tracker rows_event_tracker; |
| 325 | bool in_start_all_slaves, in_stop_all_slaves; |
| 326 | bool in_flush_all_relay_logs; |
| 327 | uint users; /* Active user for object */ |
| 328 | uint killed; |
| 329 | |
| 330 | |
| 331 | /* No of DDL event group */ |
| 332 | volatile uint64 total_ddl_groups; |
| 333 | |
| 334 | /* No of non-transactional event group*/ |
| 335 | volatile uint64 total_non_trans_groups; |
| 336 | |
| 337 | /* No of transactional event group*/ |
| 338 | volatile uint64 total_trans_groups; |
| 339 | |
| 340 | /* domain-id based filter */ |
| 341 | Domain_id_filter domain_id_filter; |
| 342 | |
| 343 | /* The parallel replication mode. */ |
| 344 | enum_slave_parallel_mode parallel_mode; |
| 345 | /* |
| 346 | semi_ack is used to identify if the current binlog event needs an |
| 347 | ACK from slave, or if delay_master is enabled. |
| 348 | */ |
| 349 | int semi_ack; |
| 350 | }; |
| 351 | |
| 352 | int init_master_info(Master_info* mi, const char* master_info_fname, |
| 353 | const char* slave_info_fname, |
| 354 | bool abort_if_no_master_info_file, |
| 355 | int thread_mask); |
| 356 | void end_master_info(Master_info* mi); |
| 357 | int flush_master_info(Master_info* mi, |
| 358 | bool flush_relay_log_cache, |
| 359 | bool need_lock_relay_log); |
| 360 | void copy_filter_setting(Rpl_filter* dst_filter, Rpl_filter* src_filter); |
| 361 | void update_change_master_ids(DYNAMIC_ARRAY *new_ids, DYNAMIC_ARRAY *old_ids); |
| 362 | void prot_store_ids(THD *thd, DYNAMIC_ARRAY *ids); |
| 363 | |
| 364 | /* |
| 365 | Multi master are handled trough this struct. |
| 366 | Changes to this needs to be protected by LOCK_active_mi; |
| 367 | */ |
| 368 | |
| 369 | class Master_info_index |
| 370 | { |
| 371 | private: |
| 372 | IO_CACHE index_file; |
| 373 | char index_file_name[FN_REFLEN]; |
| 374 | |
| 375 | public: |
| 376 | Master_info_index(); |
| 377 | ~Master_info_index(); |
| 378 | |
| 379 | HASH master_info_hash; |
| 380 | |
| 381 | bool init_all_master_info(); |
| 382 | bool write_master_name_to_index_file(LEX_CSTRING *connection_name, |
| 383 | bool do_sync); |
| 384 | |
| 385 | bool check_duplicate_master_info(LEX_CSTRING *connection_name, |
| 386 | const char *host, uint port); |
| 387 | bool add_master_info(Master_info *mi, bool write_to_file); |
| 388 | bool remove_master_info(Master_info *mi); |
| 389 | Master_info *get_master_info(const LEX_CSTRING *connection_name, |
| 390 | Sql_condition::enum_warning_level warning); |
| 391 | bool start_all_slaves(THD *thd); |
| 392 | bool stop_all_slaves(THD *thd); |
| 393 | void free_connections(); |
| 394 | bool flush_all_relay_logs(); |
| 395 | }; |
| 396 | |
| 397 | |
| 398 | /* |
| 399 | The class rpl_io_thread_info is the THD::system_thread_info for the IO thread. |
| 400 | */ |
| 401 | class rpl_io_thread_info |
| 402 | { |
| 403 | public: |
| 404 | }; |
| 405 | |
| 406 | |
| 407 | Master_info *get_master_info(const LEX_CSTRING *connection_name, |
| 408 | Sql_condition::enum_warning_level warning); |
| 409 | bool check_master_connection_name(LEX_CSTRING *name); |
| 410 | void create_logfile_name_with_suffix(char *res_file_name, size_t length, |
| 411 | const char *info_file, |
| 412 | bool append, |
| 413 | LEX_CSTRING *suffix); |
| 414 | |
| 415 | uchar *get_key_master_info(Master_info *mi, size_t *length, |
| 416 | my_bool not_used __attribute__((unused))); |
| 417 | void free_key_master_info(Master_info *mi); |
| 418 | uint any_slave_sql_running(bool already_locked); |
| 419 | bool give_error_if_slave_running(bool already_lock); |
| 420 | |
| 421 | #endif /* HAVE_REPLICATION */ |
| 422 | #endif /* RPL_MI_H */ |
| 423 | |