MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mtr0mtr.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #include "mtr0mtr.h"
27 
28 #ifdef UNIV_NONINL
29 #include "mtr0mtr.ic"
30 #endif
31 
32 #include "buf0buf.h"
33 #include "buf0flu.h"
34 #include "page0types.h"
35 #include "mtr0log.h"
36 #include "log0log.h"
37 
38 #ifndef UNIV_HOTBACKUP
39 # include "log0recv.h"
40 
41 /***************************************************/
44 UNIV_INTERN
45 ibool
47 /*==============*/
48  const buf_block_t* block)
49 {
51  ut_ad(block->page.buf_fix_count > 0);
52 
53  /* It is OK to read oldest_modification because no
54  other thread can be performing a write of it and it
55  is only during write that the value is reset to 0. */
56  return(block->page.oldest_modification == 0);
57 }
58 
59 /*****************************************************************/
61 static __attribute__((nonnull))
62 void
63 mtr_memo_slot_release_func(
64 /*=======================*/
65 #ifdef UNIV_DEBUG
66  mtr_t* mtr,
67 #endif /* UNIV_DEBUG */
68  mtr_memo_slot_t* slot)
69 {
70  void* object = slot->object;
71  slot->object = NULL;
72 
73  /* slot release is a local operation for the current mtr.
74  We must not be holding the flush_order mutex while
75  doing this. */
77 
78  switch (slot->type) {
79  case MTR_MEMO_PAGE_S_FIX:
80  case MTR_MEMO_PAGE_X_FIX:
81  case MTR_MEMO_BUF_FIX:
82  buf_page_release((buf_block_t*) object, slot->type);
83  break;
84  case MTR_MEMO_S_LOCK:
85  rw_lock_s_unlock((rw_lock_t*) object);
86  break;
87  case MTR_MEMO_X_LOCK:
88  rw_lock_x_unlock((rw_lock_t*) object);
89  break;
90 #ifdef UNIV_DEBUG
91  default:
92  ut_ad(slot->type == MTR_MEMO_MODIFY);
93  ut_ad(mtr_memo_contains(mtr, object, MTR_MEMO_PAGE_X_FIX));
94 #endif /* UNIV_DEBUG */
95  }
96 }
97 
98 #ifdef UNIV_DEBUG
99 # define mtr_memo_slot_release(mtr, slot) mtr_memo_slot_release_func(mtr, slot)
100 #else /* UNIV_DEBUG */
101 # define mtr_memo_slot_release(mtr, slot) mtr_memo_slot_release_func(slot)
102 #endif /* UNIV_DEBUG */
103 
104 /**********************************************************/
108 static __attribute__((nonnull))
109 void
110 mtr_memo_pop_all(
111 /*=============*/
112  mtr_t* mtr)
113 {
114  ut_ad(mtr->magic_n == MTR_MAGIC_N);
115  ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in
116  commit */
117 
118  for (const dyn_block_t* block = dyn_array_get_last_block(&mtr->memo);
119  block;
120  block = dyn_array_get_prev_block(&mtr->memo, block)) {
121  const mtr_memo_slot_t* start
122  = reinterpret_cast<mtr_memo_slot_t*>(
124  mtr_memo_slot_t* slot
125  = reinterpret_cast<mtr_memo_slot_t*>(
128 
130 
131  while (slot-- != start) {
132  if (slot->object != NULL) {
133  mtr_memo_slot_release(mtr, slot);
134  }
135  }
136  }
137 }
138 
139 /*****************************************************************/
141 static
142 void
143 mtr_memo_slot_note_modification(
144 /*============================*/
145  mtr_t* mtr,
146  mtr_memo_slot_t* slot)
147 {
148  ut_ad(mtr->modifications);
150  ut_ad(mtr->magic_n == MTR_MAGIC_N);
151 
152  if (slot->object != NULL && slot->type == MTR_MEMO_PAGE_X_FIX) {
153  buf_block_t* block = (buf_block_t*) slot->object;
154 
156  buf_flush_note_modification(block, mtr);
157  }
158 }
159 
160 /**********************************************************/
167 static
168 void
169 mtr_memo_note_modifications(
170 /*========================*/
171  mtr_t* mtr)
172 {
173  dyn_array_t* memo;
174  ulint offset;
175 
177  ut_ad(mtr->magic_n == MTR_MAGIC_N);
178  ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in
179  commit */
180  memo = &mtr->memo;
181 
182  offset = dyn_array_get_data_size(memo);
183 
184  while (offset > 0) {
185  mtr_memo_slot_t* slot;
186 
187  offset -= sizeof(mtr_memo_slot_t);
188 
189  slot = static_cast<mtr_memo_slot_t*>(
190  dyn_array_get_element(memo, offset));
191 
192  mtr_memo_slot_note_modification(mtr, slot);
193  }
194 }
195 
196 /************************************************************/
198 static
199 void
200 mtr_add_dirtied_pages_to_flush_list(
201 /*================================*/
202  mtr_t* mtr)
203 {
205 
206  /* No need to acquire log_flush_order_mutex if this mtr has
207  not dirtied a clean page. log_flush_order_mutex is used to
208  ensure ordered insertions in the flush_list. We need to
209  insert in the flush_list iff the page in question was clean
210  before modifications. */
211  if (mtr->made_dirty) {
213  }
214 
215  /* It is now safe to release the log mutex because the
216  flush_order mutex will ensure that we are the first one
217  to insert into the flush list. */
218  log_release();
219 
220  if (mtr->modifications) {
221  mtr_memo_note_modifications(mtr);
222  }
223 
224  if (mtr->made_dirty) {
226  }
227 }
228 
229 /************************************************************/
231 static
232 void
233 mtr_log_reserve_and_write(
234 /*======================*/
235  mtr_t* mtr)
236 {
237  dyn_array_t* mlog;
238  ulint data_size;
239  byte* first_data;
240 
242 
243  mlog = &(mtr->log);
244 
245  first_data = dyn_block_get_data(mlog);
246 
247  if (mtr->n_log_recs > 1) {
249  } else {
250  *first_data = (byte)((ulint)*first_data
252  }
253 
254  if (mlog->heap == NULL) {
255  ulint len;
256 
257  len = mtr->log_mode != MTR_LOG_NO_REDO
258  ? dyn_block_get_used(mlog) : 0;
259 
260  mtr->end_lsn = log_reserve_and_write_fast(
261  first_data, len, &mtr->start_lsn);
262 
263  if (mtr->end_lsn) {
264 
265  /* Success. We have the log mutex.
266  Add pages to flush list and exit */
267  mtr_add_dirtied_pages_to_flush_list(mtr);
268 
269  return;
270  }
271  }
272 
273  data_size = dyn_array_get_data_size(mlog);
274 
275  /* Open the database log for log_write_low */
276  mtr->start_lsn = log_reserve_and_open(data_size);
277 
278  if (mtr->log_mode == MTR_LOG_ALL) {
279 
280  for (dyn_block_t* block = mlog;
281  block != 0;
282  block = dyn_array_get_next_block(mlog, block)) {
283 
285  dyn_block_get_data(block),
286  dyn_block_get_used(block));
287  }
288 
289  } else {
290  ut_ad(mtr->log_mode == MTR_LOG_NONE
291  || mtr->log_mode == MTR_LOG_NO_REDO);
292  /* Do nothing */
293  }
294 
295  mtr->end_lsn = log_close();
296 
297  mtr_add_dirtied_pages_to_flush_list(mtr);
298 }
299 #endif /* !UNIV_HOTBACKUP */
300 
301 /***************************************************************/
303 UNIV_INTERN
304 void
306 /*=======*/
307  mtr_t* mtr)
308 {
309  ut_ad(mtr);
310  ut_ad(mtr->magic_n == MTR_MAGIC_N);
311  ut_ad(mtr->state == MTR_ACTIVE);
312  ut_ad(!mtr->inside_ibuf);
313  ut_d(mtr->state = MTR_COMMITTING);
314 
315 #ifndef UNIV_HOTBACKUP
316  /* This is a dirty read, for debugging. */
317  ut_ad(!recv_no_log_write);
318 
319  if (mtr->modifications && mtr->n_log_recs) {
321  mtr_log_reserve_and_write(mtr);
322  }
323 
324  mtr_memo_pop_all(mtr);
325 #endif /* !UNIV_HOTBACKUP */
326 
327  dyn_array_free(&(mtr->memo));
328  dyn_array_free(&(mtr->log));
329 #ifdef UNIV_DEBUG_VALGRIND
330  /* Declare everything uninitialized except
331  mtr->start_lsn, mtr->end_lsn and mtr->state. */
332  {
333  lsn_t start_lsn = mtr->start_lsn;
334  lsn_t end_lsn = mtr->end_lsn;
335  UNIV_MEM_INVALID(mtr, sizeof *mtr);
336  mtr->start_lsn = start_lsn;
337  mtr->end_lsn = end_lsn;
338  }
339 #endif /* UNIV_DEBUG_VALGRIND */
340  ut_d(mtr->state = MTR_COMMITTED);
341 }
342 
343 #ifndef UNIV_HOTBACKUP
344 /***************************************************/
347 UNIV_INTERN
348 bool
350 /*=============*/
351  mtr_t* mtr,
352  void* object,
353  ulint type)
354 {
355  ut_ad(mtr->magic_n == MTR_MAGIC_N);
356  ut_ad(mtr->state == MTR_ACTIVE);
357  /* We cannot release a page that has been written to in the
358  middle of a mini-transaction. */
359  ut_ad(!mtr->modifications || type != MTR_MEMO_PAGE_X_FIX);
360 
361  for (const dyn_block_t* block = dyn_array_get_last_block(&mtr->memo);
362  block;
363  block = dyn_array_get_prev_block(&mtr->memo, block)) {
364  const mtr_memo_slot_t* start
365  = reinterpret_cast<mtr_memo_slot_t*>(
366  dyn_block_get_data(block));
367  mtr_memo_slot_t* slot
368  = reinterpret_cast<mtr_memo_slot_t*>(
369  dyn_block_get_data(block)
370  + dyn_block_get_used(block));
371 
372  ut_ad(!(dyn_block_get_used(block) % sizeof(mtr_memo_slot_t)));
373 
374  while (slot-- != start) {
375  if (object == slot->object && type == slot->type) {
376  mtr_memo_slot_release(mtr, slot);
377  return(true);
378  }
379  }
380  }
381 
382  return(false);
383 }
384 #endif /* !UNIV_HOTBACKUP */
385 
386 /********************************************************/
389 UNIV_INTERN
390 ulint
392 /*===========*/
393  const byte* ptr,
394  ulint type,
395  mtr_t* mtr __attribute__((unused)))
397 {
398  ut_ad(mtr->state == MTR_ACTIVE);
399  ut_ad(mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_S_FIX)
400  || mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_X_FIX));
401 
402  return(mach_read_ulint(ptr, type));
403 }
404 
405 #ifdef UNIV_DEBUG
406 # ifndef UNIV_HOTBACKUP
407 /**********************************************************/
410 UNIV_INTERN
411 ibool
412 mtr_memo_contains_page(
413 /*===================*/
414  mtr_t* mtr,
415  const byte* ptr,
416  ulint type)
417 {
418  return(mtr_memo_contains(mtr, buf_block_align(ptr), type));
419 }
420 
421 /*********************************************************/
423 UNIV_INTERN
424 void
425 mtr_print(
426 /*======*/
427  mtr_t* mtr)
428 {
429  fprintf(stderr,
430  "Mini-transaction handle: memo size %lu bytes"
431  " log size %lu bytes\n",
432  (ulong) dyn_array_get_data_size(&(mtr->memo)),
433  (ulong) dyn_array_get_data_size(&(mtr->log)));
434 }
435 # endif /* !UNIV_HOTBACKUP */
436 #endif /* UNIV_DEBUG */