~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/mtr/mtr0log.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}