641.2.2
by Monty Taylor
InnoDB Plugin 1.0.3 |
1 |
/*****************************************************************************
|
2 |
||
3 |
Copyright (c) 1995, 2009, Innobase Oy. 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., 59 Temple
|
|
15 |
Place, Suite 330, Boston, MA 02111-1307 USA
|
|
16 |
||
17 |
*****************************************************************************/
|
|
18 |
||
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
19 |
/******************************************************
|
20 |
Mini-transaction buffer
|
|
21 |
||
22 |
Created 11/26/1995 Heikki Tuuri
|
|
23 |
*******************************************************/
|
|
24 |
||
25 |
#include "mtr0mtr.h" |
|
26 |
||
27 |
#ifdef UNIV_NONINL
|
|
28 |
#include "mtr0mtr.ic" |
|
29 |
#endif
|
|
30 |
||
31 |
#include "buf0buf.h" |
|
32 |
#include "page0types.h" |
|
33 |
#include "mtr0log.h" |
|
34 |
#include "log0log.h" |
|
35 |
||
36 |
/*********************************************************************
|
|
37 |
Releases the item in the slot given. */
|
|
38 |
UNIV_INLINE
|
|
39 |
void
|
|
40 |
mtr_memo_slot_release( |
|
41 |
/*==================*/
|
|
42 |
mtr_t* mtr, /* in: mtr */ |
|
43 |
mtr_memo_slot_t* slot) /* in: memo slot */ |
|
44 |
{
|
|
45 |
void* object; |
|
46 |
ulint type; |
|
47 |
||
48 |
ut_ad(mtr && slot); |
|
49 |
||
50 |
object = slot->object; |
|
51 |
type = slot->type; |
|
52 |
||
53 |
if (UNIV_LIKELY(object != NULL)) { |
|
54 |
if (type <= MTR_MEMO_BUF_FIX) { |
|
55 |
buf_page_release((buf_block_t*)object, type, mtr); |
|
56 |
} else if (type == MTR_MEMO_S_LOCK) { |
|
57 |
rw_lock_s_unlock((rw_lock_t*)object); |
|
58 |
#ifdef UNIV_DEBUG
|
|
59 |
} else if (type != MTR_MEMO_X_LOCK) { |
|
60 |
ut_ad(type == MTR_MEMO_MODIFY); |
|
61 |
ut_ad(mtr_memo_contains(mtr, object, |
|
62 |
MTR_MEMO_PAGE_X_FIX)); |
|
63 |
#endif /* UNIV_DEBUG */ |
|
64 |
} else { |
|
65 |
rw_lock_x_unlock((rw_lock_t*)object); |
|
66 |
}
|
|
67 |
}
|
|
68 |
||
69 |
slot->object = NULL; |
|
70 |
}
|
|
71 |
||
72 |
/**************************************************************
|
|
73 |
Releases the mlocks and other objects stored in an mtr memo. They are released
|
|
74 |
in the order opposite to which they were pushed to the memo. NOTE! It is
|
|
75 |
essential that the x-rw-lock on a modified buffer page is not released before
|
|
76 |
buf_page_note_modification is called for that page! Otherwise, some thread
|
|
77 |
might race to modify it, and the flush list sort order on lsn would be
|
|
78 |
destroyed. */
|
|
79 |
UNIV_INLINE
|
|
80 |
void
|
|
81 |
mtr_memo_pop_all( |
|
82 |
/*=============*/
|
|
83 |
mtr_t* mtr) /* in: mtr */ |
|
84 |
{
|
|
85 |
mtr_memo_slot_t* slot; |
|
86 |
dyn_array_t* memo; |
|
87 |
ulint offset; |
|
88 |
||
89 |
ut_ad(mtr); |
|
90 |
ut_ad(mtr->magic_n == MTR_MAGIC_N); |
|
91 |
ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in |
|
92 |
commit */
|
|
93 |
memo = &(mtr->memo); |
|
94 |
||
95 |
offset = dyn_array_get_data_size(memo); |
|
96 |
||
97 |
while (offset > 0) { |
|
98 |
offset -= sizeof(mtr_memo_slot_t); |
|
99 |
slot = dyn_array_get_element(memo, offset); |
|
100 |
||
101 |
mtr_memo_slot_release(mtr, slot); |
|
102 |
}
|
|
103 |
}
|
|
104 |
||
105 |
/****************************************************************
|
|
106 |
Writes the contents of a mini-transaction log, if any, to the database log. */
|
|
107 |
static
|
|
108 |
void
|
|
109 |
mtr_log_reserve_and_write( |
|
110 |
/*======================*/
|
|
111 |
mtr_t* mtr) /* in: mtr */ |
|
112 |
{
|
|
113 |
dyn_array_t* mlog; |
|
114 |
dyn_block_t* block; |
|
115 |
ulint data_size; |
|
116 |
ibool success; |
|
117 |
byte* first_data; |
|
118 |
||
119 |
ut_ad(mtr); |
|
120 |
||
121 |
mlog = &(mtr->log); |
|
122 |
||
123 |
first_data = dyn_block_get_data(mlog); |
|
124 |
||
125 |
if (mtr->n_log_recs > 1) { |
|
126 |
mlog_catenate_ulint(mtr, MLOG_MULTI_REC_END, MLOG_1BYTE); |
|
127 |
} else { |
|
128 |
*first_data = (byte)((ulint)*first_data |
|
129 |
| MLOG_SINGLE_REC_FLAG); |
|
130 |
}
|
|
131 |
||
132 |
if (mlog->heap == NULL) { |
|
133 |
mtr->end_lsn = log_reserve_and_write_fast( |
|
134 |
first_data, dyn_block_get_used(mlog), |
|
135 |
&(mtr->start_lsn), &success); |
|
136 |
if (success) { |
|
137 |
||
138 |
return; |
|
139 |
}
|
|
140 |
}
|
|
141 |
||
142 |
data_size = dyn_array_get_data_size(mlog); |
|
143 |
||
144 |
/* Open the database log for log_write_low */
|
|
145 |
mtr->start_lsn = log_reserve_and_open(data_size); |
|
146 |
||
147 |
if (mtr->log_mode == MTR_LOG_ALL) { |
|
148 |
||
149 |
block = mlog; |
|
150 |
||
151 |
while (block != NULL) { |
|
152 |
log_write_low(dyn_block_get_data(block), |
|
153 |
dyn_block_get_used(block)); |
|
154 |
block = dyn_array_get_next_block(mlog, block); |
|
155 |
}
|
|
156 |
} else { |
|
157 |
ut_ad(mtr->log_mode == MTR_LOG_NONE); |
|
158 |
/* Do nothing */
|
|
159 |
}
|
|
160 |
||
161 |
mtr->end_lsn = log_close(); |
|
162 |
}
|
|
163 |
||
164 |
/*******************************************************************
|
|
165 |
Commits a mini-transaction. */
|
|
166 |
UNIV_INTERN
|
|
167 |
void
|
|
168 |
mtr_commit( |
|
169 |
/*=======*/
|
|
170 |
mtr_t* mtr) /* in: mini-transaction */ |
|
171 |
{
|
|
172 |
ibool write_log; |
|
173 |
||
174 |
ut_ad(mtr); |
|
175 |
ut_ad(mtr->magic_n == MTR_MAGIC_N); |
|
176 |
ut_ad(mtr->state == MTR_ACTIVE); |
|
641.2.2
by Monty Taylor
InnoDB Plugin 1.0.3 |
177 |
ut_d(mtr->state = MTR_COMMITTING); |
178 |
||
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
179 |
write_log = mtr->modifications && mtr->n_log_recs; |
180 |
||
181 |
if (write_log) { |
|
182 |
mtr_log_reserve_and_write(mtr); |
|
183 |
}
|
|
184 |
||
185 |
/* We first update the modification info to buffer pages, and only
|
|
186 |
after that release the log mutex: this guarantees that when the log
|
|
187 |
mutex is free, all buffer pages contain an up-to-date info of their
|
|
188 |
modifications. This fact is used in making a checkpoint when we look
|
|
189 |
at the oldest modification of any page in the buffer pool. It is also
|
|
190 |
required when we insert modified buffer pages in to the flush list
|
|
191 |
which must be sorted on oldest_modification. */
|
|
192 |
||
193 |
mtr_memo_pop_all(mtr); |
|
194 |
||
195 |
if (write_log) { |
|
196 |
log_release(); |
|
197 |
}
|
|
198 |
||
641.2.2
by Monty Taylor
InnoDB Plugin 1.0.3 |
199 |
ut_d(mtr->state = MTR_COMMITTED); |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
200 |
dyn_array_free(&(mtr->memo)); |
201 |
dyn_array_free(&(mtr->log)); |
|
202 |
}
|
|
203 |
||
204 |
/**************************************************************
|
|
205 |
Releases the latches stored in an mtr memo down to a savepoint.
|
|
206 |
NOTE! The mtr must not have made changes to buffer pages after the
|
|
207 |
savepoint, as these can be handled only by mtr_commit. */
|
|
208 |
UNIV_INTERN
|
|
209 |
void
|
|
210 |
mtr_rollback_to_savepoint( |
|
211 |
/*======================*/
|
|
212 |
mtr_t* mtr, /* in: mtr */ |
|
213 |
ulint savepoint) /* in: savepoint */ |
|
214 |
{
|
|
215 |
mtr_memo_slot_t* slot; |
|
216 |
dyn_array_t* memo; |
|
217 |
ulint offset; |
|
218 |
||
219 |
ut_ad(mtr); |
|
220 |
ut_ad(mtr->magic_n == MTR_MAGIC_N); |
|
221 |
ut_ad(mtr->state == MTR_ACTIVE); |
|
222 |
||
223 |
memo = &(mtr->memo); |
|
224 |
||
225 |
offset = dyn_array_get_data_size(memo); |
|
226 |
ut_ad(offset >= savepoint); |
|
227 |
||
228 |
while (offset > savepoint) { |
|
229 |
offset -= sizeof(mtr_memo_slot_t); |
|
230 |
||
231 |
slot = dyn_array_get_element(memo, offset); |
|
232 |
||
233 |
ut_ad(slot->type != MTR_MEMO_MODIFY); |
|
234 |
mtr_memo_slot_release(mtr, slot); |
|
235 |
}
|
|
236 |
}
|
|
237 |
||
238 |
/*******************************************************
|
|
239 |
Releases an object in the memo stack. */
|
|
240 |
UNIV_INTERN
|
|
241 |
void
|
|
242 |
mtr_memo_release( |
|
243 |
/*=============*/
|
|
244 |
mtr_t* mtr, /* in: mtr */ |
|
245 |
void* object, /* in: object */ |
|
246 |
ulint type) /* in: object type: MTR_MEMO_S_LOCK, ... */ |
|
247 |
{
|
|
248 |
mtr_memo_slot_t* slot; |
|
249 |
dyn_array_t* memo; |
|
250 |
ulint offset; |
|
251 |
||
252 |
ut_ad(mtr); |
|
253 |
ut_ad(mtr->magic_n == MTR_MAGIC_N); |
|
254 |
ut_ad(mtr->state == MTR_ACTIVE); |
|
255 |
||
256 |
memo = &(mtr->memo); |
|
257 |
||
258 |
offset = dyn_array_get_data_size(memo); |
|
259 |
||
260 |
while (offset > 0) { |
|
261 |
offset -= sizeof(mtr_memo_slot_t); |
|
262 |
||
263 |
slot = dyn_array_get_element(memo, offset); |
|
264 |
||
265 |
if ((object == slot->object) && (type == slot->type)) { |
|
266 |
||
267 |
mtr_memo_slot_release(mtr, slot); |
|
268 |
||
269 |
break; |
|
270 |
}
|
|
271 |
}
|
|
272 |
}
|
|
273 |
||
274 |
/************************************************************
|
|
275 |
Reads 1 - 4 bytes from a file page buffered in the buffer pool. */
|
|
276 |
UNIV_INTERN
|
|
277 |
ulint
|
|
278 |
mtr_read_ulint( |
|
279 |
/*===========*/
|
|
280 |
/* out: value read */
|
|
281 |
const byte* ptr, /* in: pointer from where to read */ |
|
282 |
ulint type, /* in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */ |
|
283 |
mtr_t* mtr __attribute__((unused))) |
|
284 |
/* in: mini-transaction handle */
|
|
285 |
{
|
|
286 |
ut_ad(mtr->state == MTR_ACTIVE); |
|
287 |
ut_ad(mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_S_FIX) |
|
288 |
|| mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_X_FIX)); |
|
289 |
if (type == MLOG_1BYTE) { |
|
290 |
return(mach_read_from_1(ptr)); |
|
291 |
} else if (type == MLOG_2BYTES) { |
|
292 |
return(mach_read_from_2(ptr)); |
|
293 |
} else { |
|
294 |
ut_ad(type == MLOG_4BYTES); |
|
295 |
return(mach_read_from_4(ptr)); |
|
296 |
}
|
|
297 |
}
|
|
298 |
||
299 |
/************************************************************
|
|
300 |
Reads 8 bytes from a file page buffered in the buffer pool. */
|
|
301 |
UNIV_INTERN
|
|
302 |
dulint
|
|
303 |
mtr_read_dulint( |
|
304 |
/*============*/
|
|
305 |
/* out: value read */
|
|
306 |
const byte* ptr, /* in: pointer from where to read */ |
|
307 |
mtr_t* mtr __attribute__((unused))) |
|
308 |
/* in: mini-transaction handle */
|
|
309 |
{
|
|
310 |
ut_ad(mtr->state == MTR_ACTIVE); |
|
311 |
ut_ad(mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_S_FIX) |
|
312 |
|| mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_X_FIX)); |
|
313 |
return(mach_read_from_8(ptr)); |
|
314 |
}
|
|
315 |
||
316 |
#ifdef UNIV_DEBUG
|
|
317 |
/**************************************************************
|
|
318 |
Checks if memo contains the given page. */
|
|
319 |
UNIV_INTERN
|
|
320 |
ibool
|
|
321 |
mtr_memo_contains_page( |
|
322 |
/*===================*/
|
|
323 |
/* out: TRUE if contains */
|
|
324 |
mtr_t* mtr, /* in: mtr */ |
|
325 |
const byte* ptr, /* in: pointer to buffer frame */ |
|
326 |
ulint type) /* in: type of object */ |
|
327 |
{
|
|
641.2.2
by Monty Taylor
InnoDB Plugin 1.0.3 |
328 |
return(mtr_memo_contains(mtr, buf_block_align(ptr), type)); |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
329 |
}
|
330 |
||
331 |
/*************************************************************
|
|
332 |
Prints info of an mtr handle. */
|
|
333 |
UNIV_INTERN
|
|
334 |
void
|
|
335 |
mtr_print( |
|
336 |
/*======*/
|
|
337 |
mtr_t* mtr) /* in: mtr */ |
|
338 |
{
|
|
339 |
fprintf(stderr, |
|
340 |
"Mini-transaction handle: memo size %lu bytes"
|
|
341 |
" log size %lu bytes\n", |
|
342 |
(ulong) dyn_array_get_data_size(&(mtr->memo)), |
|
343 |
(ulong) dyn_array_get_data_size(&(mtr->log))); |
|
344 |
}
|
|
345 |
#endif /* UNIV_DEBUG */ |