1
/* Copyright (C) 2000-2003 MySQL AB
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.
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.
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 */
24
Abort logging when we get an error in reading or writing log files
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>
33
#include <mysys/my_dir.h>
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>
42
#include <drizzled/errmsg.h>
44
/* max size of the log message */
45
#define MY_OFF_T_UNDEF (~(my_off_t)0UL)
49
DRIZZLE_BIN_LOG drizzle_bin_log;
50
uint64_t sync_binlog_counter= 0; /* We should rationalize the largest possible counters for binlog sync */
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);
63
sql_print_message_func sql_print_message_handlers[3] =
65
sql_print_information,
71
char *make_default_log_name(char *buff,const char* log_ext)
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));
79
Helper class to hold a mutex for the duration of the
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
89
Mutex_sentry(pthread_mutex_t *mutex)
93
pthread_mutex_lock(mutex);
99
pthread_mutex_unlock(m_mutex);
104
pthread_mutex_t *m_mutex;
106
// It's not allowed to copy this object in any way
107
Mutex_sentry(Mutex_sentry const&);
108
void operator=(Mutex_sentry const&);
112
Helper class to store binary log transaction data.
114
class binlog_trx_data {
117
: at_least_one_stmt(0), m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF)
119
trans_log.end_of_file= max_binlog_cache_size;
124
assert(pending() == NULL);
125
close_cached_file(&trans_log);
128
my_off_t position() const {
129
return my_b_tell(&trans_log);
134
return pending() == NULL && my_b_tell(&trans_log) == 0;
138
Truncate the transaction cache to a certain position. This
139
includes deleting the pending event.
141
void truncate(my_off_t pos)
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;
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.
157
at_least_one_stmt= (pos > 0);
161
Reset the entire contents of the transaction cache, emptying it
167
before_stmt_pos= MY_OFF_T_UNDEF;
168
trans_log.end_of_file= max_binlog_cache_size;
171
Rows_log_event *pending() const
176
void set_pending(Rows_log_event *const pending)
181
IO_CACHE trans_log; // The transaction cache
184
Boolean that is true if there is at least one statement in the
187
bool at_least_one_stmt;
191
Pending binrows event. This event is the event where the rows are
194
Rows_log_event *m_pending;
198
Binlog position before the start of the current statement.
200
my_off_t before_stmt_pos;
203
handlerton *binlog_hton;
207
Log error with all enabled log event handlers
212
level The level of the error significance: NOTE,
214
format format string for the error message
215
args list of arguments for the format string
222
bool LOGGER::error_log_print(enum loglevel level, const char *format,
226
Log_event_handler **current_handler;
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;
236
void LOGGER::cleanup_base()
239
rwlock_destroy(&LOCK_logger);
243
void LOGGER::cleanup_end()
250
Perform basic log initialization: create file-based log handler and
253
void LOGGER::init_base()
258
/* by default we use traditional error log */
259
init_error_log(LOG_FILE);
261
my_rwlock_init(&LOCK_logger, NULL);
265
bool LOGGER::flush_logs(Session *)
270
Now we lock logger, as nobody should be able to use logging routines while
271
log tables are closed
273
logger.lock_exclusive();
275
/* end of log flush */
280
void LOGGER::init_error_log(uint32_t error_log_printer)
282
if (error_log_printer & LOG_NONE)
284
error_log_handler_list[0]= 0;
290
int LOGGER::set_handlers(uint32_t error_log_printer)
292
/* error log table is not supported yet */
295
init_error_log(error_log_printer);
303
Save position of binary log transaction cache.
306
binlog_trans_log_savepos()
308
session The thread to take the binlog data from
309
pos Pointer to variable where the position will be stored
313
Save the current position in the binary log transaction cache into
314
the variable pointed to by 'pos'
318
binlog_trans_log_savepos(Session *session, my_off_t *pos)
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();
332
Truncate the binary log transaction cache.
335
binlog_trans_log_truncate()
337
session The thread to take the binlog data from
338
pos Position to truncate to
342
Truncate the binary log to the given position. Will not change
347
binlog_trans_log_truncate(Session *session, my_off_t pos)
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);
353
binlog_trx_data *const trx_data=
354
(binlog_trx_data*) session_get_ha_data(session, binlog_hton);
355
trx_data->truncate(pos);
361
this function is mostly a placeholder.
362
conceptually, binlog initialization (now mostly done in DRIZZLE_BIN_LOG::open)
363
should be moved here.
366
int binlog_init(void *p)
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;
382
static int binlog_close_connection(handlerton *, Session *session)
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);
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.
407
End the currently open transaction. The transaction can be either
408
a real transaction (if 'all' is true) or a statement transaction
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).
417
binlog_end_trans(Session *session, binlog_trx_data *trx_data,
418
Log_event *end_ev, bool all)
421
IO_CACHE *trans_log= &trx_data->trans_log;
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
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.
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.
441
session->binlog_flush_pending_rows_event(true);
443
error= drizzle_bin_log.write(session, &trx_data->trans_log, end_ev);
447
We need to step the table map version after writing the
448
transaction cache to disk.
450
drizzle_bin_log.update_table_map_version();
451
statistic_increment(binlog_cache_use, &LOCK_status);
452
if (trans_log->disk_writes != 0)
454
statistic_increment(binlog_cache_disk_use, &LOCK_status);
455
trans_log->disk_writes= 0;
461
If rolling back an entire transaction or a single statement not
462
inside a transaction, we reset the transaction cache.
464
If rolling back a statement in a transaction, we truncate the
465
transaction cache to remove the statement.
467
if (all || !(session->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT)))
471
assert(!session->binlog_get_pending_rows_event());
472
session->clear_binlog_table_maps();
475
trx_data->truncate(trx_data->before_stmt_pos);
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.
482
drizzle_bin_log.update_table_map_version();
488
static int binlog_prepare(handlerton *, Session *, bool)
492
just pretend we can do 2pc, so that MySQL won't
494
real work will be done in DRIZZLE_BIN_LOG::log_xid()
500
This function is called once after each statement.
502
It has the responsibility to flush the transaction cache to the
503
binlog file on commits.
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
510
@see handlerton::commit
512
static int binlog_commit(handlerton *, Session *session, bool all)
514
binlog_trx_data *const trx_data=
515
(binlog_trx_data*) session_get_ha_data(session, binlog_hton);
517
if (trx_data->empty())
519
// we're here because trans_log was flushed in DRIZZLE_BIN_LOG::log_xid()
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
530
Real transaction 'all' was true
532
Statement in cache There were at least one statement in the
535
In transaction We are inside a transaction
537
Stmt modified non-trans The statement being committed modified a
538
non-transactional table
540
All modified non-trans Some statement before this one in the
541
transaction modified a non-transactional
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
552
Action: (C)ommit/(A)ccumulate C C - C A C - C - - - - A A - A
553
============================= = = = = = = = = = = = = = = = =
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
563
(C)ommit/(A)ccumulate/(-) - - - - C C - C - - - - C C - C
564
============================= = = = = = = = = = = = = = = = =
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
570
- We are in a transaction and one (or more) of the following are
573
- A full transaction is committed
577
- A non-transactional statement is committed and there is
580
Otherwise, we accumulate the statement
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))
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);
595
This function is called when a transaction involving a transactional
596
table is rolled back.
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.
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
607
@see handlerton::rollback
609
static int binlog_rollback(handlerton *, Session *session, bool all)
612
binlog_trx_data *const trx_data=
613
(binlog_trx_data*) session_get_ha_data(session, binlog_hton);
615
if (trx_data->empty()) {
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))
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.
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);
636
else if ((all && !session->transaction.all.modified_non_trans_table) ||
637
(!all && !session->transaction.stmt.modified_non_trans_table))
640
If we have modified only transactional tables, we can truncate
641
the transaction cache without writing anything to the binary
644
error= binlog_end_trans(session, trx_data, 0, all);
651
How do we handle this (unlikely but legal) case:
653
[transaction] + [update to non-trans table] + [rollback to savepoint] ?
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).
673
static int binlog_savepoint_set(handlerton *, Session *session, void *sv)
675
binlog_trans_log_savepos(session, (my_off_t*) sv);
676
/* Write it to the binary log */
679
session->binlog_query(Session::STMT_QUERY_TYPE,
680
session->query, session->query_length, true, false);
684
static int binlog_savepoint_rollback(handlerton *, Session *session, void *sv)
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.
691
if (unlikely(session->transaction.all.modified_non_trans_table ||
692
(session->options & OPTION_KEEP_LOG)))
695
session->binlog_query(Session::STMT_QUERY_TYPE,
696
session->query, session->query_length, true, false);
699
binlog_trans_log_truncate(session, *(my_off_t*)sv);
704
int check_binlog_magic(IO_CACHE* log, const char** errmsg)
707
assert(my_b_tell(log) == 0);
709
if (my_b_read(log, (unsigned char*) magic, sizeof(magic)))
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,
716
if (memcmp(magic, BINLOG_MAGIC, sizeof(magic)))
718
*errmsg = _("Binlog has bad magic number; It's not a binary log file "
719
"that can be used by this version of Drizzle");
726
File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg)
730
if ((file = my_open(log_file_name, O_RDONLY,
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");
738
if (init_io_cache(log, file, IO_SIZE*2, READ_CACHE, 0, 0,
739
MYF(MY_WME|MY_DONT_CHECK_FILESIZE)))
741
sql_print_error(_("Failed to create a cache on log (file '%s')"),
743
*errmsg = _("Could not open log file");
746
if (check_binlog_magic(log,errmsg))
753
my_close(file,MYF(0));
761
Find a unique filename for 'filename.#'.
763
Set '#' to a number as low as possible.
766
nonzero if not possible to get unique filename
769
static int find_uniq_filename(char *name)
773
char buff[FN_REFLEN];
774
struct st_my_dir *dir_info;
775
register struct fileinfo *file_info;
777
size_t buf_length, length;
780
length= dirname_part(buff, name, &buf_length);
781
start= name + length;
782
end= strchr(start, '\0');
785
length= (size_t) (end-start+1);
787
if (!(dir_info = my_dir(buff,MYF(MY_DONT_SORT))))
788
{ // This shouldn't happen
789
my_stpcpy(end,".1"); // use name+1
792
file_info= dir_info->dir_entry;
793
for (i=dir_info->number_off_files ; i-- ; file_info++)
795
if (memcmp(file_info->name, start, length) == 0 &&
796
test_if_number(file_info->name+length, &number,0))
798
set_if_bigger(max_found,(ulong) number);
804
sprintf(end,"%06ld",max_found+1);
809
void DRIZZLE_LOG::init(enum_log_type log_type_arg,
810
enum cache_type io_cache_type_arg)
812
log_type= log_type_arg;
813
io_cache_type= io_cache_type_arg;
819
Open a (new) log file.
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
831
Open the logfile, init IO_CACHE and write startup messages
832
(in case of general and slow query logs).
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)
842
char buff[FN_REFLEN];
844
int open_flags= O_CREAT;
848
init(log_type_arg, io_cache_type_arg);
850
if (!(name= my_strdup(log_name, MYF(MY_WME))))
852
name= (char *)log_name; // for the error message
857
my_stpcpy(log_file_name, new_name);
858
else if (generate_new_name(log_file_name, name))
861
if (io_cache_type == SEQ_READ_APPEND)
862
open_flags |= O_RDWR | O_APPEND;
864
open_flags |= O_WRONLY | (log_type == LOG_BIN ? 0 : O_APPEND);
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))))
876
if (log_type == LOG_NORMAL)
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,
884
end= my_stpncpy(buff + len, "Time Id Command Argument\n",
886
if (my_b_write(&log_file, (unsigned char*) buff, (uint) (end-buff)) ||
887
flush_io_cache(&log_file))
891
log_state= LOG_OPENED;
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."),
902
my_close(file, MYF(0));
903
end_io_cache(&log_file);
909
log_state= LOG_CLOSED;
913
DRIZZLE_LOG::DRIZZLE_LOG()
914
: name(0), write_error(false), inited(false), log_type(LOG_UNKNOWN),
915
log_state(LOG_CLOSED)
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
923
memset(&log_file, 0, sizeof(log_file));
926
void DRIZZLE_LOG::init_pthread_objects()
930
(void) pthread_mutex_init(&LOCK_log, MY_MUTEX_INIT_SLOW);
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.
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
947
void DRIZZLE_LOG::close(uint32_t exiting)
948
{ // One can't set log_type here!
949
if (log_state == LOG_OPENED)
951
end_io_cache(&log_file);
953
if (my_sync(log_file.file, MYF(MY_WME)) && ! write_error)
956
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
959
if (my_close(log_file.file, MYF(MY_WME)) && ! write_error)
962
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
966
log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
975
/** This is called only once. */
977
void DRIZZLE_LOG::cleanup()
982
(void) pthread_mutex_destroy(&LOCK_log);
989
int DRIZZLE_LOG::generate_new_name(char *new_name, const char *log_name)
991
fn_format(new_name, log_name, drizzle_data_home, "", 4);
992
if (log_type == LOG_BIN)
994
if (!fn_ext(log_name)[0])
996
if (find_uniq_filename(new_name))
998
sql_print_error(ER(ER_NO_UNIQUE_LOGFILE), log_name);
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.
1012
const char *DRIZZLE_LOG::generate_name(const char *log_name,
1014
bool strip_ext, char *buff)
1016
if (!log_name || !log_name[0])
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));
1022
// get rid of extension if the log is binary to avoid problems
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;
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)
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
1046
index_file_name[0] = 0;
1047
memset(&index_file, 0, sizeof(index_file));
1050
/* this is called only once */
1052
void DRIZZLE_BIN_LOG::cleanup()
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);
1068
/* Init binlog-specific vars */
1069
void DRIZZLE_BIN_LOG::init(bool no_auto_events_arg, ulong max_size_arg)
1071
no_auto_events= no_auto_events_arg;
1072
max_size= max_size_arg;
1077
void DRIZZLE_BIN_LOG::init_pthread_objects()
1079
assert(inited == 0);
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);
1087
bool DRIZZLE_BIN_LOG::open_index_file(const char *index_file_name_arg,
1088
const char *log_name)
1090
File index_file_nr= -1;
1091
assert(!my_b_inited(&index_file));
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.
1098
myf opt= MY_UNPACK_FILENAME;
1099
if (!index_file_name_arg)
1101
index_file_name_arg= log_name; // Use same basename for index file
1102
opt= MY_UNPACK_FILENAME | MY_REPLACE_EXT;
1104
fn_format(index_file_name, index_file_name_arg, drizzle_data_home,
1106
if ((index_file_nr= my_open(index_file_name,
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)))
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().
1120
if (index_file_nr >= 0)
1121
my_close(index_file_nr,MYF(0));
1129
Open a (new) binlog file.
1131
- Open the log file and the index file. Register the new
1133
- When calling this when the file is in use, you must have a locks
1134
on LOCK_log and LOCK_index.
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,
1148
bool null_created_arg)
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 */
1158
init(no_auto_events_arg, max_size_arg);
1162
assert(log_type == LOG_BIN);
1165
bool write_file_name_to_index_file=0;
1167
if (!my_b_filelength(&log_file))
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.
1175
if (my_b_safe_write(&log_file, (unsigned char*) BINLOG_MAGIC,
1176
BIN_LOG_HEADER_SIZE))
1178
bytes_written+= BIN_LOG_HEADER_SIZE;
1179
write_file_name_to_index_file= 1;
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)
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.
1191
Format_description_log_event s(BINLOG_VERSION);
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
1196
if (io_cache_type == WRITE_CACHE)
1197
s.flags|= LOG_EVENT_BINLOG_IN_USE_F;
1200
s.dont_set_created= null_created_arg;
1201
if (s.write(&log_file))
1203
bytes_written+= s.data_written;
1205
if (description_event_for_queue &&
1206
description_event_for_queue->binlog_version>=4)
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
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).
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().
1228
description_event_for_queue->created= 0;
1229
/* Don't set log_pos in event header */
1230
description_event_for_queue->artificial_event=1;
1232
if (description_event_for_queue->write(&log_file))
1234
bytes_written+= description_event_for_queue->data_written;
1236
if (flush_io_cache(&log_file) ||
1237
my_sync(log_file.file, MYF(MY_WME)))
1240
if (write_file_name_to_index_file)
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.
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)))
1254
log_state= LOG_OPENED;
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."),
1266
my_close(file,MYF(0));
1267
end_io_cache(&log_file);
1268
end_io_cache(&index_file);
1274
log_state= LOG_CLOSED;
1279
int DRIZZLE_BIN_LOG::get_current_log(LOG_INFO* linfo)
1281
pthread_mutex_lock(&LOCK_log);
1282
int ret = raw_get_current_log(linfo);
1283
pthread_mutex_unlock(&LOCK_log);
1287
int DRIZZLE_BIN_LOG::raw_get_current_log(LOG_INFO* linfo)
1289
strmake(linfo->log_file_name, log_file_name, sizeof(linfo->log_file_name)-1);
1290
linfo->pos = my_b_tell(&log_file);
1295
Move all data up in a file in an filename index file.
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.
1301
@param index_file File to move
1302
@param offset Move everything from here to beginning
1305
File will be truncated to be 'offset' shorter or filled up with newlines
1311
static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset)
1314
my_off_t init_offset= offset;
1315
File file= index_file->file;
1316
unsigned char io_buf[IO_SIZE*2];
1318
for (;; offset+= bytes_read)
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)))
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)))
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)))
1334
/* Reset data in old index cache */
1335
reinit_io_cache(index_file, READ_CACHE, (my_off_t) 0, 0, 1);
1343
Find the position in the log-index-file for the given log name.
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
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.
1359
LOG_INFO_EOF End of log-index-file found
1361
LOG_INFO_IO Got IO error while reading file
1364
int DRIZZLE_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name,
1368
char *fname= linfo->log_file_name;
1369
uint32_t log_name_len= log_name ? (uint) strlen(log_name) : 0;
1372
Mutex needed because we need to make sure the file pointer does not
1373
move from under our feet
1376
pthread_mutex_lock(&LOCK_index);
1377
safe_mutex_assert_owner(&LOCK_index);
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);
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 */
1388
if ((length= my_b_gets(&index_file, fname, FN_REFLEN)) <= 1)
1390
/* Did not find the given entry; Return not found or error */
1391
error= !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
1395
// if the log entry matches, null string matching anything
1397
(log_name_len == length-1 && fname[log_name_len] == '\n' &&
1398
!memcmp(fname, log_name, log_name_len)))
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);
1408
pthread_mutex_unlock(&LOCK_index);
1414
Find the position in the log-index-file for the given log name.
1417
linfo Store here the next log file name and position to
1418
the file name after that.
1420
need_lock Set this to 1 if the parent doesn't already have a
1424
- Before calling this function, one has to call find_log_pos()
1426
- Mutex needed because we need to make sure the file pointer does not move
1432
LOG_INFO_EOF End of log-index-file found
1434
LOG_INFO_IO Got IO error while reading file
1437
int DRIZZLE_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock)
1441
char *fname= linfo->log_file_name;
1444
pthread_mutex_lock(&LOCK_index);
1445
safe_mutex_assert_owner(&LOCK_index);
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,
1451
linfo->index_file_start_offset= linfo->index_file_offset;
1452
if ((length=my_b_gets(&index_file, fname, FN_REFLEN)) <= 1)
1454
error = !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
1457
fname[length-1]=0; // kill \n
1458
linfo->index_file_offset = my_b_tell(&index_file);
1462
pthread_mutex_unlock(&LOCK_index);
1468
Delete all logs refered to in the index file.
1469
Start writing to a new log file.
1471
The new index file will only contain this file.
1473
@param session Thread
1476
If not called from slave thread, write start event to new log
1484
bool DRIZZLE_BIN_LOG::reset_logs(Session* session)
1488
const char* save_name;
1491
We need to get both locks to be sure that no one is trying to
1492
write to the index log file.
1494
pthread_mutex_lock(&LOCK_log);
1495
pthread_mutex_lock(&LOCK_index);
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.
1503
pthread_mutex_lock(&LOCK_thread_count);
1505
/* Save variables so that we can reopen the log */
1507
name=0; // Protect against free
1508
close(LOG_CLOSE_TO_BE_OPENED);
1510
/* First delete all old log files */
1512
if (find_log_pos(&linfo, NULL, 0))
1520
if ((error= my_delete_allow_opened(linfo.log_file_name, MYF(0))) != 0)
1522
if (my_errno == ENOENT)
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);
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);
1545
if (find_next_log(&linfo, 0))
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)
1553
if (my_errno == ENOENT)
1555
push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1556
ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
1558
sql_print_information(_("Failed to delete file '%s'"),
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",
1576
if (!session->slave_thread)
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);
1583
pthread_mutex_unlock(&LOCK_thread_count);
1584
pthread_mutex_unlock(&LOCK_index);
1585
pthread_mutex_unlock(&LOCK_log);
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
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
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).
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).
1620
LOG_INFO_EOF End of log-index-file found
1622
LOG_INFO_SEEK Could not allocate IO cache
1624
LOG_INFO_IO Got IO error while reading file
1628
int DRIZZLE_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
1633
assert(rli->slave_running == 1);
1634
assert(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name.c_str()));
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);
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
1649
pthread_cond_broadcast(&rli->log_space_cond);
1652
Read the next log file name from the index file and pass it back to
1654
If included is true, we want the first relay log;
1655
otherwise we want the one after event_relay_log_name.
1657
if ((included && (error=find_log_pos(&rli->linfo, NULL, 0))) ||
1659
((error=find_log_pos(&rli->linfo, rli->event_relay_log_name.c_str(), 0)) ||
1660
(error=find_next_log(&rli->linfo, 0)))))
1663
sql_print_error(_("next log error: %d offset: %s log: %s included: %d"),
1665
llstr(rli->linfo.index_file_offset,buff),
1666
rli->group_relay_log_name.c_str(),
1672
Reset rli's coordinates to the current log.
1674
rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
1675
rli->event_relay_log_name.assign(rli->linfo.log_file_name);
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)
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();
1689
/* Store where we are in the new file for the execution thread */
1690
flush_relay_log_info(rli);
1693
pthread_mutex_unlock(&LOCK_index);
1698
Update log index_file.
1701
int DRIZZLE_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads)
1703
if (copy_up_file_and_fill(&index_file, log_info->index_file_start_offset))
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);
1713
Remove all logs before the given log from disk and from the index file.
1715
@param to_log Delete all log file name before this file.
1716
@param included If true, to_log is deleted too.
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
1724
If any of the logs before the deleted one is in use,
1725
only purge logs up to this one.
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()
1736
int DRIZZLE_BIN_LOG::purge_logs(const char *to_log,
1739
bool need_update_threads,
1740
uint64_t *decrease_log_space)
1748
pthread_mutex_lock(&LOCK_index);
1749
if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/)))
1753
File name exists in index file; delete until we find this file
1754
or a file that is used.
1756
if ((error=find_log_pos(&log_info, NULL, 0 /*no mutex*/)))
1758
while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
1759
!log_in_use(log_info.log_file_name))
1762
if (stat(log_info.log_file_name, &s))
1764
if (errno == ENOENT)
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.
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);
1780
Other than ENOENT are fatal
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;
1795
if (!my_delete(log_info.log_file_name, MYF(0)))
1797
if (decrease_log_space)
1798
*decrease_log_space-= s.st_size;
1802
if (my_errno == ENOENT)
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);
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)
1822
error= LOG_INFO_EMFILE;
1824
error= LOG_INFO_FATAL;
1830
if (find_next_log(&log_info, 0) || exit_loop)
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
1838
error= update_log_index(&log_info, need_update_threads);
1845
pthread_mutex_unlock(&LOCK_index);
1850
Remove all logs before the given file date from disk and from the
1853
@param session Thread pointer
1854
@param before_date Delete all log files before given date.
1857
If any of the logs before the deleted one is in use,
1858
only purge logs up to this one.
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()
1868
int DRIZZLE_BIN_LOG::purge_logs_before_date(time_t purge_time)
1872
struct stat stat_area;
1874
pthread_mutex_lock(&LOCK_index);
1877
Delete until we find curren file
1878
or a file that is used or a file
1879
that is older than purge_time.
1881
if ((error=find_log_pos(&log_info, NULL, 0 /*no mutex*/)))
1884
while (strcmp(log_file_name, log_info.log_file_name) &&
1885
!log_in_use(log_info.log_file_name))
1887
if (stat(log_info.log_file_name, &stat_area))
1889
if (errno == ENOENT)
1892
It's not fatal if we can't stat a log file that does not exist.
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);
1904
Other than ENOENT are fatal
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;
1919
if (stat_area.st_mtime >= purge_time)
1921
if (my_delete(log_info.log_file_name, MYF(0)))
1923
if (my_errno == ENOENT)
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);
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;
1947
if (find_next_log(&log_info, 0))
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
1955
error= update_log_index(&log_info, 1);
1958
pthread_mutex_unlock(&LOCK_index);
1964
Create a new log file name.
1966
@param buf buf of at least FN_REFLEN where new name is stored
1969
If file name will be longer then FN_REFLEN it will be truncated
1972
void DRIZZLE_BIN_LOG::make_log_name(char* buf, const char* log_ident)
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);
1983
Check if we are writing/reading to the given log file.
1986
bool DRIZZLE_BIN_LOG::is_active(const char *log_file_name_arg)
1988
return !strcmp(log_file_name, log_file_name_arg);
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
2000
void DRIZZLE_BIN_LOG::new_file()
2006
void DRIZZLE_BIN_LOG::new_file_without_locking()
2013
Start writing to a new log file or reopen the old file.
2015
@param need_lock Set to 1 if caller has not locked LOCK_log
2018
The new file name is stored last in the index file
2021
void DRIZZLE_BIN_LOG::new_file_impl(bool need_lock)
2023
char new_name[FN_REFLEN], *new_name_ptr, *old_name;
2031
pthread_mutex_lock(&LOCK_log);
2032
pthread_mutex_lock(&LOCK_index);
2034
safe_mutex_assert_owner(&LOCK_log);
2035
safe_mutex_assert_owner(&LOCK_index);
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
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);
2053
pthread_mutex_unlock(&LOCK_prep_xids);
2056
/* Reuse old name if not binlog and not update log */
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.
2064
if (generate_new_name(new_name, name))
2066
new_name_ptr=new_name;
2068
if (log_type == LOG_BIN)
2070
if (!no_auto_events)
2073
We log the whole file name for log file as the user may decide
2074
to change base names at some point.
2076
Rotate_log_event r(new_name+dirname_length(new_name),
2077
0, LOG_EVENT_OFFSET, 0);
2079
bytes_written += r.data_written;
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.
2089
name=0; // Don't free name
2090
close(LOG_CLOSE_TO_BE_OPENED);
2093
Note that at this point, log_state != LOG_CLOSED (important for is_open()).
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.
2105
open(old_name, log_type, new_name_ptr,
2106
io_cache_type, no_auto_events, max_size, 1);
2111
pthread_mutex_unlock(&LOCK_log);
2112
pthread_mutex_unlock(&LOCK_index);
2118
bool DRIZZLE_BIN_LOG::append(Log_event* ev)
2121
pthread_mutex_lock(&LOCK_log);
2123
assert(log_file.type == SEQ_READ_APPEND);
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.
2128
if (ev->write(&log_file))
2133
bytes_written+= ev->data_written;
2134
if ((uint) my_b_append_tell(&log_file) > max_size)
2135
new_file_without_locking();
2138
pthread_mutex_unlock(&LOCK_log);
2139
signal_update(); // Safe as we don't call close
2144
bool DRIZZLE_BIN_LOG::appendv(const char* buf, uint32_t len,...)
2150
assert(log_file.type == SEQ_READ_APPEND);
2152
safe_mutex_assert_owner(&LOCK_log);
2155
if (my_b_append(&log_file,(unsigned char*) buf,len))
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();
2172
bool DRIZZLE_BIN_LOG::flush_and_sync()
2174
int err=0, fd=log_file.file;
2175
safe_mutex_assert_owner(&LOCK_log);
2176
if (flush_io_cache(&log_file))
2178
if (++sync_binlog_counter >= sync_binlog_period && sync_binlog_period)
2180
sync_binlog_counter= 0;
2181
err=my_sync(fd, MYF(MY_WME));
2186
void DRIZZLE_BIN_LOG::start_union_events(Session *session, query_id_t query_id_param)
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;
2195
void DRIZZLE_BIN_LOG::stop_union_events(Session *session)
2197
assert(session->binlog_evt_union.do_union);
2198
session->binlog_evt_union.do_union= false;
2201
bool DRIZZLE_BIN_LOG::is_query_in_union(Session *session, query_id_t query_id_param)
2203
return (session->binlog_evt_union.do_union &&
2204
query_id_param >= session->binlog_evt_union.first_query_id);
2209
These functions are placed in this file since they need access to
2210
binlog_hton, which has internal linkage.
2213
int Session::binlog_setup_trx_data()
2215
binlog_trx_data *trx_data=
2216
(binlog_trx_data*) session_get_ha_data(this, binlog_hton);
2219
return(0); // Already set up
2221
trx_data= (binlog_trx_data*) my_malloc(sizeof(binlog_trx_data), MYF(MY_ZEROFILL));
2223
open_cached_file(&trx_data->trans_log, drizzle_tmpdir,
2224
LOG_PREFIX, binlog_cache_size, MYF(MY_WME)))
2226
free((unsigned char*)trx_data);
2227
return(1); // Didn't manage to set it up
2229
session_set_ha_data(this, binlog_hton, trx_data);
2231
trx_data= new (session_get_ha_data(this, binlog_hton)) binlog_trx_data;
2237
Function to start a statement and optionally a transaction for the
2241
binlog_start_trans_and_stmt()
2245
This function does three things:
2246
- Start a transaction if not in autocommit mode or if a BEGIN
2247
statement has been seen.
2249
- Start a statement transaction to allow us to truncate the binary
2252
- Save the currrent binlog position so that we can roll back the
2253
statement by truncating the transaction log.
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.
2265
Session::binlog_start_trans_and_stmt()
2267
binlog_trx_data *trx_data= (binlog_trx_data*) session_get_ha_data(this, binlog_hton);
2269
if (trx_data == NULL ||
2270
trx_data->before_stmt_pos == MY_OFF_T_UNDEF)
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);
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.
2285
ha_data[binlog_hton->slot].ha_info[0].set_trx_read_write();
2290
void Session::binlog_set_stmt_begin() {
2291
binlog_trx_data *trx_data=
2292
(binlog_trx_data*) session_get_ha_data(this, binlog_hton);
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).
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;
2308
Write a table map to the binary log.
2311
int Session::binlog_write_table_map(Table *table, bool is_trans)
2315
/* Pre-conditions */
2316
assert(table->s->table_map_id != UINT32_MAX);
2318
Table_map_log_event::flag_set const
2319
flags= Table_map_log_event::TM_NO_FLAGS;
2322
the_event(this, table, table->s->table_map_id, is_trans, flags);
2324
if (is_trans && binlog_table_maps == 0)
2325
binlog_start_trans_and_stmt();
2327
if ((error= drizzle_bin_log.write(&the_event)))
2330
binlog_table_maps++;
2331
table->s->table_map_version= drizzle_bin_log.table_map_version();
2336
Session::binlog_get_pending_rows_event() const
2338
binlog_trx_data *const trx_data=
2339
(binlog_trx_data*) session_get_ha_data(this, binlog_hton);
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
2346
return trx_data ? trx_data->pending() : NULL;
2350
Session::binlog_set_pending_rows_event(Rows_log_event* ev)
2352
if (session_get_ha_data(this, binlog_hton) == NULL)
2353
binlog_setup_trx_data();
2355
binlog_trx_data *const trx_data=
2356
(binlog_trx_data*) session_get_ha_data(this, binlog_hton);
2359
trx_data->set_pending(ev);
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
2369
DRIZZLE_BIN_LOG::flush_and_set_pending_rows_event(Session *session,
2370
Rows_log_event* event)
2372
assert(drizzle_bin_log.is_open());
2376
binlog_trx_data *const trx_data=
2377
(binlog_trx_data*) session_get_ha_data(session, binlog_hton);
2381
if (Rows_log_event* pending= trx_data->pending())
2383
IO_CACHE *file= &log_file;
2386
Decide if we should write to the log file directly or to the
2389
if (pending->get_cache_stmt() || my_b_tell(&trx_data->trans_log))
2390
file= &trx_data->trans_log;
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.
2398
pthread_mutex_lock(&LOCK_log);
2401
Write pending event to log file or transaction cache
2403
if (pending->write(file))
2405
pthread_mutex_unlock(&LOCK_log);
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
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.
2421
TODO: Find a solution so that table maps does not have to be
2422
written several times within a transaction.
2424
if (pending->get_flags(Rows_log_event::STMT_END_F))
2425
++m_table_map_version;
2429
if (file == &log_file)
2431
error= flush_and_sync();
2435
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
2439
pthread_mutex_unlock(&LOCK_log);
2442
session->binlog_set_pending_rows_event(event);
2448
Write an event to the binary log.
2451
bool DRIZZLE_BIN_LOG::write(Log_event *event_info)
2453
Session *session= event_info->session;
2456
if (session->binlog_evt_union.do_union)
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
2462
session->binlog_evt_union.unioned_events= true;
2463
session->binlog_evt_union.unioned_events_trans |= event_info->cache_stmt;
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
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.
2477
bool const end_stmt= false;
2478
session->binlog_flush_pending_rows_event(end_stmt);
2480
pthread_mutex_lock(&LOCK_log);
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.
2487
if (likely(is_open()))
2489
IO_CACHE *file= &log_file;
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)"
2495
if (session && !(session->options & OPTION_BIN_LOG))
2497
pthread_mutex_unlock(&LOCK_log);
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).
2510
if (opt_using_transactions && session)
2512
if (session->binlog_setup_trx_data())
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)
2521
if (trans_log_pos == 0)
2522
session->binlog_start_trans_and_stmt();
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
2534
Write the SQL command
2537
if (event_info->write(file))
2540
if (file == &log_file) // we are writing to the real log (disk)
2542
if (flush_and_sync())
2545
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
2552
if (my_errno == EFBIG)
2553
my_message(ER_TRANS_CACHE_FULL, ER(ER_TRANS_CACHE_FULL), MYF(0));
2555
my_error(ER_ERROR_ON_WRITE, MYF(0), name, errno);
2560
if (event_info->flags & LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F)
2561
++m_table_map_version;
2563
pthread_mutex_unlock(&LOCK_log);
2568
int error_log_print(enum loglevel level, const char *format,
2571
return logger.error_log_print(level, format, args);
2574
void DRIZZLE_BIN_LOG::rotate_and_purge(uint32_t flags)
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))
2581
new_file_without_locking();
2582
if (expire_logs_days)
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);
2589
if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
2590
pthread_mutex_unlock(&LOCK_log);
2593
uint32_t DRIZZLE_BIN_LOG::next_file_id()
2596
pthread_mutex_lock(&LOCK_log);
2598
pthread_mutex_unlock(&LOCK_log);
2604
Write the contents of a cache to the binary log.
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
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.
2617
int DRIZZLE_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
2619
Mutex_sentry sentry(lock_log ? &LOCK_log : NULL);
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;
2625
unsigned char header[LOG_EVENT_HEADER_LEN];
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
2641
group= (uint)my_b_tell(&log_file);
2648
if we only got a partial header in the last iteration,
2649
get the other half now and process a full header.
2651
if (unlikely(carry > 0))
2653
assert(carry < LOG_EVENT_HEADER_LEN);
2655
/* assemble both halves */
2656
memcpy(&header[carry], cache->read_pos, LOG_EVENT_HEADER_LEN - carry);
2658
/* fix end_log_pos */
2659
val= uint4korr(&header[LOG_POS_OFFSET]) + group;
2660
int4store(&header[LOG_POS_OFFSET], val);
2662
/* write the first half of the split header */
2663
if (my_b_write(&log_file, header, carry))
2664
return ER_ERROR_ON_WRITE;
2667
copy fixed second half of header to cache so the correct
2668
version will be written later.
2670
memcpy(cache->read_pos, &header[carry], LOG_EVENT_HEADER_LEN - carry);
2672
/* next event header at ... */
2673
hdr_offs = uint4korr(&header[EVENT_LEN_OFFSET]) - carry;
2678
/* if there is anything to write, process it. */
2680
if (likely(length > 0))
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").
2689
while (hdr_offs < length)
2692
partial header only? save what we can get, process once
2696
if (hdr_offs + LOG_EVENT_HEADER_LEN > length)
2698
carry= length - hdr_offs;
2699
memcpy(header, cache->read_pos + hdr_offs, carry);
2704
/* we've got a full event-header, and it came in one piece */
2706
unsigned char *log_pos= (unsigned char *)cache->read_pos + hdr_offs + LOG_POS_OFFSET;
2708
/* fix end_log_pos */
2709
val= uint4korr(log_pos) + group;
2710
int4store(log_pos, val);
2712
/* next event header at ... */
2713
log_pos= (unsigned char *)cache->read_pos + hdr_offs + EVENT_LEN_OFFSET;
2714
hdr_offs += uint4korr(log_pos);
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:
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)));
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.
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.
2758
We only come here if there is something in the cache.
2760
The thing in the cache is always a complete transaction.
2762
'cache' needs to be reinitialized after this functions returns.
2765
bool DRIZZLE_BIN_LOG::write(Session *session, IO_CACHE *cache, Log_event *commit_event)
2767
pthread_mutex_lock(&LOCK_log);
2769
/* NULL would represent nothing to replicate after ROLLBACK */
2770
assert(commit_event != NULL);
2773
if (likely(is_open())) // Should always be true
2776
We only bother to write to the binary log if there is anything
2779
if (my_b_tell(cache) > 0)
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.
2786
Query_log_event qinfo(session, STRING_WITH_LEN("BEGIN"), true, false);
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.
2796
This is safer than session->clear_error() against kills at shutdown.
2798
qinfo.error_code= 0;
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
2807
if (qinfo.write(&log_file))
2810
if ((write_error= write_cache(cache, false, false)))
2813
if (commit_event && commit_event->write(&log_file))
2815
if (flush_and_sync())
2817
if (cache->error) // Error on read
2819
sql_print_error(ER(ER_ERROR_ON_READ), cache->file_name, errno);
2820
write_error=1; // Don't give more errors
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
2831
If the commit_event is not Xid_log_event (then it's a Query_log_event)
2832
rotate binlog, if necessary.
2834
if (commit_event && commit_event->get_type_code() == XID_EVENT)
2836
pthread_mutex_lock(&LOCK_prep_xids);
2838
pthread_mutex_unlock(&LOCK_prep_xids);
2841
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
2843
pthread_mutex_unlock(&LOCK_log);
2851
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
2853
pthread_mutex_unlock(&LOCK_log);
2859
Wait until we get a signal that the relay log has been updated
2861
@param[in] session a Session struct
2863
LOCK_log must be taken before calling this function.
2864
It will be released at the end of the function.
2867
void DRIZZLE_BIN_LOG::wait_for_update_relay_log(Session* session)
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);
2881
Wait until we get a signal that the binary log has been updated.
2882
Applies to master only.
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
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.
2896
int DRIZZLE_BIN_LOG::wait_for_update_bin_log(Session* session,
2897
const struct timespec *timeout)
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");
2905
pthread_cond_wait(&update_cond, &LOCK_log);
2907
ret= pthread_cond_timedwait(&update_cond, &LOCK_log,
2908
const_cast<struct timespec *>(timeout));
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
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
2927
void DRIZZLE_BIN_LOG::close(uint32_t exiting)
2928
{ // One can't set log_type here!
2929
if (log_state == LOG_OPENED)
2931
if (log_type == LOG_BIN && !no_auto_events &&
2932
(exiting & LOG_CLOSE_STOP_EVENT))
2936
bytes_written+= s.data_written;
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)
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);
2948
/* this will cleanup IO_CACHE, sync and close the file */
2949
DRIZZLE_LOG::close(exiting);
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.
2957
if ((exiting & LOG_CLOSE_INDEX) && my_b_inited(&index_file))
2959
end_io_cache(&index_file);
2960
if (my_close(index_file.file, MYF(0)) < 0 && ! write_error)
2963
sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno);
2966
log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
2976
void DRIZZLE_BIN_LOG::set_max_size(ulong max_size_arg)
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.
2985
pthread_mutex_lock(&LOCK_log);
2987
max_size= max_size_arg;
2988
pthread_mutex_unlock(&LOCK_log);
2994
Check if a string is a valid number.
2996
@param str String to test
2997
@param res Store value here
2998
@param allow_wildcards Set to 1 if we should ignore '%' and '_'
3001
For the moment the allow_wildcards argument is not used
3002
Should be move to some other file.
3005
1 String is a number
3010
static bool test_if_number(register const char *str,
3011
long *res, bool allow_wildcards)
3018
while (*str++ == ' ') ;
3019
if (*--str == '-' || *str == '+')
3021
while (my_isdigit(files_charset_info,*str) ||
3022
(allow_wildcards && (*str == wild_many || *str == wild_one)))
3030
my_isdigit(files_charset_info,*str) ||
3031
(allow_wildcards && (*str == wild_many || *str == wild_one)) ;
3034
if (*str != 0 || flag == 0)
3038
return(1); /* Number ok */
3039
} /* test_if_number */
3042
void sql_perror(const char *message)
3044
sql_print_error("%s: %s",message, strerror(errno));
3048
bool flush_error_log()
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];
3059
On Windows is necessary a temporary file for to rename
3060
the current error file.
3062
strxmov(err_temp, err_renamed,"-tmp",NULL);
3063
(void) my_delete(err_temp, MYF(0));
3064
if (freopen(err_temp,"a+",stdout))
3068
unsigned char buf[IO_SIZE];
3070
if(freopen(err_temp,"a+",stderr)==NULL)
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)
3077
if(freopen(log_error_file,"a+",stderr)==NULL)
3080
if ((fd = my_open(err_temp, O_RDONLY, MYF(0))) >= 0)
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));
3087
(void) my_delete(err_temp, MYF(0));
3091
pthread_mutex_unlock(&LOCK_error_log);
3096
void DRIZZLE_BIN_LOG::signal_update()
3098
pthread_cond_broadcast(&update_cond);
3102
void sql_print_error(const char *format, ...)
3106
va_start(args, format);
3107
errmsg_vprintf (current_session, ERROR_LEVEL, format, args);
3114
void sql_print_warning(const char *format, ...)
3118
va_start(args, format);
3119
errmsg_vprintf (current_session, WARNING_LEVEL, format, args);
3126
void sql_print_information(const char *format, ...)
3130
va_start(args, format);
3131
errmsg_vprintf (current_session, INFORMATION_LEVEL, format, args);
3138
/********* transaction coordinator log for 2pc - mmap() based solution *******/
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
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
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)
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.
3176
uint64_t tc_log_page_waits= 0;
3180
#define TC_LOG_HEADER_SIZE (sizeof(tc_log_magic)+1)
3182
static const char tc_log_magic[]={(char) 254, 0x23, 0x05, 0x74};
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;
3189
int TC_LOG_MMAP::open(const char *opt_name)
3192
bool crashed= false;
3195
assert(total_ha_2pc > 1);
3196
assert(opt_name && opt_name[0]);
3198
tc_log_page_size= getpagesize();
3199
assert(TC_LOG_PAGE_SIZE % tc_log_page_size == 0);
3201
fn_format(logname,opt_name,drizzle_data_home,"",MY_UNPACK_FILENAME);
3202
if ((fd= my_open(logname, O_RDWR, MYF(0))) < 0)
3204
if (my_errno != ENOENT)
3206
if (using_heuristic_recover())
3208
if ((fd= my_create(logname, CREATE_MODE, O_RDWR, MYF(MY_WME))) < 0)
3211
file_length= opt_tc_log_size;
3212
if (ftruncate(fd, file_length))
3219
sql_print_information(_("Recovering after a crash using %s"), opt_name);
3220
if (tc_heuristic_recover)
3222
sql_print_error(_("Cannot perform automatic crash recovery when "
3223
"--tc-heuristic-recover is used"));
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)
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)
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))))
3245
for (pg=pages, i=0; i < npages; i++, pg++)
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);
3254
pg->end=(my_xid *)(pg->start + tc_log_page_size);
3255
pg->size=pg->free=tc_log_page_size/sizeof(my_xid);
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;
3263
if (crashed && recover())
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));
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);
3285
pool_last=pages+npages-1;
3295
there is no active page, let's got one from the pool.
3297
Two strategies here:
3298
-# take the first from the pool
3299
-# if there're waiters - take the one with the most free space.
3302
TODO page merging. try to allocate adjacent page first,
3303
so that they can be flushed both in one sync
3306
void TC_LOG_MMAP::get_active_from_pool()
3308
PAGE **p, **best_p=0;
3312
pthread_mutex_lock(&LOCK_pool);
3317
if ((*p)->waiters == 0) // can the first page be used ?
3318
break; // yes - take it.
3320
best_free=0; // no - trying second strategy
3321
for (p=&(*p)->next; *p; p=&(*p)->next)
3323
if ((*p)->waiters == 0 && (*p)->free > best_free)
3325
best_free=(*p)->free;
3330
while ((*best_p == 0 || best_free == 0) && overflow());
3333
if (active->free == active->size) // we've chosen an empty page
3335
tc_log_cur_pages_used++;
3336
set_if_bigger(tc_log_max_pages_used, tc_log_cur_pages_used);
3339
if ((*best_p)->next) // unlink the page from the pool
3340
*best_p=(*best_p)->next;
3345
pthread_mutex_unlock(&LOCK_pool);
3350
perhaps, increase log size ?
3352
int TC_LOG_MMAP::overflow()
3355
simple overflow handling - just wait
3356
TODO perhaps, increase log size ?
3357
let's check the behaviour of tc_log_page_waits first
3359
tc_log_page_waits++;
3360
pthread_cond_wait(&COND_pool, &LOCK_pool);
3361
return 1; // always return 1
3365
Record that transaction XID is committed on the persistent storage.
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.
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
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
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.
3391
int TC_LOG_MMAP::log_xid(Session *, my_xid xid)
3397
pthread_mutex_lock(&LOCK_active);
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.
3406
while (unlikely(active && active->free == 0))
3407
pthread_cond_wait(&COND_active, &LOCK_active);
3409
/* no active page ? take one from the pool */
3411
get_active_from_pool();
3414
pthread_mutex_lock(&p->lock);
3416
/* searching for an empty slot */
3420
assert(p->ptr < p->end); // because p->free > 0
3423
/* found! store xid there and mark the page dirty */
3424
cookie= (ulong)((unsigned char *)p->ptr - data); // can never be zero
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);
3435
{ // somebody's syncing. let's wait
3438
note - it must be while (), not do ... while () here
3439
as p->state may be not DIRTY when we come here
3441
while (p->state == DIRTY && syncing)
3442
pthread_cond_wait(&p->cond, &LOCK_sync);
3444
err= p->state == ERROR;
3445
if (p->state != DIRTY) // page was synced
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
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);
3463
return err ? 0 : cookie;
3466
int TC_LOG_MMAP::sync()
3470
assert(syncing != active);
3473
sit down and relax - this can take a while...
3474
note - no locks are held at this point
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);
3480
err= my_sync(fd, MYF(0));
3482
/* page is synced. let's move it to the pool */
3483
pthread_mutex_lock(&LOCK_pool);
3484
pool_last->next=syncing;
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);
3492
/* marking 'syncing' slot free */
3493
pthread_mutex_lock(&LOCK_sync);
3495
pthread_cond_signal(&active->cond); // wake up a new syncer
3496
pthread_mutex_unlock(&LOCK_sync);
3501
erase xid from the page, update page free space counters/pointers.
3502
cookie points directly to the memory where xid was logged.
3505
void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
3507
PAGE *p=pages+(cookie/tc_log_page_size);
3508
my_xid *x=(my_xid *)(data+cookie);
3511
assert(x >= p->start && x < p->end);
3514
pthread_mutex_lock(&p->lock);
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);
3525
void TC_LOG_MMAP::close()
3530
pthread_mutex_destroy(&LOCK_sync);
3531
pthread_mutex_destroy(&LOCK_active);
3532
pthread_mutex_destroy(&LOCK_pool);
3533
pthread_cond_destroy(&COND_pool);
3535
data[0]='A'; // garble the first (signature) byte, in case my_delete fails
3537
for (i=0; i < npages; i++)
3539
if (pages[i].ptr == 0)
3541
pthread_mutex_destroy(&pages[i].lock);
3542
pthread_cond_destroy(&pages[i].cond);
3545
free((unsigned char*)pages);
3547
my_munmap((char*)data, (size_t)file_length);
3549
my_close(fd, MYF(0));
3551
if (inited>=5) // cannot do in the switch because of Windows
3552
my_delete(logname, MYF(MY_WME));
3556
int TC_LOG_MMAP::recover()
3559
PAGE *p=pages, *end_p=pages+npages;
3561
if (memcmp(data, tc_log_magic, sizeof(tc_log_magic)))
3563
sql_print_error(_("Bad magic header in tc log"));
3568
the first byte after magic signature is set to current
3569
number of storage engines on startup
3571
if (data[sizeof(tc_log_magic)] != total_ha_2pc)
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)]);
3580
if (hash_init(&xids, &my_charset_bin, tc_log_page_size/3, 0,
3581
sizeof(my_xid), 0, 0, MYF(0)))
3584
for ( ; p < end_p ; p++)
3586
for (my_xid *x=p->start; x < p->end; x++)
3587
if (*x && my_hash_insert(&xids, (unsigned char *)x))
3591
if (ha_recover(&xids))
3595
memset(data, 0, (size_t)file_length);
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}"));
3610
TC_LOG_DUMMY tc_log_dummy;
3611
TC_LOG_MMAP tc_log_mmap;
3614
Perform heuristic recovery, if --tc-heuristic-recover was used.
3617
no matter whether heuristic recovery was successful or not
3618
mysqld must exit. So, return value is the same in both cases.
3621
0 no heuristic recovery was requested
3623
1 heuristic recovery was performed
3626
int TC_LOG::using_heuristic_recover()
3628
if (!tc_heuristic_recover)
3631
sql_print_information(_("Heuristic crash recovery mode"));
3633
sql_print_error(_("Heuristic crash recovery failed"));
3634
sql_print_information(_("Please restart mysqld without --tc-heuristic-recover"));
3638
/****** transaction coordinator log for 2pc - binlog() based solution ******/
3639
#define TC_LOG_BINLOG DRIZZLE_BIN_LOG
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!
3649
int TC_LOG_BINLOG::open(const char *opt_name)
3654
assert(total_ha_2pc > 1);
3655
assert(opt_name && opt_name[0]);
3657
pthread_mutex_init(&LOCK_prep_xids, MY_MUTEX_INIT_FAST);
3658
pthread_cond_init (&COND_prep_xids, 0);
3660
if (!my_b_inited(&index_file))
3662
/* There was a failure to open the index file, can't open the binlog */
3667
if (using_heuristic_recover())
3669
/* generate a new binlog to mask a corrupted one */
3670
open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0);
3675
if ((error= find_log_pos(&log_info, NULL, 1)))
3677
if (error != LOG_INFO_EOF)
3678
sql_print_error(_("find_log_pos() failed (error: %d)"), error);
3689
Format_description_log_event fdle(BINLOG_VERSION);
3690
char log_name[FN_REFLEN];
3692
if (! fdle.is_valid())
3697
strmake(log_name, log_info.log_file_name, sizeof(log_name)-1);
3698
} while (!(error= find_next_log(&log_info, 1)));
3700
if (error != LOG_INFO_EOF)
3702
sql_print_error(_("find_log_pos() failed (error: %d)"), error);
3706
if ((file= open_binlog(&log, log_name, &errmsg)) < 0)
3708
sql_print_error("%s", errmsg);
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)
3716
sql_print_information(_("Recovering after a crash using %s"), opt_name);
3717
error= recover(&log, (Format_description_log_event *)ev);
3724
my_close(file, MYF(MY_WME));
3734
/** This is called on shutdown, after ha_panic. */
3735
void TC_LOG_BINLOG::close()
3737
assert(prepared_xids==0);
3738
pthread_mutex_destroy(&LOCK_prep_xids);
3739
pthread_cond_destroy (&COND_prep_xids);
3751
int TC_LOG_BINLOG::log_xid(Session *session, my_xid xid)
3753
Xid_log_event xle(session, xid);
3754
binlog_trx_data *trx_data=
3755
(binlog_trx_data*) session_get_ha_data(session, binlog_hton);
3757
We always commit the entire transaction when writing an XID. Also
3758
note that the return value is inverted.
3760
return(!binlog_end_trans(session, trx_data, &xle, true));
3763
void TC_LOG_BINLOG::unlog(ulong, my_xid)
3765
pthread_mutex_lock(&LOCK_prep_xids);
3766
assert(prepared_xids > 0);
3767
if (--prepared_xids == 0) {
3768
pthread_cond_signal(&COND_prep_xids);
3770
pthread_mutex_unlock(&LOCK_prep_xids);
3771
rotate_and_purge(0); // as ::write() did not rotate
3774
int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
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)))
3785
init_alloc_root(&mem_root, TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE);
3787
fdle->flags&= ~LOG_EVENT_BINLOG_IN_USE_F; // abort on the first error
3789
while ((ev= Log_event::read_log_event(log,0,fdle)) && ev->is_valid())
3791
if (ev->get_type_code() == XID_EVENT)
3793
Xid_log_event *xev=(Xid_log_event *)ev;
3794
unsigned char *x= (unsigned char *) memdup_root(&mem_root, (unsigned char*) &xev->xid,
3798
my_hash_insert(&xids, x);
3803
if (ha_recover(&xids))
3806
free_root(&mem_root, MYF(0));
3811
free_root(&mem_root, MYF(0));
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}"));
3822
bool DRIZZLE_BIN_LOG::is_table_mapped(Table *table) const
3824
return table->s->table_map_version == table_map_version();
3828
#ifdef INNODB_COMPATIBILITY_HOOKS
3830
Get the file name of the MySQL binlog.
3831
@return the name of the binlog file
3834
const char* drizzle_bin_log_file_name(void)
3836
return drizzle_bin_log.get_log_fname();
3839
Get the current position of the MySQL binlog.
3840
@return byte offset from the beginning of the binlog
3843
uint64_t drizzle_bin_log_file_pos(void)
3845
return (uint64_t) drizzle_bin_log.get_log_file()->pos_in_file;
3847
#endif /* INNODB_COMPATIBILITY_HOOKS */
3850
mysql_declare_plugin(binlog)
3852
DRIZZLE_STORAGE_ENGINE_PLUGIN,
3856
"This is a pseudo storage engine to represent the binlog in a transaction",
3858
binlog_init, /* Plugin Init */
3859
NULL, /* Plugin Deinit */
3860
NULL, /* status variables */
3861
NULL, /* system variables */
3862
NULL /* config options */
3864
mysql_declare_plugin_end;