1/*****************************************************************************
2
3Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2012, Facebook Inc.
5Copyright (c) 2013, 2017, MariaDB Corporation
6
7This program is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free Software
9Foundation; version 2 of the License.
10
11This program is distributed in the hope that it will be useful, but WITHOUT
12ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License along with
16this program; if not, write to the Free Software Foundation, Inc.,
1751 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
18
19*****************************************************************************/
20
21/**************************************************//**
22@file include/mtr0mtr.h
23Mini-transaction buffer
24
25Created 11/26/1995 Heikki Tuuri
26*******************************************************/
27
28#ifndef mtr0mtr_h
29#define mtr0mtr_h
30
31#include "univ.i"
32#include "fil0fil.h"
33#include "dyn0buf.h"
34
35/** Start a mini-transaction. */
36#define mtr_start(m) (m)->start()
37
38/** Start a synchronous mini-transaction */
39#define mtr_start_sync(m) (m)->start(true)
40
41/** Start an asynchronous read-only mini-transaction */
42#define mtr_start_ro(m) (m)->start(true, true)
43
44/** Commit a mini-transaction. */
45#define mtr_commit(m) (m)->commit()
46
47/** Set and return a savepoint in mtr.
48@return savepoint */
49#define mtr_set_savepoint(m) (m)->get_savepoint()
50
51/** Release the (index tree) s-latch stored in an mtr memo after a
52savepoint. */
53#define mtr_release_s_latch_at_savepoint(m, s, l) \
54 (m)->release_s_latch_at_savepoint((s), (l))
55
56/** Get the logging mode of a mini-transaction.
57@return logging mode: MTR_LOG_NONE, ... */
58#define mtr_get_log_mode(m) (m)->get_log_mode()
59
60/** Change the logging mode of a mini-transaction.
61@return old mode */
62#define mtr_set_log_mode(m, d) (m)->set_log_mode((d))
63
64/** Get the flush observer of a mini-transaction.
65@return flush observer object */
66#define mtr_get_flush_observer(m) (m)->get_flush_observer()
67
68/** Set the flush observer of a mini-transaction. */
69#define mtr_set_flush_observer(m, d) (m)->set_flush_observer((d))
70
71/** Read 1 - 4 bytes from a file page buffered in the buffer pool.
72@return value read */
73#define mtr_read_ulint(p, t, m) (m)->read_ulint((p), (t))
74
75/** Release an object in the memo stack.
76@return true if released */
77#define mtr_memo_release(m, o, t) \
78 (m)->memo_release((o), (t))
79
80#ifdef UNIV_DEBUG
81/** Check if memo contains the given item.
82@return TRUE if contains */
83#define mtr_memo_contains(m, o, t) \
84 (m)->memo_contains((m)->get_memo(), (o), (t))
85
86/** Check if memo contains the given page.
87@return TRUE if contains */
88#define mtr_memo_contains_page(m, p, t) \
89 (m)->memo_contains_page_flagged((p), (t))
90#endif /* UNIV_DEBUG */
91
92/** Print info of an mtr handle. */
93#define mtr_print(m) (m)->print()
94
95/** Return the log object of a mini-transaction buffer.
96@return log */
97#define mtr_get_log(m) (m)->get_log()
98
99/** Push an object to an mtr memo stack. */
100#define mtr_memo_push(m, o, t) (m)->memo_push(o, t)
101
102/** Lock an rw-lock in s-mode. */
103#define mtr_s_lock(l, m) (m)->s_lock((l), __FILE__, __LINE__)
104
105/** Lock an rw-lock in x-mode. */
106#define mtr_x_lock(l, m) (m)->x_lock((l), __FILE__, __LINE__)
107
108/** Lock a tablespace in x-mode. */
109#define mtr_x_lock_space(s, m) (m)->x_lock_space((s), __FILE__, __LINE__)
110
111/** Lock an rw-lock in sx-mode. */
112#define mtr_sx_lock(l, m) (m)->sx_lock((l), __FILE__, __LINE__)
113
114#define mtr_memo_contains_flagged(m, p, l) \
115 (m)->memo_contains_flagged((p), (l))
116
117#define mtr_memo_contains_page_flagged(m, p, l) \
118 (m)->memo_contains_page_flagged((p), (l))
119
120#define mtr_release_block_at_savepoint(m, s, b) \
121 (m)->release_block_at_savepoint((s), (b))
122
123#define mtr_block_sx_latch_at_savepoint(m, s, b) \
124 (m)->sx_latch_at_savepoint((s), (b))
125
126#define mtr_block_x_latch_at_savepoint(m, s, b) \
127 (m)->x_latch_at_savepoint((s), (b))
128
129/** Check if a mini-transaction is dirtying a clean page.
130@param b block being x-fixed
131@return true if the mtr is dirtying a clean page. */
132#define mtr_block_dirtied(b) mtr_t::is_block_dirtied((b))
133
134/** Append records to the system-wide redo log buffer.
135@param[in] log redo log records */
136void
137mtr_write_log(
138 const mtr_buf_t* log);
139
140/** Mini-transaction memo stack slot. */
141struct mtr_memo_slot_t {
142 /** pointer to the object */
143 void* object;
144
145 /** type of the stored object (MTR_MEMO_S_LOCK, ...) */
146 ulint type;
147};
148
149/** Mini-transaction handle and buffer */
150struct mtr_t {
151
152 /** State variables of the mtr */
153 struct Impl {
154
155 /** memo stack for locks etc. */
156 mtr_buf_t m_memo;
157
158 /** mini-transaction log */
159 mtr_buf_t m_log;
160
161 /** true if mtr has made at least one buffer pool page dirty */
162 bool m_made_dirty;
163
164 /** true if inside ibuf changes */
165 bool m_inside_ibuf;
166
167 /** true if the mini-transaction modified buffer pool pages */
168 bool m_modifications;
169
170 /** Count of how many page initial log records have been
171 written to the mtr log */
172 ib_uint32_t m_n_log_recs;
173
174 /** specifies which operations should be logged; default
175 value MTR_LOG_ALL */
176 mtr_log_t m_log_mode;
177#ifdef UNIV_DEBUG
178 /** Persistent user tablespace associated with the
179 mini-transaction, or 0 (TRX_SYS_SPACE) if none yet */
180 ulint m_user_space_id;
181#endif /* UNIV_DEBUG */
182 /** User tablespace that is being modified by the
183 mini-transaction */
184 fil_space_t* m_user_space;
185
186 /** State of the transaction */
187 mtr_state_t m_state;
188
189 /** Flush Observer */
190 FlushObserver* m_flush_observer;
191
192#ifdef UNIV_DEBUG
193 /** For checking corruption. */
194 ulint m_magic_n;
195#endif /* UNIV_DEBUG */
196
197 /** Owning mini-transaction */
198 mtr_t* m_mtr;
199 };
200
201 mtr_t()
202 {
203 m_impl.m_state = MTR_STATE_INIT;
204 }
205
206 ~mtr_t() { }
207
208 /** Start a mini-transaction.
209 @param sync true if it is a synchronous mini-transaction */
210 void start(bool sync = true);
211
212 /** @return whether this is an asynchronous mini-transaction. */
213 bool is_async() const
214 {
215 return(!m_sync);
216 }
217
218 /** Request a future commit to be synchronous. */
219 void set_sync()
220 {
221 m_sync = true;
222 }
223
224 /** Commit the mini-transaction. */
225 void commit();
226
227 /** Commit a mini-transaction that did not modify any pages,
228 but generated some redo log on a higher level, such as
229 MLOG_FILE_NAME records and a MLOG_CHECKPOINT marker.
230 The caller must invoke log_mutex_enter() and log_mutex_exit().
231 This is to be used at log_checkpoint().
232 @param[in] checkpoint_lsn the LSN of the log checkpoint
233 @param[in] write_mlog_checkpoint Write MLOG_CHECKPOINT marker
234 if it is enabled. */
235 void commit_checkpoint(
236 lsn_t checkpoint_lsn,
237 bool write_mlog_checkpoint);
238
239 /** Return current size of the buffer.
240 @return savepoint */
241 ulint get_savepoint() const
242 MY_ATTRIBUTE((warn_unused_result))
243 {
244 ut_ad(is_active());
245 ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
246
247 return(m_impl.m_memo.size());
248 }
249
250 /** Release the (index tree) s-latch stored in an mtr memo after a
251 savepoint.
252 @param savepoint value returned by @see set_savepoint.
253 @param lock latch to release */
254 inline void release_s_latch_at_savepoint(
255 ulint savepoint,
256 rw_lock_t* lock);
257
258 /** Release the block in an mtr memo after a savepoint. */
259 inline void release_block_at_savepoint(
260 ulint savepoint,
261 buf_block_t* block);
262
263 /** SX-latch a not yet latched block after a savepoint. */
264 inline void sx_latch_at_savepoint(ulint savepoint, buf_block_t* block);
265
266 /** X-latch a not yet latched block after a savepoint. */
267 inline void x_latch_at_savepoint(ulint savepoint, buf_block_t* block);
268
269 /** Get the logging mode.
270 @return logging mode */
271 inline mtr_log_t get_log_mode() const
272 MY_ATTRIBUTE((warn_unused_result));
273
274 /** Change the logging mode.
275 @param mode logging mode
276 @return old mode */
277 inline mtr_log_t set_log_mode(mtr_log_t mode);
278
279 /** Copy the tablespaces associated with the mini-transaction
280 (needed for generating MLOG_FILE_NAME records)
281 @param[in] mtr mini-transaction that may modify
282 the same set of tablespaces as this one */
283 void set_spaces(const mtr_t& mtr)
284 {
285 ut_ad(!m_impl.m_user_space_id);
286 ut_ad(!m_impl.m_user_space);
287
288 ut_d(m_impl.m_user_space_id = mtr.m_impl.m_user_space_id);
289 m_impl.m_user_space = mtr.m_impl.m_user_space;
290 }
291
292 /** Set the tablespace associated with the mini-transaction
293 (needed for generating a MLOG_FILE_NAME record)
294 @param[in] space_id user or system tablespace ID
295 @return the tablespace */
296 fil_space_t* set_named_space_id(ulint space_id)
297 {
298 ut_ad(!m_impl.m_user_space_id);
299 ut_d(m_impl.m_user_space_id = space_id);
300 if (!space_id) {
301 return fil_system.sys_space;
302 } else {
303 ut_ad(m_impl.m_user_space_id == space_id);
304 ut_ad(!m_impl.m_user_space);
305 m_impl.m_user_space = fil_space_get(space_id);
306 ut_ad(m_impl.m_user_space);
307 return m_impl.m_user_space;
308 }
309 }
310
311 /** Set the tablespace associated with the mini-transaction
312 (needed for generating a MLOG_FILE_NAME record)
313 @param[in] space user or system tablespace */
314 void set_named_space(fil_space_t* space)
315 {
316 ut_ad(!m_impl.m_user_space_id);
317 ut_d(m_impl.m_user_space_id = space->id);
318 if (space->id) {
319 m_impl.m_user_space = space;
320 }
321 }
322
323#ifdef UNIV_DEBUG
324 /** Check the tablespace associated with the mini-transaction
325 (needed for generating a MLOG_FILE_NAME record)
326 @param[in] space tablespace
327 @return whether the mini-transaction is associated with the space */
328 bool is_named_space(ulint space) const;
329 /** Check the tablespace associated with the mini-transaction
330 (needed for generating a MLOG_FILE_NAME record)
331 @param[in] space tablespace
332 @return whether the mini-transaction is associated with the space */
333 bool is_named_space(const fil_space_t* space) const;
334#endif /* UNIV_DEBUG */
335
336 /** Read 1 - 4 bytes from a file page buffered in the buffer pool.
337 @param ptr pointer from where to read
338 @param type) MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES
339 @return value read */
340 inline ulint read_ulint(const byte* ptr, mlog_id_t type) const
341 MY_ATTRIBUTE((warn_unused_result));
342
343 /** Locks a rw-latch in S mode.
344 NOTE: use mtr_s_lock().
345 @param lock rw-lock
346 @param file file name from where called
347 @param line line number in file */
348 inline void s_lock(rw_lock_t* lock, const char* file, unsigned line);
349
350 /** Locks a rw-latch in X mode.
351 NOTE: use mtr_x_lock().
352 @param lock rw-lock
353 @param file file name from where called
354 @param line line number in file */
355 inline void x_lock(rw_lock_t* lock, const char* file, unsigned line);
356
357 /** Locks a rw-latch in X mode.
358 NOTE: use mtr_sx_lock().
359 @param lock rw-lock
360 @param file file name from where called
361 @param line line number in file */
362 inline void sx_lock(rw_lock_t* lock, const char* file, unsigned line);
363
364 /** Acquire a tablespace X-latch.
365 NOTE: use mtr_x_lock_space().
366 @param[in] space_id tablespace ID
367 @param[in] file file name from where called
368 @param[in] line line number in file
369 @return the tablespace object (never NULL) */
370 fil_space_t* x_lock_space(
371 ulint space_id,
372 const char* file,
373 unsigned line);
374
375 /** Release an object in the memo stack.
376 @param object object
377 @param type object type: MTR_MEMO_S_LOCK, ...
378 @return bool if lock released */
379 bool memo_release(const void* object, ulint type);
380 /** Release a page latch.
381 @param[in] ptr pointer to within a page frame
382 @param[in] type object type: MTR_MEMO_PAGE_X_FIX, ... */
383 void release_page(const void* ptr, mtr_memo_type_t type);
384
385 /** Note that the mini-transaction has modified data. */
386 void set_modified()
387 {
388 m_impl.m_modifications = true;
389 }
390
391 /** Set the state to not-modified. This will not log the
392 changes. This is only used during redo log apply, to avoid
393 logging the changes. */
394 void discard_modifications()
395 {
396 m_impl.m_modifications = false;
397 }
398
399 /** Get the LSN of commit().
400 @return the commit LSN
401 @retval 0 if the transaction only modified temporary tablespaces */
402 lsn_t commit_lsn() const
403 {
404 ut_ad(has_committed());
405 return(m_commit_lsn);
406 }
407
408 /** Note that we are inside the change buffer code. */
409 void enter_ibuf()
410 {
411 m_impl.m_inside_ibuf = true;
412 }
413
414 /** Note that we have exited from the change buffer code. */
415 void exit_ibuf()
416 {
417 m_impl.m_inside_ibuf = false;
418 }
419
420 /** @return true if we are inside the change buffer code */
421 bool is_inside_ibuf() const
422 {
423 return(m_impl.m_inside_ibuf);
424 }
425
426 /*
427 @return true if the mini-transaction is active */
428 bool is_active() const
429 {
430 return(m_impl.m_state == MTR_STATE_ACTIVE);
431 }
432
433 /** Get flush observer
434 @return flush observer */
435 FlushObserver* get_flush_observer() const
436 {
437 return(m_impl.m_flush_observer);
438 }
439
440 /** Set flush observer
441 @param[in] observer flush observer */
442 void set_flush_observer(FlushObserver* observer)
443 {
444 ut_ad(observer == NULL
445 || m_impl.m_log_mode == MTR_LOG_NO_REDO);
446
447 m_impl.m_flush_observer = observer;
448 }
449
450#ifdef UNIV_DEBUG
451 /** Check if memo contains the given item.
452 @param memo memo stack
453 @param object, object to search
454 @param type type of object
455 @return true if contains */
456 static bool memo_contains(
457 const mtr_buf_t* memo,
458 const void* object,
459 ulint type)
460 MY_ATTRIBUTE((warn_unused_result));
461
462 /** Check if memo contains the given item.
463 @param object object to search
464 @param flags specify types of object (can be ORred) of
465 MTR_MEMO_PAGE_S_FIX ... values
466 @return true if contains */
467 bool memo_contains_flagged(const void* ptr, ulint flags) const;
468
469 /** Check if memo contains the given page.
470 @param[in] ptr pointer to within buffer frame
471 @param[in] flags specify types of object with OR of
472 MTR_MEMO_PAGE_S_FIX... values
473 @return the block
474 @retval NULL if not found */
475 buf_block_t* memo_contains_page_flagged(
476 const byte* ptr,
477 ulint flags) const;
478
479 /** Mark the given latched page as modified.
480 @param[in] ptr pointer to within buffer frame */
481 void memo_modify_page(const byte* ptr);
482
483 /** Print info of an mtr handle. */
484 void print() const;
485
486 /** @return true if the mini-transaction has committed */
487 bool has_committed() const
488 {
489 return(m_impl.m_state == MTR_STATE_COMMITTED);
490 }
491
492 /** @return true if the mini-transaction is committing */
493 bool is_committing() const
494 {
495 return(m_impl.m_state == MTR_STATE_COMMITTING);
496 }
497
498 /** @return true if mini-transaction contains modifications. */
499 bool has_modifications() const
500 {
501 return(m_impl.m_modifications);
502 }
503
504 /** @return the memo stack */
505 const mtr_buf_t* get_memo() const
506 {
507 return(&m_impl.m_memo);
508 }
509
510 /** @return the memo stack */
511 mtr_buf_t* get_memo()
512 {
513 return(&m_impl.m_memo);
514 }
515#endif /* UNIV_DEBUG */
516
517 /** @return true if a record was added to the mini-transaction */
518 bool is_dirty() const
519 {
520 return(m_impl.m_made_dirty);
521 }
522
523 /** Note that a record has been added to the log */
524 void added_rec()
525 {
526 ++m_impl.m_n_log_recs;
527 }
528
529 /** Get the buffered redo log of this mini-transaction.
530 @return redo log */
531 const mtr_buf_t* get_log() const
532 {
533 ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
534
535 return(&m_impl.m_log);
536 }
537
538 /** Get the buffered redo log of this mini-transaction.
539 @return redo log */
540 mtr_buf_t* get_log()
541 {
542 ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
543
544 return(&m_impl.m_log);
545 }
546
547 /** Push an object to an mtr memo stack.
548 @param object object
549 @param type object type: MTR_MEMO_S_LOCK, ... */
550 inline void memo_push(void* object, mtr_memo_type_t type);
551
552 /** Check if this mini-transaction is dirtying a clean page.
553 @param block block being x-fixed
554 @return true if the mtr is dirtying a clean page. */
555 static bool is_block_dirtied(const buf_block_t* block)
556 MY_ATTRIBUTE((warn_unused_result));
557
558private:
559 class Command;
560
561 friend class Command;
562
563private:
564 Impl m_impl;
565
566 /** LSN at commit time */
567 volatile lsn_t m_commit_lsn;
568
569 /** true if it is synchronous mini-transaction */
570 bool m_sync;
571};
572
573#include "mtr0mtr.ic"
574
575#endif /* mtr0mtr_h */
576