1
/*****************************************************************************
3
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
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.
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.
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., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
17
*****************************************************************************/
19
/**************************************************//**
21
Mini-transaction buffer
23
Created 11/26/1995 Heikki Tuuri
24
*******************************************************/
34
#include "page0types.h"
38
#ifndef UNIV_HOTBACKUP
39
# include "log0recv.h"
40
/*****************************************************************//**
41
Releases the item in the slot given. */
44
mtr_memo_slot_release(
45
/*==================*/
46
mtr_t* mtr, /*!< in: mtr */
47
mtr_memo_slot_t* slot) /*!< in: memo slot */
57
#endif /* UNIV_DEBUG */
59
object = slot->object;
62
if (UNIV_LIKELY(object != NULL)) {
63
if (type <= MTR_MEMO_BUF_FIX) {
64
buf_page_release((buf_block_t*)object, type);
65
} else if (type == MTR_MEMO_S_LOCK) {
66
rw_lock_s_unlock((rw_lock_t*)object);
68
} else if (type != MTR_MEMO_X_LOCK) {
69
ut_ad(type == MTR_MEMO_MODIFY);
70
ut_ad(mtr_memo_contains(mtr, object,
71
MTR_MEMO_PAGE_X_FIX));
72
#endif /* UNIV_DEBUG */
74
rw_lock_x_unlock((rw_lock_t*)object);
81
/**********************************************************//**
82
Releases the mlocks and other objects stored in an mtr memo.
83
They are released in the order opposite to which they were pushed
89
mtr_t* mtr) /*!< in: mtr */
91
mtr_memo_slot_t* slot;
96
ut_ad(mtr->magic_n == MTR_MAGIC_N);
97
ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in
101
offset = dyn_array_get_data_size(memo);
104
offset -= sizeof(mtr_memo_slot_t);
105
slot = dyn_array_get_element(memo, offset);
107
mtr_memo_slot_release(mtr, slot);
111
/*****************************************************************//**
112
Releases the item in the slot given. */
115
mtr_memo_slot_note_modification(
116
/*============================*/
117
mtr_t* mtr, /*!< in: mtr */
118
mtr_memo_slot_t* slot) /*!< in: memo slot */
121
ut_ad(mtr->magic_n == MTR_MAGIC_N);
122
ut_ad(mtr->modifications);
124
if (slot->object != NULL && slot->type == MTR_MEMO_PAGE_X_FIX) {
125
buf_block_t* block = (buf_block_t*) slot->object;
128
ut_ad(log_flush_order_mutex_own());
129
#endif /* UNIV_DEBUG */
130
buf_flush_note_modification(block, mtr);
134
/**********************************************************//**
135
Add the modified pages to the buffer flush list. They are released
136
in the order opposite to which they were pushed to the memo. NOTE! It is
137
essential that the x-rw-lock on a modified buffer page is not released
138
before buf_page_note_modification is called for that page! Otherwise,
139
some thread might race to modify it, and the flush list sort order on
140
lsn would be destroyed. */
143
mtr_memo_note_modifications(
144
/*========================*/
145
mtr_t* mtr) /*!< in: mtr */
151
ut_ad(mtr->magic_n == MTR_MAGIC_N);
152
ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in
156
offset = dyn_array_get_data_size(memo);
159
mtr_memo_slot_t* slot;
161
offset -= sizeof(mtr_memo_slot_t);
162
slot = dyn_array_get_element(memo, offset);
164
mtr_memo_slot_note_modification(mtr, slot);
168
/************************************************************//**
169
Writes the contents of a mini-transaction log, if any, to the database log. */
172
mtr_log_reserve_and_write(
173
/*======================*/
174
mtr_t* mtr) /*!< in: mtr */
185
first_data = dyn_block_get_data(mlog);
187
if (mtr->n_log_recs > 1) {
188
mlog_catenate_ulint(mtr, MLOG_MULTI_REC_END, MLOG_1BYTE);
190
*first_data = (byte)((ulint)*first_data
191
| MLOG_SINGLE_REC_FLAG);
194
if (mlog->heap == NULL) {
195
mtr->end_lsn = log_reserve_and_write_fast(
196
first_data, dyn_block_get_used(mlog),
200
/* Success. We have the log mutex.
201
Add pages to flush list and exit */
206
data_size = dyn_array_get_data_size(mlog);
208
/* Open the database log for log_write_low */
209
mtr->start_lsn = log_reserve_and_open(data_size);
211
if (mtr->log_mode == MTR_LOG_ALL) {
215
while (block != NULL) {
216
log_write_low(dyn_block_get_data(block),
217
dyn_block_get_used(block));
218
block = dyn_array_get_next_block(mlog, block);
221
ut_ad(mtr->log_mode == MTR_LOG_NONE);
225
mtr->end_lsn = log_close();
228
log_flush_order_mutex_enter();
230
/* It is now safe to release the log mutex because the
231
flush_order mutex will ensure that we are the first one
232
to insert into the flush list. */
235
if (mtr->modifications) {
236
mtr_memo_note_modifications(mtr);
239
log_flush_order_mutex_exit();
241
#endif /* !UNIV_HOTBACKUP */
243
/***************************************************************//**
244
Commits a mini-transaction. */
249
mtr_t* mtr) /*!< in: mini-transaction */
252
ut_ad(mtr->magic_n == MTR_MAGIC_N);
253
ut_ad(mtr->state == MTR_ACTIVE);
254
ut_d(mtr->state = MTR_COMMITTING);
256
#ifndef UNIV_HOTBACKUP
257
/* This is a dirty read, for debugging. */
258
ut_ad(!recv_no_log_write);
260
if (mtr->modifications && mtr->n_log_recs) {
261
mtr_log_reserve_and_write(mtr);
264
mtr_memo_pop_all(mtr);
265
#endif /* !UNIV_HOTBACKUP */
267
ut_d(mtr->state = MTR_COMMITTED);
268
dyn_array_free(&(mtr->memo));
269
dyn_array_free(&(mtr->log));
272
#ifndef UNIV_HOTBACKUP
273
/**********************************************************//**
274
Releases the latches stored in an mtr memo down to a savepoint.
275
NOTE! The mtr must not have made changes to buffer pages after the
276
savepoint, as these can be handled only by mtr_commit. */
279
mtr_rollback_to_savepoint(
280
/*======================*/
281
mtr_t* mtr, /*!< in: mtr */
282
ulint savepoint) /*!< in: savepoint */
284
mtr_memo_slot_t* slot;
289
ut_ad(mtr->magic_n == MTR_MAGIC_N);
290
ut_ad(mtr->state == MTR_ACTIVE);
294
offset = dyn_array_get_data_size(memo);
295
ut_ad(offset >= savepoint);
297
while (offset > savepoint) {
298
offset -= sizeof(mtr_memo_slot_t);
300
slot = dyn_array_get_element(memo, offset);
302
ut_ad(slot->type != MTR_MEMO_MODIFY);
304
/* We do not call mtr_memo_slot_note_modification()
305
because there MUST be no changes made to the buffer
306
pages after the savepoint */
307
mtr_memo_slot_release(mtr, slot);
311
/***************************************************//**
312
Releases an object in the memo stack. */
317
mtr_t* mtr, /*!< in: mtr */
318
void* object, /*!< in: object */
319
ulint type) /*!< in: object type: MTR_MEMO_S_LOCK, ... */
321
mtr_memo_slot_t* slot;
326
ut_ad(mtr->magic_n == MTR_MAGIC_N);
327
ut_ad(mtr->state == MTR_ACTIVE);
331
offset = dyn_array_get_data_size(memo);
333
log_flush_order_mutex_enter();
335
offset -= sizeof(mtr_memo_slot_t);
337
slot = dyn_array_get_element(memo, offset);
339
if (object == slot->object && type == slot->type) {
341
/* We cannot release a page that has been written
342
to in the middle of a mini-transaction. */
344
ut_ad(!(mtr->modifications
345
&& slot->type == MTR_MEMO_PAGE_X_FIX));
347
mtr_memo_slot_release(mtr, slot);
352
log_flush_order_mutex_exit();
354
#endif /* !UNIV_HOTBACKUP */
356
/********************************************************//**
357
Reads 1 - 4 bytes from a file page buffered in the buffer pool.
358
@return value read */
363
const byte* ptr, /*!< in: pointer from where to read */
364
ulint type, /*!< in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */
365
mtr_t* mtr __attribute__((unused)))
366
/*!< in: mini-transaction handle */
368
ut_ad(mtr->state == MTR_ACTIVE);
369
ut_ad(mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_S_FIX)
370
|| mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_X_FIX));
371
if (type == MLOG_1BYTE) {
372
return(mach_read_from_1(ptr));
373
} else if (type == MLOG_2BYTES) {
374
return(mach_read_from_2(ptr));
376
ut_ad(type == MLOG_4BYTES);
377
return(mach_read_from_4(ptr));
382
# ifndef UNIV_HOTBACKUP
383
/**********************************************************//**
384
Checks if memo contains the given page.
385
@return TRUE if contains */
388
mtr_memo_contains_page(
389
/*===================*/
390
mtr_t* mtr, /*!< in: mtr */
391
const byte* ptr, /*!< in: pointer to buffer frame */
392
ulint type) /*!< in: type of object */
394
return(mtr_memo_contains(mtr, buf_block_align(ptr), type));
397
/*********************************************************//**
398
Prints info of an mtr handle. */
403
mtr_t* mtr) /*!< in: mtr */
406
"Mini-transaction handle: memo size %lu bytes"
407
" log size %lu bytes\n",
408
(ulong) dyn_array_get_data_size(&(mtr->memo)),
409
(ulong) dyn_array_get_data_size(&(mtr->log)));
411
# endif /* !UNIV_HOTBACKUP */
412
#endif /* UNIV_DEBUG */