1 /*****************************************************************************
2 
3 Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2013, 2022, MariaDB Corporation.
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 as published by the Free Software
8 Foundation; version 2 of the License.
9 
10 This program is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
17 
18 *****************************************************************************/
19 
20 /**************************************************//**
21 @file include/mtr0mtr.h
22 Mini-transaction buffer
23 
24 Created 11/26/1995 Heikki Tuuri
25 *******************************************************/
26 
27 #ifndef mtr0mtr_h
28 #define mtr0mtr_h
29 
30 #include "fil0fil.h"
31 #include "dyn0buf.h"
32 
33 /** Start a mini-transaction. */
34 #define mtr_start(m)		(m)->start()
35 
36 /** Commit a mini-transaction. */
37 #define mtr_commit(m)		(m)->commit()
38 
39 /** Set and return a savepoint in mtr.
40 @return	savepoint */
41 #define mtr_set_savepoint(m)	(m)->get_savepoint()
42 
43 /** Release the (index tree) s-latch stored in an mtr memo after a
44 savepoint. */
45 #define mtr_release_s_latch_at_savepoint(m, s, l)			\
46 				(m)->release_s_latch_at_savepoint((s), (l))
47 
48 /** Change the logging mode of a mini-transaction.
49 @return	old mode */
50 #define mtr_set_log_mode(m, d)	(m)->set_log_mode((d))
51 
52 /** Release an object in the memo stack.
53 @return true if released */
54 #define mtr_memo_release(m, o, t)					\
55 				(m)->memo_release((o), (t))
56 
57 /** Print info of an mtr handle. */
58 #define mtr_print(m)		(m)->print()
59 
60 /** Return the log object of a mini-transaction buffer.
61 @return	log */
62 #define mtr_get_log(m)		(m)->get_log()
63 
64 /** Push an object to an mtr memo stack. */
65 #define mtr_memo_push(m, o, t)	(m)->memo_push(o, t)
66 
67 #define mtr_x_lock_space(s, m)	(m)->x_lock_space((s), __FILE__, __LINE__)
68 #define mtr_sx_lock_space(s, m) (m)->sx_lock_space((s), __FILE__, __LINE__)
69 
70 #define mtr_s_lock_index(i, m)	(m)->s_lock(&(i)->lock, __FILE__, __LINE__)
71 #define mtr_x_lock_index(i, m)	(m)->x_lock(&(i)->lock, __FILE__, __LINE__)
72 #define mtr_sx_lock_index(i, m)	(m)->sx_lock(&(i)->lock, __FILE__, __LINE__)
73 
74 #define mtr_release_block_at_savepoint(m, s, b)				\
75 				(m)->release_block_at_savepoint((s), (b))
76 
77 #define mtr_block_sx_latch_at_savepoint(m, s, b)			\
78 				(m)->sx_latch_at_savepoint((s), (b))
79 
80 #define mtr_block_x_latch_at_savepoint(m, s, b)				\
81 				(m)->x_latch_at_savepoint((s), (b))
82 
83 /** Mini-transaction memo stack slot. */
84 struct mtr_memo_slot_t {
85 	/** pointer to the object */
86 	void*		object;
87 
88 	/** type of the stored object */
89 	mtr_memo_type_t	type;
90 };
91 
92 /** Mini-transaction handle and buffer */
93 struct mtr_t {
94   /** Start a mini-transaction. */
95   void start();
96 
97   /** Commit the mini-transaction. */
98   void commit();
99 
100   /** Commit a mini-transaction that is shrinking a tablespace.
101   @param space   tablespace that is being shrunk */
102   ATTRIBUTE_COLD void commit_shrink(fil_space_t &space);
103 
104   /** Commit a mini-transaction that did not modify any pages,
105   but generated some redo log on a higher level, such as
106   FILE_MODIFY records and an optional FILE_CHECKPOINT marker.
107   The caller must hold log_sys.mutex.
108   This is to be used at log_checkpoint().
109   @param checkpoint_lsn   the log sequence number of a checkpoint, or 0 */
110   void commit_files(lsn_t checkpoint_lsn= 0);
111 
112   /** @return mini-transaction savepoint (current size of m_memo) */
get_savepointmtr_t113   ulint get_savepoint() const { ut_ad(is_active()); return m_memo.size(); }
114 
115 	/** Release the (index tree) s-latch stored in an mtr memo after a
116 	savepoint.
117 	@param savepoint	value returned by @see set_savepoint.
118 	@param lock		latch to release */
119 	inline void release_s_latch_at_savepoint(
120 		ulint		savepoint,
121 		rw_lock_t*	lock);
122 
123 	/** Release the block in an mtr memo after a savepoint. */
124 	inline void release_block_at_savepoint(
125 		ulint		savepoint,
126 		buf_block_t*	block);
127 
128 	/** SX-latch a not yet latched block after a savepoint. */
129 	inline void sx_latch_at_savepoint(ulint savepoint, buf_block_t* block);
130 
131 	/** X-latch a not yet latched block after a savepoint. */
132 	inline void x_latch_at_savepoint(ulint savepoint, buf_block_t*	block);
133 
134   /** @return the logging mode */
get_log_modemtr_t135   mtr_log_t get_log_mode() const
136   {
137     static_assert(MTR_LOG_ALL == 0, "efficiency");
138     ut_ad(m_log_mode <= MTR_LOG_NO_REDO);
139     return static_cast<mtr_log_t>(m_log_mode);
140   }
141 
142   /** Change the logging mode.
143   @param mode	 logging mode
144   @return	old mode */
set_log_modemtr_t145   mtr_log_t set_log_mode(mtr_log_t mode)
146   {
147     const mtr_log_t old_mode= get_log_mode();
148     m_log_mode= mode & 3;
149     return old_mode;
150   }
151 
152   /** Check if we are holding a block latch in exclusive mode
153   @param block  buffer pool block to search for */
154   bool have_x_latch(const buf_block_t &block) const;
155 
156 	/** Copy the tablespaces associated with the mini-transaction
157 	(needed for generating FILE_MODIFY records)
158 	@param[in]	mtr	mini-transaction that may modify
159 	the same set of tablespaces as this one */
set_spacesmtr_t160 	void set_spaces(const mtr_t& mtr)
161 	{
162 		ut_ad(!m_user_space_id);
163 		ut_ad(!m_user_space);
164 
165 		ut_d(m_user_space_id = mtr.m_user_space_id);
166 		m_user_space = mtr.m_user_space;
167 	}
168 
169 	/** Set the tablespace associated with the mini-transaction
170 	(needed for generating a FILE_MODIFY record)
171 	@param[in]	space_id	user or system tablespace ID
172 	@return	the tablespace */
set_named_space_idmtr_t173 	fil_space_t* set_named_space_id(ulint space_id)
174 	{
175 		ut_ad(!m_user_space_id);
176 		ut_d(m_user_space_id = static_cast<uint32_t>(space_id));
177 		if (!space_id) {
178 			return fil_system.sys_space;
179 		} else {
180 			ut_ad(m_user_space_id == space_id);
181 			ut_ad(!m_user_space);
182 			m_user_space = fil_space_get(space_id);
183 			ut_ad(m_user_space);
184 			return m_user_space;
185 		}
186 	}
187 
188 	/** Set the tablespace associated with the mini-transaction
189 	(needed for generating a FILE_MODIFY record)
190 	@param[in]	space	user or system tablespace */
set_named_spacemtr_t191 	void set_named_space(fil_space_t* space)
192 	{
193 		ut_ad(!m_user_space_id);
194 		ut_d(m_user_space_id = static_cast<uint32_t>(space->id));
195 		if (space->id) {
196 			m_user_space = space;
197 		}
198 	}
199 
200 #ifdef UNIV_DEBUG
201 	/** Check the tablespace associated with the mini-transaction
202 	(needed for generating a FILE_MODIFY record)
203 	@param[in]	space	tablespace
204 	@return whether the mini-transaction is associated with the space */
205 	bool is_named_space(ulint space) const;
206 	/** Check the tablespace associated with the mini-transaction
207 	(needed for generating a FILE_MODIFY record)
208 	@param[in]	space	tablespace
209 	@return whether the mini-transaction is associated with the space */
210 	bool is_named_space(const fil_space_t* space) const;
211 #endif /* UNIV_DEBUG */
212 
213 	/** Acquire a tablespace X-latch.
214 	@param[in]	space_id	tablespace ID
215 	@param[in]	file		file name from where called
216 	@param[in]	line		line number in file
217 	@return the tablespace object (never NULL) */
218 	fil_space_t* x_lock_space(
219 		ulint		space_id,
220 		const char*	file,
221 		unsigned	line);
222 
223 	/** Acquire a shared rw-latch.
224 	@param[in]	lock	rw-latch
225 	@param[in]	file	file name from where called
226 	@param[in]	line	line number in file */
s_lockmtr_t227 	void s_lock(rw_lock_t* lock, const char* file, unsigned line)
228 	{
229 		rw_lock_s_lock_inline(lock, 0, file, line);
230 		memo_push(lock, MTR_MEMO_S_LOCK);
231 	}
232 
233 	/** Acquire an exclusive rw-latch.
234 	@param[in]	lock	rw-latch
235 	@param[in]	file	file name from where called
236 	@param[in]	line	line number in file */
x_lockmtr_t237 	void x_lock(rw_lock_t* lock, const char* file, unsigned line)
238 	{
239 		rw_lock_x_lock_inline(lock, 0, file, line);
240 		memo_push(lock, MTR_MEMO_X_LOCK);
241 	}
242 
243 	/** Acquire an shared/exclusive rw-latch.
244 	@param[in]	lock	rw-latch
245 	@param[in]	file	file name from where called
246 	@param[in]	line	line number in file */
sx_lockmtr_t247 	void sx_lock(rw_lock_t* lock, const char* file, unsigned line)
248 	{
249 		rw_lock_sx_lock_inline(lock, 0, file, line);
250 		memo_push(lock, MTR_MEMO_SX_LOCK);
251 	}
252 
253 	/** Acquire a tablespace X-latch.
254 	@param[in]	space	tablespace
255 	@param[in]	file	file name from where called
256 	@param[in]	line	line number in file */
x_lock_spacemtr_t257 	void x_lock_space(fil_space_t* space, const char* file, unsigned line)
258 	{
259 		ut_ad(space->purpose == FIL_TYPE_TEMPORARY
260 		      || space->purpose == FIL_TYPE_IMPORT
261 		      || space->purpose == FIL_TYPE_TABLESPACE);
262 		memo_push(space, MTR_MEMO_SPACE_X_LOCK);
263 		rw_lock_x_lock_inline(&space->latch, 0, file, line);
264 	}
265 
266  /** Acquire a tablespace SX-latch.
267  @param[in]	space	tablespace
268  @param[in]	file	file name from where called
269  @param[in]	line	line number in file */
sx_lock_spacemtr_t270  void sx_lock_space(fil_space_t *space, const char *file, unsigned line)
271  {
272    ut_ad(space->purpose == FIL_TYPE_TEMPORARY
273          || space->purpose == FIL_TYPE_IMPORT
274 	 || space->purpose == FIL_TYPE_TABLESPACE);
275    sx_lock(&space->latch, file, line);
276  }
277 
278 	/** Release an object in the memo stack.
279 	@param object	object
280 	@param type	object type
281 	@return bool if lock released */
282 	bool memo_release(const void* object, ulint type);
283 	/** Release a page latch.
284 	@param[in]	ptr	pointer to within a page frame
285 	@param[in]	type	object type: MTR_MEMO_PAGE_X_FIX, ... */
286 	void release_page(const void* ptr, mtr_memo_type_t type);
287 
288 private:
289   /** Note that the mini-transaction will modify data. */
flag_modifiedmtr_t290   void flag_modified() { m_modifications = true; }
291   /** Mark the given latched page as modified.
292   @param block   page that will be modified */
293   void modify(const buf_block_t& block);
294 public:
295   /** Note that the mini-transaction will modify a block. */
set_modifiedmtr_t296   void set_modified(const buf_block_t &block)
297   { flag_modified(); if (m_log_mode != MTR_LOG_NONE) modify(block); }
298 
299   /** Set the state to not-modified. This will not log the changes.
300   This is only used during redo log apply, to avoid logging the changes. */
discard_modificationsmtr_t301   void discard_modifications() { m_modifications = false; }
302 
303   /** Get the LSN of commit().
304   @return the commit LSN
305   @retval 0 if the transaction only modified temporary tablespaces */
commit_lsnmtr_t306   lsn_t commit_lsn() const { ut_ad(has_committed()); return m_commit_lsn; }
307 
308   /** Note that we are inside the change buffer code. */
enter_ibufmtr_t309   void enter_ibuf() { m_inside_ibuf= true; }
310 
311   /** Note that we have exited from the change buffer code. */
exit_ibufmtr_t312   void exit_ibuf() { m_inside_ibuf= false; }
313 
314   /** @return true if we are inside the change buffer code */
is_inside_ibufmtr_t315   bool is_inside_ibuf() const { return m_inside_ibuf; }
316 
317   /** Note that pages has been trimed */
set_trim_pagesmtr_t318   void set_trim_pages() { m_trim_pages= true; }
319 
320   /** @return true if pages has been trimed */
is_trim_pagesmtr_t321   bool is_trim_pages() { return m_trim_pages; }
322 
323 #ifdef UNIV_DEBUG
324   /** Check if we are holding an rw-latch in this mini-transaction
325   @param lock   latch to search for
326   @param type   held latch type
327   @return whether (lock,type) is contained */
328   bool memo_contains(const rw_lock_t &lock, mtr_memo_type_t type)
329     MY_ATTRIBUTE((warn_unused_result));
330   /** Check if we are holding exclusive tablespace latch
331   @param space  tablespace to search for
332   @return whether space.latch is being held */
333   bool memo_contains(const fil_space_t& space)
334     MY_ATTRIBUTE((warn_unused_result));
335 
336 
337 	/** Check if memo contains the given item.
338 	@param object		object to search
339 	@param flags		specify types of object (can be ORred) of
340 				MTR_MEMO_PAGE_S_FIX ... values
341 	@return true if contains */
342 	bool memo_contains_flagged(const void* ptr, ulint flags) const;
343 
344 	/** Check if memo contains the given page.
345 	@param[in]	ptr	pointer to within buffer frame
346 	@param[in]	flags	specify types of object with OR of
347 				MTR_MEMO_PAGE_S_FIX... values
348 	@return	the block
349 	@retval	NULL	if not found */
350 	buf_block_t* memo_contains_page_flagged(
351 		const byte*	ptr,
352 		ulint		flags) const;
353 
354 	/** Print info of an mtr handle. */
355 	void print() const;
356 
357 	/** @return true if mini-transaction contains modifications. */
has_modificationsmtr_t358 	bool has_modifications() const { return m_modifications; }
359 
360 	/** @return the memo stack */
get_memomtr_t361 	const mtr_buf_t* get_memo() const { return &m_memo; }
362 
363 	/** @return the memo stack */
get_memomtr_t364 	mtr_buf_t* get_memo() { return &m_memo; }
365 #endif /* UNIV_DEBUG */
366 
367 	/** @return true if a record was added to the mini-transaction */
is_dirtymtr_t368 	bool is_dirty() const { return m_made_dirty; }
369 
370 	/** Get the buffered redo log of this mini-transaction.
371 	@return	redo log */
get_logmtr_t372 	const mtr_buf_t* get_log() const { return &m_log; }
373 
374 	/** Get the buffered redo log of this mini-transaction.
375 	@return	redo log */
get_logmtr_t376 	mtr_buf_t* get_log() { return &m_log; }
377 
378 	/** Push an object to an mtr memo stack.
379 	@param object	object
380 	@param type	object type: MTR_MEMO_S_LOCK, ... */
381 	inline void memo_push(void* object, mtr_memo_type_t type);
382 
383 	/** Check if this mini-transaction is dirtying a clean page.
384 	@param block	block being x-fixed
385 	@return true if the mtr is dirtying a clean page. */
386 	static inline bool is_block_dirtied(const buf_block_t* block)
387 		MY_ATTRIBUTE((warn_unused_result));
388 
389   /** Write request types */
390   enum write_type
391   {
392     /** the page is guaranteed to always change */
393     NORMAL= 0,
394     /** optional: the page contents might not change */
395     MAYBE_NOP,
396     /** force a write, even if the page contents is not changing */
397     FORCED
398   };
399 
400   /** Write 1, 2, 4, or 8 bytes to a file page.
401   @param[in]      block   file page
402   @param[in,out]  ptr     pointer in file page
403   @param[in]      val     value to write
404   @tparam l       number of bytes to write
405   @tparam w       write request type
406   @tparam V       type of val
407   @return whether any log was written */
408   template<unsigned l,write_type w= NORMAL,typename V>
409   inline bool write(const buf_block_t &block, void *ptr, V val)
410     MY_ATTRIBUTE((nonnull));
411 
412   /** Log a write of a byte string to a page.
413   @param[in]      b       buffer page
414   @param[in]      ofs     byte offset from b->frame
415   @param[in]      len     length of the data to write */
416   inline void memcpy(const buf_block_t &b, ulint ofs, ulint len);
417 
418   /** Write a byte string to a page.
419   @param[in,out]  b       buffer page
420   @param[in]      dest    destination within b.frame
421   @param[in]      str     the data to write
422   @param[in]      len     length of the data to write
423   @tparam w       write request type */
424   template<write_type w= NORMAL>
425   inline void memcpy(const buf_block_t &b, void *dest, const void *str,
426                      ulint len);
427 
428   /** Log a write of a byte string to a ROW_FORMAT=COMPRESSED page.
429   @param[in]      b       ROW_FORMAT=COMPRESSED index page
430   @param[in]      offset  byte offset from b.zip.data
431   @param[in]      len     length of the data to write */
432   inline void zmemcpy(const buf_block_t &b, ulint offset, ulint len);
433 
434   /** Write a byte string to a ROW_FORMAT=COMPRESSED page.
435   @param[in]      b       ROW_FORMAT=COMPRESSED index page
436   @param[in]      dest    destination within b.zip.data
437   @param[in]      str     the data to write
438   @param[in]      len     length of the data to write
439   @tparam w       write request type */
440   template<write_type w= NORMAL>
441   inline void zmemcpy(const buf_block_t &b, void *dest, const void *str,
442                       ulint len);
443 
444   /** Log an initialization of a string of bytes.
445   @param[in]      b       buffer page
446   @param[in]      ofs     byte offset from b->frame
447   @param[in]      len     length of the data to write
448   @param[in]      val     the data byte to write */
449   inline void memset(const buf_block_t &b, ulint ofs, ulint len, byte val);
450 
451   /** Initialize a string of bytes.
452   @param[in,out]        b       buffer page
453   @param[in]            ofs     byte offset from b->frame
454   @param[in]            len     length of the data to write
455   @param[in]            val     the data byte to write */
456   inline void memset(const buf_block_t *b, ulint ofs, ulint len, byte val);
457 
458   /** Log an initialization of a repeating string of bytes.
459   @param[in]      b       buffer page
460   @param[in]      ofs     byte offset from b->frame
461   @param[in]      len     length of the data to write, in bytes
462   @param[in]      str     the string to write
463   @param[in]      size    size of str, in bytes */
464   inline void memset(const buf_block_t &b, ulint ofs, size_t len,
465                      const void *str, size_t size);
466 
467   /** Initialize a repeating string of bytes.
468   @param[in,out]  b       buffer page
469   @param[in]      ofs     byte offset from b->frame
470   @param[in]      len     length of the data to write, in bytes
471   @param[in]      str     the string to write
472   @param[in]      size    size of str, in bytes */
473   inline void memset(const buf_block_t *b, ulint ofs, size_t len,
474                      const void *str, size_t size);
475 
476   /** Log that a string of bytes was copied from the same page.
477   @param[in]      b       buffer page
478   @param[in]      d       destination offset within the page
479   @param[in]      s       source offset within the page
480   @param[in]      len     length of the data to copy */
481   inline void memmove(const buf_block_t &b, ulint d, ulint s, ulint len);
482 
483   /** Initialize an entire page.
484   @param[in,out]        b       buffer page */
485   void init(buf_block_t *b);
486   /** Free a page.
487   @param[in]      space   tablespace contains page to be freed
488   @param[in]      offset  page offset to be freed */
489   inline void free(fil_space_t &space, uint32_t offset);
490   /** Write log for partly initializing a B-tree or R-tree page.
491   @param block    B-tree or R-tree page
492   @param comp     false=ROW_FORMAT=REDUNDANT, true=COMPACT or DYNAMIC */
493   inline void page_create(const buf_block_t &block, bool comp);
494 
495   /** Write log for inserting a B-tree or R-tree record in
496   ROW_FORMAT=REDUNDANT.
497   @param block      B-tree or R-tree page
498   @param reuse      false=allocate from PAGE_HEAP_TOP; true=reuse PAGE_FREE
499   @param prev_rec   byte offset of the predecessor of the record to insert,
500                     starting from PAGE_OLD_INFIMUM
501   @param info_bits  info_bits of the record
502   @param n_fields_s number of fields << 1 | rec_get_1byte_offs_flag()
503   @param hdr_c      number of common record header bytes with prev_rec
504   @param data_c     number of common data bytes with prev_rec
505   @param hdr        record header bytes to copy to the log
506   @param hdr_l      number of copied record header bytes
507   @param data       record payload bytes to copy to the log
508   @param data_l     number of copied record data bytes */
509   inline void page_insert(const buf_block_t &block, bool reuse,
510                           ulint prev_rec, byte info_bits,
511                           ulint n_fields_s, size_t hdr_c, size_t data_c,
512                           const byte *hdr, size_t hdr_l,
513                           const byte *data, size_t data_l);
514   /** Write log for inserting a B-tree or R-tree record in
515   ROW_FORMAT=COMPACT or ROW_FORMAT=DYNAMIC.
516   @param block       B-tree or R-tree page
517   @param reuse       false=allocate from PAGE_HEAP_TOP; true=reuse PAGE_FREE
518   @param prev_rec    byte offset of the predecessor of the record to insert,
519                      starting from PAGE_NEW_INFIMUM
520   @param info_status rec_get_info_and_status_bits()
521   @param shift       unless !reuse: number of bytes the PAGE_FREE is moving
522   @param hdr_c       number of common record header bytes with prev_rec
523   @param data_c      number of common data bytes with prev_rec
524   @param hdr         record header bytes to copy to the log
525   @param hdr_l       number of copied record header bytes
526   @param data        record payload bytes to copy to the log
527   @param data_l      number of copied record data bytes */
528   inline void page_insert(const buf_block_t &block, bool reuse,
529                           ulint prev_rec, byte info_status,
530                           ssize_t shift, size_t hdr_c, size_t data_c,
531                           const byte *hdr, size_t hdr_l,
532                           const byte *data, size_t data_l);
533   /** Write log for deleting a B-tree or R-tree record in ROW_FORMAT=REDUNDANT.
534   @param block      B-tree or R-tree page
535   @param prev_rec   byte offset of the predecessor of the record to delete,
536                     starting from PAGE_OLD_INFIMUM */
537   inline void page_delete(const buf_block_t &block, ulint prev_rec);
538   /** Write log for deleting a COMPACT or DYNAMIC B-tree or R-tree record.
539   @param block      B-tree or R-tree page
540   @param prev_rec   byte offset of the predecessor of the record to delete,
541                     starting from PAGE_NEW_INFIMUM
542   @param hdr_size   record header size, excluding REC_N_NEW_EXTRA_BYTES
543   @param data_size  data payload size, in bytes */
544   inline void page_delete(const buf_block_t &block, ulint prev_rec,
545                           size_t hdr_size, size_t data_size);
546 
547   /** Write log for initializing an undo log page.
548   @param block    undo page */
549   inline void undo_create(const buf_block_t &block);
550   /** Write log for appending an undo log record.
551   @param block    undo page
552   @param data     record within the undo page
553   @param len      length of the undo record, in bytes */
554   inline void undo_append(const buf_block_t &block,
555                           const void *data, size_t len);
556   /** Trim the end of a tablespace.
557   @param id       first page identifier that will not be in the file */
558   inline void trim_pages(const page_id_t id);
559 
560   /** Write a log record about a file operation.
561   @param type           file operation
562   @param space_id       tablespace identifier
563   @param path           file path
564   @param new_path       new file path for type=FILE_RENAME */
565   inline void log_file_op(mfile_type_t type, ulint space_id,
566                           const char *path,
567                           const char *new_path= nullptr);
568 
569   /** Add freed page numbers to freed_pages */
add_freed_offsetmtr_t570   void add_freed_offset(fil_space_t *space, uint32_t page)
571   {
572     ut_ad(is_named_space(space));
573     if (!m_freed_pages)
574     {
575       m_freed_pages= new range_set();
576       ut_ad(!m_freed_space);
577       m_freed_space= space;
578     }
579     else
580       ut_ad(m_freed_space == space);
581     m_freed_pages->add_value(page);
582   }
583 
584   /** Determine the added buffer fix count of a block.
585   @param block block to be checked
586   @return number of buffer count added by this mtr */
587   uint32_t get_fix_count(const buf_block_t *block) const;
588 
589   /** type of page flushing is needed during commit() */
590   enum page_flush_ahead
591   {
592     /** no need to trigger page cleaner */
593     PAGE_FLUSH_NO= 0,
594     /** asynchronous flushing is needed */
595     PAGE_FLUSH_ASYNC,
596     /** furious flushing is needed */
597     PAGE_FLUSH_SYNC
598   };
599 
600 private:
601   /** Log a write of a byte string to a page.
602   @param block   buffer page
603   @param offset  byte offset within page
604   @param data    data to be written
605   @param len     length of the data, in bytes */
606   inline void memcpy_low(const buf_block_t &block, uint16_t offset,
607                          const void *data, size_t len);
608   /**
609   Write a log record.
610   @tparam type  redo log record type
611   @param id     persistent page identifier
612   @param bpage  buffer pool page, or nullptr
613   @param len    number of additional bytes to write
614   @param alloc  whether to allocate the additional bytes
615   @param offset byte offset, or 0 if the record type does not allow one
616   @return end of mini-transaction log, minus len */
617   template<byte type>
618   inline byte *log_write(const page_id_t id, const buf_page_t *bpage,
619                          size_t len= 0, bool alloc= false, size_t offset= 0);
620 
621   /** Write an EXTENDED log record.
622   @param block  buffer pool page
623   @param type   extended record subtype; @see mrec_ext_t */
624   inline void log_write_extended(const buf_block_t &block, byte type);
625 
626   /** Append the redo log records to the redo log buffer.
627   @return {start_lsn,flush_ahead} */
628   std::pair<lsn_t,page_flush_ahead> do_write();
629 
630   /** Append the redo log records to the redo log buffer.
631   @param len   number of bytes to write
632   @return {start_lsn,flush_ahead} */
633   inline std::pair<lsn_t,page_flush_ahead> finish_write(ulint len);
634 
635   /** Release the resources */
636   inline void release_resources();
637 
638 #ifdef UNIV_DEBUG
639 public:
640   /** @return whether the mini-transaction is active */
is_activemtr_t641   bool is_active() const
642   { ut_ad(!m_commit || m_start); return m_start && !m_commit; }
643   /** @return whether the mini-transaction has been committed */
has_committedmtr_t644   bool has_committed() const { ut_ad(!m_commit || m_start); return m_commit; }
645 private:
646   /** whether start() has been called */
647   bool m_start= false;
648   /** whether commit() has been called */
649   bool m_commit= false;
650 #endif
651 
652   /** The page of the most recent m_log record written, or NULL */
653   const buf_page_t* m_last;
654   /** The current byte offset in m_last, or 0 */
655   uint16_t m_last_offset;
656 
657   /** specifies which operations should be logged; default MTR_LOG_ALL */
658   uint16_t m_log_mode:2;
659 
660   /** whether at least one buffer pool page was written to */
661   uint16_t m_modifications:1;
662 
663   /** whether at least one previously clean buffer pool page was written to */
664   uint16_t m_made_dirty:1;
665 
666   /** whether change buffer is latched; only needed in non-debug builds
667   to suppress some read-ahead operations, @see ibuf_inside() */
668   uint16_t m_inside_ibuf:1;
669 
670   /** whether the pages has been trimmed */
671   uint16_t m_trim_pages:1;
672 
673 #ifdef UNIV_DEBUG
674   /** Persistent user tablespace associated with the
675   mini-transaction, or 0 (TRX_SYS_SPACE) if none yet */
676   uint32_t m_user_space_id;
677 #endif /* UNIV_DEBUG */
678 
679   /** acquired dict_index_t::lock, fil_space_t::latch, buf_block_t */
680   mtr_buf_t m_memo;
681 
682   /** mini-transaction log */
683   mtr_buf_t m_log;
684 
685   /** user tablespace that is being modified by the mini-transaction */
686   fil_space_t* m_user_space;
687 
688   /** LSN at commit time */
689   lsn_t m_commit_lsn;
690 
691   /** tablespace where pages have been freed */
692   fil_space_t *m_freed_space= nullptr;
693   /** set of freed page ids */
694   range_set *m_freed_pages= nullptr;
695 };
696 
697 #include "mtr0mtr.inl"
698 
699 #endif /* mtr0mtr_h */
700