slave.h 15 KB
Newer Older
1 2 3
#ifndef SLAVE_H
#define SLAVE_H

4
#include "mysql.h"
5
#include "my_list.h"
6
#define SLAVE_NET_TIMEOUT  3600
7
#define MAX_SLAVE_ERRMSG   1024
8
#define MAX_SLAVE_ERROR    2000
9

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*****************************************************************************

  MySQL Replication

  Replication is implemented via two types of threads:

    I/O Thread - One of these threads is started for each master server.
                 They maintain a connection to their master server, read log
                 events from the master as they arrive, and queues them into
                 a single, shared relay log file.  A MASTER_INFO struct
                 represents each of these threads.

    SQL Thread - One of these threads is started and reads from the relay log
                 file, executing each event.  A RELAY_LOG_INFO struct
                 represents this thread.

  Buffering in the relay log file makes it unnecessary to reread events from
  a master server across a slave restart.  It also decouples the slave from
  the master where long-running updates and event logging are concerned--ie
  it can continue to log new events while a slow query executes on the slave.

*****************************************************************************/
32

33
extern ulong slave_net_timeout, master_retry_count;
34 35
extern MY_BITMAP slave_error_mask;
extern bool use_slave_mask;
36
extern char* slave_load_tmpdir;
37 38
extern my_string master_info_file,relay_log_info_file;
extern my_string opt_relay_logname, opt_relaylog_index_name;
39 40
extern my_bool opt_skip_slave_start, opt_reckless_slave;
extern my_bool opt_log_slave_updates;
41
extern ulonglong relay_log_space_limit;
42 43
struct st_master_info;

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
44 45 46 47 48
/*
  TODO: this needs to be redone, but for now it does not matter since
  we do not have multi-master yet.
*/

49 50 51 52 53 54 55 56
#define LOCK_ACTIVE_MI { pthread_mutex_lock(&LOCK_active_mi); \
 ++active_mi_in_use; \
 pthread_mutex_unlock(&LOCK_active_mi);}

#define UNLOCK_ACTIVE_MI { pthread_mutex_lock(&LOCK_active_mi); \
 --active_mi_in_use; \
 pthread_mutex_unlock(&LOCK_active_mi); }

57 58 59 60 61 62 63 64 65 66
/*****************************************************************************

  Replication SQL Thread

  st_relay_log_info contains:
    - the current relay log
    - the current relay log offset
    - master log name
    - master log sequence corresponding to the last update
    - misc information specific to the SQL thread
67 68 69 70 71 72 73 74 75 76 77 78 79

  st_relay_log_info is initialized from the slave.info file if such exists.
  Otherwise, data members are intialized with defaults. The initialization is
  done with init_relay_log_info() call.

  The format of slave.info file:

  relay_log_name
  relay_log_pos
  master_log_name
  master_log_pos

  To clean up, call end_relay_log_info()
80 81

*****************************************************************************/
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
82

83 84
typedef struct st_relay_log_info
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
85
  /*** The following variables can only be read when protect by data lock ****/
86

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
87 88 89 90 91
  /*
    info_fd - file descriptor of the info file. set only during
    initialization or clean up - safe to read anytime
    cur_log_fd - file descriptor of the current read  relay log
  */
92
  File info_fd,cur_log_fd;
salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
93
  /* name of current read relay log */
94
  char relay_log_name[FN_REFLEN];
salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
95
  /* master log name corresponding to current read position */
96
  char master_log_name[FN_REFLEN];
salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
97
  /* original log position of last processed event */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
98 99 100
  volatile my_off_t master_log_pos;

  /*
101 102
    Protected with internal locks.
    Must get data_lock when resetting the logs.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
103 104 105 106 107
  */
  MYSQL_LOG relay_log;
  LOG_INFO linfo;
  IO_CACHE cache_buf,*cur_log;

salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
108
  /* The following variables are safe to read any time */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
109

salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
110
  /* IO_CACHE of the info file - set only during init or end */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
111
  IO_CACHE info_file;
112

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
113 114 115 116 117
  /*
    When we restart slave thread we need to have access to the previously
    created temporary tables. Modified only on init/end and by the SQL
    thread, read only by SQL thread.
  */
118 119
  TABLE* save_temporary_tables;

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
120 121 122 123
  /*
    standard lock acquistion order to avoid deadlocks:
    run_lock, data_lock, relay_log.LOCK_log, relay_log.LOCK_index
  */
124 125
  pthread_mutex_t data_lock,run_lock;

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
126 127 128 129 130 131
  /*
    start_cond is broadcast when SQL thread is started
    stop_cond - when stopped
    data_cond - when data protected by data_lock changes
  */
  pthread_cond_t start_cond, stop_cond, data_cond;
132

salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
133
  /* parent master info structure */
134 135
  struct st_master_info *mi;

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
136 137 138
  /*
    Needed to deal properly with cur_log getting closed and re-opened with
    a different log under our feet
139
  */
140
  uint32 cur_log_old_open_count;
141
  
142
  /*
143 144 145 146 147 148 149 150 151 152 153 154
    relay_log_pos - Current offset in the relay log.
    pending       - In some cases we do not increment offset immediately
                    after processing an event, because the following event
                    needs to be processed atomically together with this one
                    such as:

                    Intvar_event - sets auto_increment value
                    Rand_event   - sets the random seed

                    However, once both events have been processed, we need to
                    increment by the cumulative offset.  'pending' stores the
                    extra offset to be added to the position.
155 156 157
  */
  ulonglong relay_log_pos, pending;
  ulonglong log_space_limit,log_space_total;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
158

159 160 161 162 163 164 165 166
  /*
    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;

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
167 168 169 170 171
  /*
    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.
  */
172
  volatile uint32 slave_skip_counter;
173
  volatile ulong abort_pos_wait;	/* Incremented on change master */
174
  volatile ulong slave_run_id;		/* Incremented on slave start */
175 176 177 178
  pthread_mutex_t log_space_lock;
  pthread_cond_t log_space_cond;
  THD * sql_thd;
  int last_slave_errno;
179 180 181 182
#ifndef DBUG_OFF
  int events_till_abort;
#endif  
  char last_slave_error[MAX_SLAVE_ERRMSG];
183

salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
184
  /* if not set, the value of other members of the structure are undefined */
185 186
  bool inited;
  volatile bool abort_slave, slave_running;
187
  bool log_pos_current;
188
  bool skip_log_purge;
189
  
190
  st_relay_log_info()
191
  :info_fd(-1),cur_log_fd(-1), cur_log_old_open_count(0), abort_pos_wait(0),
192 193
   slave_run_id(0), inited(0), abort_slave(0), slave_running(0),
   log_pos_current(0), skip_log_purge(0)
194 195 196
  {
    relay_log_name[0] = master_log_name[0] = 0;
    bzero(&info_file,sizeof(info_file));
197
    bzero(&cache_buf, sizeof(cache_buf));
198 199 200 201 202 203 204 205
    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);
    pthread_cond_init(&data_cond, NULL);
    pthread_cond_init(&start_cond, NULL);
    pthread_cond_init(&stop_cond, NULL);
    pthread_cond_init(&log_space_cond, NULL);
  }
206
  ~st_relay_log_info()
207 208 209 210 211 212 213 214 215
  {
     pthread_mutex_destroy(&run_lock);
     pthread_mutex_destroy(&data_lock);
     pthread_mutex_destroy(&log_space_lock);
     pthread_cond_destroy(&data_cond);
     pthread_cond_destroy(&start_cond);
     pthread_cond_destroy(&stop_cond);
     pthread_cond_destroy(&log_space_cond);
   }
216 217 218 219
  inline void inc_pending(ulonglong val)
  {
    pending += val;
  }
salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
220
  /* TODO: this probably needs to be fixed */
221
  inline void inc_pos(ulonglong val, ulonglong log_pos, bool skip_lock=0)
222 223 224 225 226 227
  {
    if (!skip_lock)
      pthread_mutex_lock(&data_lock);
    relay_log_pos += val+pending;
    pending = 0;
    if (log_pos)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
228
      master_log_pos = log_pos+ val;
229 230 231 232
    pthread_cond_broadcast(&data_cond);
    if (!skip_lock)
      pthread_mutex_unlock(&data_lock);
  }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
233 234
  /*
    thread safe read of position - not needed if we are in the slave thread,
235
    but required otherwise as var is a longlong
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
236
  */
237 238 239 240 241 242 243 244 245 246
  inline void read_pos(ulonglong& var)
  {
    pthread_mutex_lock(&data_lock);
    var = relay_log_pos;
    pthread_mutex_unlock(&data_lock);
  }

  int wait_for_pos(THD* thd, String* log_name, ulonglong log_pos);
} RELAY_LOG_INFO;

247

248 249
Log_event* next_event(RELAY_LOG_INFO* rli);

250 251 252 253 254 255 256 257 258
/*****************************************************************************

  Replication IO Thread

  st_master_info contains:
    - information about how to connect to a master
    - current master log name
    - current master log offset
    - misc control variables
259

260 261 262 263
  st_master_info is initialized once from the master.info file if such
  exists. Otherwise, data members corresponding to master.info fields
  are initialized with defaults specified by master-* options. The
  initialization is done through init_master_info() call.
264

265
  The format of master.info file:
266

267 268 269 270 271 272 273
  log_name
  log_pos
  master_host
  master_user
  master_pass
  master_port
  master_connect_retry
274

275 276 277
  To write out the contents of master.info file to disk ( needed every
  time we read and queue data from the master ), a call to
  flush_master_info() is required.
278

279
  To clean up, call end_master_info()
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
280

281 282
*****************************************************************************/

283 284
typedef struct st_master_info
{
285 286
  char master_log_name[FN_REFLEN];
  
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
287
  my_off_t master_log_pos;
288
  File fd; // we keep the file open, so we need to remember the file pointer
289
  IO_CACHE file;
290
  
salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
291
  /* the variables below are needed because we can change masters on the fly */
292 293 294
  char host[HOSTNAME_LENGTH+1];
  char user[USERNAME_LENGTH+1];
  char password[HASH_PASSWORD_LENGTH+1];
295 296
  pthread_mutex_t data_lock,run_lock;
  pthread_cond_t data_cond,start_cond,stop_cond;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
297
  THD *io_thd;
298
  MYSQL* mysql;
salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
299
  uint32 file_id; /* for 3.23 load data infile */
300
  RELAY_LOG_INFO rli;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
301 302
  uint port;
  uint connect_retry;
303 304 305
#ifndef DBUG_OFF
  int events_till_abort;
#endif
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
306
  bool inited;
salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
307
  bool old_format;			/* master binlog is in 3.23 format */
308
  volatile bool abort_slave, slave_running;
309
  volatile ulong slave_run_id;
310 311
  bool ignore_stop_event;
  
312
  
313 314 315
  st_master_info()
    :fd(-1), io_thd(0), inited(0), old_format(0),abort_slave(0),
     slave_running(0), slave_run_id(0)
316 317
  {
    host[0] = 0; user[0] = 0; password[0] = 0;
318
    bzero(&file, sizeof(file));
319 320 321 322 323
    pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
    pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
    pthread_cond_init(&data_cond, NULL);
    pthread_cond_init(&start_cond, NULL);
    pthread_cond_init(&stop_cond, NULL);
324 325 326 327
  }

  ~st_master_info()
  {
328 329 330 331 332
    pthread_mutex_destroy(&run_lock);
    pthread_mutex_destroy(&data_lock);
    pthread_cond_destroy(&data_cond);
    pthread_cond_destroy(&start_cond);
    pthread_cond_destroy(&stop_cond);
333
  }
334

335 336
} MASTER_INFO;

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
337

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
338
int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len);
339

340 341 342 343 344 345 346 347
typedef struct st_table_rule_ent
{
  char* db;
  char* tbl_name;
  uint key_len;
} TABLE_RULE_ENT;

#define TABLE_RULE_HASH_SIZE   16
348
#define TABLE_RULE_ARR_SIZE   16
349 350
#define MAX_SLAVE_ERRMSG      1024

351 352 353
#define RPL_LOG_NAME (rli->master_log_name[0] ? rli->master_log_name :\
 "FIRST")
#define IO_RPL_LOG_NAME (mi->master_log_name[0] ? mi->master_log_name :\
354 355
 "FIRST")

356 357 358
/* masks for start/stop operations on io and sql slave threads */
#define SLAVE_IO  1
#define SLAVE_SQL 2
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
359 360 361 362 363 364

/*
  If the following is set, if first gives an error, second will be
  tried. Otherwise, if first fails, we fail.
*/
#define SLAVE_FORCE_ALL 4
365

366
int init_slave();
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
367
void init_slave_skip_errors(const char* arg);
368 369
bool flush_master_info(MASTER_INFO* mi);
bool flush_relay_log_info(RELAY_LOG_INFO* rli);
370
int register_slave_on_master(MYSQL* mysql);
371 372 373 374 375 376 377 378 379
int terminate_slave_threads(MASTER_INFO* mi, int thread_mask,
			     bool skip_lock = 0);
int terminate_slave_thread(THD* thd, pthread_mutex_t* term_mutex,
			   pthread_mutex_t* cond_lock,
			   pthread_cond_t* term_cond,
			   volatile bool* slave_running);
int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
			MASTER_INFO* mi, const char* master_info_fname,
			const char* slave_info_fname, int thread_mask);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
380 381 382 383 384
/*
  cond_lock is usually same as start_lock. It is needed for the case when
  start_lock is 0 which happens if start_slave_thread() is called already
  inside the start_lock section, but at the same time we want a
  pthread_cond_wait() on start_cond,start_lock
385 386 387 388
*/
int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock,
		       pthread_mutex_t *cond_lock,
		       pthread_cond_t* start_cond,
389 390
		       volatile bool *slave_running,
		       volatile ulong *slave_run_id,
391
		       MASTER_INFO* mi);
392

salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
393
/* If fd is -1, dump to NET */
394 395 396
int mysql_table_dump(THD* thd, const char* db,
		     const char* tbl_name, int fd = -1);

salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
397
/* retrieve non-exitent table from master */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
398 399
int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
		       MASTER_INFO* mi, MYSQL* mysql);
400

401
int show_master_info(THD* thd, MASTER_INFO* mi);
402 403
int show_binlog_info(THD* thd);

salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
404
/* See if the query uses any tables that should not be replicated */
405 406
int tables_ok(THD* thd, TABLE_LIST* tables);

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
407 408 409 410
/*
  Check to see if the database is ok to operate on with respect to the
  do and ignore lists - used in replication
*/
411 412 413
int db_ok(const char* db, I_List<i_string> &do_list,
	  I_List<i_string> &ignore_list );

414
int add_table_rule(HASH* h, const char* table_spec);
415
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec);
416
void init_table_rule_hash(HASH* h, bool* h_inited);
417
void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited);
418
char* rewrite_db(char* db);
419
int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code);
420
void skip_load_data_infile(NET* net);
421
void slave_print_error(RELAY_LOG_INFO* rli,int err_code, const char* msg, ...);
422

salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
423
void end_slave(); /* clean up */
424
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
425 426
		     const char* slave_info_fname,
		     bool abort_if_no_master_info_file);
427
void end_master_info(MASTER_INFO* mi);
428 429 430 431 432 433 434
int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname);
void end_relay_log_info(RELAY_LOG_INFO* rli);
void lock_slave_threads(MASTER_INFO* mi);
void unlock_slave_threads(MASTER_INFO* mi);
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);
435

436 437
int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
		     const char** errmsg);
438

439 440
extern "C" pthread_handler_decl(handle_slave_io,arg);
extern "C" pthread_handler_decl(handle_slave_sql,arg);
441
extern bool volatile abort_loop;
salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
442
extern MASTER_INFO main_mi, *active_mi; /* active_mi for multi-master */
443 444
extern volatile int active_mi_in_use;
extern LIST master_list;
445
extern HASH replicate_do_table, replicate_ignore_table;
446 447 448 449
extern DYNAMIC_ARRAY  replicate_wild_do_table, replicate_wild_ignore_table;
extern bool do_table_inited, ignore_table_inited,
	    wild_do_table_inited, wild_ignore_table_inited;
extern bool table_rules_on;
450

451
extern int disconnect_slave_event_count, abort_slave_event_count ;
452

salle@geopard.online.bg's avatar
salle@geopard.online.bg committed
453
/* the master variables are defaults read from my.cnf or command line */
454
extern uint master_port, master_connect_retry, report_port;
455
extern my_string master_user, master_password, master_host,
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
456 457
       master_info_file, relay_log_info_file, report_user, report_host,
       report_password;
458 459 460 461 462 463

extern I_List<i_string> replicate_do_db, replicate_ignore_db;
extern I_List<i_string_pair> replicate_rewrite_db;
extern I_List<THD> threads;

#endif