| 1 | /***************************************************************************** |
| 2 | |
| 3 | Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. |
| 4 | Copyright (c) 2017, 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, Suite 500, Boston, MA 02110-1335 USA |
| 17 | |
| 18 | *****************************************************************************/ |
| 19 | |
| 20 | /**************************************************//** |
| 21 | @file include/mtr0log.ic |
| 22 | Mini-transaction logging routines |
| 23 | |
| 24 | Created 12/7/1995 Heikki Tuuri |
| 25 | *******************************************************/ |
| 26 | |
| 27 | #include "buf0dblwr.h" |
| 28 | #include "fsp0types.h" |
| 29 | #include "mach0data.h" |
| 30 | #include "trx0types.h" |
| 31 | |
| 32 | /********************************************************//** |
| 33 | Opens a buffer to mlog. It must be closed with mlog_close. |
| 34 | @return buffer, NULL if log mode MTR_LOG_NONE or MTR_LOG_NO_REDO */ |
| 35 | UNIV_INLINE |
| 36 | byte* |
| 37 | mlog_open( |
| 38 | /*======*/ |
| 39 | mtr_t* mtr, /*!< in: mtr */ |
| 40 | ulint size) /*!< in: buffer size in bytes; MUST be |
| 41 | smaller than mtr_t::buf_t::MAX_DATA_SIZE! */ |
| 42 | { |
| 43 | mtr->set_modified(); |
| 44 | |
| 45 | if (mtr_get_log_mode(mtr) == MTR_LOG_NONE |
| 46 | || mtr_get_log_mode(mtr) == MTR_LOG_NO_REDO) { |
| 47 | |
| 48 | return(NULL); |
| 49 | } |
| 50 | |
| 51 | return(mtr->get_log()->open(size)); |
| 52 | } |
| 53 | |
| 54 | /********************************************************//** |
| 55 | Closes a buffer opened to mlog. */ |
| 56 | UNIV_INLINE |
| 57 | void |
| 58 | mlog_close( |
| 59 | /*=======*/ |
| 60 | mtr_t* mtr, /*!< in: mtr */ |
| 61 | byte* ptr) /*!< in: buffer space from ptr up was not used */ |
| 62 | { |
| 63 | ut_ad(mtr_get_log_mode(mtr) != MTR_LOG_NONE); |
| 64 | ut_ad(mtr_get_log_mode(mtr) != MTR_LOG_NO_REDO); |
| 65 | |
| 66 | mtr->get_log()->close(ptr); |
| 67 | } |
| 68 | |
| 69 | /********************************************************//** |
| 70 | Catenates 1 - 4 bytes to the mtr log. The value is not compressed. */ |
| 71 | UNIV_INLINE |
| 72 | void |
| 73 | mlog_catenate_ulint( |
| 74 | /*================*/ |
| 75 | mtr_buf_t* mtr_buf, /*!< in/out: buffer to write */ |
| 76 | ulint val, /*!< in: value to write */ |
| 77 | mlog_id_t type) /*!< in: type of value to write */ |
| 78 | { |
| 79 | compile_time_assert(MLOG_1BYTE == 1); |
| 80 | compile_time_assert(MLOG_2BYTES == 2); |
| 81 | compile_time_assert(MLOG_4BYTES == 4); |
| 82 | compile_time_assert(MLOG_8BYTES == 8); |
| 83 | |
| 84 | byte* ptr = mtr_buf->push<byte*>(type); |
| 85 | |
| 86 | switch (type) { |
| 87 | case MLOG_4BYTES: |
| 88 | mach_write_to_4(ptr, val); |
| 89 | break; |
| 90 | case MLOG_2BYTES: |
| 91 | mach_write_to_2(ptr, val); |
| 92 | break; |
| 93 | case MLOG_1BYTE: |
| 94 | mach_write_to_1(ptr, val); |
| 95 | break; |
| 96 | default: |
| 97 | ut_error; |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | /********************************************************//** |
| 102 | Catenates 1 - 4 bytes to the mtr log. The value is not compressed. */ |
| 103 | UNIV_INLINE |
| 104 | void |
| 105 | mlog_catenate_ulint( |
| 106 | /*================*/ |
| 107 | mtr_t* mtr, /*!< in/out: mtr */ |
| 108 | ulint val, /*!< in: value to write */ |
| 109 | mlog_id_t type) /*!< in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */ |
| 110 | { |
| 111 | if (mtr_get_log_mode(mtr) == MTR_LOG_NONE |
| 112 | || mtr_get_log_mode(mtr) == MTR_LOG_NO_REDO) { |
| 113 | |
| 114 | return; |
| 115 | } |
| 116 | |
| 117 | mlog_catenate_ulint(mtr->get_log(), val, type); |
| 118 | } |
| 119 | |
| 120 | /********************************************************//** |
| 121 | Catenates a compressed ulint to mlog. */ |
| 122 | UNIV_INLINE |
| 123 | void |
| 124 | mlog_catenate_ulint_compressed( |
| 125 | /*===========================*/ |
| 126 | mtr_t* mtr, /*!< in: mtr */ |
| 127 | ulint val) /*!< in: value to write */ |
| 128 | { |
| 129 | byte* log_ptr; |
| 130 | |
| 131 | log_ptr = mlog_open(mtr, 10); |
| 132 | |
| 133 | /* If no logging is requested, we may return now */ |
| 134 | if (log_ptr == NULL) { |
| 135 | |
| 136 | return; |
| 137 | } |
| 138 | |
| 139 | log_ptr += mach_write_compressed(log_ptr, val); |
| 140 | |
| 141 | mlog_close(mtr, log_ptr); |
| 142 | } |
| 143 | |
| 144 | /********************************************************//** |
| 145 | Catenates a compressed 64-bit integer to mlog. */ |
| 146 | UNIV_INLINE |
| 147 | void |
| 148 | mlog_catenate_ull_compressed( |
| 149 | /*=========================*/ |
| 150 | mtr_t* mtr, /*!< in: mtr */ |
| 151 | ib_uint64_t val) /*!< in: value to write */ |
| 152 | { |
| 153 | byte* log_ptr; |
| 154 | |
| 155 | log_ptr = mlog_open(mtr, 15); |
| 156 | |
| 157 | /* If no logging is requested, we may return now */ |
| 158 | if (log_ptr == NULL) { |
| 159 | |
| 160 | return; |
| 161 | } |
| 162 | |
| 163 | log_ptr += mach_u64_write_compressed(log_ptr, val); |
| 164 | |
| 165 | mlog_close(mtr, log_ptr); |
| 166 | } |
| 167 | |
| 168 | /** Writes a log record about an operation. |
| 169 | @param[in] type redo log record type |
| 170 | @param[in] space_id tablespace identifier |
| 171 | @param[in] page_no page number |
| 172 | @param[in,out] log_ptr current end of mini-transaction log |
| 173 | @param[in,out] mtr mini-transaction |
| 174 | @return end of mini-transaction log */ |
| 175 | UNIV_INLINE |
| 176 | byte* |
| 177 | mlog_write_initial_log_record_low( |
| 178 | mlog_id_t type, |
| 179 | ulint space_id, |
| 180 | ulint page_no, |
| 181 | byte* log_ptr, |
| 182 | mtr_t* mtr) |
| 183 | { |
| 184 | ut_ad(type <= MLOG_BIGGEST_TYPE || EXTRA_CHECK_MLOG_NUMBER(type)); |
| 185 | ut_ad(type == MLOG_FILE_NAME |
| 186 | || type == MLOG_FILE_DELETE |
| 187 | || type == MLOG_FILE_CREATE2 |
| 188 | || type == MLOG_FILE_RENAME2 |
| 189 | || type == MLOG_INDEX_LOAD |
| 190 | || type == MLOG_TRUNCATE |
| 191 | || type == MLOG_FILE_WRITE_CRYPT_DATA |
| 192 | || mtr->is_named_space(space_id)); |
| 193 | |
| 194 | mach_write_to_1(log_ptr, type); |
| 195 | log_ptr++; |
| 196 | |
| 197 | log_ptr += mach_write_compressed(log_ptr, space_id); |
| 198 | log_ptr += mach_write_compressed(log_ptr, page_no); |
| 199 | |
| 200 | mtr->added_rec(); |
| 201 | return(log_ptr); |
| 202 | } |
| 203 | |
| 204 | /********************************************************//** |
| 205 | Writes the initial part of a log record (3..11 bytes). |
| 206 | If the implementation of this function is changed, all |
| 207 | size parameters to mlog_open() should be adjusted accordingly! |
| 208 | @return new value of log_ptr */ |
| 209 | UNIV_INLINE |
| 210 | byte* |
| 211 | mlog_write_initial_log_record_fast( |
| 212 | /*===============================*/ |
| 213 | const byte* ptr, /*!< in: pointer to (inside) a buffer |
| 214 | frame holding the file page where |
| 215 | modification is made */ |
| 216 | mlog_id_t type, /*!< in: log item type: MLOG_1BYTE, ... */ |
| 217 | byte* log_ptr,/*!< in: pointer to mtr log which has |
| 218 | been opened */ |
| 219 | mtr_t* mtr) /*!< in/out: mtr */ |
| 220 | { |
| 221 | const byte* page; |
| 222 | ulint space; |
| 223 | ulint offset; |
| 224 | |
| 225 | ut_ad(log_ptr); |
| 226 | ut_d(mtr->memo_modify_page(ptr)); |
| 227 | |
| 228 | page = (const byte*) ut_align_down(ptr, srv_page_size); |
| 229 | space = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); |
| 230 | offset = mach_read_from_4(page + FIL_PAGE_OFFSET); |
| 231 | |
| 232 | /* check whether the page is in the doublewrite buffer; |
| 233 | the doublewrite buffer is located in pages |
| 234 | FSP_EXTENT_SIZE, ..., 3 * FSP_EXTENT_SIZE - 1 in the |
| 235 | system tablespace */ |
| 236 | |
| 237 | if (space == TRX_SYS_SPACE |
| 238 | && offset >= FSP_EXTENT_SIZE && offset < 3 * FSP_EXTENT_SIZE) { |
| 239 | ut_ad(buf_dblwr_being_created); |
| 240 | /* Do nothing: we only come to this branch in an |
| 241 | InnoDB database creation. We do not redo log |
| 242 | anything for the doublewrite buffer pages. */ |
| 243 | return(log_ptr); |
| 244 | } |
| 245 | |
| 246 | return(mlog_write_initial_log_record_low(type, space, offset, |
| 247 | log_ptr, mtr)); |
| 248 | } |
| 249 | |