~drizzle-trunk/drizzle/development

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 */