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 "mysql_priv.h"
29
#include "rpl_filter.h"
34
#include <m_ctype.h> // For test_if_number
36
#include <mysql/plugin.h>
38
/* max size of the log message */
39
#define MAX_LOG_BUFFER_SIZE 1024
40
#define MAX_USER_HOST_SIZE 512
41
#define MAX_TIME_SIZE 32
42
#define MY_OFF_T_UNDEF (~(my_off_t)0UL)
44
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
48
MYSQL_BIN_LOG mysql_bin_log;
49
ulong sync_binlog_counter= 0;
51
static bool test_if_number(const char *str,
52
long *res, bool allow_wildcards);
53
static int binlog_init(void *p);
54
static int binlog_close_connection(handlerton *hton, THD *thd);
55
static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv);
56
static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv);
57
static int binlog_commit(handlerton *hton, THD *thd, bool all);
58
static int binlog_rollback(handlerton *hton, THD *thd, bool all);
59
static int binlog_prepare(handlerton *hton, THD *thd, bool all);
62
Silence all errors and warnings reported when performing a write
64
Errors and warnings are not reported to the client or SQL exception
65
handlers, so that the presence of logging does not interfere and affect
66
the logic of an application.
68
class Silence_log_table_errors : public Internal_error_handler
70
char m_message[MYSQL_ERRMSG_SIZE];
72
Silence_log_table_errors()
77
virtual ~Silence_log_table_errors() {}
79
virtual bool handle_error(uint sql_errno, const char *message,
80
MYSQL_ERROR::enum_warning_level level,
82
const char *message() const { return m_message; }
86
Silence_log_table_errors::handle_error(uint /* sql_errno */,
87
const char *message_arg,
88
MYSQL_ERROR::enum_warning_level /* level */,
91
strmake(m_message, message_arg, sizeof(m_message)-1);
96
sql_print_message_func sql_print_message_handlers[3] =
98
sql_print_information,
104
char *make_default_log_name(char *buff,const char* log_ext)
106
strmake(buff, pidfile_name, FN_REFLEN-5);
107
return fn_format(buff, buff, mysql_data_home, log_ext,
108
MYF(MY_UNPACK_FILENAME|MY_REPLACE_EXT));
112
Helper class to hold a mutex for the duration of the
115
Eliminates the need for explicit unlocking of mutexes on, e.g.,
116
error returns. On passing a null pointer, the sentry will not do
122
Mutex_sentry(pthread_mutex_t *mutex)
126
pthread_mutex_lock(mutex);
132
pthread_mutex_unlock(m_mutex);
137
pthread_mutex_t *m_mutex;
139
// It's not allowed to copy this object in any way
140
Mutex_sentry(Mutex_sentry const&);
141
void operator=(Mutex_sentry const&);
145
Helper class to store binary log transaction data.
147
class binlog_trx_data {
150
: at_least_one_stmt(0), m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF)
152
trans_log.end_of_file= max_binlog_cache_size;
157
assert(pending() == NULL);
158
close_cached_file(&trans_log);
161
my_off_t position() const {
162
return my_b_tell(&trans_log);
167
return pending() == NULL && my_b_tell(&trans_log) == 0;
171
Truncate the transaction cache to a certain position. This
172
includes deleting the pending event.
174
void truncate(my_off_t pos)
178
reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0);
179
if (pos < before_stmt_pos)
180
before_stmt_pos= MY_OFF_T_UNDEF;
183
The only valid positions that can be truncated to are at the
184
beginning of a statement. We are relying on this fact to be able
185
to set the at_least_one_stmt flag correctly. In other word, if
186
we are truncating to the beginning of the transaction cache,
187
there will be no statements in the cache, otherwhise, we will
188
have at least one statement in the transaction cache.
190
at_least_one_stmt= (pos > 0);
194
Reset the entire contents of the transaction cache, emptying it
200
before_stmt_pos= MY_OFF_T_UNDEF;
201
trans_log.end_of_file= max_binlog_cache_size;
204
Rows_log_event *pending() const
209
void set_pending(Rows_log_event *const pending)
214
IO_CACHE trans_log; // The transaction cache
217
Boolean that is true if there is at least one statement in the
220
bool at_least_one_stmt;
224
Pending binrows event. This event is the event where the rows are
227
Rows_log_event *m_pending;
231
Binlog position before the start of the current statement.
233
my_off_t before_stmt_pos;
236
handlerton *binlog_hton;
239
/* Check if a given table is opened log table */
240
int check_if_log_table(uint db_len __attribute__((__unused__)),
241
const char *db __attribute__((__unused__)),
242
uint table_name_len __attribute__((__unused__)),
243
const char *table_name __attribute__((__unused__)),
244
uint check_if_opened __attribute__((__unused__)))
249
/* log event handlers */
251
bool Log_to_file_event_handler::
252
log_error(enum loglevel level, const char *format,
255
return vprint_msg_to_log(level, format, args);
258
void Log_to_file_event_handler::init_pthread_objects()
260
mysql_log.init_pthread_objects();
261
mysql_slow_log.init_pthread_objects();
265
/** Wrapper around MYSQL_LOG::write() for slow log. */
267
bool Log_to_file_event_handler::
268
log_slow(THD *thd, time_t current_time, time_t query_start_arg,
269
const char *user_host, uint user_host_len,
270
ulonglong query_utime, ulonglong lock_utime, bool is_command,
271
const char *sql_text, uint sql_text_len)
273
return mysql_slow_log.write(thd, current_time, query_start_arg,
274
user_host, user_host_len,
275
query_utime, lock_utime, is_command,
276
sql_text, sql_text_len);
281
Wrapper around MYSQL_LOG::write() for general log. We need it since we
282
want all log event handlers to have the same signature.
285
bool Log_to_file_event_handler::
286
log_general(THD *thd __attribute__((__unused__)),
287
time_t event_time, const char *user_host,
288
uint user_host_len, int thread_id,
289
const char *command_type, uint command_type_len,
290
const char *sql_text, uint sql_text_len,
291
CHARSET_INFO *client_cs __attribute__((__unused__)))
293
return mysql_log.write(event_time, user_host, user_host_len,
294
thread_id, command_type, command_type_len,
295
sql_text, sql_text_len);
299
bool Log_to_file_event_handler::init()
304
mysql_slow_log.open_slow_log(sys_var_slow_log_path.value);
307
mysql_log.open_query_log(sys_var_general_log_path.value);
309
is_initialized= true;
316
void Log_to_file_event_handler::cleanup()
319
mysql_slow_log.cleanup();
322
void Log_to_file_event_handler::flush()
324
/* reopen log files */
326
mysql_log.reopen_file();
328
mysql_slow_log.reopen_file();
332
Log error with all enabled log event handlers
337
level The level of the error significance: NOTE,
339
format format string for the error message
340
args list of arguments for the format string
347
bool LOGGER::error_log_print(enum loglevel level, const char *format,
351
Log_event_handler **current_handler;
353
/* currently we don't need locking here as there is no error_log table */
354
for (current_handler= error_log_handler_list ; *current_handler ;)
355
error= (*current_handler++)->log_error(level, format, args) || error;
361
void LOGGER::cleanup_base()
364
rwlock_destroy(&LOCK_logger);
365
if (file_log_handler)
366
file_log_handler->cleanup();
370
void LOGGER::cleanup_end()
373
if (file_log_handler)
374
delete file_log_handler;
379
Perform basic log initialization: create file-based log handler and
382
void LOGGER::init_base()
388
Here we create file log handler. We don't do it for the table log handler
389
here as it cannot be created so early. The reason is THD initialization,
390
which depends on the system variables (parsed later).
392
if (!file_log_handler)
393
file_log_handler= new Log_to_file_event_handler;
395
/* by default we use traditional error log */
396
init_error_log(LOG_FILE);
398
file_log_handler->init_pthread_objects();
399
my_rwlock_init(&LOCK_logger, NULL);
403
bool LOGGER::flush_logs(THD *thd __attribute__((__unused__)))
408
Now we lock logger, as nobody should be able to use logging routines while
409
log tables are closed
411
logger.lock_exclusive();
413
/* reopen log files */
414
file_log_handler->flush();
416
/* end of log flush */
423
Log slow query with all enabled log event handlers
428
thd THD of the query being logged
429
query The query being logged
430
query_length The length of the query string
431
current_utime Current time in microseconds (from undefined start)
438
bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length,
439
ulonglong current_utime)
443
Log_event_handler **current_handler;
444
bool is_command= false;
445
char user_host_buff[MAX_USER_HOST_SIZE];
446
Security_context *sctx= thd->security_ctx;
447
uint user_host_len= 0;
448
ulonglong query_utime, lock_utime;
451
Print the message to the buffer if we have slow log enabled
454
if (*slow_log_handler_list)
458
/* do not log slow queries from replication threads */
459
if (thd->slave_thread && !opt_log_slow_slave_statements)
469
/* fill in user_host value: the format is "%s[%s] @ %s [%s]" */
470
user_host_len= (strxnmov(user_host_buff, MAX_USER_HOST_SIZE,
471
sctx->priv_user ? sctx->priv_user : "", "[",
472
sctx->user ? sctx->user : "", "] @ ",
473
sctx->host ? sctx->host : "", " [",
474
sctx->ip ? sctx->ip : "", "]", NullS) -
477
current_time= my_time_possible_from_micro(current_utime);
478
if (thd->start_utime)
480
query_utime= (current_utime - thd->start_utime);
481
lock_utime= (thd->utime_after_lock - thd->start_utime);
485
query_utime= lock_utime= 0;
491
query= command_name[thd->command].str;
492
query_length= command_name[thd->command].length;
495
for (current_handler= slow_log_handler_list; *current_handler ;)
496
error= (*current_handler++)->log_slow(thd, current_time, thd->start_time,
497
user_host_buff, user_host_len,
498
query_utime, lock_utime, is_command,
499
query, query_length) || error;
506
bool LOGGER::general_log_write(THD *thd, enum enum_server_command command,
507
const char *query, uint query_length)
510
Log_event_handler **current_handler= general_log_handler_list;
511
char user_host_buff[MAX_USER_HOST_SIZE];
512
Security_context *sctx= thd->security_ctx;
514
uint user_host_len= 0;
518
id= thd->thread_id; /* Normal thread */
520
id= 0; /* Log from connect handler */
528
user_host_len= strxnmov(user_host_buff, MAX_USER_HOST_SIZE,
529
sctx->priv_user ? sctx->priv_user : "", "[",
530
sctx->user ? sctx->user : "", "] @ ",
531
sctx->host ? sctx->host : "", " [",
532
sctx->ip ? sctx->ip : "", "]", NullS) -
535
current_time= my_time(0);
537
while (*current_handler)
538
error|= (*current_handler++)->
539
log_general(thd, current_time, user_host_buff,
541
command_name[(uint) command].str,
542
command_name[(uint) command].length,
544
thd->variables.character_set_client) || error;
550
bool LOGGER::general_log_print(THD *thd, enum enum_server_command command,
551
const char *format, va_list args)
553
uint message_buff_len= 0;
554
char message_buff[MAX_LOG_BUFFER_SIZE];
556
/* prepare message */
558
message_buff_len= vsnprintf(message_buff, sizeof(message_buff),
561
message_buff[0]= '\0';
563
return general_log_write(thd, command, message_buff, message_buff_len);
566
void LOGGER::init_error_log(uint error_log_printer)
568
if (error_log_printer & LOG_NONE)
570
error_log_handler_list[0]= 0;
574
switch (error_log_printer) {
576
error_log_handler_list[0]= file_log_handler;
577
error_log_handler_list[1]= 0;
579
/* these two are disabled for now */
583
case LOG_TABLE|LOG_FILE:
589
void LOGGER::init_slow_log(uint slow_log_printer)
591
if (slow_log_printer & LOG_NONE)
593
slow_log_handler_list[0]= 0;
597
slow_log_handler_list[0]= file_log_handler;
598
slow_log_handler_list[1]= 0;
601
void LOGGER::init_general_log(uint general_log_printer)
603
if (general_log_printer & LOG_NONE)
605
general_log_handler_list[0]= 0;
609
general_log_handler_list[0]= file_log_handler;
610
general_log_handler_list[1]= 0;
614
bool LOGGER::activate_log_handler(THD* thd __attribute__((__unused__)),
617
MYSQL_QUERY_LOG *file_log;
624
file_log= file_log_handler->get_mysql_slow_log();
626
file_log->open_slow_log(sys_var_slow_log_path.value);
627
init_slow_log(log_output_options);
631
case QUERY_LOG_GENERAL:
634
file_log= file_log_handler->get_mysql_log();
636
file_log->open_query_log(sys_var_general_log_path.value);
637
init_general_log(log_output_options);
649
void LOGGER::deactivate_log_handler(THD *thd __attribute__((__unused__)),
657
tmp_opt= &opt_slow_log;
658
file_log= file_log_handler->get_mysql_slow_log();
660
case QUERY_LOG_GENERAL:
662
file_log= file_log_handler->get_mysql_log();
665
assert(0); // Impossible
677
int LOGGER::set_handlers(uint error_log_printer,
678
uint slow_log_printer,
679
uint general_log_printer)
681
/* error log table is not supported yet */
682
assert(error_log_printer < LOG_TABLE);
686
init_error_log(error_log_printer);
687
init_slow_log(slow_log_printer);
688
init_general_log(general_log_printer);
697
Save position of binary log transaction cache.
700
binlog_trans_log_savepos()
702
thd The thread to take the binlog data from
703
pos Pointer to variable where the position will be stored
707
Save the current position in the binary log transaction cache into
708
the variable pointed to by 'pos'
712
binlog_trans_log_savepos(THD *thd, my_off_t *pos)
715
if (thd_get_ha_data(thd, binlog_hton) == NULL)
716
thd->binlog_setup_trx_data();
717
binlog_trx_data *const trx_data=
718
(binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
719
assert(mysql_bin_log.is_open());
720
*pos= trx_data->position();
726
Truncate the binary log transaction cache.
729
binlog_trans_log_truncate()
731
thd The thread to take the binlog data from
732
pos Position to truncate to
736
Truncate the binary log to the given position. Will not change
741
binlog_trans_log_truncate(THD *thd, my_off_t pos)
743
assert(thd_get_ha_data(thd, binlog_hton) != NULL);
744
/* Only true if binlog_trans_log_savepos() wasn't called before */
745
assert(pos != ~(my_off_t) 0);
747
binlog_trx_data *const trx_data=
748
(binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
749
trx_data->truncate(pos);
755
this function is mostly a placeholder.
756
conceptually, binlog initialization (now mostly done in MYSQL_BIN_LOG::open)
757
should be moved here.
760
int binlog_init(void *p)
762
binlog_hton= (handlerton *)p;
763
binlog_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
764
binlog_hton->db_type=DB_TYPE_BINLOG;
765
binlog_hton->savepoint_offset= sizeof(my_off_t);
766
binlog_hton->close_connection= binlog_close_connection;
767
binlog_hton->savepoint_set= binlog_savepoint_set;
768
binlog_hton->savepoint_rollback= binlog_savepoint_rollback;
769
binlog_hton->commit= binlog_commit;
770
binlog_hton->rollback= binlog_rollback;
771
binlog_hton->prepare= binlog_prepare;
772
binlog_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
776
static int binlog_close_connection(handlerton *hton __attribute__((__unused__)),
779
binlog_trx_data *const trx_data=
780
(binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
781
assert(trx_data->empty());
782
thd_set_ha_data(thd, binlog_hton, NULL);
783
trx_data->~binlog_trx_data();
784
my_free((uchar*)trx_data, MYF(0));
794
thd The thread whose transaction should be ended
795
trx_data Pointer to the transaction data to use
796
end_ev The end event to use, or NULL
797
all True if the entire transaction should be ended, false if
798
only the statement transaction should be ended.
802
End the currently open transaction. The transaction can be either
803
a real transaction (if 'all' is true) or a statement transaction
806
If 'end_ev' is NULL, the transaction is a rollback of only
807
transactional tables, so the transaction cache will be truncated
808
to either just before the last opened statement transaction (if
809
'all' is false), or reset completely (if 'all' is true).
812
binlog_end_trans(THD *thd, binlog_trx_data *trx_data,
813
Log_event *end_ev, bool all)
816
IO_CACHE *trans_log= &trx_data->trans_log;
819
NULL denotes ROLLBACK with nothing to replicate: i.e., rollback of
820
only transactional tables. If the transaction contain changes to
821
any non-transactiona tables, we need write the transaction and log
827
Doing a commit or a rollback including non-transactional tables,
828
i.e., ending a transaction where we might write the transaction
829
cache to the binary log.
831
We can always end the statement when ending a transaction since
832
transactions are not allowed inside stored functions. If they
833
were, we would have to ensure that we're not ending a statement
834
inside a stored function.
836
thd->binlog_flush_pending_rows_event(true);
838
error= mysql_bin_log.write(thd, &trx_data->trans_log, end_ev);
842
We need to step the table map version after writing the
843
transaction cache to disk.
845
mysql_bin_log.update_table_map_version();
846
statistic_increment(binlog_cache_use, &LOCK_status);
847
if (trans_log->disk_writes != 0)
849
statistic_increment(binlog_cache_disk_use, &LOCK_status);
850
trans_log->disk_writes= 0;
856
If rolling back an entire transaction or a single statement not
857
inside a transaction, we reset the transaction cache.
859
If rolling back a statement in a transaction, we truncate the
860
transaction cache to remove the statement.
862
if (all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT)))
866
assert(!thd->binlog_get_pending_rows_event());
867
thd->clear_binlog_table_maps();
870
trx_data->truncate(trx_data->before_stmt_pos);
873
We need to step the table map version on a rollback to ensure
874
that a new table map event is generated instead of the one that
875
was written to the thrown-away transaction cache.
877
mysql_bin_log.update_table_map_version();
883
static int binlog_prepare(handlerton *hton __attribute__((__unused__)),
884
THD *thd __attribute__((__unused__)),
885
bool all __attribute__((__unused__)))
889
just pretend we can do 2pc, so that MySQL won't
891
real work will be done in MYSQL_BIN_LOG::log_xid()
896
#define YESNO(X) ((X) ? "yes" : "no")
899
This function is called once after each statement.
901
It has the responsibility to flush the transaction cache to the
902
binlog file on commits.
904
@param hton The binlog handlerton.
905
@param thd The client thread that executes the transaction.
906
@param all This is @c true if this is a real transaction commit, and
909
@see handlerton::commit
911
static int binlog_commit(handlerton *hton __attribute__((__unused__)),
914
binlog_trx_data *const trx_data=
915
(binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
917
if (trx_data->empty())
919
// we're here because trans_log was flushed in MYSQL_BIN_LOG::log_xid()
925
Decision table for committing a transaction. The top part, the
926
*conditions* represent different cases that can occur, and hte
927
bottom part, the *actions*, represent what should be done in that
930
Real transaction 'all' was true
932
Statement in cache There were at least one statement in the
935
In transaction We are inside a transaction
937
Stmt modified non-trans The statement being committed modified a
938
non-transactional table
940
All modified non-trans Some statement before this one in the
941
transaction modified a non-transactional
945
============================= = = = = = = = = = = = = = = = =
946
Real transaction N N N N N N N N N N N N N N N N
947
Statement in cache N N N N N N N N Y Y Y Y Y Y Y Y
948
In transaction N N N N Y Y Y Y N N N N Y Y Y Y
949
Stmt modified non-trans N N Y Y N N Y Y N N Y Y N N Y Y
950
All modified non-trans N Y N Y N Y N Y N Y N Y N Y N Y
952
Action: (C)ommit/(A)ccumulate C C - C A C - C - - - - A A - A
953
============================= = = = = = = = = = = = = = = = =
956
============================= = = = = = = = = = = = = = = = =
957
Real transaction Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
958
Statement in cache N N N N N N N N Y Y Y Y Y Y Y Y
959
In transaction N N N N Y Y Y Y N N N N Y Y Y Y
960
Stmt modified non-trans N N Y Y N N Y Y N N Y Y N N Y Y
961
All modified non-trans N Y N Y N Y N Y N Y N Y N Y N Y
963
(C)ommit/(A)ccumulate/(-) - - - - C C - C - - - - C C - C
964
============================= = = = = = = = = = = = = = = = =
966
In other words, we commit the transaction if and only if both of
967
the following are true:
968
- We are not in a transaction and committing a statement
970
- We are in a transaction and one (or more) of the following are
973
- A full transaction is committed
977
- A non-transactional statement is committed and there is
980
Otherwise, we accumulate the statement
982
ulonglong const in_transaction=
983
thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN);
984
if ((in_transaction && (all || (!trx_data->at_least_one_stmt && thd->transaction.stmt.modified_non_trans_table))) || (!in_transaction && !all))
986
Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), true, false);
987
qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
988
int error= binlog_end_trans(thd, trx_data, &qev, all);
995
This function is called when a transaction involving a transactional
996
table is rolled back.
998
It has the responsibility to flush the transaction cache to the
999
binlog file. However, if the transaction does not involve
1000
non-transactional tables, nothing needs to be logged.
1002
@param hton The binlog handlerton.
1003
@param thd The client thread that executes the transaction.
1004
@param all This is @c true if this is a real transaction rollback, and
1007
@see handlerton::rollback
1009
static int binlog_rollback(handlerton *hton __attribute__((__unused__)),
1013
binlog_trx_data *const trx_data=
1014
(binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
1016
if (trx_data->empty()) {
1021
if ((all && thd->transaction.all.modified_non_trans_table) ||
1022
(!all && thd->transaction.stmt.modified_non_trans_table) ||
1023
(thd->options & OPTION_KEEP_LOG))
1026
We write the transaction cache with a rollback last if we have
1027
modified any non-transactional table. We do this even if we are
1028
committing a single statement that has modified a
1029
non-transactional table since it can have modified a
1030
transactional table in that statement as well, which needs to be
1031
rolled back on the slave.
1033
Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), true, false);
1034
qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
1035
error= binlog_end_trans(thd, trx_data, &qev, all);
1037
else if ((all && !thd->transaction.all.modified_non_trans_table) ||
1038
(!all && !thd->transaction.stmt.modified_non_trans_table))
1041
If we have modified only transactional tables, we can truncate
1042
the transaction cache without writing anything to the binary
1045
error= binlog_end_trans(thd, trx_data, 0, all);
1052
How do we handle this (unlikely but legal) case:
1054
[transaction] + [update to non-trans table] + [rollback to savepoint] ?
1056
The problem occurs when a savepoint is before the update to the
1057
non-transactional table. Then when there's a rollback to the savepoint, if we
1058
simply truncate the binlog cache, we lose the part of the binlog cache where
1059
the update is. If we want to not lose it, we need to write the SAVEPOINT
1060
command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter
1061
is easy: it's just write at the end of the binlog cache, but the former
1062
should be *inserted* to the place where the user called SAVEPOINT. The
1063
solution is that when the user calls SAVEPOINT, we write it to the binlog
1064
cache (so no need to later insert it). As transactions are never intermixed
1065
in the binary log (i.e. they are serialized), we won't have conflicts with
1066
savepoint names when using mysqlbinlog or in the slave SQL thread.
1067
Then when ROLLBACK TO SAVEPOINT is called, if we updated some
1068
non-transactional table, we don't truncate the binlog cache but instead write
1069
ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which
1070
will chop the SAVEPOINT command from the binlog cache, which is good as in
1071
that case there is no need to have it in the binlog).
1074
static int binlog_savepoint_set(handlerton *hton __attribute__((__unused__)),
1077
binlog_trans_log_savepos(thd, (my_off_t*) sv);
1078
/* Write it to the binary log */
1081
thd->binlog_query(THD::STMT_QUERY_TYPE,
1082
thd->query, thd->query_length, true, false);
1086
static int binlog_savepoint_rollback(handlerton *hton __attribute__((__unused__)),
1090
Write ROLLBACK TO SAVEPOINT to the binlog cache if we have updated some
1091
non-transactional table. Otherwise, truncate the binlog cache starting
1092
from the SAVEPOINT command.
1094
if (unlikely(thd->transaction.all.modified_non_trans_table ||
1095
(thd->options & OPTION_KEEP_LOG)))
1098
thd->binlog_query(THD::STMT_QUERY_TYPE,
1099
thd->query, thd->query_length, true, false);
1102
binlog_trans_log_truncate(thd, *(my_off_t*)sv);
1107
int check_binlog_magic(IO_CACHE* log, const char** errmsg)
1110
assert(my_b_tell(log) == 0);
1112
if (my_b_read(log, (uchar*) magic, sizeof(magic)))
1114
*errmsg = "I/O error reading the header from the binary log";
1115
sql_print_error("%s, errno=%d, io cache code=%d", *errmsg, my_errno,
1119
if (memcmp(magic, BINLOG_MAGIC, sizeof(magic)))
1121
*errmsg = "Binlog has bad magic number; It's not a binary log file that can be used by this version of MySQL";
1128
File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg)
1132
if ((file = my_open(log_file_name, O_RDONLY | O_BINARY | O_SHARE,
1135
sql_print_error("Failed to open log (file '%s', errno %d)",
1136
log_file_name, my_errno);
1137
*errmsg = "Could not open log file";
1140
if (init_io_cache(log, file, IO_SIZE*2, READ_CACHE, 0, 0,
1141
MYF(MY_WME|MY_DONT_CHECK_FILESIZE)))
1143
sql_print_error("Failed to create a cache on log (file '%s')",
1145
*errmsg = "Could not open log file";
1148
if (check_binlog_magic(log,errmsg))
1155
my_close(file,MYF(0));
1163
Find a unique filename for 'filename.#'.
1165
Set '#' to a number as low as possible.
1168
nonzero if not possible to get unique filename
1171
static int find_uniq_filename(char *name)
1175
char buff[FN_REFLEN];
1176
struct st_my_dir *dir_info;
1177
register struct fileinfo *file_info;
1179
size_t buf_length, length;
1182
length= dirname_part(buff, name, &buf_length);
1183
start= name + length;
1187
length= (size_t) (end-start+1);
1189
if (!(dir_info = my_dir(buff,MYF(MY_DONT_SORT))))
1190
{ // This shouldn't happen
1191
strmov(end,".1"); // use name+1
1194
file_info= dir_info->dir_entry;
1195
for (i=dir_info->number_off_files ; i-- ; file_info++)
1197
if (bcmp((uchar*) file_info->name, (uchar*) start, length) == 0 &&
1198
test_if_number(file_info->name+length, &number,0))
1200
set_if_bigger(max_found,(ulong) number);
1203
my_dirend(dir_info);
1206
sprintf(end,"%06ld",max_found+1);
1211
void MYSQL_LOG::init(enum_log_type log_type_arg,
1212
enum cache_type io_cache_type_arg)
1214
log_type= log_type_arg;
1215
io_cache_type= io_cache_type_arg;
1221
Open a (new) log file.
1226
log_name The name of the log to open
1227
log_type_arg The type of the log. E.g. LOG_NORMAL
1228
new_name The new name for the logfile. This is only needed
1229
when the method is used to open the binlog file.
1230
io_cache_type_arg The type of the IO_CACHE to use for this log file
1233
Open the logfile, init IO_CACHE and write startup messages
1234
(in case of general and slow query logs).
1241
bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
1242
const char *new_name, enum cache_type io_cache_type_arg)
1244
char buff[FN_REFLEN];
1246
int open_flags= O_CREAT | O_BINARY;
1250
init(log_type_arg, io_cache_type_arg);
1252
if (!(name= my_strdup(log_name, MYF(MY_WME))))
1254
name= (char *)log_name; // for the error message
1259
strmov(log_file_name, new_name);
1260
else if (generate_new_name(log_file_name, name))
1263
if (io_cache_type == SEQ_READ_APPEND)
1264
open_flags |= O_RDWR | O_APPEND;
1266
open_flags |= O_WRONLY | (log_type == LOG_BIN ? 0 : O_APPEND);
1270
if ((file= my_open(log_file_name, open_flags,
1271
MYF(MY_WME | ME_WAITTANG))) < 0 ||
1272
init_io_cache(&log_file, file, IO_SIZE, io_cache_type,
1273
my_tell(file, MYF(MY_WME)), 0,
1274
MYF(MY_WME | MY_NABP |
1275
((log_type == LOG_BIN) ? MY_WAIT_IF_FULL : 0))))
1278
if (log_type == LOG_NORMAL)
1281
int len=snprintf(buff, sizeof(buff), "%s, Version: %s (%s). "
1282
"started with:\nTCP Port: %d, Named Pipe: %s\n",
1283
my_progname, server_version, MYSQL_COMPILATION_COMMENT,
1286
end= strnmov(buff + len, "Time Id Command Argument\n",
1287
sizeof(buff) - len);
1288
if (my_b_write(&log_file, (uchar*) buff, (uint) (end-buff)) ||
1289
flush_io_cache(&log_file))
1293
log_state= LOG_OPENED;
1297
sql_print_error("Could not use %s for logging (error %d). \
1298
Turning logging off for the whole duration of the MySQL server process. \
1299
To turn it on again: fix the cause, \
1300
shutdown the MySQL server and restart it.", name, errno);
1302
my_close(file, MYF(0));
1303
end_io_cache(&log_file);
1305
log_state= LOG_CLOSED;
1309
MYSQL_LOG::MYSQL_LOG()
1310
: name(0), write_error(false), inited(false), log_type(LOG_UNKNOWN),
1311
log_state(LOG_CLOSED)
1314
We don't want to initialize LOCK_Log here as such initialization depends on
1315
safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
1316
called only in main(). Doing initialization here would make it happen
1319
bzero((char*) &log_file, sizeof(log_file));
1322
void MYSQL_LOG::init_pthread_objects()
1324
assert(inited == 0);
1326
(void) pthread_mutex_init(&LOCK_log, MY_MUTEX_INIT_SLOW);
1334
exiting Bitmask. For the slow and general logs the only used bit is
1335
LOG_CLOSE_TO_BE_OPENED. This is used if we intend to call
1336
open at once after close.
1339
One can do an open on the object at once after doing a close.
1340
The internal structures are not freed until cleanup() is called
1343
void MYSQL_LOG::close(uint exiting)
1344
{ // One can't set log_type here!
1345
if (log_state == LOG_OPENED)
1347
end_io_cache(&log_file);
1349
if (my_sync(log_file.file, MYF(MY_WME)) && ! write_error)
1352
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
1355
if (my_close(log_file.file, MYF(MY_WME)) && ! write_error)
1358
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
1362
log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
1367
/** This is called only once. */
1369
void MYSQL_LOG::cleanup()
1374
(void) pthread_mutex_destroy(&LOCK_log);
1381
int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
1383
fn_format(new_name, log_name, mysql_data_home, "", 4);
1384
if (log_type == LOG_BIN)
1386
if (!fn_ext(log_name)[0])
1388
if (find_uniq_filename(new_name))
1390
sql_print_error(ER(ER_NO_UNIQUE_LOGFILE), log_name);
1406
Reopen the log file. The method is used during FLUSH LOGS
1407
and locks LOCK_log mutex
1411
void MYSQL_QUERY_LOG::reopen_file()
1420
pthread_mutex_lock(&LOCK_log);
1423
name= 0; // Don't free name
1424
close(LOG_CLOSE_TO_BE_OPENED);
1427
Note that at this point, log_state != LOG_CLOSED (important for is_open()).
1430
open(save_name, log_type, 0, io_cache_type);
1431
my_free(save_name, MYF(0));
1433
pthread_mutex_unlock(&LOCK_log);
1440
Write a command to traditional general log file
1445
event_time command start timestamp
1446
user_host the pointer to the string with user@host info
1447
user_host_len length of the user_host string. this is computed once
1448
and passed to all general log event handlers
1449
thread_id Id of the thread, issued a query
1450
command_type the type of the command being logged
1451
command_type_len the length of the string above
1452
sql_text the very text of the query being executed
1453
sql_text_len the length of sql_text string
1457
Log given command to to normal (not rotable) log file
1461
TRUE - error occured
1464
bool MYSQL_QUERY_LOG::write(time_t event_time,
1465
const char *user_host __attribute__((__unused__)),
1466
uint user_host_len __attribute__((__unused__)),
1468
const char *command_type, uint command_type_len,
1469
const char *sql_text, uint sql_text_len)
1473
char local_time_buff[MAX_TIME_SIZE];
1475
uint time_buff_len= 0;
1477
(void) pthread_mutex_lock(&LOCK_log);
1479
/* Test if someone closed between the is_open test and lock */
1482
/* Note that my_b_write() assumes it knows the length for this */
1483
if (event_time != last_time)
1485
last_time= event_time;
1487
localtime_r(&event_time, &start);
1489
time_buff_len= snprintf(local_time_buff, MAX_TIME_SIZE,
1490
"%02d%02d%02d %2d:%02d:%02d",
1491
start.tm_year % 100, start.tm_mon + 1,
1492
start.tm_mday, start.tm_hour,
1493
start.tm_min, start.tm_sec);
1495
if (my_b_write(&log_file, (uchar*) local_time_buff, time_buff_len))
1499
if (my_b_write(&log_file, (uchar*) "\t\t" ,2) < 0)
1502
/* command_type, thread_id */
1503
length= snprintf(buff, 32, "%5ld ", (long) thread_id);
1505
if (my_b_write(&log_file, (uchar*) buff, length))
1508
if (my_b_write(&log_file, (uchar*) command_type, command_type_len))
1511
if (my_b_write(&log_file, (uchar*) "\t", 1))
1515
if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len))
1518
if (my_b_write(&log_file, (uchar*) "\n", 1) ||
1519
flush_io_cache(&log_file))
1523
(void) pthread_mutex_unlock(&LOCK_log);
1530
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
1532
(void) pthread_mutex_unlock(&LOCK_log);
1538
Log a query to the traditional slow log file
1543
thd THD of the query
1544
current_time current timestamp
1545
query_start_arg command start timestamp
1546
user_host the pointer to the string with user@host info
1547
user_host_len length of the user_host string. this is computed once
1548
and passed to all general log event handlers
1549
query_utime Amount of time the query took to execute (in microseconds)
1550
lock_utime Amount of time the query was locked (in microseconds)
1551
is_command The flag, which determines, whether the sql_text is a
1552
query or an administrator command.
1553
sql_text the very text of the query or administrator command
1555
sql_text_len the length of sql_text string
1559
Log a query to the slow log file.
1563
TRUE - error occured
1566
bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
1567
time_t query_start_arg __attribute__((__unused__)),
1568
const char *user_host,
1569
uint user_host_len, ulonglong query_utime,
1570
ulonglong lock_utime, bool is_command,
1571
const char *sql_text, uint sql_text_len)
1575
(void) pthread_mutex_lock(&LOCK_log);
1579
(void) pthread_mutex_unlock(&LOCK_log);
1584
{ // Safety agains reopen
1586
char buff[80], *end;
1587
char query_time_buff[22+7], lock_time_buff[22+7];
1591
if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
1593
if (current_time != last_time)
1595
last_time= current_time;
1597
localtime_r(¤t_time, &start);
1599
buff_len= snprintf(buff, sizeof buff,
1600
"# Time: %02d%02d%02d %2d:%02d:%02d\n",
1601
start.tm_year % 100, start.tm_mon + 1,
1602
start.tm_mday, start.tm_hour,
1603
start.tm_min, start.tm_sec);
1605
/* Note that my_b_write() assumes it knows the length for this */
1606
if (my_b_write(&log_file, (uchar*) buff, buff_len))
1609
const uchar uh[]= "# User@Host: ";
1610
if (my_b_write(&log_file, uh, sizeof(uh) - 1))
1612
if (my_b_write(&log_file, (uchar*) user_host, user_host_len))
1614
if (my_b_write(&log_file, (uchar*) "\n", 1))
1617
/* For slow query log */
1618
sprintf(query_time_buff, "%.6f", ulonglong2double(query_utime)/1000000.0);
1619
sprintf(lock_time_buff, "%.6f", ulonglong2double(lock_utime)/1000000.0);
1620
if (my_b_printf(&log_file,
1621
"# Query_time: %s Lock_time: %s"
1622
" Rows_sent: %lu Rows_examined: %lu\n",
1623
query_time_buff, lock_time_buff,
1624
(ulong) thd->sent_row_count,
1625
(ulong) thd->examined_row_count) == (uint) -1)
1627
if (thd->db && strcmp(thd->db, db))
1628
{ // Database changed
1629
if (my_b_printf(&log_file,"use %s;\n",thd->db) == (uint) -1)
1633
if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
1635
end=strmov(end, ",last_insert_id=");
1636
end=longlong10_to_str((longlong)
1637
thd->first_successful_insert_id_in_prev_stmt_for_binlog,
1640
// Save value if we do an insert.
1641
if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0)
1643
if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
1645
end=strmov(end,",insert_id=");
1646
end=longlong10_to_str((longlong)
1647
thd->auto_inc_intervals_in_cur_stmt_for_binlog.minimum(),
1653
This info used to show up randomly, depending on whether the query
1654
checked the query start time or not. now we always write current
1655
timestamp to the slow log
1657
end= strmov(end, ",timestamp=");
1658
end= int10_to_str((long) current_time, end, 10);
1664
if (my_b_write(&log_file, (uchar*) "SET ", 4) ||
1665
my_b_write(&log_file, (uchar*) buff + 1, (uint) (end-buff)))
1670
end= strxmov(buff, "# administrator command: ", NullS);
1671
buff_len= (ulong) (end - buff);
1672
my_b_write(&log_file, (uchar*) buff, buff_len);
1674
if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len) ||
1675
my_b_write(&log_file, (uchar*) ";\n",2) ||
1676
flush_io_cache(&log_file))
1684
sql_print_error(ER(ER_ERROR_ON_WRITE), name, error);
1688
(void) pthread_mutex_unlock(&LOCK_log);
1695
The following should be using fn_format(); We just need to
1696
first change fn_format() to cut the file name if it's too long.
1698
const char *MYSQL_LOG::generate_name(const char *log_name,
1700
bool strip_ext, char *buff)
1702
if (!log_name || !log_name[0])
1704
strmake(buff, pidfile_name, FN_REFLEN - strlen(suffix) - 1);
1705
return (const char *)
1706
fn_format(buff, buff, "", suffix, MYF(MY_REPLACE_EXT|MY_REPLACE_DIR));
1708
// get rid of extension if the log is binary to avoid problems
1711
char *p= fn_ext(log_name);
1712
uint length= (uint) (p - log_name);
1713
strmake(buff, log_name, min(length, FN_REFLEN));
1714
return (const char*)buff;
1721
MYSQL_BIN_LOG::MYSQL_BIN_LOG()
1722
:bytes_written(0), prepared_xids(0), file_id(1), open_count(1),
1723
need_start_event(true), m_table_map_version(0),
1724
description_event_for_exec(0), description_event_for_queue(0)
1727
We don't want to initialize locks here as such initialization depends on
1728
safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
1729
called only in main(). Doing initialization here would make it happen
1732
index_file_name[0] = 0;
1733
bzero((char*) &index_file, sizeof(index_file));
1736
/* this is called only once */
1738
void MYSQL_BIN_LOG::cleanup()
1743
close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT);
1744
delete description_event_for_queue;
1745
delete description_event_for_exec;
1746
(void) pthread_mutex_destroy(&LOCK_log);
1747
(void) pthread_mutex_destroy(&LOCK_index);
1748
(void) pthread_cond_destroy(&update_cond);
1754
/* Init binlog-specific vars */
1755
void MYSQL_BIN_LOG::init(bool no_auto_events_arg, ulong max_size_arg)
1757
no_auto_events= no_auto_events_arg;
1758
max_size= max_size_arg;
1763
void MYSQL_BIN_LOG::init_pthread_objects()
1765
assert(inited == 0);
1767
(void) pthread_mutex_init(&LOCK_log, MY_MUTEX_INIT_SLOW);
1768
(void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
1769
(void) pthread_cond_init(&update_cond, 0);
1773
bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
1774
const char *log_name)
1776
File index_file_nr= -1;
1777
assert(!my_b_inited(&index_file));
1780
First open of this class instance
1781
Create an index file that will hold all file names uses for logging.
1782
Add new entries to the end of it.
1784
myf opt= MY_UNPACK_FILENAME;
1785
if (!index_file_name_arg)
1787
index_file_name_arg= log_name; // Use same basename for index file
1788
opt= MY_UNPACK_FILENAME | MY_REPLACE_EXT;
1790
fn_format(index_file_name, index_file_name_arg, mysql_data_home,
1792
if ((index_file_nr= my_open(index_file_name,
1793
O_RDWR | O_CREAT | O_BINARY ,
1794
MYF(MY_WME))) < 0 ||
1795
my_sync(index_file_nr, MYF(MY_WME)) ||
1796
init_io_cache(&index_file, index_file_nr,
1797
IO_SIZE, WRITE_CACHE,
1798
my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)),
1799
0, MYF(MY_WME | MY_WAIT_IF_FULL)))
1802
TODO: all operations creating/deleting the index file or a log, should
1803
call my_sync_dir() or my_sync_dir_by_file() to be durable.
1804
TODO: file creation should be done with my_create() not my_open().
1806
if (index_file_nr >= 0)
1807
my_close(index_file_nr,MYF(0));
1815
Open a (new) binlog file.
1817
- Open the log file and the index file. Register the new
1819
- When calling this when the file is in use, you must have a locks
1820
on LOCK_log and LOCK_index.
1828
bool MYSQL_BIN_LOG::open(const char *log_name,
1829
enum_log_type log_type_arg,
1830
const char *new_name,
1831
enum cache_type io_cache_type_arg,
1832
bool no_auto_events_arg,
1834
bool null_created_arg)
1840
/* open the main log file */
1841
if (MYSQL_LOG::open(log_name, log_type_arg, new_name, io_cache_type_arg))
1842
return(1); /* all warnings issued */
1844
init(no_auto_events_arg, max_size_arg);
1848
assert(log_type == LOG_BIN);
1851
bool write_file_name_to_index_file=0;
1853
if (!my_b_filelength(&log_file))
1856
The binary log file was empty (probably newly created)
1857
This is the normal case and happens when the user doesn't specify
1858
an extension for the binary log files.
1859
In this case we write a standard header to it.
1861
if (my_b_safe_write(&log_file, (uchar*) BINLOG_MAGIC,
1862
BIN_LOG_HEADER_SIZE))
1864
bytes_written+= BIN_LOG_HEADER_SIZE;
1865
write_file_name_to_index_file= 1;
1868
assert(my_b_inited(&index_file) != 0);
1869
reinit_io_cache(&index_file, WRITE_CACHE,
1870
my_b_filelength(&index_file), 0, 0);
1871
if (need_start_event && !no_auto_events)
1874
In 4.x we set need_start_event=0 here, but in 5.0 we want a Start event
1875
even if this is not the very first binlog.
1877
Format_description_log_event s(BINLOG_VERSION);
1879
don't set LOG_EVENT_BINLOG_IN_USE_F for SEQ_READ_APPEND io_cache
1880
as we won't be able to reset it later
1882
if (io_cache_type == WRITE_CACHE)
1883
s.flags|= LOG_EVENT_BINLOG_IN_USE_F;
1886
s.dont_set_created= null_created_arg;
1887
if (s.write(&log_file))
1889
bytes_written+= s.data_written;
1891
if (description_event_for_queue &&
1892
description_event_for_queue->binlog_version>=4)
1895
This is a relay log written to by the I/O slave thread.
1896
Write the event so that others can later know the format of this relay
1898
Note that this event is very close to the original event from the
1899
master (it has binlog version of the master, event types of the
1900
master), so this is suitable to parse the next relay log's event. It
1901
has been produced by
1902
Format_description_log_event::Format_description_log_event(char* buf,).
1903
Why don't we want to write the description_event_for_queue if this
1904
event is for format<4 (3.23 or 4.x): this is because in that case, the
1905
description_event_for_queue describes the data received from the
1906
master, but not the data written to the relay log (*conversion*),
1907
which is in format 4 (slave's).
1910
Set 'created' to 0, so that in next relay logs this event does not
1911
trigger cleaning actions on the slave in
1912
Format_description_log_event::apply_event_impl().
1914
description_event_for_queue->created= 0;
1915
/* Don't set log_pos in event header */
1916
description_event_for_queue->artificial_event=1;
1918
if (description_event_for_queue->write(&log_file))
1920
bytes_written+= description_event_for_queue->data_written;
1922
if (flush_io_cache(&log_file) ||
1923
my_sync(log_file.file, MYF(MY_WME)))
1926
if (write_file_name_to_index_file)
1929
As this is a new log file, we write the file name to the index
1930
file. As every time we write to the index file, we sync it.
1932
if (my_b_write(&index_file, (uchar*) log_file_name,
1933
strlen(log_file_name)) ||
1934
my_b_write(&index_file, (uchar*) "\n", 1) ||
1935
flush_io_cache(&index_file) ||
1936
my_sync(index_file.file, MYF(MY_WME)))
1940
log_state= LOG_OPENED;
1945
sql_print_error("Could not use %s for logging (error %d). \
1946
Turning logging off for the whole duration of the MySQL server process. \
1947
To turn it on again: fix the cause, \
1948
shutdown the MySQL server and restart it.", name, errno);
1950
my_close(file,MYF(0));
1951
end_io_cache(&log_file);
1952
end_io_cache(&index_file);
1954
log_state= LOG_CLOSED;
1959
int MYSQL_BIN_LOG::get_current_log(LOG_INFO* linfo)
1961
pthread_mutex_lock(&LOCK_log);
1962
int ret = raw_get_current_log(linfo);
1963
pthread_mutex_unlock(&LOCK_log);
1967
int MYSQL_BIN_LOG::raw_get_current_log(LOG_INFO* linfo)
1969
strmake(linfo->log_file_name, log_file_name, sizeof(linfo->log_file_name)-1);
1970
linfo->pos = my_b_tell(&log_file);
1975
Move all data up in a file in an filename index file.
1977
We do the copy outside of the IO_CACHE as the cache buffers would just
1978
make things slower and more complicated.
1979
In most cases the copy loop should only do one read.
1981
@param index_file File to move
1982
@param offset Move everything from here to beginning
1985
File will be truncated to be 'offset' shorter or filled up with newlines
1991
#ifdef HAVE_REPLICATION
1993
static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset)
1996
my_off_t init_offset= offset;
1997
File file= index_file->file;
1998
uchar io_buf[IO_SIZE*2];
2000
for (;; offset+= bytes_read)
2002
(void) my_seek(file, offset, MY_SEEK_SET, MYF(0));
2003
if ((bytes_read= (int) my_read(file, io_buf, sizeof(io_buf), MYF(MY_WME)))
2007
break; // end of file
2008
(void) my_seek(file, offset-init_offset, MY_SEEK_SET, MYF(0));
2009
if (my_write(file, io_buf, bytes_read, MYF(MY_WME | MY_NABP)))
2012
/* The following will either truncate the file or fill the end with \n' */
2013
if (ftruncate(file, offset - init_offset) || my_sync(file, MYF(MY_WME)))
2016
/* Reset data in old index cache */
2017
reinit_io_cache(index_file, READ_CACHE, (my_off_t) 0, 0, 1);
2024
#endif /* HAVE_REPLICATION */
2027
Find the position in the log-index-file for the given log name.
2029
@param linfo Store here the found log file name and position to
2030
the NEXT log file name in the index file.
2031
@param log_name Filename to find in the index file.
2032
Is a null pointer if we want to read the first entry
2033
@param need_lock Set this to 1 if the parent doesn't already have a
2037
On systems without the truncate function the file will end with one or
2038
more empty lines. These will be ignored when reading the file.
2043
LOG_INFO_EOF End of log-index-file found
2045
LOG_INFO_IO Got IO error while reading file
2048
int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name,
2052
char *fname= linfo->log_file_name;
2053
uint log_name_len= log_name ? (uint) strlen(log_name) : 0;
2056
Mutex needed because we need to make sure the file pointer does not
2057
move from under our feet
2060
pthread_mutex_lock(&LOCK_index);
2061
safe_mutex_assert_owner(&LOCK_index);
2063
/* As the file is flushed, we can't get an error here */
2064
(void) reinit_io_cache(&index_file, READ_CACHE, (my_off_t) 0, 0, 0);
2069
my_off_t offset= my_b_tell(&index_file);
2070
/* If we get 0 or 1 characters, this is the end of the file */
2072
if ((length= my_b_gets(&index_file, fname, FN_REFLEN)) <= 1)
2074
/* Did not find the given entry; Return not found or error */
2075
error= !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
2079
// if the log entry matches, null string matching anything
2081
(log_name_len == length-1 && fname[log_name_len] == '\n' &&
2082
!memcmp(fname, log_name, log_name_len)))
2084
fname[length-1]=0; // remove last \n
2085
linfo->index_file_start_offset= offset;
2086
linfo->index_file_offset = my_b_tell(&index_file);
2092
pthread_mutex_unlock(&LOCK_index);
2098
Find the position in the log-index-file for the given log name.
2101
linfo Store here the next log file name and position to
2102
the file name after that.
2104
need_lock Set this to 1 if the parent doesn't already have a
2108
- Before calling this function, one has to call find_log_pos()
2110
- Mutex needed because we need to make sure the file pointer does not move
2116
LOG_INFO_EOF End of log-index-file found
2118
LOG_INFO_IO Got IO error while reading file
2121
int MYSQL_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock)
2125
char *fname= linfo->log_file_name;
2128
pthread_mutex_lock(&LOCK_index);
2129
safe_mutex_assert_owner(&LOCK_index);
2131
/* As the file is flushed, we can't get an error here */
2132
(void) reinit_io_cache(&index_file, READ_CACHE, linfo->index_file_offset, 0,
2135
linfo->index_file_start_offset= linfo->index_file_offset;
2136
if ((length=my_b_gets(&index_file, fname, FN_REFLEN)) <= 1)
2138
error = !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
2141
fname[length-1]=0; // kill \n
2142
linfo->index_file_offset = my_b_tell(&index_file);
2146
pthread_mutex_unlock(&LOCK_index);
2152
Delete all logs refered to in the index file.
2153
Start writing to a new log file.
2155
The new index file will only contain this file.
2160
If not called from slave thread, write start event to new log
2168
bool MYSQL_BIN_LOG::reset_logs(THD* thd)
2172
const char* save_name;
2176
We need to get both locks to be sure that no one is trying to
2177
write to the index log file.
2179
pthread_mutex_lock(&LOCK_log);
2180
pthread_mutex_lock(&LOCK_index);
2183
The following mutex is needed to ensure that no threads call
2184
'delete thd' as we would then risk missing a 'rollback' from this
2185
thread. If the transaction involved MyISAM tables, it should go
2186
into binlog even on rollback.
2188
VOID(pthread_mutex_lock(&LOCK_thread_count));
2190
/* Save variables so that we can reopen the log */
2192
name=0; // Protect against free
2193
close(LOG_CLOSE_TO_BE_OPENED);
2195
/* First delete all old log files */
2197
if (find_log_pos(&linfo, NullS, 0))
2205
if ((error= my_delete_allow_opened(linfo.log_file_name, MYF(0))) != 0)
2207
if (my_errno == ENOENT)
2209
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
2210
ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
2211
linfo.log_file_name);
2212
sql_print_information("Failed to delete file '%s'",
2213
linfo.log_file_name);
2219
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
2220
ER_BINLOG_PURGE_FATAL_ERR,
2221
"a problem with deleting %s; "
2222
"consider examining correspondence "
2223
"of your binlog index file "
2224
"to the actual binlog files",
2225
linfo.log_file_name);
2230
if (find_next_log(&linfo, 0))
2234
/* Start logging with a new file */
2235
close(LOG_CLOSE_INDEX);
2236
if ((error= my_delete_allow_opened(index_file_name, MYF(0)))) // Reset (open will update)
2238
if (my_errno == ENOENT)
2240
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
2241
ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
2243
sql_print_information("Failed to delete file '%s'",
2250
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
2251
ER_BINLOG_PURGE_FATAL_ERR,
2252
"a problem with deleting %s; "
2253
"consider examining correspondence "
2254
"of your binlog index file "
2255
"to the actual binlog files",
2261
if (!thd->slave_thread)
2263
if (!open_index_file(index_file_name, 0))
2264
open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0);
2265
my_free((uchar*) save_name, MYF(0));
2268
VOID(pthread_mutex_unlock(&LOCK_thread_count));
2269
pthread_mutex_unlock(&LOCK_index);
2270
pthread_mutex_unlock(&LOCK_log);
2276
Delete relay log files prior to rli->group_relay_log_name
2277
(i.e. all logs which are not involved in a non-finished group
2278
(transaction)), remove them from the index file and start on next
2282
- Protects index file with LOCK_index
2283
- Delete relevant relay log files
2284
- Copy all file names after these ones to the front of the index file
2285
- If the OS has truncate, truncate the file, else fill it with \n'
2286
- Read the next file name from the index file and store in rli->linfo
2288
@param rli Relay log information
2289
@param included If false, all relay logs that are strictly before
2290
rli->group_relay_log_name are deleted ; if true, the
2291
latter is deleted too (i.e. all relay logs
2292
read by the SQL slave thread are deleted).
2295
- This is only called from the slave-execute thread when it has read
2296
all commands from a relay log and want to switch to a new relay log.
2297
- When this happens, we can be in an active transaction as
2298
a transaction can span over two relay logs
2299
(although it is always written as a single block to the master's binary
2300
log, hence cannot span over two master's binary logs).
2305
LOG_INFO_EOF End of log-index-file found
2307
LOG_INFO_SEEK Could not allocate IO cache
2309
LOG_INFO_IO Got IO error while reading file
2312
#ifdef HAVE_REPLICATION
2314
int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
2319
assert(rli->slave_running == 1);
2320
assert(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name));
2322
pthread_mutex_lock(&LOCK_index);
2323
pthread_mutex_lock(&rli->log_space_lock);
2324
rli->relay_log.purge_logs(rli->group_relay_log_name, included,
2325
0, 0, &rli->log_space_total);
2326
// Tell the I/O thread to take the relay_log_space_limit into account
2327
rli->ignore_log_space_limit= 0;
2328
pthread_mutex_unlock(&rli->log_space_lock);
2331
Ok to broadcast after the critical region as there is no risk of
2332
the mutex being destroyed by this thread later - this helps save
2335
pthread_cond_broadcast(&rli->log_space_cond);
2338
Read the next log file name from the index file and pass it back to
2340
If included is true, we want the first relay log;
2341
otherwise we want the one after event_relay_log_name.
2343
if ((included && (error=find_log_pos(&rli->linfo, NullS, 0))) ||
2345
((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)) ||
2346
(error=find_next_log(&rli->linfo, 0)))))
2349
sql_print_error("next log error: %d offset: %s log: %s included: %d",
2351
llstr(rli->linfo.index_file_offset,buff),
2352
rli->group_relay_log_name,
2358
Reset rli's coordinates to the current log.
2360
rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
2361
strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
2362
sizeof(rli->event_relay_log_name)-1);
2365
If we removed the rli->group_relay_log_name file,
2366
we must update the rli->group* coordinates, otherwise do not touch it as the
2367
group's execution is not finished (e.g. COMMIT not executed)
2371
rli->group_relay_log_pos = BIN_LOG_HEADER_SIZE;
2372
strmake(rli->group_relay_log_name,rli->linfo.log_file_name,
2373
sizeof(rli->group_relay_log_name)-1);
2374
rli->notify_group_relay_log_name_update();
2377
/* Store where we are in the new file for the execution thread */
2378
flush_relay_log_info(rli);
2381
pthread_mutex_unlock(&LOCK_index);
2386
Update log index_file.
2389
int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads)
2391
if (copy_up_file_and_fill(&index_file, log_info->index_file_start_offset))
2394
// now update offsets in index file for running threads
2395
if (need_update_threads)
2396
adjust_linfo_offsets(log_info->index_file_start_offset);
2401
Remove all logs before the given log from disk and from the index file.
2403
@param to_log Delete all log file name before this file.
2404
@param included If true, to_log is deleted too.
2406
@param need_update_threads If we want to update the log coordinates of
2407
all threads. False for relay logs, true otherwise.
2408
@param freed_log_space If not null, decrement this variable of
2409
the amount of log space freed
2412
If any of the logs before the deleted one is in use,
2413
only purge logs up to this one.
2418
LOG_INFO_EOF to_log not found
2419
LOG_INFO_EMFILE too many files opened
2420
LOG_INFO_FATAL if any other than ENOENT error from
2421
stat() or my_delete()
2424
int MYSQL_BIN_LOG::purge_logs(const char *to_log,
2427
bool need_update_threads,
2428
ulonglong *decrease_log_space)
2436
pthread_mutex_lock(&LOCK_index);
2437
if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/)))
2441
File name exists in index file; delete until we find this file
2442
or a file that is used.
2444
if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
2446
while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
2447
!log_in_use(log_info.log_file_name))
2450
if (stat(log_info.log_file_name, &s))
2452
if (errno == ENOENT)
2455
It's not fatal if we can't stat a log file that does not exist;
2456
If we could not stat, we won't delete.
2458
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
2459
ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
2460
log_info.log_file_name);
2461
sql_print_information("Failed to execute stat on file '%s'",
2462
log_info.log_file_name);
2468
Other than ENOENT are fatal
2470
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
2471
ER_BINLOG_PURGE_FATAL_ERR,
2472
"a problem with getting info on being purged %s; "
2473
"consider examining correspondence "
2474
"of your binlog index file "
2475
"to the actual binlog files",
2476
log_info.log_file_name);
2477
error= LOG_INFO_FATAL;
2483
if (!my_delete(log_info.log_file_name, MYF(0)))
2485
if (decrease_log_space)
2486
*decrease_log_space-= s.st_size;
2490
if (my_errno == ENOENT)
2492
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
2493
ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
2494
log_info.log_file_name);
2495
sql_print_information("Failed to delete file '%s'",
2496
log_info.log_file_name);
2501
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
2502
ER_BINLOG_PURGE_FATAL_ERR,
2503
"a problem with deleting %s; "
2504
"consider examining correspondence "
2505
"of your binlog index file "
2506
"to the actual binlog files",
2507
log_info.log_file_name);
2508
if (my_errno == EMFILE)
2510
error= LOG_INFO_EMFILE;
2512
error= LOG_INFO_FATAL;
2518
ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
2520
if (find_next_log(&log_info, 0) || exit_loop)
2525
If we get killed -9 here, the sysadmin would have to edit
2526
the log index file after restart - otherwise, this should be safe
2528
error= update_log_index(&log_info, need_update_threads);
2535
pthread_mutex_unlock(&LOCK_index);
2540
Remove all logs before the given file date from disk and from the
2543
@param thd Thread pointer
2544
@param before_date Delete all log files before given date.
2547
If any of the logs before the deleted one is in use,
2548
only purge logs up to this one.
2553
LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated
2554
LOG_INFO_FATAL if any other than ENOENT error from
2555
stat() or my_delete()
2558
int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
2562
struct stat stat_area;
2564
pthread_mutex_lock(&LOCK_index);
2567
Delete until we find curren file
2568
or a file that is used or a file
2569
that is older than purge_time.
2571
if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
2574
while (strcmp(log_file_name, log_info.log_file_name) &&
2575
!log_in_use(log_info.log_file_name))
2577
if (stat(log_info.log_file_name, &stat_area))
2579
if (errno == ENOENT)
2582
It's not fatal if we can't stat a log file that does not exist.
2584
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
2585
ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
2586
log_info.log_file_name);
2587
sql_print_information("Failed to execute stat on file '%s'",
2588
log_info.log_file_name);
2594
Other than ENOENT are fatal
2596
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
2597
ER_BINLOG_PURGE_FATAL_ERR,
2598
"a problem with getting info on being purged %s; "
2599
"consider examining correspondence "
2600
"of your binlog index file "
2601
"to the actual binlog files",
2602
log_info.log_file_name);
2603
error= LOG_INFO_FATAL;
2609
if (stat_area.st_mtime >= purge_time)
2611
if (my_delete(log_info.log_file_name, MYF(0)))
2613
if (my_errno == ENOENT)
2615
/* It's not fatal even if we can't delete a log file */
2616
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
2617
ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
2618
log_info.log_file_name);
2619
sql_print_information("Failed to delete file '%s'",
2620
log_info.log_file_name);
2625
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
2626
ER_BINLOG_PURGE_FATAL_ERR,
2627
"a problem with deleting %s; "
2628
"consider examining correspondence "
2629
"of your binlog index file "
2630
"to the actual binlog files",
2631
log_info.log_file_name);
2632
error= LOG_INFO_FATAL;
2636
ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
2638
if (find_next_log(&log_info, 0))
2643
If we get killed -9 here, the sysadmin would have to edit
2644
the log index file after restart - otherwise, this should be safe
2646
error= update_log_index(&log_info, 1);
2649
pthread_mutex_unlock(&LOCK_index);
2652
#endif /* HAVE_REPLICATION */
2656
Create a new log file name.
2658
@param buf buf of at least FN_REFLEN where new name is stored
2661
If file name will be longer then FN_REFLEN it will be truncated
2664
void MYSQL_BIN_LOG::make_log_name(char* buf, const char* log_ident)
2666
uint dir_len = dirname_length(log_file_name);
2667
if (dir_len >= FN_REFLEN)
2668
dir_len=FN_REFLEN-1;
2669
strnmov(buf, log_file_name, dir_len);
2670
strmake(buf+dir_len, log_ident, FN_REFLEN - dir_len -1);
2675
Check if we are writing/reading to the given log file.
2678
bool MYSQL_BIN_LOG::is_active(const char *log_file_name_arg)
2680
return !strcmp(log_file_name, log_file_name_arg);
2685
Wrappers around new_file_impl to avoid using argument
2686
to control locking. The argument 1) less readable 2) breaks
2687
incapsulation 3) allows external access to the class without
2688
a lock (which is not possible with private new_file_without_locking
2692
void MYSQL_BIN_LOG::new_file()
2698
void MYSQL_BIN_LOG::new_file_without_locking()
2705
Start writing to a new log file or reopen the old file.
2707
@param need_lock Set to 1 if caller has not locked LOCK_log
2710
The new file name is stored last in the index file
2713
void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
2715
char new_name[FN_REFLEN], *new_name_ptr, *old_name;
2723
pthread_mutex_lock(&LOCK_log);
2724
pthread_mutex_lock(&LOCK_index);
2726
safe_mutex_assert_owner(&LOCK_log);
2727
safe_mutex_assert_owner(&LOCK_index);
2730
if binlog is used as tc log, be sure all xids are "unlogged",
2731
so that on recover we only need to scan one - latest - binlog file
2732
for prepared xids. As this is expected to be a rare event,
2733
simple wait strategy is enough. We're locking LOCK_log to be sure no
2734
new Xid_log_event's are added to the log (and prepared_xids is not
2735
increased), and waiting on COND_prep_xids for late threads to
2740
tc_log_page_waits++;
2741
pthread_mutex_lock(&LOCK_prep_xids);
2742
while (prepared_xids) {
2743
pthread_cond_wait(&COND_prep_xids, &LOCK_prep_xids);
2745
pthread_mutex_unlock(&LOCK_prep_xids);
2748
/* Reuse old name if not binlog and not update log */
2752
If user hasn't specified an extension, generate a new log name
2753
We have to do this here and not in open as we want to store the
2754
new file name in the current binary log file.
2756
if (generate_new_name(new_name, name))
2758
new_name_ptr=new_name;
2760
if (log_type == LOG_BIN)
2762
if (!no_auto_events)
2765
We log the whole file name for log file as the user may decide
2766
to change base names at some point.
2768
Rotate_log_event r(new_name+dirname_length(new_name),
2769
0, LOG_EVENT_OFFSET, 0);
2771
bytes_written += r.data_written;
2774
Update needs to be signalled even if there is no rotate event
2775
log rotation should give the waiting thread a signal to
2776
discover EOF and move on to the next log.
2781
name=0; // Don't free name
2782
close(LOG_CLOSE_TO_BE_OPENED);
2785
Note that at this point, log_state != LOG_CLOSED (important for is_open()).
2789
new_file() is only used for rotation (in FLUSH LOGS or because size >
2790
max_binlog_size or max_relay_log_size).
2791
If this is a binary log, the Format_description_log_event at the beginning of
2792
the new file should have created=0 (to distinguish with the
2793
Format_description_log_event written at server startup, which should
2794
trigger temp tables deletion on slaves.
2797
open(old_name, log_type, new_name_ptr,
2798
io_cache_type, no_auto_events, max_size, 1);
2799
my_free(old_name,MYF(0));
2803
pthread_mutex_unlock(&LOCK_log);
2804
pthread_mutex_unlock(&LOCK_index);
2810
bool MYSQL_BIN_LOG::append(Log_event* ev)
2813
pthread_mutex_lock(&LOCK_log);
2815
assert(log_file.type == SEQ_READ_APPEND);
2817
Log_event::write() is smart enough to use my_b_write() or
2818
my_b_append() depending on the kind of cache we have.
2820
if (ev->write(&log_file))
2825
bytes_written+= ev->data_written;
2826
if ((uint) my_b_append_tell(&log_file) > max_size)
2827
new_file_without_locking();
2830
pthread_mutex_unlock(&LOCK_log);
2831
signal_update(); // Safe as we don't call close
2836
bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...)
2842
assert(log_file.type == SEQ_READ_APPEND);
2844
safe_mutex_assert_owner(&LOCK_log);
2847
if (my_b_append(&log_file,(uchar*) buf,len))
2852
bytes_written += len;
2853
} while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
2854
if ((uint) my_b_append_tell(&log_file) > max_size)
2855
new_file_without_locking();
2864
bool MYSQL_BIN_LOG::flush_and_sync()
2866
int err=0, fd=log_file.file;
2867
safe_mutex_assert_owner(&LOCK_log);
2868
if (flush_io_cache(&log_file))
2870
if (++sync_binlog_counter >= sync_binlog_period && sync_binlog_period)
2872
sync_binlog_counter= 0;
2873
err=my_sync(fd, MYF(MY_WME));
2878
void MYSQL_BIN_LOG::start_union_events(THD *thd, query_id_t query_id_param)
2880
assert(!thd->binlog_evt_union.do_union);
2881
thd->binlog_evt_union.do_union= true;
2882
thd->binlog_evt_union.unioned_events= false;
2883
thd->binlog_evt_union.unioned_events_trans= false;
2884
thd->binlog_evt_union.first_query_id= query_id_param;
2887
void MYSQL_BIN_LOG::stop_union_events(THD *thd)
2889
assert(thd->binlog_evt_union.do_union);
2890
thd->binlog_evt_union.do_union= false;
2893
bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param)
2895
return (thd->binlog_evt_union.do_union &&
2896
query_id_param >= thd->binlog_evt_union.first_query_id);
2901
These functions are placed in this file since they need access to
2902
binlog_hton, which has internal linkage.
2905
int THD::binlog_setup_trx_data()
2907
binlog_trx_data *trx_data=
2908
(binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
2911
return(0); // Already set up
2913
trx_data= (binlog_trx_data*) my_malloc(sizeof(binlog_trx_data), MYF(MY_ZEROFILL));
2915
open_cached_file(&trx_data->trans_log, mysql_tmpdir,
2916
LOG_PREFIX, binlog_cache_size, MYF(MY_WME)))
2918
my_free((uchar*)trx_data, MYF(MY_ALLOW_ZERO_PTR));
2919
return(1); // Didn't manage to set it up
2921
thd_set_ha_data(this, binlog_hton, trx_data);
2923
trx_data= new (thd_get_ha_data(this, binlog_hton)) binlog_trx_data;
2929
Function to start a statement and optionally a transaction for the
2933
binlog_start_trans_and_stmt()
2937
This function does three things:
2938
- Start a transaction if not in autocommit mode or if a BEGIN
2939
statement has been seen.
2941
- Start a statement transaction to allow us to truncate the binary
2944
- Save the currrent binlog position so that we can roll back the
2945
statement by truncating the transaction log.
2947
We only update the saved position if the old one was undefined,
2948
the reason is that there are some cases (e.g., for CREATE-SELECT)
2949
where the position is saved twice (e.g., both in
2950
select_create::prepare() and THD::binlog_write_table_map()) , but
2951
we should use the first. This means that calls to this function
2952
can be used to start the statement before the first table map
2953
event, to include some extra events.
2957
THD::binlog_start_trans_and_stmt()
2959
binlog_trx_data *trx_data= (binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
2961
if (trx_data == NULL ||
2962
trx_data->before_stmt_pos == MY_OFF_T_UNDEF)
2964
this->binlog_set_stmt_begin();
2965
if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
2966
trans_register_ha(this, true, binlog_hton);
2967
trans_register_ha(this, false, binlog_hton);
2969
Mark statement transaction as read/write. We never start
2970
a binary log transaction and keep it read-only,
2971
therefore it's best to mark the transaction read/write just
2972
at the same time we start it.
2973
Not necessary to mark the normal transaction read/write
2974
since the statement-level flag will be propagated automatically
2975
inside ha_commit_trans.
2977
ha_data[binlog_hton->slot].ha_info[0].set_trx_read_write();
2982
void THD::binlog_set_stmt_begin() {
2983
binlog_trx_data *trx_data=
2984
(binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
2987
The call to binlog_trans_log_savepos() might create the trx_data
2988
structure, if it didn't exist before, so we save the position
2989
into an auto variable and then write it into the transaction
2990
data for the binary log (i.e., trx_data).
2993
binlog_trans_log_savepos(this, &pos);
2994
trx_data= (binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
2995
trx_data->before_stmt_pos= pos;
3000
Write a table map to the binary log.
3003
int THD::binlog_write_table_map(TABLE *table, bool is_trans)
3007
/* Pre-conditions */
3008
assert(current_stmt_binlog_row_based && mysql_bin_log.is_open());
3009
assert(table->s->table_map_id != ULONG_MAX);
3011
Table_map_log_event::flag_set const
3012
flags= Table_map_log_event::TM_NO_FLAGS;
3015
the_event(this, table, table->s->table_map_id, is_trans, flags);
3017
if (is_trans && binlog_table_maps == 0)
3018
binlog_start_trans_and_stmt();
3020
if ((error= mysql_bin_log.write(&the_event)))
3023
binlog_table_maps++;
3024
table->s->table_map_version= mysql_bin_log.table_map_version();
3029
THD::binlog_get_pending_rows_event() const
3031
binlog_trx_data *const trx_data=
3032
(binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
3034
This is less than ideal, but here's the story: If there is no
3035
trx_data, prepare_pending_rows_event() has never been called
3036
(since the trx_data is set up there). In that case, we just return
3039
return trx_data ? trx_data->pending() : NULL;
3043
THD::binlog_set_pending_rows_event(Rows_log_event* ev)
3045
if (thd_get_ha_data(this, binlog_hton) == NULL)
3046
binlog_setup_trx_data();
3048
binlog_trx_data *const trx_data=
3049
(binlog_trx_data*) thd_get_ha_data(this, binlog_hton);
3052
trx_data->set_pending(ev);
3057
Moves the last bunch of rows from the pending Rows event to the binlog
3058
(either cached binlog if transaction, or disk binlog). Sets a new pending
3062
MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
3063
Rows_log_event* event)
3065
assert(mysql_bin_log.is_open());
3069
binlog_trx_data *const trx_data=
3070
(binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
3074
if (Rows_log_event* pending= trx_data->pending())
3076
IO_CACHE *file= &log_file;
3079
Decide if we should write to the log file directly or to the
3082
if (pending->get_cache_stmt() || my_b_tell(&trx_data->trans_log))
3083
file= &trx_data->trans_log;
3086
If we are writing to the log file directly, we could avoid
3087
locking the log. This does not work since we need to step the
3088
m_table_map_version below, and that change has to be protected
3089
by the LOCK_log mutex.
3091
pthread_mutex_lock(&LOCK_log);
3094
Write pending event to log file or transaction cache
3096
if (pending->write(file))
3098
pthread_mutex_unlock(&LOCK_log);
3103
We step the table map version if we are writing an event
3104
representing the end of a statement. We do this regardless of
3105
wheather we write to the transaction cache or to directly to the
3108
In an ideal world, we could avoid stepping the table map version
3109
if we were writing to a transaction cache, since we could then
3110
reuse the table map that was written earlier in the transaction
3111
cache. This does not work since STMT_END_F implies closing all
3112
table mappings on the slave side.
3114
TODO: Find a solution so that table maps does not have to be
3115
written several times within a transaction.
3117
if (pending->get_flags(Rows_log_event::STMT_END_F))
3118
++m_table_map_version;
3122
if (file == &log_file)
3124
error= flush_and_sync();
3128
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
3132
pthread_mutex_unlock(&LOCK_log);
3135
thd->binlog_set_pending_rows_event(event);
3141
Write an event to the binary log.
3144
bool MYSQL_BIN_LOG::write(Log_event *event_info)
3146
THD *thd= event_info->thd;
3149
if (thd->binlog_evt_union.do_union)
3152
In Stored function; Remember that function call caused an update.
3153
We will log the function call to the binary log on function exit
3155
thd->binlog_evt_union.unioned_events= true;
3156
thd->binlog_evt_union.unioned_events_trans |= event_info->cache_stmt;
3161
Flush the pending rows event to the transaction cache or to the
3162
log file. Since this function potentially aquire the LOCK_log
3163
mutex, we do this before aquiring the LOCK_log mutex in this
3166
We only end the statement if we are in a top-level statement. If
3167
we are inside a stored function, we do not end the statement since
3168
this will close all tables on the slave.
3170
bool const end_stmt= false;
3171
thd->binlog_flush_pending_rows_event(end_stmt);
3173
pthread_mutex_lock(&LOCK_log);
3176
In most cases this is only called if 'is_open()' is true; in fact this is
3177
mostly called if is_open() *was* true a few instructions before, but it
3178
could have changed since.
3180
if (likely(is_open()))
3182
IO_CACHE *file= &log_file;
3184
In the future we need to add to the following if tests like
3185
"do the involved tables match (to be implemented)
3186
binlog_[wild_]{do|ignore}_table?" (WL#1049)"
3188
const char *local_db= event_info->get_db();
3189
if ((thd && !(thd->options & OPTION_BIN_LOG)) ||
3190
(!binlog_filter->db_ok(local_db)))
3192
VOID(pthread_mutex_unlock(&LOCK_log));
3197
Should we write to the binlog cache or to the binlog on disk?
3198
Write to the binlog cache if:
3199
- it is already not empty (meaning we're in a transaction; note that the
3200
present event could be about a non-transactional table, but still we need
3201
to write to the binlog cache in that case to handle updates to mixed
3202
trans/non-trans table types the best possible in binlogging)
3203
- or if the event asks for it (cache_stmt == TRUE).
3205
if (opt_using_transactions && thd)
3207
if (thd->binlog_setup_trx_data())
3210
binlog_trx_data *const trx_data=
3211
(binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
3212
IO_CACHE *trans_log= &trx_data->trans_log;
3213
my_off_t trans_log_pos= my_b_tell(trans_log);
3214
if (event_info->get_cache_stmt() || trans_log_pos != 0)
3216
if (trans_log_pos == 0)
3217
thd->binlog_start_trans_and_stmt();
3221
TODO as Mats suggested, for all the cases above where we write to
3222
trans_log, it sounds unnecessary to lock LOCK_log. We should rather
3223
test first if we want to write to trans_log, and if not, lock
3229
No check for auto events flag here - this write method should
3230
never be called if auto-events are enabled
3234
1. Write first log events which describe the 'run environment'
3239
If row-based binlogging, Insert_id, Rand and other kind of "setting
3240
context" events are not needed.
3244
if (!thd->current_stmt_binlog_row_based)
3246
if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
3248
Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT,
3249
thd->first_successful_insert_id_in_prev_stmt_for_binlog);
3253
if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0)
3256
If the auto_increment was second in a table's index (possible with
3257
MyISAM or BDB) (table->next_number_keypart != 0), such event is
3258
in fact not necessary. We could avoid logging it.
3260
Intvar_log_event e(thd, (uchar) INSERT_ID_EVENT,
3261
thd->auto_inc_intervals_in_cur_stmt_for_binlog.
3268
Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2);
3272
if (thd->user_var_events.elements)
3274
for (uint i= 0; i < thd->user_var_events.elements; i++)
3276
BINLOG_USER_VAR_EVENT *user_var_event;
3277
get_dynamic(&thd->user_var_events,(uchar*) &user_var_event, i);
3278
User_var_log_event e(thd, user_var_event->user_var_event->name.str,
3279
user_var_event->user_var_event->name.length,
3280
user_var_event->value,
3281
user_var_event->length,
3282
user_var_event->type,
3283
user_var_event->charset_number);
3292
Write the SQL command
3295
if (event_info->write(file))
3298
if (file == &log_file) // we are writing to the real log (disk)
3300
if (flush_and_sync())
3303
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
3310
if (my_errno == EFBIG)
3311
my_message(ER_TRANS_CACHE_FULL, ER(ER_TRANS_CACHE_FULL), MYF(0));
3313
my_error(ER_ERROR_ON_WRITE, MYF(0), name, errno);
3318
if (event_info->flags & LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F)
3319
++m_table_map_version;
3321
pthread_mutex_unlock(&LOCK_log);
3326
int error_log_print(enum loglevel level, const char *format,
3329
return logger.error_log_print(level, format, args);
3333
bool slow_log_print(THD *thd, const char *query, uint query_length,
3334
ulonglong current_utime)
3336
return logger.slow_log_print(thd, query, query_length, current_utime);
3340
bool LOGGER::log_command(THD *thd, enum enum_server_command command)
3343
Log command if we have at least one log event handler enabled and want
3344
to log this king of commands
3346
if (*general_log_handler_list && (what_to_log & (1L << (uint) command)))
3348
if (thd->options & OPTION_LOG_OFF)
3361
bool general_log_print(THD *thd, enum enum_server_command command,
3362
const char *format, ...)
3367
/* Print the message to the buffer if we want to log this king of commands */
3368
if (! logger.log_command(thd, command))
3371
va_start(args, format);
3372
error= logger.general_log_print(thd, command, format, args);
3378
bool general_log_write(THD *thd, enum enum_server_command command,
3379
const char *query, uint query_length)
3381
/* Write the message to the log if we want to log this king of commands */
3382
if (logger.log_command(thd, command))
3383
return logger.general_log_write(thd, command, query, query_length);
3388
void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
3390
if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
3391
pthread_mutex_lock(&LOCK_log);
3392
if ((flags & RP_FORCE_ROTATE) ||
3393
(my_b_tell(&log_file) >= (my_off_t) max_size))
3395
new_file_without_locking();
3396
#ifdef HAVE_REPLICATION
3397
if (expire_logs_days)
3399
time_t purge_time= my_time(0) - expire_logs_days*24*60*60;
3400
if (purge_time >= 0)
3401
purge_logs_before_date(purge_time);
3405
if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
3406
pthread_mutex_unlock(&LOCK_log);
3409
uint MYSQL_BIN_LOG::next_file_id()
3412
pthread_mutex_lock(&LOCK_log);
3414
pthread_mutex_unlock(&LOCK_log);
3420
Write the contents of a cache to the binary log.
3424
cache Cache to write to the binary log
3425
lock_log True if the LOCK_log mutex should be aquired, false otherwise
3426
sync_log True if the log should be flushed and sync:ed
3429
Write the contents of the cache to the binary log. The cache will
3430
be reset as a READ_CACHE to be able to read the contents from it.
3433
int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
3435
Mutex_sentry sentry(lock_log ? &LOCK_log : NULL);
3437
if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
3438
return ER_ERROR_ON_WRITE;
3439
uint length= my_b_bytes_in_cache(cache), group, carry, hdr_offs;
3441
uchar header[LOG_EVENT_HEADER_LEN];
3444
The events in the buffer have incorrect end_log_pos data
3445
(relative to beginning of group rather than absolute),
3446
so we'll recalculate them in situ so the binlog is always
3447
correct, even in the middle of a group. This is possible
3448
because we now know the start position of the group (the
3449
offset of this cache in the log, if you will); all we need
3450
to do is to find all event-headers, and add the position of
3451
the group to the end_log_pos of each event. This is pretty
3452
straight forward, except that we read the cache in segments,
3453
so an event-header might end up on the cache-border and get
3457
group= (uint)my_b_tell(&log_file);
3464
if we only got a partial header in the last iteration,
3465
get the other half now and process a full header.
3467
if (unlikely(carry > 0))
3469
assert(carry < LOG_EVENT_HEADER_LEN);
3471
/* assemble both halves */
3472
memcpy(&header[carry], (char *)cache->read_pos, LOG_EVENT_HEADER_LEN - carry);
3474
/* fix end_log_pos */
3475
val= uint4korr(&header[LOG_POS_OFFSET]) + group;
3476
int4store(&header[LOG_POS_OFFSET], val);
3478
/* write the first half of the split header */
3479
if (my_b_write(&log_file, header, carry))
3480
return ER_ERROR_ON_WRITE;
3483
copy fixed second half of header to cache so the correct
3484
version will be written later.
3486
memcpy((char *)cache->read_pos, &header[carry], LOG_EVENT_HEADER_LEN - carry);
3488
/* next event header at ... */
3489
hdr_offs = uint4korr(&header[EVENT_LEN_OFFSET]) - carry;
3494
/* if there is anything to write, process it. */
3496
if (likely(length > 0))
3499
process all event-headers in this (partial) cache.
3500
if next header is beyond current read-buffer,
3501
we'll get it later (though not necessarily in the
3502
very next iteration, just "eventually").
3505
while (hdr_offs < length)
3508
partial header only? save what we can get, process once
3512
if (hdr_offs + LOG_EVENT_HEADER_LEN > length)
3514
carry= length - hdr_offs;
3515
memcpy(header, (char *)cache->read_pos + hdr_offs, carry);
3520
/* we've got a full event-header, and it came in one piece */
3522
uchar *log_pos= (uchar *)cache->read_pos + hdr_offs + LOG_POS_OFFSET;
3524
/* fix end_log_pos */
3525
val= uint4korr(log_pos) + group;
3526
int4store(log_pos, val);
3528
/* next event header at ... */
3529
log_pos= (uchar *)cache->read_pos + hdr_offs + EVENT_LEN_OFFSET;
3530
hdr_offs += uint4korr(log_pos);
3536
Adjust hdr_offs. Note that it may still point beyond the segment
3537
read in the next iteration; if the current event is very long,
3538
it may take a couple of read-iterations (and subsequent adjustments
3539
of hdr_offs) for it to point into the then-current segment.
3540
If we have a split header (!carry), hdr_offs will be set at the
3541
beginning of the next iteration, overwriting the value we set here:
3546
/* Write data to the binary log file */
3547
if (my_b_write(&log_file, cache->read_pos, length))
3548
return ER_ERROR_ON_WRITE;
3549
cache->read_pos=cache->read_end; // Mark buffer used up
3550
} while ((length= my_b_fill(cache)));
3561
Write a cached log entry to the binary log.
3562
- To support transaction over replication, we wrap the transaction
3563
with BEGIN/COMMIT or BEGIN/ROLLBACK in the binary log.
3564
We want to write a BEGIN/ROLLBACK block when a non-transactional table
3565
was updated in a transaction which was rolled back. This is to ensure
3566
that the same updates are run on the slave.
3569
@param cache The cache to copy to the binlog
3570
@param commit_event The commit event to print after writing the
3571
contents of the cache.
3574
We only come here if there is something in the cache.
3576
The thing in the cache is always a complete transaction.
3578
'cache' needs to be reinitialized after this functions returns.
3581
bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
3583
VOID(pthread_mutex_lock(&LOCK_log));
3585
/* NULL would represent nothing to replicate after ROLLBACK */
3586
assert(commit_event != NULL);
3589
if (likely(is_open())) // Should always be true
3592
We only bother to write to the binary log if there is anything
3595
if (my_b_tell(cache) > 0)
3598
Log "BEGIN" at the beginning of every transaction. Here, a
3599
transaction is either a BEGIN..COMMIT block or a single
3600
statement in autocommit mode.
3602
Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), true, false);
3604
Imagine this is rollback due to net timeout, after all
3605
statements of the transaction succeeded. Then we want a
3606
zero-error code in BEGIN. In other words, if there was a
3607
really serious error code it's already in the statement's
3608
events, there is no need to put it also in this internally
3609
generated event, and as this event is generated late it would
3610
lead to false alarms.
3612
This is safer than thd->clear_error() against kills at shutdown.
3614
qinfo.error_code= 0;
3616
Now this Query_log_event has artificial log_pos 0. It must be
3617
adjusted to reflect the real position in the log. Not doing it
3618
would confuse the slave: it would prevent this one from
3619
knowing where he is in the master's binlog, which would result
3620
in wrong positions being shown to the user, MASTER_POS_WAIT
3623
if (qinfo.write(&log_file))
3626
if ((write_error= write_cache(cache, false, false)))
3629
if (commit_event && commit_event->write(&log_file))
3631
if (flush_and_sync())
3633
if (cache->error) // Error on read
3635
sql_print_error(ER(ER_ERROR_ON_READ), cache->file_name, errno);
3636
write_error=1; // Don't give more errors
3643
if commit_event is Xid_log_event, increase the number of
3644
prepared_xids (it's decreasd in ::unlog()). Binlog cannot be rotated
3645
if there're prepared xids in it - see the comment in new_file() for
3647
If the commit_event is not Xid_log_event (then it's a Query_log_event)
3648
rotate binlog, if necessary.
3650
if (commit_event && commit_event->get_type_code() == XID_EVENT)
3652
pthread_mutex_lock(&LOCK_prep_xids);
3654
pthread_mutex_unlock(&LOCK_prep_xids);
3657
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
3659
VOID(pthread_mutex_unlock(&LOCK_log));
3667
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
3669
VOID(pthread_mutex_unlock(&LOCK_log));
3675
Wait until we get a signal that the relay log has been updated
3677
@param[in] thd a THD struct
3679
LOCK_log must be taken before calling this function.
3680
It will be released at the end of the function.
3683
void MYSQL_BIN_LOG::wait_for_update_relay_log(THD* thd)
3685
const char *old_msg;
3686
old_msg= thd->enter_cond(&update_cond, &LOCK_log,
3687
"Slave has read all relay log; "
3688
"waiting for the slave I/O "
3689
"thread to update it" );
3690
pthread_cond_wait(&update_cond, &LOCK_log);
3691
thd->exit_cond(old_msg);
3697
Wait until we get a signal that the binary log has been updated.
3698
Applies to master only.
3701
@param[in] thd a THD struct
3702
@param[in] timeout a pointer to a timespec;
3703
NULL means to wait w/o timeout.
3704
@retval 0 if got signalled on update
3705
@retval non-0 if wait timeout elapsed
3707
LOCK_log must be taken before calling this function.
3708
LOCK_log is being released while the thread is waiting.
3709
LOCK_log is released by the caller.
3712
int MYSQL_BIN_LOG::wait_for_update_bin_log(THD* thd,
3713
const struct timespec *timeout)
3716
const char* old_msg = thd->proc_info;
3717
old_msg= thd->enter_cond(&update_cond, &LOCK_log,
3718
"Master has sent all binlog to slave; "
3719
"waiting for binlog to be updated");
3721
pthread_cond_wait(&update_cond, &LOCK_log);
3723
ret= pthread_cond_timedwait(&update_cond, &LOCK_log,
3724
const_cast<struct timespec *>(timeout));
3732
@param exiting Bitmask for one or more of the following bits:
3733
- LOG_CLOSE_INDEX : if we should close the index file
3734
- LOG_CLOSE_TO_BE_OPENED : if we intend to call open
3735
at once after close.
3736
- LOG_CLOSE_STOP_EVENT : write a 'stop' event to the log
3739
One can do an open on the object at once after doing a close.
3740
The internal structures are not freed until cleanup() is called
3743
void MYSQL_BIN_LOG::close(uint exiting)
3744
{ // One can't set log_type here!
3745
if (log_state == LOG_OPENED)
3747
#ifdef HAVE_REPLICATION
3748
if (log_type == LOG_BIN && !no_auto_events &&
3749
(exiting & LOG_CLOSE_STOP_EVENT))
3753
bytes_written+= s.data_written;
3756
#endif /* HAVE_REPLICATION */
3758
/* don't pwrite in a file opened with O_APPEND - it doesn't work */
3759
if (log_file.type == WRITE_CACHE && log_type == LOG_BIN)
3761
my_off_t offset= BIN_LOG_HEADER_SIZE + FLAGS_OFFSET;
3762
uchar flags= 0; // clearing LOG_EVENT_BINLOG_IN_USE_F
3763
pwrite(log_file.file, &flags, 1, offset);
3766
/* this will cleanup IO_CACHE, sync and close the file */
3767
MYSQL_LOG::close(exiting);
3771
The following test is needed even if is_open() is not set, as we may have
3772
called a not complete close earlier and the index file is still open.
3775
if ((exiting & LOG_CLOSE_INDEX) && my_b_inited(&index_file))
3777
end_io_cache(&index_file);
3778
if (my_close(index_file.file, MYF(0)) < 0 && ! write_error)
3781
sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno);
3784
log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
3790
void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg)
3793
We need to take locks, otherwise this may happen:
3794
new_file() is called, calls open(old_max_size), then before open() starts,
3795
set_max_size() sets max_size to max_size_arg, then open() starts and
3796
uses the old_max_size argument, so max_size_arg has been overwritten and
3797
it's like if the SET command was never run.
3799
pthread_mutex_lock(&LOCK_log);
3801
max_size= max_size_arg;
3802
pthread_mutex_unlock(&LOCK_log);
3808
Check if a string is a valid number.
3810
@param str String to test
3811
@param res Store value here
3812
@param allow_wildcards Set to 1 if we should ignore '%' and '_'
3815
For the moment the allow_wildcards argument is not used
3816
Should be move to some other file.
3819
1 String is a number
3824
static bool test_if_number(register const char *str,
3825
long *res, bool allow_wildcards)
3832
while (*str++ == ' ') ;
3833
if (*--str == '-' || *str == '+')
3835
while (my_isdigit(files_charset_info,*str) ||
3836
(allow_wildcards && (*str == wild_many || *str == wild_one)))
3844
my_isdigit(files_charset_info,*str) ||
3845
(allow_wildcards && (*str == wild_many || *str == wild_one)) ;
3848
if (*str != 0 || flag == 0)
3852
return(1); /* Number ok */
3853
} /* test_if_number */
3856
void sql_perror(const char *message)
3858
#ifdef HAVE_STRERROR
3859
sql_print_error("%s: %s",message, strerror(errno));
3866
bool flush_error_log()
3871
char err_renamed[FN_REFLEN], *end;
3872
end= strmake(err_renamed,log_error_file,FN_REFLEN-4);
3873
strmov(end, "-old");
3874
VOID(pthread_mutex_lock(&LOCK_error_log));
3875
char err_temp[FN_REFLEN+4];
3877
On Windows is necessary a temporary file for to rename
3878
the current error file.
3880
strxmov(err_temp, err_renamed,"-tmp",NullS);
3881
(void) my_delete(err_temp, MYF(0));
3882
if (freopen(err_temp,"a+",stdout))
3888
freopen(err_temp,"a+",stderr);
3889
(void) my_delete(err_renamed, MYF(0));
3890
my_rename(log_error_file,err_renamed,MYF(0));
3891
if (freopen(log_error_file,"a+",stdout))
3892
freopen(log_error_file,"a+",stderr);
3894
if ((fd = my_open(err_temp, O_RDONLY, MYF(0))) >= 0)
3896
while ((bytes= my_read(fd, buf, IO_SIZE, MYF(0))) &&
3897
bytes != MY_FILE_ERROR)
3898
my_fwrite(stderr, buf, bytes, MYF(0));
3899
my_close(fd, MYF(0));
3901
(void) my_delete(err_temp, MYF(0));
3905
VOID(pthread_mutex_unlock(&LOCK_error_log));
3910
void MYSQL_BIN_LOG::signal_update()
3912
pthread_cond_broadcast(&update_cond);
3917
Prints a printf style message to the error log and, under NT, to the
3920
This function prints the message into a buffer and then sends that buffer
3921
to other functions to write that message to other logging sources.
3923
@param event_type Type of event to write (Error, Warning, or Info)
3924
@param format Printf style format of message
3925
@param args va_list list of arguments for the message
3928
The function always returns 0. The return value is present in the
3929
signature to be compatible with other logging routines, which could
3930
return an error (e.g. logging to the log tables)
3932
static void print_buffer_to_file(enum loglevel level,
3933
int error_code __attribute__((__unused__)),
3935
size_t buffer_length __attribute__((__unused__)))
3941
VOID(pthread_mutex_lock(&LOCK_error_log));
3944
localtime_r(&skr, &tm_tmp);
3947
fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d [%s] %s\n",
3948
start->tm_year % 100,
3954
(level == ERROR_LEVEL ? "ERROR" : level == WARNING_LEVEL ?
3955
"Warning" : "Note"),
3960
VOID(pthread_mutex_unlock(&LOCK_error_log));
3965
int vprint_msg_to_log(enum loglevel level, const char *format, va_list args)
3969
int error_code= errno;
3971
length= vsnprintf(buff, sizeof(buff), format, args);
3973
print_buffer_to_file(level, error_code, buff, length);
3979
void sql_print_error(const char *format, ...)
3983
va_start(args, format);
3984
error_log_print(ERROR_LEVEL, format, args);
3991
void sql_print_warning(const char *format, ...)
3995
va_start(args, format);
3996
error_log_print(WARNING_LEVEL, format, args);
4003
void sql_print_information(const char *format, ...)
4007
va_start(args, format);
4008
error_log_print(INFORMATION_LEVEL, format, args);
4015
/********* transaction coordinator log for 2pc - mmap() based solution *******/
4018
the log consists of a file, mmapped to a memory.
4019
file is divided on pages of tc_log_page_size size.
4020
(usable size of the first page is smaller because of log header)
4021
there's PAGE control structure for each page
4022
each page (or rather PAGE control structure) can be in one of three
4023
states - active, syncing, pool.
4024
there could be only one page in active or syncing states,
4025
but many in pool - pool is fifo queue.
4026
usual lifecycle of a page is pool->active->syncing->pool
4027
"active" page - is a page where new xid's are logged.
4028
the page stays active as long as syncing slot is taken.
4029
"syncing" page is being synced to disk. no new xid can be added to it.
4030
when the sync is done the page is moved to a pool and an active page
4033
the result of such an architecture is a natural "commit grouping" -
4034
If commits are coming faster than the system can sync, they do not
4035
stall. Instead, all commit that came since the last sync are
4036
logged to the same page, and they all are synced with the next -
4037
one - sync. Thus, thought individual commits are delayed, throughput
4040
when a xid is added to an active page, the thread of this xid waits
4041
for a page's condition until the page is synced. when syncing slot
4042
becomes vacant one of these waiters is awaken to take care of syncing.
4043
it syncs the page and signals all waiters that the page is synced.
4044
PAGE::waiters is used to count these waiters, and a page may never
4045
become active again until waiters==0 (that is all waiters from the
4046
previous sync have noticed the sync was completed)
4048
note, that the page becomes "dirty" and has to be synced only when a
4049
new xid is added into it. Removing a xid from a page does not make it
4050
dirty - we don't sync removals to disk.
4053
ulong tc_log_page_waits= 0;
4057
#define TC_LOG_HEADER_SIZE (sizeof(tc_log_magic)+1)
4059
static const char tc_log_magic[]={(char) 254, 0x23, 0x05, 0x74};
4061
ulong opt_tc_log_size= TC_LOG_MIN_SIZE;
4062
ulong tc_log_max_pages_used=0, tc_log_page_size=0, tc_log_cur_pages_used=0;
4064
int TC_LOG_MMAP::open(const char *opt_name)
4067
bool crashed= false;
4070
assert(total_ha_2pc > 1);
4071
assert(opt_name && opt_name[0]);
4073
tc_log_page_size= my_getpagesize();
4074
assert(TC_LOG_PAGE_SIZE % tc_log_page_size == 0);
4076
fn_format(logname,opt_name,mysql_data_home,"",MY_UNPACK_FILENAME);
4077
if ((fd= my_open(logname, O_RDWR, MYF(0))) < 0)
4079
if (my_errno != ENOENT)
4081
if (using_heuristic_recover())
4083
if ((fd= my_create(logname, CREATE_MODE, O_RDWR, MYF(MY_WME))) < 0)
4086
file_length= opt_tc_log_size;
4087
if (ftruncate(fd, file_length))
4094
sql_print_information("Recovering after a crash using %s", opt_name);
4095
if (tc_heuristic_recover)
4097
sql_print_error("Cannot perform automatic crash recovery when "
4098
"--tc-heuristic-recover is used");
4101
file_length= my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE));
4102
if (file_length == MY_FILEPOS_ERROR || file_length % tc_log_page_size)
4106
data= (uchar *)my_mmap(0, (size_t)file_length, PROT_READ|PROT_WRITE,
4107
MAP_NOSYNC|MAP_SHARED, fd, 0);
4108
if (data == MAP_FAILED)
4115
npages=(uint)file_length/tc_log_page_size;
4116
assert(npages >= 3); // to guarantee non-empty pool
4117
if (!(pages=(PAGE *)my_malloc(npages*sizeof(PAGE), MYF(MY_WME|MY_ZEROFILL))))
4120
for (pg=pages, i=0; i < npages; i++, pg++)
4125
pthread_mutex_init(&pg->lock, MY_MUTEX_INIT_FAST);
4126
pthread_cond_init (&pg->cond, 0);
4127
pg->start=(my_xid *)(data + i*tc_log_page_size);
4129
pg->end=(my_xid *)(pg->start + tc_log_page_size);
4130
pg->size=pg->free=tc_log_page_size/sizeof(my_xid);
4132
pages[0].size=pages[0].free=
4133
(tc_log_page_size-TC_LOG_HEADER_SIZE)/sizeof(my_xid);
4134
pages[0].start=pages[0].end-pages[0].size;
4135
pages[npages-1].next=0;
4138
if (crashed && recover())
4141
memcpy(data, tc_log_magic, sizeof(tc_log_magic));
4142
data[sizeof(tc_log_magic)]= (uchar)total_ha_2pc;
4143
msync(data, tc_log_page_size, MS_SYNC);
4144
my_sync(fd, MYF(0));
4147
pthread_mutex_init(&LOCK_sync, MY_MUTEX_INIT_FAST);
4148
pthread_mutex_init(&LOCK_active, MY_MUTEX_INIT_FAST);
4149
pthread_mutex_init(&LOCK_pool, MY_MUTEX_INIT_FAST);
4150
pthread_cond_init(&COND_active, 0);
4151
pthread_cond_init(&COND_pool, 0);
4158
pool_last=pages+npages-1;
4168
there is no active page, let's got one from the pool.
4170
Two strategies here:
4171
-# take the first from the pool
4172
-# if there're waiters - take the one with the most free space.
4175
TODO page merging. try to allocate adjacent page first,
4176
so that they can be flushed both in one sync
4179
void TC_LOG_MMAP::get_active_from_pool()
4181
PAGE **p, **best_p=0;
4185
pthread_mutex_lock(&LOCK_pool);
4190
if ((*p)->waiters == 0) // can the first page be used ?
4191
break; // yes - take it.
4193
best_free=0; // no - trying second strategy
4194
for (p=&(*p)->next; *p; p=&(*p)->next)
4196
if ((*p)->waiters == 0 && (*p)->free > best_free)
4198
best_free=(*p)->free;
4203
while ((*best_p == 0 || best_free == 0) && overflow());
4206
if (active->free == active->size) // we've chosen an empty page
4208
tc_log_cur_pages_used++;
4209
set_if_bigger(tc_log_max_pages_used, tc_log_cur_pages_used);
4212
if ((*best_p)->next) // unlink the page from the pool
4213
*best_p=(*best_p)->next;
4218
pthread_mutex_unlock(&LOCK_pool);
4223
perhaps, increase log size ?
4225
int TC_LOG_MMAP::overflow()
4228
simple overflow handling - just wait
4229
TODO perhaps, increase log size ?
4230
let's check the behaviour of tc_log_page_waits first
4232
tc_log_page_waits++;
4233
pthread_cond_wait(&COND_pool, &LOCK_pool);
4234
return 1; // always return 1
4238
Record that transaction XID is committed on the persistent storage.
4240
This function is called in the middle of two-phase commit:
4241
First all resources prepare the transaction, then tc_log->log() is called,
4242
then all resources commit the transaction, then tc_log->unlog() is called.
4244
All access to active page is serialized but it's not a problem, as
4245
we're assuming that fsync() will be a main bottleneck.
4246
That is, parallelizing writes to log pages we'll decrease number of
4247
threads waiting for a page, but then all these threads will be waiting
4248
for a fsync() anyway
4250
If tc_log == MYSQL_LOG then tc_log writes transaction to binlog and
4251
records XID in a special Xid_log_event.
4252
If tc_log = TC_LOG_MMAP then xid is written in a special memory-mapped
4258
\# - otherwise, "cookie", a number that will be passed as an argument
4259
to unlog() call. tc_log can define it any way it wants,
4260
and use for whatever purposes. TC_LOG_MMAP sets it
4261
to the position in memory where xid was logged to.
4264
int TC_LOG_MMAP::log_xid(THD *thd __attribute__((__unused__)), my_xid xid)
4270
pthread_mutex_lock(&LOCK_active);
4273
if active page is full - just wait...
4274
frankly speaking, active->free here accessed outside of mutex
4275
protection, but it's safe, because it only means we may miss an
4276
unlog() for the active page, and we're not waiting for it here -
4277
unlog() does not signal COND_active.
4279
while (unlikely(active && active->free == 0))
4280
pthread_cond_wait(&COND_active, &LOCK_active);
4282
/* no active page ? take one from the pool */
4284
get_active_from_pool();
4287
pthread_mutex_lock(&p->lock);
4289
/* searching for an empty slot */
4293
assert(p->ptr < p->end); // because p->free > 0
4296
/* found! store xid there and mark the page dirty */
4297
cookie= (ulong)((uchar *)p->ptr - data); // can never be zero
4302
/* to sync or not to sync - this is the question */
4303
pthread_mutex_unlock(&LOCK_active);
4304
pthread_mutex_lock(&LOCK_sync);
4305
pthread_mutex_unlock(&p->lock);
4308
{ // somebody's syncing. let's wait
4311
note - it must be while (), not do ... while () here
4312
as p->state may be not DIRTY when we come here
4314
while (p->state == DIRTY && syncing)
4315
pthread_cond_wait(&p->cond, &LOCK_sync);
4317
err= p->state == ERROR;
4318
if (p->state != DIRTY) // page was synced
4320
if (p->waiters == 0)
4321
pthread_cond_signal(&COND_pool); // in case somebody's waiting
4322
pthread_mutex_unlock(&LOCK_sync);
4323
goto done; // we're done
4325
} // page was not synced! do it now
4326
assert(active == p && syncing == 0);
4327
pthread_mutex_lock(&LOCK_active);
4328
syncing=p; // place is vacant - take it
4329
active=0; // page is not active anymore
4330
pthread_cond_broadcast(&COND_active); // in case somebody's waiting
4331
pthread_mutex_unlock(&LOCK_active);
4332
pthread_mutex_unlock(&LOCK_sync);
4336
return err ? 0 : cookie;
4339
int TC_LOG_MMAP::sync()
4343
assert(syncing != active);
4346
sit down and relax - this can take a while...
4347
note - no locks are held at this point
4349
err= msync(syncing->start, 1, MS_SYNC);
4351
err= my_sync(fd, MYF(0));
4353
/* page is synced. let's move it to the pool */
4354
pthread_mutex_lock(&LOCK_pool);
4355
pool_last->next=syncing;
4358
syncing->state= err ? ERROR : POOL;
4359
pthread_cond_broadcast(&syncing->cond); // signal "sync done"
4360
pthread_cond_signal(&COND_pool); // in case somebody's waiting
4361
pthread_mutex_unlock(&LOCK_pool);
4363
/* marking 'syncing' slot free */
4364
pthread_mutex_lock(&LOCK_sync);
4366
pthread_cond_signal(&active->cond); // wake up a new syncer
4367
pthread_mutex_unlock(&LOCK_sync);
4372
erase xid from the page, update page free space counters/pointers.
4373
cookie points directly to the memory where xid was logged.
4376
void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid __attribute__((__unused__)))
4378
PAGE *p=pages+(cookie/tc_log_page_size);
4379
my_xid *x=(my_xid *)(data+cookie);
4382
assert(x >= p->start && x < p->end);
4385
pthread_mutex_lock(&p->lock);
4387
assert(p->free <= p->size);
4388
set_if_smaller(p->ptr, x);
4389
if (p->free == p->size) // the page is completely empty
4390
statistic_decrement(tc_log_cur_pages_used, &LOCK_status);
4391
if (p->waiters == 0) // the page is in pool and ready to rock
4392
pthread_cond_signal(&COND_pool); // ping ... for overflow()
4393
pthread_mutex_unlock(&p->lock);
4396
void TC_LOG_MMAP::close()
4401
pthread_mutex_destroy(&LOCK_sync);
4402
pthread_mutex_destroy(&LOCK_active);
4403
pthread_mutex_destroy(&LOCK_pool);
4404
pthread_cond_destroy(&COND_pool);
4406
data[0]='A'; // garble the first (signature) byte, in case my_delete fails
4408
for (i=0; i < npages; i++)
4410
if (pages[i].ptr == 0)
4412
pthread_mutex_destroy(&pages[i].lock);
4413
pthread_cond_destroy(&pages[i].cond);
4416
my_free((uchar*)pages, MYF(0));
4418
my_munmap((char*)data, (size_t)file_length);
4420
my_close(fd, MYF(0));
4422
if (inited>=5) // cannot do in the switch because of Windows
4423
my_delete(logname, MYF(MY_WME));
4427
int TC_LOG_MMAP::recover()
4430
PAGE *p=pages, *end_p=pages+npages;
4432
if (memcmp(data, tc_log_magic, sizeof(tc_log_magic)))
4434
sql_print_error("Bad magic header in tc log");
4439
the first byte after magic signature is set to current
4440
number of storage engines on startup
4442
if (data[sizeof(tc_log_magic)] != total_ha_2pc)
4444
sql_print_error("Recovery failed! You must enable "
4445
"exactly %d storage engines that support "
4446
"two-phase commit protocol",
4447
data[sizeof(tc_log_magic)]);
4451
if (hash_init(&xids, &my_charset_bin, tc_log_page_size/3, 0,
4452
sizeof(my_xid), 0, 0, MYF(0)))
4455
for ( ; p < end_p ; p++)
4457
for (my_xid *x=p->start; x < p->end; x++)
4458
if (*x && my_hash_insert(&xids, (uchar *)x))
4462
if (ha_recover(&xids))
4466
bzero(data, (size_t)file_length);
4472
sql_print_error("Crash recovery failed. Either correct the problem "
4473
"(if it's, for example, out of memory error) and restart, "
4474
"or delete tc log and start mysqld with "
4475
"--tc-heuristic-recover={commit|rollback}");
4481
TC_LOG_DUMMY tc_log_dummy;
4482
TC_LOG_MMAP tc_log_mmap;
4485
Perform heuristic recovery, if --tc-heuristic-recover was used.
4488
no matter whether heuristic recovery was successful or not
4489
mysqld must exit. So, return value is the same in both cases.
4492
0 no heuristic recovery was requested
4494
1 heuristic recovery was performed
4497
int TC_LOG::using_heuristic_recover()
4499
if (!tc_heuristic_recover)
4502
sql_print_information("Heuristic crash recovery mode");
4504
sql_print_error("Heuristic crash recovery failed");
4505
sql_print_information("Please restart mysqld without --tc-heuristic-recover");
4509
/****** transaction coordinator log for 2pc - binlog() based solution ******/
4510
#define TC_LOG_BINLOG MYSQL_BIN_LOG
4514
keep in-memory list of prepared transactions
4515
(add to list in log(), remove on unlog())
4516
and copy it to the new binlog if rotated
4517
but let's check the behaviour of tc_log_page_waits first!
4520
int TC_LOG_BINLOG::open(const char *opt_name)
4525
assert(total_ha_2pc > 1);
4526
assert(opt_name && opt_name[0]);
4528
pthread_mutex_init(&LOCK_prep_xids, MY_MUTEX_INIT_FAST);
4529
pthread_cond_init (&COND_prep_xids, 0);
4531
if (!my_b_inited(&index_file))
4533
/* There was a failure to open the index file, can't open the binlog */
4538
if (using_heuristic_recover())
4540
/* generate a new binlog to mask a corrupted one */
4541
open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0);
4546
if ((error= find_log_pos(&log_info, NullS, 1)))
4548
if (error != LOG_INFO_EOF)
4549
sql_print_error("find_log_pos() failed (error: %d)", error);
4560
Format_description_log_event fdle(BINLOG_VERSION);
4561
char log_name[FN_REFLEN];
4563
if (! fdle.is_valid())
4568
strmake(log_name, log_info.log_file_name, sizeof(log_name)-1);
4569
} while (!(error= find_next_log(&log_info, 1)));
4571
if (error != LOG_INFO_EOF)
4573
sql_print_error("find_log_pos() failed (error: %d)", error);
4577
if ((file= open_binlog(&log, log_name, &errmsg)) < 0)
4579
sql_print_error("%s", errmsg);
4583
if ((ev= Log_event::read_log_event(&log, 0, &fdle)) &&
4584
ev->get_type_code() == FORMAT_DESCRIPTION_EVENT &&
4585
ev->flags & LOG_EVENT_BINLOG_IN_USE_F)
4587
sql_print_information("Recovering after a crash using %s", opt_name);
4588
error= recover(&log, (Format_description_log_event *)ev);
4595
my_close(file, MYF(MY_WME));
4605
/** This is called on shutdown, after ha_panic. */
4606
void TC_LOG_BINLOG::close()
4608
assert(prepared_xids==0);
4609
pthread_mutex_destroy(&LOCK_prep_xids);
4610
pthread_cond_destroy (&COND_prep_xids);
4622
int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid)
4624
Xid_log_event xle(thd, xid);
4625
binlog_trx_data *trx_data=
4626
(binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
4628
We always commit the entire transaction when writing an XID. Also
4629
note that the return value is inverted.
4631
return(!binlog_end_trans(thd, trx_data, &xle, true));
4634
void TC_LOG_BINLOG::unlog(ulong cookie __attribute__((__unused__)),
4635
my_xid xid __attribute__((__unused__)))
4637
pthread_mutex_lock(&LOCK_prep_xids);
4638
assert(prepared_xids > 0);
4639
if (--prepared_xids == 0) {
4640
pthread_cond_signal(&COND_prep_xids);
4642
pthread_mutex_unlock(&LOCK_prep_xids);
4643
rotate_and_purge(0); // as ::write() did not rotate
4646
int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
4652
if (! fdle->is_valid() ||
4653
hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
4654
sizeof(my_xid), 0, 0, MYF(0)))
4657
init_alloc_root(&mem_root, TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE);
4659
fdle->flags&= ~LOG_EVENT_BINLOG_IN_USE_F; // abort on the first error
4661
while ((ev= Log_event::read_log_event(log,0,fdle)) && ev->is_valid())
4663
if (ev->get_type_code() == XID_EVENT)
4665
Xid_log_event *xev=(Xid_log_event *)ev;
4666
uchar *x= (uchar *) memdup_root(&mem_root, (uchar*) &xev->xid,
4670
my_hash_insert(&xids, x);
4675
if (ha_recover(&xids))
4678
free_root(&mem_root, MYF(0));
4683
free_root(&mem_root, MYF(0));
4686
sql_print_error("Crash recovery failed. Either correct the problem "
4687
"(if it's, for example, out of memory error) and restart, "
4688
"or delete (or rename) binary log and start mysqld with "
4689
"--tc-heuristic-recover={commit|rollback}");
4694
#ifdef INNODB_COMPATIBILITY_HOOKS
4696
Get the file name of the MySQL binlog.
4697
@return the name of the binlog file
4700
const char* mysql_bin_log_file_name(void)
4702
return mysql_bin_log.get_log_fname();
4705
Get the current position of the MySQL binlog.
4706
@return byte offset from the beginning of the binlog
4709
ulonglong mysql_bin_log_file_pos(void)
4711
return (ulonglong) mysql_bin_log.get_log_file()->pos_in_file;
4713
#endif /* INNODB_COMPATIBILITY_HOOKS */
4716
struct st_mysql_storage_engine binlog_storage_engine=
4717
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
4719
mysql_declare_plugin(binlog)
4721
MYSQL_STORAGE_ENGINE_PLUGIN,
4722
&binlog_storage_engine,
4725
"This is a pseudo storage engine to represent the binlog in a transaction",
4727
binlog_init, /* Plugin Init */
4728
NULL, /* Plugin Deinit */
4730
NULL, /* status variables */
4731
NULL, /* system variables */
4732
NULL /* config options */
4734
mysql_declare_plugin_end;