slave.h 13.1 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

/*
  The replication is accomplished by starting two threads - I/O
  thread, and SQL thread. I/O thread is associated with its
  MASTER_INFO struct, so MASTER_INFO can be viewed as I/O thread
  descriptor. SQL thread is associated with RELAY_LOG_INFO struct.

  I/O thread reads maintains a connection to the master, and reads log
  events from the master as they arrive, queueing them by writing them
  out into the temporary slave binary log (relay log). The SQL thread,
  in turn, reads the slave binary log executing each event.

  Relay log is needed to be able to handle situations when there is a large
  backlog of unprocessed events from the master (eg. one particular update
  takes a day to finish), and to be able to restart the slave server without
  having to re-read the master updates.
 */
26

27
extern ulong slave_net_timeout, master_retry_count;
28 29
extern MY_BITMAP slave_error_mask;
extern bool use_slave_mask;
30
extern char* slave_load_tmpdir;
31 32 33 34 35
extern my_string master_info_file,relay_log_info_file;
extern my_string opt_relay_logname, opt_relaylog_index_name;
extern bool opt_skip_slave_start;
struct st_master_info;

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
36 37 38 39 40
/*
  TODO: this needs to be redone, but for now it does not matter since
  we do not have multi-master yet.
*/

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
#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); }

/*
  st_relay_log_info contains information on the current relay log and
  relay log offset, and master log name and log sequence corresponding to the
  last update. Additionally, misc information specific to the SQL thread is
  included.

  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()
 */
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
68

69 70
typedef struct st_relay_log_info
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
71 72 73 74 75 76
  /*** The following variables can only be read when protect by data lock ****/
  /*
    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
  */
77
  File info_fd,cur_log_fd;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
78
  // name of current read relay log
79
  char relay_log_name[FN_REFLEN];
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
80
  // master log name corresponding to current read position
81
  char master_log_name[FN_REFLEN];
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
82 83 84 85 86 87 88 89 90 91 92 93 94
  // original log position of last processed event
  volatile my_off_t master_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 ( so far, there is only one type of
    such event - Intvar_event that sets auto_increment value). However, once
    both events have been processed, we need to increment by the cumulative
    offset. pending stored the extra offset to be added to the position.
  */
  ulonglong relay_log_pos, pending;
95

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
96 97 98 99 100 101 102 103 104 105
  // protected with internal locks
  // must get data_lock when resetting the logs
  MYSQL_LOG relay_log;
  LOG_INFO linfo;
  IO_CACHE cache_buf,*cur_log;

  /*** The following variables are safe to read any time ***/

  // IO_CACHE of the info file - set only during init or end
  IO_CACHE info_file;
106

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
107 108 109 110 111
  /*
    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.
  */
112 113
  TABLE* save_temporary_tables;

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
114 115 116 117
  /*
    standard lock acquistion order to avoid deadlocks:
    run_lock, data_lock, relay_log.LOCK_log, relay_log.LOCK_index
  */
118 119
  pthread_mutex_t data_lock,run_lock;

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
120 121 122 123 124 125
  /*
    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;
126 127 128 129 130 131 132

  // if not set, the value of other members of the structure are undefined
  bool inited;

  // parent master info structure
  struct st_master_info *mi;

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
133 134 135
  /*
    Needed to deal properly with cur_log getting closed and re-opened with
    a different log under our feet
136 137 138 139
  */
  int cur_log_init_count;
  
  volatile bool abort_slave, slave_running;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
140 141 142 143 144 145

  /*
    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.
  */
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
  volatile uint32 slave_skip_counter;
#ifndef DBUG_OFF
  int events_till_abort;
#endif  
  int last_slave_errno;
  char last_slave_error[MAX_SLAVE_ERRMSG];
  THD* sql_thd;
  bool log_pos_current;
  
  st_relay_log_info():info_fd(-1),cur_log_fd(-1),inited(0),
		      cur_log_init_count(0),
		      log_pos_current(0)
    {
      relay_log_name[0] = master_log_name[0] = 0;
      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);
    }
  ~st_relay_log_info()
    {
      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);
    }
  inline void inc_pending(ulonglong val)
  {
    pending += val;
  }
  // TODO: this probably needs to be fixed
179
  inline void inc_pos(ulonglong val, ulonglong log_pos, bool skip_lock=0)
180 181 182 183 184 185
  {
    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
186
      master_log_pos = log_pos+ val;
187 188 189 190
    pthread_cond_broadcast(&data_cond);
    if (!skip_lock)
      pthread_mutex_unlock(&data_lock);
  }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
191 192 193 194
  /*
    thread safe read of position - not needed if we are in the slave thread,
    but required otherwise
  */
195 196 197 198 199 200 201 202 203 204
  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;

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
205 206 207 208 209
/*
  repopen_relay_log() is called when we notice that the current "hot" log
  got rotated under our feet
*/

210 211 212
IO_CACHE* reopen_relay_log(RELAY_LOG_INFO* rli, const char** errmsg);
Log_event* next_event(RELAY_LOG_INFO* rli);

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
213 214 215

/*
  st_master_info contains information about how to connect to a master,
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
   current master log name, and current log offset, as well as misc
   control variables

   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.

   The format of master.info file:

   log_name
   log_pos
   master_host
   master_user
   master_pass
   master_port
   master_connect_retry

   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.

   To clean up, call end_master_info()
*/
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
240

241
   
242 243
typedef struct st_master_info
{
244 245
  char master_log_name[FN_REFLEN];
  
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
246
  my_off_t master_log_pos;
247
  File fd; 
248
  IO_CACHE file;
249
  
250 251 252 253
  // the variables below are needed because we can change masters on the fly
  char host[HOSTNAME_LENGTH+1];
  char user[USERNAME_LENGTH+1];
  char password[HASH_PASSWORD_LENGTH+1];
254 255
  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
256
  THD *io_thd;
257
  RELAY_LOG_INFO rli;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
258 259
  uint port;
  uint connect_retry;
260 261 262
#ifndef DBUG_OFF
  int events_till_abort;
#endif
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
263 264
  bool inited;
  bool old_format;			// master binlog is in 3.23 format
265
  volatile bool abort_slave, slave_running;
266 267
  bool ignore_stop_event;
  
268
  
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
269
  st_master_info():fd(-1), io_thd(0), inited(0), old_format(0)
270 271
  {
    host[0] = 0; user[0] = 0; password[0] = 0;
272 273 274 275 276
    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);
277 278 279 280
  }

  ~st_master_info()
  {
281 282 283 284 285
    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);
286
  }
287

288 289
} MASTER_INFO;

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

292 293 294 295 296 297 298 299
typedef struct st_table_rule_ent
{
  char* db;
  char* tbl_name;
  uint key_len;
} TABLE_RULE_ENT;

#define TABLE_RULE_HASH_SIZE   16
300
#define TABLE_RULE_ARR_SIZE   16
301 302
#define MAX_SLAVE_ERRMSG      1024

303 304 305
#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 :\
306 307
 "FIRST")

308 309 310
/* 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
311 312 313 314 315 316

/*
  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
317

318
int init_slave();
319
void init_slave_skip_errors(char* arg);
320
int flush_master_info(MASTER_INFO* mi);
321
int flush_relay_log_info(RELAY_LOG_INFO* rli);
322
int register_slave_on_master(MYSQL* mysql);
323 324 325 326 327 328 329 330 331
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
332 333 334 335 336
/*
  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
337 338 339 340 341 342
*/
int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock,
		       pthread_mutex_t *cond_lock,
		       pthread_cond_t* start_cond,
		       volatile bool* slave_running,
		       MASTER_INFO* mi);
343

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
344
// If fd is -1, dump to NET
345 346 347
int mysql_table_dump(THD* thd, const char* db,
		     const char* tbl_name, int fd = -1);

348
// retrieve non-exitent table from master
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
349 350
int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
		       MASTER_INFO* mi, MYSQL* mysql);
351

352
int show_master_info(THD* thd, MASTER_INFO* mi);
353 354
int show_binlog_info(THD* thd);

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
355
// See if the query uses any tables that should not be replicated
356 357
int tables_ok(THD* thd, TABLE_LIST* tables);

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
358 359 360 361
/*
  Check to see if the database is ok to operate on with respect to the
  do and ignore lists - used in replication
*/
362 363 364
int db_ok(const char* db, I_List<i_string> &do_list,
	  I_List<i_string> &ignore_list );

365
int add_table_rule(HASH* h, const char* table_spec);
366
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec);
367
void init_table_rule_hash(HASH* h, bool* h_inited);
368
void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited);
369
char* rewrite_db(char* db);
370
int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code);
371
void skip_load_data_infile(NET* net);
372
void slave_print_error(RELAY_LOG_INFO* rli,int err_code, const char* msg, ...);
373

374
void end_slave(); // clean up
375 376
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
		     const char* slave_info_fname);
377
void end_master_info(MASTER_INFO* mi);
378 379 380 381 382 383 384
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);
385

386 387 388 389 390 391 392 393 394
int purge_relay_logs(RELAY_LOG_INFO* rli,bool just_reset,const char** errmsg);

extern bool opt_log_slave_updates ;
pthread_handler_decl(handle_slave_io,arg);
pthread_handler_decl(handle_slave_sql,arg);
extern bool volatile abort_loop;
extern MASTER_INFO main_mi, *active_mi; // active_mi for multi-master
extern volatile int active_mi_in_use;
extern LIST master_list;
395
extern HASH replicate_do_table, replicate_ignore_table;
396 397 398 399
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;
400

401
#ifndef DBUG_OFF
402
extern int disconnect_slave_event_count, abort_slave_event_count ;
403 404
#endif

405
// the master variables are defaults read from my.cnf or command line
406
extern uint master_port, master_connect_retry, report_port;
407
extern my_string master_user, master_password, master_host,
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
408 409
       master_info_file, relay_log_info_file, report_user, report_host,
       report_password;
410 411 412 413 414 415

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