~drizzle-trunk/drizzle/development

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