1
/******************************************************
2
Mini-transaction log routines
6
Created 12/7/1995 Heikki Tuuri
7
*******************************************************/
16
#include "dict0boot.h"
18
#include "page0page.h"
20
/************************************************************
21
Catenates n bytes to the mtr log. */
26
mtr_t* mtr, /* in: mtr */
27
const byte* str, /* in: string to write */
28
ulint len) /* in: string length */
32
if (mtr_get_log_mode(mtr) == MTR_LOG_NONE) {
39
dyn_push_string(mlog, str, len);
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. */
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 */
57
ut_ad(type <= MLOG_BIGGEST_TYPE);
58
ut_ad(type > MLOG_8BYTES);
60
if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) {
62
"InnoDB: Error: trying to write to"
63
" a stray memory location %p\n", (void*) ptr);
67
log_ptr = mlog_open(mtr, 11);
69
/* If no logging is requested, we may return now */
70
if (log_ptr == NULL) {
75
log_ptr = mlog_write_initial_log_record_fast(ptr, type, log_ptr, mtr);
77
mlog_close(mtr, log_ptr);
80
/************************************************************
81
Parses an initial log record written by mlog_write_initial_log_record. */
84
mlog_parse_initial_log_record(
85
/*==========================*/
86
/* out: parsed record end, NULL if not a complete
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 */
94
if (end_ptr < ptr + 1) {
99
*type = (byte)((ulint)*ptr & ~MLOG_SINGLE_REC_FLAG);
100
ut_ad(*type <= MLOG_BIGGEST_TYPE);
104
if (end_ptr < ptr + 2) {
109
ptr = mach_parse_compressed(ptr, end_ptr, space);
116
ptr = mach_parse_compressed(ptr, end_ptr, page_no);
121
/************************************************************
122
Parses a log record written by mlog_write_ulint or mlog_write_dulint. */
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 */
138
ut_a(type <= MLOG_8BYTES);
140
if (end_ptr < ptr + 2) {
145
offset = mach_read_from_2(ptr);
148
if (offset >= UNIV_PAGE_SIZE) {
149
recv_sys->found_corrupt_log = TRUE;
154
if (type == MLOG_8BYTES) {
155
ptr = mach_dulint_parse_compressed(ptr, end_ptr, &dval);
163
mach_write_to_8(page + offset, dval);
169
ptr = mach_parse_compressed(ptr, end_ptr, &val);
176
if (type == MLOG_1BYTE) {
178
recv_sys->found_corrupt_log = TRUE;
182
} else if (type == MLOG_2BYTES) {
183
if (val > 0xFFFFUL) {
184
recv_sys->found_corrupt_log = TRUE;
189
if (type != MLOG_4BYTES) {
190
recv_sys->found_corrupt_log = TRUE;
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);
202
ut_a(type == MLOG_4BYTES);
203
mach_write_to_4(page + offset, val);
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. */
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 */
224
if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) {
226
"InnoDB: Error: trying to write to"
227
" a stray memory location %p\n", (void*) ptr);
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);
236
ut_ad(type == MLOG_4BYTES);
237
mach_write_to_4(ptr, val);
240
log_ptr = mlog_open(mtr, 11 + 2 + 5);
242
/* If no logging is requested, we may return now */
243
if (log_ptr == NULL) {
248
log_ptr = mlog_write_initial_log_record_fast(ptr, type, log_ptr, mtr);
250
mach_write_to_2(log_ptr, ptr - buf_frame_align(ptr));
253
log_ptr += mach_write_compressed(log_ptr, val);
255
mlog_close(mtr, log_ptr);
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. */
265
byte* ptr, /* in: pointer where to write */
266
dulint val, /* in: value to write */
267
mtr_t* mtr) /* in: mini-transaction handle */
271
if (UNIV_UNLIKELY(ptr < buf_pool->frame_zero)
272
|| UNIV_UNLIKELY(ptr >= buf_pool->high_end)) {
274
"InnoDB: Error: trying to write to"
275
" a stray memory location %p\n", (void*) ptr);
281
mach_write_to_8(ptr, val);
283
log_ptr = mlog_open(mtr, 11 + 2 + 9);
285
/* If no logging is requested, we may return now */
286
if (log_ptr == NULL) {
291
log_ptr = mlog_write_initial_log_record_fast(ptr, MLOG_8BYTES,
294
mach_write_to_2(log_ptr, ptr - buf_frame_align(ptr));
297
log_ptr += mach_dulint_write_compressed(log_ptr, val);
299
mlog_close(mtr, log_ptr);
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. */
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 */
316
if (UNIV_UNLIKELY(ptr < buf_pool->frame_zero)
317
|| UNIV_UNLIKELY(ptr >= buf_pool->high_end)) {
319
"InnoDB: Error: trying to write to"
320
" a stray memory location %p\n", (void*) ptr);
324
ut_a(len < UNIV_PAGE_SIZE);
326
ut_memcpy(ptr, str, len);
328
log_ptr = mlog_open(mtr, 30);
330
/* If no logging is requested, we may return now */
331
if (log_ptr == NULL) {
336
log_ptr = mlog_write_initial_log_record_fast(ptr, MLOG_WRITE_STRING,
338
mach_write_to_2(log_ptr, ptr - buf_frame_align(ptr));
341
mach_write_to_2(log_ptr, len);
344
mlog_close(mtr, log_ptr);
346
mlog_catenate_string(mtr, str, len);
349
/************************************************************
350
Parses a log record written by mlog_write_string. */
355
/* out: parsed record end, NULL if not a complete
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 */
364
if (end_ptr < ptr + 4) {
369
offset = mach_read_from_2(ptr);
372
if (offset >= UNIV_PAGE_SIZE) {
373
recv_sys->found_corrupt_log = TRUE;
378
len = mach_read_from_2(ptr);
381
ut_a(len + offset < UNIV_PAGE_SIZE);
383
if (end_ptr < ptr + len) {
389
ut_memcpy(page + offset, ptr, len);
395
/************************************************************
396
Opens a buffer for mlog, writes the initial log record and,
397
if needed, the field lengths of an index. */
400
mlog_open_and_write_index(
401
/*======================*/
402
/* out: buffer, NULL if log mode
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) */
412
const byte* log_start;
415
ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
417
if (!page_rec_is_comp(rec)) {
418
log_start = log_ptr = mlog_open(mtr, 11 + size);
420
return(NULL); /* logging is disabled */
422
log_ptr = mlog_write_initial_log_record_fast(rec, type,
424
log_end = log_ptr + 11 + size;
427
ulint n = dict_index_get_n_fields(index);
428
/* total size needed */
429
ulint total = 11 + size + (n + 2) * 2;
431
/* allocate at most DYN_ARRAY_DATA_SIZE at a time */
432
if (alloc > DYN_ARRAY_DATA_SIZE) {
433
alloc = DYN_ARRAY_DATA_SIZE;
435
log_start = log_ptr = mlog_open(mtr, alloc);
437
return(NULL); /* logging is disabled */
439
log_end = log_ptr + alloc;
440
log_ptr = mlog_write_initial_log_record_fast(rec, type,
442
mach_write_to_2(log_ptr, n);
444
mach_write_to_2(log_ptr,
445
dict_index_get_n_unique_in_tree(index));
447
for (i = 0; i < n; i++) {
449
const dict_col_t* col;
452
field = dict_index_get_nth_field(index, i);
453
col = dict_field_get_col(field);
454
len = field->fixed_len;
457
&& (col->len > 255 || col->mtype == DATA_BLOB)) {
458
/* variable-length field
459
with maximum length > 255 */
462
if (col->prtype & DATA_NOT_NULL) {
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;
470
if (alloc > DYN_ARRAY_DATA_SIZE) {
471
alloc = DYN_ARRAY_DATA_SIZE;
473
log_start = log_ptr = mlog_open(mtr, alloc);
475
return(NULL); /* logging is disabled */
477
log_end = log_ptr + alloc;
479
mach_write_to_2(log_ptr, len);
484
mlog_close(mtr, log_ptr);
486
} else if (log_ptr + size > log_end) {
487
mlog_close(mtr, log_ptr);
488
log_ptr = mlog_open(mtr, size);
493
/************************************************************
494
Parses a log record written by mlog_open_and_write_index. */
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 */
511
ut_ad(comp == FALSE || comp == TRUE);
514
if (end_ptr < ptr + 4) {
517
n = mach_read_from_2(ptr);
519
n_uniq = mach_read_from_2(ptr);
522
if (end_ptr < ptr + n * 2) {
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);
533
ind->n_uniq = (unsigned int) n_uniq;
535
ut_a(n_uniq + DATA_ROLL_PTR <= n);
536
ind->type = DICT_CLUSTERED;
539
for (i = 0; i < n; i++) {
540
ulint len = mach_read_from_2(ptr);
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(
547
((len + 1) & 0x7fff) <= 1
548
? DATA_BINARY : DATA_FIXBINARY,
549
len & 0x8000 ? DATA_NOT_NULL : 0,
552
dict_index_add_col(ind, table, (dict_col_t*)
553
dict_table_get_nth_col(table, i),
556
dict_table_add_system_columns(table, table->heap);
558
/* Identify DB_TRX_ID and DB_ROLL_PTR in the index. */
560
== dict_index_get_nth_col(ind, DATA_TRX_ID - 1
562
ut_a(DATA_ROLL_PTR_LEN
563
== dict_index_get_nth_col(ind, DATA_ROLL_PTR - 1
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];
571
/* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */