MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
log.cc
Go to the documentation of this file.
1 /* Copyright (c) 2000, 2013 Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 
27 #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
28 #include "sql_priv.h"
29 #include "log.h"
30 #include "sql_base.h" // open_log_table
31 #include "sql_delete.h" // mysql_truncate
32 #include "sql_parse.h" // command_name
33 #include "sql_time.h" // calc_time_from_sec, my_time_compare
34 #include "tztime.h" // my_tz_OFFSET0, struct Time_zone
35 #include "sql_acl.h" // SUPER_ACL
36 #include "sql_audit.h"
38 
39 #include <my_dir.h>
40 #include <stdarg.h>
41 #include <m_ctype.h> // For test_if_number
42 
43 #ifdef _WIN32
44 #include "message.h"
45 #endif
46 
47 using std::min;
48 using std::max;
49 
50 /* max size of the log message */
51 #define MAX_LOG_BUFFER_SIZE 1024
52 #define MAX_TIME_SIZE 32
53 
54 static
55 const TABLE_FIELD_TYPE slow_query_log_table_fields[SQLT_FIELD_COUNT] =
56 {
57  {
58  { C_STRING_WITH_LEN("start_time") },
59  { C_STRING_WITH_LEN("timestamp") },
60  { NULL, 0 }
61  },
62  {
63  { C_STRING_WITH_LEN("user_host") },
64  { C_STRING_WITH_LEN("mediumtext") },
65  { C_STRING_WITH_LEN("utf8") }
66  },
67  {
68  { C_STRING_WITH_LEN("query_time") },
69  { C_STRING_WITH_LEN("time") },
70  { NULL, 0 }
71  },
72  {
73  { C_STRING_WITH_LEN("lock_time") },
74  { C_STRING_WITH_LEN("time") },
75  { NULL, 0 }
76  },
77  {
78  { C_STRING_WITH_LEN("rows_sent") },
79  { C_STRING_WITH_LEN("int(11)") },
80  { NULL, 0 }
81  },
82  {
83  { C_STRING_WITH_LEN("rows_examined") },
84  { C_STRING_WITH_LEN("int(11)") },
85  { NULL, 0 }
86  },
87  {
88  { C_STRING_WITH_LEN("db") },
89  { C_STRING_WITH_LEN("varchar(512)") },
90  { C_STRING_WITH_LEN("utf8") }
91  },
92  {
93  { C_STRING_WITH_LEN("last_insert_id") },
94  { C_STRING_WITH_LEN("int(11)") },
95  { NULL, 0 }
96  },
97  {
98  { C_STRING_WITH_LEN("insert_id") },
99  { C_STRING_WITH_LEN("int(11)") },
100  { NULL, 0 }
101  },
102  {
103  { C_STRING_WITH_LEN("server_id") },
104  { C_STRING_WITH_LEN("int(10) unsigned") },
105  { NULL, 0 }
106  },
107  {
108  { C_STRING_WITH_LEN("sql_text") },
109  { C_STRING_WITH_LEN("mediumtext") },
110  { C_STRING_WITH_LEN("utf8") }
111  },
112  {
113  { C_STRING_WITH_LEN("thread_id") },
114  { C_STRING_WITH_LEN("bigint(21) unsigned") },
115  { NULL, 0 }
116  }
117 };
118 
119 static const TABLE_FIELD_DEF
120  slow_query_log_table_def= {SQLT_FIELD_COUNT, slow_query_log_table_fields};
121 
123 {
124 protected:
125  void report_error(uint, const char *fmt, ...)
126  {
127  va_list args;
128  va_start(args, fmt);
129  error_log_print(ERROR_LEVEL, fmt, args);
130  va_end(args);
131  }
132 };
133 
135 static Slow_query_log_table_intact sqlt_intact;
136 
137 static
138 const TABLE_FIELD_TYPE general_log_table_fields[GLT_FIELD_COUNT] =
139 {
140  {
141  { C_STRING_WITH_LEN("event_time") },
142  { C_STRING_WITH_LEN("timestamp") },
143  { NULL, 0 }
144  },
145  {
146  { C_STRING_WITH_LEN("user_host") },
147  { C_STRING_WITH_LEN("mediumtext") },
148  { C_STRING_WITH_LEN("utf8") }
149  },
150  {
151  { C_STRING_WITH_LEN("thread_id") },
152  { C_STRING_WITH_LEN("bigint(21) unsigned") },
153  { NULL, 0 }
154  },
155  {
156  { C_STRING_WITH_LEN("server_id") },
157  { C_STRING_WITH_LEN("int(10) unsigned") },
158  { NULL, 0 }
159  },
160  {
161  { C_STRING_WITH_LEN("command_type") },
162  { C_STRING_WITH_LEN("varchar(64)") },
163  { C_STRING_WITH_LEN("utf8") }
164  },
165  {
166  { C_STRING_WITH_LEN("argument") },
167  { C_STRING_WITH_LEN("mediumtext") },
168  { C_STRING_WITH_LEN("utf8") }
169  }
170 };
171 
172 static const TABLE_FIELD_DEF
173  general_log_table_def= {GLT_FIELD_COUNT, general_log_table_fields};
174 
176 {
177 protected:
178  void report_error(uint, const char *fmt, ...)
179  {
180  va_list args;
181  va_start(args, fmt);
182  error_log_print(ERROR_LEVEL, fmt, args);
183  va_end(args);
184  }
185 };
186 
188 static General_log_table_intact glt_intact;
189 
190 LOGGER logger;
191 
192 static bool test_if_number(const char *str,
193  ulong *res, bool allow_wildcards);
194 
205 {
206  uint errcode= 0;
207 
208  switch (res) {
209  case 0: break;
210  case LOG_INFO_EOF: errcode= ER_UNKNOWN_TARGET_BINLOG; break;
211  case LOG_INFO_IO: errcode= ER_IO_ERR_LOG_INDEX_READ; break;
212  case LOG_INFO_INVALID:errcode= ER_BINLOG_PURGE_PROHIBITED; break;
213  case LOG_INFO_SEEK: errcode= ER_FSEEK_FAIL; break;
214  case LOG_INFO_MEM: errcode= ER_OUT_OF_RESOURCES; break;
215  case LOG_INFO_FATAL: errcode= ER_BINLOG_PURGE_FATAL_ERR; break;
216  case LOG_INFO_IN_USE: errcode= ER_LOG_IN_USE; break;
217  case LOG_INFO_EMFILE: errcode= ER_BINLOG_PURGE_EMFILE; break;
218  default: errcode= ER_LOG_PURGE_UNKNOWN_ERR; break;
219  }
220 
221  return errcode;
222 }
223 
231 class Silence_log_table_errors : public Internal_error_handler
232 {
233  char m_message[MYSQL_ERRMSG_SIZE];
234 public:
236  {
237  m_message[0]= '\0';
238  }
239 
240  virtual ~Silence_log_table_errors() {}
241 
242  virtual bool handle_condition(THD *thd,
243  uint sql_errno,
244  const char* sql_state,
245  Sql_condition::enum_warning_level level,
246  const char* msg,
247  Sql_condition ** cond_hdl);
248  const char *message() const { return m_message; }
249 };
250 
251 bool
252 Silence_log_table_errors::handle_condition(THD *,
253  uint,
254  const char*,
255  Sql_condition::enum_warning_level,
256  const char* msg,
257  Sql_condition ** cond_hdl)
258 {
259  *cond_hdl= NULL;
260  strmake(m_message, msg, sizeof(m_message)-1);
261  return TRUE;
262 }
263 
264 sql_print_message_func sql_print_message_handlers[3] =
265 {
266  sql_print_information,
267  sql_print_warning,
268  sql_print_error
269 };
270 
283 char *make_log_name(char *buff, const char *name, const char* log_ext)
284 {
285  strmake(buff, name, FN_REFLEN-5);
286  return fn_format(buff, buff, mysql_real_data_home, log_ext,
287  MYF(MY_UNPACK_FILENAME|MY_REPLACE_EXT));
288 }
289 
290 bool LOGGER::is_log_table_enabled(uint log_table_type)
291 {
292  switch (log_table_type) {
293  case QUERY_LOG_SLOW:
294  return (table_log_handler != NULL) && opt_slow_log;
295  case QUERY_LOG_GENERAL:
296  return (table_log_handler != NULL) && opt_log ;
297  default:
298  DBUG_ASSERT(0);
299  return FALSE; /* make compiler happy */
300  }
301 }
302 
303 
304 /* Check if a given table is opened log table */
305 int check_if_log_table(size_t db_len, const char *db, size_t table_name_len,
306  const char *table_name, bool check_if_opened)
307 {
308  if (db_len == 5 &&
309  !(lower_case_table_names ?
310  my_strcasecmp(system_charset_info, db, "mysql") :
311  strcmp(db, "mysql")))
312  {
313  if (table_name_len == 11 && !(lower_case_table_names ?
314  my_strcasecmp(system_charset_info,
315  table_name, "general_log") :
316  strcmp(table_name, "general_log")))
317  {
318  if (!check_if_opened || logger.is_log_table_enabled(QUERY_LOG_GENERAL))
319  return QUERY_LOG_GENERAL;
320  return 0;
321  }
322 
323  if (table_name_len == 8 && !(lower_case_table_names ?
324  my_strcasecmp(system_charset_info, table_name, "slow_log") :
325  strcmp(table_name, "slow_log")))
326  {
327  if (!check_if_opened || logger.is_log_table_enabled(QUERY_LOG_SLOW))
328  return QUERY_LOG_SLOW;
329  return 0;
330  }
331  }
332  return 0;
333 }
334 
335 
336 Log_to_csv_event_handler::Log_to_csv_event_handler()
337 {
338 }
339 
340 
341 Log_to_csv_event_handler::~Log_to_csv_event_handler()
342 {
343 }
344 
345 
346 void Log_to_csv_event_handler::cleanup()
347 {
348  logger.is_log_tables_initialized= FALSE;
349 }
350 
351 /* log event handlers */
352 
384  log_general(THD *thd, time_t event_time, const char *user_host,
385  uint user_host_len, my_thread_id thread_id,
386  const char *command_type, uint command_type_len,
387  const char *sql_text, uint sql_text_len,
388  const CHARSET_INFO *client_cs)
389 {
390  TABLE_LIST table_list;
391  TABLE *table;
392  bool result= TRUE;
393  bool need_close= FALSE;
394  bool need_pop= FALSE;
395  bool need_rnd_end= FALSE;
396  uint field_index;
397  Silence_log_table_errors error_handler;
398  Open_tables_backup open_tables_backup;
399  ulonglong save_thd_options;
400  bool save_time_zone_used;
401 
402  /*
403  CSV uses TIME_to_timestamp() internally if table needs to be repaired
404  which will set thd->time_zone_used
405  */
406  save_time_zone_used= thd->time_zone_used;
407 
408  save_thd_options= thd->variables.option_bits;
409  thd->variables.option_bits&= ~OPTION_BIN_LOG;
410 
411  table_list.init_one_table(MYSQL_SCHEMA_NAME.str, MYSQL_SCHEMA_NAME.length,
412  GENERAL_LOG_NAME.str, GENERAL_LOG_NAME.length,
413  GENERAL_LOG_NAME.str,
414  TL_WRITE_CONCURRENT_INSERT);
415 
416  /*
417  1) open_log_table generates an error if the
418  table can not be opened or is corrupted.
419  2) "INSERT INTO general_log" can generate warning sometimes.
420 
421  Suppress these warnings and errors, they can't be dealt with
422  properly anyway.
423 
424  QQ: this problem needs to be studied in more detail.
425  Comment this 2 lines and run "cast.test" to see what's happening.
426  */
427  thd->push_internal_handler(& error_handler);
428  need_pop= TRUE;
429 
430  if (!(table= open_log_table(thd, &table_list, &open_tables_backup)))
431  goto err;
432 
433  need_close= TRUE;
434 
435  if (glt_intact.check(table_list.table, &general_log_table_def))
436  goto err;
437 
438  if (table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE) ||
439  table->file->ha_rnd_init(0))
440  goto err;
441 
442  need_rnd_end= TRUE;
443 
444  /* Honor next number columns if present */
445  table->next_number_field= table->found_next_number_field;
446 
447  /*
448  NOTE: we do not call restore_record() here, as all fields are
449  filled by the Logger (=> no need to load default ones).
450  */
451 
452  /*
453  We do not set a value for table->field[0], as it will use
454  default value (which is CURRENT_TIMESTAMP).
455  */
456 
457  /* check that all columns exist */
458  if (table->s->fields < 6)
459  goto err;
460 
461  DBUG_ASSERT(table->field[GLT_FIELD_EVENT_TIME]->type() == MYSQL_TYPE_TIMESTAMP);
462  table->field[GLT_FIELD_EVENT_TIME]->store_timestamp(event_time);
463 
464  /* do a write */
465  if (table->field[GLT_FIELD_USER_HOST]->store(user_host, user_host_len,
466  client_cs) ||
467  table->field[GLT_FIELD_THREAD_ID]->store((longlong) thread_id, TRUE) ||
468  table->field[GLT_FIELD_SERVER_ID]->store((longlong) server_id, TRUE) ||
469  table->field[GLT_FIELD_COMMAND_TYPE]->store(command_type,
470  command_type_len, client_cs))
471  goto err;
472 
473  /*
474  A positive return value in store() means truncation.
475  Still logging a message in the log in this case.
476  */
477  table->field[GLT_FIELD_ARGUMENT]->flags|= FIELDFLAG_HEX_ESCAPE;
478  if (table->field[GLT_FIELD_ARGUMENT]->store(sql_text, sql_text_len,
479  client_cs) < 0)
480  goto err;
481 
482  /* mark all fields as not null */
483  table->field[GLT_FIELD_USER_HOST]->set_notnull();
484  table->field[GLT_FIELD_THREAD_ID]->set_notnull();
485  table->field[GLT_FIELD_SERVER_ID]->set_notnull();
486  table->field[GLT_FIELD_COMMAND_TYPE]->set_notnull();
487  table->field[GLT_FIELD_ARGUMENT]->set_notnull();
488 
489  /* Set any extra columns to their default values */
490  for (field_index= GLT_FIELD_COUNT ;
491  field_index < table->s->fields ;
492  field_index++)
493  {
494  table->field[field_index]->set_default();
495  }
496 
497  /* log table entries are not replicated */
498  if (table->file->ha_write_row(table->record[0]))
499  goto err;
500 
501  result= FALSE;
502 
503 err:
504  if (result && !thd->killed)
505  sql_print_error("Failed to write to mysql.general_log: %s",
506  error_handler.message());
507 
508  if (need_rnd_end)
509  {
510  table->file->ha_rnd_end();
511  table->file->ha_release_auto_increment();
512  }
513  if (need_pop)
514  thd->pop_internal_handler();
515  if (need_close)
516  close_log_table(thd, &open_tables_backup);
517 
518  thd->variables.option_bits= save_thd_options;
519  thd->time_zone_used= save_time_zone_used;
520  return result;
521 }
522 
523 
524 /*
525  Log a query to the slow log table
526 
527  SYNOPSIS
528  log_slow()
529  thd THD of the query
530  current_time current timestamp
531  query_start_arg command start timestamp
532  user_host the pointer to the string with user@host info
533  user_host_len length of the user_host string. this is computed once
534  and passed to all general log event handlers
535  query_time Amount of time the query took to execute (in microseconds)
536  lock_time Amount of time the query was locked (in microseconds)
537  is_command The flag, which determines, whether the sql_text is a
538  query or an administrator command (these are treated
539  differently by the old logging routines)
540  sql_text the very text of the query or administrator command
541  processed
542  sql_text_len the length of sql_text string
543 
544  DESCRIPTION
545 
546  Log a query to the slow log table
547 
548  RETURN
549  FALSE - OK
550  TRUE - error occured
551 */
552 
553 bool Log_to_csv_event_handler::
554  log_slow(THD *thd, time_t current_time, time_t query_start_arg,
555  const char *user_host, uint user_host_len,
556  ulonglong query_utime, ulonglong lock_utime, bool is_command,
557  const char *sql_text, uint sql_text_len)
558 {
559  TABLE_LIST table_list;
560  TABLE *table;
561  bool result= TRUE;
562  bool need_close= FALSE;
563  bool need_rnd_end= FALSE;
564  Silence_log_table_errors error_handler;
565  Open_tables_backup open_tables_backup;
566  const CHARSET_INFO *client_cs= thd->variables.character_set_client;
567  bool save_time_zone_used;
568  DBUG_ENTER("Log_to_csv_event_handler::log_slow");
569 
570  thd->push_internal_handler(& error_handler);
571  /*
572  CSV uses TIME_to_timestamp() internally if table needs to be repaired
573  which will set thd->time_zone_used
574  */
575  save_time_zone_used= thd->time_zone_used;
576 
577  table_list.init_one_table(MYSQL_SCHEMA_NAME.str, MYSQL_SCHEMA_NAME.length,
578  SLOW_LOG_NAME.str, SLOW_LOG_NAME.length,
579  SLOW_LOG_NAME.str,
580  TL_WRITE_CONCURRENT_INSERT);
581 
582  if (!(table= open_log_table(thd, &table_list, &open_tables_backup)))
583  goto err;
584 
585  need_close= TRUE;
586 
587  if (sqlt_intact.check(table_list.table, &slow_query_log_table_def))
588  goto err;
589 
590  if (table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE) ||
591  table->file->ha_rnd_init(0))
592  goto err;
593 
594  need_rnd_end= TRUE;
595 
596  /* Honor next number columns if present */
597  table->next_number_field= table->found_next_number_field;
598 
599  restore_record(table, s->default_values); // Get empty record
600 
601  /* store the time and user values */
602  DBUG_ASSERT(table->field[SQLT_FIELD_START_TIME]->type() == MYSQL_TYPE_TIMESTAMP);
603  table->field[SQLT_FIELD_START_TIME]->store_timestamp(current_time);
604  if (table->field[SQLT_FIELD_USER_HOST]->store(user_host, user_host_len,
605  client_cs))
606  goto err;
607 
608  if (query_start_arg)
609  {
610  longlong query_time= (longlong) (query_utime/1000000);
611  longlong lock_time= (longlong) (lock_utime/1000000);
612  /*
613  A TIME field can not hold the full longlong range; query_time or
614  lock_time may be truncated without warning here, if greater than
615  839 hours (~35 days)
616  */
617  MYSQL_TIME t;
618  t.neg= 0;
619 
620  /* fill in query_time field */
621  calc_time_from_sec(&t, min<long>(query_time, (longlong) TIME_MAX_VALUE_SECONDS), 0);
622  if (table->field[SQLT_FIELD_QUERY_TIME]->store_time(&t))
623  goto err;
624  /* lock_time */
625  calc_time_from_sec(&t, min<long>(lock_time, (longlong) TIME_MAX_VALUE_SECONDS), 0);
626  if (table->field[SQLT_FIELD_LOCK_TIME]->store_time(&t))
627  goto err;
628  /* rows_sent */
629  if (table->field[SQLT_FIELD_ROWS_SENT]->store((longlong) thd->get_sent_row_count(), TRUE))
630  goto err;
631  /* rows_examined */
632  if (table->field[SQLT_FIELD_ROWS_EXAMINED]->store((longlong) thd->get_examined_row_count(), TRUE))
633  goto err;
634  }
635  else
636  {
637  table->field[SQLT_FIELD_QUERY_TIME]->set_null();
638  table->field[SQLT_FIELD_LOCK_TIME]->set_null();
639  table->field[SQLT_FIELD_ROWS_SENT]->set_null();
640  table->field[SQLT_FIELD_ROWS_EXAMINED]->set_null();
641  }
642  /* fill database field */
643  if (thd->db)
644  {
645  if (table->field[SQLT_FIELD_DATABASE]->store(thd->db, thd->db_length,
646  client_cs))
647  goto err;
648  table->field[SQLT_FIELD_DATABASE]->set_notnull();
649  }
650 
651  if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
652  {
653  if (table->
654  field[SQLT_FIELD_LAST_INSERT_ID]->store((longlong)
655  thd->first_successful_insert_id_in_prev_stmt_for_binlog,
656  TRUE))
657  goto err;
658  table->field[SQLT_FIELD_LAST_INSERT_ID]->set_notnull();
659  }
660 
661  /*
662  Set value if we do an insert on autoincrement column. Note that for
663  some engines (those for which get_auto_increment() does not leave a
664  table lock until the statement ends), this is just the first value and
665  the next ones used may not be contiguous to it.
666  */
667  if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0)
668  {
669  if (table->
670  field[SQLT_FIELD_INSERT_ID]->store((longlong)
671  thd->auto_inc_intervals_in_cur_stmt_for_binlog.minimum(), TRUE))
672  goto err;
673  table->field[SQLT_FIELD_INSERT_ID]->set_notnull();
674  }
675 
676  if (table->field[SQLT_FIELD_SERVER_ID]->store((longlong) server_id, TRUE))
677  goto err;
678  table->field[SQLT_FIELD_SERVER_ID]->set_notnull();
679 
680  /*
681  Column sql_text.
682  A positive return value in store() means truncation.
683  Still logging a message in the log in this case.
684  */
685  if (table->field[SQLT_FIELD_SQL_TEXT]->store(sql_text, sql_text_len,
686  client_cs) < 0)
687  goto err;
688 
689  if (table->field[SQLT_FIELD_THREAD_ID]->store((longlong) thd->thread_id,
690  TRUE))
691  goto err;
692 
693  /* log table entries are not replicated */
694  if (table->file->ha_write_row(table->record[0]))
695  goto err;
696 
697  result= FALSE;
698 
699 err:
700  thd->pop_internal_handler();
701 
702  if (result && !thd->killed)
703  sql_print_error("Failed to write to mysql.slow_log: %s",
704  error_handler.message());
705 
706  if (need_rnd_end)
707  {
708  table->file->ha_rnd_end();
709  table->file->ha_release_auto_increment();
710  }
711  if (need_close)
712  close_log_table(thd, &open_tables_backup);
713  thd->time_zone_used= save_time_zone_used;
714  DBUG_RETURN(result);
715 }
716 
717 int Log_to_csv_event_handler::
718  activate_log(THD *thd, uint log_table_type)
719 {
720  TABLE_LIST table_list;
721  TABLE *table;
722  LEX_STRING *UNINIT_VAR(log_name);
723  int result;
724  Open_tables_backup open_tables_backup;
725 
726  DBUG_ENTER("Log_to_csv_event_handler::activate_log");
727 
728  if (log_table_type == QUERY_LOG_GENERAL)
729  {
730  log_name= &GENERAL_LOG_NAME;
731  }
732  else
733  {
734  DBUG_ASSERT(log_table_type == QUERY_LOG_SLOW);
735 
736  log_name= &SLOW_LOG_NAME;
737  }
738  table_list.init_one_table(MYSQL_SCHEMA_NAME.str, MYSQL_SCHEMA_NAME.length,
739  log_name->str, log_name->length, log_name->str,
740  TL_WRITE_CONCURRENT_INSERT);
741 
742  table= open_log_table(thd, &table_list, &open_tables_backup);
743  if (table)
744  {
745  result= 0;
746  close_log_table(thd, &open_tables_backup);
747  }
748  else
749  result= 1;
750 
751  DBUG_RETURN(result);
752 }
753 
754 bool Log_to_csv_event_handler::
755  log_error(enum loglevel level, const char *format, va_list args)
756 {
757  /* No log table is implemented */
758  DBUG_ASSERT(0);
759  return FALSE;
760 }
761 
762 bool Log_to_file_event_handler::
763  log_error(enum loglevel level, const char *format,
764  va_list args)
765 {
766  return vprint_msg_to_log(level, format, args);
767 }
768 
769 void Log_to_file_event_handler::init_pthread_objects()
770 {
771  mysql_log.init_pthread_objects();
772  mysql_slow_log.init_pthread_objects();
773 }
774 
775 
779  log_slow(THD *thd, time_t current_time, time_t query_start_arg,
780  const char *user_host, uint user_host_len,
781  ulonglong query_utime, ulonglong lock_utime, bool is_command,
782  const char *sql_text, uint sql_text_len)
783 {
784  Silence_log_table_errors error_handler;
785  thd->push_internal_handler(&error_handler);
786  bool retval= mysql_slow_log.write(thd, current_time, query_start_arg,
787  user_host, user_host_len,
788  query_utime, lock_utime, is_command,
789  sql_text, sql_text_len);
790  thd->pop_internal_handler();
791  return retval;
792 }
793 
794 
801  log_general(THD *thd, time_t event_time, const char *user_host,
802  uint user_host_len, my_thread_id thread_id,
803  const char *command_type, uint command_type_len,
804  const char *sql_text, uint sql_text_len,
805  const CHARSET_INFO *client_cs)
806 {
807  Silence_log_table_errors error_handler;
808  thd->push_internal_handler(&error_handler);
809  bool retval= mysql_log.write(event_time, user_host, user_host_len,
810  thread_id, command_type, command_type_len,
811  sql_text, sql_text_len);
812  thd->pop_internal_handler();
813  return retval;
814 }
815 
816 
817 bool Log_to_file_event_handler::init()
818 {
819  if (!is_initialized)
820  {
821  if (opt_slow_log)
822  mysql_slow_log.open_slow_log(opt_slow_logname);
823 
824  if (opt_log)
825  mysql_log.open_query_log(opt_logname);
826 
827  is_initialized= TRUE;
828  }
829 
830  return FALSE;
831 }
832 
833 
834 void Log_to_file_event_handler::cleanup()
835 {
836  mysql_log.cleanup();
837  mysql_slow_log.cleanup();
838 }
839 
840 void Log_to_file_event_handler::flush()
841 {
842  /* reopen log files */
843  if (opt_log)
844  mysql_log.reopen_file();
845  if (opt_slow_log)
846  mysql_slow_log.reopen_file();
847 }
848 
849 /*
850  Log error with all enabled log event handlers
851 
852  SYNOPSIS
853  error_log_print()
854 
855  level The level of the error significance: NOTE,
856  WARNING or ERROR.
857  format format string for the error message
858  args list of arguments for the format string
859 
860  RETURN
861  FALSE - OK
862  TRUE - error occured
863 */
864 
865 bool LOGGER::error_log_print(enum loglevel level, const char *format,
866  va_list args)
867 {
868  bool error= FALSE;
869  Log_event_handler **current_handler;
870 
871  /* currently we don't need locking here as there is no error_log table */
872  for (current_handler= error_log_handler_list ; *current_handler ;)
873  error= (*current_handler++)->log_error(level, format, args) || error;
874 
875  return error;
876 }
877 
878 
879 void LOGGER::cleanup_base()
880 {
881  DBUG_ASSERT(inited == 1);
882  mysql_rwlock_destroy(&LOCK_logger);
883  if (table_log_handler)
884  {
885  table_log_handler->cleanup();
886  delete table_log_handler;
887  table_log_handler= NULL;
888  }
889  if (file_log_handler)
890  file_log_handler->cleanup();
891 }
892 
893 
894 void LOGGER::cleanup_end()
895 {
896  DBUG_ASSERT(inited == 1);
897  if (file_log_handler)
898  {
899  delete file_log_handler;
900  file_log_handler=NULL;
901  }
902  inited= 0;
903 }
904 
905 
911 {
912  DBUG_ASSERT(inited == 0);
913  inited= 1;
914 
915  /*
916  Here we create file log handler. We don't do it for the table log handler
917  here as it cannot be created so early. The reason is THD initialization,
918  which depends on the system variables (parsed later).
919  */
920  if (!file_log_handler)
921  file_log_handler= new Log_to_file_event_handler;
922 
923  /* by default we use traditional error log */
924  init_error_log(LOG_FILE);
925 
926  file_log_handler->init_pthread_objects();
927  mysql_rwlock_init(key_rwlock_LOCK_logger, &LOCK_logger);
928 }
929 
930 
931 void LOGGER::init_log_tables()
932 {
933  if (!table_log_handler)
934  table_log_handler= new Log_to_csv_event_handler;
935 
936  if (!is_log_tables_initialized &&
937  !table_log_handler->init() && !file_log_handler->init())
938  is_log_tables_initialized= TRUE;
939 }
940 
941 
942 bool LOGGER::flush_logs(THD *thd)
943 {
944  int rc= 0;
945 
946  /*
947  Now we lock logger, as nobody should be able to use logging routines while
948  log tables are closed
949  */
950  logger.lock_exclusive();
951 
952  /* reopen log files */
953  file_log_handler->flush();
954 
955  /* end of log flush */
956  logger.unlock();
957  return rc;
958 }
959 
960 
967 {
968  /*
969  Now we lock logger, as nobody should be able to use logging routines while
970  log tables are closed
971  */
972  logger.lock_exclusive();
973 
974  /* Reopen slow log file */
975  if (opt_slow_log)
976  file_log_handler->get_mysql_slow_log()->reopen_file();
977 
978  /* End of log flush */
979  logger.unlock();
980 
981  return 0;
982 }
983 
984 
991 {
992  /*
993  Now we lock logger, as nobody should be able to use logging routines while
994  log tables are closed
995  */
996  logger.lock_exclusive();
997 
998  /* Reopen general log file */
999  if (opt_log)
1000  file_log_handler->get_mysql_log()->reopen_file();
1001 
1002  /* End of log flush */
1003  logger.unlock();
1004 
1005  return 0;
1006 }
1007 
1008 
1009 /*
1010  Log slow query with all enabled log event handlers
1011 
1012  SYNOPSIS
1013  slow_log_print()
1014 
1015  thd THD of the query being logged
1016  query The query being logged
1017  query_length The length of the query string
1018 
1019  RETURN
1020  FALSE OK
1021  TRUE error occured
1022 */
1023 
1024 bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length)
1025 
1026 {
1027  bool error= FALSE;
1028  Log_event_handler **current_handler;
1029  bool is_command= FALSE;
1030  char user_host_buff[MAX_USER_HOST_SIZE + 1];
1031  Security_context *sctx= thd->security_ctx;
1032  uint user_host_len= 0;
1033  ulonglong query_utime, lock_utime, current_utime;
1034 
1035  DBUG_ASSERT(thd->enable_slow_log);
1036  /*
1037  Print the message to the buffer if we have slow log enabled
1038  */
1039 
1040  if (*slow_log_handler_list)
1041  {
1042  time_t current_time;
1043 
1044  /* do not log slow queries from replication threads */
1045  if (thd->slave_thread && !opt_log_slow_slave_statements)
1046  return 0;
1047 
1048  lock_shared();
1049  if (!opt_slow_log)
1050  {
1051  unlock();
1052  return 0;
1053  }
1054 
1055  /* fill in user_host value: the format is "%s[%s] @ %s [%s]" */
1056  user_host_len= (strxnmov(user_host_buff, MAX_USER_HOST_SIZE,
1057  sctx->priv_user ? sctx->priv_user : "", "[",
1058  sctx->user ? sctx->user : "", "] @ ",
1059  sctx->get_host()->length() ?
1060  sctx->get_host()->ptr() : "", " [",
1061  sctx->get_ip()->length() ? sctx->get_ip()->ptr() :
1062  "", "]", NullS) - user_host_buff);
1063 
1064 
1065  current_utime= thd->current_utime();
1066  current_time= my_time_possible_from_micro(current_utime);
1067  if (thd->start_utime)
1068  {
1069  query_utime= (current_utime - thd->start_utime);
1070  lock_utime= (thd->utime_after_lock - thd->start_utime);
1071  }
1072  else
1073  {
1074  query_utime= lock_utime= 0;
1075  }
1076 
1077  if (!query)
1078  {
1079  is_command= TRUE;
1080  query= command_name[thd->get_command()].str;
1081  query_length= command_name[thd->get_command()].length;
1082  }
1083 
1084  for (current_handler= slow_log_handler_list; *current_handler ;)
1085  error= (*current_handler++)->log_slow(thd, current_time,
1086  thd->start_time.tv_sec,
1087  user_host_buff, user_host_len,
1088  query_utime, lock_utime, is_command,
1089  query, query_length) || error;
1090 
1091  unlock();
1092  }
1093  return error;
1094 }
1095 
1096 bool LOGGER::general_log_write(THD *thd, enum enum_server_command command,
1097  const char *query, uint query_length)
1098 {
1099  bool error= FALSE;
1100  Log_event_handler **current_handler= general_log_handler_list;
1101  char user_host_buff[MAX_USER_HOST_SIZE + 1];
1102  uint user_host_len= 0;
1103  time_t current_time;
1104 
1105  DBUG_ASSERT(thd);
1106 
1107  lock_shared();
1108  if (!opt_log)
1109  {
1110  unlock();
1111  return 0;
1112  }
1113  user_host_len= make_user_name(thd, user_host_buff);
1114 
1115  current_time= my_time(0);
1116 
1117  mysql_audit_general_log(thd, current_time,
1118  user_host_buff, user_host_len,
1119  command_name[(uint) command].str,
1120  command_name[(uint) command].length,
1121  query, query_length);
1122 
1123  while (*current_handler)
1124  error|= (*current_handler++)->
1125  log_general(thd, current_time, user_host_buff,
1126  user_host_len, thd->thread_id,
1127  command_name[(uint) command].str,
1128  command_name[(uint) command].length,
1129  query, query_length,
1130  thd->variables.character_set_client) || error;
1131  unlock();
1132 
1133  return error;
1134 }
1135 
1136 bool LOGGER::general_log_print(THD *thd, enum enum_server_command command,
1137  const char *format, va_list args)
1138 {
1139  uint message_buff_len= 0;
1140  char message_buff[MAX_LOG_BUFFER_SIZE];
1141 
1142  /* prepare message */
1143  if (format)
1144  message_buff_len= my_vsnprintf(message_buff, sizeof(message_buff),
1145  format, args);
1146  else
1147  message_buff[0]= '\0';
1148 
1149  return general_log_write(thd, command, message_buff, message_buff_len);
1150 }
1151 
1152 void LOGGER::init_error_log(uint error_log_printer)
1153 {
1154  if (error_log_printer & LOG_NONE)
1155  {
1156  error_log_handler_list[0]= 0;
1157  return;
1158  }
1159 
1160  switch (error_log_printer) {
1161  case LOG_FILE:
1162  error_log_handler_list[0]= file_log_handler;
1163  error_log_handler_list[1]= 0;
1164  break;
1165  /* these two are disabled for now */
1166  case LOG_TABLE:
1167  DBUG_ASSERT(0);
1168  break;
1169  case LOG_TABLE|LOG_FILE:
1170  DBUG_ASSERT(0);
1171  break;
1172  }
1173 }
1174 
1175 void LOGGER::init_slow_log(uint slow_log_printer)
1176 {
1177  if (slow_log_printer & LOG_NONE)
1178  {
1179  slow_log_handler_list[0]= 0;
1180  return;
1181  }
1182 
1183  switch (slow_log_printer) {
1184  case LOG_FILE:
1185  slow_log_handler_list[0]= file_log_handler;
1186  slow_log_handler_list[1]= 0;
1187  break;
1188  case LOG_TABLE:
1189  slow_log_handler_list[0]= table_log_handler;
1190  slow_log_handler_list[1]= 0;
1191  break;
1192  case LOG_TABLE|LOG_FILE:
1193  slow_log_handler_list[0]= file_log_handler;
1194  slow_log_handler_list[1]= table_log_handler;
1195  slow_log_handler_list[2]= 0;
1196  break;
1197  }
1198 }
1199 
1200 void LOGGER::init_general_log(uint general_log_printer)
1201 {
1202  if (general_log_printer & LOG_NONE)
1203  {
1204  general_log_handler_list[0]= 0;
1205  return;
1206  }
1207 
1208  switch (general_log_printer) {
1209  case LOG_FILE:
1210  general_log_handler_list[0]= file_log_handler;
1211  general_log_handler_list[1]= 0;
1212  break;
1213  case LOG_TABLE:
1214  general_log_handler_list[0]= table_log_handler;
1215  general_log_handler_list[1]= 0;
1216  break;
1217  case LOG_TABLE|LOG_FILE:
1218  general_log_handler_list[0]= file_log_handler;
1219  general_log_handler_list[1]= table_log_handler;
1220  general_log_handler_list[2]= 0;
1221  break;
1222  }
1223 }
1224 
1225 
1226 bool LOGGER::activate_log_handler(THD* thd, uint log_type)
1227 {
1228  MYSQL_QUERY_LOG *file_log;
1229  bool res= FALSE;
1230  lock_exclusive();
1231  switch (log_type) {
1232  case QUERY_LOG_SLOW:
1233  if (!opt_slow_log)
1234  {
1235  file_log= file_log_handler->get_mysql_slow_log();
1236 
1237  file_log->open_slow_log(opt_slow_logname);
1238  if (table_log_handler->activate_log(thd, QUERY_LOG_SLOW))
1239  {
1240  /* Error printed by open table in activate_log() */
1241  res= TRUE;
1242  file_log->close(0);
1243  }
1244  else
1245  {
1246  init_slow_log(log_output_options);
1247  opt_slow_log= TRUE;
1248  }
1249  }
1250  break;
1251  case QUERY_LOG_GENERAL:
1252  if (!opt_log)
1253  {
1254  file_log= file_log_handler->get_mysql_log();
1255 
1256  file_log->open_query_log(opt_logname);
1257  if (table_log_handler->activate_log(thd, QUERY_LOG_GENERAL))
1258  {
1259  /* Error printed by open table in activate_log() */
1260  res= TRUE;
1261  file_log->close(0);
1262  }
1263  else
1264  {
1265  init_general_log(log_output_options);
1266  opt_log= TRUE;
1267  }
1268  }
1269  break;
1270  default:
1271  DBUG_ASSERT(0);
1272  }
1273  unlock();
1274  return res;
1275 }
1276 
1277 
1278 void LOGGER::deactivate_log_handler(THD *thd, uint log_type)
1279 {
1280  my_bool *tmp_opt= 0;
1281  MYSQL_LOG *file_log= NULL;
1282 
1283  switch (log_type) {
1284  case QUERY_LOG_SLOW:
1285  tmp_opt= &opt_slow_log;
1286  file_log= file_log_handler->get_mysql_slow_log();
1287  break;
1288  case QUERY_LOG_GENERAL:
1289  tmp_opt= &opt_log;
1290  file_log= file_log_handler->get_mysql_log();
1291  break;
1292  default:
1293  MY_ASSERT_UNREACHABLE();
1294  }
1295 
1296  if (!(*tmp_opt))
1297  return;
1298 
1299  lock_exclusive();
1300  file_log->close(0);
1301  *tmp_opt= FALSE;
1302  unlock();
1303 }
1304 
1305 
1306 /* the parameters are unused for the log tables */
1307 bool Log_to_csv_event_handler::init()
1308 {
1309  return 0;
1310 }
1311 
1312 int LOGGER::set_handlers(uint error_log_printer,
1313  uint slow_log_printer,
1314  uint general_log_printer)
1315 {
1316  /* error log table is not supported yet */
1317  DBUG_ASSERT(error_log_printer < LOG_TABLE);
1318 
1319  lock_exclusive();
1320 
1321  if ((slow_log_printer & LOG_TABLE || general_log_printer & LOG_TABLE) &&
1322  !is_log_tables_initialized)
1323  {
1324  slow_log_printer= (slow_log_printer & ~LOG_TABLE) | LOG_FILE;
1325  general_log_printer= (general_log_printer & ~LOG_TABLE) | LOG_FILE;
1326 
1327  sql_print_error("Failed to initialize log tables. "
1328  "Falling back to the old-fashioned logs");
1329  }
1330 
1331  init_error_log(error_log_printer);
1332  init_slow_log(slow_log_printer);
1333  init_general_log(general_log_printer);
1334 
1335  unlock();
1336 
1337  return 0;
1338 }
1339 
1340 #ifdef _WIN32
1341 static int eventSource = 0;
1342 
1343 static void setup_windows_event_source()
1344 {
1345  HKEY hRegKey= NULL;
1346  DWORD dwError= 0;
1347  TCHAR szPath[MAX_PATH];
1348  DWORD dwTypes;
1349 
1350  if (eventSource) // Ensure that we are only called once
1351  return;
1352  eventSource= 1;
1353 
1354  // Create the event source registry key
1355  dwError= RegCreateKey(HKEY_LOCAL_MACHINE,
1356  "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\MySQL",
1357  &hRegKey);
1358 
1359  /* Name of the PE module that contains the message resource */
1360  GetModuleFileName(NULL, szPath, MAX_PATH);
1361 
1362  /* Register EventMessageFile */
1363  dwError = RegSetValueEx(hRegKey, "EventMessageFile", 0, REG_EXPAND_SZ,
1364  (PBYTE) szPath, (DWORD) (strlen(szPath) + 1));
1365 
1366  /* Register supported event types */
1367  dwTypes= (EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
1368  EVENTLOG_INFORMATION_TYPE);
1369  dwError= RegSetValueEx(hRegKey, "TypesSupported", 0, REG_DWORD,
1370  (LPBYTE) &dwTypes, sizeof dwTypes);
1371 
1372  RegCloseKey(hRegKey);
1373 }
1374 
1375 #endif /* _WIN32 */
1376 
1391 static int find_uniq_filename(char *name)
1392 {
1393  uint i;
1394  char buff[FN_REFLEN], ext_buf[FN_REFLEN];
1395  struct st_my_dir *dir_info;
1396  reg1 struct fileinfo *file_info;
1397  ulong max_found= 0, next= 0, number= 0;
1398  size_t buf_length, length;
1399  char *start, *end;
1400  int error= 0;
1401  DBUG_ENTER("find_uniq_filename");
1402 
1403  length= dirname_part(buff, name, &buf_length);
1404  start= name + length;
1405  end= strend(start);
1406 
1407  *end='.';
1408  length= (size_t) (end - start + 1);
1409 
1410  if ((DBUG_EVALUATE_IF("error_unique_log_filename", 1,
1411  !(dir_info= my_dir(buff,MYF(MY_DONT_SORT))))))
1412  { // This shouldn't happen
1413  strmov(end,".1"); // use name+1
1414  DBUG_RETURN(1);
1415  }
1416  file_info= dir_info->dir_entry;
1417  for (i= dir_info->number_off_files ; i-- ; file_info++)
1418  {
1419  if (memcmp(file_info->name, start, length) == 0 &&
1420  test_if_number(file_info->name+length, &number,0))
1421  {
1422  set_if_bigger(max_found,(ulong) number);
1423  }
1424  }
1425  my_dirend(dir_info);
1426 
1427  /* check if reached the maximum possible extension number */
1428  if (max_found == MAX_LOG_UNIQUE_FN_EXT)
1429  {
1430  sql_print_error("Log filename extension number exhausted: %06lu. \
1431 Please fix this by archiving old logs and \
1432 updating the index files.", max_found);
1433  error= 1;
1434  goto end;
1435  }
1436 
1437  next= max_found + 1;
1438  if (sprintf(ext_buf, "%06lu", next)<0)
1439  {
1440  error= 1;
1441  goto end;
1442  }
1443  *end++='.';
1444 
1445  /*
1446  Check if the generated extension size + the file name exceeds the
1447  buffer size used. If one did not check this, then the filename might be
1448  truncated, resulting in error.
1449  */
1450  if (((strlen(ext_buf) + (end - name)) >= FN_REFLEN))
1451  {
1452  sql_print_error("Log filename too large: %s%s (%zu). \
1453 Please fix this by archiving old logs and updating the \
1454 index files.", name, ext_buf, (strlen(ext_buf) + (end - name)));
1455  error= 1;
1456  goto end;
1457  }
1458 
1459  if (sprintf(end, "%06lu", next)<0)
1460  {
1461  error= 1;
1462  goto end;
1463  }
1464 
1465  /* print warning if reaching the end of available extensions. */
1466  if ((next > (MAX_LOG_UNIQUE_FN_EXT - LOG_WARN_UNIQUE_FN_EXT_LEFT)))
1467  sql_print_warning("Next log extension: %lu. \
1468 Remaining log filename extensions: %lu. \
1469 Please consider archiving some logs.", next, (MAX_LOG_UNIQUE_FN_EXT - next));
1470 
1471 end:
1472  DBUG_RETURN(error);
1473 }
1474 
1475 
1476 void MYSQL_LOG::init(enum_log_type log_type_arg,
1477  enum cache_type io_cache_type_arg)
1478 {
1479  DBUG_ENTER("MYSQL_LOG::init");
1480  log_type= log_type_arg;
1481  io_cache_type= io_cache_type_arg;
1482  DBUG_PRINT("info",("log_type: %d", log_type));
1483  DBUG_VOID_RETURN;
1484 }
1485 
1486 
1487 bool MYSQL_LOG::init_and_set_log_file_name(const char *log_name,
1488  const char *new_name,
1489  enum_log_type log_type_arg,
1490  enum cache_type io_cache_type_arg)
1491 {
1492  init(log_type_arg, io_cache_type_arg);
1493 
1494  if (new_name && !strmov(log_file_name, new_name))
1495  return TRUE;
1496  else if (!new_name && generate_new_name(log_file_name, log_name))
1497  return TRUE;
1498 
1499  return FALSE;
1500 }
1501 
1502 
1503 /*
1504  Open a (new) log file.
1505 
1506  SYNOPSIS
1507  open()
1508 
1509  log_name The name of the log to open
1510  log_type_arg The type of the log. E.g. LOG_NORMAL
1511  new_name The new name for the logfile. This is only needed
1512  when the method is used to open the binlog file.
1513  io_cache_type_arg The type of the IO_CACHE to use for this log file
1514 
1515  DESCRIPTION
1516  Open the logfile, init IO_CACHE and write startup messages
1517  (in case of general and slow query logs).
1518 
1519  RETURN VALUES
1520  0 ok
1521  1 error
1522 */
1523 
1524 bool MYSQL_LOG::open(
1525 #ifdef HAVE_PSI_INTERFACE
1526  PSI_file_key log_file_key,
1527 #endif
1528  const char *log_name, enum_log_type log_type_arg,
1529  const char *new_name, enum cache_type io_cache_type_arg)
1530 {
1531  char buff[FN_REFLEN];
1532  File file= -1;
1533  my_off_t pos= 0;
1534  int open_flags= O_CREAT | O_BINARY;
1535  DBUG_ENTER("MYSQL_LOG::open");
1536  DBUG_PRINT("enter", ("log_type: %d", (int) log_type_arg));
1537 
1538  write_error= 0;
1539 
1540  if (!(name= my_strdup(log_name, MYF(MY_WME))))
1541  {
1542  name= (char *)log_name; // for the error message
1543  goto err;
1544  }
1545 
1546  if (init_and_set_log_file_name(name, new_name,
1547  log_type_arg, io_cache_type_arg))
1548  goto err;
1549 
1550  if (io_cache_type == SEQ_READ_APPEND)
1551  open_flags |= O_RDWR | O_APPEND;
1552  else
1553  open_flags |= O_WRONLY | (log_type == LOG_BIN ? 0 : O_APPEND);
1554 
1555  db[0]= 0;
1556 
1557 #ifdef HAVE_PSI_INTERFACE
1558  /* Keep the key for reopen */
1559  m_log_file_key= log_file_key;
1560 #endif
1561 
1562  if ((file= mysql_file_open(log_file_key,
1563  log_file_name, open_flags,
1564  MYF(MY_WME | ME_WAITTANG))) < 0)
1565  goto err;
1566 
1567  if ((pos= mysql_file_tell(file, MYF(MY_WME))) == MY_FILEPOS_ERROR)
1568  {
1569  if (my_errno == ESPIPE)
1570  pos= 0;
1571  else
1572  goto err;
1573  }
1574 
1575  if (init_io_cache(&log_file, file, IO_SIZE, io_cache_type, pos, 0,
1576  MYF(MY_WME | MY_NABP |
1577  ((log_type == LOG_BIN) ? MY_WAIT_IF_FULL : 0))))
1578  goto err;
1579 
1580  if (log_type == LOG_NORMAL)
1581  {
1582  char *end;
1583  int len=my_snprintf(buff, sizeof(buff), "%s, Version: %s (%s). "
1584 #ifdef EMBEDDED_LIBRARY
1585  "embedded library\n",
1586  my_progname, server_version, MYSQL_COMPILATION_COMMENT
1587 #elif _WIN32
1588  "started with:\nTCP Port: %d, Named Pipe: %s\n",
1589  my_progname, server_version, MYSQL_COMPILATION_COMMENT,
1590  mysqld_port, mysqld_unix_port
1591 #else
1592  "started with:\nTcp port: %d Unix socket: %s\n",
1593  my_progname, server_version, MYSQL_COMPILATION_COMMENT,
1594  mysqld_port, mysqld_unix_port
1595 #endif
1596  );
1597  end= strnmov(buff + len, "Time Id Command Argument\n",
1598  sizeof(buff) - len);
1599  if (my_b_write(&log_file, (uchar*) buff, (uint) (end-buff)) ||
1600  flush_io_cache(&log_file))
1601  goto err;
1602  }
1603 
1604  log_state= LOG_OPENED;
1605  DBUG_RETURN(0);
1606 
1607 err:
1608  sql_print_error("Could not use %s for logging (error %d). \
1609 Turning logging off for the whole duration of the MySQL server process. \
1610 To turn it on again: fix the cause, \
1611 shutdown the MySQL server and restart it.", name, errno);
1612  if (file >= 0)
1613  mysql_file_close(file, MYF(0));
1614  end_io_cache(&log_file);
1615  my_free(name);
1616  name= NULL;
1617  log_state= LOG_CLOSED;
1618  DBUG_RETURN(1);
1619 }
1620 
1621 MYSQL_LOG::MYSQL_LOG()
1622  : name(0), write_error(FALSE), inited(FALSE), log_type(LOG_UNKNOWN),
1623  log_state(LOG_CLOSED)
1624 #ifdef HAVE_PSI_INTERFACE
1625  , m_key_LOCK_log(key_LOG_LOCK_log)
1626 #endif
1627 {
1628  /*
1629  We don't want to initialize LOCK_Log here as such initialization depends on
1630  safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
1631  called only in main(). Doing initialization here would make it happen
1632  before main().
1633  */
1634  memset(&log_file, 0, sizeof(log_file));
1635 }
1636 
1637 void MYSQL_LOG::init_pthread_objects()
1638 {
1639  DBUG_ASSERT(inited == 0);
1640  inited= 1;
1641  mysql_mutex_init(m_key_LOCK_log, &LOCK_log, MY_MUTEX_INIT_SLOW);
1642 }
1643 
1644 /*
1645  Close the log file
1646 
1647  SYNOPSIS
1648  close()
1649  exiting Bitmask. For the slow and general logs the only used bit is
1650  LOG_CLOSE_TO_BE_OPENED. This is used if we intend to call
1651  open at once after close.
1652 
1653  NOTES
1654  One can do an open on the object at once after doing a close.
1655  The internal structures are not freed until cleanup() is called
1656 */
1657 
1658 void MYSQL_LOG::close(uint exiting)
1659 { // One can't set log_type here!
1660  DBUG_ENTER("MYSQL_LOG::close");
1661  DBUG_PRINT("enter",("exiting: %d", (int) exiting));
1662  if (log_state == LOG_OPENED)
1663  {
1664  end_io_cache(&log_file);
1665 
1666  if (mysql_file_sync(log_file.file, MYF(MY_WME)) && ! write_error)
1667  {
1668  char errbuf[MYSYS_STRERROR_SIZE];
1669  write_error= 1;
1670  sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), name, errno,
1671  my_strerror(errbuf, sizeof(errbuf), errno));
1672  }
1673 
1674  if (mysql_file_close(log_file.file, MYF(MY_WME)) && ! write_error)
1675  {
1676  char errbuf[MYSYS_STRERROR_SIZE];
1677  write_error= 1;
1678  sql_print_error(ER_DEFAULT(ER_ERROR_ON_WRITE), name, errno,
1679  my_strerror(errbuf, sizeof(errbuf), errno));
1680  }
1681  }
1682 
1683  log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
1684  my_free(name);
1685  name= NULL;
1686  DBUG_VOID_RETURN;
1687 }
1688 
1692 {
1693  DBUG_ENTER("cleanup");
1694  if (inited)
1695  {
1696  inited= 0;
1697  mysql_mutex_destroy(&LOCK_log);
1698  close(0);
1699  }
1700  DBUG_VOID_RETURN;
1701 }
1702 
1703 
1704 int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
1705 {
1706  fn_format(new_name, log_name, mysql_data_home, "", 4);
1707  if (log_type == LOG_BIN)
1708  {
1709  if (!fn_ext(log_name)[0])
1710  {
1711  if (find_uniq_filename(new_name))
1712  {
1713  my_printf_error(ER_NO_UNIQUE_LOGFILE, ER(ER_NO_UNIQUE_LOGFILE),
1714  MYF(ME_FATALERROR), log_name);
1715  sql_print_error(ER(ER_NO_UNIQUE_LOGFILE), log_name);
1716  return 1;
1717  }
1718  }
1719  }
1720  return 0;
1721 }
1722 
1723 
1724 /*
1725  Reopen the log file
1726 
1727  SYNOPSIS
1728  reopen_file()
1729 
1730  DESCRIPTION
1731  Reopen the log file. The method is used during FLUSH LOGS
1732  and locks LOCK_log mutex
1733 */
1734 
1735 
1736 void MYSQL_QUERY_LOG::reopen_file()
1737 {
1738  char *save_name;
1739 
1740  DBUG_ENTER("MYSQL_LOG::reopen_file");
1741  if (!is_open())
1742  {
1743  DBUG_PRINT("info",("log is closed"));
1744  DBUG_VOID_RETURN;
1745  }
1746 
1747  mysql_mutex_lock(&LOCK_log);
1748 
1749  save_name= name;
1750  name= 0; // Don't free name
1751  close(LOG_CLOSE_TO_BE_OPENED);
1752 
1753  /*
1754  Note that at this point, log_state != LOG_CLOSED (important for is_open()).
1755  */
1756 
1757  open(
1758 #ifdef HAVE_PSI_INTERFACE
1759  m_log_file_key,
1760 #endif
1761  save_name, log_type, 0, io_cache_type);
1762  my_free(save_name);
1763 
1764  mysql_mutex_unlock(&LOCK_log);
1765 
1766  DBUG_VOID_RETURN;
1767 }
1768 
1769 
1770 /*
1771  Write a command to traditional general log file
1772 
1773  SYNOPSIS
1774  write()
1775 
1776  event_time command start timestamp
1777  user_host the pointer to the string with user@host info
1778  user_host_len length of the user_host string. this is computed once
1779  and passed to all general log event handlers
1780  thread_id Id of the thread, issued a query
1781  command_type the type of the command being logged
1782  command_type_len the length of the string above
1783  sql_text the very text of the query being executed
1784  sql_text_len the length of sql_text string
1785 
1786  DESCRIPTION
1787 
1788  Log given command to to normal (not rotable) log file
1789 
1790  RETURN
1791  FASE - OK
1792  TRUE - error occured
1793 */
1794 
1795 bool MYSQL_QUERY_LOG::write(time_t event_time, const char *user_host,
1796  uint user_host_len, my_thread_id thread_id,
1797  const char *command_type, uint command_type_len,
1798  const char *sql_text, uint sql_text_len)
1799 {
1800  char buff[32];
1801  uint length= 0;
1802  char local_time_buff[MAX_TIME_SIZE];
1803  struct tm start;
1804  uint time_buff_len= 0;
1805 
1806  mysql_mutex_lock(&LOCK_log);
1807 
1808  /* Test if someone closed between the is_open test and lock */
1809  if (is_open())
1810  {
1811  /* for testing output of timestamp and thread id */
1812  DBUG_EXECUTE_IF("reset_log_last_time", last_time= 0;);
1813 
1814  /* Note that my_b_write() assumes it knows the length for this */
1815  if (event_time != last_time)
1816  {
1817  last_time= event_time;
1818 
1819  localtime_r(&event_time, &start);
1820 
1821  time_buff_len= my_snprintf(local_time_buff, MAX_TIME_SIZE,
1822  "%02d%02d%02d %2d:%02d:%02d\t",
1823  start.tm_year % 100, start.tm_mon + 1,
1824  start.tm_mday, start.tm_hour,
1825  start.tm_min, start.tm_sec);
1826 
1827  if (my_b_write(&log_file, (uchar*) local_time_buff, time_buff_len))
1828  goto err;
1829  }
1830  else
1831  if (my_b_write(&log_file, (uchar*) "\t\t" ,2) < 0)
1832  goto err;
1833 
1834  length= my_snprintf(buff, 32, "%5lu ", thread_id);
1835 
1836  if (my_b_write(&log_file, (uchar*) buff, length))
1837  goto err;
1838 
1839  if (my_b_write(&log_file, (uchar*) command_type, command_type_len))
1840  goto err;
1841 
1842  if (my_b_write(&log_file, (uchar*) "\t", 1))
1843  goto err;
1844 
1845  /* sql_text */
1846  if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len))
1847  goto err;
1848 
1849  if (my_b_write(&log_file, (uchar*) "\n", 1) ||
1850  flush_io_cache(&log_file))
1851  goto err;
1852  }
1853 
1854  mysql_mutex_unlock(&LOCK_log);
1855  return FALSE;
1856 err:
1857 
1858  if (!write_error)
1859  {
1860  char errbuf[MYSYS_STRERROR_SIZE];
1861  write_error= 1;
1862  sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno,
1863  my_strerror(errbuf, sizeof(errbuf), errno));
1864  }
1865  mysql_mutex_unlock(&LOCK_log);
1866  return TRUE;
1867 }
1868 
1869 
1870 /*
1871  Log a query to the traditional slow log file
1872 
1873  SYNOPSIS
1874  write()
1875 
1876  thd THD of the query
1877  current_time current timestamp
1878  query_start_arg command start timestamp
1879  user_host the pointer to the string with user@host info
1880  user_host_len length of the user_host string. this is computed once
1881  and passed to all general log event handlers
1882  query_utime Amount of time the query took to execute (in microseconds)
1883  lock_utime Amount of time the query was locked (in microseconds)
1884  is_command The flag, which determines, whether the sql_text is a
1885  query or an administrator command.
1886  sql_text the very text of the query or administrator command
1887  processed
1888  sql_text_len the length of sql_text string
1889 
1890  DESCRIPTION
1891 
1892  Log a query to the slow log file.
1893 
1894  RETURN
1895  FALSE - OK
1896  TRUE - error occured
1897 */
1898 
1899 bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
1900  time_t query_start_arg, const char *user_host,
1901  uint user_host_len, ulonglong query_utime,
1902  ulonglong lock_utime, bool is_command,
1903  const char *sql_text, uint sql_text_len)
1904 {
1905  bool error= 0;
1906  DBUG_ENTER("MYSQL_QUERY_LOG::write");
1907 
1908  mysql_mutex_lock(&LOCK_log);
1909 
1910  if (!is_open())
1911  {
1912  mysql_mutex_unlock(&LOCK_log);
1913  DBUG_RETURN(0);
1914  }
1915 
1916  if (is_open())
1917  { // Safety agains reopen
1918  int tmp_errno= 0;
1919  char buff[80], *end;
1920  char query_time_buff[22+7], lock_time_buff[22+7];
1921  uint buff_len;
1922  end= buff;
1923 
1924  if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
1925  {
1926  if (current_time != last_time)
1927  {
1928  last_time= current_time;
1929  struct tm start;
1930  localtime_r(&current_time, &start);
1931 
1932  buff_len= my_snprintf(buff, sizeof buff,
1933  "# Time: %02d%02d%02d %2d:%02d:%02d\n",
1934  start.tm_year % 100, start.tm_mon + 1,
1935  start.tm_mday, start.tm_hour,
1936  start.tm_min, start.tm_sec);
1937 
1938  /* Note that my_b_write() assumes it knows the length for this */
1939  if (my_b_write(&log_file, (uchar*) buff, buff_len))
1940  tmp_errno= errno;
1941  }
1942  buff_len= my_snprintf(buff, 32, "%5lu", thd->thread_id);
1943  if (my_b_printf(&log_file, "# User@Host: %s Id: %s\n", user_host, buff)
1944  == (uint) -1)
1945  tmp_errno= errno;
1946  }
1947  /* For slow query log */
1948  sprintf(query_time_buff, "%.6f", ulonglong2double(query_utime)/1000000.0);
1949  sprintf(lock_time_buff, "%.6f", ulonglong2double(lock_utime)/1000000.0);
1950  if (my_b_printf(&log_file,
1951  "# Query_time: %s Lock_time: %s"
1952  " Rows_sent: %lu Rows_examined: %lu\n",
1953  query_time_buff, lock_time_buff,
1954  (ulong) thd->get_sent_row_count(),
1955  (ulong) thd->get_examined_row_count()) == (uint) -1)
1956  tmp_errno= errno;
1957  if (thd->db && strcmp(thd->db, db))
1958  { // Database changed
1959  if (my_b_printf(&log_file,"use %s;\n",thd->db) == (uint) -1)
1960  tmp_errno= errno;
1961  strmov(db,thd->db);
1962  }
1963  if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
1964  {
1965  end=strmov(end, ",last_insert_id=");
1966  end=longlong10_to_str((longlong)
1967  thd->first_successful_insert_id_in_prev_stmt_for_binlog,
1968  end, -10);
1969  }
1970  // Save value if we do an insert.
1971  if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0)
1972  {
1973  if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
1974  {
1975  end=strmov(end,",insert_id=");
1976  end=longlong10_to_str((longlong)
1977  thd->auto_inc_intervals_in_cur_stmt_for_binlog.minimum(),
1978  end, -10);
1979  }
1980  }
1981 
1982  /*
1983  This info used to show up randomly, depending on whether the query
1984  checked the query start time or not. now we always write current
1985  timestamp to the slow log
1986  */
1987  end= strmov(end, ",timestamp=");
1988  end= int10_to_str((long) current_time, end, 10);
1989 
1990  if (end != buff)
1991  {
1992  *end++=';';
1993  *end='\n';
1994  if (my_b_write(&log_file, (uchar*) "SET ", 4) ||
1995  my_b_write(&log_file, (uchar*) buff + 1, (uint) (end-buff)))
1996  tmp_errno= errno;
1997  }
1998  if (is_command)
1999  {
2000  end= strxmov(buff, "# administrator command: ", NullS);
2001  buff_len= (ulong) (end - buff);
2002  DBUG_EXECUTE_IF("simulate_slow_log_write_error",
2003  {DBUG_SET("+d,simulate_file_write_error");});
2004  if(my_b_write(&log_file, (uchar*) buff, buff_len))
2005  tmp_errno= errno;
2006  }
2007  if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len) ||
2008  my_b_write(&log_file, (uchar*) ";\n",2) ||
2009  flush_io_cache(&log_file))
2010  tmp_errno= errno;
2011  if (tmp_errno)
2012  {
2013  error= 1;
2014  if (! write_error)
2015  {
2016  char errbuf[MYSYS_STRERROR_SIZE];
2017  write_error= 1;
2018  sql_print_error(ER(ER_ERROR_ON_WRITE), name, error,
2019  my_strerror(errbuf, sizeof(errbuf), errno));
2020  }
2021  }
2022  }
2023  mysql_mutex_unlock(&LOCK_log);
2024  DBUG_RETURN(error);
2025 }
2026 
2027 
2033 const char *MYSQL_LOG::generate_name(const char *log_name,
2034  const char *suffix,
2035  bool strip_ext, char *buff)
2036 {
2037  if (!log_name || !log_name[0])
2038  {
2039  strmake(buff, pidfile_name, FN_REFLEN - strlen(suffix) - 1);
2040  return (const char *)
2041  fn_format(buff, buff, "", suffix, MYF(MY_REPLACE_EXT|MY_REPLACE_DIR));
2042  }
2043  // get rid of extension if the log is binary to avoid problems
2044  if (strip_ext)
2045  {
2046  char *p= fn_ext(log_name);
2047  uint length= (uint) (p - log_name);
2048  strmake(buff, log_name, min<size_t>(length, FN_REFLEN-1));
2049  return (const char*)buff;
2050  }
2051  return log_name;
2052 }
2053 
2054 
2055 int error_log_print(enum loglevel level, const char *format,
2056  va_list args)
2057 {
2058  return logger.error_log_print(level, format, args);
2059 }
2060 
2061 
2062 bool slow_log_print(THD *thd, const char *query, uint query_length)
2063 {
2064  return logger.slow_log_print(thd, query, query_length);
2065 }
2066 
2067 
2068 bool LOGGER::log_command(THD *thd, enum enum_server_command command)
2069 {
2070 #ifndef NO_EMBEDDED_ACCESS_CHECKS
2071  Security_context *sctx= thd->security_ctx;
2072 #endif
2073  /*
2074  Log command if we have at least one log event handler enabled and want
2075  to log this king of commands
2076  */
2077  if (*general_log_handler_list && (what_to_log & (1L << (uint) command)))
2078  {
2079  if ((thd->variables.option_bits & OPTION_LOG_OFF)
2080 #ifndef NO_EMBEDDED_ACCESS_CHECKS
2081  && (sctx->master_access & SUPER_ACL)
2082 #endif
2083  )
2084  {
2085  /* No logging */
2086  return FALSE;
2087  }
2088 
2089  return TRUE;
2090  }
2091 
2092  return FALSE;
2093 }
2094 
2095 
2096 bool general_log_print(THD *thd, enum enum_server_command command,
2097  const char *format, ...)
2098 {
2099  va_list args;
2100  uint error= 0;
2101 
2102  /* Print the message to the buffer if we want to log this king of commands */
2103  if (! logger.log_command(thd, command))
2104  return FALSE;
2105 
2106  va_start(args, format);
2107  error= logger.general_log_print(thd, command, format, args);
2108  va_end(args);
2109 
2110  return error;
2111 }
2112 
2113 bool general_log_write(THD *thd, enum enum_server_command command,
2114  const char *query, uint query_length)
2115 {
2116  /* Write the message to the log if we want to log this king of commands */
2117  if (logger.log_command(thd, command))
2118  return logger.general_log_write(thd, command, query, query_length);
2119 
2120  return FALSE;
2121 }
2122 
2140 static bool test_if_number(register const char *str,
2141  ulong *res, bool allow_wildcards)
2142 {
2143  reg2 int flag;
2144  const char *start;
2145  DBUG_ENTER("test_if_number");
2146 
2147  flag=0; start=str;
2148  while (*str++ == ' ') ;
2149  if (*--str == '-' || *str == '+')
2150  str++;
2151  while (my_isdigit(files_charset_info,*str) ||
2152  (allow_wildcards && (*str == wild_many || *str == wild_one)))
2153  {
2154  flag=1;
2155  str++;
2156  }
2157  if (*str == '.')
2158  {
2159  for (str++ ;
2160  my_isdigit(files_charset_info,*str) ||
2161  (allow_wildcards && (*str == wild_many || *str == wild_one)) ;
2162  str++, flag=1) ;
2163  }
2164  if (*str != 0 || flag == 0)
2165  DBUG_RETURN(0);
2166  if (res)
2167  *res=atol(start);
2168  DBUG_RETURN(1); /* Number ok */
2169 } /* test_if_number */
2170 
2171 
2172 void sql_perror(const char *message)
2173 {
2174 #ifdef HAVE_STRERROR
2175  sql_print_error("%s: %s",message, strerror(errno));
2176 #else
2177  perror(message);
2178 #endif
2179 }
2180 
2181 
2182 /*
2183  Change the file associated with two output streams. Used to
2184  redirect stdout and stderr to a file. The streams are reopened
2185  only for appending (writing at end of file).
2186 */
2187 extern "C" my_bool reopen_fstreams(const char *filename,
2188  FILE *outstream, FILE *errstream)
2189 {
2190  if (outstream && !my_freopen(filename, "a", outstream))
2191  return TRUE;
2192 
2193  if (errstream && !my_freopen(filename, "a", errstream))
2194  return TRUE;
2195 
2196  /* The error stream must be unbuffered. */
2197  if (errstream)
2198  setbuf(errstream, NULL);
2199 
2200  return FALSE;
2201 }
2202 
2203 
2204 /*
2205  Unfortunately, there seems to be no good way
2206  to restore the original streams upon failure.
2207 */
2208 static bool redirect_std_streams(const char *file)
2209 {
2210  if (reopen_fstreams(file, stdout, stderr))
2211  return TRUE;
2212 
2213  setbuf(stderr, NULL);
2214  return FALSE;
2215 }
2216 
2217 
2218 bool flush_error_log()
2219 {
2220  bool result= 0;
2221  if (opt_error_log)
2222  {
2223  mysql_mutex_lock(&LOCK_error_log);
2224  if (redirect_std_streams(log_error_file))
2225  result= 1;
2226  mysql_mutex_unlock(&LOCK_error_log);
2227  }
2228  return result;
2229 }
2230 
2231 #ifdef _WIN32
2232 static void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,
2233  size_t length, size_t buffLen)
2234 {
2235  HANDLE event;
2236  char *buffptr= buff;
2237  DBUG_ENTER("print_buffer_to_nt_eventlog");
2238 
2239  /* Add ending CR/LF's to string, overwrite last chars if necessary */
2240  strmov(buffptr+min(length, buffLen-5), "\r\n\r\n");
2241 
2242  setup_windows_event_source();
2243  if ((event= RegisterEventSource(NULL,"MySQL")))
2244  {
2245  switch (level) {
2246  case ERROR_LEVEL:
2247  ReportEvent(event, EVENTLOG_ERROR_TYPE, 0, MSG_DEFAULT, NULL, 1, 0,
2248  (LPCSTR*)&buffptr, NULL);
2249  break;
2250  case WARNING_LEVEL:
2251  ReportEvent(event, EVENTLOG_WARNING_TYPE, 0, MSG_DEFAULT, NULL, 1, 0,
2252  (LPCSTR*) &buffptr, NULL);
2253  break;
2254  case INFORMATION_LEVEL:
2255  ReportEvent(event, EVENTLOG_INFORMATION_TYPE, 0, MSG_DEFAULT, NULL, 1,
2256  0, (LPCSTR*) &buffptr, NULL);
2257  break;
2258  }
2259  DeregisterEventSource(event);
2260  }
2261 
2262  DBUG_VOID_RETURN;
2263 }
2264 #endif /* _WIN32 */
2265 
2266 
2267 #ifndef EMBEDDED_LIBRARY
2268 static void print_buffer_to_file(enum loglevel level, const char *buffer,
2269  size_t length)
2270 {
2271  time_t skr;
2272  struct tm tm_tmp;
2273  struct tm *start;
2274  DBUG_ENTER("print_buffer_to_file");
2275  DBUG_PRINT("enter",("buffer: %s", buffer));
2276 
2277  mysql_mutex_lock(&LOCK_error_log);
2278 
2279  skr= my_time(0);
2280  localtime_r(&skr, &tm_tmp);
2281  start=&tm_tmp;
2282 
2283  fprintf(stderr, "%d-%02d-%02d %02d:%02d:%02d %lu [%s] %.*s\n",
2284  start->tm_year + 1900,
2285  start->tm_mon + 1,
2286  start->tm_mday,
2287  start->tm_hour,
2288  start->tm_min,
2289  start->tm_sec,
2290  current_pid,
2291  (level == ERROR_LEVEL ? "ERROR" : level == WARNING_LEVEL ?
2292  "Warning" : "Note"),
2293  (int) length, buffer);
2294 
2295  fflush(stderr);
2296 
2297  mysql_mutex_unlock(&LOCK_error_log);
2298  DBUG_VOID_RETURN;
2299 }
2300 
2317 int vprint_msg_to_log(enum loglevel level, const char *format, va_list args)
2318 {
2319  char buff[1024];
2320  size_t length;
2321  DBUG_ENTER("vprint_msg_to_log");
2322 
2323  length= my_vsnprintf(buff, sizeof(buff), format, args);
2324  print_buffer_to_file(level, buff, length);
2325 
2326 #ifdef _WIN32
2327  print_buffer_to_nt_eventlog(level, buff, length, sizeof(buff));
2328 #endif
2329 
2330  DBUG_RETURN(0);
2331 }
2332 #endif /* EMBEDDED_LIBRARY */
2333 
2334 
2335 void sql_print_error(const char *format, ...)
2336 {
2337  va_list args;
2338  DBUG_ENTER("sql_print_error");
2339 
2340  va_start(args, format);
2341  error_log_print(ERROR_LEVEL, format, args);
2342  va_end(args);
2343 
2344  DBUG_VOID_RETURN;
2345 }
2346 
2347 
2348 void sql_print_warning(const char *format, ...)
2349 {
2350  va_list args;
2351  DBUG_ENTER("sql_print_warning");
2352 
2353  va_start(args, format);
2354  error_log_print(WARNING_LEVEL, format, args);
2355  va_end(args);
2356 
2357  DBUG_VOID_RETURN;
2358 }
2359 
2360 
2361 void sql_print_information(const char *format, ...)
2362 {
2363  va_list args;
2364  DBUG_ENTER("sql_print_information");
2365 
2366  va_start(args, format);
2367  error_log_print(INFORMATION_LEVEL, format, args);
2368  va_end(args);
2369 
2370  DBUG_VOID_RETURN;
2371 }
2372 
2373 
2374 extern "C"
2375 int my_plugin_log_message(MYSQL_PLUGIN *plugin_ptr, plugin_log_level level,
2376  const char *format, ...)
2377 {
2378  char format2[MYSQL_ERRMSG_SIZE];
2379  int ret;
2380  loglevel lvl;
2381  struct st_plugin_int *plugin = static_cast<st_plugin_int *> (*plugin_ptr);
2382  va_list args;
2383 
2384  DBUG_ASSERT(level >= MY_ERROR_LEVEL || level <= MY_INFORMATION_LEVEL);
2385 
2386  switch (level)
2387  {
2388  case MY_ERROR_LEVEL: lvl= ERROR_LEVEL; break;
2389  case MY_WARNING_LEVEL: lvl= WARNING_LEVEL; break;
2390  case MY_INFORMATION_LEVEL: lvl= INFORMATION_LEVEL; break;
2391  default: return 1;
2392  }
2393 
2394  va_start(args, format);
2395  snprintf(format2, sizeof (format2) - 1, "Plugin %.*s reported: '%s'",
2396  (int) plugin->name.length, plugin->name.str, format);
2397  ret= error_log_print(lvl, format2, args);
2398  va_end(args);
2399  return ret;
2400 }
2401 
2402 
2403 /********* transaction coordinator log for 2pc - mmap() based solution *******/
2404 
2405 /*
2406  the log consists of a file, mmapped to a memory.
2407  file is divided on pages of tc_log_page_size size.
2408  (usable size of the first page is smaller because of log header)
2409  there's PAGE control structure for each page
2410  each page (or rather PAGE control structure) can be in one of three
2411  states - active, syncing, pool.
2412  there could be only one page in active or syncing states,
2413  but many in pool - pool is fifo queue.
2414  usual lifecycle of a page is pool->active->syncing->pool
2415  "active" page - is a page where new xid's are logged.
2416  the page stays active as long as syncing slot is taken.
2417  "syncing" page is being synced to disk. no new xid can be added to it.
2418  when the sync is done the page is moved to a pool and an active page
2419  becomes "syncing".
2420 
2421  the result of such an architecture is a natural "commit grouping" -
2422  If commits are coming faster than the system can sync, they do not
2423  stall. Instead, all commit that came since the last sync are
2424  logged to the same page, and they all are synced with the next -
2425  one - sync. Thus, thought individual commits are delayed, throughput
2426  is not decreasing.
2427 
2428  when a xid is added to an active page, the thread of this xid waits
2429  for a page's condition until the page is synced. when syncing slot
2430  becomes vacant one of these waiters is awaken to take care of syncing.
2431  it syncs the page and signals all waiters that the page is synced.
2432  PAGE::waiters is used to count these waiters, and a page may never
2433  become active again until waiters==0 (that is all waiters from the
2434  previous sync have noticed the sync was completed)
2435 
2436  note, that the page becomes "dirty" and has to be synced only when a
2437  new xid is added into it. Removing a xid from a page does not make it
2438  dirty - we don't sync removals to disk.
2439 */
2440 
2441 ulong tc_log_page_waits= 0;
2442 
2443 #ifdef HAVE_MMAP
2444 
2445 #define TC_LOG_HEADER_SIZE (sizeof(tc_log_magic)+1)
2446 
2447 static const char tc_log_magic[]={(char) 254, 0x23, 0x05, 0x74};
2448 
2449 ulong opt_tc_log_size= TC_LOG_MIN_SIZE;
2450 ulong tc_log_max_pages_used=0, tc_log_page_size=0, tc_log_cur_pages_used=0;
2451 
2452 int TC_LOG_MMAP::open(const char *opt_name)
2453 {
2454  uint i;
2455  bool crashed=FALSE;
2456  PAGE *pg;
2457 
2458  DBUG_ASSERT(total_ha_2pc > 1);
2459  DBUG_ASSERT(opt_name && opt_name[0]);
2460 
2461  tc_log_page_size= my_getpagesize();
2462  if (TC_LOG_PAGE_SIZE > tc_log_page_size)
2463  {
2464  DBUG_ASSERT(TC_LOG_PAGE_SIZE % tc_log_page_size == 0);
2465  }
2466 
2467  fn_format(logname,opt_name,mysql_data_home,"",MY_UNPACK_FILENAME);
2468  if ((fd= mysql_file_open(key_file_tclog, logname, O_RDWR, MYF(0))) < 0)
2469  {
2470  if (my_errno != ENOENT)
2471  goto err;
2472  if (using_heuristic_recover())
2473  return 1;
2474  if ((fd= mysql_file_create(key_file_tclog, logname, CREATE_MODE,
2475  O_RDWR, MYF(MY_WME))) < 0)
2476  goto err;
2477  inited=1;
2478  file_length= opt_tc_log_size;
2479  if (mysql_file_chsize(fd, file_length, 0, MYF(MY_WME)))
2480  goto err;
2481  }
2482  else
2483  {
2484  inited= 1;
2485  crashed= TRUE;
2486  sql_print_information("Recovering after a crash using %s", opt_name);
2487  if (tc_heuristic_recover)
2488  {
2489  sql_print_error("Cannot perform automatic crash recovery when "
2490  "--tc-heuristic-recover is used");
2491  goto err;
2492  }
2493  file_length= mysql_file_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE));
2494  if (file_length == MY_FILEPOS_ERROR || file_length % tc_log_page_size)
2495  goto err;
2496  }
2497 
2498  data= (uchar *)my_mmap(0, (size_t)file_length, PROT_READ|PROT_WRITE,
2499  MAP_NOSYNC|MAP_SHARED, fd, 0);
2500  if (data == MAP_FAILED)
2501  {
2502  my_errno=errno;
2503  goto err;
2504  }
2505  inited=2;
2506 
2507  npages=(uint)file_length/tc_log_page_size;
2508  DBUG_ASSERT(npages >= 3); // to guarantee non-empty pool
2509  if (!(pages=(PAGE *)my_malloc(npages*sizeof(PAGE), MYF(MY_WME|MY_ZEROFILL))))
2510  goto err;
2511  inited=3;
2512  for (pg=pages, i=0; i < npages; i++, pg++)
2513  {
2514  pg->next=pg+1;
2515  pg->waiters=0;
2516  pg->state=PS_POOL;
2517  mysql_mutex_init(key_PAGE_lock, &pg->lock, MY_MUTEX_INIT_FAST);
2518  mysql_cond_init(key_PAGE_cond, &pg->cond, 0);
2519  pg->start=(my_xid *)(data + i*tc_log_page_size);
2520  pg->end=(my_xid *)(pg->start + tc_log_page_size);
2521  pg->size=pg->free=tc_log_page_size/sizeof(my_xid);
2522  }
2523  pages[0].size=pages[0].free=
2524  (tc_log_page_size-TC_LOG_HEADER_SIZE)/sizeof(my_xid);
2525  pages[0].start=pages[0].end-pages[0].size;
2526  pages[npages-1].next=0;
2527  inited=4;
2528 
2529  if (crashed && recover())
2530  goto err;
2531 
2532  memcpy(data, tc_log_magic, sizeof(tc_log_magic));
2533  data[sizeof(tc_log_magic)]= (uchar)total_ha_2pc;
2534  my_msync(fd, data, tc_log_page_size, MS_SYNC);
2535  inited=5;
2536 
2537  mysql_mutex_init(key_LOCK_sync, &LOCK_sync, MY_MUTEX_INIT_FAST);
2538  mysql_mutex_init(key_LOCK_active, &LOCK_active, MY_MUTEX_INIT_FAST);
2539  mysql_mutex_init(key_LOCK_pool, &LOCK_pool, MY_MUTEX_INIT_FAST);
2540  mysql_cond_init(key_COND_active, &COND_active, 0);
2541  mysql_cond_init(key_COND_pool, &COND_pool, 0);
2542 
2543  inited=6;
2544 
2545  syncing= 0;
2546  active=pages;
2547  pool=pages+1;
2548  pool_last=pages+npages-1;
2549 
2550  return 0;
2551 
2552 err:
2553  close();
2554  return 1;
2555 }
2556 
2569 void TC_LOG_MMAP::get_active_from_pool()
2570 {
2571  PAGE **p, **best_p=0;
2572  int best_free;
2573 
2574  if (syncing)
2575  mysql_mutex_lock(&LOCK_pool);
2576 
2577  do
2578  {
2579  best_p= p= &pool;
2580  if ((*p)->waiters == 0) // can the first page be used ?
2581  break; // yes - take it.
2582 
2583  best_free=0; // no - trying second strategy
2584  for (p=&(*p)->next; *p; p=&(*p)->next)
2585  {
2586  if ((*p)->waiters == 0 && (*p)->free > best_free)
2587  {
2588  best_free=(*p)->free;
2589  best_p=p;
2590  }
2591  }
2592  }
2593  while ((*best_p == 0 || best_free == 0) && overflow());
2594 
2595  active=*best_p;
2596  if (active->free == active->size) // we've chosen an empty page
2597  {
2598  tc_log_cur_pages_used++;
2599  set_if_bigger(tc_log_max_pages_used, tc_log_cur_pages_used);
2600  }
2601 
2602  if ((*best_p)->next) // unlink the page from the pool
2603  *best_p=(*best_p)->next;
2604  else
2605  pool_last=*best_p;
2606 
2607  if (syncing)
2608  mysql_mutex_unlock(&LOCK_pool);
2609 }
2610 
2615 int TC_LOG_MMAP::overflow()
2616 {
2617  /*
2618  simple overflow handling - just wait
2619  TODO perhaps, increase log size ?
2620  let's check the behaviour of tc_log_page_waits first
2621  */
2622  tc_log_page_waits++;
2623  mysql_cond_wait(&COND_pool, &LOCK_pool);
2624  return 1; // always return 1
2625 }
2626 
2634 TC_LOG::enum_result TC_LOG_MMAP::commit(THD *thd, bool all)
2635 {
2636  DBUG_ENTER("TC_LOG_MMAP::commit");
2637  unsigned long cookie= 0;
2638  my_xid xid= thd->transaction.xid_state.xid.get_my_xid();
2639 
2640  if (all && xid)
2641  if ((cookie= log_xid(thd, xid)))
2642  DBUG_RETURN(RESULT_ABORTED); // Failed to log the transaction
2643 
2644  if (ha_commit_low(thd, all))
2645  DBUG_RETURN(RESULT_INCONSISTENT); // Transaction logged, but not committed
2646 
2647  /* If cookie is non-zero, something was logged */
2648  if (cookie)
2649  if (unlog(cookie, xid))
2650  DBUG_RETURN(RESULT_INCONSISTENT); // Transaction logged, committed, but not unlogged.
2651  DBUG_RETURN(RESULT_SUCCESS);
2652 }
2653 
2654 
2682 int TC_LOG_MMAP::log_xid(THD *thd, my_xid xid)
2683 {
2684  int err;
2685  PAGE *p;
2686  ulong cookie;
2687 
2688  mysql_mutex_lock(&LOCK_active);
2689 
2690  /*
2691  if active page is full - just wait...
2692  frankly speaking, active->free here accessed outside of mutex
2693  protection, but it's safe, because it only means we may miss an
2694  unlog() for the active page, and we're not waiting for it here -
2695  unlog() does not signal COND_active.
2696  */
2697  while (unlikely(active && active->free == 0))
2698  mysql_cond_wait(&COND_active, &LOCK_active);
2699 
2700  /* no active page ? take one from the pool */
2701  if (active == 0)
2702  get_active_from_pool();
2703 
2704  p=active;
2705  mysql_mutex_lock(&p->lock);
2706 
2707  /* searching for an empty slot */
2708  while (*p->ptr)
2709  {
2710  p->ptr++;
2711  DBUG_ASSERT(p->ptr < p->end); // because p->free > 0
2712  }
2713 
2714  /* found! store xid there and mark the page dirty */
2715  cookie= (ulong)((uchar *)p->ptr - data); // can never be zero
2716  *p->ptr++= xid;
2717  p->free--;
2718  p->state= PS_DIRTY;
2719 
2720  /* to sync or not to sync - this is the question */
2721  mysql_mutex_unlock(&LOCK_active);
2722  mysql_mutex_lock(&LOCK_sync);
2723  mysql_mutex_unlock(&p->lock);
2724 
2725  if (syncing)
2726  { // somebody's syncing. let's wait
2727  p->waiters++;
2728  /*
2729  note - it must be while (), not do ... while () here
2730  as p->state may be not PS_DIRTY when we come here
2731  */
2732  while (p->state == PS_DIRTY && syncing)
2733  mysql_cond_wait(&p->cond, &LOCK_sync);
2734  p->waiters--;
2735  err= p->state == PS_ERROR;
2736  if (p->state != PS_DIRTY) // page was synced
2737  {
2738  if (p->waiters == 0)
2739  mysql_cond_signal(&COND_pool); // in case somebody's waiting
2740  mysql_mutex_unlock(&LOCK_sync);
2741  goto done; // we're done
2742  }
2743  } // page was not synced! do it now
2744  DBUG_ASSERT(active == p && syncing == 0);
2745  mysql_mutex_lock(&LOCK_active);
2746  syncing=p; // place is vacant - take it
2747  active=0; // page is not active anymore
2748  mysql_cond_broadcast(&COND_active); // in case somebody's waiting
2749  mysql_mutex_unlock(&LOCK_active);
2750  mysql_mutex_unlock(&LOCK_sync);
2751  err= sync();
2752 
2753 done:
2754  return err ? 0 : cookie;
2755 }
2756 
2757 int TC_LOG_MMAP::sync()
2758 {
2759  int err;
2760 
2761  DBUG_ASSERT(syncing != active);
2762 
2763  /*
2764  sit down and relax - this can take a while...
2765  note - no locks are held at this point
2766  */
2767  err= my_msync(fd, syncing->start, 1, MS_SYNC);
2768 
2769  /* page is synced. let's move it to the pool */
2770  mysql_mutex_lock(&LOCK_pool);
2771  pool_last->next=syncing;
2772  pool_last=syncing;
2773  syncing->next=0;
2774  syncing->state= err ? PS_ERROR : PS_POOL;
2775  mysql_cond_broadcast(&syncing->cond); // signal "sync done"
2776  mysql_cond_signal(&COND_pool); // in case somebody's waiting
2777  mysql_mutex_unlock(&LOCK_pool);
2778 
2779  /* marking 'syncing' slot free */
2780  mysql_mutex_lock(&LOCK_sync);
2781  syncing=0;
2782  mysql_cond_signal(&active->cond); // wake up a new syncer
2783  mysql_mutex_unlock(&LOCK_sync);
2784  return err;
2785 }
2786 
2792 int TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
2793 {
2794  PAGE *p=pages+(cookie/tc_log_page_size);
2795  my_xid *x=(my_xid *)(data+cookie);
2796 
2797  DBUG_ASSERT(*x == xid);
2798  DBUG_ASSERT(x >= p->start && x < p->end);
2799  *x=0;
2800 
2801  mysql_mutex_lock(&p->lock);
2802  p->free++;
2803  DBUG_ASSERT(p->free <= p->size);
2804  set_if_smaller(p->ptr, x);
2805  if (p->free == p->size) // the page is completely empty
2806  statistic_decrement(tc_log_cur_pages_used, &LOCK_status);
2807  if (p->waiters == 0) // the page is in pool and ready to rock
2808  mysql_cond_signal(&COND_pool); // ping ... for overflow()
2809  mysql_mutex_unlock(&p->lock);
2810  return 0;
2811 }
2812 
2813 void TC_LOG_MMAP::close()
2814 {
2815  uint i;
2816  switch (inited) {
2817  case 6:
2818  mysql_mutex_destroy(&LOCK_sync);
2819  mysql_mutex_destroy(&LOCK_active);
2820  mysql_mutex_destroy(&LOCK_pool);
2821  mysql_cond_destroy(&COND_pool);
2822  case 5:
2823  data[0]='A'; // garble the first (signature) byte, in case mysql_file_delete fails
2824  case 4:
2825  for (i=0; i < npages; i++)
2826  {
2827  if (pages[i].ptr == 0)
2828  break;
2829  mysql_mutex_destroy(&pages[i].lock);
2830  mysql_cond_destroy(&pages[i].cond);
2831  }
2832  case 3:
2833  my_free(pages);
2834  case 2:
2835  my_munmap((char*)data, (size_t)file_length);
2836  case 1:
2837  mysql_file_close(fd, MYF(0));
2838  }
2839  if (inited>=5) // cannot do in the switch because of Windows
2840  mysql_file_delete(key_file_tclog, logname, MYF(MY_WME));
2841  inited=0;
2842 }
2843 
2844 int TC_LOG_MMAP::recover()
2845 {
2846  HASH xids;
2847  PAGE *p=pages, *end_p=pages+npages;
2848 
2849  if (memcmp(data, tc_log_magic, sizeof(tc_log_magic)))
2850  {
2851  sql_print_error("Bad magic header in tc log");
2852  goto err1;
2853  }
2854 
2855  /*
2856  the first byte after magic signature is set to current
2857  number of storage engines on startup
2858  */
2859  if (data[sizeof(tc_log_magic)] != total_ha_2pc)
2860  {
2861  sql_print_error("Recovery failed! You must enable "
2862  "exactly %d storage engines that support "
2863  "two-phase commit protocol",
2864  data[sizeof(tc_log_magic)]);
2865  goto err1;
2866  }
2867 
2868  if (my_hash_init(&xids, &my_charset_bin, tc_log_page_size/3, 0,
2869  sizeof(my_xid), 0, 0, MYF(0)))
2870  goto err1;
2871 
2872  for ( ; p < end_p ; p++)
2873  {
2874  for (my_xid *x=p->start; x < p->end; x++)
2875  if (*x && my_hash_insert(&xids, (uchar *)x))
2876  goto err2; // OOM
2877  }
2878 
2879  if (ha_recover(&xids))
2880  goto err2;
2881 
2882  my_hash_free(&xids);
2883  memset(data, 0, (size_t)file_length);
2884  return 0;
2885 
2886 err2:
2887  my_hash_free(&xids);
2888 err1:
2889  sql_print_error("Crash recovery failed. Either correct the problem "
2890  "(if it's, for example, out of memory error) and restart, "
2891  "or delete tc log and start mysqld with "
2892  "--tc-heuristic-recover={commit|rollback}");
2893  return 1;
2894 }
2895 #endif
2896 
2897 TC_LOG *tc_log;
2898 TC_LOG_DUMMY tc_log_dummy;
2899 TC_LOG_MMAP tc_log_mmap;
2900 
2915 {
2916  if (!tc_heuristic_recover)
2917  return 0;
2918 
2919  sql_print_information("Heuristic crash recovery mode");
2920  if (ha_recover(0))
2921  sql_print_error("Heuristic crash recovery failed");
2922  sql_print_information("Please restart mysqld without --tc-heuristic-recover");
2923  return 1;
2924 }