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 log routines
23
Created 12/7/1995 Heikki Tuuri
24
*******************************************************/
33
#include "dict0dict.h"
35
#include "page0page.h"
37
#ifndef UNIV_HOTBACKUP
38
# include "dict0boot.h"
40
/********************************************************//**
41
Catenates n bytes to the mtr log. */
46
mtr_t* mtr, /*!< in: mtr */
47
const byte* str, /*!< in: string to write */
48
ulint len) /*!< in: string length */
52
if (mtr_get_log_mode(mtr) == MTR_LOG_NONE) {
59
dyn_push_string(mlog, str, len);
62
/********************************************************//**
63
Writes the initial part of a log record consisting of one-byte item
64
type and four-byte space and page numbers. Also pushes info
65
to the mtr memo that a buffer page has been modified. */
68
mlog_write_initial_log_record(
69
/*==========================*/
70
const byte* ptr, /*!< in: pointer to (inside) a buffer
71
frame holding the file page where
72
modification is made */
73
byte type, /*!< in: log item type: MLOG_1BYTE, ... */
74
mtr_t* mtr) /*!< in: mini-transaction handle */
78
ut_ad(type <= MLOG_BIGGEST_TYPE);
79
ut_ad(type > MLOG_8BYTES);
81
log_ptr = mlog_open(mtr, 11);
83
/* If no logging is requested, we may return now */
84
if (log_ptr == NULL) {
89
log_ptr = mlog_write_initial_log_record_fast(ptr, type, log_ptr, mtr);
91
mlog_close(mtr, log_ptr);
93
#endif /* !UNIV_HOTBACKUP */
95
/********************************************************//**
96
Parses an initial log record written by mlog_write_initial_log_record.
97
@return parsed record end, NULL if not a complete record */
100
mlog_parse_initial_log_record(
101
/*==========================*/
102
byte* ptr, /*!< in: buffer */
103
byte* end_ptr,/*!< in: buffer end */
104
byte* type, /*!< out: log record type: MLOG_1BYTE, ... */
105
ulint* space, /*!< out: space id */
106
ulint* page_no)/*!< out: page number */
108
if (end_ptr < ptr + 1) {
113
*type = (byte)((ulint)*ptr & ~MLOG_SINGLE_REC_FLAG);
114
ut_ad(*type <= MLOG_BIGGEST_TYPE);
118
if (end_ptr < ptr + 2) {
123
ptr = mach_parse_compressed(ptr, end_ptr, space);
130
ptr = mach_parse_compressed(ptr, end_ptr, page_no);
135
/********************************************************//**
136
Parses a log record written by mlog_write_ulint or mlog_write_ull.
137
@return parsed record end, NULL if not a complete record or a corrupt record */
142
ulint type, /*!< in: log record type: MLOG_1BYTE, ... */
143
byte* ptr, /*!< in: buffer */
144
byte* end_ptr,/*!< in: buffer end */
145
byte* page, /*!< in: page where to apply the log record, or NULL */
146
void* page_zip)/*!< in/out: compressed page, or NULL */
152
ut_a(type <= MLOG_8BYTES);
153
ut_a(!page || !page_zip || fil_page_get_type(page) != FIL_PAGE_INDEX);
155
if (end_ptr < ptr + 2) {
160
offset = mach_read_from_2(ptr);
163
if (offset >= UNIV_PAGE_SIZE) {
164
recv_sys->found_corrupt_log = TRUE;
169
if (type == MLOG_8BYTES) {
170
ptr = mach_ull_parse_compressed(ptr, end_ptr, &dval);
178
if (UNIV_LIKELY_NULL(page_zip)) {
180
(((page_zip_des_t*) page_zip)->data
183
mach_write_to_8(page + offset, dval);
189
ptr = mach_parse_compressed(ptr, end_ptr, &val);
198
if (UNIV_UNLIKELY(val > 0xFFUL)) {
202
if (UNIV_LIKELY_NULL(page_zip)) {
204
(((page_zip_des_t*) page_zip)->data
207
mach_write_to_1(page + offset, val);
211
if (UNIV_UNLIKELY(val > 0xFFFFUL)) {
215
if (UNIV_LIKELY_NULL(page_zip)) {
217
(((page_zip_des_t*) page_zip)->data
220
mach_write_to_2(page + offset, val);
225
if (UNIV_LIKELY_NULL(page_zip)) {
227
(((page_zip_des_t*) page_zip)->data
230
mach_write_to_4(page + offset, val);
235
recv_sys->found_corrupt_log = TRUE;
242
/********************************************************//**
243
Writes 1 - 4 bytes to a file page buffered in the buffer pool.
244
Writes the corresponding log record to the mini-transaction log. */
249
byte* ptr, /*!< in: pointer where to write */
250
ulint val, /*!< in: value to write */
251
byte type, /*!< in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */
252
mtr_t* mtr) /*!< in: mini-transaction handle */
258
mach_write_to_1(ptr, val);
261
mach_write_to_2(ptr, val);
264
mach_write_to_4(ptr, val);
270
log_ptr = mlog_open(mtr, 11 + 2 + 5);
272
/* If no logging is requested, we may return now */
273
if (log_ptr == NULL) {
278
log_ptr = mlog_write_initial_log_record_fast(ptr, type, log_ptr, mtr);
280
mach_write_to_2(log_ptr, page_offset(ptr));
283
log_ptr += mach_write_compressed(log_ptr, val);
285
mlog_close(mtr, log_ptr);
288
/********************************************************//**
289
Writes 8 bytes to a file page buffered in the buffer pool.
290
Writes the corresponding log record to the mini-transaction log. */
295
byte* ptr, /*!< in: pointer where to write */
296
ib_uint64_t val, /*!< in: value to write */
297
mtr_t* mtr) /*!< in: mini-transaction handle */
303
mach_write_to_8(ptr, val);
305
log_ptr = mlog_open(mtr, 11 + 2 + 9);
307
/* If no logging is requested, we may return now */
308
if (log_ptr == NULL) {
313
log_ptr = mlog_write_initial_log_record_fast(ptr, MLOG_8BYTES,
316
mach_write_to_2(log_ptr, page_offset(ptr));
319
log_ptr += mach_ull_write_compressed(log_ptr, val);
321
mlog_close(mtr, log_ptr);
324
#ifndef UNIV_HOTBACKUP
325
/********************************************************//**
326
Writes a string to a file page buffered in the buffer pool. Writes the
327
corresponding log record to the mini-transaction log. */
332
byte* ptr, /*!< in: pointer where to write */
333
const byte* str, /*!< in: string to write */
334
ulint len, /*!< in: string length */
335
mtr_t* mtr) /*!< in: mini-transaction handle */
338
ut_a(len < UNIV_PAGE_SIZE);
340
memcpy(ptr, str, len);
342
mlog_log_string(ptr, len, mtr);
345
/********************************************************//**
346
Logs a write of a string to a file page buffered in the buffer pool.
347
Writes the corresponding log record to the mini-transaction log. */
352
byte* ptr, /*!< in: pointer written to */
353
ulint len, /*!< in: string length */
354
mtr_t* mtr) /*!< in: mini-transaction handle */
359
ut_ad(len <= UNIV_PAGE_SIZE);
361
log_ptr = mlog_open(mtr, 30);
363
/* If no logging is requested, we may return now */
364
if (log_ptr == NULL) {
369
log_ptr = mlog_write_initial_log_record_fast(ptr, MLOG_WRITE_STRING,
371
mach_write_to_2(log_ptr, page_offset(ptr));
374
mach_write_to_2(log_ptr, len);
377
mlog_close(mtr, log_ptr);
379
mlog_catenate_string(mtr, ptr, len);
381
#endif /* !UNIV_HOTBACKUP */
383
/********************************************************//**
384
Parses a log record written by mlog_write_string.
385
@return parsed record end, NULL if not a complete record */
390
byte* ptr, /*!< in: buffer */
391
byte* end_ptr,/*!< in: buffer end */
392
byte* page, /*!< in: page where to apply the log record, or NULL */
393
void* page_zip)/*!< in/out: compressed page, or NULL */
398
ut_a(!page || !page_zip || fil_page_get_type(page) != FIL_PAGE_INDEX);
400
if (end_ptr < ptr + 4) {
405
offset = mach_read_from_2(ptr);
407
len = mach_read_from_2(ptr);
410
if (UNIV_UNLIKELY(offset >= UNIV_PAGE_SIZE)
411
|| UNIV_UNLIKELY(len + offset) > UNIV_PAGE_SIZE) {
412
recv_sys->found_corrupt_log = TRUE;
417
if (end_ptr < ptr + len) {
423
if (UNIV_LIKELY_NULL(page_zip)) {
424
memcpy(((page_zip_des_t*) page_zip)->data
427
memcpy(page + offset, ptr, len);
433
#ifndef UNIV_HOTBACKUP
434
/********************************************************//**
435
Opens a buffer for mlog, writes the initial log record and,
436
if needed, the field lengths of an index.
437
@return buffer, NULL if log mode MTR_LOG_NONE */
440
mlog_open_and_write_index(
441
/*======================*/
442
mtr_t* mtr, /*!< in: mtr */
443
const byte* rec, /*!< in: index record or page */
444
dict_index_t* index, /*!< in: record descriptor */
445
byte type, /*!< in: log item type */
446
ulint size) /*!< in: requested buffer size in bytes
447
(if 0, calls mlog_close() and returns NULL) */
450
const byte* log_start;
453
ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
455
if (!page_rec_is_comp(rec)) {
456
log_start = log_ptr = mlog_open(mtr, 11 + size);
458
return(NULL); /* logging is disabled */
460
log_ptr = mlog_write_initial_log_record_fast(rec, type,
462
log_end = log_ptr + 11 + size;
465
ulint n = dict_index_get_n_fields(index);
466
/* total size needed */
467
ulint total = 11 + size + (n + 2) * 2;
469
/* allocate at most DYN_ARRAY_DATA_SIZE at a time */
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;
478
log_ptr = mlog_write_initial_log_record_fast(rec, type,
480
mach_write_to_2(log_ptr, n);
482
mach_write_to_2(log_ptr,
483
dict_index_get_n_unique_in_tree(index));
485
for (i = 0; i < n; i++) {
487
const dict_col_t* col;
490
field = dict_index_get_nth_field(index, i);
491
col = dict_field_get_col(field);
492
len = field->fixed_len;
495
&& (col->len > 255 || col->mtype == DATA_BLOB)) {
496
/* variable-length field
497
with maximum length > 255 */
500
if (col->prtype & DATA_NOT_NULL) {
503
if (log_ptr + 2 > log_end) {
504
mlog_close(mtr, log_ptr);
505
ut_a(total > (ulint) (log_ptr - log_start));
506
total -= log_ptr - log_start;
508
if (alloc > DYN_ARRAY_DATA_SIZE) {
509
alloc = DYN_ARRAY_DATA_SIZE;
511
log_start = log_ptr = mlog_open(mtr, alloc);
513
return(NULL); /* logging is disabled */
515
log_end = log_ptr + alloc;
517
mach_write_to_2(log_ptr, len);
522
mlog_close(mtr, log_ptr);
524
} else if (log_ptr + size > log_end) {
525
mlog_close(mtr, log_ptr);
526
log_ptr = mlog_open(mtr, size);
530
#endif /* !UNIV_HOTBACKUP */
532
/********************************************************//**
533
Parses a log record written by mlog_open_and_write_index.
534
@return parsed record end, NULL if not a complete record */
539
byte* ptr, /*!< in: buffer */
540
const byte* end_ptr,/*!< in: buffer end */
541
ibool comp, /*!< in: TRUE=compact record format */
542
dict_index_t** index) /*!< out, own: dummy index */
548
ut_ad(comp == FALSE || comp == TRUE);
551
if (end_ptr < ptr + 4) {
554
n = mach_read_from_2(ptr);
556
n_uniq = mach_read_from_2(ptr);
559
if (end_ptr < ptr + n * 2) {
565
table = dict_mem_table_create("LOG_DUMMY", DICT_HDR_SPACE, n,
566
comp ? DICT_TF_COMPACT : 0);
567
ind = dict_mem_index_create("LOG_DUMMY", "LOG_DUMMY",
568
DICT_HDR_SPACE, 0, n);
570
ind->n_uniq = (unsigned int) n_uniq;
572
ut_a(n_uniq + DATA_ROLL_PTR <= n);
573
ind->type = DICT_CLUSTERED;
576
for (i = 0; i < n; i++) {
577
ulint len = mach_read_from_2(ptr);
579
/* The high-order bit of len is the NOT NULL flag;
580
the rest is 0 or 0x7fff for variable-length fields,
581
and 1..0x7ffe for fixed-length fields. */
582
dict_mem_table_add_col(
584
((len + 1) & 0x7fff) <= 1
585
? DATA_BINARY : DATA_FIXBINARY,
586
len & 0x8000 ? DATA_NOT_NULL : 0,
589
dict_index_add_col(ind, table,
590
dict_table_get_nth_col(table, i),
593
dict_table_add_system_columns(table, table->heap);
595
/* Identify DB_TRX_ID and DB_ROLL_PTR in the index. */
597
== dict_index_get_nth_col(ind, DATA_TRX_ID - 1
599
ut_a(DATA_ROLL_PTR_LEN
600
== dict_index_get_nth_col(ind, DATA_ROLL_PTR - 1
602
ind->fields[DATA_TRX_ID - 1 + n_uniq].col
603
= &table->cols[n + DATA_TRX_ID];
604
ind->fields[DATA_ROLL_PTR - 1 + n_uniq].col
605
= &table->cols[n + DATA_ROLL_PTR];
608
/* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */