~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/log.cc

  • Committer: Mark Atwood
  • Date: 2011-12-28 02:50:31 UTC
  • Revision ID: me@mark.atwood.name-20111228025031-eh4h1zwv4ig88g0i
fix tests/r/basic.result

Show diffs side-by-side

added added

removed removed

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