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 
515   bool snapshot_lock_acquired;
516 
open(const char * opt_name)517   int open(const char *opt_name) { return open_binlog(opt_name); }
518   bool change_stage(THD *thd, Stage_manager::StageID stage,
519                     THD* queue, mysql_mutex_t *leave,
520                     mysql_mutex_t *enter);
521   std::pair<int,my_off_t> flush_thread_caches(THD *thd);
522   int flush_cache_to_file(my_off_t *flush_end_pos);
523   int finish_commit(THD *thd);
524   std::pair<bool, bool> sync_binlog_file(bool force);
525   void process_commit_stage_queue(THD *thd, THD *queue);
526   void process_after_commit_stage_queue(THD *thd, THD *first);
527   int process_flush_stage_queue(my_off_t *total_bytes_var, bool *rotate_var,
528                                 THD **out_queue_var);
529   int ordered_commit(THD *thd, bool all, bool skip_commit = false);
530   void handle_binlog_flush_or_sync_error(THD *thd, bool need_lock_log);
531 public:
532   int open_binlog(const char *opt_name);
533   void close();
534   enum_result commit(THD *thd, bool all);
535   int rollback(THD *thd, bool all);
536   int prepare(THD *thd, bool all);
537   int recover(IO_CACHE *log, Format_description_log_event *fdle,
538               my_off_t *valid_pos);
539   int recover(IO_CACHE *log, Format_description_log_event *fdle);
540 #if !defined(MYSQL_CLIENT)
541 
542   void update_thd_next_event_pos(THD *thd);
543   int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event,
544                                        bool is_transactional);
545   void xlock(void);
546   void xunlock(void);
slock(void)547   void slock(void) { mysql_rwlock_rdlock(&LOCK_consistent_snapshot); }
sunlock(void)548   void sunlock(void) { mysql_rwlock_unlock(&LOCK_consistent_snapshot); }
549 #else
xlock(void)550   void xlock(void) { }
xunlock(void)551   void xunlock(void) { }
slock(void)552   void slock(void) { }
sunlock(void)553   void sunlock(void) { }
554 #endif /* !defined(MYSQL_CLIENT) */
add_bytes_written(ulonglong inc)555   void add_bytes_written(ulonglong inc)
556   {
557     bytes_written += inc;
558   }
reset_bytes_written()559   void reset_bytes_written()
560   {
561     bytes_written = 0;
562   }
563   void harvest_bytes_written(Relay_log_info *rli, bool need_log_space_lock);
564   void set_max_size(ulong max_size_arg);
565   void signal_update();
566   int wait_for_update_relay_log(THD* thd, const struct timespec * timeout);
567   int  wait_for_update_bin_log(THD* thd, const struct timespec * timeout);
568 public:
569   void init_pthread_objects();
570   void cleanup();
571   /**
572     Create a new binary log.
573     @param log_name Name of binlog
574     @param new_name Name of binlog, too. todo: what's the difference
575     between new_name and log_name?
576     @param io_cache_type_arg Specifies how the IO cache is opened:
577     read-only or read-write.
578     @param max_size The size at which this binlog will be rotated.
579     @param null_created If false, and a Format_description_log_event
580     is written, then the Format_description_log_event will have the
581     timestamp 0. Otherwise, it the timestamp will be the time when the
582     event was written to the log.
583     @param need_lock_index If true, LOCK_index is acquired; otherwise
584     LOCK_index must be taken by the caller.
585     @param need_sid_lock If true, the read lock on global_sid_lock
586     will be acquired.  Otherwise, the caller must hold the read lock
587     on global_sid_lock.
588   */
589   bool open_binlog(const char *log_name,
590                    const char *new_name,
591                    enum cache_type io_cache_type_arg,
592                    ulong max_size,
593                    bool null_created,
594                    bool need_lock_log,
595                    bool need_lock_index, bool need_sid_lock,
596                    Format_description_log_event *extra_description_event);
597   bool open_index_file(const char *index_file_name_arg,
598                        const char *log_name, bool need_lock_index);
599   /* Use this to start writing a new log file */
600   int new_file(Format_description_log_event *extra_description_event);
601 
602   bool write_event(Log_event* event_info);
603   bool write_cache(THD *thd, class binlog_cache_data *binlog_cache_data);
604   int  do_write_cache(THD *thd, IO_CACHE *cache);
605 
606   /**
607      Write a DML into statement cache and then flush it into binlog. It writes
608      Gtid_log_event and BEGIN, COMMIT automatically.
609 
610      It is aimed to handle cases of "background" logging where a statement is
611      logged indirectly, like "DELETE FROM a_memory_table". So don't use it on any
612      normal statement.
613 
614      @param[IN] thd  the THD object of current thread.
615      @param[IN] stmt the DML statement.
616      @param[IN] stmt_len the length of the DML statement.
617      @param[IN] sql_command type of the DML statement.
618 
619      @return Returns false if succeeds, otherwise true is returned.
620   */
621   bool write_dml_directly(THD* thd, const char *stmt, size_t stmt_len,
622                           enum enum_sql_command sql_command);
623 
624   void set_write_error(THD *thd, bool is_transactional);
625   bool check_write_error(THD *thd);
626   bool write_incident(THD *thd, bool need_lock_log,
627                       bool do_flush_and_sync= true);
628   bool write_incident(Incident_log_event *ev, bool need_lock_log,
629                       bool do_flush_and_sync= true);
630 
631   void start_union_events(THD *thd, query_id_t query_id_param);
632   void stop_union_events(THD *thd);
633   bool is_query_in_union(THD *thd, query_id_t query_id_param);
634 
635 #ifdef HAVE_REPLICATION
636   bool append_buffer(const char* buf, uint len, Master_info *mi);
637   bool append_event(Log_event* ev, Master_info *mi);
638 private:
639   bool after_append_to_relay_log(Master_info *mi);
640 #endif // ifdef HAVE_REPLICATION
641 public:
642 
643   void make_log_name(char* buf, const char* log_ident);
644   bool is_active(const char* log_file_name);
645   int remove_logs_from_index(LOG_INFO* linfo, bool need_update_threads);
646   int rotate(bool force_rotate, bool* check_purge);
647   void purge();
648   int rotate_and_purge(THD* thd, bool force_rotate);
649   /**
650      Flush binlog cache and synchronize to disk.
651 
652      This function flushes events in binlog cache to binary log file,
653      it will do synchronizing according to the setting of system
654      variable 'sync_binlog'. If file is synchronized, @c synced will
655      be set to 1, otherwise 0.
656 
657      @param[out] synced if not NULL, set to 1 if file is synchronized, otherwise 0
658      @param[in] force if TRUE, ignores the 'sync_binlog' and synchronizes the file.
659 
660      @retval 0 Success
661      @retval other Failure
662   */
663   bool flush_and_sync(const bool force= false);
664   int purge_logs(const char *to_log, bool included,
665                  bool need_lock_index, bool need_update_threads,
666                  ulonglong *decrease_log_space, bool auto_purge);
667   int purge_logs_maximum_number(ulong max_nr_files);
668   int purge_logs_before_date(time_t purge_time, bool auto_purge);
669   int purge_first_log(Relay_log_info* rli, bool included);
670   int set_crash_safe_index_file_name(const char *base_file_name);
671   int open_crash_safe_index_file();
672   int close_crash_safe_index_file();
673   int add_log_to_index(uchar* log_file_name, int name_len,
674                        bool need_lock_index);
675   int move_crash_safe_index_file_to_index_file(bool need_lock_index);
676   int set_purge_index_file_name(const char *base_file_name);
677   int open_purge_index_file(bool destroy);
678   bool is_inited_purge_index_file();
679   int close_purge_index_file();
680   int clean_purge_index_file();
681   int sync_purge_index_file();
682   int register_purge_index_entry(const char* entry);
683   int register_create_index_entry(const char* entry);
684   int purge_index_entry(THD *thd, ulonglong *decrease_log_space,
685                         bool need_lock_index);
686   bool reset_logs(THD* thd);
687   void close(uint exiting, bool need_lock_log, bool need_lock_index);
688 
689   // iterating through the log index file
690   int find_log_pos(LOG_INFO* linfo, const char* log_name,
691                    bool need_lock_index);
692   int find_next_log(LOG_INFO* linfo, bool need_lock_index);
693   int get_current_log(LOG_INFO* linfo, bool need_lock_log= true);
694   int raw_get_current_log(LOG_INFO* linfo);
695   uint next_file_id();
get_index_fname()696   inline char* get_index_fname() { return index_file_name;}
get_log_fname()697   inline char* get_log_fname() { return log_file_name; }
get_name()698   inline char* get_name() { return name; }
get_log_lock()699   inline mysql_mutex_t* get_log_lock() { return &LOCK_log; }
get_log_cond()700   inline mysql_cond_t* get_log_cond() { return &update_cond; }
get_log_file()701   inline IO_CACHE* get_log_file() { return &log_file; }
702 
lock_index()703   inline void lock_index() { mysql_mutex_lock(&LOCK_index);}
unlock_index()704   inline void unlock_index() { mysql_mutex_unlock(&LOCK_index);}
get_index_file()705   inline IO_CACHE *get_index_file() { return &index_file;}
get_open_count()706   inline uint32 get_open_count() { return open_count; }
707 
708   /**
709     Function to report the missing GTIDs.
710 
711     This function logs the missing transactions on master to its error log
712     as a warning. If the missing GTIDs are too long to print in a message,
713     it suggests the steps to extract the missing transactions.
714 
715     This function also informs slave about the GTID set sent by the slave,
716     transactions missing on the master and few suggestions to recover from
717     the error. This message shall be wrapped by
718     ER_MASTER_FATAL_ERROR_READING_BINLOG on slave and will be logged as an
719     error.
720 
721     This function will be called from mysql_binlog_send() function.
722 
723     @param slave_executed_gtid_set     GTID set executed by slave
724     @param errmsg                      Pointer to the error message
725 
726     @return void
727   */
728   void report_missing_purged_gtids(const Gtid_set* slave_executed_gtid_set,
729                                    const char** errmsg);
730 
731   /**
732     Function to report the missing GTIDs.
733 
734     This function logs the missing transactions on master to its error log
735     as a warning. If the missing GTIDs are too long to print in a message,
736     it suggests the steps to extract the missing transactions.
737 
738     This function also informs slave about the GTID set sent by the slave,
739     transactions missing on the master and few suggestions to recover from
740     the error. This message shall be wrapped by
741     ER_MASTER_FATAL_ERROR_READING_BINLOG on slave and will be logged as an
742     error.
743 
744     This function will be called from find_first_log_not_in_gtid_set()
745     function.
746 
747     @param previous_gtid_set           Previous GTID set found
748     @param slave_executed_gtid_set     GTID set executed by slave
749     @param errmsg                      Pointer to the error message
750 
751     @return void
752   */
753   void report_missing_gtids(const Gtid_set* previous_gtid_set,
754                             const Gtid_set* slave_executed_gtid_set,
755                             const char** errmsg);
756   static const int MAX_RETRIES_FOR_DELETE_RENAME_FAILURE = 5;
757 private:
758   void publish_coordinates_for_global_status(void) const;
759 };
760 
761 typedef struct st_load_file_info
762 {
763   THD* thd;
764   my_off_t last_pos_in_file;
765   bool wrote_create_file, log_delayed;
766 } LOAD_FILE_INFO;
767 
768 extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log;
769 
770 bool trans_has_updated_trans_table(const THD* thd);
771 bool stmt_has_updated_trans_table(Ha_trx_info* ha_list);
772 bool ending_trans(THD* thd, const bool all);
773 bool ending_single_stmt_trans(THD* thd, const bool all);
774 bool trans_cannot_safely_rollback(const THD* thd);
775 bool stmt_cannot_safely_rollback(const THD* thd);
776 
777 int log_loaded_block(IO_CACHE* file);
778 
779 /**
780   Open a single binary log file for reading.
781 */
782 File open_binlog_file(IO_CACHE *log, const char *log_file_name,
783                       const char **errmsg);
784 int check_binlog_magic(IO_CACHE* log, const char** errmsg);
785 bool purge_master_logs(THD* thd, const char* to_log);
786 bool purge_master_logs_before_date(THD* thd, time_t purge_time);
787 bool show_binlog_events(THD *thd, MYSQL_BIN_LOG *binary_log);
788 bool mysql_show_binlog_events(THD* thd);
789 void check_binlog_cache_size(THD *thd);
790 void check_binlog_stmt_cache_size(THD *thd);
791 bool binlog_enabled();
792 void register_binlog_handler(THD *thd, bool trx);
793 int gtid_empty_group_log_and_cleanup(THD *thd);
794 
795 extern const char *log_bin_index;
796 extern const char *log_bin_basename;
797 extern bool opt_binlog_order_commits;
798 
799 /**
800   Turns a relative log binary log path into a full path, based on the
801   opt_bin_logname or opt_relay_logname.
802 
803   @param from         The log name we want to make into an absolute path.
804   @param to           The buffer where to put the results of the
805                       normalization.
806   @param is_relay_log Switch that makes is used inside to choose which
807                       option (opt_bin_logname or opt_relay_logname) to
808                       use when calculating the base path.
809 
810   @returns true if a problem occurs, false otherwise.
811  */
812 
normalize_binlog_name(char * to,const char * from,bool is_relay_log)813 inline bool normalize_binlog_name(char *to, const char *from, bool is_relay_log)
814 {
815   DBUG_ENTER("normalize_binlog_name");
816   bool error= false;
817   char buff[FN_REFLEN];
818   char *ptr= (char*) from;
819   char *opt_name= is_relay_log ? opt_relay_logname : opt_bin_logname;
820 
821   DBUG_ASSERT(from);
822 
823   /* opt_name is not null and not empty and from is a relative path */
824   if (opt_name && opt_name[0] && from && !test_if_hard_path(from))
825   {
826     // take the path from opt_name
827     // take the filename from from
828     char log_dirpart[FN_REFLEN], log_dirname[FN_REFLEN];
829     size_t log_dirpart_len, log_dirname_len;
830     dirname_part(log_dirpart, opt_name, &log_dirpart_len);
831     dirname_part(log_dirname, from, &log_dirname_len);
832 
833     /* log may be empty => relay-log or log-bin did not
834         hold paths, just filename pattern */
835     if (log_dirpart_len > 0)
836     {
837       /* create the new path name */
838       if(fn_format(buff, from+log_dirname_len, log_dirpart, "",
839                    MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH)) == NULL)
840       {
841         error= true;
842         goto end;
843       }
844 
845       ptr= buff;
846     }
847   }
848 
849   DBUG_ASSERT(ptr);
850 
851   if (ptr)
852     strmake(to, ptr, strlen(ptr));
853 
854 end:
855   DBUG_RETURN(error);
856 }
857 #endif /* BINLOG_H_INCLUDED */
858