1 /* Copyright (c) 2005, 2019, 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, version 2.0, 5 as published by the Free Software Foundation. 6 7 This program is also distributed with certain software (including 8 but not limited to OpenSSL) that is licensed under separate terms, 9 as designated in a particular file or component or in included license 10 documentation. The authors of MySQL hereby grant you an additional 11 permission to link the program and your derivative works with the 12 separately licensed software that they have included with MySQL. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License, version 2.0, for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ 22 23 #ifndef LOG_H 24 #define LOG_H 25 26 #include "unireg.h" // REQUIRED: for other includes 27 #include "handler.h" /* my_xid */ 28 29 /** 30 the struct aggregates two paramenters that identify an event 31 uniquely in scope of communication of a particular master and slave couple. 32 I.e there can not be 2 events from the same staying connected master which 33 have the same coordinates. 34 @note 35 Such identifier is not yet unique generally as the event originating master 36 is resetable. Also the crashed master can be replaced with some other. 37 */ 38 typedef struct event_coordinates 39 { 40 char * file_name; // binlog file name (directories stripped) 41 my_off_t pos; // event's position in the binlog file 42 } LOG_POS_COORD; 43 44 /** 45 Transaction Coordinator Log. 46 47 A base abstract class for three different implementations of the 48 transaction coordinator. 49 50 The server uses the transaction coordinator to order transactions 51 correctly and there are three different implementations: one using 52 an in-memory structure, one dummy that does not do anything, and one 53 using the binary log for transaction coordination. 54 */ 55 class TC_LOG 56 { 57 public: 58 int using_heuristic_recover(); TC_LOG()59 TC_LOG() {} ~TC_LOG()60 virtual ~TC_LOG() {} 61 62 enum enum_result { 63 RESULT_SUCCESS, 64 RESULT_ABORTED, 65 RESULT_INCONSISTENT 66 }; 67 68 virtual int open(const char *opt_name)=0; 69 virtual void close()=0; 70 71 /** 72 Log a commit record of the transaction to the transaction 73 coordinator log. 74 75 When the function returns, the transaction commit is properly 76 logged to the transaction coordinator log and can be committed in 77 the storage engines. 78 79 @param thd Session to log transaction for. 80 @param all @c True if this is a "real" commit, @c false if it is a "statement" commit. 81 82 @return Error code on failure, zero on success. 83 */ 84 virtual enum_result commit(THD *thd, bool all) = 0; 85 86 /** 87 Log a rollback record of the transaction to the transaction 88 coordinator log. 89 90 When the function returns, the transaction have been aborted in 91 the transaction coordinator log. 92 93 @param thd Session to log transaction record for. 94 95 @param all @c true if an explicit commit or an implicit commit 96 for a statement, @c false if an internal commit of the statement. 97 98 @return Error code on failure, zero on success. 99 */ 100 virtual int rollback(THD *thd, bool all) = 0; 101 /** 102 Log a prepare record of the transaction to the storage engines. 103 104 @param thd Session to log transaction record for. 105 106 @param all @c true if an explicit commit or an implicit commit 107 for a statement, @c false if an internal commit of the statement. 108 109 @return Error code on failure, zero on success. 110 */ 111 virtual int prepare(THD *thd, bool all) = 0; 112 113 /** 114 Acquire an exclusive lock to block binary log updates and commits. This is 115 used by START TRANSACTION WITH CONSISTENT SNAPSHOT to create an atomic 116 snapshot. 117 */ 118 virtual void xlock(void) = 0; 119 120 /** Release lock acquired with xlock(). */ 121 virtual void xunlock(void) = 0; 122 123 /** 124 Acquire a shared lock to block commits. This is used when calling 125 ha_commit_low() to block commits if there's an exclusive lock acquired by 126 START TRANSACTION WITH CONSISTENT SNAPSHOT. 127 */ 128 virtual void slock(void) = 0; 129 130 /** Release lock acquired with slock(). */ 131 virtual void sunlock(void) = 0; 132 }; 133 134 135 class TC_LOG_DUMMY: public TC_LOG // use it to disable the logging 136 { 137 public: TC_LOG_DUMMY()138 TC_LOG_DUMMY() {} open(const char * opt_name)139 int open(const char *opt_name) { return 0; } close()140 void close() { } commit(THD * thd,bool all)141 enum_result commit(THD *thd, bool all) { 142 return ha_commit_low(thd, all) ? RESULT_ABORTED : RESULT_SUCCESS; 143 } rollback(THD * thd,bool all)144 int rollback(THD *thd, bool all) { 145 return ha_rollback_low(thd, all); 146 } prepare(THD * thd,bool all)147 int prepare(THD *thd, bool all) { 148 return ha_prepare_low(thd, all); 149 } xlock(void)150 void xlock(void) {} xunlock(void)151 void xunlock(void) {} slock(void)152 void slock(void) {} sunlock(void)153 void sunlock(void) {} 154 }; 155 156 #ifdef HAVE_MMAP 157 class TC_LOG_MMAP: public TC_LOG 158 { 159 public: // only to keep Sun Forte on sol9x86 happy 160 typedef enum { 161 PS_POOL, // page is in pool 162 PS_ERROR, // last sync failed 163 PS_DIRTY // new xids added since last sync 164 } PAGE_STATE; 165 166 private: 167 typedef struct st_page { 168 struct st_page *next; // page a linked in a fifo queue 169 my_xid *start, *end; // usable area of a page 170 my_xid *ptr; // next xid will be written here 171 int size, free; // max and current number of free xid slots on the page 172 int waiters; // number of waiters on condition 173 PAGE_STATE state; // see above 174 mysql_mutex_t lock; // to access page data or control structure 175 mysql_cond_t cond; // to wait for a sync 176 } PAGE; 177 178 char logname[FN_REFLEN]; 179 File fd; 180 my_off_t file_length; 181 uint npages, inited; 182 uchar *data; 183 struct st_page *pages, *syncing, *active, *pool, **pool_last_ptr; 184 /* 185 note that, e.g. LOCK_active is only used to protect 186 'active' pointer, to protect the content of the active page 187 one has to use active->lock. 188 Same for LOCK_pool and LOCK_sync 189 */ 190 mysql_mutex_t LOCK_active, LOCK_pool, LOCK_sync; 191 mysql_cond_t COND_pool, COND_active; 192 193 public: TC_LOG_MMAP()194 TC_LOG_MMAP(): inited(0) {} 195 int open(const char *opt_name); 196 void close(); 197 enum_result commit(THD *thd, bool all); rollback(THD * thd,bool all)198 int rollback(THD *thd, bool all) { return ha_rollback_low(thd, all); } prepare(THD * thd,bool all)199 int prepare(THD *thd, bool all) { return ha_prepare_low(thd, all); } xlock(void)200 void xlock(void) { mysql_rwlock_wrlock(&LOCK_consistent_snapshot); } xunlock(void)201 void xunlock(void) { mysql_rwlock_unlock(&LOCK_consistent_snapshot); } slock(void)202 void slock(void) { mysql_rwlock_rdlock(&LOCK_consistent_snapshot); } sunlock(void)203 void sunlock(void) { mysql_rwlock_unlock(&LOCK_consistent_snapshot); } 204 int recover(); 205 uint size() const; 206 207 private: 208 int log_xid(THD *thd, my_xid xid); 209 int unlog(ulong cookie, my_xid xid); 210 void get_active_from_pool(); 211 int sync(); 212 int overflow(); 213 214 friend class TCLogMMapTest; 215 }; 216 #else 217 #define TC_LOG_MMAP TC_LOG_DUMMY 218 #endif 219 220 extern TC_LOG *tc_log; 221 extern TC_LOG_MMAP tc_log_mmap; 222 extern TC_LOG_DUMMY tc_log_dummy; 223 224 /* log info errors */ 225 #define LOG_INFO_EOF -1 226 #define LOG_INFO_IO -2 227 #define LOG_INFO_INVALID -3 228 #define LOG_INFO_SEEK -4 229 #define LOG_INFO_MEM -6 230 #define LOG_INFO_FATAL -7 231 #define LOG_INFO_IN_USE -8 232 #define LOG_INFO_EMFILE -9 233 234 235 /* bitmap to SQL_LOG::close() */ 236 #define LOG_CLOSE_INDEX 1 237 #define LOG_CLOSE_TO_BE_OPENED 2 238 #define LOG_CLOSE_STOP_EVENT 4 239 240 /* 241 Maximum unique log filename extension. 242 Note: setting to 0x7FFFFFFF due to atol windows 243 overflow/truncate. 244 */ 245 #define MAX_LOG_UNIQUE_FN_EXT 0x7FFFFFFF 246 247 /* 248 Number of warnings that will be printed to error log 249 before extension number is exhausted. 250 */ 251 #define LOG_WARN_UNIQUE_FN_EXT_LEFT 1000 252 253 /* max size of log messages (error log, plugins' logging, general log) */ 254 #define MAX_LOG_BUFFER_SIZE 1024 255 #define MAX_TIME_SIZE 32 256 257 #ifdef HAVE_PSI_INTERFACE 258 extern PSI_mutex_key key_LOG_INFO_lock; 259 #endif 260 261 /* 262 Note that we destroy the lock mutex in the desctructor here. 263 This means that object instances cannot be destroyed/go out of scope, 264 until we have reset thd->current_linfo to NULL; 265 */ 266 typedef struct st_log_info 267 { 268 char log_file_name[FN_REFLEN]; 269 my_off_t index_file_offset, index_file_start_offset; 270 my_off_t pos; 271 bool fatal; // if the purge happens to give us a negative offset 272 int entry_index; //used in purge_logs(), calculatd in find_log_pos(). 273 mysql_mutex_t lock; st_log_infost_log_info274 st_log_info() 275 : index_file_offset(0), index_file_start_offset(0), 276 pos(0), fatal(0), entry_index(0) 277 { 278 log_file_name[0] = '\0'; 279 mysql_mutex_init(key_LOG_INFO_lock, &lock, MY_MUTEX_INIT_FAST); 280 } ~st_log_infost_log_info281 ~st_log_info() { mysql_mutex_destroy(&lock);} 282 } LOG_INFO; 283 284 /* 285 Currently we have only 3 kinds of logging functions: old-fashioned 286 logs, stdout and csv logging routines. 287 */ 288 #define MAX_LOG_HANDLERS_NUM 3 289 290 /* log event handler flags */ 291 #define LOG_NONE 1 292 #define LOG_FILE 2 293 #define LOG_TABLE 4 294 295 enum enum_log_type { LOG_UNKNOWN, LOG_NORMAL, LOG_BIN }; 296 enum enum_log_state { LOG_OPENED, LOG_CLOSED, LOG_TO_BE_OPENED }; 297 298 /* 299 TODO use mmap instead of IO_CACHE for binlog 300 (mmap+fsync is two times faster than write+fsync) 301 */ 302 303 class MYSQL_LOG 304 { 305 public: 306 MYSQL_LOG(); 307 void init_pthread_objects(); 308 void cleanup(); 309 bool open( 310 #ifdef HAVE_PSI_INTERFACE 311 PSI_file_key log_file_key, 312 #endif 313 const char *log_name, 314 enum_log_type log_type, 315 const char *new_name, 316 enum cache_type io_cache_type_arg); 317 bool init_and_set_log_file_name(const char *log_name, 318 const char *new_name, 319 enum_log_type log_type_arg, 320 enum cache_type io_cache_type_arg); 321 void init(enum_log_type log_type_arg, 322 enum cache_type io_cache_type_arg); 323 void close(uint exiting); is_open()324 inline bool is_open() { return log_state != LOG_CLOSED; } 325 const char *generate_name(const char *log_name, const char *suffix, 326 bool strip_ext, char *buff); 327 int generate_new_name(char *new_name, const char *log_name); 328 protected: 329 /* LOCK_log is inited by init_pthread_objects() */ 330 mysql_mutex_t LOCK_log; 331 char *name; 332 char log_file_name[FN_REFLEN]; 333 char time_buff[20], db[NAME_LEN + 1]; 334 bool write_error, inited; 335 IO_CACHE log_file; 336 enum_log_type log_type; 337 volatile enum_log_state log_state; 338 enum cache_type io_cache_type; 339 friend class Log_event; 340 ulong cur_log_ext; 341 #ifdef HAVE_PSI_INTERFACE 342 /** Instrumentation key to use for file io in @c log_file */ 343 PSI_file_key m_log_file_key; 344 /** The instrumentation key to use for @ LOCK_log. */ 345 PSI_mutex_key m_key_LOCK_log; 346 #endif 347 int purge_up_to(ulong to_ext, const char *log_name); 348 }; 349 350 351 enum enum_general_log_table_field 352 { 353 GLT_FIELD_EVENT_TIME = 0, 354 GLT_FIELD_USER_HOST, 355 GLT_FIELD_THREAD_ID, 356 GLT_FIELD_SERVER_ID, 357 GLT_FIELD_COMMAND_TYPE, 358 GLT_FIELD_ARGUMENT, 359 GLT_FIELD_COUNT 360 }; 361 362 363 enum enum_slow_query_log_table_field 364 { 365 SQLT_FIELD_START_TIME = 0, 366 SQLT_FIELD_USER_HOST, 367 SQLT_FIELD_QUERY_TIME, 368 SQLT_FIELD_LOCK_TIME, 369 SQLT_FIELD_ROWS_SENT, 370 SQLT_FIELD_ROWS_EXAMINED, 371 SQLT_FIELD_DATABASE, 372 SQLT_FIELD_LAST_INSERT_ID, 373 SQLT_FIELD_INSERT_ID, 374 SQLT_FIELD_SERVER_ID, 375 SQLT_FIELD_SQL_TEXT, 376 SQLT_FIELD_THREAD_ID, 377 SQLT_FIELD_COUNT 378 }; 379 380 381 class MYSQL_QUERY_LOG: public MYSQL_LOG 382 { 383 public: MYSQL_QUERY_LOG()384 MYSQL_QUERY_LOG() : last_time(0) {} 385 bool reopen_file(); 386 bool write(time_t event_time, const char *user_host, 387 uint user_host_len, my_thread_id thread_id, 388 const char *command_type, uint command_type_len, 389 const char *sql_text, uint sql_text_len); 390 bool write(THD *thd, ulonglong current_time, time_t query_start_arg, 391 const char *user_host, uint user_host_len, 392 ulonglong query_utime, ulonglong lock_utime, bool is_command, 393 const char *sql_text, uint sql_text_len); open_slow_log(const char * log_name)394 bool open_slow_log(const char *log_name) 395 { 396 char buf[FN_REFLEN]; 397 return open( 398 #ifdef HAVE_PSI_INTERFACE 399 key_file_slow_log, 400 #endif 401 generate_name(log_name, "-slow.log", 0, buf), 402 LOG_NORMAL, 0, WRITE_CACHE); 403 } open_query_log(const char * log_name)404 bool open_query_log(const char *log_name) 405 { 406 char buf[FN_REFLEN]; 407 return open( 408 #ifdef HAVE_PSI_INTERFACE 409 key_file_query_log, 410 #endif 411 generate_name(log_name, ".log", 0, buf), 412 LOG_NORMAL, 0, WRITE_CACHE); 413 } 414 int rotate(ulong max_size, bool *need_purge); 415 int new_file(); 416 417 private: 418 time_t last_time; 419 }; 420 421 class Log_event_handler 422 { 423 public: Log_event_handler()424 Log_event_handler() {} 425 virtual bool init()= 0; 426 virtual void cleanup()= 0; 427 428 virtual bool log_slow(THD *thd, ulonglong current_time, 429 time_t query_start_arg, const char *user_host, 430 uint user_host_len, ulonglong query_utime, 431 ulonglong lock_utime, bool is_command, 432 const char *sql_text, uint sql_text_len)= 0; 433 virtual bool log_error(enum loglevel level, const char *format, 434 va_list args)= 0; 435 virtual bool log_general(THD *thd, time_t event_time, const char *user_host, 436 uint user_host_len, my_thread_id thread_id, 437 const char *command_type, uint command_type_len, 438 const char *sql_text, uint sql_text_len, 439 const CHARSET_INFO *client_cs)= 0; ~Log_event_handler()440 virtual ~Log_event_handler() {} 441 }; 442 443 444 int check_if_log_table(size_t db_len, const char *db, size_t table_name_len, 445 const char *table_name, bool check_if_opened); 446 447 class Log_to_csv_event_handler: public Log_event_handler 448 { 449 public: 450 Log_to_csv_event_handler(); 451 ~Log_to_csv_event_handler(); 452 virtual bool init(); 453 virtual void cleanup(); 454 455 virtual bool log_slow(THD *thd, ulonglong current_utime, 456 time_t query_start_arg, const char *user_host, 457 uint user_host_len, ulonglong query_utime, 458 ulonglong lock_utime, bool is_command, 459 const char *sql_text, uint sql_text_len); 460 virtual bool log_error(enum loglevel level, const char *format, 461 va_list args); 462 virtual bool log_general(THD *thd, time_t event_time, const char *user_host, 463 uint user_host_len, my_thread_id thread_id, 464 const char *command_type, uint command_type_len, 465 const char *sql_text, uint sql_text_len, 466 const CHARSET_INFO *client_cs); 467 468 int activate_log(THD *thd, uint log_type); 469 }; 470 471 472 /* type of the log table */ 473 #define QUERY_LOG_SLOW 1 474 #define QUERY_LOG_GENERAL 2 475 476 class Log_to_file_event_handler: public Log_event_handler 477 { 478 MYSQL_QUERY_LOG mysql_log; 479 MYSQL_QUERY_LOG mysql_slow_log; 480 bool is_initialized; 481 public: Log_to_file_event_handler()482 Log_to_file_event_handler(): is_initialized(FALSE) 483 {} 484 virtual bool init(); 485 virtual void cleanup(); 486 487 virtual bool log_slow(THD *thd, ulonglong current_utime, 488 time_t query_start_arg, const char *user_host, 489 uint user_host_len, ulonglong query_utime, 490 ulonglong lock_utime, bool is_command, 491 const char *sql_text, uint sql_text_len); 492 virtual bool log_error(enum loglevel level, const char *format, 493 va_list args); 494 virtual bool log_general(THD *thd, time_t event_time, const char *user_host, 495 uint user_host_len, my_thread_id thread_id, 496 const char *command_type, uint command_type_len, 497 const char *sql_text, uint sql_text_len, 498 const CHARSET_INFO *client_cs); 499 void flush(); 500 void flush_slow_log(); 501 void init_pthread_objects(); get_mysql_slow_log()502 MYSQL_QUERY_LOG *get_mysql_slow_log() { return &mysql_slow_log; } get_mysql_log()503 MYSQL_QUERY_LOG *get_mysql_log() { return &mysql_log; } 504 }; 505 506 507 /* Class which manages slow, general and error log event handlers */ 508 class LOGGER 509 { 510 mysql_rwlock_t LOCK_logger; 511 /* flag to check whether logger mutex is initialized */ 512 uint inited; 513 514 /* available log handlers */ 515 Log_to_csv_event_handler *table_log_handler; 516 Log_to_file_event_handler *file_log_handler; 517 518 /* NULL-terminated arrays of log handlers */ 519 Log_event_handler *error_log_handler_list[MAX_LOG_HANDLERS_NUM + 1]; 520 Log_event_handler *slow_log_handler_list[MAX_LOG_HANDLERS_NUM + 1]; 521 Log_event_handler *general_log_handler_list[MAX_LOG_HANDLERS_NUM + 1]; 522 523 public: 524 525 bool is_log_tables_initialized; 526 LOGGER()527 LOGGER() : inited(0), table_log_handler(NULL), 528 file_log_handler(NULL), is_log_tables_initialized(FALSE) 529 {} lock_shared()530 void lock_shared() { mysql_rwlock_rdlock(&LOCK_logger); } lock_exclusive()531 void lock_exclusive() { mysql_rwlock_wrlock(&LOCK_logger); } unlock()532 void unlock() { mysql_rwlock_unlock(&LOCK_logger); } 533 bool is_log_table_enabled(uint log_table_type); 534 bool log_command(THD *thd, enum enum_server_command command, 535 const char *query_str, size_t query_length); 536 537 /* 538 We want to initialize all log mutexes as soon as possible, 539 but we cannot do it in constructor, as safe_mutex relies on 540 initialization, performed by MY_INIT(). This why this is done in 541 this function. 542 */ 543 void init_base(); 544 void init_log_tables(); 545 bool flush_logs(THD *thd); 546 bool flush_slow_log(); 547 bool flush_general_log(); 548 /* Perform basic logger cleanup. this will leave e.g. error log open. */ 549 void cleanup_base(); 550 /* Free memory. Nothing could be logged after this function is called */ 551 void cleanup_end(); 552 bool error_log_print(enum loglevel level, const char *format, 553 va_list args); 554 bool slow_log_print(THD *thd, const char *query, uint query_length); 555 bool general_log_print(THD *thd,enum enum_server_command command, 556 const char *format, va_list args); 557 bool general_log_write(THD *thd, enum enum_server_command command, 558 const char *query, uint query_length); 559 560 /* we use this function to setup all enabled log event handlers */ 561 int set_handlers(uint error_log_printer, 562 uint slow_log_printer, 563 uint general_log_printer); 564 void init_error_log(uint error_log_printer); 565 void init_slow_log(uint slow_log_printer); 566 void init_general_log(uint general_log_printer); 567 void deactivate_log_handler(THD* thd, uint log_type); 568 bool activate_log_handler(THD* thd, uint log_type); get_slow_log_file_handler()569 MYSQL_QUERY_LOG *get_slow_log_file_handler() const 570 { 571 if (file_log_handler) 572 return file_log_handler->get_mysql_slow_log(); 573 return NULL; 574 } get_log_file_handler()575 MYSQL_QUERY_LOG *get_log_file_handler() const 576 { 577 if (file_log_handler) 578 return file_log_handler->get_mysql_log(); 579 return NULL; 580 } 581 }; 582 583 enum enum_binlog_row_image { 584 /** PKE in the before image and changed columns in the after image */ 585 BINLOG_ROW_IMAGE_MINIMAL= 0, 586 /** Whenever possible, before and after image contain all columns except blobs. */ 587 BINLOG_ROW_IMAGE_NOBLOB= 1, 588 /** All columns in both before and after image. */ 589 BINLOG_ROW_IMAGE_FULL= 2 590 }; 591 592 enum enum_binlog_format { 593 BINLOG_FORMAT_MIXED= 0, ///< statement if safe, otherwise row - autodetected 594 BINLOG_FORMAT_STMT= 1, ///< statement-based 595 BINLOG_FORMAT_ROW= 2, ///< row-based 596 BINLOG_FORMAT_UNSPEC=3 ///< thd_binlog_format() returns it when binlog is closed 597 }; 598 599 void exec_binlog_error_action_abort(const char* err_string); 600 int query_error_code(THD *thd, bool not_killed); 601 uint purge_log_get_error_code(int res); 602 603 int vprint_msg_to_log(enum loglevel level, const char *format, va_list args); 604 void sql_print_error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); 605 void sql_print_warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); 606 void sql_print_information(const char *format, ...) 607 ATTRIBUTE_FORMAT(printf, 1, 2); 608 typedef void (*sql_print_message_func)(const char *format, ...) 609 ATTRIBUTE_FORMAT_FPTR(printf, 1, 2); 610 extern sql_print_message_func sql_print_message_handlers[]; 611 612 int error_log_print(enum loglevel level, const char *format, 613 va_list args); 614 615 bool slow_log_print(THD *thd, const char *query, uint query_length); 616 617 bool general_log_print(THD *thd, enum enum_server_command command, 618 const char *format,...); 619 620 bool general_log_write(THD *thd, enum enum_server_command command, 621 const char *query, uint query_length); 622 623 void sql_perror(const char *message); 624 bool flush_error_log(); 625 626 char *make_log_name(char *buff, const char *name, const char* log_ext); 627 628 /** 629 Check given log name against certain blacklisted names/extensions. 630 631 @param name Log name to check 632 @param len Length of log name 633 634 @returns true if name is valid, false otherwise. 635 */ 636 bool is_valid_log_name(const char *name, size_t len); 637 638 extern LOGGER logger; 639 640 #endif /* LOG_H */ 641