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