~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/******************************************************
2
Mini-transaction log routines
3
4
(c) 1995 Innobase Oy
5
6
Created 12/7/1995 Heikki Tuuri
7
*******************************************************/
8
9
#include "mtr0log.h"
10
11
#ifdef UNIV_NONINL
12
#include "mtr0log.ic"
13
#endif
14
15
#include "buf0buf.h"
16
#include "dict0boot.h"
17
#include "log0recv.h"
18
#include "page0page.h"
19
20
/************************************************************
21
Catenates n bytes to the mtr log. */
22
23
void
24
mlog_catenate_string(
25
/*=================*/
26
	mtr_t*		mtr,	/* in: mtr */
27
	const byte*	str,	/* in: string to write */
28
	ulint		len)	/* in: string length */
29
{
30
	dyn_array_t*	mlog;
31
32
	if (mtr_get_log_mode(mtr) == MTR_LOG_NONE) {
33
34
		return;
35
	}
36
37
	mlog = &(mtr->log);
38
39
	dyn_push_string(mlog, str, len);
40
}
41
42
/************************************************************
43
Writes the initial part of a log record consisting of one-byte item
44
type and four-byte space and page numbers. Also pushes info
45
to the mtr memo that a buffer page has been modified. */
46
47
void
48
mlog_write_initial_log_record(
49
/*==========================*/
50
	byte*	ptr,	/* in: pointer to (inside) a buffer frame holding the
51
			file page where modification is made */
52
	byte	type,	/* in: log item type: MLOG_1BYTE, ... */
53
	mtr_t*	mtr)	/* in: mini-transaction handle */
54
{
55
	byte*	log_ptr;
56
57
	ut_ad(type <= MLOG_BIGGEST_TYPE);
58
	ut_ad(type > MLOG_8BYTES);
59
60
	if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) {
61
		fprintf(stderr,
62
			"InnoDB: Error: trying to write to"
63
			" a stray memory location %p\n", (void*) ptr);
64
		ut_error;
65
	}
66
67
	log_ptr = mlog_open(mtr, 11);
68
69
	/* If no logging is requested, we may return now */
70
	if (log_ptr == NULL) {
71
72
		return;
73
	}
74
75
	log_ptr = mlog_write_initial_log_record_fast(ptr, type, log_ptr, mtr);
76
77
	mlog_close(mtr, log_ptr);
78
}
79
80
/************************************************************
81
Parses an initial log record written by mlog_write_initial_log_record. */
82
83
byte*
84
mlog_parse_initial_log_record(
85
/*==========================*/
86
			/* out: parsed record end, NULL if not a complete
87
			record */
88
	byte*	ptr,	/* in: buffer */
89
	byte*	end_ptr,/* in: buffer end */
90
	byte*	type,	/* out: log record type: MLOG_1BYTE, ... */
91
	ulint*	space,	/* out: space id */
92
	ulint*	page_no)/* out: page number */
93
{
94
	if (end_ptr < ptr + 1) {
95
96
		return(NULL);
97
	}
98
99
	*type = (byte)((ulint)*ptr & ~MLOG_SINGLE_REC_FLAG);
100
	ut_ad(*type <= MLOG_BIGGEST_TYPE);
101
102
	ptr++;
103
104
	if (end_ptr < ptr + 2) {
105
106
		return(NULL);
107
	}
108
109
	ptr = mach_parse_compressed(ptr, end_ptr, space);
110
111
	if (ptr == NULL) {
112
113
		return(NULL);
114
	}
115
116
	ptr = mach_parse_compressed(ptr, end_ptr, page_no);
117
118
	return(ptr);
119
}
120
121
/************************************************************
122
Parses a log record written by mlog_write_ulint or mlog_write_dulint. */
123
124
byte*
125
mlog_parse_nbytes(
126
/*==============*/
127
			/* out: parsed record end, NULL if not a complete
128
			record or a corrupt record */
129
	ulint	type,	/* in: log record type: MLOG_1BYTE, ... */
130
	byte*	ptr,	/* in: buffer */
131
	byte*	end_ptr,/* in: buffer end */
132
	byte*	page)	/* in: page where to apply the log record, or NULL */
133
{
134
	ulint	offset;
135
	ulint	val;
136
	dulint	dval;
137
138
	ut_a(type <= MLOG_8BYTES);
139
140
	if (end_ptr < ptr + 2) {
141
142
		return(NULL);
143
	}
144
145
	offset = mach_read_from_2(ptr);
146
	ptr += 2;
147
148
	if (offset >= UNIV_PAGE_SIZE) {
149
		recv_sys->found_corrupt_log = TRUE;
150
151
		return(NULL);
152
	}
153
154
	if (type == MLOG_8BYTES) {
155
		ptr = mach_dulint_parse_compressed(ptr, end_ptr, &dval);
156
157
		if (ptr == NULL) {
158
159
			return(NULL);
160
		}
161
162
		if (page) {
163
			mach_write_to_8(page + offset, dval);
164
		}
165
166
		return(ptr);
167
	}
168
169
	ptr = mach_parse_compressed(ptr, end_ptr, &val);
170
171
	if (ptr == NULL) {
172
173
		return(NULL);
174
	}
175
176
	if (type == MLOG_1BYTE) {
177
		if (val > 0xFFUL) {
178
			recv_sys->found_corrupt_log = TRUE;
179
180
			return(NULL);
181
		}
182
	} else if (type == MLOG_2BYTES) {
183
		if (val > 0xFFFFUL) {
184
			recv_sys->found_corrupt_log = TRUE;
185
186
			return(NULL);
187
		}
188
	} else {
189
		if (type != MLOG_4BYTES) {
190
			recv_sys->found_corrupt_log = TRUE;
191
192
			return(NULL);
193
		}
194
	}
195
196
	if (page) {
197
		if (type == MLOG_1BYTE) {
198
			mach_write_to_1(page + offset, val);
199
		} else if (type == MLOG_2BYTES) {
200
			mach_write_to_2(page + offset, val);
201
		} else {
202
			ut_a(type == MLOG_4BYTES);
203
			mach_write_to_4(page + offset, val);
204
		}
205
	}
206
207
	return(ptr);
208
}
209
210
/************************************************************
211
Writes 1 - 4 bytes to a file page buffered in the buffer pool.
212
Writes the corresponding log record to the mini-transaction log. */
213
214
void
215
mlog_write_ulint(
216
/*=============*/
217
	byte*	ptr,	/* in: pointer where to write */
218
	ulint	val,	/* in: value to write */
219
	byte	type,	/* in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */
220
	mtr_t*	mtr)	/* in: mini-transaction handle */
221
{
222
	byte*	log_ptr;
223
224
	if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) {
225
		fprintf(stderr,
226
			"InnoDB: Error: trying to write to"
227
			" a stray memory location %p\n", (void*) ptr);
228
		ut_error;
229
	}
230
231
	if (type == MLOG_1BYTE) {
232
		mach_write_to_1(ptr, val);
233
	} else if (type == MLOG_2BYTES) {
234
		mach_write_to_2(ptr, val);
235
	} else {
236
		ut_ad(type == MLOG_4BYTES);
237
		mach_write_to_4(ptr, val);
238
	}
239
240
	log_ptr = mlog_open(mtr, 11 + 2 + 5);
241
242
	/* If no logging is requested, we may return now */
243
	if (log_ptr == NULL) {
244
245
		return;
246
	}
247
248
	log_ptr = mlog_write_initial_log_record_fast(ptr, type, log_ptr, mtr);
249
250
	mach_write_to_2(log_ptr, ptr - buf_frame_align(ptr));
251
	log_ptr += 2;
252
253
	log_ptr += mach_write_compressed(log_ptr, val);
254
255
	mlog_close(mtr, log_ptr);
256
}
257
258
/************************************************************
259
Writes 8 bytes to a file page buffered in the buffer pool.
260
Writes the corresponding log record to the mini-transaction log. */
261
262
void
263
mlog_write_dulint(
264
/*==============*/
265
	byte*	ptr,	/* in: pointer where to write */
266
	dulint	val,	/* in: value to write */
267
	mtr_t*	mtr)	/* in: mini-transaction handle */
268
{
269
	byte*	log_ptr;
270
271
	if (UNIV_UNLIKELY(ptr < buf_pool->frame_zero)
272
	    || UNIV_UNLIKELY(ptr >= buf_pool->high_end)) {
273
		fprintf(stderr,
274
			"InnoDB: Error: trying to write to"
275
			" a stray memory location %p\n", (void*) ptr);
276
		ut_error;
277
	}
278
279
	ut_ad(ptr && mtr);
280
281
	mach_write_to_8(ptr, val);
282
283
	log_ptr = mlog_open(mtr, 11 + 2 + 9);
284
285
	/* If no logging is requested, we may return now */
286
	if (log_ptr == NULL) {
287
288
		return;
289
	}
290
291
	log_ptr = mlog_write_initial_log_record_fast(ptr, MLOG_8BYTES,
292
						     log_ptr, mtr);
293
294
	mach_write_to_2(log_ptr, ptr - buf_frame_align(ptr));
295
	log_ptr += 2;
296
297
	log_ptr += mach_dulint_write_compressed(log_ptr, val);
298
299
	mlog_close(mtr, log_ptr);
300
}
301
302
/************************************************************
303
Writes a string to a file page buffered in the buffer pool. Writes the
304
corresponding log record to the mini-transaction log. */
305
306
void
307
mlog_write_string(
308
/*==============*/
309
	byte*		ptr,	/* in: pointer where to write */
310
	const byte*	str,	/* in: string to write */
311
	ulint		len,	/* in: string length */
312
	mtr_t*		mtr)	/* in: mini-transaction handle */
313
{
314
	byte*	log_ptr;
315
316
	if (UNIV_UNLIKELY(ptr < buf_pool->frame_zero)
317
	    || UNIV_UNLIKELY(ptr >= buf_pool->high_end)) {
318
		fprintf(stderr,
319
			"InnoDB: Error: trying to write to"
320
			" a stray memory location %p\n", (void*) ptr);
321
		ut_error;
322
	}
323
	ut_ad(ptr && mtr);
324
	ut_a(len < UNIV_PAGE_SIZE);
325
326
	ut_memcpy(ptr, str, len);
327
328
	log_ptr = mlog_open(mtr, 30);
329
330
	/* If no logging is requested, we may return now */
331
	if (log_ptr == NULL) {
332
333
		return;
334
	}
335
336
	log_ptr = mlog_write_initial_log_record_fast(ptr, MLOG_WRITE_STRING,
337
						     log_ptr, mtr);
338
	mach_write_to_2(log_ptr, ptr - buf_frame_align(ptr));
339
	log_ptr += 2;
340
341
	mach_write_to_2(log_ptr, len);
342
	log_ptr += 2;
343
344
	mlog_close(mtr, log_ptr);
345
346
	mlog_catenate_string(mtr, str, len);
347
}
348
349
/************************************************************
350
Parses a log record written by mlog_write_string. */
351
352
byte*
353
mlog_parse_string(
354
/*==============*/
355
			/* out: parsed record end, NULL if not a complete
356
			record */
357
	byte*	ptr,	/* in: buffer */
358
	byte*	end_ptr,/* in: buffer end */
359
	byte*	page)	/* in: page where to apply the log record, or NULL */
360
{
361
	ulint	offset;
362
	ulint	len;
363
364
	if (end_ptr < ptr + 4) {
365
366
		return(NULL);
367
	}
368
369
	offset = mach_read_from_2(ptr);
370
	ptr += 2;
371
372
	if (offset >= UNIV_PAGE_SIZE) {
373
		recv_sys->found_corrupt_log = TRUE;
374
375
		return(NULL);
376
	}
377
378
	len = mach_read_from_2(ptr);
379
	ptr += 2;
380
381
	ut_a(len + offset < UNIV_PAGE_SIZE);
382
383
	if (end_ptr < ptr + len) {
384
385
		return(NULL);
386
	}
387
388
	if (page) {
389
		ut_memcpy(page + offset, ptr, len);
390
	}
391
392
	return(ptr + len);
393
}
394
395
/************************************************************
396
Opens a buffer for mlog, writes the initial log record and,
397
if needed, the field lengths of an index. */
398
399
byte*
400
mlog_open_and_write_index(
401
/*======================*/
402
				/* out: buffer, NULL if log mode
403
				MTR_LOG_NONE */
404
	mtr_t*		mtr,	/* in: mtr */
405
	byte*		rec,	/* in: index record or page */
406
	dict_index_t*	index,	/* in: record descriptor */
407
	byte		type,	/* in: log item type */
408
	ulint		size)	/* in: requested buffer size in bytes
409
				(if 0, calls mlog_close() and returns NULL) */
410
{
411
	byte*		log_ptr;
412
	const byte*	log_start;
413
	const byte*	log_end;
414
415
	ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
416
417
	if (!page_rec_is_comp(rec)) {
418
		log_start = log_ptr = mlog_open(mtr, 11 + size);
419
		if (!log_ptr) {
420
			return(NULL); /* logging is disabled */
421
		}
422
		log_ptr = mlog_write_initial_log_record_fast(rec, type,
423
							     log_ptr, mtr);
424
		log_end = log_ptr + 11 + size;
425
	} else {
426
		ulint	i;
427
		ulint	n	= dict_index_get_n_fields(index);
428
		/* total size needed */
429
		ulint	total	= 11 + size + (n + 2) * 2;
430
		ulint	alloc	= total;
431
		/* allocate at most DYN_ARRAY_DATA_SIZE at a time */
432
		if (alloc > DYN_ARRAY_DATA_SIZE) {
433
			alloc = DYN_ARRAY_DATA_SIZE;
434
		}
435
		log_start = log_ptr = mlog_open(mtr, alloc);
436
		if (!log_ptr) {
437
			return(NULL); /* logging is disabled */
438
		}
439
		log_end = log_ptr + alloc;
440
		log_ptr = mlog_write_initial_log_record_fast(rec, type,
441
							     log_ptr, mtr);
442
		mach_write_to_2(log_ptr, n);
443
		log_ptr += 2;
444
		mach_write_to_2(log_ptr,
445
				dict_index_get_n_unique_in_tree(index));
446
		log_ptr += 2;
447
		for (i = 0; i < n; i++) {
448
			dict_field_t*		field;
449
			const dict_col_t*	col;
450
			ulint			len;
451
452
			field = dict_index_get_nth_field(index, i);
453
			col = dict_field_get_col(field);
454
			len = field->fixed_len;
455
			ut_ad(len < 0x7fff);
456
			if (len == 0
457
			    && (col->len > 255 || col->mtype == DATA_BLOB)) {
458
				/* variable-length field
459
				with maximum length > 255 */
460
				len = 0x7fff;
461
			}
462
			if (col->prtype & DATA_NOT_NULL) {
463
				len |= 0x8000;
464
			}
465
			if (log_ptr + 2 > log_end) {
466
				mlog_close(mtr, log_ptr);
467
				ut_a(total > (ulint) (log_ptr - log_start));
468
				total -= log_ptr - log_start;
469
				alloc = total;
470
				if (alloc > DYN_ARRAY_DATA_SIZE) {
471
					alloc = DYN_ARRAY_DATA_SIZE;
472
				}
473
				log_start = log_ptr = mlog_open(mtr, alloc);
474
				if (!log_ptr) {
475
					return(NULL); /* logging is disabled */
476
				}
477
				log_end = log_ptr + alloc;
478
			}
479
			mach_write_to_2(log_ptr, len);
480
			log_ptr += 2;
481
		}
482
	}
483
	if (size == 0) {
484
		mlog_close(mtr, log_ptr);
485
		log_ptr = NULL;
486
	} else if (log_ptr + size > log_end) {
487
		mlog_close(mtr, log_ptr);
488
		log_ptr = mlog_open(mtr, size);
489
	}
490
	return(log_ptr);
491
}
492
493
/************************************************************
494
Parses a log record written by mlog_open_and_write_index. */
495
496
byte*
497
mlog_parse_index(
498
/*=============*/
499
				/* out: parsed record end,
500
				NULL if not a complete record */
501
	byte*		ptr,	/* in: buffer */
502
	byte*		end_ptr,/* in: buffer end */
503
				/* out: new value of log_ptr */
504
	ibool		comp,	/* in: TRUE=compact record format */
505
	dict_index_t**	index)	/* out, own: dummy index */
506
{
507
	ulint		i, n, n_uniq;
508
	dict_table_t*	table;
509
	dict_index_t*	ind;
510
511
	ut_ad(comp == FALSE || comp == TRUE);
512
513
	if (comp) {
514
		if (end_ptr < ptr + 4) {
515
			return(NULL);
516
		}
517
		n = mach_read_from_2(ptr);
518
		ptr += 2;
519
		n_uniq = mach_read_from_2(ptr);
520
		ptr += 2;
521
		ut_ad(n_uniq <= n);
522
		if (end_ptr < ptr + n * 2) {
523
			return(NULL);
524
		}
525
	} else {
526
		n = n_uniq = 1;
527
	}
528
	table = dict_mem_table_create("LOG_DUMMY", DICT_HDR_SPACE, n,
529
				      comp ? DICT_TF_COMPACT : 0);
530
	ind = dict_mem_index_create("LOG_DUMMY", "LOG_DUMMY",
531
				    DICT_HDR_SPACE, 0, n);
532
	ind->table = table;
533
	ind->n_uniq = (unsigned int) n_uniq;
534
	if (n_uniq != n) {
535
		ut_a(n_uniq + DATA_ROLL_PTR <= n);
536
		ind->type = DICT_CLUSTERED;
537
	}
538
	if (comp) {
539
		for (i = 0; i < n; i++) {
540
			ulint	len = mach_read_from_2(ptr);
541
			ptr += 2;
542
			/* The high-order bit of len is the NOT NULL flag;
543
			the rest is 0 or 0x7fff for variable-length fields,
544
			and 1..0x7ffe for fixed-length fields. */
545
			dict_mem_table_add_col(
546
				table, NULL, NULL,
547
				((len + 1) & 0x7fff) <= 1
548
				? DATA_BINARY : DATA_FIXBINARY,
549
				len & 0x8000 ? DATA_NOT_NULL : 0,
550
				len & 0x7fff);
551
552
			dict_index_add_col(ind, table, (dict_col_t*)
553
					   dict_table_get_nth_col(table, i),
554
					   0);
555
		}
556
		dict_table_add_system_columns(table, table->heap);
557
		if (n_uniq != n) {
558
			/* Identify DB_TRX_ID and DB_ROLL_PTR in the index. */
559
			ut_a(DATA_TRX_ID_LEN
560
			     == dict_index_get_nth_col(ind, DATA_TRX_ID - 1
561
						       + n_uniq)->len);
562
			ut_a(DATA_ROLL_PTR_LEN
563
			     == dict_index_get_nth_col(ind, DATA_ROLL_PTR - 1
564
						       + n_uniq)->len);
565
			ind->fields[DATA_TRX_ID - 1 + n_uniq].col
566
				= &table->cols[n + DATA_TRX_ID];
567
			ind->fields[DATA_ROLL_PTR - 1 + n_uniq].col
568
				= &table->cols[n + DATA_ROLL_PTR];
569
		}
570
	}
571
	/* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
572
	ind->cached = TRUE;
573
	*index = ind;
574
	return(ptr);
575
}