~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to server/log.cc

Removed/replaced DBUG symbols and TRUE/FALSE

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-2003 MySQL AB
 
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
 
 
17
/**
 
18
  @file
 
19
 
 
20
  @brief
 
21
  logging of commands
 
22
 
 
23
  @todo
 
24
    Abort logging when we get an error in reading or writing log files
 
25
*/
 
26
 
 
27
#include "mysql_priv.h"
 
28
#include "sql_repl.h"
 
29
#include "rpl_filter.h"
 
30
#include "rpl_rli.h"
 
31
 
 
32
#include <my_dir.h>
 
33
#include <stdarg.h>
 
34
#include <m_ctype.h>                            // For test_if_number
 
35
 
 
36
#include <mysql/plugin.h>
 
37
 
 
38
/* max size of the log message */
 
39
#define MAX_LOG_BUFFER_SIZE 1024
 
40
#define MAX_USER_HOST_SIZE 512
 
41
#define MAX_TIME_SIZE 32
 
42
#define MY_OFF_T_UNDEF (~(my_off_t)0UL)
 
43
 
 
44
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
 
45
 
 
46
LOGGER logger;
 
47
 
 
48
MYSQL_BIN_LOG mysql_bin_log;
 
49
ulong sync_binlog_counter= 0;
 
50
 
 
51
static bool test_if_number(const char *str,
 
52
                           long *res, bool allow_wildcards);
 
53
static int binlog_init(void *p);
 
54
static int binlog_close_connection(handlerton *hton, THD *thd);
 
55
static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv);
 
56
static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv);
 
57
static int binlog_commit(handlerton *hton, THD *thd, bool all);
 
58
static int binlog_rollback(handlerton *hton, THD *thd, bool all);
 
59
static int binlog_prepare(handlerton *hton, THD *thd, bool all);
 
60
 
 
61
/**
 
62
  Silence all errors and warnings reported when performing a write
 
63
  to a log table.
 
64
  Errors and warnings are not reported to the client or SQL exception
 
65
  handlers, so that the presence of logging does not interfere and affect
 
66
  the logic of an application.
 
67
*/
 
68
class Silence_log_table_errors : public Internal_error_handler
 
69
{
 
70
  char m_message[MYSQL_ERRMSG_SIZE];
 
71
public:
 
72
  Silence_log_table_errors()
 
73
  {
 
74
    m_message[0]= '\0';
 
75
  }
 
76
 
 
77
  virtual ~Silence_log_table_errors() {}
 
78
 
 
79
  virtual bool handle_error(uint sql_errno, const char *message,
 
80
                            MYSQL_ERROR::enum_warning_level level,
 
81
                            THD *thd);
 
82
  const char *message() const { return m_message; }
 
83
};
 
84
 
 
85
bool
 
86
Silence_log_table_errors::handle_error(uint /* sql_errno */,
 
87
                                       const char *message_arg,
 
88
                                       MYSQL_ERROR::enum_warning_level /* level */,
 
89
                                       THD * /* thd */)
 
90
{
 
91
  strmake(m_message, message_arg, sizeof(m_message)-1);
 
92
  return true;
 
93
}
 
94
 
 
95
 
 
96
sql_print_message_func sql_print_message_handlers[3] =
 
97
{
 
98
  sql_print_information,
 
99
  sql_print_warning,
 
100
  sql_print_error
 
101
};
 
102
 
 
103
 
 
104
char *make_default_log_name(char *buff,const char* log_ext)
 
105
{
 
106
  strmake(buff, pidfile_name, FN_REFLEN-5);
 
107
  return fn_format(buff, buff, mysql_data_home, log_ext,
 
108
                   MYF(MY_UNPACK_FILENAME|MY_REPLACE_EXT));
 
109
}
 
110
 
 
111
/*
 
112
  Helper class to hold a mutex for the duration of the
 
113
  block.
 
114
 
 
115
  Eliminates the need for explicit unlocking of mutexes on, e.g.,
 
116
  error returns.  On passing a null pointer, the sentry will not do
 
117
  anything.
 
118
 */
 
119
class Mutex_sentry
 
120
{
 
121
public:
 
122
  Mutex_sentry(pthread_mutex_t *mutex)
 
123
    : m_mutex(mutex)
 
124
  {
 
125
    if (m_mutex)
 
126
      pthread_mutex_lock(mutex);
 
127
  }
 
128
 
 
129
  ~Mutex_sentry()
 
130
  {
 
131
    if (m_mutex)
 
132
      pthread_mutex_unlock(m_mutex);
 
133
    m_mutex= 0;
 
134
  }
 
135
 
 
136
private:
 
137
  pthread_mutex_t *m_mutex;
 
138
 
 
139
  // It's not allowed to copy this object in any way
 
140
  Mutex_sentry(Mutex_sentry const&);
 
141
  void operator=(Mutex_sentry const&);
 
142
};
 
143
 
 
144
/*
 
145
  Helper class to store binary log transaction data.
 
146
*/
 
147
class binlog_trx_data {
 
148
public:
 
149
  binlog_trx_data()
 
150
    : at_least_one_stmt(0), m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF)
 
151
  {
 
152
    trans_log.end_of_file= max_binlog_cache_size;
 
153
  }
 
154
 
 
155
  ~binlog_trx_data()
 
156
  {
 
157
    assert(pending() == NULL);
 
158
    close_cached_file(&trans_log);
 
159
  }
 
160
 
 
161
  my_off_t position() const {
 
162
    return my_b_tell(&trans_log);
 
163
  }
 
164
 
 
165
  bool empty() const
 
166
  {
 
167
    return pending() == NULL && my_b_tell(&trans_log) == 0;
 
168
  }
 
169
 
 
170
  /*
 
171
    Truncate the transaction cache to a certain position. This
 
172
    includes deleting the pending event.
 
173
   */
 
174
  void truncate(my_off_t pos)
 
175
  {
 
176
    delete pending();
 
177
    set_pending(0);
 
178
    reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0);
 
179
    if (pos < before_stmt_pos)
 
180
      before_stmt_pos= MY_OFF_T_UNDEF;
 
181
 
 
182
    /*
 
183
      The only valid positions that can be truncated to are at the
 
184
      beginning of a statement. We are relying on this fact to be able
 
185
      to set the at_least_one_stmt flag correctly. In other word, if
 
186
      we are truncating to the beginning of the transaction cache,
 
187
      there will be no statements in the cache, otherwhise, we will
 
188
      have at least one statement in the transaction cache.
 
189
     */
 
190
    at_least_one_stmt= (pos > 0);
 
191
  }
 
192
 
 
193
  /*
 
194
    Reset the entire contents of the transaction cache, emptying it
 
195
    completely.
 
196
   */
 
197
  void reset() {
 
198
    if (!empty())
 
199
      truncate(0);
 
200
    before_stmt_pos= MY_OFF_T_UNDEF;
 
201
    trans_log.end_of_file= max_binlog_cache_size;
 
202
  }
 
203
 
 
204
  Rows_log_event *pending() const
 
205
  {
 
206
    return m_pending;
 
207
  }
 
208
 
 
209
  void set_pending(Rows_log_event *const pending)
 
210
  {
 
211
    m_pending= pending;
 
212
  }
 
213
 
 
214
  IO_CACHE trans_log;                         // The transaction cache
 
215
 
 
216
  /**
 
217
    Boolean that is true if there is at least one statement in the
 
218
    transaction cache.
 
219
  */
 
220
  bool at_least_one_stmt;
 
221
 
 
222
private:
 
223
  /*
 
224
    Pending binrows event. This event is the event where the rows are
 
225
    currently written.
 
226
   */
 
227
  Rows_log_event *m_pending;
 
228
 
 
229
public:
 
230
  /*
 
231
    Binlog position before the start of the current statement.
 
232
  */
 
233
  my_off_t before_stmt_pos;
 
234
};
 
235
 
 
236
handlerton *binlog_hton;
 
237
 
 
238
 
 
239
/* Check if a given table is opened log table */
 
240
int check_if_log_table(uint db_len __attribute__((__unused__)),
 
241
                       const char *db __attribute__((__unused__)),
 
242
                       uint table_name_len __attribute__((__unused__)),
 
243
                       const char *table_name __attribute__((__unused__)),
 
244
                       uint check_if_opened __attribute__((__unused__)))
 
245
{
 
246
  return 0;
 
247
}
 
248
 
 
249
/* log event handlers */
 
250
 
 
251
bool Log_to_file_event_handler::
 
252
  log_error(enum loglevel level, const char *format,
 
253
            va_list args)
 
254
{
 
255
  return vprint_msg_to_log(level, format, args);
 
256
}
 
257
 
 
258
void Log_to_file_event_handler::init_pthread_objects()
 
259
{
 
260
  mysql_log.init_pthread_objects();
 
261
  mysql_slow_log.init_pthread_objects();
 
262
}
 
263
 
 
264
 
 
265
/** Wrapper around MYSQL_LOG::write() for slow log. */
 
266
 
 
267
bool Log_to_file_event_handler::
 
268
  log_slow(THD *thd, time_t current_time, time_t query_start_arg,
 
269
           const char *user_host, uint user_host_len,
 
270
           ulonglong query_utime, ulonglong lock_utime, bool is_command,
 
271
           const char *sql_text, uint sql_text_len)
 
272
{
 
273
  return mysql_slow_log.write(thd, current_time, query_start_arg,
 
274
                              user_host, user_host_len,
 
275
                              query_utime, lock_utime, is_command,
 
276
                              sql_text, sql_text_len);
 
277
}
 
278
 
 
279
 
 
280
/**
 
281
   Wrapper around MYSQL_LOG::write() for general log. We need it since we
 
282
   want all log event handlers to have the same signature.
 
283
*/
 
284
 
 
285
bool Log_to_file_event_handler::
 
286
  log_general(THD *thd __attribute__((__unused__)),
 
287
              time_t event_time, const char *user_host,
 
288
              uint user_host_len, int thread_id,
 
289
              const char *command_type, uint command_type_len,
 
290
              const char *sql_text, uint sql_text_len,
 
291
              CHARSET_INFO *client_cs __attribute__((__unused__)))
 
292
{
 
293
  return mysql_log.write(event_time, user_host, user_host_len,
 
294
                         thread_id, command_type, command_type_len,
 
295
                         sql_text, sql_text_len);
 
296
}
 
297
 
 
298
 
 
299
bool Log_to_file_event_handler::init()
 
300
{
 
301
  if (!is_initialized)
 
302
  {
 
303
    if (opt_slow_log)
 
304
      mysql_slow_log.open_slow_log(sys_var_slow_log_path.value);
 
305
 
 
306
    if (opt_log)
 
307
      mysql_log.open_query_log(sys_var_general_log_path.value);
 
308
 
 
309
    is_initialized= true;
 
310
  }
 
311
 
 
312
  return false;
 
313
}
 
314
 
 
315
 
 
316
void Log_to_file_event_handler::cleanup()
 
317
{
 
318
  mysql_log.cleanup();
 
319
  mysql_slow_log.cleanup();
 
320
}
 
321
 
 
322
void Log_to_file_event_handler::flush()
 
323
{
 
324
  /* reopen log files */
 
325
  if (opt_log)
 
326
    mysql_log.reopen_file();
 
327
  if (opt_slow_log)
 
328
    mysql_slow_log.reopen_file();
 
329
}
 
330
 
 
331
/*
 
332
  Log error with all enabled log event handlers
 
333
 
 
334
  SYNOPSIS
 
335
    error_log_print()
 
336
 
 
337
    level             The level of the error significance: NOTE,
 
338
                      WARNING or ERROR.
 
339
    format            format string for the error message
 
340
    args              list of arguments for the format string
 
341
 
 
342
  RETURN
 
343
    FALSE - OK
 
344
    TRUE - error occured
 
345
*/
 
346
 
 
347
bool LOGGER::error_log_print(enum loglevel level, const char *format,
 
348
                             va_list args)
 
349
{
 
350
  bool error= false;
 
351
  Log_event_handler **current_handler;
 
352
 
 
353
  /* currently we don't need locking here as there is no error_log table */
 
354
  for (current_handler= error_log_handler_list ; *current_handler ;)
 
355
    error= (*current_handler++)->log_error(level, format, args) || error;
 
356
 
 
357
  return error;
 
358
}
 
359
 
 
360
 
 
361
void LOGGER::cleanup_base()
 
362
{
 
363
  assert(inited == 1);
 
364
  rwlock_destroy(&LOCK_logger);
 
365
  if (file_log_handler)
 
366
    file_log_handler->cleanup();
 
367
}
 
368
 
 
369
 
 
370
void LOGGER::cleanup_end()
 
371
{
 
372
  assert(inited == 1);
 
373
  if (file_log_handler)
 
374
    delete file_log_handler;
 
375
}
 
376
 
 
377
 
 
378
/**
 
379
  Perform basic log initialization: create file-based log handler and
 
380
  init error log.
 
381
*/
 
382
void LOGGER::init_base()
 
383
{
 
384
  assert(inited == 0);
 
385
  inited= 1;
 
386
 
 
387
  /*
 
388
    Here we create file log handler. We don't do it for the table log handler
 
389
    here as it cannot be created so early. The reason is THD initialization,
 
390
    which depends on the system variables (parsed later).
 
391
  */
 
392
  if (!file_log_handler)
 
393
    file_log_handler= new Log_to_file_event_handler;
 
394
 
 
395
  /* by default we use traditional error log */
 
396
  init_error_log(LOG_FILE);
 
397
 
 
398
  file_log_handler->init_pthread_objects();
 
399
  my_rwlock_init(&LOCK_logger, NULL);
 
400
}
 
401
 
 
402
 
 
403
bool LOGGER::flush_logs(THD *thd __attribute__((__unused__)))
 
404
{
 
405
  int rc= 0;
 
406
 
 
407
  /*
 
408
    Now we lock logger, as nobody should be able to use logging routines while
 
409
    log tables are closed
 
410
  */
 
411
  logger.lock_exclusive();
 
412
 
 
413
  /* reopen log files */
 
414
  file_log_handler->flush();
 
415
 
 
416
  /* end of log flush */
 
417
  logger.unlock();
 
418
  return rc;
 
419
}
 
420
 
 
421
 
 
422
/*
 
423
  Log slow query with all enabled log event handlers
 
424
 
 
425
  SYNOPSIS
 
426
    slow_log_print()
 
427
 
 
428
    thd                 THD of the query being logged
 
429
    query               The query being logged
 
430
    query_length        The length of the query string
 
431
    current_utime       Current time in microseconds (from undefined start)
 
432
 
 
433
  RETURN
 
434
    FALSE   OK
 
435
    TRUE    error occured
 
436
*/
 
437
 
 
438
bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length,
 
439
                            ulonglong current_utime)
 
440
 
 
441
{
 
442
  bool error= false;
 
443
  Log_event_handler **current_handler;
 
444
  bool is_command= false;
 
445
  char user_host_buff[MAX_USER_HOST_SIZE];
 
446
  Security_context *sctx= thd->security_ctx;
 
447
  uint user_host_len= 0;
 
448
  ulonglong query_utime, lock_utime;
 
449
 
 
450
  /*
 
451
    Print the message to the buffer if we have slow log enabled
 
452
  */
 
453
 
 
454
  if (*slow_log_handler_list)
 
455
  {
 
456
    time_t current_time;
 
457
 
 
458
    /* do not log slow queries from replication threads */
 
459
    if (thd->slave_thread && !opt_log_slow_slave_statements)
 
460
      return 0;
 
461
 
 
462
    lock_shared();
 
463
    if (!opt_slow_log)
 
464
    {
 
465
      unlock();
 
466
      return 0;
 
467
    }
 
468
 
 
469
    /* fill in user_host value: the format is "%s[%s] @ %s [%s]" */
 
470
    user_host_len= (strxnmov(user_host_buff, MAX_USER_HOST_SIZE,
 
471
                             sctx->priv_user ? sctx->priv_user : "", "[",
 
472
                             sctx->user ? sctx->user : "", "] @ ",
 
473
                             sctx->host ? sctx->host : "", " [",
 
474
                             sctx->ip ? sctx->ip : "", "]", NullS) -
 
475
                    user_host_buff);
 
476
 
 
477
    current_time= my_time_possible_from_micro(current_utime);
 
478
    if (thd->start_utime)
 
479
    {
 
480
      query_utime= (current_utime - thd->start_utime);
 
481
      lock_utime=  (thd->utime_after_lock - thd->start_utime);
 
482
    }
 
483
    else
 
484
    {
 
485
      query_utime= lock_utime= 0;
 
486
    }
 
487
 
 
488
    if (!query)
 
489
    {
 
490
      is_command= true;
 
491
      query= command_name[thd->command].str;
 
492
      query_length= command_name[thd->command].length;
 
493
    }
 
494
 
 
495
    for (current_handler= slow_log_handler_list; *current_handler ;)
 
496
      error= (*current_handler++)->log_slow(thd, current_time, thd->start_time,
 
497
                                            user_host_buff, user_host_len,
 
498
                                            query_utime, lock_utime, is_command,
 
499
                                            query, query_length) || error;
 
500
 
 
501
    unlock();
 
502
  }
 
503
  return error;
 
504
}
 
505
 
 
506
bool LOGGER::general_log_write(THD *thd, enum enum_server_command command,
 
507
                               const char *query, uint query_length)
 
508
{
 
509
  bool error= false;
 
510
  Log_event_handler **current_handler= general_log_handler_list;
 
511
  char user_host_buff[MAX_USER_HOST_SIZE];
 
512
  Security_context *sctx= thd->security_ctx;
 
513
  ulong id;
 
514
  uint user_host_len= 0;
 
515
  time_t current_time;
 
516
 
 
517
  if (thd)
 
518
    id= thd->thread_id;                 /* Normal thread */
 
519
  else
 
520
    id= 0;                              /* Log from connect handler */
 
521
 
 
522
  lock_shared();
 
523
  if (!opt_log)
 
524
  {
 
525
    unlock();
 
526
    return 0;
 
527
  }
 
528
  user_host_len= strxnmov(user_host_buff, MAX_USER_HOST_SIZE,
 
529
                          sctx->priv_user ? sctx->priv_user : "", "[",
 
530
                          sctx->user ? sctx->user : "", "] @ ",
 
531
                          sctx->host ? sctx->host : "", " [",
 
532
                          sctx->ip ? sctx->ip : "", "]", NullS) -
 
533
                                                          user_host_buff;
 
534
 
 
535
  current_time= my_time(0);
 
536
 
 
537
  while (*current_handler)
 
538
    error|= (*current_handler++)->
 
539
      log_general(thd, current_time, user_host_buff,
 
540
                  user_host_len, id,
 
541
                  command_name[(uint) command].str,
 
542
                  command_name[(uint) command].length,
 
543
                  query, query_length,
 
544
                  thd->variables.character_set_client) || error;
 
545
  unlock();
 
546
 
 
547
  return error;
 
548
}
 
549
 
 
550
bool LOGGER::general_log_print(THD *thd, enum enum_server_command command,
 
551
                               const char *format, va_list args)
 
552
{
 
553
  uint message_buff_len= 0;
 
554
  char message_buff[MAX_LOG_BUFFER_SIZE];
 
555
 
 
556
  /* prepare message */
 
557
  if (format)
 
558
    message_buff_len= vsnprintf(message_buff, sizeof(message_buff),
 
559
                                   format, args);
 
560
  else
 
561
    message_buff[0]= '\0';
 
562
 
 
563
  return general_log_write(thd, command, message_buff, message_buff_len);
 
564
}
 
565
 
 
566
void LOGGER::init_error_log(uint error_log_printer)
 
567
{
 
568
  if (error_log_printer & LOG_NONE)
 
569
  {
 
570
    error_log_handler_list[0]= 0;
 
571
    return;
 
572
  }
 
573
 
 
574
  switch (error_log_printer) {
 
575
  case LOG_FILE:
 
576
    error_log_handler_list[0]= file_log_handler;
 
577
    error_log_handler_list[1]= 0;
 
578
    break;
 
579
    /* these two are disabled for now */
 
580
  case LOG_TABLE:
 
581
    assert(0);
 
582
    break;
 
583
  case LOG_TABLE|LOG_FILE:
 
584
    assert(0);
 
585
    break;
 
586
  }
 
587
}
 
588
 
 
589
void LOGGER::init_slow_log(uint slow_log_printer)
 
590
{
 
591
  if (slow_log_printer & LOG_NONE)
 
592
  {
 
593
    slow_log_handler_list[0]= 0;
 
594
    return;
 
595
  }
 
596
 
 
597
  slow_log_handler_list[0]= file_log_handler;
 
598
  slow_log_handler_list[1]= 0;
 
599
}
 
600
 
 
601
void LOGGER::init_general_log(uint general_log_printer)
 
602
{
 
603
  if (general_log_printer & LOG_NONE)
 
604
  {
 
605
    general_log_handler_list[0]= 0;
 
606
    return;
 
607
  }
 
608
 
 
609
  general_log_handler_list[0]= file_log_handler;
 
610
  general_log_handler_list[1]= 0;
 
611
}
 
612
 
 
613
 
 
614
bool LOGGER::activate_log_handler(THD* thd __attribute__((__unused__)),
 
615
                                  uint log_type)
 
616
{
 
617
  MYSQL_QUERY_LOG *file_log;
 
618
  bool res= false;
 
619
  lock_exclusive();
 
620
  switch (log_type) {
 
621
  case QUERY_LOG_SLOW:
 
622
    if (!opt_slow_log)
 
623
    {
 
624
      file_log= file_log_handler->get_mysql_slow_log();
 
625
 
 
626
      file_log->open_slow_log(sys_var_slow_log_path.value);
 
627
      init_slow_log(log_output_options);
 
628
      opt_slow_log= true;
 
629
    }
 
630
    break;
 
631
  case QUERY_LOG_GENERAL:
 
632
    if (!opt_log)
 
633
    {
 
634
      file_log= file_log_handler->get_mysql_log();
 
635
 
 
636
      file_log->open_query_log(sys_var_general_log_path.value);
 
637
      init_general_log(log_output_options);
 
638
      opt_log= true;
 
639
    }
 
640
    break;
 
641
  default:
 
642
    assert(0);
 
643
  }
 
644
  unlock();
 
645
  return res;
 
646
}
 
647
 
 
648
 
 
649
void LOGGER::deactivate_log_handler(THD *thd __attribute__((__unused__)),
 
650
                                    uint log_type)
 
651
{
 
652
  my_bool *tmp_opt= 0;
 
653
  MYSQL_LOG *file_log;
 
654
 
 
655
  switch (log_type) {
 
656
  case QUERY_LOG_SLOW:
 
657
    tmp_opt= &opt_slow_log;
 
658
    file_log= file_log_handler->get_mysql_slow_log();
 
659
    break;
 
660
  case QUERY_LOG_GENERAL:
 
661
    tmp_opt= &opt_log;
 
662
    file_log= file_log_handler->get_mysql_log();
 
663
    break;
 
664
  default:
 
665
    assert(0);                                  // Impossible
 
666
  }
 
667
 
 
668
  if (!(*tmp_opt))
 
669
    return;
 
670
 
 
671
  lock_exclusive();
 
672
  file_log->close(0);
 
673
  *tmp_opt= false;
 
674
  unlock();
 
675
}
 
676
 
 
677
int LOGGER::set_handlers(uint error_log_printer,
 
678
                         uint slow_log_printer,
 
679
                         uint general_log_printer)
 
680
{
 
681
  /* error log table is not supported yet */
 
682
  assert(error_log_printer < LOG_TABLE);
 
683
 
 
684
  lock_exclusive();
 
685
 
 
686
  init_error_log(error_log_printer);
 
687
  init_slow_log(slow_log_printer);
 
688
  init_general_log(general_log_printer);
 
689
 
 
690
  unlock();
 
691
 
 
692
  return 0;
 
693
}
 
694
 
 
695
 
 
696
 /*
 
697
  Save position of binary log transaction cache.
 
698
 
 
699
  SYNPOSIS
 
700
    binlog_trans_log_savepos()
 
701
 
 
702
    thd      The thread to take the binlog data from
 
703
    pos      Pointer to variable where the position will be stored
 
704
 
 
705
  DESCRIPTION
 
706
 
 
707
    Save the current position in the binary log transaction cache into
 
708
    the variable pointed to by 'pos'
 
709
 */
 
710
 
 
711
static void
 
712
binlog_trans_log_savepos(THD *thd, my_off_t *pos)
 
713
{
 
714
  assert(pos != NULL);
 
715
  if (thd_get_ha_data(thd, binlog_hton) == NULL)
 
716
    thd->binlog_setup_trx_data();
 
717
  binlog_trx_data *const trx_data=
 
718
    (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
 
719
  assert(mysql_bin_log.is_open());
 
720
  *pos= trx_data->position();
 
721
  return;
 
722
}
 
723
 
 
724
 
 
725
/*
 
726
  Truncate the binary log transaction cache.
 
727
 
 
728
  SYNPOSIS
 
729
    binlog_trans_log_truncate()
 
730
 
 
731
    thd      The thread to take the binlog data from
 
732
    pos      Position to truncate to
 
733
 
 
734
  DESCRIPTION
 
735
 
 
736
    Truncate the binary log to the given position. Will not change
 
737
    anything else.
 
738
 
 
739
 */
 
740
static void
 
741
binlog_trans_log_truncate(THD *thd, my_off_t pos)
 
742
{
 
743
  assert(thd_get_ha_data(thd, binlog_hton) != NULL);
 
744
  /* Only true if binlog_trans_log_savepos() wasn't called before */
 
745
  assert(pos != ~(my_off_t) 0);
 
746
 
 
747
  binlog_trx_data *const trx_data=
 
748
    (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
 
749
  trx_data->truncate(pos);
 
750
  return;
 
751
}
 
752
 
 
753
 
 
754
/*
 
755
  this function is mostly a placeholder.
 
756
  conceptually, binlog initialization (now mostly done in MYSQL_BIN_LOG::open)
 
757
  should be moved here.
 
758
*/
 
759
 
 
760
int binlog_init(void *p)
 
761
{
 
762
  binlog_hton= (handlerton *)p;
 
763
  binlog_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
 
764
  binlog_hton->db_type=DB_TYPE_BINLOG;
 
765
  binlog_hton->savepoint_offset= sizeof(my_off_t);
 
766
  binlog_hton->close_connection= binlog_close_connection;
 
767
  binlog_hton->savepoint_set= binlog_savepoint_set;
 
768
  binlog_hton->savepoint_rollback= binlog_savepoint_rollback;
 
769
  binlog_hton->commit= binlog_commit;
 
770
  binlog_hton->rollback= binlog_rollback;
 
771
  binlog_hton->prepare= binlog_prepare;
 
772
  binlog_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
 
773
  return 0;
 
774
}
 
775
 
 
776
static int binlog_close_connection(handlerton *hton __attribute__((__unused__)),
 
777
                                   THD *thd)
 
778
{
 
779
  binlog_trx_data *const trx_data=
 
780
    (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
 
781
  assert(trx_data->empty());
 
782
  thd_set_ha_data(thd, binlog_hton, NULL);
 
783
  trx_data->~binlog_trx_data();
 
784
  my_free((uchar*)trx_data, MYF(0));
 
785
  return 0;
 
786
}
 
787
 
 
788
/*
 
789
  End a transaction.
 
790
 
 
791
  SYNOPSIS
 
792
    binlog_end_trans()
 
793
 
 
794
    thd      The thread whose transaction should be ended
 
795
    trx_data Pointer to the transaction data to use
 
796
    end_ev   The end event to use, or NULL
 
797
    all      True if the entire transaction should be ended, false if
 
798
             only the statement transaction should be ended.
 
799
 
 
800
  DESCRIPTION
 
801
 
 
802
    End the currently open transaction. The transaction can be either
 
803
    a real transaction (if 'all' is true) or a statement transaction
 
804
    (if 'all' is false).
 
805
 
 
806
    If 'end_ev' is NULL, the transaction is a rollback of only
 
807
    transactional tables, so the transaction cache will be truncated
 
808
    to either just before the last opened statement transaction (if
 
809
    'all' is false), or reset completely (if 'all' is true).
 
810
 */
 
811
static int
 
812
binlog_end_trans(THD *thd, binlog_trx_data *trx_data,
 
813
                 Log_event *end_ev, bool all)
 
814
{
 
815
  int error=0;
 
816
  IO_CACHE *trans_log= &trx_data->trans_log;
 
817
 
 
818
  /*
 
819
    NULL denotes ROLLBACK with nothing to replicate: i.e., rollback of
 
820
    only transactional tables.  If the transaction contain changes to
 
821
    any non-transactiona tables, we need write the transaction and log
 
822
    a ROLLBACK last.
 
823
  */
 
824
  if (end_ev != NULL)
 
825
  {
 
826
    /*
 
827
      Doing a commit or a rollback including non-transactional tables,
 
828
      i.e., ending a transaction where we might write the transaction
 
829
      cache to the binary log.
 
830
 
 
831
      We can always end the statement when ending a transaction since
 
832
      transactions are not allowed inside stored functions.  If they
 
833
      were, we would have to ensure that we're not ending a statement
 
834
      inside a stored function.
 
835
     */
 
836
    thd->binlog_flush_pending_rows_event(true);
 
837
 
 
838
    error= mysql_bin_log.write(thd, &trx_data->trans_log, end_ev);
 
839
    trx_data->reset();
 
840
 
 
841
    /*
 
842
      We need to step the table map version after writing the
 
843
      transaction cache to disk.
 
844
    */
 
845
    mysql_bin_log.update_table_map_version();
 
846
    statistic_increment(binlog_cache_use, &LOCK_status);
 
847
    if (trans_log->disk_writes != 0)
 
848
    {
 
849
      statistic_increment(binlog_cache_disk_use, &LOCK_status);
 
850
      trans_log->disk_writes= 0;
 
851
    }
 
852
  }
 
853
  else
 
854
  {
 
855
    /*
 
856
      If rolling back an entire transaction or a single statement not
 
857
      inside a transaction, we reset the transaction cache.
 
858
 
 
859
      If rolling back a statement in a transaction, we truncate the
 
860
      transaction cache to remove the statement.
 
861
     */
 
862
    if (all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT)))
 
863
    {
 
864
      trx_data->reset();
 
865
 
 
866
      assert(!thd->binlog_get_pending_rows_event());
 
867
      thd->clear_binlog_table_maps();
 
868
    }
 
869
    else                                        // ...statement
 
870
      trx_data->truncate(trx_data->before_stmt_pos);
 
871
 
 
872
    /*
 
873
      We need to step the table map version on a rollback to ensure
 
874
      that a new table map event is generated instead of the one that
 
875
      was written to the thrown-away transaction cache.
 
876
    */
 
877
    mysql_bin_log.update_table_map_version();
 
878
  }
 
879
 
 
880
  return(error);
 
881
}
 
882
 
 
883
static int binlog_prepare(handlerton *hton __attribute__((__unused__)),
 
884
                          THD *thd __attribute__((__unused__)),
 
885
                          bool all __attribute__((__unused__)))
 
886
{
 
887
  /*
 
888
    do nothing.
 
889
    just pretend we can do 2pc, so that MySQL won't
 
890
    switch to 1pc.
 
891
    real work will be done in MYSQL_BIN_LOG::log_xid()
 
892
  */
 
893
  return 0;
 
894
}
 
895
 
 
896
#define YESNO(X) ((X) ? "yes" : "no")
 
897
 
 
898
/**
 
899
  This function is called once after each statement.
 
900
 
 
901
  It has the responsibility to flush the transaction cache to the
 
902
  binlog file on commits.
 
903
 
 
904
  @param hton  The binlog handlerton.
 
905
  @param thd   The client thread that executes the transaction.
 
906
  @param all   This is @c true if this is a real transaction commit, and
 
907
               @false otherwise.
 
908
 
 
909
  @see handlerton::commit
 
910
*/
 
911
static int binlog_commit(handlerton *hton __attribute__((__unused__)),
 
912
                         THD *thd, bool all)
 
913
{
 
914
  binlog_trx_data *const trx_data=
 
915
    (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
 
916
 
 
917
  if (trx_data->empty())
 
918
  {
 
919
    // we're here because trans_log was flushed in MYSQL_BIN_LOG::log_xid()
 
920
    trx_data->reset();
 
921
    return(0);
 
922
  }
 
923
 
 
924
  /*
 
925
    Decision table for committing a transaction. The top part, the
 
926
    *conditions* represent different cases that can occur, and hte
 
927
    bottom part, the *actions*, represent what should be done in that
 
928
    particular case.
 
929
 
 
930
    Real transaction        'all' was true
 
931
 
 
932
    Statement in cache      There were at least one statement in the
 
933
                            transaction cache
 
934
 
 
935
    In transaction          We are inside a transaction
 
936
 
 
937
    Stmt modified non-trans The statement being committed modified a
 
938
                            non-transactional table
 
939
 
 
940
    All modified non-trans  Some statement before this one in the
 
941
                            transaction modified a non-transactional
 
942
                            table
 
943
 
 
944
 
 
945
    =============================  = = = = = = = = = = = = = = = =
 
946
    Real transaction               N N N N N N N N N N N N N N N N
 
947
    Statement in cache             N N N N N N N N Y Y Y Y Y Y Y Y
 
948
    In transaction                 N N N N Y Y Y Y N N N N Y Y Y Y
 
949
    Stmt modified non-trans        N N Y Y N N Y Y N N Y Y N N Y Y
 
950
    All modified non-trans         N Y N Y N Y N Y N Y N Y N Y N Y
 
951
 
 
952
    Action: (C)ommit/(A)ccumulate  C C - C A C - C - - - - A A - A
 
953
    =============================  = = = = = = = = = = = = = = = =
 
954
 
 
955
 
 
956
    =============================  = = = = = = = = = = = = = = = =
 
957
    Real transaction               Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
 
958
    Statement in cache             N N N N N N N N Y Y Y Y Y Y Y Y
 
959
    In transaction                 N N N N Y Y Y Y N N N N Y Y Y Y
 
960
    Stmt modified non-trans        N N Y Y N N Y Y N N Y Y N N Y Y
 
961
    All modified non-trans         N Y N Y N Y N Y N Y N Y N Y N Y
 
962
 
 
963
    (C)ommit/(A)ccumulate/(-)      - - - - C C - C - - - - C C - C
 
964
    =============================  = = = = = = = = = = = = = = = =
 
965
 
 
966
    In other words, we commit the transaction if and only if both of
 
967
    the following are true:
 
968
     - We are not in a transaction and committing a statement
 
969
 
 
970
     - We are in a transaction and one (or more) of the following are
 
971
       true:
 
972
 
 
973
       - A full transaction is committed
 
974
 
 
975
         OR
 
976
 
 
977
       - A non-transactional statement is committed and there is
 
978
         no statement cached
 
979
 
 
980
    Otherwise, we accumulate the statement
 
981
  */
 
982
  ulonglong const in_transaction=
 
983
    thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN);
 
984
  if ((in_transaction && (all || (!trx_data->at_least_one_stmt && thd->transaction.stmt.modified_non_trans_table))) || (!in_transaction && !all))
 
985
  {
 
986
    Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), true, false);
 
987
    qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
 
988
    int error= binlog_end_trans(thd, trx_data, &qev, all);
 
989
    return(error);
 
990
  }
 
991
  return(0);
 
992
}
 
993
 
 
994
/**
 
995
  This function is called when a transaction involving a transactional
 
996
  table is rolled back.
 
997
 
 
998
  It has the responsibility to flush the transaction cache to the
 
999
  binlog file. However, if the transaction does not involve
 
1000
  non-transactional tables, nothing needs to be logged.
 
1001
 
 
1002
  @param hton  The binlog handlerton.
 
1003
  @param thd   The client thread that executes the transaction.
 
1004
  @param all   This is @c true if this is a real transaction rollback, and
 
1005
               @false otherwise.
 
1006
 
 
1007
  @see handlerton::rollback
 
1008
*/
 
1009
static int binlog_rollback(handlerton *hton __attribute__((__unused__)),
 
1010
                           THD *thd, bool all)
 
1011
{
 
1012
  int error=0;
 
1013
  binlog_trx_data *const trx_data=
 
1014
    (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
 
1015
 
 
1016
  if (trx_data->empty()) {
 
1017
    trx_data->reset();
 
1018
    return(0);
 
1019
  }
 
1020
 
 
1021
  if ((all && thd->transaction.all.modified_non_trans_table) ||
 
1022
      (!all && thd->transaction.stmt.modified_non_trans_table) ||
 
1023
      (thd->options & OPTION_KEEP_LOG))
 
1024
  {
 
1025
    /*
 
1026
      We write the transaction cache with a rollback last if we have
 
1027
      modified any non-transactional table. We do this even if we are
 
1028
      committing a single statement that has modified a
 
1029
      non-transactional table since it can have modified a
 
1030
      transactional table in that statement as well, which needs to be
 
1031
      rolled back on the slave.
 
1032
    */
 
1033
    Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), true, false);
 
1034
    qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
 
1035
    error= binlog_end_trans(thd, trx_data, &qev, all);
 
1036
  }
 
1037
  else if ((all && !thd->transaction.all.modified_non_trans_table) ||
 
1038
           (!all && !thd->transaction.stmt.modified_non_trans_table))
 
1039
  {
 
1040
    /*
 
1041
      If we have modified only transactional tables, we can truncate
 
1042
      the transaction cache without writing anything to the binary
 
1043
      log.
 
1044
     */
 
1045
    error= binlog_end_trans(thd, trx_data, 0, all);
 
1046
  }
 
1047
  return(error);
 
1048
}
 
1049
 
 
1050
/**
 
1051
  @note
 
1052
  How do we handle this (unlikely but legal) case:
 
1053
  @verbatim
 
1054
    [transaction] + [update to non-trans table] + [rollback to savepoint] ?
 
1055
  @endverbatim
 
1056
  The problem occurs when a savepoint is before the update to the
 
1057
  non-transactional table. Then when there's a rollback to the savepoint, if we
 
1058
  simply truncate the binlog cache, we lose the part of the binlog cache where
 
1059
  the update is. If we want to not lose it, we need to write the SAVEPOINT
 
1060
  command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter
 
1061
  is easy: it's just write at the end of the binlog cache, but the former
 
1062
  should be *inserted* to the place where the user called SAVEPOINT. The
 
1063
  solution is that when the user calls SAVEPOINT, we write it to the binlog
 
1064
  cache (so no need to later insert it). As transactions are never intermixed
 
1065
  in the binary log (i.e. they are serialized), we won't have conflicts with
 
1066
  savepoint names when using mysqlbinlog or in the slave SQL thread.
 
1067
  Then when ROLLBACK TO SAVEPOINT is called, if we updated some
 
1068
  non-transactional table, we don't truncate the binlog cache but instead write
 
1069
  ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which
 
1070
  will chop the SAVEPOINT command from the binlog cache, which is good as in
 
1071
  that case there is no need to have it in the binlog).
 
1072
*/
 
1073
 
 
1074
static int binlog_savepoint_set(handlerton *hton __attribute__((__unused__)),
 
1075
                                THD *thd, void *sv)
 
1076
{
 
1077
  binlog_trans_log_savepos(thd, (my_off_t*) sv);
 
1078
  /* Write it to the binary log */
 
1079
  
 
1080
  int const error=
 
1081
    thd->binlog_query(THD::STMT_QUERY_TYPE,
 
1082
                      thd->query, thd->query_length, true, false);
 
1083
  return(error);
 
1084
}
 
1085
 
 
1086
static int binlog_savepoint_rollback(handlerton *hton __attribute__((__unused__)),
 
1087
                                     THD *thd, void *sv)
 
1088
{
 
1089
  /*
 
1090
    Write ROLLBACK TO SAVEPOINT to the binlog cache if we have updated some
 
1091
    non-transactional table. Otherwise, truncate the binlog cache starting
 
1092
    from the SAVEPOINT command.
 
1093
  */
 
1094
  if (unlikely(thd->transaction.all.modified_non_trans_table || 
 
1095
               (thd->options & OPTION_KEEP_LOG)))
 
1096
  {
 
1097
    int error=
 
1098
      thd->binlog_query(THD::STMT_QUERY_TYPE,
 
1099
                        thd->query, thd->query_length, true, false);
 
1100
    return(error);
 
1101
  }
 
1102
  binlog_trans_log_truncate(thd, *(my_off_t*)sv);
 
1103
  return(0);
 
1104
}
 
1105
 
 
1106
 
 
1107
int check_binlog_magic(IO_CACHE* log, const char** errmsg)
 
1108
{
 
1109
  char magic[4];
 
1110
  assert(my_b_tell(log) == 0);
 
1111
 
 
1112
  if (my_b_read(log, (uchar*) magic, sizeof(magic)))
 
1113
  {
 
1114
    *errmsg = "I/O error reading the header from the binary log";
 
1115
    sql_print_error("%s, errno=%d, io cache code=%d", *errmsg, my_errno,
 
1116
                    log->error);
 
1117
    return 1;
 
1118
  }
 
1119
  if (memcmp(magic, BINLOG_MAGIC, sizeof(magic)))
 
1120
  {
 
1121
    *errmsg = "Binlog has bad magic number;  It's not a binary log file that can be used by this version of MySQL";
 
1122
    return 1;
 
1123
  }
 
1124
  return 0;
 
1125
}
 
1126
 
 
1127
 
 
1128
File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg)
 
1129
{
 
1130
  File file;
 
1131
 
 
1132
  if ((file = my_open(log_file_name, O_RDONLY | O_BINARY | O_SHARE, 
 
1133
                      MYF(MY_WME))) < 0)
 
1134
  {
 
1135
    sql_print_error("Failed to open log (file '%s', errno %d)",
 
1136
                    log_file_name, my_errno);
 
1137
    *errmsg = "Could not open log file";
 
1138
    goto err;
 
1139
  }
 
1140
  if (init_io_cache(log, file, IO_SIZE*2, READ_CACHE, 0, 0,
 
1141
                    MYF(MY_WME|MY_DONT_CHECK_FILESIZE)))
 
1142
  {
 
1143
    sql_print_error("Failed to create a cache on log (file '%s')",
 
1144
                    log_file_name);
 
1145
    *errmsg = "Could not open log file";
 
1146
    goto err;
 
1147
  }
 
1148
  if (check_binlog_magic(log,errmsg))
 
1149
    goto err;
 
1150
  return(file);
 
1151
 
 
1152
err:
 
1153
  if (file >= 0)
 
1154
  {
 
1155
    my_close(file,MYF(0));
 
1156
    end_io_cache(log);
 
1157
  }
 
1158
  return(-1);
 
1159
}
 
1160
 
 
1161
 
 
1162
/**
 
1163
  Find a unique filename for 'filename.#'.
 
1164
 
 
1165
  Set '#' to a number as low as possible.
 
1166
 
 
1167
  @return
 
1168
    nonzero if not possible to get unique filename
 
1169
*/
 
1170
 
 
1171
static int find_uniq_filename(char *name)
 
1172
{
 
1173
  long                  number;
 
1174
  uint                  i;
 
1175
  char                  buff[FN_REFLEN];
 
1176
  struct st_my_dir     *dir_info;
 
1177
  register struct fileinfo *file_info;
 
1178
  ulong                 max_found=0;
 
1179
  size_t                buf_length, length;
 
1180
  char                  *start, *end;
 
1181
 
 
1182
  length= dirname_part(buff, name, &buf_length);
 
1183
  start=  name + length;
 
1184
  end=    strend(start);
 
1185
 
 
1186
  *end='.';
 
1187
  length= (size_t) (end-start+1);
 
1188
 
 
1189
  if (!(dir_info = my_dir(buff,MYF(MY_DONT_SORT))))
 
1190
  {                                             // This shouldn't happen
 
1191
    strmov(end,".1");                           // use name+1
 
1192
    return(0);
 
1193
  }
 
1194
  file_info= dir_info->dir_entry;
 
1195
  for (i=dir_info->number_off_files ; i-- ; file_info++)
 
1196
  {
 
1197
    if (bcmp((uchar*) file_info->name, (uchar*) start, length) == 0 &&
 
1198
        test_if_number(file_info->name+length, &number,0))
 
1199
    {
 
1200
      set_if_bigger(max_found,(ulong) number);
 
1201
    }
 
1202
  }
 
1203
  my_dirend(dir_info);
 
1204
 
 
1205
  *end++='.';
 
1206
  sprintf(end,"%06ld",max_found+1);
 
1207
  return(0);
 
1208
}
 
1209
 
 
1210
 
 
1211
void MYSQL_LOG::init(enum_log_type log_type_arg,
 
1212
                     enum cache_type io_cache_type_arg)
 
1213
{
 
1214
  log_type= log_type_arg;
 
1215
  io_cache_type= io_cache_type_arg;
 
1216
  return;
 
1217
}
 
1218
 
 
1219
 
 
1220
/*
 
1221
  Open a (new) log file.
 
1222
 
 
1223
  SYNOPSIS
 
1224
    open()
 
1225
 
 
1226
    log_name            The name of the log to open
 
1227
    log_type_arg        The type of the log. E.g. LOG_NORMAL
 
1228
    new_name            The new name for the logfile. This is only needed
 
1229
                        when the method is used to open the binlog file.
 
1230
    io_cache_type_arg   The type of the IO_CACHE to use for this log file
 
1231
 
 
1232
  DESCRIPTION
 
1233
    Open the logfile, init IO_CACHE and write startup messages
 
1234
    (in case of general and slow query logs).
 
1235
 
 
1236
  RETURN VALUES
 
1237
    0   ok
 
1238
    1   error
 
1239
*/
 
1240
 
 
1241
bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
 
1242
                     const char *new_name, enum cache_type io_cache_type_arg)
 
1243
{
 
1244
  char buff[FN_REFLEN];
 
1245
  File file= -1;
 
1246
  int open_flags= O_CREAT | O_BINARY;
 
1247
 
 
1248
  write_error= 0;
 
1249
 
 
1250
  init(log_type_arg, io_cache_type_arg);
 
1251
 
 
1252
  if (!(name= my_strdup(log_name, MYF(MY_WME))))
 
1253
  {
 
1254
    name= (char *)log_name; // for the error message
 
1255
    goto err;
 
1256
  }
 
1257
 
 
1258
  if (new_name)
 
1259
    strmov(log_file_name, new_name);
 
1260
  else if (generate_new_name(log_file_name, name))
 
1261
    goto err;
 
1262
 
 
1263
  if (io_cache_type == SEQ_READ_APPEND)
 
1264
    open_flags |= O_RDWR | O_APPEND;
 
1265
  else
 
1266
    open_flags |= O_WRONLY | (log_type == LOG_BIN ? 0 : O_APPEND);
 
1267
 
 
1268
  db[0]= 0;
 
1269
 
 
1270
  if ((file= my_open(log_file_name, open_flags,
 
1271
                     MYF(MY_WME | ME_WAITTANG))) < 0 ||
 
1272
      init_io_cache(&log_file, file, IO_SIZE, io_cache_type,
 
1273
                    my_tell(file, MYF(MY_WME)), 0,
 
1274
                    MYF(MY_WME | MY_NABP |
 
1275
                        ((log_type == LOG_BIN) ? MY_WAIT_IF_FULL : 0))))
 
1276
    goto err;
 
1277
 
 
1278
  if (log_type == LOG_NORMAL)
 
1279
  {
 
1280
    char *end;
 
1281
    int len=snprintf(buff, sizeof(buff), "%s, Version: %s (%s). "
 
1282
                     "started with:\nTCP Port: %d, Named Pipe: %s\n",
 
1283
                     my_progname, server_version, MYSQL_COMPILATION_COMMENT,
 
1284
                     mysqld_port, ""
 
1285
                     );
 
1286
    end= strnmov(buff + len, "Time                 Id Command    Argument\n",
 
1287
                 sizeof(buff) - len);
 
1288
    if (my_b_write(&log_file, (uchar*) buff, (uint) (end-buff)) ||
 
1289
        flush_io_cache(&log_file))
 
1290
      goto err;
 
1291
  }
 
1292
 
 
1293
  log_state= LOG_OPENED;
 
1294
  return(0);
 
1295
 
 
1296
err:
 
1297
  sql_print_error("Could not use %s for logging (error %d). \
 
1298
Turning logging off for the whole duration of the MySQL server process. \
 
1299
To turn it on again: fix the cause, \
 
1300
shutdown the MySQL server and restart it.", name, errno);
 
1301
  if (file >= 0)
 
1302
    my_close(file, MYF(0));
 
1303
  end_io_cache(&log_file);
 
1304
  safeFree(name);
 
1305
  log_state= LOG_CLOSED;
 
1306
  return(1);
 
1307
}
 
1308
 
 
1309
MYSQL_LOG::MYSQL_LOG()
 
1310
  : name(0), write_error(false), inited(false), log_type(LOG_UNKNOWN),
 
1311
    log_state(LOG_CLOSED)
 
1312
{
 
1313
  /*
 
1314
    We don't want to initialize LOCK_Log here as such initialization depends on
 
1315
    safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
 
1316
    called only in main(). Doing initialization here would make it happen
 
1317
    before main().
 
1318
  */
 
1319
  bzero((char*) &log_file, sizeof(log_file));
 
1320
}
 
1321
 
 
1322
void MYSQL_LOG::init_pthread_objects()
 
1323
{
 
1324
  assert(inited == 0);
 
1325
  inited= 1;
 
1326
  (void) pthread_mutex_init(&LOCK_log, MY_MUTEX_INIT_SLOW);
 
1327
}
 
1328
 
 
1329
/*
 
1330
  Close the log file
 
1331
 
 
1332
  SYNOPSIS
 
1333
    close()
 
1334
    exiting     Bitmask. For the slow and general logs the only used bit is
 
1335
                LOG_CLOSE_TO_BE_OPENED. This is used if we intend to call
 
1336
                open at once after close.
 
1337
 
 
1338
  NOTES
 
1339
    One can do an open on the object at once after doing a close.
 
1340
    The internal structures are not freed until cleanup() is called
 
1341
*/
 
1342
 
 
1343
void MYSQL_LOG::close(uint exiting)
 
1344
{                                       // One can't set log_type here!
 
1345
  if (log_state == LOG_OPENED)
 
1346
  {
 
1347
    end_io_cache(&log_file);
 
1348
 
 
1349
    if (my_sync(log_file.file, MYF(MY_WME)) && ! write_error)
 
1350
    {
 
1351
      write_error= 1;
 
1352
      sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
 
1353
    }
 
1354
 
 
1355
    if (my_close(log_file.file, MYF(MY_WME)) && ! write_error)
 
1356
    {
 
1357
      write_error= 1;
 
1358
      sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
 
1359
    }
 
1360
  }
 
1361
 
 
1362
  log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
 
1363
  safeFree(name);
 
1364
  return;
 
1365
}
 
1366
 
 
1367
/** This is called only once. */
 
1368
 
 
1369
void MYSQL_LOG::cleanup()
 
1370
{
 
1371
  if (inited)
 
1372
  {
 
1373
    inited= 0;
 
1374
    (void) pthread_mutex_destroy(&LOCK_log);
 
1375
    close(0);
 
1376
  }
 
1377
  return;
 
1378
}
 
1379
 
 
1380
 
 
1381
int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
 
1382
{
 
1383
  fn_format(new_name, log_name, mysql_data_home, "", 4);
 
1384
  if (log_type == LOG_BIN)
 
1385
  {
 
1386
    if (!fn_ext(log_name)[0])
 
1387
    {
 
1388
      if (find_uniq_filename(new_name))
 
1389
      {
 
1390
        sql_print_error(ER(ER_NO_UNIQUE_LOGFILE), log_name);
 
1391
        return 1;
 
1392
      }
 
1393
    }
 
1394
  }
 
1395
  return 0;
 
1396
}
 
1397
 
 
1398
 
 
1399
/*
 
1400
  Reopen the log file
 
1401
 
 
1402
  SYNOPSIS
 
1403
    reopen_file()
 
1404
 
 
1405
  DESCRIPTION
 
1406
    Reopen the log file. The method is used during FLUSH LOGS
 
1407
    and locks LOCK_log mutex
 
1408
*/
 
1409
 
 
1410
 
 
1411
void MYSQL_QUERY_LOG::reopen_file()
 
1412
{
 
1413
  char *save_name;
 
1414
 
 
1415
  if (!is_open())
 
1416
  {
 
1417
    return;
 
1418
  }
 
1419
 
 
1420
  pthread_mutex_lock(&LOCK_log);
 
1421
 
 
1422
  save_name= name;
 
1423
  name= 0;                              // Don't free name
 
1424
  close(LOG_CLOSE_TO_BE_OPENED);
 
1425
 
 
1426
  /*
 
1427
     Note that at this point, log_state != LOG_CLOSED (important for is_open()).
 
1428
  */
 
1429
 
 
1430
  open(save_name, log_type, 0, io_cache_type);
 
1431
  my_free(save_name, MYF(0));
 
1432
 
 
1433
  pthread_mutex_unlock(&LOCK_log);
 
1434
 
 
1435
  return;
 
1436
}
 
1437
 
 
1438
 
 
1439
/*
 
1440
  Write a command to traditional general log file
 
1441
 
 
1442
  SYNOPSIS
 
1443
    write()
 
1444
 
 
1445
    event_time        command start timestamp
 
1446
    user_host         the pointer to the string with user@host info
 
1447
    user_host_len     length of the user_host string. this is computed once
 
1448
                      and passed to all general log  event handlers
 
1449
    thread_id         Id of the thread, issued a query
 
1450
    command_type      the type of the command being logged
 
1451
    command_type_len  the length of the string above
 
1452
    sql_text          the very text of the query being executed
 
1453
    sql_text_len      the length of sql_text string
 
1454
 
 
1455
  DESCRIPTION
 
1456
 
 
1457
   Log given command to to normal (not rotable) log file
 
1458
 
 
1459
  RETURN
 
1460
    FASE - OK
 
1461
    TRUE - error occured
 
1462
*/
 
1463
 
 
1464
bool MYSQL_QUERY_LOG::write(time_t event_time,
 
1465
                            const char *user_host __attribute__((__unused__)),
 
1466
                            uint user_host_len __attribute__((__unused__)),
 
1467
                            int thread_id,
 
1468
                            const char *command_type, uint command_type_len,
 
1469
                            const char *sql_text, uint sql_text_len)
 
1470
{
 
1471
  char buff[32];
 
1472
  uint length= 0;
 
1473
  char local_time_buff[MAX_TIME_SIZE];
 
1474
  struct tm start;
 
1475
  uint time_buff_len= 0;
 
1476
 
 
1477
  (void) pthread_mutex_lock(&LOCK_log);
 
1478
 
 
1479
  /* Test if someone closed between the is_open test and lock */
 
1480
  if (is_open())
 
1481
  {
 
1482
    /* Note that my_b_write() assumes it knows the length for this */
 
1483
      if (event_time != last_time)
 
1484
      {
 
1485
        last_time= event_time;
 
1486
 
 
1487
        localtime_r(&event_time, &start);
 
1488
 
 
1489
        time_buff_len= snprintf(local_time_buff, MAX_TIME_SIZE,
 
1490
                                "%02d%02d%02d %2d:%02d:%02d",
 
1491
                                start.tm_year % 100, start.tm_mon + 1,
 
1492
                                start.tm_mday, start.tm_hour,
 
1493
                                start.tm_min, start.tm_sec);
 
1494
 
 
1495
        if (my_b_write(&log_file, (uchar*) local_time_buff, time_buff_len))
 
1496
          goto err;
 
1497
      }
 
1498
      else
 
1499
        if (my_b_write(&log_file, (uchar*) "\t\t" ,2) < 0)
 
1500
          goto err;
 
1501
 
 
1502
      /* command_type, thread_id */
 
1503
      length= snprintf(buff, 32, "%5ld ", (long) thread_id);
 
1504
 
 
1505
    if (my_b_write(&log_file, (uchar*) buff, length))
 
1506
      goto err;
 
1507
 
 
1508
    if (my_b_write(&log_file, (uchar*) command_type, command_type_len))
 
1509
      goto err;
 
1510
 
 
1511
    if (my_b_write(&log_file, (uchar*) "\t", 1))
 
1512
      goto err;
 
1513
 
 
1514
    /* sql_text */
 
1515
    if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len))
 
1516
      goto err;
 
1517
 
 
1518
    if (my_b_write(&log_file, (uchar*) "\n", 1) ||
 
1519
        flush_io_cache(&log_file))
 
1520
      goto err;
 
1521
  }
 
1522
 
 
1523
  (void) pthread_mutex_unlock(&LOCK_log);
 
1524
  return false;
 
1525
err:
 
1526
 
 
1527
  if (!write_error)
 
1528
  {
 
1529
    write_error= 1;
 
1530
    sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
 
1531
  }
 
1532
  (void) pthread_mutex_unlock(&LOCK_log);
 
1533
  return true;
 
1534
}
 
1535
 
 
1536
 
 
1537
/*
 
1538
  Log a query to the traditional slow log file
 
1539
 
 
1540
  SYNOPSIS
 
1541
    write()
 
1542
 
 
1543
    thd               THD of the query
 
1544
    current_time      current timestamp
 
1545
    query_start_arg   command start timestamp
 
1546
    user_host         the pointer to the string with user@host info
 
1547
    user_host_len     length of the user_host string. this is computed once
 
1548
                      and passed to all general log event handlers
 
1549
    query_utime       Amount of time the query took to execute (in microseconds)
 
1550
    lock_utime        Amount of time the query was locked (in microseconds)
 
1551
    is_command        The flag, which determines, whether the sql_text is a
 
1552
                      query or an administrator command.
 
1553
    sql_text          the very text of the query or administrator command
 
1554
                      processed
 
1555
    sql_text_len      the length of sql_text string
 
1556
 
 
1557
  DESCRIPTION
 
1558
 
 
1559
   Log a query to the slow log file.
 
1560
 
 
1561
  RETURN
 
1562
    FALSE - OK
 
1563
    TRUE - error occured
 
1564
*/
 
1565
 
 
1566
bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
 
1567
                            time_t query_start_arg __attribute__((__unused__)),
 
1568
                            const char *user_host,
 
1569
                            uint user_host_len, ulonglong query_utime,
 
1570
                            ulonglong lock_utime, bool is_command,
 
1571
                            const char *sql_text, uint sql_text_len)
 
1572
{
 
1573
  bool error= 0;
 
1574
 
 
1575
  (void) pthread_mutex_lock(&LOCK_log);
 
1576
 
 
1577
  if (!is_open())
 
1578
  {
 
1579
    (void) pthread_mutex_unlock(&LOCK_log);
 
1580
    return(0);
 
1581
  }
 
1582
 
 
1583
  if (is_open())
 
1584
  {                                             // Safety agains reopen
 
1585
    int tmp_errno= 0;
 
1586
    char buff[80], *end;
 
1587
    char query_time_buff[22+7], lock_time_buff[22+7];
 
1588
    uint buff_len;
 
1589
    end= buff;
 
1590
 
 
1591
    if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
 
1592
    {
 
1593
      if (current_time != last_time)
 
1594
      {
 
1595
        last_time= current_time;
 
1596
        struct tm start;
 
1597
        localtime_r(&current_time, &start);
 
1598
 
 
1599
        buff_len= snprintf(buff, sizeof buff,
 
1600
                           "# Time: %02d%02d%02d %2d:%02d:%02d\n",
 
1601
                           start.tm_year % 100, start.tm_mon + 1,
 
1602
                           start.tm_mday, start.tm_hour,
 
1603
                           start.tm_min, start.tm_sec);
 
1604
 
 
1605
        /* Note that my_b_write() assumes it knows the length for this */
 
1606
        if (my_b_write(&log_file, (uchar*) buff, buff_len))
 
1607
          tmp_errno= errno;
 
1608
      }
 
1609
      const uchar uh[]= "# User@Host: ";
 
1610
      if (my_b_write(&log_file, uh, sizeof(uh) - 1))
 
1611
        tmp_errno= errno;
 
1612
      if (my_b_write(&log_file, (uchar*) user_host, user_host_len))
 
1613
        tmp_errno= errno;
 
1614
      if (my_b_write(&log_file, (uchar*) "\n", 1))
 
1615
        tmp_errno= errno;
 
1616
    }
 
1617
    /* For slow query log */
 
1618
    sprintf(query_time_buff, "%.6f", ulonglong2double(query_utime)/1000000.0);
 
1619
    sprintf(lock_time_buff,  "%.6f", ulonglong2double(lock_utime)/1000000.0);
 
1620
    if (my_b_printf(&log_file,
 
1621
                    "# Query_time: %s  Lock_time: %s"
 
1622
                    " Rows_sent: %lu  Rows_examined: %lu\n",
 
1623
                    query_time_buff, lock_time_buff,
 
1624
                    (ulong) thd->sent_row_count,
 
1625
                    (ulong) thd->examined_row_count) == (uint) -1)
 
1626
      tmp_errno= errno;
 
1627
    if (thd->db && strcmp(thd->db, db))
 
1628
    {                                           // Database changed
 
1629
      if (my_b_printf(&log_file,"use %s;\n",thd->db) == (uint) -1)
 
1630
        tmp_errno= errno;
 
1631
      strmov(db,thd->db);
 
1632
    }
 
1633
    if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
 
1634
    {
 
1635
      end=strmov(end, ",last_insert_id=");
 
1636
      end=longlong10_to_str((longlong)
 
1637
                            thd->first_successful_insert_id_in_prev_stmt_for_binlog,
 
1638
                            end, -10);
 
1639
    }
 
1640
    // Save value if we do an insert.
 
1641
    if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0)
 
1642
    {
 
1643
      if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
 
1644
      {
 
1645
        end=strmov(end,",insert_id=");
 
1646
        end=longlong10_to_str((longlong)
 
1647
                              thd->auto_inc_intervals_in_cur_stmt_for_binlog.minimum(),
 
1648
                              end, -10);
 
1649
      }
 
1650
    }
 
1651
 
 
1652
    /*
 
1653
      This info used to show up randomly, depending on whether the query
 
1654
      checked the query start time or not. now we always write current
 
1655
      timestamp to the slow log
 
1656
    */
 
1657
    end= strmov(end, ",timestamp=");
 
1658
    end= int10_to_str((long) current_time, end, 10);
 
1659
 
 
1660
    if (end != buff)
 
1661
    {
 
1662
      *end++=';';
 
1663
      *end='\n';
 
1664
      if (my_b_write(&log_file, (uchar*) "SET ", 4) ||
 
1665
          my_b_write(&log_file, (uchar*) buff + 1, (uint) (end-buff)))
 
1666
        tmp_errno= errno;
 
1667
    }
 
1668
    if (is_command)
 
1669
    {
 
1670
      end= strxmov(buff, "# administrator command: ", NullS);
 
1671
      buff_len= (ulong) (end - buff);
 
1672
      my_b_write(&log_file, (uchar*) buff, buff_len);
 
1673
    }
 
1674
    if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len) ||
 
1675
        my_b_write(&log_file, (uchar*) ";\n",2) ||
 
1676
        flush_io_cache(&log_file))
 
1677
      tmp_errno= errno;
 
1678
    if (tmp_errno)
 
1679
    {
 
1680
      error= 1;
 
1681
      if (! write_error)
 
1682
      {
 
1683
        write_error= 1;
 
1684
        sql_print_error(ER(ER_ERROR_ON_WRITE), name, error);
 
1685
      }
 
1686
    }
 
1687
  }
 
1688
  (void) pthread_mutex_unlock(&LOCK_log);
 
1689
  return(error);
 
1690
}
 
1691
 
 
1692
 
 
1693
/**
 
1694
  @todo
 
1695
  The following should be using fn_format();  We just need to
 
1696
  first change fn_format() to cut the file name if it's too long.
 
1697
*/
 
1698
const char *MYSQL_LOG::generate_name(const char *log_name,
 
1699
                                      const char *suffix,
 
1700
                                      bool strip_ext, char *buff)
 
1701
{
 
1702
  if (!log_name || !log_name[0])
 
1703
  {
 
1704
    strmake(buff, pidfile_name, FN_REFLEN - strlen(suffix) - 1);
 
1705
    return (const char *)
 
1706
      fn_format(buff, buff, "", suffix, MYF(MY_REPLACE_EXT|MY_REPLACE_DIR));
 
1707
  }
 
1708
  // get rid of extension if the log is binary to avoid problems
 
1709
  if (strip_ext)
 
1710
  {
 
1711
    char *p= fn_ext(log_name);
 
1712
    uint length= (uint) (p - log_name);
 
1713
    strmake(buff, log_name, min(length, FN_REFLEN));
 
1714
    return (const char*)buff;
 
1715
  }
 
1716
  return log_name;
 
1717
}
 
1718
 
 
1719
 
 
1720
 
 
1721
MYSQL_BIN_LOG::MYSQL_BIN_LOG()
 
1722
  :bytes_written(0), prepared_xids(0), file_id(1), open_count(1),
 
1723
   need_start_event(true), m_table_map_version(0),
 
1724
   description_event_for_exec(0), description_event_for_queue(0)
 
1725
{
 
1726
  /*
 
1727
    We don't want to initialize locks here as such initialization depends on
 
1728
    safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
 
1729
    called only in main(). Doing initialization here would make it happen
 
1730
    before main().
 
1731
  */
 
1732
  index_file_name[0] = 0;
 
1733
  bzero((char*) &index_file, sizeof(index_file));
 
1734
}
 
1735
 
 
1736
/* this is called only once */
 
1737
 
 
1738
void MYSQL_BIN_LOG::cleanup()
 
1739
{
 
1740
  if (inited)
 
1741
  {
 
1742
    inited= 0;
 
1743
    close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT);
 
1744
    delete description_event_for_queue;
 
1745
    delete description_event_for_exec;
 
1746
    (void) pthread_mutex_destroy(&LOCK_log);
 
1747
    (void) pthread_mutex_destroy(&LOCK_index);
 
1748
    (void) pthread_cond_destroy(&update_cond);
 
1749
  }
 
1750
  return;
 
1751
}
 
1752
 
 
1753
 
 
1754
/* Init binlog-specific vars */
 
1755
void MYSQL_BIN_LOG::init(bool no_auto_events_arg, ulong max_size_arg)
 
1756
{
 
1757
  no_auto_events= no_auto_events_arg;
 
1758
  max_size= max_size_arg;
 
1759
  return;
 
1760
}
 
1761
 
 
1762
 
 
1763
void MYSQL_BIN_LOG::init_pthread_objects()
 
1764
{
 
1765
  assert(inited == 0);
 
1766
  inited= 1;
 
1767
  (void) pthread_mutex_init(&LOCK_log, MY_MUTEX_INIT_SLOW);
 
1768
  (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
 
1769
  (void) pthread_cond_init(&update_cond, 0);
 
1770
}
 
1771
 
 
1772
 
 
1773
bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
 
1774
                                const char *log_name)
 
1775
{
 
1776
  File index_file_nr= -1;
 
1777
  assert(!my_b_inited(&index_file));
 
1778
 
 
1779
  /*
 
1780
    First open of this class instance
 
1781
    Create an index file that will hold all file names uses for logging.
 
1782
    Add new entries to the end of it.
 
1783
  */
 
1784
  myf opt= MY_UNPACK_FILENAME;
 
1785
  if (!index_file_name_arg)
 
1786
  {
 
1787
    index_file_name_arg= log_name;    // Use same basename for index file
 
1788
    opt= MY_UNPACK_FILENAME | MY_REPLACE_EXT;
 
1789
  }
 
1790
  fn_format(index_file_name, index_file_name_arg, mysql_data_home,
 
1791
            ".index", opt);
 
1792
  if ((index_file_nr= my_open(index_file_name,
 
1793
                              O_RDWR | O_CREAT | O_BINARY ,
 
1794
                              MYF(MY_WME))) < 0 ||
 
1795
       my_sync(index_file_nr, MYF(MY_WME)) ||
 
1796
       init_io_cache(&index_file, index_file_nr,
 
1797
                     IO_SIZE, WRITE_CACHE,
 
1798
                     my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)),
 
1799
                        0, MYF(MY_WME | MY_WAIT_IF_FULL)))
 
1800
  {
 
1801
    /*
 
1802
      TODO: all operations creating/deleting the index file or a log, should
 
1803
      call my_sync_dir() or my_sync_dir_by_file() to be durable.
 
1804
      TODO: file creation should be done with my_create() not my_open().
 
1805
    */
 
1806
    if (index_file_nr >= 0)
 
1807
      my_close(index_file_nr,MYF(0));
 
1808
    return true;
 
1809
  }
 
1810
  return false;
 
1811
}
 
1812
 
 
1813
 
 
1814
/**
 
1815
  Open a (new) binlog file.
 
1816
 
 
1817
  - Open the log file and the index file. Register the new
 
1818
  file name in it
 
1819
  - When calling this when the file is in use, you must have a locks
 
1820
  on LOCK_log and LOCK_index.
 
1821
 
 
1822
  @retval
 
1823
    0   ok
 
1824
  @retval
 
1825
    1   error
 
1826
*/
 
1827
 
 
1828
bool MYSQL_BIN_LOG::open(const char *log_name,
 
1829
                         enum_log_type log_type_arg,
 
1830
                         const char *new_name,
 
1831
                         enum cache_type io_cache_type_arg,
 
1832
                         bool no_auto_events_arg,
 
1833
                         ulong max_size_arg,
 
1834
                         bool null_created_arg)
 
1835
{
 
1836
  File file= -1;
 
1837
 
 
1838
  write_error=0;
 
1839
 
 
1840
  /* open the main log file */
 
1841
  if (MYSQL_LOG::open(log_name, log_type_arg, new_name, io_cache_type_arg))
 
1842
    return(1);                            /* all warnings issued */
 
1843
 
 
1844
  init(no_auto_events_arg, max_size_arg);
 
1845
 
 
1846
  open_count++;
 
1847
 
 
1848
  assert(log_type == LOG_BIN);
 
1849
 
 
1850
  {
 
1851
    bool write_file_name_to_index_file=0;
 
1852
 
 
1853
    if (!my_b_filelength(&log_file))
 
1854
    {
 
1855
      /*
 
1856
        The binary log file was empty (probably newly created)
 
1857
        This is the normal case and happens when the user doesn't specify
 
1858
        an extension for the binary log files.
 
1859
        In this case we write a standard header to it.
 
1860
      */
 
1861
      if (my_b_safe_write(&log_file, (uchar*) BINLOG_MAGIC,
 
1862
                          BIN_LOG_HEADER_SIZE))
 
1863
        goto err;
 
1864
      bytes_written+= BIN_LOG_HEADER_SIZE;
 
1865
      write_file_name_to_index_file= 1;
 
1866
    }
 
1867
 
 
1868
    assert(my_b_inited(&index_file) != 0);
 
1869
    reinit_io_cache(&index_file, WRITE_CACHE,
 
1870
                    my_b_filelength(&index_file), 0, 0);
 
1871
    if (need_start_event && !no_auto_events)
 
1872
    {
 
1873
      /*
 
1874
        In 4.x we set need_start_event=0 here, but in 5.0 we want a Start event
 
1875
        even if this is not the very first binlog.
 
1876
      */
 
1877
      Format_description_log_event s(BINLOG_VERSION);
 
1878
      /*
 
1879
        don't set LOG_EVENT_BINLOG_IN_USE_F for SEQ_READ_APPEND io_cache
 
1880
        as we won't be able to reset it later
 
1881
      */
 
1882
      if (io_cache_type == WRITE_CACHE)
 
1883
        s.flags|= LOG_EVENT_BINLOG_IN_USE_F;
 
1884
      if (!s.is_valid())
 
1885
        goto err;
 
1886
      s.dont_set_created= null_created_arg;
 
1887
      if (s.write(&log_file))
 
1888
        goto err;
 
1889
      bytes_written+= s.data_written;
 
1890
    }
 
1891
    if (description_event_for_queue &&
 
1892
        description_event_for_queue->binlog_version>=4)
 
1893
    {
 
1894
      /*
 
1895
        This is a relay log written to by the I/O slave thread.
 
1896
        Write the event so that others can later know the format of this relay
 
1897
        log.
 
1898
        Note that this event is very close to the original event from the
 
1899
        master (it has binlog version of the master, event types of the
 
1900
        master), so this is suitable to parse the next relay log's event. It
 
1901
        has been produced by
 
1902
        Format_description_log_event::Format_description_log_event(char* buf,).
 
1903
        Why don't we want to write the description_event_for_queue if this
 
1904
        event is for format<4 (3.23 or 4.x): this is because in that case, the
 
1905
        description_event_for_queue describes the data received from the
 
1906
        master, but not the data written to the relay log (*conversion*),
 
1907
        which is in format 4 (slave's).
 
1908
      */
 
1909
      /*
 
1910
        Set 'created' to 0, so that in next relay logs this event does not
 
1911
        trigger cleaning actions on the slave in
 
1912
        Format_description_log_event::apply_event_impl().
 
1913
      */
 
1914
      description_event_for_queue->created= 0;
 
1915
      /* Don't set log_pos in event header */
 
1916
      description_event_for_queue->artificial_event=1;
 
1917
 
 
1918
      if (description_event_for_queue->write(&log_file))
 
1919
        goto err;
 
1920
      bytes_written+= description_event_for_queue->data_written;
 
1921
    }
 
1922
    if (flush_io_cache(&log_file) ||
 
1923
        my_sync(log_file.file, MYF(MY_WME)))
 
1924
      goto err;
 
1925
 
 
1926
    if (write_file_name_to_index_file)
 
1927
    {
 
1928
      /*
 
1929
        As this is a new log file, we write the file name to the index
 
1930
        file. As every time we write to the index file, we sync it.
 
1931
      */
 
1932
      if (my_b_write(&index_file, (uchar*) log_file_name,
 
1933
                     strlen(log_file_name)) ||
 
1934
          my_b_write(&index_file, (uchar*) "\n", 1) ||
 
1935
          flush_io_cache(&index_file) ||
 
1936
          my_sync(index_file.file, MYF(MY_WME)))
 
1937
        goto err;
 
1938
    }
 
1939
  }
 
1940
  log_state= LOG_OPENED;
 
1941
 
 
1942
  return(0);
 
1943
 
 
1944
err:
 
1945
  sql_print_error("Could not use %s for logging (error %d). \
 
1946
Turning logging off for the whole duration of the MySQL server process. \
 
1947
To turn it on again: fix the cause, \
 
1948
shutdown the MySQL server and restart it.", name, errno);
 
1949
  if (file >= 0)
 
1950
    my_close(file,MYF(0));
 
1951
  end_io_cache(&log_file);
 
1952
  end_io_cache(&index_file);
 
1953
  safeFree(name);
 
1954
  log_state= LOG_CLOSED;
 
1955
  return(1);
 
1956
}
 
1957
 
 
1958
 
 
1959
int MYSQL_BIN_LOG::get_current_log(LOG_INFO* linfo)
 
1960
{
 
1961
  pthread_mutex_lock(&LOCK_log);
 
1962
  int ret = raw_get_current_log(linfo);
 
1963
  pthread_mutex_unlock(&LOCK_log);
 
1964
  return ret;
 
1965
}
 
1966
 
 
1967
int MYSQL_BIN_LOG::raw_get_current_log(LOG_INFO* linfo)
 
1968
{
 
1969
  strmake(linfo->log_file_name, log_file_name, sizeof(linfo->log_file_name)-1);
 
1970
  linfo->pos = my_b_tell(&log_file);
 
1971
  return 0;
 
1972
}
 
1973
 
 
1974
/**
 
1975
  Move all data up in a file in an filename index file.
 
1976
 
 
1977
    We do the copy outside of the IO_CACHE as the cache buffers would just
 
1978
    make things slower and more complicated.
 
1979
    In most cases the copy loop should only do one read.
 
1980
 
 
1981
  @param index_file                     File to move
 
1982
  @param offset                 Move everything from here to beginning
 
1983
 
 
1984
  @note
 
1985
    File will be truncated to be 'offset' shorter or filled up with newlines
 
1986
 
 
1987
  @retval
 
1988
    0   ok
 
1989
*/
 
1990
 
 
1991
#ifdef HAVE_REPLICATION
 
1992
 
 
1993
static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset)
 
1994
{
 
1995
  int bytes_read;
 
1996
  my_off_t init_offset= offset;
 
1997
  File file= index_file->file;
 
1998
  uchar io_buf[IO_SIZE*2];
 
1999
 
 
2000
  for (;; offset+= bytes_read)
 
2001
  {
 
2002
    (void) my_seek(file, offset, MY_SEEK_SET, MYF(0));
 
2003
    if ((bytes_read= (int) my_read(file, io_buf, sizeof(io_buf), MYF(MY_WME)))
 
2004
        < 0)
 
2005
      goto err;
 
2006
    if (!bytes_read)
 
2007
      break;                                    // end of file
 
2008
    (void) my_seek(file, offset-init_offset, MY_SEEK_SET, MYF(0));
 
2009
    if (my_write(file, io_buf, bytes_read, MYF(MY_WME | MY_NABP)))
 
2010
      goto err;
 
2011
  }
 
2012
  /* The following will either truncate the file or fill the end with \n' */
 
2013
  if (ftruncate(file, offset - init_offset) || my_sync(file, MYF(MY_WME)))
 
2014
    goto err;
 
2015
 
 
2016
  /* Reset data in old index cache */
 
2017
  reinit_io_cache(index_file, READ_CACHE, (my_off_t) 0, 0, 1);
 
2018
  return(0);
 
2019
 
 
2020
err:
 
2021
  return(1);
 
2022
}
 
2023
 
 
2024
#endif /* HAVE_REPLICATION */
 
2025
 
 
2026
/**
 
2027
  Find the position in the log-index-file for the given log name.
 
2028
 
 
2029
  @param linfo          Store here the found log file name and position to
 
2030
                       the NEXT log file name in the index file.
 
2031
  @param log_name       Filename to find in the index file.
 
2032
                       Is a null pointer if we want to read the first entry
 
2033
  @param need_lock      Set this to 1 if the parent doesn't already have a
 
2034
                       lock on LOCK_index
 
2035
 
 
2036
  @note
 
2037
    On systems without the truncate function the file will end with one or
 
2038
    more empty lines.  These will be ignored when reading the file.
 
2039
 
 
2040
  @retval
 
2041
    0                   ok
 
2042
  @retval
 
2043
    LOG_INFO_EOF                End of log-index-file found
 
2044
  @retval
 
2045
    LOG_INFO_IO         Got IO error while reading file
 
2046
*/
 
2047
 
 
2048
int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name,
 
2049
                            bool need_lock)
 
2050
{
 
2051
  int error= 0;
 
2052
  char *fname= linfo->log_file_name;
 
2053
  uint log_name_len= log_name ? (uint) strlen(log_name) : 0;
 
2054
 
 
2055
  /*
 
2056
    Mutex needed because we need to make sure the file pointer does not
 
2057
    move from under our feet
 
2058
  */
 
2059
  if (need_lock)
 
2060
    pthread_mutex_lock(&LOCK_index);
 
2061
  safe_mutex_assert_owner(&LOCK_index);
 
2062
 
 
2063
  /* As the file is flushed, we can't get an error here */
 
2064
  (void) reinit_io_cache(&index_file, READ_CACHE, (my_off_t) 0, 0, 0);
 
2065
 
 
2066
  for (;;)
 
2067
  {
 
2068
    uint length;
 
2069
    my_off_t offset= my_b_tell(&index_file);
 
2070
    /* If we get 0 or 1 characters, this is the end of the file */
 
2071
 
 
2072
    if ((length= my_b_gets(&index_file, fname, FN_REFLEN)) <= 1)
 
2073
    {
 
2074
      /* Did not find the given entry; Return not found or error */
 
2075
      error= !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
 
2076
      break;
 
2077
    }
 
2078
 
 
2079
    // if the log entry matches, null string matching anything
 
2080
    if (!log_name ||
 
2081
        (log_name_len == length-1 && fname[log_name_len] == '\n' &&
 
2082
         !memcmp(fname, log_name, log_name_len)))
 
2083
    {
 
2084
      fname[length-1]=0;                        // remove last \n
 
2085
      linfo->index_file_start_offset= offset;
 
2086
      linfo->index_file_offset = my_b_tell(&index_file);
 
2087
      break;
 
2088
    }
 
2089
  }
 
2090
 
 
2091
  if (need_lock)
 
2092
    pthread_mutex_unlock(&LOCK_index);
 
2093
  return(error);
 
2094
}
 
2095
 
 
2096
 
 
2097
/**
 
2098
  Find the position in the log-index-file for the given log name.
 
2099
 
 
2100
  @param
 
2101
    linfo               Store here the next log file name and position to
 
2102
                        the file name after that.
 
2103
  @param
 
2104
    need_lock           Set this to 1 if the parent doesn't already have a
 
2105
                        lock on LOCK_index
 
2106
 
 
2107
  @note
 
2108
    - Before calling this function, one has to call find_log_pos()
 
2109
    to set up 'linfo'
 
2110
    - Mutex needed because we need to make sure the file pointer does not move
 
2111
    from under our feet
 
2112
 
 
2113
  @retval
 
2114
    0                   ok
 
2115
  @retval
 
2116
    LOG_INFO_EOF                End of log-index-file found
 
2117
  @retval
 
2118
    LOG_INFO_IO         Got IO error while reading file
 
2119
*/
 
2120
 
 
2121
int MYSQL_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock)
 
2122
{
 
2123
  int error= 0;
 
2124
  uint length;
 
2125
  char *fname= linfo->log_file_name;
 
2126
 
 
2127
  if (need_lock)
 
2128
    pthread_mutex_lock(&LOCK_index);
 
2129
  safe_mutex_assert_owner(&LOCK_index);
 
2130
 
 
2131
  /* As the file is flushed, we can't get an error here */
 
2132
  (void) reinit_io_cache(&index_file, READ_CACHE, linfo->index_file_offset, 0,
 
2133
                         0);
 
2134
 
 
2135
  linfo->index_file_start_offset= linfo->index_file_offset;
 
2136
  if ((length=my_b_gets(&index_file, fname, FN_REFLEN)) <= 1)
 
2137
  {
 
2138
    error = !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
 
2139
    goto err;
 
2140
  }
 
2141
  fname[length-1]=0;                            // kill \n
 
2142
  linfo->index_file_offset = my_b_tell(&index_file);
 
2143
 
 
2144
err:
 
2145
  if (need_lock)
 
2146
    pthread_mutex_unlock(&LOCK_index);
 
2147
  return error;
 
2148
}
 
2149
 
 
2150
 
 
2151
/**
 
2152
  Delete all logs refered to in the index file.
 
2153
  Start writing to a new log file.
 
2154
 
 
2155
  The new index file will only contain this file.
 
2156
 
 
2157
  @param thd            Thread
 
2158
 
 
2159
  @note
 
2160
    If not called from slave thread, write start event to new log
 
2161
 
 
2162
  @retval
 
2163
    0   ok
 
2164
  @retval
 
2165
    1   error
 
2166
*/
 
2167
 
 
2168
bool MYSQL_BIN_LOG::reset_logs(THD* thd)
 
2169
{
 
2170
  LOG_INFO linfo;
 
2171
  bool error=0;
 
2172
  const char* save_name;
 
2173
 
 
2174
  ha_reset_logs(thd);
 
2175
  /*
 
2176
    We need to get both locks to be sure that no one is trying to
 
2177
    write to the index log file.
 
2178
  */
 
2179
  pthread_mutex_lock(&LOCK_log);
 
2180
  pthread_mutex_lock(&LOCK_index);
 
2181
 
 
2182
  /*
 
2183
    The following mutex is needed to ensure that no threads call
 
2184
    'delete thd' as we would then risk missing a 'rollback' from this
 
2185
    thread. If the transaction involved MyISAM tables, it should go
 
2186
    into binlog even on rollback.
 
2187
  */
 
2188
  VOID(pthread_mutex_lock(&LOCK_thread_count));
 
2189
 
 
2190
  /* Save variables so that we can reopen the log */
 
2191
  save_name=name;
 
2192
  name=0;                                       // Protect against free
 
2193
  close(LOG_CLOSE_TO_BE_OPENED);
 
2194
 
 
2195
  /* First delete all old log files */
 
2196
 
 
2197
  if (find_log_pos(&linfo, NullS, 0))
 
2198
  {
 
2199
    error=1;
 
2200
    goto err;
 
2201
  }
 
2202
 
 
2203
  for (;;)
 
2204
  {
 
2205
    if ((error= my_delete_allow_opened(linfo.log_file_name, MYF(0))) != 0)
 
2206
    {
 
2207
      if (my_errno == ENOENT) 
 
2208
      {
 
2209
        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
 
2210
                            ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
 
2211
                            linfo.log_file_name);
 
2212
        sql_print_information("Failed to delete file '%s'",
 
2213
                              linfo.log_file_name);
 
2214
        my_errno= 0;
 
2215
        error= 0;
 
2216
      }
 
2217
      else
 
2218
      {
 
2219
        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
 
2220
                            ER_BINLOG_PURGE_FATAL_ERR,
 
2221
                            "a problem with deleting %s; "
 
2222
                            "consider examining correspondence "
 
2223
                            "of your binlog index file "
 
2224
                            "to the actual binlog files",
 
2225
                            linfo.log_file_name);
 
2226
        error= 1;
 
2227
        goto err;
 
2228
      }
 
2229
    }
 
2230
    if (find_next_log(&linfo, 0))
 
2231
      break;
 
2232
  }
 
2233
 
 
2234
  /* Start logging with a new file */
 
2235
  close(LOG_CLOSE_INDEX);
 
2236
  if ((error= my_delete_allow_opened(index_file_name, MYF(0)))) // Reset (open will update)
 
2237
  {
 
2238
    if (my_errno == ENOENT) 
 
2239
    {
 
2240
      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
 
2241
                          ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
 
2242
                          index_file_name);
 
2243
      sql_print_information("Failed to delete file '%s'",
 
2244
                            index_file_name);
 
2245
      my_errno= 0;
 
2246
      error= 0;
 
2247
    }
 
2248
    else
 
2249
    {
 
2250
      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
 
2251
                          ER_BINLOG_PURGE_FATAL_ERR,
 
2252
                          "a problem with deleting %s; "
 
2253
                          "consider examining correspondence "
 
2254
                          "of your binlog index file "
 
2255
                          "to the actual binlog files",
 
2256
                          index_file_name);
 
2257
      error= 1;
 
2258
      goto err;
 
2259
    }
 
2260
  }
 
2261
  if (!thd->slave_thread)
 
2262
    need_start_event=1;
 
2263
  if (!open_index_file(index_file_name, 0))
 
2264
    open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0);
 
2265
  my_free((uchar*) save_name, MYF(0));
 
2266
 
 
2267
err:
 
2268
  VOID(pthread_mutex_unlock(&LOCK_thread_count));
 
2269
  pthread_mutex_unlock(&LOCK_index);
 
2270
  pthread_mutex_unlock(&LOCK_log);
 
2271
  return(error);
 
2272
}
 
2273
 
 
2274
 
 
2275
/**
 
2276
  Delete relay log files prior to rli->group_relay_log_name
 
2277
  (i.e. all logs which are not involved in a non-finished group
 
2278
  (transaction)), remove them from the index file and start on next
 
2279
  relay log.
 
2280
 
 
2281
  IMPLEMENTATION
 
2282
  - Protects index file with LOCK_index
 
2283
  - Delete relevant relay log files
 
2284
  - Copy all file names after these ones to the front of the index file
 
2285
  - If the OS has truncate, truncate the file, else fill it with \n'
 
2286
  - Read the next file name from the index file and store in rli->linfo
 
2287
 
 
2288
  @param rli           Relay log information
 
2289
  @param included     If false, all relay logs that are strictly before
 
2290
                      rli->group_relay_log_name are deleted ; if true, the
 
2291
                      latter is deleted too (i.e. all relay logs
 
2292
                      read by the SQL slave thread are deleted).
 
2293
 
 
2294
  @note
 
2295
    - This is only called from the slave-execute thread when it has read
 
2296
    all commands from a relay log and want to switch to a new relay log.
 
2297
    - When this happens, we can be in an active transaction as
 
2298
    a transaction can span over two relay logs
 
2299
    (although it is always written as a single block to the master's binary
 
2300
    log, hence cannot span over two master's binary logs).
 
2301
 
 
2302
  @retval
 
2303
    0                   ok
 
2304
  @retval
 
2305
    LOG_INFO_EOF                End of log-index-file found
 
2306
  @retval
 
2307
    LOG_INFO_SEEK       Could not allocate IO cache
 
2308
  @retval
 
2309
    LOG_INFO_IO         Got IO error while reading file
 
2310
*/
 
2311
 
 
2312
#ifdef HAVE_REPLICATION
 
2313
 
 
2314
int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
 
2315
{
 
2316
  int error;
 
2317
 
 
2318
  assert(is_open());
 
2319
  assert(rli->slave_running == 1);
 
2320
  assert(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name));
 
2321
 
 
2322
  pthread_mutex_lock(&LOCK_index);
 
2323
  pthread_mutex_lock(&rli->log_space_lock);
 
2324
  rli->relay_log.purge_logs(rli->group_relay_log_name, included,
 
2325
                            0, 0, &rli->log_space_total);
 
2326
  // Tell the I/O thread to take the relay_log_space_limit into account
 
2327
  rli->ignore_log_space_limit= 0;
 
2328
  pthread_mutex_unlock(&rli->log_space_lock);
 
2329
 
 
2330
  /*
 
2331
    Ok to broadcast after the critical region as there is no risk of
 
2332
    the mutex being destroyed by this thread later - this helps save
 
2333
    context switches
 
2334
  */
 
2335
  pthread_cond_broadcast(&rli->log_space_cond);
 
2336
  
 
2337
  /*
 
2338
    Read the next log file name from the index file and pass it back to
 
2339
    the caller
 
2340
    If included is true, we want the first relay log;
 
2341
    otherwise we want the one after event_relay_log_name.
 
2342
  */
 
2343
  if ((included && (error=find_log_pos(&rli->linfo, NullS, 0))) ||
 
2344
      (!included &&
 
2345
       ((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)) ||
 
2346
        (error=find_next_log(&rli->linfo, 0)))))
 
2347
  {
 
2348
    char buff[22];
 
2349
    sql_print_error("next log error: %d  offset: %s  log: %s included: %d",
 
2350
                    error,
 
2351
                    llstr(rli->linfo.index_file_offset,buff),
 
2352
                    rli->group_relay_log_name,
 
2353
                    included);
 
2354
    goto err;
 
2355
  }
 
2356
 
 
2357
  /*
 
2358
    Reset rli's coordinates to the current log.
 
2359
  */
 
2360
  rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
 
2361
  strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
 
2362
          sizeof(rli->event_relay_log_name)-1);
 
2363
 
 
2364
  /*
 
2365
    If we removed the rli->group_relay_log_name file,
 
2366
    we must update the rli->group* coordinates, otherwise do not touch it as the
 
2367
    group's execution is not finished (e.g. COMMIT not executed)
 
2368
  */
 
2369
  if (included)
 
2370
  {
 
2371
    rli->group_relay_log_pos = BIN_LOG_HEADER_SIZE;
 
2372
    strmake(rli->group_relay_log_name,rli->linfo.log_file_name,
 
2373
            sizeof(rli->group_relay_log_name)-1);
 
2374
    rli->notify_group_relay_log_name_update();
 
2375
  }
 
2376
 
 
2377
  /* Store where we are in the new file for the execution thread */
 
2378
  flush_relay_log_info(rli);
 
2379
 
 
2380
err:
 
2381
  pthread_mutex_unlock(&LOCK_index);
 
2382
  return(error);
 
2383
}
 
2384
 
 
2385
/**
 
2386
  Update log index_file.
 
2387
*/
 
2388
 
 
2389
int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads)
 
2390
{
 
2391
  if (copy_up_file_and_fill(&index_file, log_info->index_file_start_offset))
 
2392
    return LOG_INFO_IO;
 
2393
 
 
2394
  // now update offsets in index file for running threads
 
2395
  if (need_update_threads)
 
2396
    adjust_linfo_offsets(log_info->index_file_start_offset);
 
2397
  return 0;
 
2398
}
 
2399
 
 
2400
/**
 
2401
  Remove all logs before the given log from disk and from the index file.
 
2402
 
 
2403
  @param to_log       Delete all log file name before this file.
 
2404
  @param included            If true, to_log is deleted too.
 
2405
  @param need_mutex
 
2406
  @param need_update_threads If we want to update the log coordinates of
 
2407
                             all threads. False for relay logs, true otherwise.
 
2408
  @param freed_log_space     If not null, decrement this variable of
 
2409
                             the amount of log space freed
 
2410
 
 
2411
  @note
 
2412
    If any of the logs before the deleted one is in use,
 
2413
    only purge logs up to this one.
 
2414
 
 
2415
  @retval
 
2416
    0                   ok
 
2417
  @retval
 
2418
    LOG_INFO_EOF                to_log not found
 
2419
    LOG_INFO_EMFILE             too many files opened
 
2420
    LOG_INFO_FATAL              if any other than ENOENT error from
 
2421
                                stat() or my_delete()
 
2422
*/
 
2423
 
 
2424
int MYSQL_BIN_LOG::purge_logs(const char *to_log, 
 
2425
                          bool included,
 
2426
                          bool need_mutex, 
 
2427
                          bool need_update_threads, 
 
2428
                          ulonglong *decrease_log_space)
 
2429
{
 
2430
  int error;
 
2431
  int ret = 0;
 
2432
  bool exit_loop= 0;
 
2433
  LOG_INFO log_info;
 
2434
 
 
2435
  if (need_mutex)
 
2436
    pthread_mutex_lock(&LOCK_index);
 
2437
  if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/)))
 
2438
    goto err;
 
2439
 
 
2440
  /*
 
2441
    File name exists in index file; delete until we find this file
 
2442
    or a file that is used.
 
2443
  */
 
2444
  if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
 
2445
    goto err;
 
2446
  while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
 
2447
         !log_in_use(log_info.log_file_name))
 
2448
  {
 
2449
    struct stat s;
 
2450
    if (stat(log_info.log_file_name, &s))
 
2451
    {
 
2452
      if (errno == ENOENT) 
 
2453
      {
 
2454
        /*
 
2455
          It's not fatal if we can't stat a log file that does not exist;
 
2456
          If we could not stat, we won't delete.
 
2457
        */     
 
2458
        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
 
2459
                            ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
 
2460
                            log_info.log_file_name);
 
2461
        sql_print_information("Failed to execute stat on file '%s'",
 
2462
                              log_info.log_file_name);
 
2463
        my_errno= 0;
 
2464
      }
 
2465
      else
 
2466
      {
 
2467
        /*
 
2468
          Other than ENOENT are fatal
 
2469
        */
 
2470
        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
 
2471
                            ER_BINLOG_PURGE_FATAL_ERR,
 
2472
                            "a problem with getting info on being purged %s; "
 
2473
                            "consider examining correspondence "
 
2474
                            "of your binlog index file "
 
2475
                            "to the actual binlog files",
 
2476
                            log_info.log_file_name);
 
2477
        error= LOG_INFO_FATAL;
 
2478
        goto err;
 
2479
      }
 
2480
    }
 
2481
    else
 
2482
    {
 
2483
      if (!my_delete(log_info.log_file_name, MYF(0)))
 
2484
      {
 
2485
        if (decrease_log_space)
 
2486
          *decrease_log_space-= s.st_size;
 
2487
      }
 
2488
      else
 
2489
      {
 
2490
        if (my_errno == ENOENT) 
 
2491
        {
 
2492
          push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
 
2493
                              ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
 
2494
                              log_info.log_file_name);
 
2495
          sql_print_information("Failed to delete file '%s'",
 
2496
                                log_info.log_file_name);
 
2497
          my_errno= 0;
 
2498
        }
 
2499
        else
 
2500
        {
 
2501
          push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
 
2502
                              ER_BINLOG_PURGE_FATAL_ERR,
 
2503
                              "a problem with deleting %s; "
 
2504
                              "consider examining correspondence "
 
2505
                              "of your binlog index file "
 
2506
                              "to the actual binlog files",
 
2507
                              log_info.log_file_name);
 
2508
          if (my_errno == EMFILE)
 
2509
          {
 
2510
            error= LOG_INFO_EMFILE;
 
2511
          }
 
2512
          error= LOG_INFO_FATAL;
 
2513
          goto err;
 
2514
        }
 
2515
      }
 
2516
    }
 
2517
 
 
2518
    ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
 
2519
 
 
2520
    if (find_next_log(&log_info, 0) || exit_loop)
 
2521
      break;
 
2522
  }
 
2523
  
 
2524
  /*
 
2525
    If we get killed -9 here, the sysadmin would have to edit
 
2526
    the log index file after restart - otherwise, this should be safe
 
2527
  */
 
2528
  error= update_log_index(&log_info, need_update_threads);
 
2529
  if (error == 0) {
 
2530
    error = ret;
 
2531
  }
 
2532
 
 
2533
err:
 
2534
  if (need_mutex)
 
2535
    pthread_mutex_unlock(&LOCK_index);
 
2536
  return(error);
 
2537
}
 
2538
 
 
2539
/**
 
2540
  Remove all logs before the given file date from disk and from the
 
2541
  index file.
 
2542
 
 
2543
  @param thd            Thread pointer
 
2544
  @param before_date    Delete all log files before given date.
 
2545
 
 
2546
  @note
 
2547
    If any of the logs before the deleted one is in use,
 
2548
    only purge logs up to this one.
 
2549
 
 
2550
  @retval
 
2551
    0                           ok
 
2552
  @retval
 
2553
    LOG_INFO_PURGE_NO_ROTATE    Binary file that can't be rotated
 
2554
    LOG_INFO_FATAL              if any other than ENOENT error from
 
2555
                                stat() or my_delete()
 
2556
*/
 
2557
 
 
2558
int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
 
2559
{
 
2560
  int error;
 
2561
  LOG_INFO log_info;
 
2562
  struct stat stat_area;
 
2563
 
 
2564
  pthread_mutex_lock(&LOCK_index);
 
2565
 
 
2566
  /*
 
2567
    Delete until we find curren file
 
2568
    or a file that is used or a file
 
2569
    that is older than purge_time.
 
2570
  */
 
2571
  if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
 
2572
    goto err;
 
2573
 
 
2574
  while (strcmp(log_file_name, log_info.log_file_name) &&
 
2575
         !log_in_use(log_info.log_file_name))
 
2576
  {
 
2577
    if (stat(log_info.log_file_name, &stat_area))
 
2578
    {
 
2579
      if (errno == ENOENT) 
 
2580
      {
 
2581
        /*
 
2582
          It's not fatal if we can't stat a log file that does not exist.
 
2583
        */     
 
2584
        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
 
2585
                            ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
 
2586
                            log_info.log_file_name);
 
2587
        sql_print_information("Failed to execute stat on file '%s'",
 
2588
                              log_info.log_file_name);
 
2589
        my_errno= 0;
 
2590
      }
 
2591
      else
 
2592
      {
 
2593
        /*
 
2594
          Other than ENOENT are fatal
 
2595
        */
 
2596
        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
 
2597
                            ER_BINLOG_PURGE_FATAL_ERR,
 
2598
                            "a problem with getting info on being purged %s; "
 
2599
                            "consider examining correspondence "
 
2600
                            "of your binlog index file "
 
2601
                            "to the actual binlog files",
 
2602
                            log_info.log_file_name);
 
2603
        error= LOG_INFO_FATAL;
 
2604
        goto err;
 
2605
      }
 
2606
    }
 
2607
    else
 
2608
    {
 
2609
      if (stat_area.st_mtime >= purge_time)
 
2610
        break;
 
2611
      if (my_delete(log_info.log_file_name, MYF(0)))
 
2612
      {
 
2613
        if (my_errno == ENOENT) 
 
2614
        {
 
2615
          /* It's not fatal even if we can't delete a log file */
 
2616
          push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
 
2617
                              ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
 
2618
                              log_info.log_file_name);
 
2619
          sql_print_information("Failed to delete file '%s'",
 
2620
                                log_info.log_file_name);
 
2621
          my_errno= 0;
 
2622
        }
 
2623
        else
 
2624
        {
 
2625
          push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
 
2626
                              ER_BINLOG_PURGE_FATAL_ERR,
 
2627
                              "a problem with deleting %s; "
 
2628
                              "consider examining correspondence "
 
2629
                              "of your binlog index file "
 
2630
                              "to the actual binlog files",
 
2631
                              log_info.log_file_name);
 
2632
          error= LOG_INFO_FATAL;
 
2633
          goto err;
 
2634
        }
 
2635
      }
 
2636
      ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
 
2637
    }
 
2638
    if (find_next_log(&log_info, 0))
 
2639
      break;
 
2640
  }
 
2641
 
 
2642
  /*
 
2643
    If we get killed -9 here, the sysadmin would have to edit
 
2644
    the log index file after restart - otherwise, this should be safe
 
2645
  */
 
2646
  error= update_log_index(&log_info, 1);
 
2647
 
 
2648
err:
 
2649
  pthread_mutex_unlock(&LOCK_index);
 
2650
  return(error);
 
2651
}
 
2652
#endif /* HAVE_REPLICATION */
 
2653
 
 
2654
 
 
2655
/**
 
2656
  Create a new log file name.
 
2657
 
 
2658
  @param buf            buf of at least FN_REFLEN where new name is stored
 
2659
 
 
2660
  @note
 
2661
    If file name will be longer then FN_REFLEN it will be truncated
 
2662
*/
 
2663
 
 
2664
void MYSQL_BIN_LOG::make_log_name(char* buf, const char* log_ident)
 
2665
{
 
2666
  uint dir_len = dirname_length(log_file_name); 
 
2667
  if (dir_len >= FN_REFLEN)
 
2668
    dir_len=FN_REFLEN-1;
 
2669
  strnmov(buf, log_file_name, dir_len);
 
2670
  strmake(buf+dir_len, log_ident, FN_REFLEN - dir_len -1);
 
2671
}
 
2672
 
 
2673
 
 
2674
/**
 
2675
  Check if we are writing/reading to the given log file.
 
2676
*/
 
2677
 
 
2678
bool MYSQL_BIN_LOG::is_active(const char *log_file_name_arg)
 
2679
{
 
2680
  return !strcmp(log_file_name, log_file_name_arg);
 
2681
}
 
2682
 
 
2683
 
 
2684
/*
 
2685
  Wrappers around new_file_impl to avoid using argument
 
2686
  to control locking. The argument 1) less readable 2) breaks
 
2687
  incapsulation 3) allows external access to the class without
 
2688
  a lock (which is not possible with private new_file_without_locking
 
2689
  method).
 
2690
*/
 
2691
 
 
2692
void MYSQL_BIN_LOG::new_file()
 
2693
{
 
2694
  new_file_impl(1);
 
2695
}
 
2696
 
 
2697
 
 
2698
void MYSQL_BIN_LOG::new_file_without_locking()
 
2699
{
 
2700
  new_file_impl(0);
 
2701
}
 
2702
 
 
2703
 
 
2704
/**
 
2705
  Start writing to a new log file or reopen the old file.
 
2706
 
 
2707
  @param need_lock              Set to 1 if caller has not locked LOCK_log
 
2708
 
 
2709
  @note
 
2710
    The new file name is stored last in the index file
 
2711
*/
 
2712
 
 
2713
void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
 
2714
{
 
2715
  char new_name[FN_REFLEN], *new_name_ptr, *old_name;
 
2716
 
 
2717
  if (!is_open())
 
2718
  {
 
2719
    return;
 
2720
  }
 
2721
 
 
2722
  if (need_lock)
 
2723
    pthread_mutex_lock(&LOCK_log);
 
2724
  pthread_mutex_lock(&LOCK_index);
 
2725
 
 
2726
  safe_mutex_assert_owner(&LOCK_log);
 
2727
  safe_mutex_assert_owner(&LOCK_index);
 
2728
 
 
2729
  /*
 
2730
    if binlog is used as tc log, be sure all xids are "unlogged",
 
2731
    so that on recover we only need to scan one - latest - binlog file
 
2732
    for prepared xids. As this is expected to be a rare event,
 
2733
    simple wait strategy is enough. We're locking LOCK_log to be sure no
 
2734
    new Xid_log_event's are added to the log (and prepared_xids is not
 
2735
    increased), and waiting on COND_prep_xids for late threads to
 
2736
    catch up.
 
2737
  */
 
2738
  if (prepared_xids)
 
2739
  {
 
2740
    tc_log_page_waits++;
 
2741
    pthread_mutex_lock(&LOCK_prep_xids);
 
2742
    while (prepared_xids) {
 
2743
      pthread_cond_wait(&COND_prep_xids, &LOCK_prep_xids);
 
2744
    }
 
2745
    pthread_mutex_unlock(&LOCK_prep_xids);
 
2746
  }
 
2747
 
 
2748
  /* Reuse old name if not binlog and not update log */
 
2749
  new_name_ptr= name;
 
2750
 
 
2751
  /*
 
2752
    If user hasn't specified an extension, generate a new log name
 
2753
    We have to do this here and not in open as we want to store the
 
2754
    new file name in the current binary log file.
 
2755
  */
 
2756
  if (generate_new_name(new_name, name))
 
2757
    goto end;
 
2758
  new_name_ptr=new_name;
 
2759
 
 
2760
  if (log_type == LOG_BIN)
 
2761
  {
 
2762
    if (!no_auto_events)
 
2763
    {
 
2764
      /*
 
2765
        We log the whole file name for log file as the user may decide
 
2766
        to change base names at some point.
 
2767
      */
 
2768
      Rotate_log_event r(new_name+dirname_length(new_name),
 
2769
                         0, LOG_EVENT_OFFSET, 0);
 
2770
      r.write(&log_file);
 
2771
      bytes_written += r.data_written;
 
2772
    }
 
2773
    /*
 
2774
      Update needs to be signalled even if there is no rotate event
 
2775
      log rotation should give the waiting thread a signal to
 
2776
      discover EOF and move on to the next log.
 
2777
    */
 
2778
    signal_update();
 
2779
  }
 
2780
  old_name=name;
 
2781
  name=0;                               // Don't free name
 
2782
  close(LOG_CLOSE_TO_BE_OPENED);
 
2783
 
 
2784
  /*
 
2785
     Note that at this point, log_state != LOG_CLOSED (important for is_open()).
 
2786
  */
 
2787
 
 
2788
  /*
 
2789
     new_file() is only used for rotation (in FLUSH LOGS or because size >
 
2790
     max_binlog_size or max_relay_log_size).
 
2791
     If this is a binary log, the Format_description_log_event at the beginning of
 
2792
     the new file should have created=0 (to distinguish with the
 
2793
     Format_description_log_event written at server startup, which should
 
2794
     trigger temp tables deletion on slaves.
 
2795
  */
 
2796
 
 
2797
  open(old_name, log_type, new_name_ptr,
 
2798
       io_cache_type, no_auto_events, max_size, 1);
 
2799
  my_free(old_name,MYF(0));
 
2800
 
 
2801
end:
 
2802
  if (need_lock)
 
2803
    pthread_mutex_unlock(&LOCK_log);
 
2804
  pthread_mutex_unlock(&LOCK_index);
 
2805
 
 
2806
  return;
 
2807
}
 
2808
 
 
2809
 
 
2810
bool MYSQL_BIN_LOG::append(Log_event* ev)
 
2811
{
 
2812
  bool error = 0;
 
2813
  pthread_mutex_lock(&LOCK_log);
 
2814
 
 
2815
  assert(log_file.type == SEQ_READ_APPEND);
 
2816
  /*
 
2817
    Log_event::write() is smart enough to use my_b_write() or
 
2818
    my_b_append() depending on the kind of cache we have.
 
2819
  */
 
2820
  if (ev->write(&log_file))
 
2821
  {
 
2822
    error=1;
 
2823
    goto err;
 
2824
  }
 
2825
  bytes_written+= ev->data_written;
 
2826
  if ((uint) my_b_append_tell(&log_file) > max_size)
 
2827
    new_file_without_locking();
 
2828
 
 
2829
err:
 
2830
  pthread_mutex_unlock(&LOCK_log);
 
2831
  signal_update();                              // Safe as we don't call close
 
2832
  return(error);
 
2833
}
 
2834
 
 
2835
 
 
2836
bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...)
 
2837
{
 
2838
  bool error= 0;
 
2839
  va_list(args);
 
2840
  va_start(args,len);
 
2841
 
 
2842
  assert(log_file.type == SEQ_READ_APPEND);
 
2843
 
 
2844
  safe_mutex_assert_owner(&LOCK_log);
 
2845
  do
 
2846
  {
 
2847
    if (my_b_append(&log_file,(uchar*) buf,len))
 
2848
    {
 
2849
      error= 1;
 
2850
      goto err;
 
2851
    }
 
2852
    bytes_written += len;
 
2853
  } while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
 
2854
  if ((uint) my_b_append_tell(&log_file) > max_size)
 
2855
    new_file_without_locking();
 
2856
 
 
2857
err:
 
2858
  if (!error)
 
2859
    signal_update();
 
2860
  return(error);
 
2861
}
 
2862
 
 
2863
 
 
2864
bool MYSQL_BIN_LOG::flush_and_sync()
 
2865
{
 
2866
  int err=0, fd=log_file.file;
 
2867
  safe_mutex_assert_owner(&LOCK_log);
 
2868
  if (flush_io_cache(&log_file))
 
2869
    return 1;
 
2870
  if (++sync_binlog_counter >= sync_binlog_period && sync_binlog_period)
 
2871
  {
 
2872
    sync_binlog_counter= 0;
 
2873
    err=my_sync(fd, MYF(MY_WME));
 
2874
  }
 
2875
  return err;
 
2876
}
 
2877
 
 
2878
void MYSQL_BIN_LOG::start_union_events(THD *thd, query_id_t query_id_param)
 
2879
{
 
2880
  assert(!thd->binlog_evt_union.do_union);
 
2881
  thd->binlog_evt_union.do_union= true;
 
2882
  thd->binlog_evt_union.unioned_events= false;
 
2883
  thd->binlog_evt_union.unioned_events_trans= false;
 
2884
  thd->binlog_evt_union.first_query_id= query_id_param;
 
2885
}
 
2886
 
 
2887
void MYSQL_BIN_LOG::stop_union_events(THD *thd)
 
2888
{
 
2889
  assert(thd->binlog_evt_union.do_union);
 
2890
  thd->binlog_evt_union.do_union= false;
 
2891
}
 
2892
 
 
2893
bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param)
 
2894
{
 
2895
  return (thd->binlog_evt_union.do_union && 
 
2896
          query_id_param >= thd->binlog_evt_union.first_query_id);
 
2897
}
 
2898
 
 
2899
 
 
2900
/*
 
2901
  These functions are placed in this file since they need access to
 
2902
  binlog_hton, which has internal linkage.
 
2903
*/
 
2904
 
 
2905
int THD::binlog_setup_trx_data()
 
2906
{
 
2907
  binlog_trx_data *trx_data=
 
2908
    (binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
 
2909
 
 
2910
  if (trx_data)
 
2911
    return(0);                             // Already set up
 
2912
 
 
2913
  trx_data= (binlog_trx_data*) my_malloc(sizeof(binlog_trx_data), MYF(MY_ZEROFILL));
 
2914
  if (!trx_data ||
 
2915
      open_cached_file(&trx_data->trans_log, mysql_tmpdir,
 
2916
                       LOG_PREFIX, binlog_cache_size, MYF(MY_WME)))
 
2917
  {
 
2918
    my_free((uchar*)trx_data, MYF(MY_ALLOW_ZERO_PTR));
 
2919
    return(1);                      // Didn't manage to set it up
 
2920
  }
 
2921
  thd_set_ha_data(this, binlog_hton, trx_data);
 
2922
 
 
2923
  trx_data= new (thd_get_ha_data(this, binlog_hton)) binlog_trx_data;
 
2924
 
 
2925
  return(0);
 
2926
}
 
2927
 
 
2928
/*
 
2929
  Function to start a statement and optionally a transaction for the
 
2930
  binary log.
 
2931
 
 
2932
  SYNOPSIS
 
2933
    binlog_start_trans_and_stmt()
 
2934
 
 
2935
  DESCRIPTION
 
2936
 
 
2937
    This function does three things:
 
2938
    - Start a transaction if not in autocommit mode or if a BEGIN
 
2939
      statement has been seen.
 
2940
 
 
2941
    - Start a statement transaction to allow us to truncate the binary
 
2942
      log.
 
2943
 
 
2944
    - Save the currrent binlog position so that we can roll back the
 
2945
      statement by truncating the transaction log.
 
2946
 
 
2947
      We only update the saved position if the old one was undefined,
 
2948
      the reason is that there are some cases (e.g., for CREATE-SELECT)
 
2949
      where the position is saved twice (e.g., both in
 
2950
      select_create::prepare() and THD::binlog_write_table_map()) , but
 
2951
      we should use the first. This means that calls to this function
 
2952
      can be used to start the statement before the first table map
 
2953
      event, to include some extra events.
 
2954
 */
 
2955
 
 
2956
void
 
2957
THD::binlog_start_trans_and_stmt()
 
2958
{
 
2959
  binlog_trx_data *trx_data= (binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
 
2960
 
 
2961
  if (trx_data == NULL ||
 
2962
      trx_data->before_stmt_pos == MY_OFF_T_UNDEF)
 
2963
  {
 
2964
    this->binlog_set_stmt_begin();
 
2965
    if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
 
2966
      trans_register_ha(this, true, binlog_hton);
 
2967
    trans_register_ha(this, false, binlog_hton);
 
2968
    /*
 
2969
      Mark statement transaction as read/write. We never start
 
2970
      a binary log transaction and keep it read-only,
 
2971
      therefore it's best to mark the transaction read/write just
 
2972
      at the same time we start it.
 
2973
      Not necessary to mark the normal transaction read/write
 
2974
      since the statement-level flag will be propagated automatically
 
2975
      inside ha_commit_trans.
 
2976
    */
 
2977
    ha_data[binlog_hton->slot].ha_info[0].set_trx_read_write();
 
2978
  }
 
2979
  return;
 
2980
}
 
2981
 
 
2982
void THD::binlog_set_stmt_begin() {
 
2983
  binlog_trx_data *trx_data=
 
2984
    (binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
 
2985
 
 
2986
  /*
 
2987
    The call to binlog_trans_log_savepos() might create the trx_data
 
2988
    structure, if it didn't exist before, so we save the position
 
2989
    into an auto variable and then write it into the transaction
 
2990
    data for the binary log (i.e., trx_data).
 
2991
  */
 
2992
  my_off_t pos= 0;
 
2993
  binlog_trans_log_savepos(this, &pos);
 
2994
  trx_data= (binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
 
2995
  trx_data->before_stmt_pos= pos;
 
2996
}
 
2997
 
 
2998
 
 
2999
/*
 
3000
  Write a table map to the binary log.
 
3001
 */
 
3002
 
 
3003
int THD::binlog_write_table_map(TABLE *table, bool is_trans)
 
3004
{
 
3005
  int error;
 
3006
 
 
3007
  /* Pre-conditions */
 
3008
  assert(current_stmt_binlog_row_based && mysql_bin_log.is_open());
 
3009
  assert(table->s->table_map_id != ULONG_MAX);
 
3010
 
 
3011
  Table_map_log_event::flag_set const
 
3012
    flags= Table_map_log_event::TM_NO_FLAGS;
 
3013
 
 
3014
  Table_map_log_event
 
3015
    the_event(this, table, table->s->table_map_id, is_trans, flags);
 
3016
 
 
3017
  if (is_trans && binlog_table_maps == 0)
 
3018
    binlog_start_trans_and_stmt();
 
3019
 
 
3020
  if ((error= mysql_bin_log.write(&the_event)))
 
3021
    return(error);
 
3022
 
 
3023
  binlog_table_maps++;
 
3024
  table->s->table_map_version= mysql_bin_log.table_map_version();
 
3025
  return(0);
 
3026
}
 
3027
 
 
3028
Rows_log_event*
 
3029
THD::binlog_get_pending_rows_event() const
 
3030
{
 
3031
  binlog_trx_data *const trx_data=
 
3032
    (binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
 
3033
  /*
 
3034
    This is less than ideal, but here's the story: If there is no
 
3035
    trx_data, prepare_pending_rows_event() has never been called
 
3036
    (since the trx_data is set up there). In that case, we just return
 
3037
    NULL.
 
3038
   */
 
3039
  return trx_data ? trx_data->pending() : NULL;
 
3040
}
 
3041
 
 
3042
void
 
3043
THD::binlog_set_pending_rows_event(Rows_log_event* ev)
 
3044
{
 
3045
  if (thd_get_ha_data(this, binlog_hton) == NULL)
 
3046
    binlog_setup_trx_data();
 
3047
 
 
3048
  binlog_trx_data *const trx_data=
 
3049
    (binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
 
3050
 
 
3051
  assert(trx_data);
 
3052
  trx_data->set_pending(ev);
 
3053
}
 
3054
 
 
3055
 
 
3056
/*
 
3057
  Moves the last bunch of rows from the pending Rows event to the binlog
 
3058
  (either cached binlog if transaction, or disk binlog). Sets a new pending
 
3059
  event.
 
3060
*/
 
3061
int
 
3062
MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
 
3063
                                                Rows_log_event* event)
 
3064
{
 
3065
  assert(mysql_bin_log.is_open());
 
3066
 
 
3067
  int error= 0;
 
3068
 
 
3069
  binlog_trx_data *const trx_data=
 
3070
    (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
 
3071
 
 
3072
  assert(trx_data);
 
3073
 
 
3074
  if (Rows_log_event* pending= trx_data->pending())
 
3075
  {
 
3076
    IO_CACHE *file= &log_file;
 
3077
 
 
3078
    /*
 
3079
      Decide if we should write to the log file directly or to the
 
3080
      transaction log.
 
3081
    */
 
3082
    if (pending->get_cache_stmt() || my_b_tell(&trx_data->trans_log))
 
3083
      file= &trx_data->trans_log;
 
3084
 
 
3085
    /*
 
3086
      If we are writing to the log file directly, we could avoid
 
3087
      locking the log. This does not work since we need to step the
 
3088
      m_table_map_version below, and that change has to be protected
 
3089
      by the LOCK_log mutex.
 
3090
    */
 
3091
    pthread_mutex_lock(&LOCK_log);
 
3092
 
 
3093
    /*
 
3094
      Write pending event to log file or transaction cache
 
3095
    */
 
3096
    if (pending->write(file))
 
3097
    {
 
3098
      pthread_mutex_unlock(&LOCK_log);
 
3099
      return(1);
 
3100
    }
 
3101
 
 
3102
    /*
 
3103
      We step the table map version if we are writing an event
 
3104
      representing the end of a statement.  We do this regardless of
 
3105
      wheather we write to the transaction cache or to directly to the
 
3106
      file.
 
3107
 
 
3108
      In an ideal world, we could avoid stepping the table map version
 
3109
      if we were writing to a transaction cache, since we could then
 
3110
      reuse the table map that was written earlier in the transaction
 
3111
      cache.  This does not work since STMT_END_F implies closing all
 
3112
      table mappings on the slave side.
 
3113
 
 
3114
      TODO: Find a solution so that table maps does not have to be
 
3115
      written several times within a transaction.
 
3116
     */
 
3117
    if (pending->get_flags(Rows_log_event::STMT_END_F))
 
3118
      ++m_table_map_version;
 
3119
 
 
3120
    delete pending;
 
3121
 
 
3122
    if (file == &log_file)
 
3123
    {
 
3124
      error= flush_and_sync();
 
3125
      if (!error)
 
3126
      {
 
3127
        signal_update();
 
3128
        rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
 
3129
      }
 
3130
    }
 
3131
 
 
3132
    pthread_mutex_unlock(&LOCK_log);
 
3133
  }
 
3134
 
 
3135
  thd->binlog_set_pending_rows_event(event);
 
3136
 
 
3137
  return(error);
 
3138
}
 
3139
 
 
3140
/**
 
3141
  Write an event to the binary log.
 
3142
*/
 
3143
 
 
3144
bool MYSQL_BIN_LOG::write(Log_event *event_info)
 
3145
{
 
3146
  THD *thd= event_info->thd;
 
3147
  bool error= 1;
 
3148
 
 
3149
  if (thd->binlog_evt_union.do_union)
 
3150
  {
 
3151
    /*
 
3152
      In Stored function; Remember that function call caused an update.
 
3153
      We will log the function call to the binary log on function exit
 
3154
    */
 
3155
    thd->binlog_evt_union.unioned_events= true;
 
3156
    thd->binlog_evt_union.unioned_events_trans |= event_info->cache_stmt;
 
3157
    return(0);
 
3158
  }
 
3159
 
 
3160
  /*
 
3161
    Flush the pending rows event to the transaction cache or to the
 
3162
    log file.  Since this function potentially aquire the LOCK_log
 
3163
    mutex, we do this before aquiring the LOCK_log mutex in this
 
3164
    function.
 
3165
 
 
3166
    We only end the statement if we are in a top-level statement.  If
 
3167
    we are inside a stored function, we do not end the statement since
 
3168
    this will close all tables on the slave.
 
3169
  */
 
3170
  bool const end_stmt= false;
 
3171
  thd->binlog_flush_pending_rows_event(end_stmt);
 
3172
 
 
3173
  pthread_mutex_lock(&LOCK_log);
 
3174
 
 
3175
  /*
 
3176
     In most cases this is only called if 'is_open()' is true; in fact this is
 
3177
     mostly called if is_open() *was* true a few instructions before, but it
 
3178
     could have changed since.
 
3179
  */
 
3180
  if (likely(is_open()))
 
3181
  {
 
3182
    IO_CACHE *file= &log_file;
 
3183
    /*
 
3184
      In the future we need to add to the following if tests like
 
3185
      "do the involved tables match (to be implemented)
 
3186
      binlog_[wild_]{do|ignore}_table?" (WL#1049)"
 
3187
    */
 
3188
    const char *local_db= event_info->get_db();
 
3189
    if ((thd && !(thd->options & OPTION_BIN_LOG)) ||
 
3190
        (!binlog_filter->db_ok(local_db)))
 
3191
    {
 
3192
      VOID(pthread_mutex_unlock(&LOCK_log));
 
3193
      return(0);
 
3194
    }
 
3195
 
 
3196
    /*
 
3197
      Should we write to the binlog cache or to the binlog on disk?
 
3198
      Write to the binlog cache if:
 
3199
      - it is already not empty (meaning we're in a transaction; note that the
 
3200
     present event could be about a non-transactional table, but still we need
 
3201
     to write to the binlog cache in that case to handle updates to mixed
 
3202
     trans/non-trans table types the best possible in binlogging)
 
3203
      - or if the event asks for it (cache_stmt == TRUE).
 
3204
    */
 
3205
    if (opt_using_transactions && thd)
 
3206
    {
 
3207
      if (thd->binlog_setup_trx_data())
 
3208
        goto err;
 
3209
 
 
3210
      binlog_trx_data *const trx_data=
 
3211
        (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
 
3212
      IO_CACHE *trans_log= &trx_data->trans_log;
 
3213
      my_off_t trans_log_pos= my_b_tell(trans_log);
 
3214
      if (event_info->get_cache_stmt() || trans_log_pos != 0)
 
3215
      {
 
3216
        if (trans_log_pos == 0)
 
3217
          thd->binlog_start_trans_and_stmt();
 
3218
        file= trans_log;
 
3219
      }
 
3220
      /*
 
3221
        TODO as Mats suggested, for all the cases above where we write to
 
3222
        trans_log, it sounds unnecessary to lock LOCK_log. We should rather
 
3223
        test first if we want to write to trans_log, and if not, lock
 
3224
        LOCK_log.
 
3225
      */
 
3226
    }
 
3227
 
 
3228
    /*
 
3229
      No check for auto events flag here - this write method should
 
3230
      never be called if auto-events are enabled
 
3231
    */
 
3232
 
 
3233
    /*
 
3234
      1. Write first log events which describe the 'run environment'
 
3235
      of the SQL command
 
3236
    */
 
3237
 
 
3238
    /*
 
3239
      If row-based binlogging, Insert_id, Rand and other kind of "setting
 
3240
      context" events are not needed.
 
3241
    */
 
3242
    if (thd)
 
3243
    {
 
3244
      if (!thd->current_stmt_binlog_row_based)
 
3245
      {
 
3246
        if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
 
3247
        {
 
3248
          Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT,
 
3249
                             thd->first_successful_insert_id_in_prev_stmt_for_binlog);
 
3250
          if (e.write(file))
 
3251
            goto err;
 
3252
        }
 
3253
        if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0)
 
3254
        {
 
3255
          /*
 
3256
            If the auto_increment was second in a table's index (possible with
 
3257
            MyISAM or BDB) (table->next_number_keypart != 0), such event is
 
3258
            in fact not necessary. We could avoid logging it.
 
3259
          */
 
3260
          Intvar_log_event e(thd, (uchar) INSERT_ID_EVENT,
 
3261
                             thd->auto_inc_intervals_in_cur_stmt_for_binlog.
 
3262
                             minimum());
 
3263
          if (e.write(file))
 
3264
            goto err;
 
3265
        }
 
3266
        if (thd->rand_used)
 
3267
        {
 
3268
          Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2);
 
3269
          if (e.write(file))
 
3270
            goto err;
 
3271
        }
 
3272
        if (thd->user_var_events.elements)
 
3273
        {
 
3274
          for (uint i= 0; i < thd->user_var_events.elements; i++)
 
3275
          {
 
3276
            BINLOG_USER_VAR_EVENT *user_var_event;
 
3277
            get_dynamic(&thd->user_var_events,(uchar*) &user_var_event, i);
 
3278
            User_var_log_event e(thd, user_var_event->user_var_event->name.str,
 
3279
                                 user_var_event->user_var_event->name.length,
 
3280
                                 user_var_event->value,
 
3281
                                 user_var_event->length,
 
3282
                                 user_var_event->type,
 
3283
                                 user_var_event->charset_number);
 
3284
            if (e.write(file))
 
3285
              goto err;
 
3286
          }
 
3287
        }
 
3288
      }
 
3289
    }
 
3290
 
 
3291
    /*
 
3292
       Write the SQL command
 
3293
     */
 
3294
 
 
3295
    if (event_info->write(file))
 
3296
      goto err;
 
3297
 
 
3298
    if (file == &log_file) // we are writing to the real log (disk)
 
3299
    {
 
3300
      if (flush_and_sync())
 
3301
        goto err;
 
3302
      signal_update();
 
3303
      rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
 
3304
    }
 
3305
    error=0;
 
3306
 
 
3307
err:
 
3308
    if (error)
 
3309
    {
 
3310
      if (my_errno == EFBIG)
 
3311
        my_message(ER_TRANS_CACHE_FULL, ER(ER_TRANS_CACHE_FULL), MYF(0));
 
3312
      else
 
3313
        my_error(ER_ERROR_ON_WRITE, MYF(0), name, errno);
 
3314
      write_error=1;
 
3315
    }
 
3316
  }
 
3317
 
 
3318
  if (event_info->flags & LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F)
 
3319
    ++m_table_map_version;
 
3320
 
 
3321
  pthread_mutex_unlock(&LOCK_log);
 
3322
  return(error);
 
3323
}
 
3324
 
 
3325
 
 
3326
int error_log_print(enum loglevel level, const char *format,
 
3327
                    va_list args)
 
3328
{
 
3329
  return logger.error_log_print(level, format, args);
 
3330
}
 
3331
 
 
3332
 
 
3333
bool slow_log_print(THD *thd, const char *query, uint query_length,
 
3334
                    ulonglong current_utime)
 
3335
{
 
3336
  return logger.slow_log_print(thd, query, query_length, current_utime);
 
3337
}
 
3338
 
 
3339
 
 
3340
bool LOGGER::log_command(THD *thd, enum enum_server_command command)
 
3341
{
 
3342
  /*
 
3343
    Log command if we have at least one log event handler enabled and want
 
3344
    to log this king of commands
 
3345
  */
 
3346
  if (*general_log_handler_list && (what_to_log & (1L << (uint) command)))
 
3347
  {
 
3348
    if (thd->options & OPTION_LOG_OFF)
 
3349
    {
 
3350
      /* No logging */
 
3351
      return false;
 
3352
    }
 
3353
 
 
3354
    return true;
 
3355
  }
 
3356
 
 
3357
  return false;
 
3358
}
 
3359
 
 
3360
 
 
3361
bool general_log_print(THD *thd, enum enum_server_command command,
 
3362
                       const char *format, ...)
 
3363
{
 
3364
  va_list args;
 
3365
  uint error= 0;
 
3366
 
 
3367
  /* Print the message to the buffer if we want to log this king of commands */
 
3368
  if (! logger.log_command(thd, command))
 
3369
    return false;
 
3370
 
 
3371
  va_start(args, format);
 
3372
  error= logger.general_log_print(thd, command, format, args);
 
3373
  va_end(args);
 
3374
 
 
3375
  return error;
 
3376
}
 
3377
 
 
3378
bool general_log_write(THD *thd, enum enum_server_command command,
 
3379
                       const char *query, uint query_length)
 
3380
{
 
3381
  /* Write the message to the log if we want to log this king of commands */
 
3382
  if (logger.log_command(thd, command))
 
3383
    return logger.general_log_write(thd, command, query, query_length);
 
3384
 
 
3385
  return false;
 
3386
}
 
3387
 
 
3388
void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
 
3389
{
 
3390
  if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
 
3391
    pthread_mutex_lock(&LOCK_log);
 
3392
  if ((flags & RP_FORCE_ROTATE) ||
 
3393
      (my_b_tell(&log_file) >= (my_off_t) max_size))
 
3394
  {
 
3395
    new_file_without_locking();
 
3396
#ifdef HAVE_REPLICATION
 
3397
    if (expire_logs_days)
 
3398
    {
 
3399
      time_t purge_time= my_time(0) - expire_logs_days*24*60*60;
 
3400
      if (purge_time >= 0)
 
3401
        purge_logs_before_date(purge_time);
 
3402
    }
 
3403
#endif
 
3404
  }
 
3405
  if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
 
3406
    pthread_mutex_unlock(&LOCK_log);
 
3407
}
 
3408
 
 
3409
uint MYSQL_BIN_LOG::next_file_id()
 
3410
{
 
3411
  uint res;
 
3412
  pthread_mutex_lock(&LOCK_log);
 
3413
  res = file_id++;
 
3414
  pthread_mutex_unlock(&LOCK_log);
 
3415
  return res;
 
3416
}
 
3417
 
 
3418
 
 
3419
/*
 
3420
  Write the contents of a cache to the binary log.
 
3421
 
 
3422
  SYNOPSIS
 
3423
    write_cache()
 
3424
    cache    Cache to write to the binary log
 
3425
    lock_log True if the LOCK_log mutex should be aquired, false otherwise
 
3426
    sync_log True if the log should be flushed and sync:ed
 
3427
 
 
3428
  DESCRIPTION
 
3429
    Write the contents of the cache to the binary log. The cache will
 
3430
    be reset as a READ_CACHE to be able to read the contents from it.
 
3431
 */
 
3432
 
 
3433
int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
 
3434
{
 
3435
  Mutex_sentry sentry(lock_log ? &LOCK_log : NULL);
 
3436
 
 
3437
  if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
 
3438
    return ER_ERROR_ON_WRITE;
 
3439
  uint length= my_b_bytes_in_cache(cache), group, carry, hdr_offs;
 
3440
  long val;
 
3441
  uchar header[LOG_EVENT_HEADER_LEN];
 
3442
 
 
3443
  /*
 
3444
    The events in the buffer have incorrect end_log_pos data
 
3445
    (relative to beginning of group rather than absolute),
 
3446
    so we'll recalculate them in situ so the binlog is always
 
3447
    correct, even in the middle of a group. This is possible
 
3448
    because we now know the start position of the group (the
 
3449
    offset of this cache in the log, if you will); all we need
 
3450
    to do is to find all event-headers, and add the position of
 
3451
    the group to the end_log_pos of each event.  This is pretty
 
3452
    straight forward, except that we read the cache in segments,
 
3453
    so an event-header might end up on the cache-border and get
 
3454
    split.
 
3455
  */
 
3456
 
 
3457
  group= (uint)my_b_tell(&log_file);
 
3458
  hdr_offs= carry= 0;
 
3459
 
 
3460
  do
 
3461
  {
 
3462
 
 
3463
    /*
 
3464
      if we only got a partial header in the last iteration,
 
3465
      get the other half now and process a full header.
 
3466
    */
 
3467
    if (unlikely(carry > 0))
 
3468
    {
 
3469
      assert(carry < LOG_EVENT_HEADER_LEN);
 
3470
 
 
3471
      /* assemble both halves */
 
3472
      memcpy(&header[carry], (char *)cache->read_pos, LOG_EVENT_HEADER_LEN - carry);
 
3473
 
 
3474
      /* fix end_log_pos */
 
3475
      val= uint4korr(&header[LOG_POS_OFFSET]) + group;
 
3476
      int4store(&header[LOG_POS_OFFSET], val);
 
3477
 
 
3478
      /* write the first half of the split header */
 
3479
      if (my_b_write(&log_file, header, carry))
 
3480
        return ER_ERROR_ON_WRITE;
 
3481
 
 
3482
      /*
 
3483
        copy fixed second half of header to cache so the correct
 
3484
        version will be written later.
 
3485
      */
 
3486
      memcpy((char *)cache->read_pos, &header[carry], LOG_EVENT_HEADER_LEN - carry);
 
3487
 
 
3488
      /* next event header at ... */
 
3489
      hdr_offs = uint4korr(&header[EVENT_LEN_OFFSET]) - carry;
 
3490
 
 
3491
      carry= 0;
 
3492
    }
 
3493
 
 
3494
    /* if there is anything to write, process it. */
 
3495
 
 
3496
    if (likely(length > 0))
 
3497
    {
 
3498
      /*
 
3499
        process all event-headers in this (partial) cache.
 
3500
        if next header is beyond current read-buffer,
 
3501
        we'll get it later (though not necessarily in the
 
3502
        very next iteration, just "eventually").
 
3503
      */
 
3504
 
 
3505
      while (hdr_offs < length)
 
3506
      {
 
3507
        /*
 
3508
          partial header only? save what we can get, process once
 
3509
          we get the rest.
 
3510
        */
 
3511
 
 
3512
        if (hdr_offs + LOG_EVENT_HEADER_LEN > length)
 
3513
        {
 
3514
          carry= length - hdr_offs;
 
3515
          memcpy(header, (char *)cache->read_pos + hdr_offs, carry);
 
3516
          length= hdr_offs;
 
3517
        }
 
3518
        else
 
3519
        {
 
3520
          /* we've got a full event-header, and it came in one piece */
 
3521
 
 
3522
          uchar *log_pos= (uchar *)cache->read_pos + hdr_offs + LOG_POS_OFFSET;
 
3523
 
 
3524
          /* fix end_log_pos */
 
3525
          val= uint4korr(log_pos) + group;
 
3526
          int4store(log_pos, val);
 
3527
 
 
3528
          /* next event header at ... */
 
3529
          log_pos= (uchar *)cache->read_pos + hdr_offs + EVENT_LEN_OFFSET;
 
3530
          hdr_offs += uint4korr(log_pos);
 
3531
 
 
3532
        }
 
3533
      }
 
3534
 
 
3535
      /*
 
3536
        Adjust hdr_offs. Note that it may still point beyond the segment
 
3537
        read in the next iteration; if the current event is very long,
 
3538
        it may take a couple of read-iterations (and subsequent adjustments
 
3539
        of hdr_offs) for it to point into the then-current segment.
 
3540
        If we have a split header (!carry), hdr_offs will be set at the
 
3541
        beginning of the next iteration, overwriting the value we set here:
 
3542
      */
 
3543
      hdr_offs -= length;
 
3544
    }
 
3545
 
 
3546
    /* Write data to the binary log file */
 
3547
    if (my_b_write(&log_file, cache->read_pos, length))
 
3548
      return ER_ERROR_ON_WRITE;
 
3549
    cache->read_pos=cache->read_end;            // Mark buffer used up
 
3550
  } while ((length= my_b_fill(cache)));
 
3551
 
 
3552
  assert(carry == 0);
 
3553
 
 
3554
  if (sync_log)
 
3555
    flush_and_sync();
 
3556
 
 
3557
  return 0;                                     // All OK
 
3558
}
 
3559
 
 
3560
/**
 
3561
  Write a cached log entry to the binary log.
 
3562
  - To support transaction over replication, we wrap the transaction
 
3563
  with BEGIN/COMMIT or BEGIN/ROLLBACK in the binary log.
 
3564
  We want to write a BEGIN/ROLLBACK block when a non-transactional table
 
3565
  was updated in a transaction which was rolled back. This is to ensure
 
3566
  that the same updates are run on the slave.
 
3567
 
 
3568
  @param thd
 
3569
  @param cache          The cache to copy to the binlog
 
3570
  @param commit_event   The commit event to print after writing the
 
3571
                        contents of the cache.
 
3572
 
 
3573
  @note
 
3574
    We only come here if there is something in the cache.
 
3575
  @note
 
3576
    The thing in the cache is always a complete transaction.
 
3577
  @note
 
3578
    'cache' needs to be reinitialized after this functions returns.
 
3579
*/
 
3580
 
 
3581
bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
 
3582
{
 
3583
  VOID(pthread_mutex_lock(&LOCK_log));
 
3584
 
 
3585
  /* NULL would represent nothing to replicate after ROLLBACK */
 
3586
  assert(commit_event != NULL);
 
3587
 
 
3588
  assert(is_open());
 
3589
  if (likely(is_open()))                       // Should always be true
 
3590
  {
 
3591
    /*
 
3592
      We only bother to write to the binary log if there is anything
 
3593
      to write.
 
3594
     */
 
3595
    if (my_b_tell(cache) > 0)
 
3596
    {
 
3597
      /*
 
3598
        Log "BEGIN" at the beginning of every transaction.  Here, a
 
3599
        transaction is either a BEGIN..COMMIT block or a single
 
3600
        statement in autocommit mode.
 
3601
      */
 
3602
      Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), true, false);
 
3603
      /*
 
3604
        Imagine this is rollback due to net timeout, after all
 
3605
        statements of the transaction succeeded. Then we want a
 
3606
        zero-error code in BEGIN.  In other words, if there was a
 
3607
        really serious error code it's already in the statement's
 
3608
        events, there is no need to put it also in this internally
 
3609
        generated event, and as this event is generated late it would
 
3610
        lead to false alarms.
 
3611
 
 
3612
        This is safer than thd->clear_error() against kills at shutdown.
 
3613
      */
 
3614
      qinfo.error_code= 0;
 
3615
      /*
 
3616
        Now this Query_log_event has artificial log_pos 0. It must be
 
3617
        adjusted to reflect the real position in the log. Not doing it
 
3618
        would confuse the slave: it would prevent this one from
 
3619
        knowing where he is in the master's binlog, which would result
 
3620
        in wrong positions being shown to the user, MASTER_POS_WAIT
 
3621
        undue waiting etc.
 
3622
      */
 
3623
      if (qinfo.write(&log_file))
 
3624
        goto err;
 
3625
 
 
3626
      if ((write_error= write_cache(cache, false, false)))
 
3627
        goto err;
 
3628
 
 
3629
      if (commit_event && commit_event->write(&log_file))
 
3630
        goto err;
 
3631
      if (flush_and_sync())
 
3632
        goto err;
 
3633
      if (cache->error)                         // Error on read
 
3634
      {
 
3635
        sql_print_error(ER(ER_ERROR_ON_READ), cache->file_name, errno);
 
3636
        write_error=1;                          // Don't give more errors
 
3637
        goto err;
 
3638
      }
 
3639
      signal_update();
 
3640
    }
 
3641
 
 
3642
    /*
 
3643
      if commit_event is Xid_log_event, increase the number of
 
3644
      prepared_xids (it's decreasd in ::unlog()). Binlog cannot be rotated
 
3645
      if there're prepared xids in it - see the comment in new_file() for
 
3646
      an explanation.
 
3647
      If the commit_event is not Xid_log_event (then it's a Query_log_event)
 
3648
      rotate binlog, if necessary.
 
3649
    */
 
3650
    if (commit_event && commit_event->get_type_code() == XID_EVENT)
 
3651
    {
 
3652
      pthread_mutex_lock(&LOCK_prep_xids);
 
3653
      prepared_xids++;
 
3654
      pthread_mutex_unlock(&LOCK_prep_xids);
 
3655
    }
 
3656
    else
 
3657
      rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
 
3658
  }
 
3659
  VOID(pthread_mutex_unlock(&LOCK_log));
 
3660
 
 
3661
  return(0);
 
3662
 
 
3663
err:
 
3664
  if (!write_error)
 
3665
  {
 
3666
    write_error= 1;
 
3667
    sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
 
3668
  }
 
3669
  VOID(pthread_mutex_unlock(&LOCK_log));
 
3670
  return(1);
 
3671
}
 
3672
 
 
3673
 
 
3674
/**
 
3675
  Wait until we get a signal that the relay log has been updated
 
3676
 
 
3677
  @param[in] thd   a THD struct
 
3678
  @note
 
3679
    LOCK_log must be taken before calling this function.
 
3680
    It will be released at the end of the function.
 
3681
*/
 
3682
 
 
3683
void MYSQL_BIN_LOG::wait_for_update_relay_log(THD* thd)
 
3684
{
 
3685
  const char *old_msg;
 
3686
  old_msg= thd->enter_cond(&update_cond, &LOCK_log,
 
3687
                           "Slave has read all relay log; " 
 
3688
                           "waiting for the slave I/O "
 
3689
                           "thread to update it" );
 
3690
  pthread_cond_wait(&update_cond, &LOCK_log);
 
3691
  thd->exit_cond(old_msg);
 
3692
  return;
 
3693
}
 
3694
 
 
3695
 
 
3696
/**
 
3697
  Wait until we get a signal that the binary log has been updated.
 
3698
  Applies to master only.
 
3699
     
 
3700
  NOTES
 
3701
  @param[in] thd        a THD struct
 
3702
  @param[in] timeout    a pointer to a timespec;
 
3703
                        NULL means to wait w/o timeout.
 
3704
  @retval    0          if got signalled on update
 
3705
  @retval    non-0      if wait timeout elapsed
 
3706
  @note
 
3707
    LOCK_log must be taken before calling this function.
 
3708
    LOCK_log is being released while the thread is waiting.
 
3709
    LOCK_log is released by the caller.
 
3710
*/
 
3711
 
 
3712
int MYSQL_BIN_LOG::wait_for_update_bin_log(THD* thd,
 
3713
                                           const struct timespec *timeout)
 
3714
{
 
3715
  int ret= 0;
 
3716
  const char* old_msg = thd->proc_info;
 
3717
  old_msg= thd->enter_cond(&update_cond, &LOCK_log,
 
3718
                           "Master has sent all binlog to slave; "
 
3719
                           "waiting for binlog to be updated");
 
3720
  if (!timeout)
 
3721
    pthread_cond_wait(&update_cond, &LOCK_log);
 
3722
  else
 
3723
    ret= pthread_cond_timedwait(&update_cond, &LOCK_log,
 
3724
                                const_cast<struct timespec *>(timeout));
 
3725
  return(ret);
 
3726
}
 
3727
 
 
3728
 
 
3729
/**
 
3730
  Close the log file.
 
3731
 
 
3732
  @param exiting     Bitmask for one or more of the following bits:
 
3733
          - LOG_CLOSE_INDEX : if we should close the index file
 
3734
          - LOG_CLOSE_TO_BE_OPENED : if we intend to call open
 
3735
                                     at once after close.
 
3736
          - LOG_CLOSE_STOP_EVENT : write a 'stop' event to the log
 
3737
 
 
3738
  @note
 
3739
    One can do an open on the object at once after doing a close.
 
3740
    The internal structures are not freed until cleanup() is called
 
3741
*/
 
3742
 
 
3743
void MYSQL_BIN_LOG::close(uint exiting)
 
3744
{                                       // One can't set log_type here!
 
3745
  if (log_state == LOG_OPENED)
 
3746
  {
 
3747
#ifdef HAVE_REPLICATION
 
3748
    if (log_type == LOG_BIN && !no_auto_events &&
 
3749
        (exiting & LOG_CLOSE_STOP_EVENT))
 
3750
    {
 
3751
      Stop_log_event s;
 
3752
      s.write(&log_file);
 
3753
      bytes_written+= s.data_written;
 
3754
      signal_update();
 
3755
    }
 
3756
#endif /* HAVE_REPLICATION */
 
3757
 
 
3758
    /* don't pwrite in a file opened with O_APPEND - it doesn't work */
 
3759
    if (log_file.type == WRITE_CACHE && log_type == LOG_BIN)
 
3760
    {
 
3761
      my_off_t offset= BIN_LOG_HEADER_SIZE + FLAGS_OFFSET;
 
3762
      uchar flags= 0;            // clearing LOG_EVENT_BINLOG_IN_USE_F
 
3763
      pwrite(log_file.file, &flags, 1, offset);
 
3764
    }
 
3765
 
 
3766
    /* this will cleanup IO_CACHE, sync and close the file */
 
3767
    MYSQL_LOG::close(exiting);
 
3768
  }
 
3769
 
 
3770
  /*
 
3771
    The following test is needed even if is_open() is not set, as we may have
 
3772
    called a not complete close earlier and the index file is still open.
 
3773
  */
 
3774
 
 
3775
  if ((exiting & LOG_CLOSE_INDEX) && my_b_inited(&index_file))
 
3776
  {
 
3777
    end_io_cache(&index_file);
 
3778
    if (my_close(index_file.file, MYF(0)) < 0 && ! write_error)
 
3779
    {
 
3780
      write_error= 1;
 
3781
      sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno);
 
3782
    }
 
3783
  }
 
3784
  log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
 
3785
  safeFree(name);
 
3786
  return;
 
3787
}
 
3788
 
 
3789
 
 
3790
void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg)
 
3791
{
 
3792
  /*
 
3793
    We need to take locks, otherwise this may happen:
 
3794
    new_file() is called, calls open(old_max_size), then before open() starts,
 
3795
    set_max_size() sets max_size to max_size_arg, then open() starts and
 
3796
    uses the old_max_size argument, so max_size_arg has been overwritten and
 
3797
    it's like if the SET command was never run.
 
3798
  */
 
3799
  pthread_mutex_lock(&LOCK_log);
 
3800
  if (is_open())
 
3801
    max_size= max_size_arg;
 
3802
  pthread_mutex_unlock(&LOCK_log);
 
3803
  return;
 
3804
}
 
3805
 
 
3806
 
 
3807
/**
 
3808
  Check if a string is a valid number.
 
3809
 
 
3810
  @param str                    String to test
 
3811
  @param res                    Store value here
 
3812
  @param allow_wildcards        Set to 1 if we should ignore '%' and '_'
 
3813
 
 
3814
  @note
 
3815
    For the moment the allow_wildcards argument is not used
 
3816
    Should be move to some other file.
 
3817
 
 
3818
  @retval
 
3819
    1   String is a number
 
3820
  @retval
 
3821
    0   Error
 
3822
*/
 
3823
 
 
3824
static bool test_if_number(register const char *str,
 
3825
                           long *res, bool allow_wildcards)
 
3826
{
 
3827
  register int flag;
 
3828
  const char *start;
 
3829
 
 
3830
  flag= 0; 
 
3831
  start= str;
 
3832
  while (*str++ == ' ') ;
 
3833
  if (*--str == '-' || *str == '+')
 
3834
    str++;
 
3835
  while (my_isdigit(files_charset_info,*str) ||
 
3836
         (allow_wildcards && (*str == wild_many || *str == wild_one)))
 
3837
  {
 
3838
    flag=1;
 
3839
    str++;
 
3840
  }
 
3841
  if (*str == '.')
 
3842
  {
 
3843
    for (str++ ;
 
3844
         my_isdigit(files_charset_info,*str) ||
 
3845
           (allow_wildcards && (*str == wild_many || *str == wild_one)) ;
 
3846
         str++, flag=1) ;
 
3847
  }
 
3848
  if (*str != 0 || flag == 0)
 
3849
    return(0);
 
3850
  if (res)
 
3851
    *res=atol(start);
 
3852
  return(1);                    /* Number ok */
 
3853
} /* test_if_number */
 
3854
 
 
3855
 
 
3856
void sql_perror(const char *message)
 
3857
{
 
3858
#ifdef HAVE_STRERROR
 
3859
  sql_print_error("%s: %s",message, strerror(errno));
 
3860
#else
 
3861
  perror(message);
 
3862
#endif
 
3863
}
 
3864
 
 
3865
 
 
3866
bool flush_error_log()
 
3867
{
 
3868
  bool result=0;
 
3869
  if (opt_error_log)
 
3870
  {
 
3871
    char err_renamed[FN_REFLEN], *end;
 
3872
    end= strmake(err_renamed,log_error_file,FN_REFLEN-4);
 
3873
    strmov(end, "-old");
 
3874
    VOID(pthread_mutex_lock(&LOCK_error_log));
 
3875
    char err_temp[FN_REFLEN+4];
 
3876
    /*
 
3877
     On Windows is necessary a temporary file for to rename
 
3878
     the current error file.
 
3879
    */
 
3880
    strxmov(err_temp, err_renamed,"-tmp",NullS);
 
3881
    (void) my_delete(err_temp, MYF(0)); 
 
3882
    if (freopen(err_temp,"a+",stdout))
 
3883
    {
 
3884
      int fd;
 
3885
      size_t bytes;
 
3886
      uchar buf[IO_SIZE];
 
3887
 
 
3888
      freopen(err_temp,"a+",stderr);
 
3889
      (void) my_delete(err_renamed, MYF(0));
 
3890
      my_rename(log_error_file,err_renamed,MYF(0));
 
3891
      if (freopen(log_error_file,"a+",stdout))
 
3892
        freopen(log_error_file,"a+",stderr);
 
3893
 
 
3894
      if ((fd = my_open(err_temp, O_RDONLY, MYF(0))) >= 0)
 
3895
      {
 
3896
        while ((bytes= my_read(fd, buf, IO_SIZE, MYF(0))) &&
 
3897
               bytes != MY_FILE_ERROR)
 
3898
          my_fwrite(stderr, buf, bytes, MYF(0));
 
3899
        my_close(fd, MYF(0));
 
3900
      }
 
3901
      (void) my_delete(err_temp, MYF(0)); 
 
3902
    }
 
3903
    else
 
3904
     result= 1;
 
3905
    VOID(pthread_mutex_unlock(&LOCK_error_log));
 
3906
  }
 
3907
   return result;
 
3908
}
 
3909
 
 
3910
void MYSQL_BIN_LOG::signal_update()
 
3911
{
 
3912
  pthread_cond_broadcast(&update_cond);
 
3913
  return;
 
3914
}
 
3915
 
 
3916
/**
 
3917
  Prints a printf style message to the error log and, under NT, to the
 
3918
  Windows event log.
 
3919
 
 
3920
  This function prints the message into a buffer and then sends that buffer
 
3921
  to other functions to write that message to other logging sources.
 
3922
 
 
3923
  @param event_type          Type of event to write (Error, Warning, or Info)
 
3924
  @param format              Printf style format of message
 
3925
  @param args                va_list list of arguments for the message
 
3926
 
 
3927
  @returns
 
3928
    The function always returns 0. The return value is present in the
 
3929
    signature to be compatible with other logging routines, which could
 
3930
    return an error (e.g. logging to the log tables)
 
3931
*/
 
3932
static void print_buffer_to_file(enum loglevel level,
 
3933
                                 int error_code __attribute__((__unused__)),
 
3934
                                 const char *buffer,
 
3935
                                 size_t buffer_length __attribute__((__unused__)))
 
3936
{
 
3937
  time_t skr;
 
3938
  struct tm tm_tmp;
 
3939
  struct tm *start;
 
3940
 
 
3941
  VOID(pthread_mutex_lock(&LOCK_error_log));
 
3942
 
 
3943
  skr= my_time(0);
 
3944
  localtime_r(&skr, &tm_tmp);
 
3945
  start=&tm_tmp;
 
3946
 
 
3947
  fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d [%s] %s\n",
 
3948
          start->tm_year % 100,
 
3949
          start->tm_mon+1,
 
3950
          start->tm_mday,
 
3951
          start->tm_hour,
 
3952
          start->tm_min,
 
3953
          start->tm_sec,
 
3954
          (level == ERROR_LEVEL ? "ERROR" : level == WARNING_LEVEL ?
 
3955
           "Warning" : "Note"),
 
3956
          buffer);
 
3957
 
 
3958
  fflush(stderr);
 
3959
 
 
3960
  VOID(pthread_mutex_unlock(&LOCK_error_log));
 
3961
  return;
 
3962
}
 
3963
 
 
3964
 
 
3965
int vprint_msg_to_log(enum loglevel level, const char *format, va_list args)
 
3966
{
 
3967
  char   buff[1024];
 
3968
  size_t length;
 
3969
  int error_code= errno;
 
3970
 
 
3971
  length= vsnprintf(buff, sizeof(buff), format, args);
 
3972
 
 
3973
  print_buffer_to_file(level, error_code, buff, length);
 
3974
 
 
3975
  return(0);
 
3976
}
 
3977
 
 
3978
 
 
3979
void sql_print_error(const char *format, ...) 
 
3980
{
 
3981
  va_list args;
 
3982
 
 
3983
  va_start(args, format);
 
3984
  error_log_print(ERROR_LEVEL, format, args);
 
3985
  va_end(args);
 
3986
 
 
3987
  return;
 
3988
}
 
3989
 
 
3990
 
 
3991
void sql_print_warning(const char *format, ...) 
 
3992
{
 
3993
  va_list args;
 
3994
 
 
3995
  va_start(args, format);
 
3996
  error_log_print(WARNING_LEVEL, format, args);
 
3997
  va_end(args);
 
3998
 
 
3999
  return;
 
4000
}
 
4001
 
 
4002
 
 
4003
void sql_print_information(const char *format, ...) 
 
4004
{
 
4005
  va_list args;
 
4006
 
 
4007
  va_start(args, format);
 
4008
  error_log_print(INFORMATION_LEVEL, format, args);
 
4009
  va_end(args);
 
4010
 
 
4011
  return;
 
4012
}
 
4013
 
 
4014
 
 
4015
/********* transaction coordinator log for 2pc - mmap() based solution *******/
 
4016
 
 
4017
/*
 
4018
  the log consists of a file, mmapped to a memory.
 
4019
  file is divided on pages of tc_log_page_size size.
 
4020
  (usable size of the first page is smaller because of log header)
 
4021
  there's PAGE control structure for each page
 
4022
  each page (or rather PAGE control structure) can be in one of three
 
4023
  states - active, syncing, pool.
 
4024
  there could be only one page in active or syncing states,
 
4025
  but many in pool - pool is fifo queue.
 
4026
  usual lifecycle of a page is pool->active->syncing->pool
 
4027
  "active" page - is a page where new xid's are logged.
 
4028
  the page stays active as long as syncing slot is taken.
 
4029
  "syncing" page is being synced to disk. no new xid can be added to it.
 
4030
  when the sync is done the page is moved to a pool and an active page
 
4031
  becomes "syncing".
 
4032
 
 
4033
  the result of such an architecture is a natural "commit grouping" -
 
4034
  If commits are coming faster than the system can sync, they do not
 
4035
  stall. Instead, all commit that came since the last sync are
 
4036
  logged to the same page, and they all are synced with the next -
 
4037
  one - sync. Thus, thought individual commits are delayed, throughput
 
4038
  is not decreasing.
 
4039
 
 
4040
  when a xid is added to an active page, the thread of this xid waits
 
4041
  for a page's condition until the page is synced. when syncing slot
 
4042
  becomes vacant one of these waiters is awaken to take care of syncing.
 
4043
  it syncs the page and signals all waiters that the page is synced.
 
4044
  PAGE::waiters is used to count these waiters, and a page may never
 
4045
  become active again until waiters==0 (that is all waiters from the
 
4046
  previous sync have noticed the sync was completed)
 
4047
 
 
4048
  note, that the page becomes "dirty" and has to be synced only when a
 
4049
  new xid is added into it. Removing a xid from a page does not make it
 
4050
  dirty - we don't sync removals to disk.
 
4051
*/
 
4052
 
 
4053
ulong tc_log_page_waits= 0;
 
4054
 
 
4055
#ifdef HAVE_MMAP
 
4056
 
 
4057
#define TC_LOG_HEADER_SIZE (sizeof(tc_log_magic)+1)
 
4058
 
 
4059
static const char tc_log_magic[]={(char) 254, 0x23, 0x05, 0x74};
 
4060
 
 
4061
ulong opt_tc_log_size= TC_LOG_MIN_SIZE;
 
4062
ulong tc_log_max_pages_used=0, tc_log_page_size=0, tc_log_cur_pages_used=0;
 
4063
 
 
4064
int TC_LOG_MMAP::open(const char *opt_name)
 
4065
{
 
4066
  uint i;
 
4067
  bool crashed= false;
 
4068
  PAGE *pg;
 
4069
 
 
4070
  assert(total_ha_2pc > 1);
 
4071
  assert(opt_name && opt_name[0]);
 
4072
 
 
4073
  tc_log_page_size= my_getpagesize();
 
4074
  assert(TC_LOG_PAGE_SIZE % tc_log_page_size == 0);
 
4075
 
 
4076
  fn_format(logname,opt_name,mysql_data_home,"",MY_UNPACK_FILENAME);
 
4077
  if ((fd= my_open(logname, O_RDWR, MYF(0))) < 0)
 
4078
  {
 
4079
    if (my_errno != ENOENT)
 
4080
      goto err;
 
4081
    if (using_heuristic_recover())
 
4082
      return 1;
 
4083
    if ((fd= my_create(logname, CREATE_MODE, O_RDWR, MYF(MY_WME))) < 0)
 
4084
      goto err;
 
4085
    inited=1;
 
4086
    file_length= opt_tc_log_size;
 
4087
    if (ftruncate(fd, file_length))
 
4088
      goto err;
 
4089
  }
 
4090
  else
 
4091
  {
 
4092
    inited= 1;
 
4093
    crashed= true;
 
4094
    sql_print_information("Recovering after a crash using %s", opt_name);
 
4095
    if (tc_heuristic_recover)
 
4096
    {
 
4097
      sql_print_error("Cannot perform automatic crash recovery when "
 
4098
                      "--tc-heuristic-recover is used");
 
4099
      goto err;
 
4100
    }
 
4101
    file_length= my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE));
 
4102
    if (file_length == MY_FILEPOS_ERROR || file_length % tc_log_page_size)
 
4103
      goto err;
 
4104
  }
 
4105
 
 
4106
  data= (uchar *)my_mmap(0, (size_t)file_length, PROT_READ|PROT_WRITE,
 
4107
                        MAP_NOSYNC|MAP_SHARED, fd, 0);
 
4108
  if (data == MAP_FAILED)
 
4109
  {
 
4110
    my_errno=errno;
 
4111
    goto err;
 
4112
  }
 
4113
  inited=2;
 
4114
 
 
4115
  npages=(uint)file_length/tc_log_page_size;
 
4116
  assert(npages >= 3);             // to guarantee non-empty pool
 
4117
  if (!(pages=(PAGE *)my_malloc(npages*sizeof(PAGE), MYF(MY_WME|MY_ZEROFILL))))
 
4118
    goto err;
 
4119
  inited=3;
 
4120
  for (pg=pages, i=0; i < npages; i++, pg++)
 
4121
  {
 
4122
    pg->next=pg+1;
 
4123
    pg->waiters=0;
 
4124
    pg->state=POOL;
 
4125
    pthread_mutex_init(&pg->lock, MY_MUTEX_INIT_FAST);
 
4126
    pthread_cond_init (&pg->cond, 0);
 
4127
    pg->start=(my_xid *)(data + i*tc_log_page_size);
 
4128
    pg->ptr=pg->start;
 
4129
    pg->end=(my_xid *)(pg->start + tc_log_page_size);
 
4130
    pg->size=pg->free=tc_log_page_size/sizeof(my_xid);
 
4131
  }
 
4132
  pages[0].size=pages[0].free=
 
4133
                (tc_log_page_size-TC_LOG_HEADER_SIZE)/sizeof(my_xid);
 
4134
  pages[0].start=pages[0].end-pages[0].size;
 
4135
  pages[npages-1].next=0;
 
4136
  inited=4;
 
4137
 
 
4138
  if (crashed && recover())
 
4139
      goto err;
 
4140
 
 
4141
  memcpy(data, tc_log_magic, sizeof(tc_log_magic));
 
4142
  data[sizeof(tc_log_magic)]= (uchar)total_ha_2pc;
 
4143
  msync(data, tc_log_page_size, MS_SYNC);
 
4144
  my_sync(fd, MYF(0));
 
4145
  inited=5;
 
4146
 
 
4147
  pthread_mutex_init(&LOCK_sync,    MY_MUTEX_INIT_FAST);
 
4148
  pthread_mutex_init(&LOCK_active,  MY_MUTEX_INIT_FAST);
 
4149
  pthread_mutex_init(&LOCK_pool,    MY_MUTEX_INIT_FAST);
 
4150
  pthread_cond_init(&COND_active, 0);
 
4151
  pthread_cond_init(&COND_pool, 0);
 
4152
 
 
4153
  inited=6;
 
4154
 
 
4155
  syncing= 0;
 
4156
  active=pages;
 
4157
  pool=pages+1;
 
4158
  pool_last=pages+npages-1;
 
4159
 
 
4160
  return 0;
 
4161
 
 
4162
err:
 
4163
  close();
 
4164
  return 1;
 
4165
}
 
4166
 
 
4167
/**
 
4168
  there is no active page, let's got one from the pool.
 
4169
 
 
4170
  Two strategies here:
 
4171
    -# take the first from the pool
 
4172
    -# if there're waiters - take the one with the most free space.
 
4173
 
 
4174
  @todo
 
4175
    TODO page merging. try to allocate adjacent page first,
 
4176
    so that they can be flushed both in one sync
 
4177
*/
 
4178
 
 
4179
void TC_LOG_MMAP::get_active_from_pool()
 
4180
{
 
4181
  PAGE **p, **best_p=0;
 
4182
  int best_free;
 
4183
 
 
4184
  if (syncing)
 
4185
    pthread_mutex_lock(&LOCK_pool);
 
4186
 
 
4187
  do
 
4188
  {
 
4189
    best_p= p= &pool;
 
4190
    if ((*p)->waiters == 0) // can the first page be used ?
 
4191
      break;                // yes - take it.
 
4192
 
 
4193
    best_free=0;            // no - trying second strategy
 
4194
    for (p=&(*p)->next; *p; p=&(*p)->next)
 
4195
    {
 
4196
      if ((*p)->waiters == 0 && (*p)->free > best_free)
 
4197
      {
 
4198
        best_free=(*p)->free;
 
4199
        best_p=p;
 
4200
      }
 
4201
    }
 
4202
  }
 
4203
  while ((*best_p == 0 || best_free == 0) && overflow());
 
4204
 
 
4205
  active=*best_p;
 
4206
  if (active->free == active->size) // we've chosen an empty page
 
4207
  {
 
4208
    tc_log_cur_pages_used++;
 
4209
    set_if_bigger(tc_log_max_pages_used, tc_log_cur_pages_used);
 
4210
  }
 
4211
 
 
4212
  if ((*best_p)->next)              // unlink the page from the pool
 
4213
    *best_p=(*best_p)->next;
 
4214
  else
 
4215
    pool_last=*best_p;
 
4216
 
 
4217
  if (syncing)
 
4218
    pthread_mutex_unlock(&LOCK_pool);
 
4219
}
 
4220
 
 
4221
/**
 
4222
  @todo
 
4223
  perhaps, increase log size ?
 
4224
*/
 
4225
int TC_LOG_MMAP::overflow()
 
4226
{
 
4227
  /*
 
4228
    simple overflow handling - just wait
 
4229
    TODO perhaps, increase log size ?
 
4230
    let's check the behaviour of tc_log_page_waits first
 
4231
  */
 
4232
  tc_log_page_waits++;
 
4233
  pthread_cond_wait(&COND_pool, &LOCK_pool);
 
4234
  return 1; // always return 1
 
4235
}
 
4236
 
 
4237
/**
 
4238
  Record that transaction XID is committed on the persistent storage.
 
4239
 
 
4240
    This function is called in the middle of two-phase commit:
 
4241
    First all resources prepare the transaction, then tc_log->log() is called,
 
4242
    then all resources commit the transaction, then tc_log->unlog() is called.
 
4243
 
 
4244
    All access to active page is serialized but it's not a problem, as
 
4245
    we're assuming that fsync() will be a main bottleneck.
 
4246
    That is, parallelizing writes to log pages we'll decrease number of
 
4247
    threads waiting for a page, but then all these threads will be waiting
 
4248
    for a fsync() anyway
 
4249
 
 
4250
   If tc_log == MYSQL_LOG then tc_log writes transaction to binlog and
 
4251
   records XID in a special Xid_log_event.
 
4252
   If tc_log = TC_LOG_MMAP then xid is written in a special memory-mapped
 
4253
   log.
 
4254
 
 
4255
  @retval
 
4256
    0  - error
 
4257
  @retval
 
4258
    \# - otherwise, "cookie", a number that will be passed as an argument
 
4259
    to unlog() call. tc_log can define it any way it wants,
 
4260
    and use for whatever purposes. TC_LOG_MMAP sets it
 
4261
    to the position in memory where xid was logged to.
 
4262
*/
 
4263
 
 
4264
int TC_LOG_MMAP::log_xid(THD *thd __attribute__((__unused__)), my_xid xid)
 
4265
{
 
4266
  int err;
 
4267
  PAGE *p;
 
4268
  ulong cookie;
 
4269
 
 
4270
  pthread_mutex_lock(&LOCK_active);
 
4271
 
 
4272
  /*
 
4273
    if active page is full - just wait...
 
4274
    frankly speaking, active->free here accessed outside of mutex
 
4275
    protection, but it's safe, because it only means we may miss an
 
4276
    unlog() for the active page, and we're not waiting for it here -
 
4277
    unlog() does not signal COND_active.
 
4278
  */
 
4279
  while (unlikely(active && active->free == 0))
 
4280
    pthread_cond_wait(&COND_active, &LOCK_active);
 
4281
 
 
4282
  /* no active page ? take one from the pool */
 
4283
  if (active == 0)
 
4284
    get_active_from_pool();
 
4285
 
 
4286
  p=active;
 
4287
  pthread_mutex_lock(&p->lock);
 
4288
 
 
4289
  /* searching for an empty slot */
 
4290
  while (*p->ptr)
 
4291
  {
 
4292
    p->ptr++;
 
4293
    assert(p->ptr < p->end);               // because p->free > 0
 
4294
  }
 
4295
 
 
4296
  /* found! store xid there and mark the page dirty */
 
4297
  cookie= (ulong)((uchar *)p->ptr - data);      // can never be zero
 
4298
  *p->ptr++= xid;
 
4299
  p->free--;
 
4300
  p->state= DIRTY;
 
4301
 
 
4302
  /* to sync or not to sync - this is the question */
 
4303
  pthread_mutex_unlock(&LOCK_active);
 
4304
  pthread_mutex_lock(&LOCK_sync);
 
4305
  pthread_mutex_unlock(&p->lock);
 
4306
 
 
4307
  if (syncing)
 
4308
  {                                          // somebody's syncing. let's wait
 
4309
    p->waiters++;
 
4310
    /*
 
4311
      note - it must be while (), not do ... while () here
 
4312
      as p->state may be not DIRTY when we come here
 
4313
    */
 
4314
    while (p->state == DIRTY && syncing)
 
4315
      pthread_cond_wait(&p->cond, &LOCK_sync);
 
4316
    p->waiters--;
 
4317
    err= p->state == ERROR;
 
4318
    if (p->state != DIRTY)                   // page was synced
 
4319
    {
 
4320
      if (p->waiters == 0)
 
4321
        pthread_cond_signal(&COND_pool);     // in case somebody's waiting
 
4322
      pthread_mutex_unlock(&LOCK_sync);
 
4323
      goto done;                             // we're done
 
4324
    }
 
4325
  }                                          // page was not synced! do it now
 
4326
  assert(active == p && syncing == 0);
 
4327
  pthread_mutex_lock(&LOCK_active);
 
4328
  syncing=p;                                 // place is vacant - take it
 
4329
  active=0;                                  // page is not active anymore
 
4330
  pthread_cond_broadcast(&COND_active);      // in case somebody's waiting
 
4331
  pthread_mutex_unlock(&LOCK_active);
 
4332
  pthread_mutex_unlock(&LOCK_sync);
 
4333
  err= sync();
 
4334
 
 
4335
done:
 
4336
  return err ? 0 : cookie;
 
4337
}
 
4338
 
 
4339
int TC_LOG_MMAP::sync()
 
4340
{
 
4341
  int err;
 
4342
 
 
4343
  assert(syncing != active);
 
4344
 
 
4345
  /*
 
4346
    sit down and relax - this can take a while...
 
4347
    note - no locks are held at this point
 
4348
  */
 
4349
  err= msync(syncing->start, 1, MS_SYNC);
 
4350
  if(err==0)
 
4351
    err= my_sync(fd, MYF(0));
 
4352
 
 
4353
  /* page is synced. let's move it to the pool */
 
4354
  pthread_mutex_lock(&LOCK_pool);
 
4355
  pool_last->next=syncing;
 
4356
  pool_last=syncing;
 
4357
  syncing->next=0;
 
4358
  syncing->state= err ? ERROR : POOL;
 
4359
  pthread_cond_broadcast(&syncing->cond);    // signal "sync done"
 
4360
  pthread_cond_signal(&COND_pool);           // in case somebody's waiting
 
4361
  pthread_mutex_unlock(&LOCK_pool);
 
4362
 
 
4363
  /* marking 'syncing' slot free */
 
4364
  pthread_mutex_lock(&LOCK_sync);
 
4365
  syncing=0;
 
4366
  pthread_cond_signal(&active->cond);        // wake up a new syncer
 
4367
  pthread_mutex_unlock(&LOCK_sync);
 
4368
  return err;
 
4369
}
 
4370
 
 
4371
/**
 
4372
  erase xid from the page, update page free space counters/pointers.
 
4373
  cookie points directly to the memory where xid was logged.
 
4374
*/
 
4375
 
 
4376
void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid __attribute__((__unused__)))
 
4377
{
 
4378
  PAGE *p=pages+(cookie/tc_log_page_size);
 
4379
  my_xid *x=(my_xid *)(data+cookie);
 
4380
 
 
4381
  assert(*x == xid);
 
4382
  assert(x >= p->start && x < p->end);
 
4383
  *x=0;
 
4384
 
 
4385
  pthread_mutex_lock(&p->lock);
 
4386
  p->free++;
 
4387
  assert(p->free <= p->size);
 
4388
  set_if_smaller(p->ptr, x);
 
4389
  if (p->free == p->size)               // the page is completely empty
 
4390
    statistic_decrement(tc_log_cur_pages_used, &LOCK_status);
 
4391
  if (p->waiters == 0)                 // the page is in pool and ready to rock
 
4392
    pthread_cond_signal(&COND_pool);   // ping ... for overflow()
 
4393
  pthread_mutex_unlock(&p->lock);
 
4394
}
 
4395
 
 
4396
void TC_LOG_MMAP::close()
 
4397
{
 
4398
  uint i;
 
4399
  switch (inited) {
 
4400
  case 6:
 
4401
    pthread_mutex_destroy(&LOCK_sync);
 
4402
    pthread_mutex_destroy(&LOCK_active);
 
4403
    pthread_mutex_destroy(&LOCK_pool);
 
4404
    pthread_cond_destroy(&COND_pool);
 
4405
  case 5:
 
4406
    data[0]='A'; // garble the first (signature) byte, in case my_delete fails
 
4407
  case 4:
 
4408
    for (i=0; i < npages; i++)
 
4409
    {
 
4410
      if (pages[i].ptr == 0)
 
4411
        break;
 
4412
      pthread_mutex_destroy(&pages[i].lock);
 
4413
      pthread_cond_destroy(&pages[i].cond);
 
4414
    }
 
4415
  case 3:
 
4416
    my_free((uchar*)pages, MYF(0));
 
4417
  case 2:
 
4418
    my_munmap((char*)data, (size_t)file_length);
 
4419
  case 1:
 
4420
    my_close(fd, MYF(0));
 
4421
  }
 
4422
  if (inited>=5) // cannot do in the switch because of Windows
 
4423
    my_delete(logname, MYF(MY_WME));
 
4424
  inited=0;
 
4425
}
 
4426
 
 
4427
int TC_LOG_MMAP::recover()
 
4428
{
 
4429
  HASH xids;
 
4430
  PAGE *p=pages, *end_p=pages+npages;
 
4431
 
 
4432
  if (memcmp(data, tc_log_magic, sizeof(tc_log_magic)))
 
4433
  {
 
4434
    sql_print_error("Bad magic header in tc log");
 
4435
    goto err1;
 
4436
  }
 
4437
 
 
4438
  /*
 
4439
    the first byte after magic signature is set to current
 
4440
    number of storage engines on startup
 
4441
  */
 
4442
  if (data[sizeof(tc_log_magic)] != total_ha_2pc)
 
4443
  {
 
4444
    sql_print_error("Recovery failed! You must enable "
 
4445
                    "exactly %d storage engines that support "
 
4446
                    "two-phase commit protocol",
 
4447
                    data[sizeof(tc_log_magic)]);
 
4448
    goto err1;
 
4449
  }
 
4450
 
 
4451
  if (hash_init(&xids, &my_charset_bin, tc_log_page_size/3, 0,
 
4452
                sizeof(my_xid), 0, 0, MYF(0)))
 
4453
    goto err1;
 
4454
 
 
4455
  for ( ; p < end_p ; p++)
 
4456
  {
 
4457
    for (my_xid *x=p->start; x < p->end; x++)
 
4458
      if (*x && my_hash_insert(&xids, (uchar *)x))
 
4459
        goto err2; // OOM
 
4460
  }
 
4461
 
 
4462
  if (ha_recover(&xids))
 
4463
    goto err2;
 
4464
 
 
4465
  hash_free(&xids);
 
4466
  bzero(data, (size_t)file_length);
 
4467
  return 0;
 
4468
 
 
4469
err2:
 
4470
  hash_free(&xids);
 
4471
err1:
 
4472
  sql_print_error("Crash recovery failed. Either correct the problem "
 
4473
                  "(if it's, for example, out of memory error) and restart, "
 
4474
                  "or delete tc log and start mysqld with "
 
4475
                  "--tc-heuristic-recover={commit|rollback}");
 
4476
  return 1;
 
4477
}
 
4478
#endif
 
4479
 
 
4480
TC_LOG *tc_log;
 
4481
TC_LOG_DUMMY tc_log_dummy;
 
4482
TC_LOG_MMAP  tc_log_mmap;
 
4483
 
 
4484
/**
 
4485
  Perform heuristic recovery, if --tc-heuristic-recover was used.
 
4486
 
 
4487
  @note
 
4488
    no matter whether heuristic recovery was successful or not
 
4489
    mysqld must exit. So, return value is the same in both cases.
 
4490
 
 
4491
  @retval
 
4492
    0   no heuristic recovery was requested
 
4493
  @retval
 
4494
    1   heuristic recovery was performed
 
4495
*/
 
4496
 
 
4497
int TC_LOG::using_heuristic_recover()
 
4498
{
 
4499
  if (!tc_heuristic_recover)
 
4500
    return 0;
 
4501
 
 
4502
  sql_print_information("Heuristic crash recovery mode");
 
4503
  if (ha_recover(0))
 
4504
    sql_print_error("Heuristic crash recovery failed");
 
4505
  sql_print_information("Please restart mysqld without --tc-heuristic-recover");
 
4506
  return 1;
 
4507
}
 
4508
 
 
4509
/****** transaction coordinator log for 2pc - binlog() based solution ******/
 
4510
#define TC_LOG_BINLOG MYSQL_BIN_LOG
 
4511
 
 
4512
/**
 
4513
  @todo
 
4514
  keep in-memory list of prepared transactions
 
4515
  (add to list in log(), remove on unlog())
 
4516
  and copy it to the new binlog if rotated
 
4517
  but let's check the behaviour of tc_log_page_waits first!
 
4518
*/
 
4519
 
 
4520
int TC_LOG_BINLOG::open(const char *opt_name)
 
4521
{
 
4522
  LOG_INFO log_info;
 
4523
  int      error= 1;
 
4524
 
 
4525
  assert(total_ha_2pc > 1);
 
4526
  assert(opt_name && opt_name[0]);
 
4527
 
 
4528
  pthread_mutex_init(&LOCK_prep_xids, MY_MUTEX_INIT_FAST);
 
4529
  pthread_cond_init (&COND_prep_xids, 0);
 
4530
 
 
4531
  if (!my_b_inited(&index_file))
 
4532
  {
 
4533
    /* There was a failure to open the index file, can't open the binlog */
 
4534
    cleanup();
 
4535
    return 1;
 
4536
  }
 
4537
 
 
4538
  if (using_heuristic_recover())
 
4539
  {
 
4540
    /* generate a new binlog to mask a corrupted one */
 
4541
    open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0);
 
4542
    cleanup();
 
4543
    return 1;
 
4544
  }
 
4545
 
 
4546
  if ((error= find_log_pos(&log_info, NullS, 1)))
 
4547
  {
 
4548
    if (error != LOG_INFO_EOF)
 
4549
      sql_print_error("find_log_pos() failed (error: %d)", error);
 
4550
    else
 
4551
      error= 0;
 
4552
    goto err;
 
4553
  }
 
4554
 
 
4555
  {
 
4556
    const char *errmsg;
 
4557
    IO_CACHE    log;
 
4558
    File        file;
 
4559
    Log_event  *ev=0;
 
4560
    Format_description_log_event fdle(BINLOG_VERSION);
 
4561
    char        log_name[FN_REFLEN];
 
4562
 
 
4563
    if (! fdle.is_valid())
 
4564
      goto err;
 
4565
 
 
4566
    do
 
4567
    {
 
4568
      strmake(log_name, log_info.log_file_name, sizeof(log_name)-1);
 
4569
    } while (!(error= find_next_log(&log_info, 1)));
 
4570
 
 
4571
    if (error !=  LOG_INFO_EOF)
 
4572
    {
 
4573
      sql_print_error("find_log_pos() failed (error: %d)", error);
 
4574
      goto err;
 
4575
    }
 
4576
 
 
4577
    if ((file= open_binlog(&log, log_name, &errmsg)) < 0)
 
4578
    {
 
4579
      sql_print_error("%s", errmsg);
 
4580
      goto err;
 
4581
    }
 
4582
 
 
4583
    if ((ev= Log_event::read_log_event(&log, 0, &fdle)) &&
 
4584
        ev->get_type_code() == FORMAT_DESCRIPTION_EVENT &&
 
4585
        ev->flags & LOG_EVENT_BINLOG_IN_USE_F)
 
4586
    {
 
4587
      sql_print_information("Recovering after a crash using %s", opt_name);
 
4588
      error= recover(&log, (Format_description_log_event *)ev);
 
4589
    }
 
4590
    else
 
4591
      error=0;
 
4592
 
 
4593
    delete ev;
 
4594
    end_io_cache(&log);
 
4595
    my_close(file, MYF(MY_WME));
 
4596
 
 
4597
    if (error)
 
4598
      goto err;
 
4599
  }
 
4600
 
 
4601
err:
 
4602
  return error;
 
4603
}
 
4604
 
 
4605
/** This is called on shutdown, after ha_panic. */
 
4606
void TC_LOG_BINLOG::close()
 
4607
{
 
4608
  assert(prepared_xids==0);
 
4609
  pthread_mutex_destroy(&LOCK_prep_xids);
 
4610
  pthread_cond_destroy (&COND_prep_xids);
 
4611
}
 
4612
 
 
4613
/**
 
4614
  @todo
 
4615
  group commit
 
4616
 
 
4617
  @retval
 
4618
    0    error
 
4619
  @retval
 
4620
    1    success
 
4621
*/
 
4622
int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid)
 
4623
{
 
4624
  Xid_log_event xle(thd, xid);
 
4625
  binlog_trx_data *trx_data=
 
4626
    (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
 
4627
  /*
 
4628
    We always commit the entire transaction when writing an XID. Also
 
4629
    note that the return value is inverted.
 
4630
   */
 
4631
  return(!binlog_end_trans(thd, trx_data, &xle, true));
 
4632
}
 
4633
 
 
4634
void TC_LOG_BINLOG::unlog(ulong cookie __attribute__((__unused__)),
 
4635
                          my_xid xid __attribute__((__unused__)))
 
4636
{
 
4637
  pthread_mutex_lock(&LOCK_prep_xids);
 
4638
  assert(prepared_xids > 0);
 
4639
  if (--prepared_xids == 0) {
 
4640
    pthread_cond_signal(&COND_prep_xids);
 
4641
  }
 
4642
  pthread_mutex_unlock(&LOCK_prep_xids);
 
4643
  rotate_and_purge(0);     // as ::write() did not rotate
 
4644
}
 
4645
 
 
4646
int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
 
4647
{
 
4648
  Log_event  *ev;
 
4649
  HASH xids;
 
4650
  MEM_ROOT mem_root;
 
4651
 
 
4652
  if (! fdle->is_valid() ||
 
4653
      hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
 
4654
                sizeof(my_xid), 0, 0, MYF(0)))
 
4655
    goto err1;
 
4656
 
 
4657
  init_alloc_root(&mem_root, TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE);
 
4658
 
 
4659
  fdle->flags&= ~LOG_EVENT_BINLOG_IN_USE_F; // abort on the first error
 
4660
 
 
4661
  while ((ev= Log_event::read_log_event(log,0,fdle)) && ev->is_valid())
 
4662
  {
 
4663
    if (ev->get_type_code() == XID_EVENT)
 
4664
    {
 
4665
      Xid_log_event *xev=(Xid_log_event *)ev;
 
4666
      uchar *x= (uchar *) memdup_root(&mem_root, (uchar*) &xev->xid,
 
4667
                                      sizeof(xev->xid));
 
4668
      if (! x)
 
4669
        goto err2;
 
4670
      my_hash_insert(&xids, x);
 
4671
    }
 
4672
    delete ev;
 
4673
  }
 
4674
 
 
4675
  if (ha_recover(&xids))
 
4676
    goto err2;
 
4677
 
 
4678
  free_root(&mem_root, MYF(0));
 
4679
  hash_free(&xids);
 
4680
  return 0;
 
4681
 
 
4682
err2:
 
4683
  free_root(&mem_root, MYF(0));
 
4684
  hash_free(&xids);
 
4685
err1:
 
4686
  sql_print_error("Crash recovery failed. Either correct the problem "
 
4687
                  "(if it's, for example, out of memory error) and restart, "
 
4688
                  "or delete (or rename) binary log and start mysqld with "
 
4689
                  "--tc-heuristic-recover={commit|rollback}");
 
4690
  return 1;
 
4691
}
 
4692
 
 
4693
 
 
4694
#ifdef INNODB_COMPATIBILITY_HOOKS
 
4695
/**
 
4696
  Get the file name of the MySQL binlog.
 
4697
  @return the name of the binlog file
 
4698
*/
 
4699
extern "C"
 
4700
const char* mysql_bin_log_file_name(void)
 
4701
{
 
4702
  return mysql_bin_log.get_log_fname();
 
4703
}
 
4704
/**
 
4705
  Get the current position of the MySQL binlog.
 
4706
  @return byte offset from the beginning of the binlog
 
4707
*/
 
4708
extern "C"
 
4709
ulonglong mysql_bin_log_file_pos(void)
 
4710
{
 
4711
  return (ulonglong) mysql_bin_log.get_log_file()->pos_in_file;
 
4712
}
 
4713
#endif /* INNODB_COMPATIBILITY_HOOKS */
 
4714
 
 
4715
 
 
4716
struct st_mysql_storage_engine binlog_storage_engine=
 
4717
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
 
4718
 
 
4719
mysql_declare_plugin(binlog)
 
4720
{
 
4721
  MYSQL_STORAGE_ENGINE_PLUGIN,
 
4722
  &binlog_storage_engine,
 
4723
  "binlog",
 
4724
  "MySQL AB",
 
4725
  "This is a pseudo storage engine to represent the binlog in a transaction",
 
4726
  PLUGIN_LICENSE_GPL,
 
4727
  binlog_init, /* Plugin Init */
 
4728
  NULL, /* Plugin Deinit */
 
4729
  0x0100 /* 1.0 */,
 
4730
  NULL,                       /* status variables                */
 
4731
  NULL,                       /* system variables                */
 
4732
  NULL                        /* config options                  */
 
4733
}
 
4734
mysql_declare_plugin_end;