1 /* Copyright (c) 2005, 2016, Oracle and/or its affiliates.
2    Copyright (c) 2009, 2020, MariaDB Corporation.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1335  USA */
16 
17 #ifndef LOG_H
18 #define LOG_H
19 
20 #include "handler.h"                            /* my_xid */
21 #include "wsrep_mysqld.h"
22 #include "rpl_constants.h"
23 
24 class Relay_log_info;
25 
26 class Format_description_log_event;
27 
28 bool reopen_fstreams(const char *filename, FILE *outstream, FILE *errstream);
29 void setup_log_handling();
30 bool trans_has_updated_trans_table(const THD* thd);
31 bool stmt_has_updated_trans_table(const THD *thd);
32 bool use_trans_cache(const THD* thd, bool is_transactional);
33 bool ending_trans(THD* thd, const bool all);
34 bool ending_single_stmt_trans(THD* thd, const bool all);
35 bool trans_has_updated_non_trans_table(const THD* thd);
36 bool stmt_has_updated_non_trans_table(const THD* thd);
37 
38 /*
39   Transaction Coordinator log - a base abstract class
40   for two different implementations
41 */
42 class TC_LOG
43 {
44   public:
45   int using_heuristic_recover();
TC_LOG()46   TC_LOG() {}
~TC_LOG()47   virtual ~TC_LOG() {}
48 
49   virtual int open(const char *opt_name)=0;
50   virtual void close()=0;
51   /*
52     Transaction coordinator 2-phase commit.
53 
54     Must invoke the run_prepare_ordered and run_commit_ordered methods, as
55     described below for these methods.
56 
57     In addition, must invoke THD::wait_for_prior_commit(), or equivalent
58     wait, to ensure that one commit waits for another if registered to do so.
59   */
60   virtual int log_and_order(THD *thd, my_xid xid, bool all,
61                             bool need_prepare_ordered,
62                             bool need_commit_ordered) = 0;
63   virtual int unlog(ulong cookie, my_xid xid)=0;
64   virtual void commit_checkpoint_notify(void *cookie)= 0;
65 
66 protected:
67   /*
68     These methods are meant to be invoked from log_and_order() implementations
69     to run any prepare_ordered() respectively commit_ordered() methods in
70     participating handlers.
71 
72     They must be called using suitable thread syncronisation to ensure that
73     they are each called in the correct commit order among all
74     transactions. However, it is only necessary to call them if the
75     corresponding flag passed to log_and_order is set (it is safe, but not
76     required, to call them when the flag is false).
77 
78     The caller must be holding LOCK_prepare_ordered respectively
79     LOCK_commit_ordered when calling these methods.
80   */
81   void run_prepare_ordered(THD *thd, bool all);
82   void run_commit_ordered(THD *thd, bool all);
83 };
84 
85 /*
86   Locks used to ensure serialised execution of TC_LOG::run_prepare_ordered()
87   and TC_LOG::run_commit_ordered(), or any other code that calls handler
88   prepare_ordered() or commit_ordered() methods.
89 */
90 extern mysql_mutex_t LOCK_prepare_ordered;
91 extern mysql_cond_t COND_prepare_ordered;
92 extern mysql_mutex_t LOCK_after_binlog_sync;
93 extern mysql_mutex_t LOCK_commit_ordered;
94 #ifdef HAVE_PSI_INTERFACE
95 extern PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered;
96 extern PSI_mutex_key key_LOCK_after_binlog_sync;
97 extern PSI_cond_key key_COND_prepare_ordered;
98 #endif
99 
100 class TC_LOG_DUMMY: public TC_LOG // use it to disable the logging
101 {
102 public:
TC_LOG_DUMMY()103   TC_LOG_DUMMY() {}
open(const char * opt_name)104   int open(const char *opt_name)        { return 0; }
close()105   void close()                          { }
106   /*
107     TC_LOG_DUMMY is only used when there are <= 1 XA-capable engines, and we
108     only use internal XA during commit when >= 2 XA-capable engines
109     participate.
110   */
log_and_order(THD * thd,my_xid xid,bool all,bool need_prepare_ordered,bool need_commit_ordered)111   int log_and_order(THD *thd, my_xid xid, bool all,
112                     bool need_prepare_ordered, bool need_commit_ordered)
113   {
114     DBUG_ASSERT(0);
115     return 1;
116   }
unlog(ulong cookie,my_xid xid)117   int unlog(ulong cookie, my_xid xid)  { return 0; }
commit_checkpoint_notify(void * cookie)118   void commit_checkpoint_notify(void *cookie) { DBUG_ASSERT(0); };
119 };
120 
121 #define TC_LOG_PAGE_SIZE   8192
122 
123 #ifdef HAVE_MMAP
124 class TC_LOG_MMAP: public TC_LOG
125 {
126   public:                // only to keep Sun Forte on sol9x86 happy
127   typedef enum {
128     PS_POOL,                 // page is in pool
129     PS_ERROR,                // last sync failed
130     PS_DIRTY                 // new xids added since last sync
131   } PAGE_STATE;
132 
133   struct pending_cookies {
134     uint count;
135     uint pending_count;
136     ulong cookies[1];
137   };
138 
139   private:
140   typedef struct st_page {
141     struct st_page *next; // page a linked in a fifo queue
142     my_xid *start, *end;  // usable area of a page
143     my_xid *ptr;          // next xid will be written here
144     int size, free;       // max and current number of free xid slots on the page
145     int waiters;          // number of waiters on condition
146     PAGE_STATE state;     // see above
147     mysql_mutex_t lock; // to access page data or control structure
148     mysql_cond_t  cond; // to wait for a sync
149   } PAGE;
150 
151   /* List of THDs for which to invoke commit_ordered(), in order. */
152   struct commit_entry
153   {
154     struct commit_entry *next;
155     THD *thd;
156   };
157 
158   char logname[FN_REFLEN];
159   File fd;
160   my_off_t file_length;
161   uint npages, inited;
162   uchar *data;
163   struct st_page *pages, *syncing, *active, *pool, **pool_last_ptr;
164   /*
165     note that, e.g. LOCK_active is only used to protect
166     'active' pointer, to protect the content of the active page
167     one has to use active->lock.
168     Same for LOCK_pool and LOCK_sync
169   */
170   mysql_mutex_t LOCK_active, LOCK_pool, LOCK_sync, LOCK_pending_checkpoint;
171   mysql_cond_t COND_pool, COND_active;
172   /*
173     Queue of threads that need to call commit_ordered().
174     Access to this queue must be protected by LOCK_prepare_ordered.
175   */
176   commit_entry *commit_ordered_queue;
177   /*
178     This flag and condition is used to reserve the queue while threads in it
179     each run the commit_ordered() methods one after the other. Only once the
180     last commit_ordered() in the queue is done can we start on a new queue
181     run.
182 
183     Since we start this process in the first thread in the queue and finish in
184     the last (and possibly different) thread, we need a condition variable for
185     this (we cannot unlock a mutex in a different thread than the one who
186     locked it).
187 
188     The condition is used together with the LOCK_prepare_ordered mutex.
189   */
190   mysql_cond_t COND_queue_busy;
191   my_bool commit_ordered_queue_busy;
192   pending_cookies* pending_checkpoint;
193 
194   public:
TC_LOG_MMAP()195   TC_LOG_MMAP(): inited(0), pending_checkpoint(0) {}
196   int open(const char *opt_name);
197   void close();
198   int log_and_order(THD *thd, my_xid xid, bool all,
199                     bool need_prepare_ordered, bool need_commit_ordered);
200   int unlog(ulong cookie, my_xid xid);
201   void commit_checkpoint_notify(void *cookie);
202   int recover();
203 
204   private:
205   int log_one_transaction(my_xid xid);
206   void get_active_from_pool();
207   int sync();
208   int overflow();
209   int delete_entry(ulong cookie);
210 };
211 #else
212 #define TC_LOG_MMAP TC_LOG_DUMMY
213 #endif
214 
215 extern TC_LOG *tc_log;
216 extern TC_LOG_MMAP tc_log_mmap;
217 extern TC_LOG_DUMMY tc_log_dummy;
218 
219 /* log info errors */
220 #define LOG_INFO_EOF -1
221 #define LOG_INFO_IO  -2
222 #define LOG_INFO_INVALID -3
223 #define LOG_INFO_SEEK -4
224 #define LOG_INFO_MEM -6
225 #define LOG_INFO_FATAL -7
226 #define LOG_INFO_IN_USE -8
227 #define LOG_INFO_EMFILE -9
228 
229 
230 /* bitmap to SQL_LOG::close() */
231 #define LOG_CLOSE_INDEX		1
232 #define LOG_CLOSE_TO_BE_OPENED	2
233 #define LOG_CLOSE_STOP_EVENT	4
234 #define LOG_CLOSE_DELAYED_CLOSE 8
235 
236 /*
237   Maximum unique log filename extension.
238   Note: setting to 0x7FFFFFFF due to atol windows
239         overflow/truncate.
240  */
241 #define MAX_LOG_UNIQUE_FN_EXT 0x7FFFFFFF
242 
243 /*
244    Number of warnings that will be printed to error log
245    before extension number is exhausted.
246 */
247 #define LOG_WARN_UNIQUE_FN_EXT_LEFT 1000
248 
249 class Relay_log_info;
250 
251 /*
252   Note that we destroy the lock mutex in the desctructor here.
253   This means that object instances cannot be destroyed/go out of scope,
254   until we have reset thd->current_linfo to NULL;
255  */
256 typedef struct st_log_info
257 {
258   char log_file_name[FN_REFLEN];
259   my_off_t index_file_offset, index_file_start_offset;
260   my_off_t pos;
261   bool fatal; // if the purge happens to give us a negative offset
st_log_infost_log_info262   st_log_info() : index_file_offset(0), index_file_start_offset(0),
263       pos(0), fatal(0)
264   {
265     DBUG_ENTER("LOG_INFO");
266     log_file_name[0] = '\0';
267     DBUG_VOID_RETURN;
268   }
269 } LOG_INFO;
270 
271 /*
272   Currently we have only 3 kinds of logging functions: old-fashioned
273   logs, stdout and csv logging routines.
274 */
275 #define MAX_LOG_HANDLERS_NUM 3
276 
277 /* log event handler flags */
278 #define LOG_NONE       1U
279 #define LOG_FILE       2U
280 #define LOG_TABLE      4U
281 
282 class Log_event;
283 class Rows_log_event;
284 
285 enum enum_log_type { LOG_UNKNOWN, LOG_NORMAL, LOG_BIN };
286 enum enum_log_state { LOG_OPENED, LOG_CLOSED, LOG_TO_BE_OPENED };
287 
288 /*
289   TODO use mmap instead of IO_CACHE for binlog
290   (mmap+fsync is two times faster than write+fsync)
291 */
292 
293 class MYSQL_LOG
294 {
295 public:
296   MYSQL_LOG();
~MYSQL_LOG()297   virtual ~MYSQL_LOG() {}
298   void init_pthread_objects();
299   void cleanup();
300   bool open(
301 #ifdef HAVE_PSI_INTERFACE
302             PSI_file_key log_file_key,
303 #endif
304             const char *log_name,
305             enum_log_type log_type,
306             const char *new_name, ulong next_file_number,
307             enum cache_type io_cache_type_arg);
308   bool init_and_set_log_file_name(const char *log_name,
309                                   const char *new_name,
310                                   ulong next_log_number,
311                                   enum_log_type log_type_arg,
312                                   enum cache_type io_cache_type_arg);
313   void init(enum_log_type log_type_arg,
314             enum cache_type io_cache_type_arg);
315   void close(uint exiting);
is_open()316   inline bool is_open() { return log_state != LOG_CLOSED; }
317   const char *generate_name(const char *log_name,
318                             const char *suffix,
319                             bool strip_ext, char *buff);
320   virtual int generate_new_name(char *new_name, const char *log_name,
321                                 ulong next_log_number);
322  protected:
323   /* LOCK_log is inited by init_pthread_objects() */
324   mysql_mutex_t LOCK_log;
325   char *name;
326   char log_file_name[FN_REFLEN];
327   char time_buff[20], db[NAME_LEN + 1];
328   bool write_error, inited;
329   IO_CACHE log_file;
330   enum_log_type log_type;
331   volatile enum_log_state log_state;
332   enum cache_type io_cache_type;
333   friend class Log_event;
334 #ifdef HAVE_PSI_INTERFACE
335   /** Instrumentation key to use for file io in @c log_file */
336   PSI_file_key m_log_file_key;
337 #endif
338   /* for documentation of mutexes held in various places in code */
339 };
340 
341 /* Tell the io thread if we can delay the master info sync. */
342 #define SEMI_SYNC_SLAVE_DELAY_SYNC 1
343 /* Tell the io thread if the current event needs a ack. */
344 #define SEMI_SYNC_NEED_ACK  2
345 
346 class MYSQL_QUERY_LOG: public MYSQL_LOG
347 {
348 public:
MYSQL_QUERY_LOG()349   MYSQL_QUERY_LOG() : last_time(0) {}
350   void reopen_file();
351   bool write(time_t event_time, const char *user_host, size_t user_host_len, my_thread_id thread_id,
352              const char *command_type, size_t command_type_len,
353              const char *sql_text, size_t sql_text_len);
354   bool write(THD *thd, time_t current_time,
355              const char *user_host, size_t user_host_len,
356              ulonglong query_utime, ulonglong lock_utime, bool is_command,
357              const char *sql_text, size_t sql_text_len);
open_slow_log(const char * log_name)358   bool open_slow_log(const char *log_name)
359   {
360     char buf[FN_REFLEN];
361     return open(
362 #ifdef HAVE_PSI_INTERFACE
363                 key_file_slow_log,
364 #endif
365                 generate_name(log_name, "-slow.log", 0, buf),
366                 LOG_NORMAL, 0, 0, WRITE_CACHE);
367   }
open_query_log(const char * log_name)368   bool open_query_log(const char *log_name)
369   {
370     char buf[FN_REFLEN];
371     return open(
372 #ifdef HAVE_PSI_INTERFACE
373                 key_file_query_log,
374 #endif
375                 generate_name(log_name, ".log", 0, buf),
376                 LOG_NORMAL, 0, 0, WRITE_CACHE);
377   }
378 
379 private:
380   time_t last_time;
381 };
382 
383 /*
384   We assign each binlog file an internal ID, used to identify them for unlog().
385   The IDs start from 0 and increment for each new binlog created.
386 
387   In unlog() we need to know the ID of the binlog file that the corresponding
388   transaction was written into. We also need a special value for a corner
389   case where there is no corresponding binlog id (since nothing was logged).
390   And we need an error flag to mark that unlog() must return failure.
391 
392   We use the following macros to pack all of this information into the single
393   ulong available with log_and_order() / unlog().
394 
395   Note that we cannot use the value 0 for cookie, as that is reserved as error
396   return value from log_and_order().
397   */
398 #define BINLOG_COOKIE_ERROR_RETURN 0
399 #define BINLOG_COOKIE_DUMMY_ID 1
400 #define BINLOG_COOKIE_BASE 2
401 #define BINLOG_COOKIE_DUMMY(error_flag) \
402   ( (BINLOG_COOKIE_DUMMY_ID<<1) | ((error_flag)&1) )
403 #define BINLOG_COOKIE_MAKE(id, error_flag) \
404   ( (((id)+BINLOG_COOKIE_BASE)<<1) | ((error_flag)&1) )
405 #define BINLOG_COOKIE_GET_ERROR_FLAG(c) ((c) & 1)
406 #define BINLOG_COOKIE_GET_ID(c) ( ((ulong)(c)>>1) - BINLOG_COOKIE_BASE )
407 #define BINLOG_COOKIE_IS_DUMMY(c) \
408   ( ((ulong)(c)>>1) == BINLOG_COOKIE_DUMMY_ID )
409 
410 class binlog_cache_mngr;
411 class binlog_cache_data;
412 struct rpl_gtid;
413 struct wait_for_commit;
414 
415 class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
416 {
417  private:
418 #ifdef HAVE_PSI_INTERFACE
419   /** The instrumentation key to use for @ LOCK_index. */
420   PSI_mutex_key m_key_LOCK_index;
421   /** The instrumentation key to use for @ COND_relay_log_updated */
422   PSI_cond_key m_key_relay_log_update;
423   /** The instrumentation key to use for @ COND_bin_log_updated */
424   PSI_cond_key m_key_bin_log_update;
425   /** The instrumentation key to use for opening the log file. */
426   PSI_file_key m_key_file_log;
427   /** The instrumentation key to use for opening the log index file. */
428   PSI_file_key m_key_file_log_index;
429 
430   PSI_file_key m_key_COND_queue_busy;
431   /** The instrumentation key to use for LOCK_binlog_end_pos. */
432   PSI_mutex_key m_key_LOCK_binlog_end_pos;
433 #endif
434 
435   struct group_commit_entry
436   {
437     struct group_commit_entry *next;
438     THD *thd;
439     binlog_cache_mngr *cache_mngr;
440     bool using_stmt_cache;
441     bool using_trx_cache;
442     /*
443       Extra events (COMMIT/ROLLBACK/XID, and possibly INCIDENT) to be
444       written during group commit. The incident_event is only valid if
445       trx_data->has_incident() is true.
446     */
447     Log_event *end_event;
448     Log_event *incident_event;
449     /* Set during group commit to record any per-thread error. */
450     int error;
451     int commit_errno;
452     IO_CACHE *error_cache;
453     /* This is the `all' parameter for ha_commit_ordered(). */
454     bool all;
455     /*
456       True if we need to increment xid_count in trx_group_commit_leader() and
457       decrement in unlog() (this is needed if there is a participating engine
458       that does not implement the commit_checkpoint_request() handlerton
459       method).
460     */
461     bool need_unlog;
462     /*
463       Fields used to pass the necessary information to the last thread in a
464       group commit, only used when opt_optimize_thread_scheduling is not set.
465     */
466     bool check_purge;
467     /* Flag used to optimise around wait_for_prior_commit. */
468     bool queued_by_other;
469     ulong binlog_id;
470   };
471 
472   /*
473     When this is set, a RESET MASTER is in progress.
474 
475     Then we should not write any binlog checkpoints into the binlog (that
476     could result in deadlock on LOCK_log, and we will delete all binlog files
477     anyway). Instead we should signal COND_xid_list whenever a new binlog
478     checkpoint arrives - when all have arrived, RESET MASTER will complete.
479   */
480   uint reset_master_pending;
481   ulong mark_xid_done_waiting;
482 
483   /* LOCK_log and LOCK_index are inited by init_pthread_objects() */
484   mysql_mutex_t LOCK_index;
485   mysql_mutex_t LOCK_binlog_end_pos;
486   mysql_mutex_t LOCK_xid_list;
487   mysql_cond_t  COND_xid_list;
488   mysql_cond_t  COND_relay_log_updated, COND_bin_log_updated;
489   ulonglong bytes_written;
490   IO_CACHE index_file;
491   char index_file_name[FN_REFLEN];
492   /*
493     purge_file is a temp file used in purge_logs so that the index file
494     can be updated before deleting files from disk, yielding better crash
495     recovery. It is created on demand the first time purge_logs is called
496     and then reused for subsequent calls. It is cleaned up in cleanup().
497   */
498   IO_CACHE purge_index_file;
499   char purge_index_file_name[FN_REFLEN];
500   /*
501      The max size before rotation (usable only if log_type == LOG_BIN: binary
502      logs and relay logs).
503      For a binlog, max_size should be max_binlog_size.
504      max_size is set in init(), and dynamically changed (when one does SET
505      GLOBAL MAX_BINLOG_SIZE|MAX_RELAY_LOG_SIZE) from sys_vars.cc
506   */
507   ulong max_size;
508   /*
509     Number generated by last call of find_uniq_filename(). Corresponds
510     closely with current_binlog_id
511   */
512   ulong last_used_log_number;
513   // current file sequence number for load data infile binary logging
514   uint file_id;
515   uint open_count;				// For replication
516   int readers_count;
517   /* Queue of transactions queued up to participate in group commit. */
518   group_commit_entry *group_commit_queue;
519   /*
520     Condition variable to mark that the group commit queue is busy.
521     Used when each thread does it's own commit_ordered() (when
522     binlog_optimize_thread_scheduling=1).
523     Used with the LOCK_commit_ordered mutex.
524   */
525   my_bool group_commit_queue_busy;
526   mysql_cond_t COND_queue_busy;
527   /* Total number of committed transactions. */
528   ulonglong num_commits;
529   /* Number of group commits done. */
530   ulonglong num_group_commits;
531   /* The reason why the group commit was grouped */
532   ulonglong group_commit_trigger_count, group_commit_trigger_timeout;
533   ulonglong group_commit_trigger_lock_wait;
534 
535   /* binlog encryption data */
536   struct Binlog_crypt_data crypto;
537 
538   /* pointer to the sync period variable, for binlog this will be
539      sync_binlog_period, for relay log this will be
540      sync_relay_log_period
541   */
542   uint *sync_period_ptr;
543   uint sync_counter;
544   bool state_file_deleted;
545   bool binlog_state_recover_done;
546 
get_sync_period()547   inline uint get_sync_period()
548   {
549     return *sync_period_ptr;
550   }
551 
552   int write_to_file(IO_CACHE *cache);
553   /*
554     This is used to start writing to a new log file. The difference from
555     new_file() is locking. new_file_without_locking() does not acquire
556     LOCK_log.
557   */
558   int new_file_without_locking();
559   int new_file_impl();
560   void do_checkpoint_request(ulong binlog_id);
561   void purge();
562   int write_transaction_or_stmt(group_commit_entry *entry, uint64 commit_id);
563   int queue_for_group_commit(group_commit_entry *entry);
564   bool write_transaction_to_binlog_events(group_commit_entry *entry);
565   void trx_group_commit_leader(group_commit_entry *leader);
566   bool is_xidlist_idle_nolock();
567 #ifdef WITH_WSREP
568   /*
569    When this mariadb node is slave and galera enabled. So in this case
570    we write the gtid in wsrep_run_commit itself.
571   */
572   inline bool is_gtid_cached(THD *thd);
573 #endif
574 public:
575   /*
576     A list of struct xid_count_per_binlog is used to keep track of how many
577     XIDs are in prepared, but not committed, state in each binlog. And how
578     many commit_checkpoint_request()'s are pending.
579 
580     When count drops to zero in a binlog after rotation, it means that there
581     are no more XIDs in prepared state, so that binlog is no longer needed
582     for XA crash recovery, and we can log a new binlog checkpoint event.
583 
584     The list is protected against simultaneous access from multiple
585     threads by LOCK_xid_list.
586   */
587   struct xid_count_per_binlog : public ilink {
588     char *binlog_name;
589     uint binlog_name_len;
590     ulong binlog_id;
591     /* Total prepared XIDs and pending checkpoint requests in this binlog. */
592     long xid_count;
593     long notify_count;
594     /* For linking in requests to the binlog background thread. */
595     xid_count_per_binlog *next_in_queue;
xid_count_per_binlogxid_count_per_binlog596     xid_count_per_binlog(char *log_file_name, uint log_file_name_len)
597       :binlog_id(0), xid_count(0), notify_count(0)
598     {
599       binlog_name_len= log_file_name_len;
600       binlog_name= (char *) my_malloc(binlog_name_len, MYF(MY_ZEROFILL));
601       if (binlog_name)
602         memcpy(binlog_name, log_file_name, binlog_name_len);
603     }
~xid_count_per_binlogxid_count_per_binlog604     ~xid_count_per_binlog()
605     {
606       my_free(binlog_name);
607     }
608   };
609   I_List<xid_count_per_binlog> binlog_xid_count_list;
610   mysql_mutex_t LOCK_binlog_background_thread;
611   mysql_cond_t COND_binlog_background_thread;
612   mysql_cond_t COND_binlog_background_thread_end;
613 
614   void stop_background_thread();
615 
616   using MYSQL_LOG::generate_name;
617   using MYSQL_LOG::is_open;
618 
619   /* This is relay log */
620   bool is_relay_log;
621   ulong relay_signal_cnt;  // update of the counter is checked by heartbeat
622   enum enum_binlog_checksum_alg checksum_alg_reset; // to contain a new value when binlog is rotated
623   /*
624     Holds the last seen in Relay-Log FD's checksum alg value.
625     The initial value comes from the slave's local FD that heads
626     the very first Relay-Log file. In the following the value may change
627     with each received master's FD_m.
628     Besides to be used in verification events that IO thread receives
629     (except the 1st fake Rotate, see @c Master_info:: checksum_alg_before_fd),
630     the value specifies if/how to compute checksum for slave's local events
631     and the first fake Rotate (R_f^1) coming from the master.
632     R_f^1 needs logging checksum-compatibly with the RL's heading FD_s.
633 
634     Legends for the checksum related comments:
635 
636     FD     - Format-Description event,
637     R      - Rotate event
638     R_f    - the fake Rotate event
639     E      - an arbirary event
640 
641     The underscore indexes for any event
642     `_s'   indicates the event is generated by Slave
643     `_m'   - by Master
644 
645     Two special underscore indexes of FD:
646     FD_q   - Format Description event for queuing   (relay-logging)
647     FD_e   - Format Description event for executing (relay-logging)
648 
649     Upper indexes:
650     E^n    - n:th event is a sequence
651 
652     RL     - Relay Log
653     (A)    - checksum algorithm descriptor value
654     FD.(A) - the value of (A) in FD
655   */
656   enum enum_binlog_checksum_alg relay_log_checksum_alg;
657   /*
658     These describe the log's format. This is used only for relay logs.
659     _for_exec is used by the SQL thread, _for_queue by the I/O thread. It's
660     necessary to have 2 distinct objects, because the I/O thread may be reading
661     events in a different format from what the SQL thread is reading (consider
662     the case of a master which has been upgraded from 5.0 to 5.1 without doing
663     RESET MASTER, or from 4.x to 5.0).
664   */
665   Format_description_log_event *description_event_for_exec,
666     *description_event_for_queue;
667   /*
668     Binlog position of last commit (or non-transactional write) to the binlog.
669     Access to this is protected by LOCK_commit_ordered.
670   */
671   char last_commit_pos_file[FN_REFLEN];
672   my_off_t last_commit_pos_offset;
673   ulong current_binlog_id;
674 
675   /*
676     Tracks the number of times that the master has been reset
677   */
678   Atomic_counter<uint64> reset_master_count;
679 
680   MYSQL_BIN_LOG(uint *sync_period);
681   /*
682     note that there's no destructor ~MYSQL_BIN_LOG() !
683     The reason is that we don't want it to be automatically called
684     on exit() - but only during the correct shutdown process
685   */
686 
687 #ifdef HAVE_PSI_INTERFACE
set_psi_keys(PSI_mutex_key key_LOCK_index,PSI_cond_key key_relay_log_update,PSI_cond_key key_bin_log_update,PSI_file_key key_file_log,PSI_file_key key_file_log_index,PSI_file_key key_COND_queue_busy,PSI_mutex_key key_LOCK_binlog_end_pos)688   void set_psi_keys(PSI_mutex_key key_LOCK_index,
689                     PSI_cond_key key_relay_log_update,
690                     PSI_cond_key key_bin_log_update,
691                     PSI_file_key key_file_log,
692                     PSI_file_key key_file_log_index,
693                     PSI_file_key key_COND_queue_busy,
694                     PSI_mutex_key key_LOCK_binlog_end_pos)
695   {
696     m_key_LOCK_index= key_LOCK_index;
697     m_key_relay_log_update=  key_relay_log_update;
698     m_key_bin_log_update=    key_bin_log_update;
699     m_key_file_log= key_file_log;
700     m_key_file_log_index= key_file_log_index;
701     m_key_COND_queue_busy= key_COND_queue_busy;
702     m_key_LOCK_binlog_end_pos= key_LOCK_binlog_end_pos;
703   }
704 #endif
705 
706   int open(const char *opt_name);
707   void close();
708   virtual int generate_new_name(char *new_name, const char *log_name,
709                                 ulong next_log_number);
710   int log_and_order(THD *thd, my_xid xid, bool all,
711                     bool need_prepare_ordered, bool need_commit_ordered);
712   int unlog(ulong cookie, my_xid xid);
713   void commit_checkpoint_notify(void *cookie);
714   int recover(LOG_INFO *linfo, const char *last_log_name, IO_CACHE *first_log,
715               Format_description_log_event *fdle, bool do_xa);
716   int do_binlog_recovery(const char *opt_name, bool do_xa_recovery);
717 #if !defined(MYSQL_CLIENT)
718 
719   int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event,
720                                        bool is_transactional);
721   int remove_pending_rows_event(THD *thd, bool is_transactional);
722 
723 #endif /* !defined(MYSQL_CLIENT) */
reset_bytes_written()724   void reset_bytes_written()
725   {
726     bytes_written = 0;
727   }
harvest_bytes_written(Atomic_counter<uint64> * counter)728   void harvest_bytes_written(Atomic_counter<uint64> *counter)
729   {
730 #ifndef DBUG_OFF
731     char buf1[22],buf2[22];
732 #endif
733     DBUG_ENTER("harvest_bytes_written");
734     (*counter)+=bytes_written;
735     DBUG_PRINT("info",("counter: %s  bytes_written: %s", llstr(*counter,buf1),
736 		       llstr(bytes_written,buf2)));
737     bytes_written=0;
738     DBUG_VOID_RETURN;
739   }
740   void set_max_size(ulong max_size_arg);
741 
742   /* Handle signaling that relay has been updated */
signal_relay_log_update()743   void signal_relay_log_update()
744   {
745     mysql_mutex_assert_owner(&LOCK_log);
746     DBUG_ASSERT(is_relay_log);
747     DBUG_ENTER("MYSQL_BIN_LOG::signal_relay_log_update");
748     relay_signal_cnt++;
749     mysql_cond_broadcast(&COND_relay_log_updated);
750     DBUG_VOID_RETURN;
751   }
signal_bin_log_update()752   void signal_bin_log_update()
753   {
754     mysql_mutex_assert_owner(&LOCK_binlog_end_pos);
755     DBUG_ASSERT(!is_relay_log);
756     DBUG_ENTER("MYSQL_BIN_LOG::signal_bin_log_update");
757     mysql_cond_broadcast(&COND_bin_log_updated);
758     DBUG_VOID_RETURN;
759   }
update_binlog_end_pos()760   void update_binlog_end_pos()
761   {
762     if (is_relay_log)
763       signal_relay_log_update();
764     else
765     {
766       lock_binlog_end_pos();
767       binlog_end_pos= my_b_safe_tell(&log_file);
768       signal_bin_log_update();
769       unlock_binlog_end_pos();
770     }
771   }
update_binlog_end_pos(my_off_t pos)772   void update_binlog_end_pos(my_off_t pos)
773   {
774     mysql_mutex_assert_owner(&LOCK_log);
775     mysql_mutex_assert_not_owner(&LOCK_binlog_end_pos);
776     lock_binlog_end_pos();
777     /*
778       Note: it would make more sense to assert(pos > binlog_end_pos)
779       but there are two places triggered by mtr that has pos == binlog_end_pos
780       i didn't investigate but accepted as it should do no harm
781     */
782     DBUG_ASSERT(pos >= binlog_end_pos);
783     binlog_end_pos= pos;
784     signal_bin_log_update();
785     unlock_binlog_end_pos();
786   }
787 
788   void wait_for_sufficient_commits();
789   void binlog_trigger_immediate_group_commit();
790   void wait_for_update_relay_log(THD* thd);
791   void init(ulong max_size);
792   void init_pthread_objects();
793   void cleanup();
794   bool open(const char *log_name,
795             enum_log_type log_type,
796             const char *new_name,
797             ulong next_log_number,
798 	    enum cache_type io_cache_type_arg,
799 	    ulong max_size,
800             bool null_created,
801             bool need_mutex);
802   bool open_index_file(const char *index_file_name_arg,
803                        const char *log_name, bool need_mutex);
804   /* Use this to start writing a new log file */
805   int new_file();
806 
807   bool write(Log_event* event_info,
808              my_bool *with_annotate= 0); // binary log write
809   bool write_transaction_to_binlog(THD *thd, binlog_cache_mngr *cache_mngr,
810                                    Log_event *end_ev, bool all,
811                                    bool using_stmt_cache, bool using_trx_cache);
812 
813   bool write_incident_already_locked(THD *thd);
814   bool write_incident(THD *thd);
815   void write_binlog_checkpoint_event_already_locked(const char *name, uint len);
816   int  write_cache(THD *thd, IO_CACHE *cache);
817   void set_write_error(THD *thd, bool is_transactional);
818   bool check_write_error(THD *thd);
819 
820   void start_union_events(THD *thd, query_id_t query_id_param);
821   void stop_union_events(THD *thd);
822   bool is_query_in_union(THD *thd, query_id_t query_id_param);
823 
824   bool write_event(Log_event *ev, binlog_cache_data *data, IO_CACHE *file);
write_event(Log_event * ev)825   bool write_event(Log_event *ev) { return write_event(ev, 0, &log_file); }
826 
827   bool write_event_buffer(uchar* buf,uint len);
828   bool append(Log_event* ev);
829   bool append_no_lock(Log_event* ev);
830 
831   void mark_xids_active(ulong cookie, uint xid_count);
832   void mark_xid_done(ulong cookie, bool write_checkpoint);
833   void make_log_name(char* buf, const char* log_ident);
834   bool is_active(const char* log_file_name);
835   bool can_purge_log(const char *log_file_name);
836   int update_log_index(LOG_INFO* linfo, bool need_update_threads);
837   int rotate(bool force_rotate, bool* check_purge);
838   void checkpoint_and_purge(ulong binlog_id);
839   int rotate_and_purge(bool force_rotate, DYNAMIC_ARRAY* drop_gtid_domain= NULL);
840   /**
841      Flush binlog cache and synchronize to disk.
842 
843      This function flushes events in binlog cache to binary log file,
844      it will do synchronizing according to the setting of system
845      variable 'sync_binlog'. If file is synchronized, @c synced will
846      be set to 1, otherwise 0.
847 
848      @param[out] synced if not NULL, set to 1 if file is synchronized, otherwise 0
849 
850      @retval 0 Success
851      @retval other Failure
852   */
853   bool flush_and_sync(bool *synced);
854   int purge_logs(const char *to_log, bool included,
855                  bool need_mutex, bool need_update_threads,
856                  ulonglong *decrease_log_space);
857   int purge_logs_before_date(time_t purge_time);
858   int purge_first_log(Relay_log_info* rli, bool included);
859   int set_purge_index_file_name(const char *base_file_name);
860   int open_purge_index_file(bool destroy);
861   bool is_inited_purge_index_file();
862   int close_purge_index_file();
863   int clean_purge_index_file();
864   int sync_purge_index_file();
865   int register_purge_index_entry(const char* entry);
866   int register_create_index_entry(const char* entry);
867   int purge_index_entry(THD *thd, ulonglong *decrease_log_space,
868                         bool need_mutex);
869   bool reset_logs(THD* thd, bool create_new_log,
870                   rpl_gtid *init_state, uint32 init_state_len,
871                   ulong next_log_number);
872   void wait_for_last_checkpoint_event();
873   void close(uint exiting);
874   void clear_inuse_flag_when_closing(File file);
875 
876   // iterating through the log index file
877   int find_log_pos(LOG_INFO* linfo, const char* log_name,
878 		   bool need_mutex);
879   int find_next_log(LOG_INFO* linfo, bool need_mutex);
880   int get_current_log(LOG_INFO* linfo);
881   int raw_get_current_log(LOG_INFO* linfo);
882   uint next_file_id();
get_index_fname()883   inline char* get_index_fname() { return index_file_name;}
get_log_fname()884   inline char* get_log_fname() { return log_file_name; }
get_name()885   inline char* get_name() { return name; }
get_log_lock()886   inline mysql_mutex_t* get_log_lock() { return &LOCK_log; }
get_bin_log_cond()887   inline mysql_cond_t* get_bin_log_cond() { return &COND_bin_log_updated; }
get_log_file()888   inline IO_CACHE* get_log_file() { return &log_file; }
get_reset_master_count()889   inline uint64 get_reset_master_count() { return reset_master_count; }
890 
lock_index()891   inline void lock_index() { mysql_mutex_lock(&LOCK_index);}
unlock_index()892   inline void unlock_index() { mysql_mutex_unlock(&LOCK_index);}
get_index_file()893   inline IO_CACHE *get_index_file() { return &index_file;}
get_open_count()894   inline uint32 get_open_count() { return open_count; }
895   void set_status_variables(THD *thd);
896   bool is_xidlist_idle();
897   bool write_gtid_event(THD *thd, bool standalone, bool is_transactional,
898                         uint64 commit_id);
899   int read_state_from_file();
900   int write_state_to_file();
901   int get_most_recent_gtid_list(rpl_gtid **list, uint32 *size);
902   bool append_state_pos(String *str);
903   bool append_state(String *str);
904   bool is_empty_state();
905   bool find_in_binlog_state(uint32 domain_id, uint32 server_id,
906                             rpl_gtid *out_gtid);
907   bool lookup_domain_in_binlog_state(uint32 domain_id, rpl_gtid *out_gtid);
908   int bump_seq_no_counter_if_needed(uint32 domain_id, uint64 seq_no);
909   bool check_strict_gtid_sequence(uint32 domain_id, uint32 server_id,
910                                   uint64 seq_no);
911 
912   /**
913    * used when opening new file, and binlog_end_pos moves backwards
914    */
reset_binlog_end_pos(const char file_name[FN_REFLEN],my_off_t pos)915   void reset_binlog_end_pos(const char file_name[FN_REFLEN], my_off_t pos)
916   {
917     mysql_mutex_assert_owner(&LOCK_log);
918     mysql_mutex_assert_not_owner(&LOCK_binlog_end_pos);
919     lock_binlog_end_pos();
920     binlog_end_pos= pos;
921     strcpy(binlog_end_pos_file, file_name);
922     signal_bin_log_update();
923     unlock_binlog_end_pos();
924   }
925 
926   /*
927     It is called by the threads(e.g. dump thread) which want to read
928     log without LOCK_log protection.
929   */
get_binlog_end_pos(char file_name_buf[FN_REFLEN])930   my_off_t get_binlog_end_pos(char file_name_buf[FN_REFLEN]) const
931   {
932     mysql_mutex_assert_not_owner(&LOCK_log);
933     mysql_mutex_assert_owner(&LOCK_binlog_end_pos);
934     strcpy(file_name_buf, binlog_end_pos_file);
935     return binlog_end_pos;
936   }
lock_binlog_end_pos()937   void lock_binlog_end_pos() { mysql_mutex_lock(&LOCK_binlog_end_pos); }
unlock_binlog_end_pos()938   void unlock_binlog_end_pos() { mysql_mutex_unlock(&LOCK_binlog_end_pos); }
get_binlog_end_pos_lock()939   mysql_mutex_t* get_binlog_end_pos_lock() { return &LOCK_binlog_end_pos; }
940 
941   /*
942     Ensures the log's state is either LOG_OPEN or LOG_CLOSED. If something
943     failed along the desired path and left the log in invalid state, i.e.
944     LOG_TO_BE_OPENED, forces the state to be LOG_CLOSED.
945   */
try_fix_log_state()946   void try_fix_log_state()
947   {
948     mysql_mutex_lock(get_log_lock());
949     /* Only change the log state if it is LOG_TO_BE_OPENED */
950     if (log_state == LOG_TO_BE_OPENED)
951       log_state= LOG_CLOSED;
952     mysql_mutex_unlock(get_log_lock());
953   }
954 
955   int wait_for_update_binlog_end_pos(THD* thd, struct timespec * timeout);
956 
957   /*
958     Binlog position of end of the binlog.
959     Access to this is protected by LOCK_binlog_end_pos
960 
961     The difference between this and last_commit_pos_{file,offset} is that
962     the commit position is updated later. If semi-sync wait point is set
963     to WAIT_AFTER_SYNC, the commit pos is update after semi-sync-ack has
964     been received and the end point is updated after the write as it's needed
965     for the dump threads to be able to semi-sync the event.
966   */
967   my_off_t binlog_end_pos;
968   char binlog_end_pos_file[FN_REFLEN];
969 };
970 
971 class Log_event_handler
972 {
973 public:
Log_event_handler()974   Log_event_handler() {}
975   virtual bool init()= 0;
976   virtual void cleanup()= 0;
977 
978   virtual bool log_slow(THD *thd, my_hrtime_t current_time,
979                         const char *user_host, size_t user_host_len, ulonglong query_utime,
980                         ulonglong lock_utime, bool is_command,
981                         const char *sql_text, size_t sql_text_len)= 0;
982   virtual bool log_error(enum loglevel level, const char *format,
983                          va_list args)= 0;
984   virtual bool log_general(THD *thd, my_hrtime_t event_time, const char *user_host, size_t user_host_len, my_thread_id thread_id,
985                            const char *command_type, size_t command_type_len,
986                            const char *sql_text, size_t sql_text_len,
987                            CHARSET_INFO *client_cs)= 0;
~Log_event_handler()988   virtual ~Log_event_handler() {}
989 };
990 
991 
992 int check_if_log_table(const TABLE_LIST *table, bool check_if_opened,
993                        const char *errmsg);
994 
995 class Log_to_csv_event_handler: public Log_event_handler
996 {
997   friend class LOGGER;
998 
999 public:
1000   Log_to_csv_event_handler();
1001   ~Log_to_csv_event_handler();
1002   virtual bool init();
1003   virtual void cleanup();
1004 
1005   virtual bool log_slow(THD *thd, my_hrtime_t current_time,
1006                         const char *user_host, size_t user_host_len, ulonglong query_utime,
1007                         ulonglong lock_utime, bool is_command,
1008                         const char *sql_text, size_t sql_text_len);
1009   virtual bool log_error(enum loglevel level, const char *format,
1010                          va_list args);
1011   virtual bool log_general(THD *thd, my_hrtime_t event_time, const char *user_host, size_t user_host_len, my_thread_id thread_id,
1012                            const char *command_type, size_t command_type_len,
1013                            const char *sql_text, size_t sql_text_len,
1014                            CHARSET_INFO *client_cs);
1015 
1016   int activate_log(THD *thd, uint log_type);
1017 };
1018 
1019 
1020 /* type of the log table */
1021 #define QUERY_LOG_SLOW 1
1022 #define QUERY_LOG_GENERAL 2
1023 
1024 class Log_to_file_event_handler: public Log_event_handler
1025 {
1026   MYSQL_QUERY_LOG mysql_log;
1027   MYSQL_QUERY_LOG mysql_slow_log;
1028   bool is_initialized;
1029 public:
Log_to_file_event_handler()1030   Log_to_file_event_handler(): is_initialized(FALSE)
1031   {}
1032   virtual bool init();
1033   virtual void cleanup();
1034 
1035   virtual bool log_slow(THD *thd, my_hrtime_t current_time,
1036                         const char *user_host, size_t user_host_len, ulonglong query_utime,
1037                         ulonglong lock_utime, bool is_command,
1038                         const char *sql_text, size_t sql_text_len);
1039   virtual bool log_error(enum loglevel level, const char *format,
1040                          va_list args);
1041   virtual bool log_general(THD *thd, my_hrtime_t event_time, const char *user_host, size_t user_host_len, my_thread_id thread_id,
1042                            const char *command_type, size_t command_type_len,
1043                            const char *sql_text, size_t sql_text_len,
1044                            CHARSET_INFO *client_cs);
1045   void flush();
1046   void init_pthread_objects();
get_mysql_slow_log()1047   MYSQL_QUERY_LOG *get_mysql_slow_log() { return &mysql_slow_log; }
get_mysql_log()1048   MYSQL_QUERY_LOG *get_mysql_log() { return &mysql_log; }
1049 };
1050 
1051 
1052 /* Class which manages slow, general and error log event handlers */
1053 class LOGGER
1054 {
1055   mysql_rwlock_t LOCK_logger;
1056   /* flag to check whether logger mutex is initialized */
1057   uint inited;
1058 
1059   /* available log handlers */
1060   Log_to_csv_event_handler *table_log_handler;
1061   Log_to_file_event_handler *file_log_handler;
1062 
1063   /* NULL-terminated arrays of log handlers */
1064   Log_event_handler *error_log_handler_list[MAX_LOG_HANDLERS_NUM + 1];
1065   Log_event_handler *slow_log_handler_list[MAX_LOG_HANDLERS_NUM + 1];
1066   Log_event_handler *general_log_handler_list[MAX_LOG_HANDLERS_NUM + 1];
1067 
1068 public:
1069 
1070   bool is_log_tables_initialized;
1071 
LOGGER()1072   LOGGER() : inited(0), table_log_handler(NULL),
1073              file_log_handler(NULL), is_log_tables_initialized(FALSE)
1074   {}
lock_shared()1075   void lock_shared() { mysql_rwlock_rdlock(&LOCK_logger); }
lock_exclusive()1076   void lock_exclusive() { mysql_rwlock_wrlock(&LOCK_logger); }
unlock()1077   void unlock() { mysql_rwlock_unlock(&LOCK_logger); }
1078   bool is_log_table_enabled(uint log_table_type);
1079   bool log_command(THD *thd, enum enum_server_command command);
1080 
1081   /*
1082     We want to initialize all log mutexes as soon as possible,
1083     but we cannot do it in constructor, as safe_mutex relies on
1084     initialization, performed by MY_INIT(). This why this is done in
1085     this function.
1086   */
1087   void init_base();
1088   void init_log_tables();
1089   bool flush_slow_log();
1090   bool flush_general_log();
1091   /* Perform basic logger cleanup. this will leave e.g. error log open. */
1092   void cleanup_base();
1093   /* Free memory. Nothing could be logged after this function is called */
1094   void cleanup_end();
1095   bool error_log_print(enum loglevel level, const char *format,
1096                       va_list args);
1097   bool slow_log_print(THD *thd, const char *query, size_t query_length,
1098                       ulonglong current_utime);
1099   bool general_log_print(THD *thd,enum enum_server_command command,
1100                          const char *format, va_list args);
1101   bool general_log_write(THD *thd, enum enum_server_command command,
1102                          const char *query, size_t query_length);
1103 
1104   /* we use this function to setup all enabled log event handlers */
1105   int set_handlers(ulonglong error_log_printer,
1106                    ulonglong slow_log_printer,
1107                    ulonglong general_log_printer);
1108   void init_error_log(ulonglong error_log_printer);
1109   void init_slow_log(ulonglong slow_log_printer);
1110   void init_general_log(ulonglong general_log_printer);
1111   void deactivate_log_handler(THD* thd, uint log_type);
1112   bool activate_log_handler(THD* thd, uint log_type);
get_slow_log_file_handler()1113   MYSQL_QUERY_LOG *get_slow_log_file_handler() const
1114   {
1115     if (file_log_handler)
1116       return file_log_handler->get_mysql_slow_log();
1117     return NULL;
1118   }
get_log_file_handler()1119   MYSQL_QUERY_LOG *get_log_file_handler() const
1120   {
1121     if (file_log_handler)
1122       return file_log_handler->get_mysql_log();
1123     return NULL;
1124   }
1125 };
1126 
1127 enum enum_binlog_format {
1128   BINLOG_FORMAT_MIXED= 0, ///< statement if safe, otherwise row - autodetected
1129   BINLOG_FORMAT_STMT=  1, ///< statement-based
1130   BINLOG_FORMAT_ROW=   2, ///< row-based
1131   BINLOG_FORMAT_UNSPEC=3  ///< thd_binlog_format() returns it when binlog is closed
1132 };
1133 
1134 int query_error_code(THD *thd, bool not_killed);
1135 uint purge_log_get_error_code(int res);
1136 
1137 int vprint_msg_to_log(enum loglevel level, const char *format, va_list args);
1138 void sql_print_error(const char *format, ...);
1139 void sql_print_warning(const char *format, ...);
1140 void sql_print_information(const char *format, ...);
1141 void sql_print_information_v(const char *format, va_list ap);
1142 typedef void (*sql_print_message_func)(const char *format, ...);
1143 extern sql_print_message_func sql_print_message_handlers[];
1144 
1145 int error_log_print(enum loglevel level, const char *format,
1146                     va_list args);
1147 
1148 bool slow_log_print(THD *thd, const char *query, uint query_length,
1149                     ulonglong current_utime);
1150 
1151 bool general_log_print(THD *thd, enum enum_server_command command,
1152                        const char *format,...);
1153 
1154 bool general_log_write(THD *thd, enum enum_server_command command,
1155                        const char *query, size_t query_length);
1156 
1157 void binlog_report_wait_for(THD *thd, THD *other_thd);
1158 void sql_perror(const char *message);
1159 bool flush_error_log();
1160 
1161 File open_binlog(IO_CACHE *log, const char *log_file_name,
1162                  const char **errmsg);
1163 
1164 void make_default_log_name(char **out, const char* log_ext, bool once);
1165 void binlog_reset_cache(THD *thd);
1166 
1167 extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log;
1168 extern handlerton *binlog_hton;
1169 extern LOGGER logger;
1170 
1171 extern const char *log_bin_index;
1172 extern const char *log_bin_basename;
1173 
1174 /**
1175   Turns a relative log binary log path into a full path, based on the
1176   opt_bin_logname or opt_relay_logname.
1177 
1178   @param from         The log name we want to make into an absolute path.
1179   @param to           The buffer where to put the results of the
1180                       normalization.
1181   @param is_relay_log Switch that makes is used inside to choose which
1182                       option (opt_bin_logname or opt_relay_logname) to
1183                       use when calculating the base path.
1184 
1185   @returns true if a problem occurs, false otherwise.
1186  */
1187 
normalize_binlog_name(char * to,const char * from,bool is_relay_log)1188 inline bool normalize_binlog_name(char *to, const char *from, bool is_relay_log)
1189 {
1190   DBUG_ENTER("normalize_binlog_name");
1191   bool error= false;
1192   char buff[FN_REFLEN];
1193   char *ptr= (char*) from;
1194   char *opt_name= is_relay_log ? opt_relay_logname : opt_bin_logname;
1195 
1196   DBUG_ASSERT(from);
1197 
1198   /* opt_name is not null and not empty and from is a relative path */
1199   if (opt_name && opt_name[0] && from && !test_if_hard_path(from))
1200   {
1201     // take the path from opt_name
1202     // take the filename from from
1203     char log_dirpart[FN_REFLEN], log_dirname[FN_REFLEN];
1204     size_t log_dirpart_len, log_dirname_len;
1205     dirname_part(log_dirpart, opt_name, &log_dirpart_len);
1206     dirname_part(log_dirname, from, &log_dirname_len);
1207 
1208     /* log may be empty => relay-log or log-bin did not
1209         hold paths, just filename pattern */
1210     if (log_dirpart_len > 0)
1211     {
1212       /* create the new path name */
1213       if(fn_format(buff, from+log_dirname_len, log_dirpart, "",
1214                    MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH)) == NULL)
1215       {
1216         error= true;
1217         goto end;
1218       }
1219 
1220       ptr= buff;
1221     }
1222   }
1223 
1224   DBUG_ASSERT(ptr);
1225 
1226   if (ptr)
1227     strmake(to, ptr, strlen(ptr));
1228 
1229 end:
1230   DBUG_RETURN(error);
1231 }
1232 
get_tc_log_implementation()1233 static inline TC_LOG *get_tc_log_implementation()
1234 {
1235   if (total_ha_2pc <= 1)
1236     return &tc_log_dummy;
1237   if (opt_bin_log)
1238     return &mysql_bin_log;
1239   return &tc_log_mmap;
1240 }
1241 
1242 #ifdef WITH_WSREP
1243 IO_CACHE* wsrep_get_trans_cache(THD *);
1244 void wsrep_thd_binlog_trx_reset(THD * thd);
1245 void wsrep_thd_binlog_stmt_rollback(THD * thd);
1246 #endif /* WITH_WSREP */
1247 
1248 class Gtid_list_log_event;
1249 const char *
1250 get_gtid_list_event(IO_CACHE *cache, Gtid_list_log_event **out_gtid_list);
1251 
1252 #endif /* LOG_H */
1253