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