1 /*****************************************************************************
2 
3 Copyright (c) 1995, 2020, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2012, Facebook Inc.
5 
6 This program is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License, version 2.0, as published by the
8 Free Software Foundation.
9 
10 This program is also distributed with certain software (including but not
11 limited to OpenSSL) that is licensed under separate terms, as designated in a
12 particular file or component or in included license documentation. The authors
13 of MySQL hereby grant you an additional permission to link the program and
14 your derivative works with the separately licensed software that they have
15 included with MySQL.
16 
17 This program is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
20 for more details.
21 
22 You should have received a copy of the GNU General Public License along with
23 this program; if not, write to the Free Software Foundation, Inc.,
24 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
25 
26 *****************************************************************************/
27 
28 /** @file include/mtr0mtr.h
29  Mini-transaction buffer
30 
31  Created 11/26/1995 Heikki Tuuri
32  *******************************************************/
33 
34 #ifndef mtr0mtr_h
35 #define mtr0mtr_h
36 
37 #include <stddef.h>
38 
39 #include "univ.i"
40 
41 #include "buf0types.h"
42 #include "dyn0buf.h"
43 #include "fil0fil.h"
44 #include "log0types.h"
45 #include "mtr0types.h"
46 #include "srv0srv.h"
47 #include "trx0types.h"
48 
49 /** Start a mini-transaction. */
50 #define mtr_start(m) (m)->start()
51 
52 /** Start a synchronous mini-transaction */
53 #define mtr_start_sync(m) (m)->start(true)
54 
55 /** Start an asynchronous read-only mini-transaction */
56 #define mtr_start_ro(m) (m)->start(true, true)
57 
58 /** Commit a mini-transaction. */
59 #define mtr_commit(m) (m)->commit()
60 
61 /** Set and return a savepoint in mtr.
62 @return	savepoint */
63 #define mtr_set_savepoint(m) (m)->get_savepoint()
64 
65 /** Release the (index tree) s-latch stored in an mtr memo after a
66 savepoint. */
67 #define mtr_release_s_latch_at_savepoint(m, s, l) \
68   (m)->release_s_latch_at_savepoint((s), (l))
69 
70 /** Get the logging mode of a mini-transaction.
71 @return	logging mode: MTR_LOG_NONE, ... */
72 #define mtr_get_log_mode(m) (m)->get_log_mode()
73 
74 /** Change the logging mode of a mini-transaction.
75 @return	old mode */
76 #define mtr_set_log_mode(m, d) (m)->set_log_mode((d))
77 
78 /** Get the flush observer of a mini-transaction.
79 @return flush observer object */
80 #define mtr_get_flush_observer(m) (m)->get_flush_observer()
81 
82 /** Set the flush observer of a mini-transaction. */
83 #define mtr_set_flush_observer(m, d) (m)->set_flush_observer((d))
84 
85 /** Read 1 - 4 bytes from a file page buffered in the buffer pool.
86 @return	value read */
87 #define mtr_read_ulint(p, t, m) (m)->read_ulint((p), (t))
88 
89 /** Release an object in the memo stack.
90 @return true if released */
91 #define mtr_memo_release(m, o, t) (m)->memo_release((o), (t))
92 
93 #ifdef UNIV_DEBUG
94 
95 /** Check if memo contains the given item ignore if table is intrinsic
96 @return true if contains or table is intrinsic. */
97 #define mtr_is_block_fix(m, o, t, table) \
98   (mtr_memo_contains(m, o, t) || table->is_intrinsic())
99 
100 /** Check if memo contains the given page ignore if table is intrinsic
101 @return true if contains or table is intrinsic. */
102 #define mtr_is_page_fix(m, p, t, table) \
103   (mtr_memo_contains_page(m, p, t) || table->is_intrinsic())
104 
105 /** Check if memo contains the given item.
106 @return	true if contains */
107 #define mtr_memo_contains(m, o, t) (m)->memo_contains((m)->get_memo(), (o), (t))
108 
109 /** Check if memo contains the given page.
110 @return	true if contains */
111 #define mtr_memo_contains_page(m, p, t) \
112   (m)->memo_contains_page_flagged((p), (t))
113 #endif /* UNIV_DEBUG */
114 
115 /** Print info of an mtr handle. */
116 #define mtr_print(m) (m)->print()
117 
118 /** Return the log object of a mini-transaction buffer.
119 @return	log */
120 #define mtr_get_log(m) (m)->get_log()
121 
122 /** Push an object to an mtr memo stack. */
123 #define mtr_memo_push(m, o, t) (m)->memo_push(o, t)
124 
125 /** Lock an rw-lock in s-mode. */
126 #define mtr_s_lock(l, m) (m)->s_lock((l), __FILE__, __LINE__)
127 
128 /** Lock an rw-lock in x-mode. */
129 #define mtr_x_lock(l, m) (m)->x_lock((l), __FILE__, __LINE__)
130 
131 /** Lock a tablespace in x-mode. */
132 #define mtr_x_lock_space(s, m) (m)->x_lock_space((s), __FILE__, __LINE__)
133 
134 /** Lock an rw-lock in sx-mode. */
135 #define mtr_sx_lock(l, m) (m)->sx_lock((l), __FILE__, __LINE__)
136 
137 #define mtr_memo_contains_flagged(m, p, l) (m)->memo_contains_flagged((p), (l))
138 
139 #define mtr_memo_contains_page_flagged(m, p, l) \
140   (m)->memo_contains_page_flagged((p), (l))
141 
142 #define mtr_release_block_at_savepoint(m, s, b) \
143   (m)->release_block_at_savepoint((s), (b))
144 
145 #define mtr_block_sx_latch_at_savepoint(m, s, b) \
146   (m)->sx_latch_at_savepoint((s), (b))
147 
148 #define mtr_block_x_latch_at_savepoint(m, s, b) \
149   (m)->x_latch_at_savepoint((s), (b))
150 
151 /** Check if a mini-transaction is dirtying a clean page.
152 @param b	block being x-fixed
153 @return true if the mtr is dirtying a clean page. */
154 #define mtr_block_dirtied(b) mtr_t::is_block_dirtied((b))
155 
156 /** Forward declaration of a tablespace object */
157 struct fil_space_t;
158 
159 /** Mini-transaction memo stack slot. */
160 struct mtr_memo_slot_t {
161   /** pointer to the object */
162   void *object;
163 
164   /** type of the stored object (MTR_MEMO_S_LOCK, ...) */
165   ulint type;
166 };
167 
168 /** Mini-transaction handle and buffer */
169 struct mtr_t {
170   /** State variables of the mtr */
171   struct Impl {
172     /** memo stack for locks etc. */
173     mtr_buf_t m_memo;
174 
175     /** mini-transaction log */
176     mtr_buf_t m_log;
177 
178     /** true if mtr has made at least one buffer pool page dirty */
179     bool m_made_dirty;
180 
181     /** true if inside ibuf changes */
182     bool m_inside_ibuf;
183 
184     /** true if the mini-transaction modified buffer pool pages */
185     bool m_modifications;
186 
187     /** true if mtr is forced to NO_LOG mode because redo logging is
188     disabled globally. In this case, mtr increments the global counter
189     at ::start and must decrement it back at ::commit. */
190     bool m_marked_nolog;
191 
192     /** Shard index used for incrementing global counter at ::start. We need
193     to use the same shard while decrementing counter at ::commit. */
194     size_t m_shard_index;
195 
196     /** Count of how many page initial log records have been
197     written to the mtr log */
198     ib_uint32_t m_n_log_recs;
199 
200     /** specifies which operations should be logged; default
201     value MTR_LOG_ALL */
202     mtr_log_t m_log_mode;
203 
204     /** State of the transaction */
205     mtr_state_t m_state;
206 
207     /** Flush Observer */
208     FlushObserver *m_flush_observer;
209 
210 #ifdef UNIV_DEBUG
211     /** For checking corruption. */
212     ulint m_magic_n;
213 
214 #endif /* UNIV_DEBUG */
215 
216     /** Owning mini-transaction */
217     mtr_t *m_mtr;
218   };
219 
220 #ifndef UNIV_HOTBACKUP
221   /** mtr global logging */
222   class Logging {
223    public:
224     /** mtr global redo logging state.
225     Enable Logging  :
226     [ENABLED] -> [ENABLED_RESTRICT] -> [DISABLED]
227 
228     Disable Logging :
229     [DISABLED] -> [ENABLED_RESTRICT] -> [ENABLED_DBLWR] -> [ENABLED] */
230 
231     enum State : uint32_t {
232       /* Redo Logging is enabled. Server is crash safe. */
233       ENABLED,
234       /* Redo logging is enabled. All non-logging mtr are finished with the
235       pages flushed to disk. Double write is enabled. Some pages could be
236       still getting written to disk without double-write. Not safe to crash. */
237       ENABLED_DBLWR,
238       /* Redo logging is enabled but there could be some mtrs still running
239       in no logging mode. Redo archiving and clone are not allowed to start.
240       No double-write */
241       ENABLED_RESTRICT,
242       /* Redo logging is disabled and all new mtrs would not generate any redo.
243       Redo archiving and clone are not allowed. */
244       DISABLED
245     };
246 
247     /** Initialize logging state at server start up. */
initmtr_t248     void init() {
249       m_state.store(ENABLED);
250       /* We use sharded counter and force sequentially consistent counting
251       which is the general default for c++ atomic operation. If we try to
252       optimize it further specific to current operations, we could use
253       Release-Acquire ordering i.e. std::memory_order_release during counting
254       and std::memory_order_acquire while checking for the count. However,
255       sharding looks to be good enough for now and we should go for non default
256       memory ordering only with some visible proof for improvement. */
257       m_count_nologging_mtr.set_order(std::memory_order_seq_cst);
258       Counter::clear(m_count_nologging_mtr);
259     }
260 
261     /** Disable mtr redo logging. Server is crash unsafe without logging.
262     @param[in]	thd	server connection THD
263     @return mysql error code. */
264     int disable(THD *thd);
265 
266     /** Enable mtr redo logging. Ensure that the server is crash safe
267     before returning.
268     @param[in]	thd	server connection THD
269     @return mysql error code. */
270     int enable(THD *thd);
271 
272     /** Mark a no-logging mtr to indicate that it would not generate redo log
273     and system is crash unsafe.
274     @return true iff logging is disabled and mtr is marked. */
mark_mtrmtr_t275     bool mark_mtr(size_t index) {
276       /* Have initial check to avoid incrementing global counter for regular
277       case when redo logging is enabled. */
278       if (is_disabled()) {
279         /* Increment counter to restrict state change DISABLED to ENABLED. */
280         Counter::inc(m_count_nologging_mtr, index);
281 
282         /* Check if the no-logging is still disabled. At this point, if we
283         find the state disabled, it is no longer possible for the state move
284         back to enabled till the mtr finishes and we unmark the mtr. */
285         if (is_disabled()) {
286           return (true);
287         }
288         Counter::dec(m_count_nologging_mtr, index);
289       }
290       return (false);
291     }
292 
293     /** unmark a no logging mtr. */
unmark_mtrmtr_t294     void unmark_mtr(size_t index) {
295       ut_ad(!is_enabled());
296       ut_ad(Counter::total(m_count_nologging_mtr) > 0);
297       Counter::dec(m_count_nologging_mtr, index);
298     }
299 
300     /* @return flush loop count for faster response when logging is disabled. */
get_nolog_flush_loopmtr_t301     uint32_t get_nolog_flush_loop() const { return (NOLOG_MAX_FLUSH_LOOP); }
302 
303     /** @return true iff redo logging is enabled and server is crash safe. */
is_enabledmtr_t304     bool is_enabled() const { return (m_state.load() == ENABLED); }
305 
306     /** @return true iff redo logging is disabled and new mtrs are not going
307     to generate redo log. */
is_disabledmtr_t308     bool is_disabled() const { return (m_state.load() == DISABLED); }
309 
310     /** @return true iff we can skip data page double write. */
dblwr_disabledmtr_t311     bool dblwr_disabled() const {
312       auto state = m_state.load();
313       return (state == DISABLED || state == ENABLED_RESTRICT);
314     }
315 
316     /* Force faster flush loop for quicker adaptive flush response when logging
317     is disabled. When redo logging is disabled the system operates faster with
318     dirty pages generated at much faster rate. */
319     static constexpr uint32_t NOLOG_MAX_FLUSH_LOOP = 5;
320 
321    private:
322     /** Wait till all no-logging mtrs are finished.
323     @return mysql error code. */
324     int wait_no_log_mtr(THD *thd);
325 
326    private:
327     /** Global redo logging state. */
328     std::atomic<State> m_state;
329 
330     using Shards = Counter::Shards<128>;
331 
332     /** Number of no logging mtrs currently running. */
333     Shards m_count_nologging_mtr;
334   };
335 
336   /** Check if redo logging is disabled globally and mark
337   the global counter till mtr ends. */
338   void check_nolog_and_mark();
339 
340   /** Check if the mtr has marked the global no log counter and
341   unmark it. */
342   void check_nolog_and_unmark();
343 #endif /* !UNIV_HOTBACKUP */
344 
mtr_tmtr_t345   mtr_t() {
346     m_impl.m_state = MTR_STATE_INIT;
347     m_impl.m_marked_nolog = false;
348     m_impl.m_shard_index = 0;
349   }
350 
~mtr_tmtr_t351   ~mtr_t() {
352 #ifdef UNIV_DEBUG
353     switch (m_impl.m_state) {
354       case MTR_STATE_ACTIVE:
355         ut_ad(m_impl.m_memo.size() == 0);
356         break;
357       case MTR_STATE_INIT:
358       case MTR_STATE_COMMITTED:
359         break;
360       case MTR_STATE_COMMITTING:
361         ut_error;
362     }
363 #endif /* UNIV_DEBUG */
364 #ifndef UNIV_HOTBACKUP
365     /* Safety check in case mtr is not committed. */
366     if (m_impl.m_state != MTR_STATE_INIT) {
367       check_nolog_and_unmark();
368     }
369 #endif /* !UNIV_HOTBACKUP */
370   }
371 
372   /** Start a mini-transaction.
373   @param sync		true if it is a synchronous mini-transaction
374   @param read_only	true if read only mini-transaction */
375   void start(bool sync = true, bool read_only = false);
376 
377   /** @return whether this is an asynchronous mini-transaction. */
is_asyncmtr_t378   bool is_async() const { return (!m_sync); }
379 
380   /** Request a future commit to be synchronous. */
set_syncmtr_t381   void set_sync() { m_sync = true; }
382 
383   /** Commit the mini-transaction. */
384   void commit();
385 
386   /** Return current size of the buffer.
387   @return	savepoint */
get_savepointmtr_t388   ulint get_savepoint() const MY_ATTRIBUTE((warn_unused_result)) {
389     ut_ad(is_active());
390     ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
391 
392     return (m_impl.m_memo.size());
393   }
394 
395   /** Release the (index tree) s-latch stored in an mtr memo after a
396   savepoint.
397   @param savepoint	value returned by @see set_savepoint.
398   @param lock		latch to release */
399   inline void release_s_latch_at_savepoint(ulint savepoint, rw_lock_t *lock);
400 
401   /** Release the block in an mtr memo after a savepoint. */
402   inline void release_block_at_savepoint(ulint savepoint, buf_block_t *block);
403 
404   /** SX-latch a not yet latched block after a savepoint. */
405   inline void sx_latch_at_savepoint(ulint savepoint, buf_block_t *block);
406 
407   /** X-latch a not yet latched block after a savepoint. */
408   inline void x_latch_at_savepoint(ulint savepoint, buf_block_t *block);
409 
410   /** Get the logging mode.
411   @return	logging mode */
412   inline mtr_log_t get_log_mode() const MY_ATTRIBUTE((warn_unused_result));
413 
414   /** Change the logging mode.
415   @param mode	 logging mode
416   @return	old mode */
417   mtr_log_t set_log_mode(mtr_log_t mode);
418 
419   /** Read 1 - 4 bytes from a file page buffered in the buffer pool.
420   @param ptr	pointer from where to read
421   @param type	MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES
422   @return	value read */
423   inline uint32_t read_ulint(const byte *ptr, mlog_id_t type) const
424       MY_ATTRIBUTE((warn_unused_result));
425 
426   /** Locks a rw-latch in S mode.
427   NOTE: use mtr_s_lock().
428   @param lock	rw-lock
429   @param file	file name from where called
430   @param line	line number in file */
431   inline void s_lock(rw_lock_t *lock, const char *file, ulint line);
432 
433   /** Locks a rw-latch in X mode.
434   NOTE: use mtr_x_lock().
435   @param lock	rw-lock
436   @param file	file name from where called
437   @param line	line number in file */
438   inline void x_lock(rw_lock_t *lock, const char *file, ulint line);
439 
440   /** Locks a rw-latch in X mode.
441   NOTE: use mtr_sx_lock().
442   @param lock	rw-lock
443   @param file	file name from where called
444   @param line	line number in file */
445   inline void sx_lock(rw_lock_t *lock, const char *file, ulint line);
446 
447   /** Acquire a tablespace X-latch.
448   NOTE: use mtr_x_lock_space().
449   @param[in]	space		tablespace instance
450   @param[in]	file		file name from where called
451   @param[in]	line		line number in file */
452   void x_lock_space(fil_space_t *space, const char *file, ulint line);
453 
454   /** Release an object in the memo stack.
455   @param object	object
456   @param type	object type: MTR_MEMO_S_LOCK, ... */
457   void memo_release(const void *object, ulint type);
458 
459   /** Release a page latch.
460   @param[in]	ptr	pointer to within a page frame
461   @param[in]	type	object type: MTR_MEMO_PAGE_X_FIX, ... */
462   void release_page(const void *ptr, mtr_memo_type_t type);
463 
464   /** Note that the mini-transaction has modified data. */
set_modifiedmtr_t465   void set_modified() { m_impl.m_modifications = true; }
466 
467   /** Set the state to not-modified. This will not log the
468   changes.  This is only used during redo log apply, to avoid
469   logging the changes. */
discard_modificationsmtr_t470   void discard_modifications() { m_impl.m_modifications = false; }
471 
472   /** Get the LSN of commit().
473   @return the commit LSN
474   @retval 0 if the transaction only modified temporary tablespaces or logging
475   is disabled globally. */
commit_lsnmtr_t476   lsn_t commit_lsn() const MY_ATTRIBUTE((warn_unused_result)) {
477     ut_ad(has_committed());
478     ut_ad(m_impl.m_log_mode == MTR_LOG_ALL);
479     return (m_commit_lsn);
480   }
481 
482   /** Note that we are inside the change buffer code. */
enter_ibufmtr_t483   void enter_ibuf() { m_impl.m_inside_ibuf = true; }
484 
485   /** Note that we have exited from the change buffer code. */
exit_ibufmtr_t486   void exit_ibuf() { m_impl.m_inside_ibuf = false; }
487 
488   /** @return true if we are inside the change buffer code */
is_inside_ibufmtr_t489   bool is_inside_ibuf() const MY_ATTRIBUTE((warn_unused_result)) {
490     return (m_impl.m_inside_ibuf);
491   }
492 
493   /*
494   @return true if the mini-transaction is active */
is_activemtr_t495   bool is_active() const MY_ATTRIBUTE((warn_unused_result)) {
496     return (m_impl.m_state == MTR_STATE_ACTIVE);
497   }
498 
499   /** Get flush observer
500   @return flush observer */
get_flush_observermtr_t501   FlushObserver *get_flush_observer() const MY_ATTRIBUTE((warn_unused_result)) {
502     return (m_impl.m_flush_observer);
503   }
504 
505   /** Set flush observer
506   @param[in]	observer	flush observer */
set_flush_observermtr_t507   void set_flush_observer(FlushObserver *observer) {
508     ut_ad(observer == nullptr || m_impl.m_log_mode == MTR_LOG_NO_REDO);
509 
510     m_impl.m_flush_observer = observer;
511   }
512 
513 #ifdef UNIV_DEBUG
514   /** Check if memo contains the given item.
515   @param memo	memo stack
516   @param object	object to search
517   @param type	type of object
518   @return	true if contains */
519   static bool memo_contains(mtr_buf_t *memo, const void *object, ulint type)
520       MY_ATTRIBUTE((warn_unused_result));
521 
522   /** Check if memo contains the given item.
523   @param ptr		object to search
524   @param flags		specify types of object (can be ORred) of
525                           MTR_MEMO_PAGE_S_FIX ... values
526   @return true if contains */
527   bool memo_contains_flagged(const void *ptr, ulint flags) const
528       MY_ATTRIBUTE((warn_unused_result));
529 
530   /** Check if memo contains the given page.
531   @param[in]	ptr	pointer to within buffer frame
532   @param[in]	flags	specify types of object with OR of
533                           MTR_MEMO_PAGE_S_FIX... values
534   @return	the block
535   @retval	NULL	if not found */
536   buf_block_t *memo_contains_page_flagged(const byte *ptr, ulint flags) const
537       MY_ATTRIBUTE((warn_unused_result));
538 
539   /** Mark the given latched page as modified.
540   @param[in]	ptr	pointer to within buffer frame */
541   void memo_modify_page(const byte *ptr);
542 
543   /** Print info of an mtr handle. */
544   void print() const;
545 
546   /** @return true if the mini-transaction has committed */
has_committedmtr_t547   bool has_committed() const MY_ATTRIBUTE((warn_unused_result)) {
548     return (m_impl.m_state == MTR_STATE_COMMITTED);
549   }
550 
551   /** @return true if the mini-transaction is committing */
is_committingmtr_t552   bool is_committing() const {
553     return (m_impl.m_state == MTR_STATE_COMMITTING);
554   }
555 
556   /** @return true if mini-transaction contains modifications. */
has_modificationsmtr_t557   bool has_modifications() const MY_ATTRIBUTE((warn_unused_result)) {
558     return (m_impl.m_modifications);
559   }
560 
561   /** @return the memo stack */
get_memomtr_t562   const mtr_buf_t *get_memo() const MY_ATTRIBUTE((warn_unused_result)) {
563     return (&m_impl.m_memo);
564   }
565 
566   /** @return the memo stack */
get_memomtr_t567   mtr_buf_t *get_memo() MY_ATTRIBUTE((warn_unused_result)) {
568     return (&m_impl.m_memo);
569   }
570 
571   /** Computes the number of bytes that would be written to the redo
572   log if mtr was committed right now (excluding headers of log blocks).
573   @return  number of bytes of the colllected log records increased
574            by 1 if MLOG_MULTI_REC_END would already be required */
get_expected_log_sizemtr_t575   size_t get_expected_log_size() const {
576     return (m_impl.m_log.size() + (m_impl.m_n_log_recs > 1 ? 1 : 0));
577   }
578 
579   void wait_for_flush();
580 #endif /* UNIV_DEBUG */
581 
582   /** @return true if a record was added to the mini-transaction */
is_dirtymtr_t583   bool is_dirty() const MY_ATTRIBUTE((warn_unused_result)) {
584     return (m_impl.m_made_dirty);
585   }
586 
587   /** Note that a record has been added to the log */
added_recmtr_t588   void added_rec() { ++m_impl.m_n_log_recs; }
589 
590   /** Get the buffered redo log of this mini-transaction.
591   @return	redo log */
get_logmtr_t592   const mtr_buf_t *get_log() const MY_ATTRIBUTE((warn_unused_result)) {
593     ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
594 
595     return (&m_impl.m_log);
596   }
597 
598   /** Get the buffered redo log of this mini-transaction.
599   @return	redo log */
get_logmtr_t600   mtr_buf_t *get_log() MY_ATTRIBUTE((warn_unused_result)) {
601     ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
602 
603     return (&m_impl.m_log);
604   }
605 
606   /** Push an object to an mtr memo stack.
607   @param object	object
608   @param type	object type: MTR_MEMO_S_LOCK, ... */
609   inline void memo_push(void *object, mtr_memo_type_t type);
610 
611   /** Check if this mini-transaction is dirtying a clean page.
612   @param block	block being x-fixed
613   @return true if the mtr is dirtying a clean page. */
614   static bool is_block_dirtied(const buf_block_t *block)
615       MY_ATTRIBUTE((warn_unused_result));
616 
617   /** Matrix to check if a mode update request should be ignored. */
618   static bool s_mode_update[MTR_LOG_MODE_MAX][MTR_LOG_MODE_MAX];
619 
620 #ifdef UNIV_DEBUG
621   /** For checking invalid mode update requests. */
622   static bool s_mode_update_valid[MTR_LOG_MODE_MAX][MTR_LOG_MODE_MAX];
623 #endif /* UNIV_DEBUG */
624 
625 #ifndef UNIV_HOTBACKUP
626   /** Instance level logging information for all mtrs. */
627   static Logging s_logging;
628 #endif /* !UNIV_HOTBACKUP */
629 
630  private:
631   Impl m_impl;
632 
633   /** LSN at commit time */
634   lsn_t m_commit_lsn;
635 
636   /** true if it is synchronous mini-transaction */
637   bool m_sync;
638 
639   class Command;
640 
641   friend class Command;
642 };
643 
644 #ifndef UNIV_HOTBACKUP
645 #ifdef UNIV_DEBUG
646 
647 /** Reserves space in the log buffer and writes a single MLOG_TEST.
648 @param[in,out]  log      redo log
649 @param[in]      payload  number of extra bytes within the record,
650                          not greater than 1024
651 @return end_lsn pointing to the first byte after the written record */
652 lsn_t mtr_commit_mlog_test(log_t &log, size_t payload = 0);
653 
654 /** Reserves space in the log buffer and writes a single MLOG_TEST.
655 Adjusts size of the payload in the record, in order to fill the current
656 block up to its boundary. If nothing else is happening in parallel,
657 we could expect to see afterwards:
658 (cur_lsn + space_left) % OS_FILE_LOG_BLOCK_SIZE == LOG_BLOCK_HDR_SIZE,
659 where cur_lsn = log_get_lsn(log).
660 @param[in,out]  log         redo log
661 @param[in]      space_left  extra bytes left to the boundary of block,
662                             must be not greater than 496 */
663 void mtr_commit_mlog_test_filling_block(log_t &log, size_t space_left = 0);
664 
665 #endif /* UNIV_DEBUG */
666 #endif /* !UNIV_HOTBACKUP */
667 
668 #include "mtr0mtr.ic"
669 
670 #endif /* mtr0mtr_h */
671