1 #ifndef BINLOG_H_INCLUDED
2 /* Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.
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, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software Foundation,
22    51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
23 
24 #define BINLOG_H_INCLUDED
25 
26 #include "mysqld.h"                             /* opt_relay_logname */
27 #include "log_event.h"
28 #include "log.h"
29 
30 class Relay_log_info;
31 class Master_info;
32 
33 class Format_description_log_event;
34 
35 /**
36   Class for maintaining the commit stages for binary log group commit.
37  */
38 class Stage_manager {
39 public:
40   class Mutex_queue {
41     friend class Stage_manager;
42   public:
Mutex_queue()43     Mutex_queue()
44       : m_first(NULL), m_last(&m_first)
45     {
46     }
47 
init(PSI_mutex_key key_LOCK_queue)48     void init(
49 #ifdef HAVE_PSI_INTERFACE
50               PSI_mutex_key key_LOCK_queue
51 #endif
52               ) {
53       mysql_mutex_init(key_LOCK_queue, &m_lock, MY_MUTEX_INIT_FAST);
54     }
55 
deinit()56     void deinit() {
57       mysql_mutex_destroy(&m_lock);
58     }
59 
is_empty()60     bool is_empty() const {
61       return m_first == NULL;
62     }
63 
64     /** Append a linked list of threads to the queue */
65     bool append(THD *first);
66 
67     /**
68        Fetch the entire queue for a stage.
69 
70        This will fetch the entire queue in one go.
71     */
72     THD *fetch_and_empty();
73 
74     std::pair<bool,THD*> pop_front();
75 
76   private:
lock()77     void lock() { mysql_mutex_lock(&m_lock); }
unlock()78     void unlock() { mysql_mutex_unlock(&m_lock); }
79 
80     /**
81        Pointer to the first thread in the queue, or NULL if the queue is
82        empty.
83     */
84     THD *m_first;
85 
86     /**
87        Pointer to the location holding the end of the queue.
88 
89        This is either @c &first, or a pointer to the @c next_to_commit of
90        the last thread that is enqueued.
91     */
92     THD **m_last;
93 
94     /** Lock for protecting the queue. */
95     mysql_mutex_t m_lock;
96   } MY_ATTRIBUTE((aligned(CPU_LEVEL1_DCACHE_LINESIZE)));
97 
98 public:
Stage_manager()99   Stage_manager()
100   {
101   }
102 
~Stage_manager()103   ~Stage_manager()
104   {
105   }
106 
107   /**
108      Constants for queues for different stages.
109    */
110   enum StageID {
111     FLUSH_STAGE,
112     SYNC_STAGE,
113     COMMIT_STAGE,
114     STAGE_COUNTER
115   };
116 
init(PSI_mutex_key key_LOCK_flush_queue,PSI_mutex_key key_LOCK_sync_queue,PSI_mutex_key key_LOCK_commit_queue,PSI_mutex_key key_LOCK_done,PSI_cond_key key_COND_done)117   void init(
118 #ifdef HAVE_PSI_INTERFACE
119             PSI_mutex_key key_LOCK_flush_queue,
120             PSI_mutex_key key_LOCK_sync_queue,
121             PSI_mutex_key key_LOCK_commit_queue,
122             PSI_mutex_key key_LOCK_done,
123             PSI_cond_key key_COND_done
124 #endif
125             )
126   {
127     mysql_mutex_init(key_LOCK_done, &m_lock_done, MY_MUTEX_INIT_FAST);
128     mysql_cond_init(key_COND_done, &m_cond_done, NULL);
129 #ifndef DBUG_OFF
130     /* reuse key_COND_done 'cos a new PSI object would be wasteful in DBUG_ON */
131     mysql_cond_init(key_COND_done, &m_cond_preempt, NULL);
132 #endif
133     m_queue[FLUSH_STAGE].init(
134 #ifdef HAVE_PSI_INTERFACE
135                               key_LOCK_flush_queue
136 #endif
137                               );
138     m_queue[SYNC_STAGE].init(
139 #ifdef HAVE_PSI_INTERFACE
140                              key_LOCK_sync_queue
141 #endif
142                              );
143     m_queue[COMMIT_STAGE].init(
144 #ifdef HAVE_PSI_INTERFACE
145                                key_LOCK_commit_queue
146 #endif
147                                );
148   }
149 
deinit()150   void deinit()
151   {
152     for (size_t i = 0 ; i < STAGE_COUNTER ; ++i)
153       m_queue[i].deinit();
154     mysql_cond_destroy(&m_cond_done);
155     mysql_mutex_destroy(&m_lock_done);
156   }
157 
158   /**
159     Enroll a set of sessions for a stage.
160 
161     This will queue the session thread for writing and flushing.
162 
163     If the thread being queued is assigned as stage leader, it will
164     return immediately.
165 
166     If wait_if_follower is true the thread is not the stage leader,
167     the thread will be wait for the queue to be processed by the
168     leader before it returns.
169     In DBUG-ON version the follower marks is preempt status as ready.
170 
171     @param stage Stage identifier for the queue to append to.
172     @param first Queue to append.
173     @param stage_mutex
174                  Pointer to the currently held stage mutex, or NULL if
175                  we're not in a stage.
176 
177     @retval true  Thread is stage leader.
178     @retval false Thread was not stage leader and processing has been done.
179    */
180   bool enroll_for(StageID stage, THD *first, mysql_mutex_t *stage_mutex);
181 
pop_front(StageID stage)182   std::pair<bool,THD*> pop_front(StageID stage)
183   {
184     return m_queue[stage].pop_front();
185   }
186 
187 #ifndef DBUG_OFF
188   /**
189      The method ensures the follower's execution path can be preempted
190      by the leader's thread.
191      Preempt status of @c head follower is checked to engange the leader
192      into waiting when set.
193 
194      @param head  THD* of a follower thread
195   */
196   void clear_preempt_status(THD *head);
197 #endif
198 
199   /**
200     Fetch the entire queue and empty it.
201 
202     @return Pointer to the first session of the queue.
203    */
fetch_queue_for(StageID stage)204   THD *fetch_queue_for(StageID stage) {
205     DBUG_PRINT("debug", ("Fetching queue for stage %d", stage));
206     return m_queue[stage].fetch_and_empty();
207   }
208 
signal_done(THD * queue)209   void signal_done(THD *queue) {
210     mysql_mutex_lock(&m_lock_done);
211     for (THD *thd= queue ; thd ; thd = thd->next_to_commit)
212       thd->transaction.flags.pending= false;
213     mysql_mutex_unlock(&m_lock_done);
214     mysql_cond_broadcast(&m_cond_done);
215   }
216 
217 private:
218   /**
219      Queues for sessions.
220 
221      We need two queues:
222      - Waiting. Threads waiting to be processed
223      - Committing. Threads waiting to be committed.
224    */
225   Mutex_queue m_queue[STAGE_COUNTER];
226 
227   /** Condition variable to indicate that the commit was processed */
228   mysql_cond_t m_cond_done;
229 
230   /** Mutex used for the condition variable above */
231   mysql_mutex_t m_lock_done;
232 #ifndef DBUG_OFF
233   /** Flag is set by Leader when it starts waiting for follower's all-clear */
234   bool leader_await_preempt_status;
235 
236   /** Condition variable to indicate a follower started waiting for commit */
237   mysql_cond_t m_cond_preempt;
238 #endif
239 };
240 
241 
242 class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
243 {
244  private:
245 #ifdef HAVE_PSI_INTERFACE
246   /** The instrumentation key to use for @ LOCK_index. */
247   PSI_mutex_key m_key_LOCK_index;
248 
249   PSI_mutex_key m_key_COND_done;
250 
251   PSI_mutex_key m_key_LOCK_commit_queue;
252   PSI_mutex_key m_key_LOCK_done;
253   PSI_mutex_key m_key_LOCK_flush_queue;
254   PSI_mutex_key m_key_LOCK_sync_queue;
255   /** The instrumentation key to use for @ LOCK_commit. */
256   PSI_mutex_key m_key_LOCK_commit;
257   /** The instrumentation key to use for @ LOCK_sync. */
258   PSI_mutex_key m_key_LOCK_sync;
259   /** The instrumentation key to use for @ LOCK_xids. */
260   PSI_mutex_key m_key_LOCK_xids;
261   /** The instrumentation key to use for @ update_cond. */
262   PSI_cond_key m_key_update_cond;
263   /** The instrumentation key to use for @ prep_xids_cond. */
264   PSI_cond_key m_key_prep_xids_cond;
265   /** The instrumentation key to use for opening the log file. */
266   PSI_file_key m_key_file_log;
267   /** The instrumentation key to use for opening the log index file. */
268   PSI_file_key m_key_file_log_index;
269 #endif
270   /* POSIX thread objects are inited by init_pthread_objects() */
271   mysql_mutex_t LOCK_index;
272   mysql_mutex_t LOCK_commit;
273   mysql_mutex_t LOCK_sync;
274   mysql_mutex_t LOCK_xids;
275   mysql_cond_t update_cond;
276   ulonglong bytes_written;
277   IO_CACHE index_file;
278   char index_file_name[FN_REFLEN];
279   /*
280     crash_safe_index_file is temp file used for guaranteeing
281     index file crash safe when master server restarts.
282   */
283   IO_CACHE crash_safe_index_file;
284   char crash_safe_index_file_name[FN_REFLEN];
285   /*
286     purge_file is a temp file used in purge_logs so that the index file
287     can be updated before deleting files from disk, yielding better crash
288     recovery. It is created on demand the first time purge_logs is called
289     and then reused for subsequent calls. It is cleaned up in cleanup().
290   */
291   IO_CACHE purge_index_file;
292   char purge_index_file_name[FN_REFLEN];
293   /*
294      The max size before rotation (usable only if log_type == LOG_BIN: binary
295      logs and relay logs).
296      For a binlog, max_size should be max_binlog_size.
297      For a relay log, it should be max_relay_log_size if this is non-zero,
298      max_binlog_size otherwise.
299      max_size is set in init(), and dynamically changed (when one does SET
300      GLOBAL MAX_BINLOG_SIZE|MAX_RELAY_LOG_SIZE) by fix_max_binlog_size and
301      fix_max_relay_log_size).
302   */
303   ulong max_size;
304 
305   // current file sequence number for load data infile binary logging
306   uint file_id;
307   uint open_count;				// For replication
308   int readers_count;
309 
310   /* pointer to the sync period variable, for binlog this will be
311      sync_binlog_period, for relay log this will be
312      sync_relay_log_period
313   */
314   uint *sync_period_ptr;
315   uint sync_counter;
316 
317   my_atomic_rwlock_t m_prep_xids_lock;
318   mysql_cond_t m_prep_xids_cond;
319   volatile int32 m_prep_xids;
320 
321   /**
322     Increment the prepared XID counter.
323    */
inc_prep_xids(THD * thd)324   void inc_prep_xids(THD *thd) {
325     DBUG_ENTER("MYSQL_BIN_LOG::inc_prep_xids");
326     my_atomic_rwlock_wrlock(&m_prep_xids_lock);
327 #ifndef DBUG_OFF
328     int result= my_atomic_add32(&m_prep_xids, 1);
329 #else
330     (void) my_atomic_add32(&m_prep_xids, 1);
331 #endif
332     DBUG_PRINT("debug", ("m_prep_xids: %d", result + 1));
333     my_atomic_rwlock_wrunlock(&m_prep_xids_lock);
334     thd->transaction.flags.xid_written= true;
335     DBUG_VOID_RETURN;
336   }
337 
338   /**
339     Decrement the prepared XID counter.
340 
341     Signal m_prep_xids_cond if the counter reaches zero.
342    */
dec_prep_xids(THD * thd)343   void dec_prep_xids(THD *thd) {
344     DBUG_ENTER("MYSQL_BIN_LOG::dec_prep_xids");
345     my_atomic_rwlock_wrlock(&m_prep_xids_lock);
346     int32 result= my_atomic_add32(&m_prep_xids, -1);
347     DBUG_PRINT("debug", ("m_prep_xids: %d", result - 1));
348     my_atomic_rwlock_wrunlock(&m_prep_xids_lock);
349     thd->transaction.flags.xid_written= false;
350     /* If the old value was 1, it is zero now. */
351     if (result == 1)
352     {
353       mysql_mutex_lock(&LOCK_xids);
354       mysql_cond_signal(&m_prep_xids_cond);
355       mysql_mutex_unlock(&LOCK_xids);
356     }
357     DBUG_VOID_RETURN;
358   }
359 
get_prep_xids()360   int32 get_prep_xids() {
361     my_atomic_rwlock_rdlock(&m_prep_xids_lock);
362     int32 result= my_atomic_load32(&m_prep_xids);
363     my_atomic_rwlock_rdunlock(&m_prep_xids_lock);
364     return result;
365   }
366 
get_sync_period()367   inline uint get_sync_period()
368   {
369     return *sync_period_ptr;
370   }
371 
372   int write_to_file(IO_CACHE *cache);
373   /*
374     This is used to start writing to a new log file. The difference from
375     new_file() is locking. new_file_without_locking() does not acquire
376     LOCK_log.
377   */
378   int new_file_without_locking(Format_description_log_event *extra_description_event);
379   int new_file_impl(bool need_lock, Format_description_log_event *extra_description_event);
380 
381   /** Manage the stages in ordered_commit. */
382   Stage_manager stage_manager;
383   void do_flush(THD *thd);
384 
385 public:
386   using MYSQL_LOG::generate_name;
387   using MYSQL_LOG::is_open;
388 
389   /* This is relay log */
390   bool is_relay_log;
391   ulong signal_cnt;  // update of the counter is checked by heartbeat
392   uint8 checksum_alg_reset; // to contain a new value when binlog is rotated
393   /*
394     Holds the last seen in Relay-Log FD's checksum alg value.
395     The initial value comes from the slave's local FD that heads
396     the very first Relay-Log file. In the following the value may change
397     with each received master's FD_m.
398     Besides to be used in verification events that IO thread receives
399     (except the 1st fake Rotate, see @c Master_info:: checksum_alg_before_fd),
400     the value specifies if/how to compute checksum for slave's local events
401     and the first fake Rotate (R_f^1) coming from the master.
402     R_f^1 needs logging checksum-compatibly with the RL's heading FD_s.
403 
404     Legends for the checksum related comments:
405 
406     FD     - Format-Description event,
407     R      - Rotate event
408     R_f    - the fake Rotate event
409     E      - an arbirary event
410 
411     The underscore indexes for any event
412     `_s'   indicates the event is generated by Slave
413     `_m'   - by Master
414 
415     Two special underscore indexes of FD:
416     FD_q   - Format Description event for queuing   (relay-logging)
417     FD_e   - Format Description event for executing (relay-logging)
418 
419     Upper indexes:
420     E^n    - n:th event is a sequence
421 
422     RL     - Relay Log
423     (A)    - checksum algorithm descriptor value
424     FD.(A) - the value of (A) in FD
425   */
426   uint8 relay_log_checksum_alg;
427 
428   MYSQL_BIN_LOG(uint *sync_period);
429   /*
430     note that there's no destructor ~MYSQL_BIN_LOG() !
431     The reason is that we don't want it to be automatically called
432     on exit() - but only during the correct shutdown process
433   */
434 
435 #ifdef HAVE_PSI_INTERFACE
set_psi_keys(PSI_mutex_key key_LOCK_index,PSI_mutex_key key_LOCK_commit,PSI_mutex_key key_LOCK_commit_queue,PSI_mutex_key key_LOCK_done,PSI_mutex_key key_LOCK_flush_queue,PSI_mutex_key key_LOCK_log,PSI_mutex_key key_LOCK_sync,PSI_mutex_key key_LOCK_sync_queue,PSI_mutex_key key_LOCK_xids,PSI_cond_key key_COND_done,PSI_cond_key key_update_cond,PSI_cond_key key_prep_xids_cond,PSI_file_key key_file_log,PSI_file_key key_file_log_index)436   void set_psi_keys(PSI_mutex_key key_LOCK_index,
437                     PSI_mutex_key key_LOCK_commit,
438                     PSI_mutex_key key_LOCK_commit_queue,
439                     PSI_mutex_key key_LOCK_done,
440                     PSI_mutex_key key_LOCK_flush_queue,
441                     PSI_mutex_key key_LOCK_log,
442                     PSI_mutex_key key_LOCK_sync,
443                     PSI_mutex_key key_LOCK_sync_queue,
444                     PSI_mutex_key key_LOCK_xids,
445                     PSI_cond_key key_COND_done,
446                     PSI_cond_key key_update_cond,
447                     PSI_cond_key key_prep_xids_cond,
448                     PSI_file_key key_file_log,
449                     PSI_file_key key_file_log_index)
450   {
451     m_key_COND_done= key_COND_done;
452 
453     m_key_LOCK_commit_queue= key_LOCK_commit_queue;
454     m_key_LOCK_done= key_LOCK_done;
455     m_key_LOCK_flush_queue= key_LOCK_flush_queue;
456     m_key_LOCK_sync_queue= key_LOCK_sync_queue;
457 
458     m_key_LOCK_index= key_LOCK_index;
459     m_key_LOCK_log= key_LOCK_log;
460     m_key_LOCK_commit= key_LOCK_commit;
461     m_key_LOCK_sync= key_LOCK_sync;
462     m_key_LOCK_xids= key_LOCK_xids;
463     m_key_update_cond= key_update_cond;
464     m_key_prep_xids_cond= key_prep_xids_cond;
465     m_key_file_log= key_file_log;
466     m_key_file_log_index= key_file_log_index;
467   }
468 #endif
469   /**
470     Find the oldest binary log that contains any GTID that
471     is not in the given gtid set.
472 
473     @param[out] binlog_file_name, the file name of oldest binary log found
474     @param[in]  gtid_set, the given gtid set
475     @param[out] first_gtid, the first GTID information from the binary log
476                 file returned at binlog_file_name
477     @param[out] errmsg, the error message outputted, which is left untouched
478                 if the function returns false
479     @return false on success, true on error.
480   */
481   bool find_first_log_not_in_gtid_set(char *binlog_file_name,
482                                       const Gtid_set *gtid_set,
483                                       Gtid *first_gtid,
484                                       const char **errmsg);
485 
486   /**
487     Reads the set of all GTIDs in the binary log, and the set of all
488     lost GTIDs in the binary log, and stores each set in respective
489     argument.
490 
491     @param gtid_set Will be filled with all GTIDs in this binary log.
492     @param lost_groups Will be filled with all GTIDs in the
493     Previous_gtids_log_event of the first binary log that has a
494     Previous_gtids_log_event.
495     @param last_gtid Will be filled with the last availble GTID information
496     in the binary/relay log files.
497     @param verify_checksum If true, checksums will be checked.
498     @param need_lock If true, LOCK_log, LOCK_index, and
499     global_sid_lock->wrlock are acquired; otherwise they are asserted
500     to be taken already.
501     @param is_server_starting True if the server is starting.
502     @return false on success, true on error.
503   */
504   bool init_gtid_sets(Gtid_set *gtid_set, Gtid_set *lost_groups,
505                       Gtid *last_gtid, bool verify_checksum,
506                       bool need_lock, bool is_server_starting= false);
507 
set_previous_gtid_set(Gtid_set * previous_gtid_set_param)508   void set_previous_gtid_set(Gtid_set *previous_gtid_set_param)
509   {
510     previous_gtid_set= previous_gtid_set_param;
511   }
512 private:
513   Gtid_set* previous_gtid_set;
514 
open(const char * opt_name)515   int open(const char *opt_name) { return open_binlog(opt_name); }
516   bool change_stage(THD *thd, Stage_manager::StageID stage,
517                     THD* queue, mysql_mutex_t *leave,
518                     mysql_mutex_t *enter);
519   std::pair<int,my_off_t> flush_thread_caches(THD *thd);
520   int flush_cache_to_file(my_off_t *flush_end_pos);
521   int finish_commit(THD *thd);
522   std::pair<bool, bool> sync_binlog_file(bool force);
523   void process_commit_stage_queue(THD *thd, THD *queue);
524   void process_after_commit_stage_queue(THD *thd, THD *first);
525   int process_flush_stage_queue(my_off_t *total_bytes_var, bool *rotate_var,
526                                 THD **out_queue_var);
527   int ordered_commit(THD *thd, bool all, bool skip_commit = false);
528   void handle_binlog_flush_or_sync_error(THD *thd, bool need_lock_log);
529 public:
530   int open_binlog(const char *opt_name);
531   void close();
532   enum_result commit(THD *thd, bool all);
533   int rollback(THD *thd, bool all);
534   int prepare(THD *thd, bool all);
535   int recover(IO_CACHE *log, Format_description_log_event *fdle,
536               my_off_t *valid_pos);
537   int recover(IO_CACHE *log, Format_description_log_event *fdle);
538 #if !defined(MYSQL_CLIENT)
539 
540   void update_thd_next_event_pos(THD *thd);
541   int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event,
542                                        bool is_transactional);
543 
544 #endif /* !defined(MYSQL_CLIENT) */
add_bytes_written(ulonglong inc)545   void add_bytes_written(ulonglong inc)
546   {
547     bytes_written += inc;
548   }
reset_bytes_written()549   void reset_bytes_written()
550   {
551     bytes_written = 0;
552   }
553   void harvest_bytes_written(Relay_log_info *rli, bool need_log_space_lock);
554   void set_max_size(ulong max_size_arg);
555   void signal_update();
556   int wait_for_update_relay_log(THD* thd, const struct timespec * timeout);
557   int  wait_for_update_bin_log(THD* thd, const struct timespec * timeout);
558 public:
559   void init_pthread_objects();
560   void cleanup();
561   /**
562     Create a new binary log.
563     @param log_name Name of binlog
564     @param new_name Name of binlog, too. todo: what's the difference
565     between new_name and log_name?
566     @param io_cache_type_arg Specifies how the IO cache is opened:
567     read-only or read-write.
568     @param max_size The size at which this binlog will be rotated.
569     @param null_created If false, and a Format_description_log_event
570     is written, then the Format_description_log_event will have the
571     timestamp 0. Otherwise, it the timestamp will be the time when the
572     event was written to the log.
573     @param need_lock_index If true, LOCK_index is acquired; otherwise
574     LOCK_index must be taken by the caller.
575     @param need_sid_lock If true, the read lock on global_sid_lock
576     will be acquired.  Otherwise, the caller must hold the read lock
577     on global_sid_lock.
578   */
579   bool open_binlog(const char *log_name,
580                    const char *new_name,
581                    enum cache_type io_cache_type_arg,
582                    ulong max_size,
583                    bool null_created,
584                    bool need_lock_log,
585                    bool need_lock_index, bool need_sid_lock,
586                    Format_description_log_event *extra_description_event);
587   bool open_index_file(const char *index_file_name_arg,
588                        const char *log_name, bool need_lock_index);
589   /* Use this to start writing a new log file */
590   int new_file(Format_description_log_event *extra_description_event);
591 
592   bool write_event(Log_event* event_info);
593   bool write_cache(THD *thd, class binlog_cache_data *binlog_cache_data);
594   int  do_write_cache(IO_CACHE *cache);
595 
596   /**
597      Write a DML into statement cache and then flush it into binlog. It writes
598      Gtid_log_event and BEGIN, COMMIT automatically.
599 
600      It is aimed to handle cases of "background" logging where a statement is
601      logged indirectly, like "DELETE FROM a_memory_table". So don't use it on any
602      normal statement.
603 
604      @param[IN] thd  the THD object of current thread.
605      @param[IN] stmt the DML statement.
606      @param[IN] stmt_len the length of the DML statement.
607      @param[IN] sql_command type of the DML statement.
608 
609      @return Returns false if succeeds, otherwise true is returned.
610   */
611   bool write_dml_directly(THD* thd, const char *stmt, size_t stmt_len,
612                           enum enum_sql_command sql_command);
613 
614   void set_write_error(THD *thd, bool is_transactional);
615   bool check_write_error(THD *thd);
616   bool write_incident(THD *thd, bool need_lock_log,
617                       bool do_flush_and_sync= true);
618   bool write_incident(Incident_log_event *ev, bool need_lock_log,
619                       bool do_flush_and_sync= true);
620 
621   void start_union_events(THD *thd, query_id_t query_id_param);
622   void stop_union_events(THD *thd);
623   bool is_query_in_union(THD *thd, query_id_t query_id_param);
624 
625 #ifdef HAVE_REPLICATION
626   bool append_buffer(const char* buf, uint len, Master_info *mi);
627   bool append_event(Log_event* ev, Master_info *mi);
628 private:
629   bool after_append_to_relay_log(Master_info *mi);
630 #endif // ifdef HAVE_REPLICATION
631 public:
632 
633   void make_log_name(char* buf, const char* log_ident);
634   bool is_active(const char* log_file_name);
635   int remove_logs_from_index(LOG_INFO* linfo, bool need_update_threads);
636   int rotate(bool force_rotate, bool* check_purge);
637   void purge();
638   int rotate_and_purge(THD* thd, bool force_rotate);
639   /**
640      Flush binlog cache and synchronize to disk.
641 
642      This function flushes events in binlog cache to binary log file,
643      it will do synchronizing according to the setting of system
644      variable 'sync_binlog'. If file is synchronized, @c synced will
645      be set to 1, otherwise 0.
646 
647      @param[out] synced if not NULL, set to 1 if file is synchronized, otherwise 0
648      @param[in] force if TRUE, ignores the 'sync_binlog' and synchronizes the file.
649 
650      @retval 0 Success
651      @retval other Failure
652   */
653   bool flush_and_sync(const bool force= false);
654   int purge_logs(const char *to_log, bool included,
655                  bool need_lock_index, bool need_update_threads,
656                  ulonglong *decrease_log_space, bool auto_purge);
657   int purge_logs_before_date(time_t purge_time, bool auto_purge);
658   int purge_first_log(Relay_log_info* rli, bool included);
659   int set_crash_safe_index_file_name(const char *base_file_name);
660   int open_crash_safe_index_file();
661   int close_crash_safe_index_file();
662   int add_log_to_index(uchar* log_file_name, int name_len,
663                        bool need_lock_index);
664   int move_crash_safe_index_file_to_index_file(bool need_lock_index);
665   int set_purge_index_file_name(const char *base_file_name);
666   int open_purge_index_file(bool destroy);
667   bool is_inited_purge_index_file();
668   int close_purge_index_file();
669   int clean_purge_index_file();
670   int sync_purge_index_file();
671   int register_purge_index_entry(const char* entry);
672   int register_create_index_entry(const char* entry);
673   int purge_index_entry(THD *thd, ulonglong *decrease_log_space,
674                         bool need_lock_index);
675   bool reset_logs(THD* thd);
676   void close(uint exiting, bool need_lock_log, bool need_lock_index);
677 
678   // iterating through the log index file
679   int find_log_pos(LOG_INFO* linfo, const char* log_name,
680                    bool need_lock_index);
681   int find_next_log(LOG_INFO* linfo, bool need_lock_index);
682   int get_current_log(LOG_INFO* linfo, bool need_lock_log= true);
683   int raw_get_current_log(LOG_INFO* linfo);
684   uint next_file_id();
get_index_fname()685   inline char* get_index_fname() { return index_file_name;}
get_log_fname()686   inline char* get_log_fname() { return log_file_name; }
get_name()687   inline char* get_name() { return name; }
get_log_lock()688   inline mysql_mutex_t* get_log_lock() { return &LOCK_log; }
get_log_cond()689   inline mysql_cond_t* get_log_cond() { return &update_cond; }
get_log_file()690   inline IO_CACHE* get_log_file() { return &log_file; }
691 
lock_index()692   inline void lock_index() { mysql_mutex_lock(&LOCK_index);}
unlock_index()693   inline void unlock_index() { mysql_mutex_unlock(&LOCK_index);}
get_index_file()694   inline IO_CACHE *get_index_file() { return &index_file;}
get_open_count()695   inline uint32 get_open_count() { return open_count; }
696 
697   /**
698     Function to report the missing GTIDs.
699 
700     This function logs the missing transactions on master to its error log
701     as a warning. If the missing GTIDs are too long to print in a message,
702     it suggests the steps to extract the missing transactions.
703 
704     This function also informs slave about the GTID set sent by the slave,
705     transactions missing on the master and few suggestions to recover from
706     the error. This message shall be wrapped by
707     ER_MASTER_FATAL_ERROR_READING_BINLOG on slave and will be logged as an
708     error.
709 
710     This function will be called from mysql_binlog_send() function.
711 
712     @param slave_executed_gtid_set     GTID set executed by slave
713     @param errmsg                      Pointer to the error message
714 
715     @return void
716   */
717   void report_missing_purged_gtids(const Gtid_set* slave_executed_gtid_set,
718                                    const char** errmsg);
719 
720   /**
721     Function to report the missing GTIDs.
722 
723     This function logs the missing transactions on master to its error log
724     as a warning. If the missing GTIDs are too long to print in a message,
725     it suggests the steps to extract the missing transactions.
726 
727     This function also informs slave about the GTID set sent by the slave,
728     transactions missing on the master and few suggestions to recover from
729     the error. This message shall be wrapped by
730     ER_MASTER_FATAL_ERROR_READING_BINLOG on slave and will be logged as an
731     error.
732 
733     This function will be called from find_first_log_not_in_gtid_set()
734     function.
735 
736     @param previous_gtid_set           Previous GTID set found
737     @param slave_executed_gtid_set     GTID set executed by slave
738     @param errmsg                      Pointer to the error message
739 
740     @return void
741   */
742   void report_missing_gtids(const Gtid_set* previous_gtid_set,
743                             const Gtid_set* slave_executed_gtid_set,
744                             const char** errmsg);
745   static const int MAX_RETRIES_FOR_DELETE_RENAME_FAILURE = 5;
746 };
747 
748 typedef struct st_load_file_info
749 {
750   THD* thd;
751   my_off_t last_pos_in_file;
752   bool wrote_create_file, log_delayed;
753 } LOAD_FILE_INFO;
754 
755 extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log;
756 
757 bool trans_has_updated_trans_table(const THD* thd);
758 bool stmt_has_updated_trans_table(Ha_trx_info* ha_list);
759 bool ending_trans(THD* thd, const bool all);
760 bool ending_single_stmt_trans(THD* thd, const bool all);
761 bool trans_cannot_safely_rollback(const THD* thd);
762 bool stmt_cannot_safely_rollback(const THD* thd);
763 
764 int log_loaded_block(IO_CACHE* file);
765 
766 /**
767   Open a single binary log file for reading.
768 */
769 File open_binlog_file(IO_CACHE *log, const char *log_file_name,
770                       const char **errmsg);
771 int check_binlog_magic(IO_CACHE* log, const char** errmsg);
772 bool purge_master_logs(THD* thd, const char* to_log);
773 bool purge_master_logs_before_date(THD* thd, time_t purge_time);
774 bool show_binlog_events(THD *thd, MYSQL_BIN_LOG *binary_log);
775 bool mysql_show_binlog_events(THD* thd);
776 void check_binlog_cache_size(THD *thd);
777 void check_binlog_stmt_cache_size(THD *thd);
778 bool binlog_enabled();
779 void register_binlog_handler(THD *thd, bool trx);
780 int gtid_empty_group_log_and_cleanup(THD *thd);
781 
782 extern const char *log_bin_index;
783 extern const char *log_bin_basename;
784 extern bool opt_binlog_order_commits;
785 
786 /**
787   Turns a relative log binary log path into a full path, based on the
788   opt_bin_logname or opt_relay_logname.
789 
790   @param from         The log name we want to make into an absolute path.
791   @param to           The buffer where to put the results of the
792                       normalization.
793   @param is_relay_log Switch that makes is used inside to choose which
794                       option (opt_bin_logname or opt_relay_logname) to
795                       use when calculating the base path.
796 
797   @returns true if a problem occurs, false otherwise.
798  */
799 
normalize_binlog_name(char * to,const char * from,bool is_relay_log)800 inline bool normalize_binlog_name(char *to, const char *from, bool is_relay_log)
801 {
802   DBUG_ENTER("normalize_binlog_name");
803   bool error= false;
804   char buff[FN_REFLEN];
805   char *ptr= (char*) from;
806   char *opt_name= is_relay_log ? opt_relay_logname : opt_bin_logname;
807 
808   DBUG_ASSERT(from);
809 
810   /* opt_name is not null and not empty and from is a relative path */
811   if (opt_name && opt_name[0] && from && !test_if_hard_path(from))
812   {
813     // take the path from opt_name
814     // take the filename from from
815     char log_dirpart[FN_REFLEN], log_dirname[FN_REFLEN];
816     size_t log_dirpart_len, log_dirname_len;
817     dirname_part(log_dirpart, opt_name, &log_dirpart_len);
818     dirname_part(log_dirname, from, &log_dirname_len);
819 
820     /* log may be empty => relay-log or log-bin did not
821         hold paths, just filename pattern */
822     if (log_dirpart_len > 0)
823     {
824       /* create the new path name */
825       if(fn_format(buff, from+log_dirname_len, log_dirpart, "",
826                    MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH)) == NULL)
827       {
828         error= true;
829         goto end;
830       }
831 
832       ptr= buff;
833     }
834   }
835 
836   DBUG_ASSERT(ptr);
837 
838   if (ptr)
839     strmake(to, ptr, strlen(ptr));
840 
841 end:
842   DBUG_RETURN(error);
843 }
844 #endif /* BINLOG_H_INCLUDED */
845