~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/page/page0cur.c

  • Committer: Brian Aker
  • Date: 2008-11-04 15:39:09 UTC
  • mfrom: (575.1.2 devel)
  • Revision ID: brian@tangent.org-20081104153909-c72hn65udxs1ccal
Merge of Monty's work

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
#include "page0cur.ic"
12
12
#endif
13
13
 
 
14
#include "page0zip.h"
14
15
#include "rem0cmp.h"
15
16
#include "mtr0log.h"
16
17
#include "log0recv.h"
20
21
 
21
22
#ifdef PAGE_CUR_ADAPT
22
23
# ifdef UNIV_SEARCH_PERF_STAT
23
 
ulint   page_cur_short_succ     = 0;
 
24
static ulint    page_cur_short_succ     = 0;
24
25
# endif /* UNIV_SEARCH_PERF_STAT */
25
26
 
26
27
/********************************************************************
29
30
ibool
30
31
page_cur_try_search_shortcut(
31
32
/*=========================*/
32
 
                                /* out: TRUE on success */
33
 
        page_t*         page,   /* in: index page */
34
 
        dict_index_t*   index,  /* in: record descriptor */
35
 
        dtuple_t*       tuple,  /* in: data tuple */
36
 
        ulint*          iup_matched_fields,
37
 
                                /* in/out: already matched fields in upper
38
 
                                limit record */
39
 
        ulint*          iup_matched_bytes,
40
 
                                /* in/out: already matched bytes in a field
41
 
                                not yet completely matched */
42
 
        ulint*          ilow_matched_fields,
43
 
                                /* in/out: already matched fields in lower
44
 
                                limit record */
45
 
        ulint*          ilow_matched_bytes,
46
 
                                /* in/out: already matched bytes in a field
47
 
                                not yet completely matched */
48
 
        page_cur_t*     cursor) /* out: page cursor */
 
33
                                        /* out: TRUE on success */
 
34
        const buf_block_t*      block,  /* in: index page */
 
35
        const dict_index_t*     index,  /* in: record descriptor */
 
36
        const dtuple_t*         tuple,  /* in: data tuple */
 
37
        ulint*                  iup_matched_fields,
 
38
                                        /* in/out: already matched
 
39
                                        fields in upper limit record */
 
40
        ulint*                  iup_matched_bytes,
 
41
                                        /* in/out: already matched
 
42
                                        bytes in a field not yet
 
43
                                        completely matched */
 
44
        ulint*                  ilow_matched_fields,
 
45
                                        /* in/out: already matched
 
46
                                        fields in lower limit record */
 
47
        ulint*                  ilow_matched_bytes,
 
48
                                        /* in/out: already matched
 
49
                                        bytes in a field not yet
 
50
                                        completely matched */
 
51
        page_cur_t*             cursor) /* out: page cursor */
49
52
{
50
 
        rec_t*  rec;
51
 
        rec_t*  next_rec;
52
 
        ulint   low_match;
53
 
        ulint   low_bytes;
54
 
        ulint   up_match;
55
 
        ulint   up_bytes;
 
53
        const rec_t*    rec;
 
54
        const rec_t*    next_rec;
 
55
        ulint           low_match;
 
56
        ulint           low_bytes;
 
57
        ulint           up_match;
 
58
        ulint           up_bytes;
56
59
#ifdef UNIV_SEARCH_DEBUG
57
 
        page_cur_t cursor2;
 
60
        page_cur_t      cursor2;
58
61
#endif
59
62
        ibool           success         = FALSE;
 
63
        const page_t*   page            = buf_block_get_frame(block);
60
64
        mem_heap_t*     heap            = NULL;
61
65
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
62
66
        ulint*          offsets         = offsets_;
63
 
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
 
67
        rec_offs_init(offsets_);
64
68
 
65
69
        ut_ad(dtuple_check_typed(tuple));
66
70
 
83
87
                goto exit_func;
84
88
        }
85
89
 
86
 
        next_rec = page_rec_get_next(rec);
 
90
        next_rec = page_rec_get_next_const(rec);
87
91
        offsets = rec_get_offsets(next_rec, index, offsets,
88
92
                                  dtuple_get_n_fields(tuple), &heap);
89
93
 
92
96
                goto exit_func;
93
97
        }
94
98
 
95
 
        cursor->rec = rec;
 
99
        page_cur_position(rec, block, cursor);
96
100
 
97
101
#ifdef UNIV_SEARCH_DEBUG
98
 
        page_cur_search_with_match(page, index, tuple, PAGE_CUR_DBG,
 
102
        page_cur_search_with_match(block, index, tuple, PAGE_CUR_DBG,
99
103
                                   iup_matched_fields,
100
104
                                   iup_matched_bytes,
101
105
                                   ilow_matched_fields,
103
107
                                   &cursor2);
104
108
        ut_a(cursor2.rec == cursor->rec);
105
109
 
106
 
        if (next_rec != page_get_supremum_rec(page)) {
 
110
        if (!page_rec_is_supremum(next_rec)) {
107
111
 
108
112
                ut_a(*iup_matched_fields == up_match);
109
113
                ut_a(*iup_matched_bytes == up_bytes);
145
149
/*=======================*/
146
150
                                /* out: TRUE if rec field
147
151
                                extends tuple field */
148
 
        dtuple_t*       tuple,  /* in: data tuple */
149
 
        rec_t*          rec,    /* in: record */
 
152
        const dtuple_t* tuple,  /* in: data tuple */
 
153
        const rec_t*    rec,    /* in: record */
150
154
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
151
155
        ulint           n)      /* in: compare nth field */
152
156
{
153
 
        dtype_t* type;
154
 
        dfield_t* dfield;
155
 
        byte*     rec_f;
156
 
        ulint     rec_f_len;
 
157
        const dtype_t*  type;
 
158
        const dfield_t* dfield;
 
159
        const byte*     rec_f;
 
160
        ulint           rec_f_len;
157
161
 
158
162
        ut_ad(rec_offs_validate(rec, NULL, offsets));
159
163
        dfield = dtuple_get_nth_field(tuple, n);
173
177
                if (dfield_get_len(dfield) != UNIV_SQL_NULL
174
178
                    && rec_f_len != UNIV_SQL_NULL
175
179
                    && rec_f_len >= dfield_get_len(dfield)
176
 
                    && !cmp_data_data_slow(type,
 
180
                    && !cmp_data_data_slow(type->mtype, type->prtype,
177
181
                                           dfield_get_data(dfield),
178
182
                                           dfield_get_len(dfield),
179
183
                                           rec_f, dfield_get_len(dfield))) {
188
192
 
189
193
/********************************************************************
190
194
Searches the right position for a page cursor. */
191
 
 
 
195
UNIV_INTERN
192
196
void
193
197
page_cur_search_with_match(
194
198
/*=======================*/
195
 
        page_t*         page,   /* in: index page */
196
 
        dict_index_t*   index,  /* in: record descriptor */
197
 
        dtuple_t*       tuple,  /* in: data tuple */
198
 
        ulint           mode,   /* in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G,
199
 
                                or PAGE_CUR_GE */
200
 
        ulint*          iup_matched_fields,
201
 
                                /* in/out: already matched fields in upper
202
 
                                limit record */
203
 
        ulint*          iup_matched_bytes,
204
 
                                /* in/out: already matched bytes in a field
205
 
                                not yet completely matched */
206
 
        ulint*          ilow_matched_fields,
207
 
                                /* in/out: already matched fields in lower
208
 
                                limit record */
209
 
        ulint*          ilow_matched_bytes,
210
 
                                /* in/out: already matched bytes in a field
211
 
                                not yet completely matched */
212
 
        page_cur_t*     cursor) /* out: page cursor */
 
199
        const buf_block_t*      block,  /* in: buffer block */
 
200
        const dict_index_t*     index,  /* in: record descriptor */
 
201
        const dtuple_t*         tuple,  /* in: data tuple */
 
202
        ulint                   mode,   /* in: PAGE_CUR_L,
 
203
                                        PAGE_CUR_LE, PAGE_CUR_G, or
 
204
                                        PAGE_CUR_GE */
 
205
        ulint*                  iup_matched_fields,
 
206
                                        /* in/out: already matched
 
207
                                        fields in upper limit record */
 
208
        ulint*                  iup_matched_bytes,
 
209
                                        /* in/out: already matched
 
210
                                        bytes in a field not yet
 
211
                                        completely matched */
 
212
        ulint*                  ilow_matched_fields,
 
213
                                        /* in/out: already matched
 
214
                                        fields in lower limit record */
 
215
        ulint*                  ilow_matched_bytes,
 
216
                                        /* in/out: already matched
 
217
                                        bytes in a field not yet
 
218
                                        completely matched */
 
219
        page_cur_t*             cursor) /* out: page cursor */
213
220
{
214
 
        ulint   up;
215
 
        ulint   low;
216
 
        ulint   mid;
217
 
        page_dir_slot_t* slot;
218
 
        rec_t*  up_rec;
219
 
        rec_t*  low_rec;
220
 
        rec_t*  mid_rec;
221
 
        ulint   up_matched_fields;
222
 
        ulint   up_matched_bytes;
223
 
        ulint   low_matched_fields;
224
 
        ulint   low_matched_bytes;
225
 
        ulint   cur_matched_fields;
226
 
        ulint   cur_matched_bytes;
227
 
        int     cmp;
 
221
        ulint           up;
 
222
        ulint           low;
 
223
        ulint           mid;
 
224
        const page_t*   page;
 
225
        const page_dir_slot_t* slot;
 
226
        const rec_t*    up_rec;
 
227
        const rec_t*    low_rec;
 
228
        const rec_t*    mid_rec;
 
229
        ulint           up_matched_fields;
 
230
        ulint           up_matched_bytes;
 
231
        ulint           low_matched_fields;
 
232
        ulint           low_matched_bytes;
 
233
        ulint           cur_matched_fields;
 
234
        ulint           cur_matched_bytes;
 
235
        int             cmp;
228
236
#ifdef UNIV_SEARCH_DEBUG
229
 
        int     dbg_cmp;
230
 
        ulint   dbg_matched_fields;
231
 
        ulint   dbg_matched_bytes;
 
237
        int             dbg_cmp;
 
238
        ulint           dbg_matched_fields;
 
239
        ulint           dbg_matched_bytes;
232
240
#endif
 
241
#ifdef UNIV_ZIP_DEBUG
 
242
        const page_zip_des_t*   page_zip = buf_block_get_page_zip(block);
 
243
#endif /* UNIV_ZIP_DEBUG */
233
244
        mem_heap_t*     heap            = NULL;
234
245
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
235
246
        ulint*          offsets         = offsets_;
236
 
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
 
247
        rec_offs_init(offsets_);
237
248
 
238
 
        ut_ad(page && tuple && iup_matched_fields && iup_matched_bytes
 
249
        ut_ad(block && tuple && iup_matched_fields && iup_matched_bytes
239
250
              && ilow_matched_fields && ilow_matched_bytes && cursor);
240
251
        ut_ad(dtuple_validate(tuple));
241
 
        ut_ad(dtuple_check_typed(tuple));
242
252
#ifdef UNIV_DEBUG
243
253
# ifdef PAGE_CUR_DBG
244
254
        if (mode != PAGE_CUR_DBG)
249
259
                        ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE
250
260
                              || mode == PAGE_CUR_G || mode == PAGE_CUR_GE);
251
261
#endif /* UNIV_DEBUG */
 
262
        page = buf_block_get_frame(block);
 
263
#ifdef UNIV_ZIP_DEBUG
 
264
        ut_a(!page_zip || page_zip_validate(page_zip, page));
 
265
#endif /* UNIV_ZIP_DEBUG */
252
266
 
253
267
        page_check_dir(page);
254
268
 
255
269
#ifdef PAGE_CUR_ADAPT
256
 
        if ((page_header_get_field(page, PAGE_LEVEL) == 0)
 
270
        if (page_is_leaf(page)
257
271
            && (mode == PAGE_CUR_LE)
258
272
            && (page_header_get_field(page, PAGE_N_DIRECTION) > 3)
259
273
            && (page_header_get_ptr(page, PAGE_LAST_INSERT))
260
274
            && (page_header_get_field(page, PAGE_DIRECTION) == PAGE_RIGHT)) {
261
275
 
262
276
                if (page_cur_try_search_shortcut(
263
 
                            page, index, tuple,
 
277
                            block, index, tuple,
264
278
                            iup_matched_fields, iup_matched_bytes,
265
279
                            ilow_matched_fields, ilow_matched_bytes,
266
280
                            cursor)) {
359
373
        /* Perform linear search until the upper and lower records come to
360
374
        distance 1 of each other. */
361
375
 
362
 
        while (page_rec_get_next(low_rec) != up_rec) {
 
376
        while (page_rec_get_next_const(low_rec) != up_rec) {
363
377
 
364
 
                mid_rec = page_rec_get_next(low_rec);
 
378
                mid_rec = page_rec_get_next_const(low_rec);
365
379
 
366
380
                ut_pair_min(&cur_matched_fields, &cur_matched_bytes,
367
381
                            low_matched_fields, low_matched_bytes,
429
443
                ut_a(dbg_cmp >= 0);
430
444
        }
431
445
 
432
 
        if (low_rec != page_get_infimum_rec(page)) {
 
446
        if (!page_rec_is_infimum(low_rec)) {
433
447
 
434
448
                ut_a(low_matched_fields == dbg_matched_fields);
435
449
                ut_a(low_matched_bytes == dbg_matched_bytes);
453
467
                ut_a(dbg_cmp == -1);
454
468
        }
455
469
 
456
 
        if (up_rec != page_get_supremum_rec(page)) {
 
470
        if (!page_rec_is_supremum(up_rec)) {
457
471
 
458
472
                ut_a(up_matched_fields == dbg_matched_fields);
459
473
                ut_a(up_matched_bytes == dbg_matched_bytes);
460
474
        }
461
475
#endif
462
476
        if (mode <= PAGE_CUR_GE) {
463
 
                cursor->rec = up_rec;
 
477
                page_cur_position(up_rec, block, cursor);
464
478
        } else {
465
 
                cursor->rec = low_rec;
 
479
                page_cur_position(low_rec, block, cursor);
466
480
        }
467
481
 
468
482
        *iup_matched_fields  = up_matched_fields;
477
491
/***************************************************************
478
492
Positions a page cursor on a randomly chosen user record on a page. If there
479
493
are no user records, sets the cursor on the infimum record. */
480
 
 
 
494
UNIV_INTERN
481
495
void
482
496
page_cur_open_on_rnd_user_rec(
483
497
/*==========================*/
484
 
        page_t*         page,   /* in: page */
485
 
        page_cur_t*     cursor) /* in/out: page cursor */
 
498
        buf_block_t*    block,  /* in: page */
 
499
        page_cur_t*     cursor) /* out: page cursor */
486
500
{
487
501
        ulint   rnd;
488
 
        rec_t*  rec;
489
 
 
490
 
        if (page_get_n_recs(page) == 0) {
491
 
                page_cur_position(page_get_infimum_rec(page), cursor);
 
502
        ulint   n_recs = page_get_n_recs(buf_block_get_frame(block));
 
503
 
 
504
        page_cur_set_before_first(block, cursor);
 
505
 
 
506
        if (UNIV_UNLIKELY(n_recs == 0)) {
492
507
 
493
508
                return;
494
509
        }
495
510
 
496
511
        page_rnd += 87584577;
497
512
 
498
 
        rnd = page_rnd % page_get_n_recs(page);
499
 
 
500
 
        rec = page_get_infimum_rec(page);
501
 
 
502
 
        rec = page_rec_get_next(rec);
503
 
 
504
 
        while (rnd > 0) {
505
 
                rec = page_rec_get_next(rec);
506
 
 
507
 
                rnd--;
508
 
        }
509
 
 
510
 
        page_cur_position(rec, cursor);
 
513
        rnd = page_rnd % n_recs;
 
514
 
 
515
        do {
 
516
                page_cur_move_to_next(cursor);
 
517
        } while (rnd--);
511
518
}
512
519
 
513
520
/***************************************************************
526
533
        ulint   cur_rec_size;
527
534
        ulint   extra_size;
528
535
        ulint   cur_extra_size;
529
 
        ulint   min_rec_size;
530
 
        byte*   ins_ptr;
531
 
        byte*   cur_ptr;
532
 
        ulint   extra_info_yes;
 
536
        const byte* ins_ptr;
533
537
        byte*   log_ptr;
534
 
        byte*   log_end;
 
538
        const byte* log_end;
535
539
        ulint   i;
536
 
        ulint   comp;
537
540
 
538
541
        ut_a(rec_size < UNIV_PAGE_SIZE);
539
 
        ut_ad(buf_frame_align(insert_rec) == buf_frame_align(cursor_rec));
 
542
        ut_ad(page_align(insert_rec) == page_align(cursor_rec));
540
543
        ut_ad(!page_rec_is_comp(insert_rec)
541
544
              == !dict_table_is_comp(index->table));
542
 
        comp = page_rec_is_comp(insert_rec);
543
545
 
544
546
        {
545
547
                mem_heap_t*     heap            = NULL;
549
551
                ulint*          cur_offs;
550
552
                ulint*          ins_offs;
551
553
 
552
 
                *cur_offs_ = (sizeof cur_offs_) / sizeof *cur_offs_;
553
 
                *ins_offs_ = (sizeof ins_offs_) / sizeof *ins_offs_;
 
554
                rec_offs_init(cur_offs_);
 
555
                rec_offs_init(ins_offs_);
554
556
 
555
557
                cur_offs = rec_get_offsets(cursor_rec, index, cur_offs_,
556
558
                                           ULINT_UNDEFINED, &heap);
572
574
        i = 0;
573
575
 
574
576
        if (cur_extra_size == extra_size) {
575
 
                min_rec_size = ut_min(cur_rec_size, rec_size);
 
577
                ulint           min_rec_size = ut_min(cur_rec_size, rec_size);
576
578
 
577
 
                cur_ptr = cursor_rec - cur_extra_size;
 
579
                const byte*     cur_ptr = cursor_rec - cur_extra_size;
578
580
 
579
581
                /* Find out the first byte in insert_rec which differs from
580
582
                cursor_rec; skip the bytes in the record info */
581
583
 
582
 
                for (;;) {
583
 
                        if (i >= min_rec_size) {
584
 
 
585
 
                                break;
586
 
                        } else if (*ins_ptr == *cur_ptr) {
 
584
                do {
 
585
                        if (*ins_ptr == *cur_ptr) {
587
586
                                i++;
588
587
                                ins_ptr++;
589
588
                                cur_ptr++;
590
589
                        } else if ((i < extra_size)
591
590
                                   && (i >= extra_size
592
 
                                       - (comp
593
 
                                          ? REC_N_NEW_EXTRA_BYTES
594
 
                                          : REC_N_OLD_EXTRA_BYTES))) {
 
591
                                       - page_rec_get_base_extra_size
 
592
                                       (insert_rec))) {
595
593
                                i = extra_size;
596
594
                                ins_ptr = insert_rec;
597
595
                                cur_ptr = cursor_rec;
598
596
                        } else {
599
597
                                break;
600
598
                        }
601
 
                }
 
599
                } while (i < min_rec_size);
602
600
        }
603
601
 
604
602
        if (mtr_get_log_mode(mtr) != MTR_LOG_SHORT_INSERTS) {
605
603
 
606
 
                log_ptr = mlog_open_and_write_index(mtr, insert_rec, index,
607
 
                                                    comp
608
 
                                                    ? MLOG_COMP_REC_INSERT
609
 
                                                    : MLOG_REC_INSERT,
610
 
                                                    2 + 5 + 1 + 5 + 5
611
 
                                                    + MLOG_BUF_MARGIN);
 
604
                if (page_rec_is_comp(insert_rec)) {
 
605
                        log_ptr = mlog_open_and_write_index(
 
606
                                mtr, insert_rec, index, MLOG_COMP_REC_INSERT,
 
607
                                2 + 5 + 1 + 5 + 5 + MLOG_BUF_MARGIN);
 
608
                        if (UNIV_UNLIKELY(!log_ptr)) {
 
609
                                /* Logging in mtr is switched off
 
610
                                during crash recovery: in that case
 
611
                                mlog_open returns NULL */
 
612
                                return;
 
613
                        }
 
614
                } else {
 
615
                        log_ptr = mlog_open(mtr, 11
 
616
                                            + 2 + 5 + 1 + 5 + 5
 
617
                                            + MLOG_BUF_MARGIN);
 
618
                        if (UNIV_UNLIKELY(!log_ptr)) {
 
619
                                /* Logging in mtr is switched off
 
620
                                during crash recovery: in that case
 
621
                                mlog_open returns NULL */
 
622
                                return;
 
623
                        }
612
624
 
613
 
                if (!log_ptr) {
614
 
                        /* Logging in mtr is switched off during crash
615
 
                        recovery: in that case mlog_open returns NULL */
616
 
                        return;
 
625
                        log_ptr = mlog_write_initial_log_record_fast(
 
626
                                insert_rec, MLOG_REC_INSERT, log_ptr, mtr);
617
627
                }
618
628
 
619
629
                log_end = &log_ptr[2 + 5 + 1 + 5 + 5 + MLOG_BUF_MARGIN];
620
630
                /* Write the cursor rec offset as a 2-byte ulint */
621
 
                mach_write_to_2(log_ptr, cursor_rec
622
 
                                - buf_frame_align(cursor_rec));
 
631
                mach_write_to_2(log_ptr, page_offset(cursor_rec));
623
632
                log_ptr += 2;
624
633
        } else {
625
634
                log_ptr = mlog_open(mtr, 5 + 1 + 5 + 5 + MLOG_BUF_MARGIN);
631
640
                log_end = &log_ptr[5 + 1 + 5 + 5 + MLOG_BUF_MARGIN];
632
641
        }
633
642
 
634
 
        if ((rec_get_info_and_status_bits(insert_rec, comp)
635
 
             != rec_get_info_and_status_bits(cursor_rec, comp))
636
 
            || (extra_size != cur_extra_size)
637
 
            || (rec_size != cur_rec_size)) {
 
643
        if (page_rec_is_comp(insert_rec)) {
 
644
                if (UNIV_UNLIKELY
 
645
                    (rec_get_info_and_status_bits(insert_rec, TRUE)
 
646
                     != rec_get_info_and_status_bits(cursor_rec, TRUE))) {
638
647
 
639
 
                extra_info_yes = 1;
 
648
                        goto need_extra_info;
 
649
                }
640
650
        } else {
641
 
                extra_info_yes = 0;
 
651
                if (UNIV_UNLIKELY
 
652
                    (rec_get_info_and_status_bits(insert_rec, FALSE)
 
653
                     != rec_get_info_and_status_bits(cursor_rec, FALSE))) {
 
654
 
 
655
                        goto need_extra_info;
 
656
                }
642
657
        }
643
658
 
644
 
        /* Write the record end segment length and the extra info storage
645
 
        flag */
646
 
        log_ptr += mach_write_compressed(log_ptr, 2 * (rec_size - i)
647
 
                                         + extra_info_yes);
648
 
        if (extra_info_yes) {
 
659
        if (extra_size != cur_extra_size || rec_size != cur_rec_size) {
 
660
need_extra_info:
 
661
                /* Write the record end segment length
 
662
                and the extra info storage flag */
 
663
                log_ptr += mach_write_compressed(log_ptr,
 
664
                                                 2 * (rec_size - i) + 1);
 
665
 
649
666
                /* Write the info bits */
650
667
                mach_write_to_1(log_ptr,
651
 
                                rec_get_info_and_status_bits(insert_rec,
652
 
                                                             comp));
 
668
                                rec_get_info_and_status_bits(
 
669
                                        insert_rec,
 
670
                                        page_rec_is_comp(insert_rec)));
653
671
                log_ptr++;
654
672
 
655
673
                /* Write the record origin offset */
660
678
 
661
679
                ut_a(i < UNIV_PAGE_SIZE);
662
680
                ut_a(extra_size < UNIV_PAGE_SIZE);
 
681
        } else {
 
682
                /* Write the record end segment length
 
683
                and the extra info storage flag */
 
684
                log_ptr += mach_write_compressed(log_ptr, 2 * (rec_size - i));
663
685
        }
664
686
 
665
687
        /* Write to the log the inserted index record end segment which
679
701
 
680
702
/***************************************************************
681
703
Parses a log record of a record insert on a page. */
682
 
 
 
704
UNIV_INTERN
683
705
byte*
684
706
page_cur_parse_insert_rec(
685
707
/*======================*/
687
709
        ibool           is_short,/* in: TRUE if short inserts */
688
710
        byte*           ptr,    /* in: buffer */
689
711
        byte*           end_ptr,/* in: buffer end */
 
712
        buf_block_t*    block,  /* in: page or NULL */
690
713
        dict_index_t*   index,  /* in: record descriptor */
691
 
        page_t*         page,   /* in: page or NULL */
692
714
        mtr_t*          mtr)    /* in: mtr or NULL */
693
715
{
694
 
        ulint   extra_info_yes;
695
 
        ulint   offset = 0; /* remove warning */
696
716
        ulint   origin_offset;
697
717
        ulint   end_seg_len;
698
718
        ulint   mismatch_index;
 
719
        page_t* page;
699
720
        rec_t*  cursor_rec;
700
721
        byte    buf1[1024];
701
722
        byte*   buf;
702
 
        byte*   ptr2 = ptr;
 
723
        byte*   ptr2                    = ptr;
703
724
        ulint   info_and_status_bits = 0; /* remove warning */
704
725
        page_cur_t cursor;
705
726
        mem_heap_t*     heap            = NULL;
706
727
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
707
728
        ulint*          offsets         = offsets_;
708
 
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
709
 
 
710
 
        if (!is_short) {
 
729
        rec_offs_init(offsets_);
 
730
 
 
731
        page = block ? buf_block_get_frame(block) : NULL;
 
732
 
 
733
        if (is_short) {
 
734
                cursor_rec = page_rec_get_prev(page_get_supremum_rec(page));
 
735
        } else {
 
736
                ulint   offset;
 
737
 
711
738
                /* Read the cursor rec offset as a 2-byte ulint */
712
739
 
713
 
                if (end_ptr < ptr + 2) {
 
740
                if (UNIV_UNLIKELY(end_ptr < ptr + 2)) {
714
741
 
715
742
                        return(NULL);
716
743
                }
717
744
 
718
745
                offset = mach_read_from_2(ptr);
719
 
 
720
 
                if (offset >= UNIV_PAGE_SIZE) {
 
746
                ptr += 2;
 
747
 
 
748
                cursor_rec = page + offset;
 
749
 
 
750
                if (UNIV_UNLIKELY(offset >= UNIV_PAGE_SIZE)) {
721
751
 
722
752
                        recv_sys->found_corrupt_log = TRUE;
723
753
 
724
754
                        return(NULL);
725
755
                }
726
 
 
727
 
                ptr += 2;
728
756
        }
729
757
 
730
758
        ptr = mach_parse_compressed(ptr, end_ptr, &end_seg_len);
734
762
                return(NULL);
735
763
        }
736
764
 
737
 
        extra_info_yes = end_seg_len & 0x1UL;
738
 
        end_seg_len >>= 1;
739
 
 
740
 
        if (end_seg_len >= UNIV_PAGE_SIZE) {
 
765
        if (UNIV_UNLIKELY(end_seg_len >= UNIV_PAGE_SIZE << 1)) {
741
766
                recv_sys->found_corrupt_log = TRUE;
742
767
 
743
768
                return(NULL);
744
769
        }
745
770
 
746
 
        if (extra_info_yes) {
 
771
        if (end_seg_len & 0x1UL) {
747
772
                /* Read the info bits */
748
773
 
749
774
                if (end_ptr < ptr + 1) {
773
798
                ut_a(mismatch_index < UNIV_PAGE_SIZE);
774
799
        }
775
800
 
776
 
        if (end_ptr < ptr + end_seg_len) {
 
801
        if (UNIV_UNLIKELY(end_ptr < ptr + (end_seg_len >> 1))) {
777
802
 
778
803
                return(NULL);
779
804
        }
780
805
 
781
 
        if (page == NULL) {
 
806
        if (!block) {
782
807
 
783
 
                return(ptr + end_seg_len);
 
808
                return(ptr + (end_seg_len >> 1));
784
809
        }
785
810
 
786
811
        ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
 
812
        ut_ad(!buf_block_get_page_zip(block) || page_is_comp(page));
787
813
 
788
814
        /* Read from the log the inserted index record end segment which
789
815
        differs from the cursor record */
790
816
 
791
 
        if (is_short) {
792
 
                cursor_rec = page_rec_get_prev(page_get_supremum_rec(page));
793
 
        } else {
794
 
                cursor_rec = page + offset;
795
 
        }
796
 
 
797
817
        offsets = rec_get_offsets(cursor_rec, index, offsets,
798
818
                                  ULINT_UNDEFINED, &heap);
799
819
 
800
 
        if (extra_info_yes == 0) {
 
820
        if (!(end_seg_len & 0x1UL)) {
801
821
                info_and_status_bits = rec_get_info_and_status_bits(
802
822
                        cursor_rec, page_is_comp(page));
803
823
                origin_offset = rec_offs_extra_size(offsets);
804
 
                mismatch_index = rec_offs_size(offsets) - end_seg_len;
 
824
                mismatch_index = rec_offs_size(offsets) - (end_seg_len >> 1);
805
825
        }
806
826
 
 
827
        end_seg_len >>= 1;
 
828
 
807
829
        if (mismatch_index + end_seg_len < sizeof buf1) {
808
830
                buf = buf1;
809
831
        } else {
812
834
 
813
835
        /* Build the inserted record to buf */
814
836
 
815
 
        if (mismatch_index >= UNIV_PAGE_SIZE) {
 
837
        if (UNIV_UNLIKELY(mismatch_index >= UNIV_PAGE_SIZE)) {
816
838
                fprintf(stderr,
817
839
                        "Is short %lu, info_and_status_bits %lu, offset %lu, "
818
840
                        "o_offset %lu\n"
819
841
                        "mismatch index %lu, end_seg_len %lu\n"
820
842
                        "parsed len %lu\n",
821
843
                        (ulong) is_short, (ulong) info_and_status_bits,
822
 
                        (ulong) offset,
 
844
                        (ulong) page_offset(cursor_rec),
823
845
                        (ulong) origin_offset,
824
846
                        (ulong) mismatch_index, (ulong) end_seg_len,
825
847
                        (ulong) (ptr - ptr2));
827
849
                fputs("Dump of 300 bytes of log:\n", stderr);
828
850
                ut_print_buf(stderr, ptr2, 300);
829
851
 
830
 
                buf_page_print(page);
 
852
                buf_page_print(page, 0);
831
853
 
832
854
                ut_error;
833
855
        }
835
857
        ut_memcpy(buf, rec_get_start(cursor_rec, offsets), mismatch_index);
836
858
        ut_memcpy(buf + mismatch_index, ptr, end_seg_len);
837
859
 
838
 
        rec_set_info_and_status_bits(buf + origin_offset, page_is_comp(page),
 
860
        if (page_is_comp(page)) {
 
861
                rec_set_info_and_status_bits(buf + origin_offset,
839
862
                                     info_and_status_bits);
 
863
        } else {
 
864
                rec_set_info_bits_old(buf + origin_offset,
 
865
                                                        info_and_status_bits);
 
866
        }
840
867
 
841
 
        page_cur_position(cursor_rec, &cursor);
 
868
        page_cur_position(cursor_rec, block, &cursor);
842
869
 
843
870
        offsets = rec_get_offsets(buf + origin_offset, index, offsets,
844
871
                                  ULINT_UNDEFINED, &heap);
845
 
        page_cur_rec_insert(&cursor, buf + origin_offset, index, offsets, mtr);
 
872
        if (UNIV_UNLIKELY(!page_cur_rec_insert(&cursor,
 
873
                                               buf + origin_offset,
 
874
                                               index, offsets, mtr))) {
 
875
                /* The redo log record should only have been written
 
876
                after the write was successful. */
 
877
                ut_error;
 
878
        }
846
879
 
847
880
        if (buf != buf1) {
848
881
 
857
890
}
858
891
 
859
892
/***************************************************************
860
 
Inserts a record next to page cursor. Returns pointer to inserted record if
861
 
succeed, i.e., enough space available, NULL otherwise. The record to be
862
 
inserted can be in a data tuple or as a physical record. The other parameter
863
 
must then be NULL. The cursor stays at the same position. */
864
 
 
 
893
Inserts a record next to page cursor on an uncompressed page.
 
894
Returns pointer to inserted record if succeed, i.e., enough
 
895
space available, NULL otherwise. The cursor stays at the same position. */
 
896
UNIV_INTERN
865
897
rec_t*
866
898
page_cur_insert_rec_low(
867
899
/*====================*/
868
900
                                /* out: pointer to record if succeed, NULL
869
901
                                otherwise */
870
 
        page_cur_t*     cursor, /* in: a page cursor */
871
 
        dtuple_t*       tuple,  /* in: pointer to a data tuple or NULL */
 
902
        rec_t*          current_rec,/* in: pointer to current record after
 
903
                                which the new record is inserted */
872
904
        dict_index_t*   index,  /* in: record descriptor */
873
 
        rec_t*          rec,    /* in: pointer to a physical record or NULL */
874
 
        ulint*          offsets,/* in: rec_get_offsets(rec, index) or NULL */
875
 
        mtr_t*          mtr)    /* in: mini-transaction handle */
 
905
        const rec_t*    rec,    /* in: pointer to a physical record */
 
906
        ulint*          offsets,/* in/out: rec_get_offsets(rec, index) */
 
907
        mtr_t*          mtr)    /* in: mini-transaction handle, or NULL */
876
908
{
877
909
        byte*           insert_buf      = NULL;
878
910
        ulint           rec_size;
879
 
        byte*           page;           /* the relevant page */
 
911
        page_t*         page;           /* the relevant page */
880
912
        rec_t*          last_insert;    /* cursor position at previous
881
913
                                        insert */
 
914
        rec_t*          free_rec;       /* a free record that was reused,
 
915
                                        or NULL */
882
916
        rec_t*          insert_rec;     /* inserted record */
883
917
        ulint           heap_no;        /* heap number of the inserted
884
918
                                        record */
885
 
        rec_t*          current_rec;    /* current record after which the
886
 
                                        new record is inserted */
887
 
        rec_t*          next_rec;       /* next record after current before
888
 
                                        the insertion */
889
 
        ulint           owner_slot;     /* the slot which owns the
890
 
                                        inserted record */
891
 
        rec_t*          owner_rec;
892
 
        ulint           n_owned;
893
 
        mem_heap_t*     heap            = NULL;
894
 
        ulint           comp;
895
 
 
896
 
        ut_ad(cursor && mtr);
897
 
        ut_ad(tuple || rec);
898
 
        ut_ad(!(tuple && rec));
899
 
        ut_ad(rec || dtuple_check_typed(tuple));
900
 
 
901
 
        page = page_cur_get_page(cursor);
902
 
        comp = page_is_comp(page);
903
 
        ut_ad(dict_table_is_comp(index->table) == !!comp);
904
 
 
905
 
        ut_ad(cursor->rec != page_get_supremum_rec(page));
 
919
 
 
920
        ut_ad(rec_offs_validate(rec, index, offsets));
 
921
 
 
922
        page = page_align(current_rec);
 
923
        ut_ad(dict_table_is_comp(index->table)
 
924
              == (ibool) !!page_is_comp(page));
 
925
 
 
926
        ut_ad(!page_rec_is_supremum(current_rec));
906
927
 
907
928
        /* 1. Get the size of the physical record in the page */
908
 
        if (tuple != NULL) {
909
 
                rec_size = rec_get_converted_size(index, tuple);
910
 
        } else {
911
 
                if (!offsets) {
912
 
                        offsets = rec_get_offsets(rec, index, offsets,
913
 
                                                  ULINT_UNDEFINED, &heap);
914
 
                }
915
 
                ut_ad(rec_offs_validate(rec, index, offsets));
916
 
                rec_size = rec_offs_size(offsets);
 
929
        rec_size = rec_offs_size(offsets);
 
930
 
 
931
#ifdef UNIV_DEBUG_VALGRIND
 
932
        {
 
933
                const void*     rec_start
 
934
                        = rec - rec_offs_extra_size(offsets);
 
935
                ulint           extra_size
 
936
                        = rec_offs_extra_size(offsets)
 
937
                        - (rec_offs_comp(offsets)
 
938
                           ? REC_N_NEW_EXTRA_BYTES
 
939
                           : REC_N_OLD_EXTRA_BYTES);
 
940
 
 
941
                /* All data bytes of the record must be valid. */
 
942
                UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
 
943
                /* The variable-length header must be valid. */
 
944
                UNIV_MEM_ASSERT_RW(rec_start, extra_size);
917
945
        }
 
946
#endif /* UNIV_DEBUG_VALGRIND */
918
947
 
919
948
        /* 2. Try to find suitable space from page memory management */
920
 
        insert_buf = page_mem_alloc(page, rec_size, index, &heap_no);
921
 
 
922
 
        if (insert_buf == NULL) {
 
949
 
 
950
        free_rec = page_header_get_ptr(page, PAGE_FREE);
 
951
        if (UNIV_LIKELY_NULL(free_rec)) {
 
952
                /* Try to allocate from the head of the free list. */
 
953
                ulint           foffsets_[REC_OFFS_NORMAL_SIZE];
 
954
                ulint*          foffsets        = foffsets_;
 
955
                mem_heap_t*     heap            = NULL;
 
956
 
 
957
                rec_offs_init(foffsets_);
 
958
 
 
959
                foffsets = rec_get_offsets(free_rec, index, foffsets,
 
960
                                        ULINT_UNDEFINED, &heap);
 
961
                if (rec_offs_size(foffsets) < rec_size) {
 
962
                        if (UNIV_LIKELY_NULL(heap)) {
 
963
                                mem_heap_free(heap);
 
964
                        }
 
965
 
 
966
                        goto use_heap;
 
967
                }
 
968
 
 
969
                insert_buf = free_rec - rec_offs_extra_size(foffsets);
 
970
 
 
971
                if (page_is_comp(page)) {
 
972
                        heap_no = rec_get_heap_no_new(free_rec);
 
973
                        page_mem_alloc_free(page, NULL,
 
974
                                        rec_get_next_ptr(free_rec, TRUE),
 
975
                                        rec_size);
 
976
                } else {
 
977
                        heap_no = rec_get_heap_no_old(free_rec);
 
978
                        page_mem_alloc_free(page, NULL,
 
979
                                        rec_get_next_ptr(free_rec, FALSE),
 
980
                                        rec_size);
 
981
                }
 
982
 
923
983
                if (UNIV_LIKELY_NULL(heap)) {
924
984
                        mem_heap_free(heap);
925
985
                }
926
 
                return(NULL);
 
986
        } else {
 
987
use_heap:
 
988
                free_rec = NULL;
 
989
                insert_buf = page_mem_alloc_heap(page, NULL,
 
990
                                                 rec_size, &heap_no);
 
991
 
 
992
                if (UNIV_UNLIKELY(insert_buf == NULL)) {
 
993
                        return(NULL);
 
994
                }
927
995
        }
928
996
 
929
997
        /* 3. Create the record */
930
 
        if (tuple != NULL) {
931
 
                insert_rec = rec_convert_dtuple_to_rec(insert_buf,
932
 
                                                       index, tuple);
933
 
                offsets = rec_get_offsets(insert_rec, index, offsets,
934
 
                                          ULINT_UNDEFINED, &heap);
935
 
        } else {
936
 
                insert_rec = rec_copy(insert_buf, rec, offsets);
937
 
                ut_ad(rec_offs_validate(rec, index, offsets));
938
 
                rec_offs_make_valid(insert_rec, index, offsets);
939
 
        }
940
 
 
941
 
        ut_ad(insert_rec);
942
 
        ut_ad(rec_size == rec_offs_size(offsets));
 
998
        insert_rec = rec_copy(insert_buf, rec, offsets);
 
999
        rec_offs_make_valid(insert_rec, index, offsets);
943
1000
 
944
1001
        /* 4. Insert the record in the linked list of records */
945
 
        current_rec = cursor->rec;
946
 
 
947
 
        ut_ad(!comp || rec_get_status(current_rec) <= REC_STATUS_INFIMUM);
948
 
        ut_ad(!comp || rec_get_status(insert_rec) < REC_STATUS_INFIMUM);
949
 
 
950
 
        next_rec = page_rec_get_next(current_rec);
951
 
        ut_ad(!comp || rec_get_status(next_rec) != REC_STATUS_INFIMUM);
952
 
        page_rec_set_next(insert_rec, next_rec);
953
 
        page_rec_set_next(current_rec, insert_rec);
954
 
 
955
 
        page_header_set_field(page, PAGE_N_RECS, 1 + page_get_n_recs(page));
 
1002
        ut_ad(current_rec != insert_rec);
 
1003
 
 
1004
        {
 
1005
                /* next record after current before the insertion */
 
1006
                rec_t*  next_rec = page_rec_get_next(current_rec);
 
1007
#ifdef UNIV_DEBUG
 
1008
                if (page_is_comp(page)) {
 
1009
                        ut_ad(rec_get_status(current_rec)
 
1010
                                <= REC_STATUS_INFIMUM);
 
1011
                        ut_ad(rec_get_status(insert_rec) < REC_STATUS_INFIMUM);
 
1012
                        ut_ad(rec_get_status(next_rec) != REC_STATUS_INFIMUM);
 
1013
                }
 
1014
#endif
 
1015
                page_rec_set_next(insert_rec, next_rec);
 
1016
                page_rec_set_next(current_rec, insert_rec);
 
1017
        }
 
1018
 
 
1019
        page_header_set_field(page, NULL, PAGE_N_RECS,
 
1020
                              1 + page_get_n_recs(page));
956
1021
 
957
1022
        /* 5. Set the n_owned field in the inserted record to zero,
958
1023
        and set the heap_no field */
959
 
 
960
 
        rec_set_n_owned(insert_rec, comp, 0);
961
 
        rec_set_heap_no(insert_rec, comp, heap_no);
962
 
 
 
1024
        if (page_is_comp(page)) {
 
1025
                rec_set_n_owned_new(insert_rec, NULL, 0);
 
1026
                rec_set_heap_no_new(insert_rec, heap_no);
 
1027
        } else {
 
1028
                rec_set_n_owned_old(insert_rec, 0);
 
1029
                rec_set_heap_no_old(insert_rec, heap_no);
 
1030
        }
 
1031
 
 
1032
        UNIV_MEM_ASSERT_RW(rec_get_start(insert_rec, offsets),
 
1033
                           rec_offs_size(offsets));
963
1034
        /* 6. Update the last insertion info in page header */
964
1035
 
965
1036
        last_insert = page_header_get_ptr(page, PAGE_LAST_INSERT);
966
 
        ut_ad(!last_insert || !comp
 
1037
        ut_ad(!last_insert || !page_is_comp(page)
967
1038
              || rec_get_node_ptr_flag(last_insert)
968
1039
              == rec_get_node_ptr_flag(insert_rec));
969
1040
 
970
 
        if (last_insert == NULL) {
971
 
                page_header_set_field(page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
972
 
                page_header_set_field(page, PAGE_N_DIRECTION, 0);
 
1041
        if (UNIV_UNLIKELY(last_insert == NULL)) {
 
1042
                page_header_set_field(page, NULL, PAGE_DIRECTION,
 
1043
                                      PAGE_NO_DIRECTION);
 
1044
                page_header_set_field(page, NULL, PAGE_N_DIRECTION, 0);
973
1045
 
974
1046
        } else if ((last_insert == current_rec)
975
1047
                   && (page_header_get_field(page, PAGE_DIRECTION)
976
1048
                       != PAGE_LEFT)) {
977
1049
 
978
 
                page_header_set_field(page, PAGE_DIRECTION, PAGE_RIGHT);
979
 
                page_header_set_field(page, PAGE_N_DIRECTION,
980
 
                                      page_header_get_field(
981
 
                                              page, PAGE_N_DIRECTION) + 1);
982
 
 
983
 
        } else if ((page_rec_get_next(insert_rec) == last_insert)
984
 
                   && (page_header_get_field(page, PAGE_DIRECTION)
985
 
                       != PAGE_RIGHT)) {
986
 
 
987
 
                page_header_set_field(page, PAGE_DIRECTION, PAGE_LEFT);
988
 
                page_header_set_field(page, PAGE_N_DIRECTION,
989
 
                                      page_header_get_field(
990
 
                                              page, PAGE_N_DIRECTION) + 1);
991
 
        } else {
992
 
                page_header_set_field(page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
993
 
                page_header_set_field(page, PAGE_N_DIRECTION, 0);
994
 
        }
995
 
 
996
 
        page_header_set_ptr(page, PAGE_LAST_INSERT, insert_rec);
997
 
 
998
 
        /* 7. It remains to update the owner record. */
999
 
 
1000
 
        owner_rec = page_rec_find_owner_rec(insert_rec);
1001
 
        n_owned = rec_get_n_owned(owner_rec, comp);
1002
 
        rec_set_n_owned(owner_rec, comp, n_owned + 1);
1003
 
 
1004
 
        /* 8. Now we have incremented the n_owned field of the owner
1005
 
        record. If the number exceeds PAGE_DIR_SLOT_MAX_N_OWNED,
1006
 
        we have to split the corresponding directory slot in two. */
1007
 
 
1008
 
        if (n_owned == PAGE_DIR_SLOT_MAX_N_OWNED) {
1009
 
                owner_slot = page_dir_find_owner_slot(owner_rec);
1010
 
                page_dir_split_slot(page, owner_slot);
1011
 
        }
1012
 
 
1013
 
        /* 9. Write log record of the insert */
1014
 
        page_cur_insert_rec_write_log(insert_rec, rec_size, current_rec,
1015
 
                                      index, mtr);
1016
 
 
1017
 
        if (UNIV_LIKELY_NULL(heap)) {
1018
 
                mem_heap_free(heap);
1019
 
        }
 
1050
                page_header_set_field(page, NULL, PAGE_DIRECTION,
 
1051
                                                        PAGE_RIGHT);
 
1052
                page_header_set_field(page, NULL, PAGE_N_DIRECTION,
 
1053
                                      page_header_get_field(
 
1054
                                              page, PAGE_N_DIRECTION) + 1);
 
1055
 
 
1056
        } else if ((page_rec_get_next(insert_rec) == last_insert)
 
1057
                   && (page_header_get_field(page, PAGE_DIRECTION)
 
1058
                       != PAGE_RIGHT)) {
 
1059
 
 
1060
                page_header_set_field(page, NULL, PAGE_DIRECTION,
 
1061
                                                        PAGE_LEFT);
 
1062
                page_header_set_field(page, NULL, PAGE_N_DIRECTION,
 
1063
                                      page_header_get_field(
 
1064
                                              page, PAGE_N_DIRECTION) + 1);
 
1065
        } else {
 
1066
                page_header_set_field(page, NULL, PAGE_DIRECTION,
 
1067
                                                        PAGE_NO_DIRECTION);
 
1068
                page_header_set_field(page, NULL, PAGE_N_DIRECTION, 0);
 
1069
        }
 
1070
 
 
1071
        page_header_set_ptr(page, NULL, PAGE_LAST_INSERT, insert_rec);
 
1072
 
 
1073
        /* 7. It remains to update the owner record. */
 
1074
        {
 
1075
                rec_t*  owner_rec       = page_rec_find_owner_rec(insert_rec);
 
1076
                ulint   n_owned;
 
1077
                if (page_is_comp(page)) {
 
1078
                        n_owned = rec_get_n_owned_new(owner_rec);
 
1079
                        rec_set_n_owned_new(owner_rec, NULL, n_owned + 1);
 
1080
                } else {
 
1081
                        n_owned = rec_get_n_owned_old(owner_rec);
 
1082
                        rec_set_n_owned_old(owner_rec, n_owned + 1);
 
1083
                }
 
1084
 
 
1085
                /* 8. Now we have incremented the n_owned field of the owner
 
1086
                record. If the number exceeds PAGE_DIR_SLOT_MAX_N_OWNED,
 
1087
                we have to split the corresponding directory slot in two. */
 
1088
 
 
1089
                if (UNIV_UNLIKELY(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED)) {
 
1090
                        page_dir_split_slot(
 
1091
                                page, NULL,
 
1092
                                page_dir_find_owner_slot(owner_rec));
 
1093
                }
 
1094
        }
 
1095
 
 
1096
        /* 9. Write log record of the insert */
 
1097
        if (UNIV_LIKELY(mtr != NULL)) {
 
1098
                page_cur_insert_rec_write_log(insert_rec, rec_size,
 
1099
                                              current_rec, index, mtr);
 
1100
        }
 
1101
 
 
1102
        return(insert_rec);
 
1103
}
 
1104
 
 
1105
/***************************************************************
 
1106
Compresses or reorganizes a page after an optimistic insert. */
 
1107
static
 
1108
rec_t*
 
1109
page_cur_insert_rec_zip_reorg(
 
1110
/*==========================*/
 
1111
                                /* out: rec if succeed, NULL otherwise */
 
1112
        rec_t**         current_rec,/* in/out: pointer to current record after
 
1113
                                which the new record is inserted */
 
1114
        buf_block_t*    block,  /* in: buffer block */
 
1115
        dict_index_t*   index,  /* in: record descriptor */
 
1116
        rec_t*          rec,    /* in: inserted record */
 
1117
        page_t*         page,   /* in: uncompressed page */
 
1118
        page_zip_des_t* page_zip,/* in: compressed page */
 
1119
        mtr_t*          mtr)    /* in: mini-transaction, or NULL */
 
1120
{
 
1121
        ulint           pos;
 
1122
 
 
1123
        /* Recompress or reorganize and recompress the page. */
 
1124
        if (UNIV_LIKELY(page_zip_compress(page_zip, page, index, mtr))) {
 
1125
                return(rec);
 
1126
        }
 
1127
 
 
1128
        /* Before trying to reorganize the page,
 
1129
        store the number of preceding records on the page. */
 
1130
        pos = page_rec_get_n_recs_before(rec);
 
1131
 
 
1132
        if (page_zip_reorganize(block, index, mtr)) {
 
1133
                /* The page was reorganized: Find rec by seeking to pos,
 
1134
                and update *current_rec. */
 
1135
                rec = page + PAGE_NEW_INFIMUM;
 
1136
 
 
1137
                while (--pos) {
 
1138
                        rec = page + rec_get_next_offs(rec, TRUE);
 
1139
                }
 
1140
 
 
1141
                *current_rec = rec;
 
1142
                rec = page + rec_get_next_offs(rec, TRUE);
 
1143
 
 
1144
                return(rec);
 
1145
        }
 
1146
 
 
1147
        /* Out of space: restore the page */
 
1148
        if (!page_zip_decompress(page_zip, page)) {
 
1149
                ut_error; /* Memory corrupted? */
 
1150
        }
 
1151
        ut_ad(page_validate(page, index));
 
1152
        return(NULL);
 
1153
}
 
1154
 
 
1155
/***************************************************************
 
1156
Inserts a record next to page cursor on a compressed and uncompressed
 
1157
page. Returns pointer to inserted record if succeed, i.e.,
 
1158
enough space available, NULL otherwise.
 
1159
The cursor stays at the same position. */
 
1160
UNIV_INTERN
 
1161
rec_t*
 
1162
page_cur_insert_rec_zip(
 
1163
/*====================*/
 
1164
                                /* out: pointer to record if succeed, NULL
 
1165
                                otherwise */
 
1166
        rec_t**         current_rec,/* in/out: pointer to current record after
 
1167
                                which the new record is inserted */
 
1168
        buf_block_t*    block,  /* in: buffer block of *current_rec */
 
1169
        dict_index_t*   index,  /* in: record descriptor */
 
1170
        const rec_t*    rec,    /* in: pointer to a physical record */
 
1171
        ulint*          offsets,/* in/out: rec_get_offsets(rec, index) */
 
1172
        mtr_t*          mtr)    /* in: mini-transaction handle, or NULL */
 
1173
{
 
1174
        byte*           insert_buf      = NULL;
 
1175
        ulint           rec_size;
 
1176
        page_t*         page;           /* the relevant page */
 
1177
        rec_t*          last_insert;    /* cursor position at previous
 
1178
                                        insert */
 
1179
        rec_t*          free_rec;       /* a free record that was reused,
 
1180
                                        or NULL */
 
1181
        rec_t*          insert_rec;     /* inserted record */
 
1182
        ulint           heap_no;        /* heap number of the inserted
 
1183
                                        record */
 
1184
        page_zip_des_t* page_zip;
 
1185
 
 
1186
        page_zip = buf_block_get_page_zip(block);
 
1187
        ut_ad(page_zip);
 
1188
 
 
1189
        ut_ad(rec_offs_validate(rec, index, offsets));
 
1190
 
 
1191
        page = page_align(*current_rec);
 
1192
        ut_ad(dict_table_is_comp(index->table));
 
1193
        ut_ad(page_is_comp(page));
 
1194
 
 
1195
        ut_ad(!page_rec_is_supremum(*current_rec));
 
1196
#ifdef UNIV_ZIP_DEBUG
 
1197
        ut_a(page_zip_validate(page_zip, page));
 
1198
#endif /* UNIV_ZIP_DEBUG */
 
1199
 
 
1200
        /* 1. Get the size of the physical record in the page */
 
1201
        rec_size = rec_offs_size(offsets);
 
1202
 
 
1203
#ifdef UNIV_DEBUG_VALGRIND
 
1204
        {
 
1205
                const void*     rec_start
 
1206
                        = rec - rec_offs_extra_size(offsets);
 
1207
                ulint           extra_size
 
1208
                        = rec_offs_extra_size(offsets)
 
1209
                        - (rec_offs_comp(offsets)
 
1210
                           ? REC_N_NEW_EXTRA_BYTES
 
1211
                           : REC_N_OLD_EXTRA_BYTES);
 
1212
 
 
1213
                /* All data bytes of the record must be valid. */
 
1214
                UNIV_MEM_ASSERT_RW(rec, rec_offs_data_size(offsets));
 
1215
                /* The variable-length header must be valid. */
 
1216
                UNIV_MEM_ASSERT_RW(rec_start, extra_size);
 
1217
        }
 
1218
#endif /* UNIV_DEBUG_VALGRIND */
 
1219
 
 
1220
        /* 2. Try to find suitable space from page memory management */
 
1221
        if (!page_zip_available(page_zip, dict_index_is_clust(index),
 
1222
                                rec_size, 1)) {
 
1223
 
 
1224
                /* Try compressing the whole page afterwards. */
 
1225
                insert_rec = page_cur_insert_rec_low(*current_rec,
 
1226
                                                     index, rec, offsets,
 
1227
                                                     NULL);
 
1228
 
 
1229
                if (UNIV_LIKELY(insert_rec != NULL)) {
 
1230
                        insert_rec = page_cur_insert_rec_zip_reorg(
 
1231
                                current_rec, block, index, insert_rec,
 
1232
                                page, page_zip, mtr);
 
1233
                }
 
1234
 
 
1235
                return(insert_rec);
 
1236
        }
 
1237
 
 
1238
        free_rec = page_header_get_ptr(page, PAGE_FREE);
 
1239
        if (UNIV_LIKELY_NULL(free_rec)) {
 
1240
                /* Try to allocate from the head of the free list. */
 
1241
                lint    extra_size_diff;
 
1242
                ulint           foffsets_[REC_OFFS_NORMAL_SIZE];
 
1243
                ulint*          foffsets        = foffsets_;
 
1244
                mem_heap_t*     heap            = NULL;
 
1245
 
 
1246
                rec_offs_init(foffsets_);
 
1247
 
 
1248
                foffsets = rec_get_offsets(free_rec, index, foffsets,
 
1249
                                        ULINT_UNDEFINED, &heap);
 
1250
                if (rec_offs_size(foffsets) < rec_size) {
 
1251
too_small:
 
1252
                        if (UNIV_LIKELY_NULL(heap)) {
 
1253
                                mem_heap_free(heap);
 
1254
                        }
 
1255
 
 
1256
                        goto use_heap;
 
1257
                }
 
1258
 
 
1259
                insert_buf = free_rec - rec_offs_extra_size(foffsets);
 
1260
 
 
1261
                /* On compressed pages, do not relocate records from
 
1262
                the free list.  If extra_size would grow, use the heap. */
 
1263
                extra_size_diff
 
1264
                        = rec_offs_extra_size(offsets)
 
1265
                        - rec_offs_extra_size(foffsets);
 
1266
 
 
1267
                if (UNIV_UNLIKELY(extra_size_diff < 0)) {
 
1268
                        /* Add an offset to the extra_size. */
 
1269
                        if (rec_offs_size(foffsets)
 
1270
                            < rec_size - extra_size_diff) {
 
1271
 
 
1272
                                goto too_small;
 
1273
                        }
 
1274
 
 
1275
                        insert_buf -= extra_size_diff;
 
1276
                } else if (UNIV_UNLIKELY(extra_size_diff)) {
 
1277
                        /* Do not allow extra_size to grow */
 
1278
 
 
1279
                        goto too_small;
 
1280
                }
 
1281
 
 
1282
                heap_no = rec_get_heap_no_new(free_rec);
 
1283
                page_mem_alloc_free(page, page_zip,
 
1284
                                    rec_get_next_ptr(free_rec, TRUE),
 
1285
                                    rec_size);
 
1286
 
 
1287
                if (UNIV_LIKELY_NULL(heap)) {
 
1288
                        mem_heap_free(heap);
 
1289
                }
 
1290
        } else {
 
1291
use_heap:
 
1292
                free_rec = NULL;
 
1293
                insert_buf = page_mem_alloc_heap(page, page_zip,
 
1294
                                                 rec_size, &heap_no);
 
1295
 
 
1296
                if (UNIV_UNLIKELY(insert_buf == NULL)) {
 
1297
                        return(NULL);
 
1298
                }
 
1299
 
 
1300
                page_zip_dir_add_slot(page_zip, dict_index_is_clust(index));
 
1301
        }
 
1302
 
 
1303
        /* 3. Create the record */
 
1304
        insert_rec = rec_copy(insert_buf, rec, offsets);
 
1305
        rec_offs_make_valid(insert_rec, index, offsets);
 
1306
 
 
1307
        /* 4. Insert the record in the linked list of records */
 
1308
        ut_ad(*current_rec != insert_rec);
 
1309
 
 
1310
        {
 
1311
                /* next record after current before the insertion */
 
1312
                rec_t*  next_rec = page_rec_get_next(*current_rec);
 
1313
                ut_ad(rec_get_status(*current_rec)
 
1314
                      <= REC_STATUS_INFIMUM);
 
1315
                ut_ad(rec_get_status(insert_rec) < REC_STATUS_INFIMUM);
 
1316
                ut_ad(rec_get_status(next_rec) != REC_STATUS_INFIMUM);
 
1317
 
 
1318
                page_rec_set_next(insert_rec, next_rec);
 
1319
                page_rec_set_next(*current_rec, insert_rec);
 
1320
        }
 
1321
 
 
1322
        page_header_set_field(page, page_zip, PAGE_N_RECS,
 
1323
                              1 + page_get_n_recs(page));
 
1324
 
 
1325
        /* 5. Set the n_owned field in the inserted record to zero,
 
1326
        and set the heap_no field */
 
1327
        rec_set_n_owned_new(insert_rec, NULL, 0);
 
1328
        rec_set_heap_no_new(insert_rec, heap_no);
 
1329
 
 
1330
        UNIV_MEM_ASSERT_RW(rec_get_start(insert_rec, offsets),
 
1331
                           rec_offs_size(offsets));
 
1332
 
 
1333
        page_zip_dir_insert(page_zip, *current_rec, free_rec, insert_rec);
 
1334
 
 
1335
        /* 6. Update the last insertion info in page header */
 
1336
 
 
1337
        last_insert = page_header_get_ptr(page, PAGE_LAST_INSERT);
 
1338
        ut_ad(!last_insert
 
1339
              || rec_get_node_ptr_flag(last_insert)
 
1340
              == rec_get_node_ptr_flag(insert_rec));
 
1341
 
 
1342
        if (UNIV_UNLIKELY(last_insert == NULL)) {
 
1343
                page_header_set_field(page, page_zip, PAGE_DIRECTION,
 
1344
                                                        PAGE_NO_DIRECTION);
 
1345
                page_header_set_field(page, page_zip, PAGE_N_DIRECTION, 0);
 
1346
 
 
1347
        } else if ((last_insert == *current_rec)
 
1348
                   && (page_header_get_field(page, PAGE_DIRECTION)
 
1349
                       != PAGE_LEFT)) {
 
1350
 
 
1351
                page_header_set_field(page, page_zip, PAGE_DIRECTION,
 
1352
                                                        PAGE_RIGHT);
 
1353
                page_header_set_field(page, page_zip, PAGE_N_DIRECTION,
 
1354
                                      page_header_get_field(
 
1355
                                              page, PAGE_N_DIRECTION) + 1);
 
1356
 
 
1357
        } else if ((page_rec_get_next(insert_rec) == last_insert)
 
1358
                   && (page_header_get_field(page, PAGE_DIRECTION)
 
1359
                       != PAGE_RIGHT)) {
 
1360
 
 
1361
                page_header_set_field(page, page_zip, PAGE_DIRECTION,
 
1362
                                                        PAGE_LEFT);
 
1363
                page_header_set_field(page, page_zip, PAGE_N_DIRECTION,
 
1364
                                      page_header_get_field(
 
1365
                                              page, PAGE_N_DIRECTION) + 1);
 
1366
        } else {
 
1367
                page_header_set_field(page, page_zip, PAGE_DIRECTION,
 
1368
                                                        PAGE_NO_DIRECTION);
 
1369
                page_header_set_field(page, page_zip, PAGE_N_DIRECTION, 0);
 
1370
        }
 
1371
 
 
1372
        page_header_set_ptr(page, page_zip, PAGE_LAST_INSERT, insert_rec);
 
1373
 
 
1374
        /* 7. It remains to update the owner record. */
 
1375
        {
 
1376
                rec_t*  owner_rec       = page_rec_find_owner_rec(insert_rec);
 
1377
                ulint   n_owned;
 
1378
 
 
1379
                n_owned = rec_get_n_owned_new(owner_rec);
 
1380
                rec_set_n_owned_new(owner_rec, page_zip, n_owned + 1);
 
1381
 
 
1382
                /* 8. Now we have incremented the n_owned field of the owner
 
1383
                record. If the number exceeds PAGE_DIR_SLOT_MAX_N_OWNED,
 
1384
                we have to split the corresponding directory slot in two. */
 
1385
 
 
1386
                if (UNIV_UNLIKELY(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED)) {
 
1387
                        page_dir_split_slot(
 
1388
                                page, page_zip,
 
1389
                                page_dir_find_owner_slot(owner_rec));
 
1390
                }
 
1391
        }
 
1392
 
 
1393
        page_zip_write_rec(page_zip, insert_rec, index, offsets, 1);
 
1394
 
 
1395
        /* 9. Write log record of the insert */
 
1396
        if (UNIV_LIKELY(mtr != NULL)) {
 
1397
                page_cur_insert_rec_write_log(insert_rec, rec_size,
 
1398
                                              *current_rec, index, mtr);
 
1399
        }
 
1400
 
1020
1401
        return(insert_rec);
1021
1402
}
1022
1403
 
1027
1408
page_copy_rec_list_to_created_page_write_log(
1028
1409
/*=========================================*/
1029
1410
                                /* out: 4-byte field where to
1030
 
                                write the log data length */
 
1411
                                write the log data length,
 
1412
                                or NULL if logging is disabled */
1031
1413
        page_t*         page,   /* in: index page */
1032
1414
        dict_index_t*   index,  /* in: record descriptor */
1033
1415
        mtr_t*          mtr)    /* in: mtr */
1040
1422
                                            page_is_comp(page)
1041
1423
                                            ? MLOG_COMP_LIST_END_COPY_CREATED
1042
1424
                                            : MLOG_LIST_END_COPY_CREATED, 4);
1043
 
        ut_a(log_ptr);
1044
 
        mlog_close(mtr, log_ptr + 4);
 
1425
        if (UNIV_LIKELY(log_ptr != NULL)) {
 
1426
                mlog_close(mtr, log_ptr + 4);
 
1427
        }
1045
1428
 
1046
1429
        return(log_ptr);
1047
1430
}
1048
1431
 
1049
1432
/**************************************************************
1050
1433
Parses a log record of copying a record list end to a new created page. */
1051
 
 
 
1434
UNIV_INTERN
1052
1435
byte*
1053
1436
page_parse_copy_rec_list_to_created_page(
1054
1437
/*=====================================*/
1055
1438
                                /* out: end of log record or NULL */
1056
1439
        byte*           ptr,    /* in: buffer */
1057
1440
        byte*           end_ptr,/* in: buffer end */
 
1441
        buf_block_t*    block,  /* in: page or NULL */
1058
1442
        dict_index_t*   index,  /* in: record descriptor */
1059
 
        page_t*         page,   /* in: page or NULL */
1060
1443
        mtr_t*          mtr)    /* in: mtr or NULL */
1061
1444
{
1062
 
        byte*   rec_end;
1063
 
        ulint   log_data_len;
 
1445
        byte*           rec_end;
 
1446
        ulint           log_data_len;
 
1447
        page_t*         page;
 
1448
        page_zip_des_t* page_zip;
1064
1449
 
1065
1450
        if (ptr + 4 > end_ptr) {
1066
1451
 
1077
1462
                return(NULL);
1078
1463
        }
1079
1464
 
1080
 
        if (!page) {
 
1465
        if (!block) {
1081
1466
 
1082
1467
                return(rec_end);
1083
1468
        }
1084
1469
 
1085
1470
        while (ptr < rec_end) {
1086
1471
                ptr = page_cur_parse_insert_rec(TRUE, ptr, end_ptr,
1087
 
                                                index, page, mtr);
 
1472
                                                block, index, mtr);
1088
1473
        }
1089
1474
 
1090
1475
        ut_a(ptr == rec_end);
1091
1476
 
1092
 
        page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
1093
 
        page_header_set_field(page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
1094
 
        page_header_set_field(page, PAGE_N_DIRECTION, 0);
 
1477
        page = buf_block_get_frame(block);
 
1478
        page_zip = buf_block_get_page_zip(block);
 
1479
 
 
1480
        page_header_set_ptr(page, page_zip, PAGE_LAST_INSERT, NULL);
 
1481
        page_header_set_field(page, page_zip, PAGE_DIRECTION,
 
1482
                                                        PAGE_NO_DIRECTION);
 
1483
        page_header_set_field(page, page_zip, PAGE_N_DIRECTION, 0);
1095
1484
 
1096
1485
        return(rec_end);
1097
1486
}
1099
1488
/*****************************************************************
1100
1489
Copies records from page to a newly created page, from a given record onward,
1101
1490
including that record. Infimum and supremum records are not copied. */
1102
 
 
 
1491
UNIV_INTERN
1103
1492
void
1104
1493
page_copy_rec_list_end_to_created_page(
1105
1494
/*===================================*/
1106
 
        page_t*         new_page,       /* in: index page to copy to */
1107
 
        page_t*         page,           /* in: index page */
 
1495
        page_t*         new_page,       /* in/out: index page to copy to */
1108
1496
        rec_t*          rec,            /* in: first record to copy */
1109
1497
        dict_index_t*   index,          /* in: record descriptor */
1110
1498
        mtr_t*          mtr)            /* in: mtr */
1120
1508
        ulint   log_mode;
1121
1509
        byte*   log_ptr;
1122
1510
        ulint   log_data_len;
1123
 
        ulint           comp            = page_is_comp(page);
1124
1511
        mem_heap_t*     heap            = NULL;
1125
1512
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
1126
1513
        ulint*          offsets         = offsets_;
1127
 
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
1128
 
 
1129
 
        ut_ad(page_dir_get_n_heap(new_page) == 2);
1130
 
        ut_ad(page != new_page);
1131
 
        ut_ad(comp == page_is_comp(new_page));
1132
 
 
1133
 
        if (rec == page_get_infimum_rec(page)) {
 
1514
        rec_offs_init(offsets_);
 
1515
 
 
1516
        ut_ad(page_dir_get_n_heap(new_page) == PAGE_HEAP_NO_USER_LOW);
 
1517
        ut_ad(page_align(rec) != new_page);
 
1518
        ut_ad(page_rec_is_comp(rec) == page_is_comp(new_page));
 
1519
 
 
1520
        if (page_rec_is_infimum(rec)) {
1134
1521
 
1135
1522
                rec = page_rec_get_next(rec);
1136
1523
        }
1137
1524
 
1138
 
        if (rec == page_get_supremum_rec(page)) {
 
1525
        if (page_rec_is_supremum(rec)) {
1139
1526
 
1140
1527
                return;
1141
1528
        }
1143
1530
#ifdef UNIV_DEBUG
1144
1531
        /* To pass the debug tests we have to set these dummy values
1145
1532
        in the debug version */
1146
 
        page_dir_set_n_slots(new_page, UNIV_PAGE_SIZE / 2);
1147
 
        page_header_set_ptr(new_page, PAGE_HEAP_TOP,
 
1533
        page_dir_set_n_slots(new_page, NULL, UNIV_PAGE_SIZE / 2);
 
1534
        page_header_set_ptr(new_page, NULL, PAGE_HEAP_TOP,
1148
1535
                            new_page + UNIV_PAGE_SIZE - 1);
1149
1536
#endif
1150
1537
 
1158
1545
        log_mode = mtr_set_log_mode(mtr, MTR_LOG_SHORT_INSERTS);
1159
1546
 
1160
1547
        prev_rec = page_get_infimum_rec(new_page);
1161
 
        if (comp) {
 
1548
        if (page_is_comp(new_page)) {
1162
1549
                heap_top = new_page + PAGE_NEW_SUPREMUM_END;
1163
1550
        } else {
1164
1551
                heap_top = new_page + PAGE_OLD_SUPREMUM_END;
1167
1554
        slot_index = 0;
1168
1555
        n_recs = 0;
1169
1556
 
1170
 
        /* should be do ... until, comment by Jani */
1171
 
        while (rec != page_get_supremum_rec(page)) {
 
1557
        do {
1172
1558
                offsets = rec_get_offsets(rec, index, offsets,
1173
1559
                                          ULINT_UNDEFINED, &heap);
1174
1560
                insert_rec = rec_copy(heap_top, rec, offsets);
1175
1561
 
1176
 
                rec_set_next_offs(prev_rec, comp, insert_rec - new_page);
1177
 
 
1178
 
                rec_set_n_owned(insert_rec, comp, 0);
1179
 
                rec_set_heap_no(insert_rec, comp, 2 + n_recs);
1180
 
 
1181
 
                rec_size = rec_offs_size(offsets);
1182
 
 
1183
 
                heap_top = heap_top + rec_size;
1184
 
 
1185
 
                ut_ad(heap_top < new_page + UNIV_PAGE_SIZE);
 
1562
                if (page_is_comp(new_page)) {
 
1563
                        rec_set_next_offs_new(prev_rec,
 
1564
                                              page_offset(insert_rec));
 
1565
 
 
1566
                        rec_set_n_owned_new(insert_rec, NULL, 0);
 
1567
                        rec_set_heap_no_new(insert_rec,
 
1568
                                            PAGE_HEAP_NO_USER_LOW + n_recs);
 
1569
                } else {
 
1570
                        rec_set_next_offs_old(prev_rec,
 
1571
                                              page_offset(insert_rec));
 
1572
 
 
1573
                        rec_set_n_owned_old(insert_rec, 0);
 
1574
                        rec_set_heap_no_old(insert_rec,
 
1575
                                            PAGE_HEAP_NO_USER_LOW + n_recs);
 
1576
                }
1186
1577
 
1187
1578
                count++;
1188
1579
                n_recs++;
1189
1580
 
1190
 
                if (count == (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2) {
 
1581
                if (UNIV_UNLIKELY
 
1582
                    (count == (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2)) {
1191
1583
 
1192
1584
                        slot_index++;
1193
1585
 
1194
1586
                        slot = page_dir_get_nth_slot(new_page, slot_index);
1195
1587
 
1196
1588
                        page_dir_slot_set_rec(slot, insert_rec);
1197
 
                        page_dir_slot_set_n_owned(slot, count);
 
1589
                        page_dir_slot_set_n_owned(slot, NULL, count);
1198
1590
 
1199
1591
                        count = 0;
1200
1592
                }
1201
1593
 
 
1594
                rec_size = rec_offs_size(offsets);
 
1595
 
 
1596
                ut_ad(heap_top < new_page + UNIV_PAGE_SIZE);
 
1597
 
 
1598
                heap_top += rec_size;
 
1599
 
1202
1600
                page_cur_insert_rec_write_log(insert_rec, rec_size, prev_rec,
1203
1601
                                              index, mtr);
1204
1602
                prev_rec = insert_rec;
1205
1603
                rec = page_rec_get_next(rec);
1206
 
        }
 
1604
        } while (!page_rec_is_supremum(rec));
1207
1605
 
1208
1606
        if ((slot_index > 0) && (count + 1
1209
1607
                                 + (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2
1217
1615
 
1218
1616
                count += (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2;
1219
1617
 
1220
 
                page_dir_slot_set_n_owned(slot, 0);
 
1618
                page_dir_slot_set_n_owned(slot, NULL, 0);
1221
1619
 
1222
1620
                slot_index--;
1223
1621
        }
1230
1628
 
1231
1629
        ut_a(log_data_len < 100 * UNIV_PAGE_SIZE);
1232
1630
 
1233
 
        mach_write_to_4(log_ptr, log_data_len);
 
1631
        if (UNIV_LIKELY(log_ptr != NULL)) {
 
1632
                mach_write_to_4(log_ptr, log_data_len);
 
1633
        }
1234
1634
 
1235
 
        rec_set_next_offs(insert_rec, comp,
1236
 
                          comp ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM);
 
1635
        if (page_is_comp(new_page)) {
 
1636
                rec_set_next_offs_new(insert_rec, PAGE_NEW_SUPREMUM);
 
1637
        } else {
 
1638
                rec_set_next_offs_old(insert_rec, PAGE_OLD_SUPREMUM);
 
1639
        }
1237
1640
 
1238
1641
        slot = page_dir_get_nth_slot(new_page, 1 + slot_index);
1239
1642
 
1240
1643
        page_dir_slot_set_rec(slot, page_get_supremum_rec(new_page));
1241
 
        page_dir_slot_set_n_owned(slot, count + 1);
1242
 
 
1243
 
        page_dir_set_n_slots(new_page, 2 + slot_index);
1244
 
        page_header_set_ptr(new_page, PAGE_HEAP_TOP, heap_top);
1245
 
        page_dir_set_n_heap(new_page, 2 + n_recs);
1246
 
        page_header_set_field(new_page, PAGE_N_RECS, n_recs);
1247
 
 
1248
 
        page_header_set_ptr(new_page, PAGE_LAST_INSERT, NULL);
1249
 
        page_header_set_field(new_page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
1250
 
        page_header_set_field(new_page, PAGE_N_DIRECTION, 0);
 
1644
        page_dir_slot_set_n_owned(slot, NULL, count + 1);
 
1645
 
 
1646
        page_dir_set_n_slots(new_page, NULL, 2 + slot_index);
 
1647
        page_header_set_ptr(new_page, NULL, PAGE_HEAP_TOP, heap_top);
 
1648
        page_dir_set_n_heap(new_page, NULL, PAGE_HEAP_NO_USER_LOW + n_recs);
 
1649
        page_header_set_field(new_page, NULL, PAGE_N_RECS, n_recs);
 
1650
 
 
1651
        page_header_set_ptr(new_page, NULL, PAGE_LAST_INSERT, NULL);
 
1652
        page_header_set_field(new_page, NULL, PAGE_DIRECTION,
 
1653
                                                        PAGE_NO_DIRECTION);
 
1654
        page_header_set_field(new_page, NULL, PAGE_N_DIRECTION, 0);
1251
1655
 
1252
1656
        /* Restore the log mode */
1253
1657
 
1287
1691
 
1288
1692
/***************************************************************
1289
1693
Parses log record of a record delete on a page. */
1290
 
 
 
1694
UNIV_INTERN
1291
1695
byte*
1292
1696
page_cur_parse_delete_rec(
1293
1697
/*======================*/
1294
1698
                                /* out: pointer to record end or NULL */
1295
1699
        byte*           ptr,    /* in: buffer */
1296
1700
        byte*           end_ptr,/* in: buffer end */
 
1701
        buf_block_t*    block,  /* in: page or NULL */
1297
1702
        dict_index_t*   index,  /* in: record descriptor */
1298
 
        page_t*         page,   /* in: page or NULL */
1299
1703
        mtr_t*          mtr)    /* in: mtr or NULL */
1300
1704
{
1301
1705
        ulint           offset;
1312
1716
 
1313
1717
        ut_a(offset <= UNIV_PAGE_SIZE);
1314
1718
 
1315
 
        if (page) {
 
1719
        if (block) {
 
1720
                page_t*         page            = buf_block_get_frame(block);
1316
1721
                mem_heap_t*     heap            = NULL;
1317
1722
                ulint           offsets_[REC_OFFS_NORMAL_SIZE];
1318
1723
                rec_t*          rec             = page + offset;
1319
 
                *offsets_ = (sizeof offsets_) / sizeof *offsets_;
 
1724
                rec_offs_init(offsets_);
1320
1725
 
1321
 
                page_cur_position(rec, &cursor);
 
1726
                page_cur_position(rec, block, &cursor);
 
1727
                ut_ad(!buf_block_get_page_zip(block) || page_is_comp(page));
1322
1728
 
1323
1729
                page_cur_delete_rec(&cursor, index,
1324
1730
                                    rec_get_offsets(rec, index, offsets_,
1335
1741
/***************************************************************
1336
1742
Deletes a record at the page cursor. The cursor is moved to the next
1337
1743
record after the deleted one. */
1338
 
 
 
1744
UNIV_INTERN
1339
1745
void
1340
1746
page_cur_delete_rec(
1341
1747
/*================*/
1342
 
        page_cur_t*     cursor, /* in: a page cursor */
 
1748
        page_cur_t*     cursor, /* in/out: a page cursor */
1343
1749
        dict_index_t*   index,  /* in: record descriptor */
1344
1750
        const ulint*    offsets,/* in: rec_get_offsets(cursor->rec, index) */
1345
1751
        mtr_t*          mtr)    /* in: mini-transaction handle */
1347
1753
        page_dir_slot_t* cur_dir_slot;
1348
1754
        page_dir_slot_t* prev_slot;
1349
1755
        page_t*         page;
 
1756
        page_zip_des_t* page_zip;
1350
1757
        rec_t*          current_rec;
1351
1758
        rec_t*          prev_rec        = NULL;
1352
1759
        rec_t*          next_rec;
1357
1764
        ut_ad(cursor && mtr);
1358
1765
 
1359
1766
        page = page_cur_get_page(cursor);
 
1767
        page_zip = page_cur_get_page_zip(cursor);
 
1768
        /* page_zip_validate() may fail here when
 
1769
        btr_cur_pessimistic_delete() invokes btr_set_min_rec_mark(). */
1360
1770
        current_rec = cursor->rec;
1361
1771
        ut_ad(rec_offs_validate(current_rec, index, offsets));
1362
1772
        ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
1363
1773
 
1364
1774
        /* The record must not be the supremum or infimum record. */
1365
 
        ut_ad(current_rec != page_get_supremum_rec(page));
1366
 
        ut_ad(current_rec != page_get_infimum_rec(page));
 
1775
        ut_ad(page_rec_is_user_rec(current_rec));
1367
1776
 
1368
1777
        /* Save to local variables some data associated with current_rec */
1369
1778
        cur_slot_no = page_dir_find_owner_slot(current_rec);
1376
1785
        /* 1. Reset the last insert info in the page header and increment
1377
1786
        the modify clock for the frame */
1378
1787
 
1379
 
        page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
 
1788
        page_header_set_ptr(page, page_zip, PAGE_LAST_INSERT, NULL);
1380
1789
 
1381
1790
        /* The page gets invalid for optimistic searches: increment the
1382
1791
        frame modify clock */
1383
1792
 
1384
 
        buf_frame_modify_clock_inc(page);
 
1793
        buf_block_modify_clock_inc(page_cur_get_block(cursor));
1385
1794
 
1386
1795
        /* 2. Find the next and the previous record. Note that the cursor is
1387
1796
        left at the next record. */
1389
1798
        ut_ad(cur_slot_no > 0);
1390
1799
        prev_slot = page_dir_get_nth_slot(page, cur_slot_no - 1);
1391
1800
 
1392
 
        rec = page_dir_slot_get_rec(prev_slot);
 
1801
        rec = (rec_t*) page_dir_slot_get_rec(prev_slot);
1393
1802
 
1394
1803
        /* rec now points to the record of the previous directory slot. Look
1395
1804
        for the immediate predecessor of current_rec in a loop. */
1405
1814
        /* 3. Remove the record from the linked list of records */
1406
1815
 
1407
1816
        page_rec_set_next(prev_rec, next_rec);
1408
 
        page_header_set_field(page, PAGE_N_RECS,
1409
 
                              (ulint)(page_get_n_recs(page) - 1));
1410
1817
 
1411
1818
        /* 4. If the deleted record is pointed to by a dir slot, update the
1412
1819
        record pointer in slot. In the following if-clause we assume that
1424
1831
 
1425
1832
        /* 5. Update the number of owned records of the slot */
1426
1833
 
1427
 
        page_dir_slot_set_n_owned(cur_dir_slot, cur_n_owned - 1);
 
1834
        page_dir_slot_set_n_owned(cur_dir_slot, page_zip, cur_n_owned - 1);
1428
1835
 
1429
1836
        /* 6. Free the memory occupied by the record */
1430
 
        page_mem_free(page, current_rec, offsets);
 
1837
        page_mem_free(page, page_zip, current_rec, index, offsets);
1431
1838
 
1432
1839
        /* 7. Now we have decremented the number of owned records of the slot.
1433
1840
        If the number drops below PAGE_DIR_SLOT_MIN_N_OWNED, we balance the
1434
1841
        slots. */
1435
1842
 
1436
 
        if (cur_n_owned <= PAGE_DIR_SLOT_MIN_N_OWNED) {
1437
 
                page_dir_balance_slot(page, cur_slot_no);
 
1843
        if (UNIV_UNLIKELY(cur_n_owned <= PAGE_DIR_SLOT_MIN_N_OWNED)) {
 
1844
                page_dir_balance_slot(page, page_zip, cur_slot_no);
1438
1845
        }
 
1846
 
 
1847
#ifdef UNIV_ZIP_DEBUG
 
1848
        ut_a(!page_zip || page_zip_validate(page_zip, page));
 
1849
#endif /* UNIV_ZIP_DEBUG */
1439
1850
}