~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2008-12-02 21:16:50 UTC
  • mto: This revision was merged to the branch mainline in revision 641.
  • Revision ID: mordred@solanthus.local-20081202211650-r0adnzw0v9hbke7b
Removed AM_CONDITIONAL from SEARCH_FOR_LIB. Aligned naming of AM_CONDITIONALS.

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
Created 2/2/1994 Heikki Tuuri
7
7
*******************************************************/
8
8
 
9
 
#define THIS_MODULE
10
9
#include "page0page.h"
11
10
#ifdef UNIV_NONINL
12
11
#include "page0page.ic"
13
12
#endif
14
 
#undef THIS_MODULE
15
13
 
16
14
#include "page0cur.h"
 
15
#include "page0zip.h"
17
16
#include "lock0lock.h"
18
17
#include "fut0lst.h"
19
18
#include "btr0sea.h"
65
64
 
66
65
/*******************************************************************
67
66
Looks for the directory slot which owns the given record. */
68
 
 
 
67
UNIV_INTERN
69
68
ulint
70
69
page_dir_find_owner_slot(
71
70
/*=====================*/
72
 
                        /* out: the directory slot number */
73
 
        rec_t*  rec)    /* in: the physical record */
 
71
                                /* out: the directory slot number */
 
72
        const rec_t*    rec)    /* in: the physical record */
74
73
{
75
 
        page_t*                         page;
 
74
        const page_t*                   page;
76
75
        register uint16                 rec_offs_bytes;
77
 
        register page_dir_slot_t*       slot;
 
76
        register const page_dir_slot_t* slot;
78
77
        register const page_dir_slot_t* first_slot;
79
 
        register rec_t*                 r = rec;
 
78
        register const rec_t*           r = rec;
80
79
 
81
80
        ut_ad(page_rec_check(rec));
82
81
 
83
 
        page = buf_frame_align(rec);
 
82
        page = page_align(rec);
84
83
        first_slot = page_dir_get_nth_slot(page, 0);
85
84
        slot = page_dir_get_nth_slot(page, page_dir_get_n_slots(page) - 1);
86
85
 
87
86
        if (page_is_comp(page)) {
88
 
                while (rec_get_n_owned(r, TRUE) == 0) {
89
 
                        r = page + rec_get_next_offs(r, TRUE);
 
87
                while (rec_get_n_owned_new(r) == 0) {
 
88
                        r = rec_get_next_ptr_const(r, TRUE);
90
89
                        ut_ad(r >= page + PAGE_NEW_SUPREMUM);
91
90
                        ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
92
91
                }
93
92
        } else {
94
 
                while (rec_get_n_owned(r, FALSE) == 0) {
95
 
                        r = page + rec_get_next_offs(r, FALSE);
 
93
                while (rec_get_n_owned_old(r) == 0) {
 
94
                        r = rec_get_next_ptr_const(r, FALSE);
96
95
                        ut_ad(r >= page + PAGE_OLD_SUPREMUM);
97
96
                        ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
98
97
                }
107
106
                                "InnoDB: Probable data corruption on"
108
107
                                " page %lu\n"
109
108
                                "InnoDB: Original record ",
110
 
                                (ulong) buf_frame_get_page_no(page));
 
109
                                (ulong) page_get_page_no(page));
111
110
 
112
111
                        if (page_is_comp(page)) {
113
112
                                fputs("(compact record)", stderr);
128
127
                        fputs("\n"
129
128
                              "InnoDB: on that page!\n", stderr);
130
129
 
131
 
                        buf_page_print(page);
 
130
                        buf_page_print(page, 0);
132
131
 
133
132
                        ut_error;
134
133
                }
154
153
 
155
154
        ut_a(slot);
156
155
 
157
 
        page = buf_frame_align(slot);
 
156
        page = page_align(slot);
158
157
 
159
158
        n_slots = page_dir_get_n_slots(page);
160
159
 
163
162
 
164
163
        ut_a(page_rec_check(page_dir_slot_get_rec(slot)));
165
164
 
166
 
        n_owned = rec_get_n_owned(page_dir_slot_get_rec(slot),
167
 
                                  page_is_comp(page));
 
165
        if (page_is_comp(page)) {
 
166
                n_owned = rec_get_n_owned_new(page_dir_slot_get_rec(slot));
 
167
        } else {
 
168
                n_owned = rec_get_n_owned_old(page_dir_slot_get_rec(slot));
 
169
        }
168
170
 
169
171
        if (slot == page_dir_get_nth_slot(page, 0)) {
170
172
                ut_a(n_owned == 1);
181
183
 
182
184
/*****************************************************************
183
185
Sets the max trx id field value. */
184
 
 
 
186
UNIV_INTERN
185
187
void
186
188
page_set_max_trx_id(
187
189
/*================*/
188
 
        page_t* page,   /* in: page */
189
 
        dulint  trx_id) /* in: transaction id */
 
190
        buf_block_t*    block,  /* in/out: page */
 
191
        page_zip_des_t* page_zip,/* in/out: compressed page, or NULL */
 
192
        dulint          trx_id) /* in: transaction id */
190
193
{
191
 
        buf_block_t*    block;
192
 
 
193
 
        ut_ad(page);
194
 
 
195
 
        block = buf_block_align(page);
196
 
 
197
 
        if (block->is_hashed) {
 
194
        const ibool     is_hashed       = block->is_hashed;
 
195
        page_t*         page            = buf_block_get_frame(block);
 
196
 
 
197
        if (is_hashed) {
198
198
                rw_lock_x_lock(&btr_search_latch);
199
199
        }
200
200
 
202
202
        during a database recovery we assume that the max trx id of every
203
203
        page is the maximum trx id assigned before the crash. */
204
204
 
205
 
        mach_write_to_8(page + PAGE_HEADER + PAGE_MAX_TRX_ID, trx_id);
 
205
        mach_write_to_8(page + (PAGE_HEADER + PAGE_MAX_TRX_ID), trx_id);
 
206
        if (UNIV_LIKELY_NULL(page_zip)) {
 
207
                page_zip_write_header(page_zip,
 
208
                                      page + (PAGE_HEADER + PAGE_MAX_TRX_ID),
 
209
                                      8, NULL);
 
210
        }
206
211
 
207
 
        if (block->is_hashed) {
 
212
        if (is_hashed) {
208
213
                rw_lock_x_unlock(&btr_search_latch);
209
214
        }
210
215
}
211
216
 
212
 
/*****************************************************************
213
 
Calculates free space if a page is emptied. */
214
 
 
215
 
ulint
216
 
page_get_free_space_of_empty_noninline(
217
 
/*===================================*/
218
 
                        /* out: free space */
219
 
        ulint   comp)   /* in: nonzero=compact page format */
220
 
{
221
 
        return(page_get_free_space_of_empty(comp));
222
 
}
223
 
 
224
217
/****************************************************************
225
 
Allocates a block of memory from an index page. */
226
 
 
 
218
Allocates a block of memory from the heap of an index page. */
 
219
UNIV_INTERN
227
220
byte*
228
 
page_mem_alloc(
229
 
/*===========*/
 
221
page_mem_alloc_heap(
 
222
/*================*/
230
223
                                /* out: pointer to start of allocated
231
224
                                buffer, or NULL if allocation fails */
232
 
        page_t*         page,   /* in: index page */
233
 
        ulint           need,   /* in: number of bytes needed */
234
 
        dict_index_t*   index,  /* in: record descriptor */
 
225
        page_t*         page,   /* in/out: index page */
 
226
        page_zip_des_t* page_zip,/* in/out: compressed page with enough
 
227
                                space available for inserting the record,
 
228
                                or NULL */
 
229
        ulint           need,   /* in: total number of bytes needed */
235
230
        ulint*          heap_no)/* out: this contains the heap number
236
231
                                of the allocated record
237
232
                                if allocation succeeds */
238
233
{
239
 
        rec_t*  rec;
240
234
        byte*   block;
241
235
        ulint   avl_space;
242
 
        ulint   garbage;
243
236
 
244
237
        ut_ad(page && heap_no);
245
238
 
246
 
        /* If there are records in the free list, look if the first is
247
 
        big enough */
248
 
 
249
 
        rec = page_header_get_ptr(page, PAGE_FREE);
250
 
 
251
 
        if (rec) {
252
 
                mem_heap_t*     heap            = NULL;
253
 
                ulint           offsets_[REC_OFFS_NORMAL_SIZE];
254
 
                ulint*          offsets         = offsets_;
255
 
                *offsets_ = (sizeof offsets_) / sizeof *offsets_;
256
 
 
257
 
                offsets = rec_get_offsets(rec, index, offsets,
258
 
                                          ULINT_UNDEFINED, &heap);
259
 
 
260
 
                if (rec_offs_size(offsets) >= need) {
261
 
                        page_header_set_ptr(page, PAGE_FREE,
262
 
                                            page_rec_get_next(rec));
263
 
 
264
 
                        garbage = page_header_get_field(page, PAGE_GARBAGE);
265
 
                        ut_ad(garbage >= need);
266
 
 
267
 
                        page_header_set_field(page, PAGE_GARBAGE,
268
 
                                              garbage - need);
269
 
 
270
 
                        *heap_no = rec_get_heap_no(rec, page_is_comp(page));
271
 
 
272
 
                        block = rec_get_start(rec, offsets);
273
 
                        if (UNIV_LIKELY_NULL(heap)) {
274
 
                                mem_heap_free(heap);
275
 
                        }
276
 
                        return(block);
277
 
                }
278
 
 
279
 
                if (UNIV_LIKELY_NULL(heap)) {
280
 
                        mem_heap_free(heap);
281
 
                }
282
 
        }
283
 
 
284
 
        /* Could not find space from the free list, try top of heap */
285
 
 
286
239
        avl_space = page_get_max_insert_size(page, 1);
287
240
 
288
241
        if (avl_space >= need) {
289
242
                block = page_header_get_ptr(page, PAGE_HEAP_TOP);
290
243
 
291
 
                page_header_set_ptr(page, PAGE_HEAP_TOP, block + need);
 
244
                page_header_set_ptr(page, page_zip, PAGE_HEAP_TOP,
 
245
                                    block + need);
292
246
                *heap_no = page_dir_get_n_heap(page);
293
247
 
294
 
                page_dir_set_n_heap(page, 1 + *heap_no);
 
248
                page_dir_set_n_heap(page, page_zip, 1 + *heap_no);
295
249
 
296
250
                return(block);
297
251
        }
308
262
        buf_frame_t*    frame,  /* in: a buffer frame where the page is
309
263
                                created */
310
264
        mtr_t*          mtr,    /* in: mini-transaction handle */
311
 
        ulint           comp)   /* in: nonzero=compact page format */
 
265
        ibool           comp)   /* in: TRUE=compact page format */
312
266
{
313
267
        mlog_write_initial_log_record(frame, comp
314
268
                                      ? MLOG_COMP_PAGE_CREATE
317
271
 
318
272
/***************************************************************
319
273
Parses a redo log record of creating a page. */
320
 
 
 
274
UNIV_INTERN
321
275
byte*
322
276
page_parse_create(
323
277
/*==============*/
324
 
                        /* out: end of log record or NULL */
325
 
        byte*   ptr,    /* in: buffer */
326
 
        byte*   end_ptr __attribute__((unused)), /* in: buffer end */
327
 
        ulint   comp,   /* in: nonzero=compact page format */
328
 
        page_t* page,   /* in: page or NULL */
329
 
        mtr_t*  mtr)    /* in: mtr or NULL */
 
278
                                /* out: end of log record or NULL */
 
279
        byte*           ptr,    /* in: buffer */
 
280
        byte*           end_ptr __attribute__((unused)), /* in: buffer end */
 
281
        ulint           comp,   /* in: nonzero=compact page format */
 
282
        buf_block_t*    block,  /* in: block or NULL */
 
283
        mtr_t*          mtr)    /* in: mtr or NULL */
330
284
{
331
285
        ut_ad(ptr && end_ptr);
332
286
 
333
287
        /* The record is empty, except for the record initial part */
334
288
 
335
 
        if (page) {
336
 
                page_create(page, mtr, comp);
 
289
        if (block) {
 
290
                page_create(block, mtr, comp);
337
291
        }
338
292
 
339
293
        return(ptr);
341
295
 
342
296
/**************************************************************
343
297
The index page creation function. */
344
 
 
 
298
static
345
299
page_t*
346
 
page_create(
347
 
/*========*/
348
 
                                /* out: pointer to the page */
349
 
        buf_frame_t*    frame,  /* in: a buffer frame where the page is
350
 
                                created */
351
 
        mtr_t*          mtr,    /* in: mini-transaction handle */
352
 
        ulint           comp)   /* in: nonzero=compact page format */
 
300
page_create_low(
 
301
/*============*/
 
302
                                        /* out: pointer to the page */
 
303
        buf_block_t*    block,          /* in: a buffer block where the
 
304
                                        page is created */
 
305
        ulint           comp)           /* in: nonzero=compact page format */
353
306
{
354
307
        page_dir_slot_t* slot;
355
308
        mem_heap_t*     heap;
362
315
        dict_index_t*   index;
363
316
        ulint*          offsets;
364
317
 
365
 
        index = comp ? srv_sys->dummy_ind2 : srv_sys->dummy_ind1;
366
 
 
367
 
        ut_ad(frame && mtr);
 
318
        ut_ad(block);
368
319
#if PAGE_BTR_IBUF_FREE_LIST + FLST_BASE_NODE_SIZE > PAGE_DATA
369
320
# error "PAGE_BTR_IBUF_FREE_LIST + FLST_BASE_NODE_SIZE > PAGE_DATA"
370
321
#endif
372
323
# error "PAGE_BTR_IBUF_FREE_LIST_NODE + FLST_NODE_SIZE > PAGE_DATA"
373
324
#endif
374
325
 
 
326
        /* The infimum and supremum records use a dummy index. */
 
327
        if (UNIV_LIKELY(comp)) {
 
328
                index = srv_sys->dummy_ind2;
 
329
        } else {
 
330
                index = srv_sys->dummy_ind1;
 
331
        }
 
332
 
375
333
        /* 1. INCREMENT MODIFY CLOCK */
376
 
        buf_frame_modify_clock_inc(frame);
377
 
 
378
 
        /* 2. WRITE LOG INFORMATION */
379
 
        page_create_write_log(frame, mtr, comp);
380
 
 
381
 
        page = frame;
 
334
        buf_block_modify_clock_inc(block);
 
335
 
 
336
        page = buf_block_get_frame(block);
382
337
 
383
338
        fil_page_set_type(page, FIL_PAGE_INDEX);
384
339
 
399
354
 
400
355
        heap_top = page + PAGE_DATA;
401
356
 
402
 
        infimum_rec = rec_convert_dtuple_to_rec(heap_top, index, tuple);
403
 
 
404
 
        ut_a(infimum_rec == page
405
 
             + (comp ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
406
 
 
407
 
        rec_set_n_owned(infimum_rec, comp, 1);
408
 
        rec_set_heap_no(infimum_rec, comp, 0);
 
357
        infimum_rec = rec_convert_dtuple_to_rec(heap_top, index, tuple, 0);
 
358
 
 
359
        if (UNIV_LIKELY(comp)) {
 
360
                ut_a(infimum_rec == page + PAGE_NEW_INFIMUM);
 
361
 
 
362
                rec_set_n_owned_new(infimum_rec, NULL, 1);
 
363
                rec_set_heap_no_new(infimum_rec, 0);
 
364
        } else {
 
365
                ut_a(infimum_rec == page + PAGE_OLD_INFIMUM);
 
366
 
 
367
                rec_set_n_owned_old(infimum_rec, 1);
 
368
                rec_set_heap_no_old(infimum_rec, 0);
 
369
        }
 
370
 
409
371
        offsets = rec_get_offsets(infimum_rec, index, NULL,
410
372
                                  ULINT_UNDEFINED, &heap);
411
373
 
421
383
        dtype_set(dfield_get_type(field),
422
384
                  DATA_VARCHAR, DATA_ENGLISH | DATA_NOT_NULL, comp ? 8 : 9);
423
385
 
424
 
        supremum_rec = rec_convert_dtuple_to_rec(heap_top, index, tuple);
425
 
 
426
 
        ut_a(supremum_rec == page
427
 
             + (comp ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM));
428
 
 
429
 
        rec_set_n_owned(supremum_rec, comp, 1);
430
 
        rec_set_heap_no(supremum_rec, comp, 1);
 
386
        supremum_rec = rec_convert_dtuple_to_rec(heap_top, index, tuple, 0);
 
387
 
 
388
        if (UNIV_LIKELY(comp)) {
 
389
                ut_a(supremum_rec == page + PAGE_NEW_SUPREMUM);
 
390
 
 
391
                rec_set_n_owned_new(supremum_rec, NULL, 1);
 
392
                rec_set_heap_no_new(supremum_rec, 1);
 
393
        } else {
 
394
                ut_a(supremum_rec == page + PAGE_OLD_SUPREMUM);
 
395
 
 
396
                rec_set_n_owned_old(supremum_rec, 1);
 
397
                rec_set_heap_no_old(supremum_rec, 1);
 
398
        }
431
399
 
432
400
        offsets = rec_get_offsets(supremum_rec, index, offsets,
433
401
                                  ULINT_UNDEFINED, &heap);
440
408
 
441
409
        /* 4. INITIALIZE THE PAGE */
442
410
 
443
 
        page_header_set_field(page, PAGE_N_DIR_SLOTS, 2);
444
 
        page_header_set_ptr(page, PAGE_HEAP_TOP, heap_top);
445
 
        page_header_set_field(page, PAGE_N_HEAP, comp ? 0x8002 : 2);
446
 
        page_header_set_ptr(page, PAGE_FREE, NULL);
447
 
        page_header_set_field(page, PAGE_GARBAGE, 0);
448
 
        page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
449
 
        page_header_set_field(page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
450
 
        page_header_set_field(page, PAGE_N_DIRECTION, 0);
451
 
        page_header_set_field(page, PAGE_N_RECS, 0);
452
 
        page_set_max_trx_id(page, ut_dulint_zero);
 
411
        page_header_set_field(page, NULL, PAGE_N_DIR_SLOTS, 2);
 
412
        page_header_set_ptr(page, NULL, PAGE_HEAP_TOP, heap_top);
 
413
        page_header_set_field(page, NULL, PAGE_N_HEAP, comp
 
414
                              ? 0x8000 | PAGE_HEAP_NO_USER_LOW
 
415
                              : PAGE_HEAP_NO_USER_LOW);
 
416
        page_header_set_ptr(page, NULL, PAGE_FREE, NULL);
 
417
        page_header_set_field(page, NULL, PAGE_GARBAGE, 0);
 
418
        page_header_set_ptr(page, NULL, PAGE_LAST_INSERT, NULL);
 
419
        page_header_set_field(page, NULL, PAGE_DIRECTION, PAGE_NO_DIRECTION);
 
420
        page_header_set_field(page, NULL, PAGE_N_DIRECTION, 0);
 
421
        page_header_set_field(page, NULL, PAGE_N_RECS, 0);
 
422
        page_set_max_trx_id(block, NULL, ut_dulint_zero);
453
423
        memset(heap_top, 0, UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START
454
 
               - (heap_top - page));
 
424
               - page_offset(heap_top));
455
425
 
456
426
        /* 5. SET POINTERS IN RECORDS AND DIR SLOTS */
457
427
 
465
435
 
466
436
        /* Set the next pointers in infimum and supremum */
467
437
 
468
 
        rec_set_next_offs(infimum_rec, comp, (ulint)(supremum_rec - page));
469
 
        rec_set_next_offs(supremum_rec, comp, 0);
 
438
        if (UNIV_LIKELY(comp)) {
 
439
                rec_set_next_offs_new(infimum_rec, PAGE_NEW_SUPREMUM);
 
440
                rec_set_next_offs_new(supremum_rec, 0);
 
441
        } else {
 
442
                rec_set_next_offs_old(infimum_rec, PAGE_OLD_SUPREMUM);
 
443
                rec_set_next_offs_old(supremum_rec, 0);
 
444
        }
 
445
 
 
446
        return(page);
 
447
}
 
448
 
 
449
/**************************************************************
 
450
Create an uncompressed B-tree index page. */
 
451
UNIV_INTERN
 
452
page_t*
 
453
page_create(
 
454
/*========*/
 
455
                                        /* out: pointer to the page */
 
456
        buf_block_t*    block,          /* in: a buffer block where the
 
457
                                        page is created */
 
458
        mtr_t*          mtr,            /* in: mini-transaction handle */
 
459
        ulint           comp)           /* in: nonzero=compact page format */
 
460
{
 
461
        page_create_write_log(buf_block_get_frame(block), mtr, comp);
 
462
        return(page_create_low(block, comp));
 
463
}
 
464
 
 
465
/**************************************************************
 
466
Create a compressed B-tree index page. */
 
467
UNIV_INTERN
 
468
page_t*
 
469
page_create_zip(
 
470
/*============*/
 
471
                                        /* out: pointer to the page */
 
472
        buf_block_t*    block,          /* in/out: a buffer frame where the
 
473
                                        page is created */
 
474
        dict_index_t*   index,          /* in: the index of the page */
 
475
        ulint           level,          /* in: the B-tree level of the page */
 
476
        mtr_t*          mtr)            /* in: mini-transaction handle */
 
477
{
 
478
        page_t*         page;
 
479
        page_zip_des_t* page_zip        = buf_block_get_page_zip(block);
 
480
 
 
481
        ut_ad(block);
 
482
        ut_ad(page_zip);
 
483
        ut_ad(index);
 
484
        ut_ad(dict_table_is_comp(index->table));
 
485
 
 
486
        page = page_create_low(block, TRUE);
 
487
        mach_write_to_2(page + PAGE_HEADER + PAGE_LEVEL, level);
 
488
 
 
489
        if (UNIV_UNLIKELY(!page_zip_compress(page_zip, page, index, mtr))) {
 
490
                /* The compression of a newly created page
 
491
                should always succeed. */
 
492
                ut_error;
 
493
        }
470
494
 
471
495
        return(page);
472
496
}
473
497
 
474
498
/*****************************************************************
475
499
Differs from page_copy_rec_list_end, because this function does not
476
 
touch the lock table and max trx id on page. */
477
 
 
 
500
touch the lock table and max trx id on page or compress the page. */
 
501
UNIV_INTERN
478
502
void
479
503
page_copy_rec_list_end_no_locks(
480
504
/*============================*/
481
 
        page_t*         new_page,       /* in: index page to copy to */
482
 
        page_t*         page,           /* in: index page */
 
505
        buf_block_t*    new_block,      /* in: index page to copy to */
 
506
        buf_block_t*    block,          /* in: index page of rec */
483
507
        rec_t*          rec,            /* in: record on page */
484
508
        dict_index_t*   index,          /* in: record descriptor */
485
509
        mtr_t*          mtr)            /* in: mtr */
486
510
{
 
511
        page_t*         new_page        = buf_block_get_frame(new_block);
487
512
        page_cur_t      cur1;
488
 
        page_cur_t      cur2;
489
 
        rec_t*          sup;
 
513
        rec_t*          cur2;
490
514
        mem_heap_t*     heap            = NULL;
491
515
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
492
516
        ulint*          offsets         = offsets_;
493
 
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
 
517
        rec_offs_init(offsets_);
494
518
 
495
 
        page_cur_position(rec, &cur1);
 
519
        page_cur_position(rec, block, &cur1);
496
520
 
497
521
        if (page_cur_is_before_first(&cur1)) {
498
522
 
501
525
 
502
526
        ut_a((ibool)!!page_is_comp(new_page)
503
527
             == dict_table_is_comp(index->table));
504
 
        ut_a(page_is_comp(new_page) == page_is_comp(page));
 
528
        ut_a(page_is_comp(new_page) == page_rec_is_comp(rec));
505
529
        ut_a(mach_read_from_2(new_page + UNIV_PAGE_SIZE - 10) == (ulint)
506
 
             (page_is_comp(new_page)
507
 
              ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
 
530
             (page_is_comp(new_page) ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
508
531
 
509
 
        page_cur_set_before_first(new_page, &cur2);
 
532
        cur2 = page_get_infimum_rec(buf_block_get_frame(new_block));
510
533
 
511
534
        /* Copy records from the original page to the new page */
512
535
 
513
 
        sup = page_get_supremum_rec(page);
514
 
 
515
 
        for (;;) {
 
536
        while (!page_cur_is_after_last(&cur1)) {
516
537
                rec_t*  cur1_rec = page_cur_get_rec(&cur1);
517
 
                if (cur1_rec == sup) {
518
 
                        break;
519
 
                }
 
538
                rec_t*  ins_rec;
520
539
                offsets = rec_get_offsets(cur1_rec, index, offsets,
521
540
                                          ULINT_UNDEFINED, &heap);
522
 
                if (UNIV_UNLIKELY(!page_cur_rec_insert(&cur2, cur1_rec, index,
523
 
                                                       offsets, mtr))) {
 
541
                ins_rec = page_cur_insert_rec_low(cur2, index,
 
542
                                                  cur1_rec, offsets, mtr);
 
543
                if (UNIV_UNLIKELY(!ins_rec)) {
524
544
                        /* Track an assertion failure reported on the mailing
525
545
                        list on June 18th, 2003 */
526
546
 
527
 
                        buf_page_print(new_page);
528
 
                        buf_page_print(page);
 
547
                        buf_page_print(new_page, 0);
 
548
                        buf_page_print(page_align(rec), 0);
529
549
                        ut_print_timestamp(stderr);
530
550
 
531
551
                        fprintf(stderr,
532
552
                                "InnoDB: rec offset %lu, cur1 offset %lu,"
533
553
                                " cur2 offset %lu\n",
534
 
                                (ulong)(rec - page),
535
 
                                (ulong)(page_cur_get_rec(&cur1) - page),
536
 
                                (ulong)(page_cur_get_rec(&cur2) - new_page));
537
 
 
 
554
                                (ulong) page_offset(rec),
 
555
                                (ulong) page_offset(page_cur_get_rec(&cur1)),
 
556
                                (ulong) page_offset(cur2));
538
557
                        ut_error;
539
558
                }
540
559
 
541
560
                page_cur_move_to_next(&cur1);
542
 
                page_cur_move_to_next(&cur2);
 
561
                cur2 = ins_rec;
543
562
        }
544
563
 
545
564
        if (UNIV_LIKELY_NULL(heap)) {
551
570
Copies records from page to new_page, from a given record onward,
552
571
including that record. Infimum and supremum records are not copied.
553
572
The records are copied to the start of the record list on new_page. */
554
 
 
555
 
void
 
573
UNIV_INTERN
 
574
rec_t*
556
575
page_copy_rec_list_end(
557
576
/*===================*/
558
 
        page_t*         new_page,       /* in: index page to copy to */
559
 
        page_t*         page,           /* in: index page */
 
577
                                        /* out: pointer to the original
 
578
                                        successor of the infimum record
 
579
                                        on new_page, or NULL on zip overflow
 
580
                                        (new_block will be decompressed) */
 
581
        buf_block_t*    new_block,      /* in/out: index page to copy to */
 
582
        buf_block_t*    block,          /* in: index page containing rec */
560
583
        rec_t*          rec,            /* in: record on page */
561
584
        dict_index_t*   index,          /* in: record descriptor */
562
585
        mtr_t*          mtr)            /* in: mtr */
563
586
{
564
 
        if (page_dir_get_n_heap(new_page) == 2) {
565
 
                page_copy_rec_list_end_to_created_page(new_page, page, rec,
 
587
        page_t*         new_page        = buf_block_get_frame(new_block);
 
588
        page_zip_des_t* new_page_zip    = buf_block_get_page_zip(new_block);
 
589
        page_t*         page            = page_align(rec);
 
590
        rec_t*          ret             = page_rec_get_next(
 
591
                page_get_infimum_rec(new_page));
 
592
        ulint           log_mode        = 0; /* remove warning */
 
593
 
 
594
        /* page_zip_validate() will fail here if btr_compress()
 
595
        sets FIL_PAGE_PREV to FIL_NULL */
 
596
        ut_ad(buf_block_get_frame(block) == page);
 
597
        ut_ad(page_is_leaf(page) == page_is_leaf(new_page));
 
598
        ut_ad(page_is_comp(page) == page_is_comp(new_page));
 
599
 
 
600
        if (UNIV_LIKELY_NULL(new_page_zip)) {
 
601
                log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
 
602
        }
 
603
 
 
604
        if (page_dir_get_n_heap(new_page) == PAGE_HEAP_NO_USER_LOW) {
 
605
                page_copy_rec_list_end_to_created_page(new_page, rec,
566
606
                                                       index, mtr);
567
607
        } else {
568
 
                page_copy_rec_list_end_no_locks(new_page, page, rec,
 
608
                page_copy_rec_list_end_no_locks(new_block, block, rec,
569
609
                                                index, mtr);
570
610
        }
571
611
 
 
612
        if (UNIV_LIKELY_NULL(new_page_zip)) {
 
613
                mtr_set_log_mode(mtr, log_mode);
 
614
 
 
615
                if (UNIV_UNLIKELY
 
616
                    (!page_zip_compress(new_page_zip, new_page, index, mtr))) {
 
617
                        /* Before trying to reorganize the page,
 
618
                        store the number of preceding records on the page. */
 
619
                        ulint   ret_pos
 
620
                                = page_rec_get_n_recs_before(ret);
 
621
 
 
622
                        if (UNIV_UNLIKELY
 
623
                            (!page_zip_reorganize(new_block, index, mtr))) {
 
624
 
 
625
                                if (UNIV_UNLIKELY
 
626
                                    (!page_zip_decompress(new_page_zip,
 
627
                                                          new_page))) {
 
628
                                        ut_error;
 
629
                                }
 
630
                                ut_ad(page_validate(new_page, index));
 
631
                                return(NULL);
 
632
                        } else {
 
633
                                /* The page was reorganized:
 
634
                                Seek to ret_pos. */
 
635
                                ret = new_page + PAGE_NEW_INFIMUM;
 
636
 
 
637
                                do {
 
638
                                        ret = rec_get_next_ptr(ret, TRUE);
 
639
                                } while (--ret_pos);
 
640
                        }
 
641
                }
 
642
        }
 
643
 
572
644
        /* Update the lock table, MAX_TRX_ID, and possible hash index */
573
645
 
574
 
        lock_move_rec_list_end(new_page, page, rec);
575
 
 
576
 
        page_update_max_trx_id(new_page, page_get_max_trx_id(page));
577
 
 
578
 
        btr_search_move_or_delete_hash_entries(new_page, page, index);
 
646
        lock_move_rec_list_end(new_block, block, rec);
 
647
 
 
648
        page_update_max_trx_id(new_block, new_page_zip,
 
649
                               page_get_max_trx_id(page));
 
650
 
 
651
        btr_search_move_or_delete_hash_entries(new_block, block, index);
 
652
 
 
653
        return(ret);
579
654
}
580
655
 
581
656
/*****************************************************************
582
657
Copies records from page to new_page, up to the given record,
583
658
NOT including that record. Infimum and supremum records are not copied.
584
659
The records are copied to the end of the record list on new_page. */
585
 
 
586
 
void
 
660
UNIV_INTERN
 
661
rec_t*
587
662
page_copy_rec_list_start(
588
663
/*=====================*/
589
 
        page_t*         new_page,       /* in: index page to copy to */
590
 
        page_t*         page,           /* in: index page */
 
664
                                        /* out: pointer to the original
 
665
                                        predecessor of the supremum record
 
666
                                        on new_page, or NULL on zip overflow
 
667
                                        (new_block will be decompressed) */
 
668
        buf_block_t*    new_block,      /* in/out: index page to copy to */
 
669
        buf_block_t*    block,          /* in: index page containing rec */
591
670
        rec_t*          rec,            /* in: record on page */
592
671
        dict_index_t*   index,          /* in: record descriptor */
593
672
        mtr_t*          mtr)            /* in: mtr */
594
673
{
 
674
        page_t*         new_page        = buf_block_get_frame(new_block);
 
675
        page_zip_des_t* new_page_zip    = buf_block_get_page_zip(new_block);
595
676
        page_cur_t      cur1;
596
 
        page_cur_t      cur2;
597
 
        rec_t*          old_end;
 
677
        rec_t*          cur2;
 
678
        ulint           log_mode        = 0 /* remove warning */;
598
679
        mem_heap_t*     heap            = NULL;
 
680
        rec_t*          ret
 
681
                = page_rec_get_prev(page_get_supremum_rec(new_page));
599
682
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
600
683
        ulint*          offsets         = offsets_;
601
 
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
602
 
 
603
 
        page_cur_set_before_first(page, &cur1);
604
 
 
605
 
        if (rec == page_cur_get_rec(&cur1)) {
606
 
 
607
 
                return;
608
 
        }
609
 
 
 
684
        rec_offs_init(offsets_);
 
685
 
 
686
        if (page_rec_is_infimum(rec)) {
 
687
 
 
688
                return(ret);
 
689
        }
 
690
 
 
691
        if (UNIV_LIKELY_NULL(new_page_zip)) {
 
692
                log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
 
693
        }
 
694
 
 
695
        page_cur_set_before_first(block, &cur1);
610
696
        page_cur_move_to_next(&cur1);
611
697
 
612
 
        page_cur_set_after_last(new_page, &cur2);
613
 
        page_cur_move_to_prev(&cur2);
614
 
        old_end = page_cur_get_rec(&cur2);
 
698
        cur2 = ret;
615
699
 
616
700
        /* Copy records from the original page to the new page */
617
701
 
618
702
        while (page_cur_get_rec(&cur1) != rec) {
619
 
                rec_t*  ins_rec;
620
703
                rec_t*  cur1_rec = page_cur_get_rec(&cur1);
621
704
                offsets = rec_get_offsets(cur1_rec, index, offsets,
622
705
                                          ULINT_UNDEFINED, &heap);
623
 
                ins_rec = page_cur_rec_insert(&cur2, cur1_rec, index,
624
 
                                              offsets, mtr);
625
 
                ut_a(ins_rec);
 
706
                cur2 = page_cur_insert_rec_low(cur2, index,
 
707
                                               cur1_rec, offsets, mtr);
 
708
                ut_a(cur2);
626
709
 
627
710
                page_cur_move_to_next(&cur1);
628
 
                page_cur_move_to_next(&cur2);
629
711
        }
630
712
 
631
 
        /* Update the lock table, MAX_TRX_ID, and possible hash index */
632
 
 
633
 
        lock_move_rec_list_start(new_page, page, rec, old_end);
634
 
 
635
 
        page_update_max_trx_id(new_page, page_get_max_trx_id(page));
636
 
 
637
 
        btr_search_move_or_delete_hash_entries(new_page, page, index);
638
 
 
639
713
        if (UNIV_LIKELY_NULL(heap)) {
640
714
                mem_heap_free(heap);
641
715
        }
 
716
 
 
717
        if (UNIV_LIKELY_NULL(new_page_zip)) {
 
718
                mtr_set_log_mode(mtr, log_mode);
 
719
 
 
720
                if (UNIV_UNLIKELY
 
721
                    (!page_zip_compress(new_page_zip, new_page, index, mtr))) {
 
722
                        /* Before trying to reorganize the page,
 
723
                        store the number of preceding records on the page. */
 
724
                        ulint   ret_pos
 
725
                                = page_rec_get_n_recs_before(ret);
 
726
 
 
727
                        if (UNIV_UNLIKELY
 
728
                            (!page_zip_reorganize(new_block, index, mtr))) {
 
729
 
 
730
                                if (UNIV_UNLIKELY
 
731
                                    (!page_zip_decompress(new_page_zip,
 
732
                                                          new_page))) {
 
733
                                        ut_error;
 
734
                                }
 
735
                                ut_ad(page_validate(new_page, index));
 
736
                                return(NULL);
 
737
                        } else {
 
738
                                /* The page was reorganized:
 
739
                                Seek to ret_pos. */
 
740
                                ret = new_page + PAGE_NEW_INFIMUM;
 
741
 
 
742
                                do {
 
743
                                        ret = rec_get_next_ptr(ret, TRUE);
 
744
                                } while (--ret_pos);
 
745
                        }
 
746
                }
 
747
        }
 
748
 
 
749
        /* Update MAX_TRX_ID, the lock table, and possible hash index */
 
750
 
 
751
        page_update_max_trx_id(new_block, new_page_zip,
 
752
                               page_get_max_trx_id(page_align(rec)));
 
753
 
 
754
        lock_move_rec_list_start(new_block, block, rec, ret);
 
755
 
 
756
        btr_search_move_or_delete_hash_entries(new_block, block, index);
 
757
 
 
758
        return(ret);
642
759
}
643
760
 
644
761
/**************************************************************
669
786
 
670
787
/**************************************************************
671
788
Parses a log record of a record list end or start deletion. */
672
 
 
 
789
UNIV_INTERN
673
790
byte*
674
791
page_parse_delete_rec_list(
675
792
/*=======================*/
680
797
                                MLOG_COMP_LIST_START_DELETE */
681
798
        byte*           ptr,    /* in: buffer */
682
799
        byte*           end_ptr,/* in: buffer end */
 
800
        buf_block_t*    block,  /* in/out: buffer block or NULL */
683
801
        dict_index_t*   index,  /* in: record descriptor */
684
 
        page_t*         page,   /* in: page or NULL */
685
802
        mtr_t*          mtr)    /* in: mtr or NULL */
686
803
{
 
804
        page_t* page;
687
805
        ulint   offset;
688
806
 
689
807
        ut_ad(type == MLOG_LIST_END_DELETE
701
819
        offset = mach_read_from_2(ptr);
702
820
        ptr += 2;
703
821
 
704
 
        if (!page) {
 
822
        if (!block) {
705
823
 
706
824
                return(ptr);
707
825
        }
708
826
 
 
827
        page = buf_block_get_frame(block);
 
828
 
709
829
        ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
710
830
 
711
831
        if (type == MLOG_LIST_END_DELETE
712
832
            || type == MLOG_COMP_LIST_END_DELETE) {
713
 
                page_delete_rec_list_end(page, page + offset, index,
714
 
                                         ULINT_UNDEFINED,
715
 
                                         ULINT_UNDEFINED, mtr);
 
833
                page_delete_rec_list_end(page + offset, block, index,
 
834
                                         ULINT_UNDEFINED, ULINT_UNDEFINED,
 
835
                                         mtr);
716
836
        } else {
717
 
                page_delete_rec_list_start(page, page + offset, index, mtr);
 
837
                page_delete_rec_list_start(page + offset, block, index, mtr);
718
838
        }
719
839
 
720
840
        return(ptr);
723
843
/*****************************************************************
724
844
Deletes records from a page from a given record onward, including that record.
725
845
The infimum and supremum records are not deleted. */
726
 
 
 
846
UNIV_INTERN
727
847
void
728
848
page_delete_rec_list_end(
729
849
/*=====================*/
730
 
        page_t*         page,   /* in: index page */
731
 
        rec_t*          rec,    /* in: record on page */
 
850
        rec_t*          rec,    /* in: pointer to record on page */
 
851
        buf_block_t*    block,  /* in: buffer block of the page */
732
852
        dict_index_t*   index,  /* in: record descriptor */
733
853
        ulint           n_recs, /* in: number of records to delete,
734
854
                                or ULINT_UNDEFINED if not known */
737
857
                                delete, or ULINT_UNDEFINED if not known */
738
858
        mtr_t*          mtr)    /* in: mtr */
739
859
{
740
 
        page_dir_slot_t* slot;
741
 
        ulint   slot_index;
742
 
        rec_t*  last_rec;
743
 
        rec_t*  prev_rec;
744
 
        rec_t*  free;
745
 
        rec_t*  rec2;
746
 
        ulint   count;
747
 
        ulint   n_owned;
748
 
        rec_t*  sup;
749
 
        ulint   comp;
 
860
        page_dir_slot_t*slot;
 
861
        ulint           slot_index;
 
862
        rec_t*          last_rec;
 
863
        rec_t*          prev_rec;
 
864
        ulint           n_owned;
 
865
        page_zip_des_t* page_zip        = buf_block_get_page_zip(block);
 
866
        page_t*         page            = page_align(rec);
 
867
        mem_heap_t*     heap            = NULL;
 
868
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
869
        ulint*          offsets         = offsets_;
 
870
        rec_offs_init(offsets_);
 
871
 
 
872
        ut_ad(size == ULINT_UNDEFINED || size < UNIV_PAGE_SIZE);
 
873
        ut_ad(!page_zip || page_rec_is_comp(rec));
 
874
#ifdef UNIV_ZIP_DEBUG
 
875
        ut_a(!page_zip || page_zip_validate(page_zip, page));
 
876
#endif /* UNIV_ZIP_DEBUG */
 
877
 
 
878
        if (page_rec_is_infimum(rec)) {
 
879
                rec = page_rec_get_next(rec);
 
880
        }
 
881
 
 
882
        if (page_rec_is_supremum(rec)) {
 
883
 
 
884
                return;
 
885
        }
750
886
 
751
887
        /* Reset the last insert info in the page header and increment
752
888
        the modify clock for the frame */
753
889
 
754
 
        ut_ad(size == ULINT_UNDEFINED || size < UNIV_PAGE_SIZE);
755
 
        page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
 
890
        page_header_set_ptr(page, page_zip, PAGE_LAST_INSERT, NULL);
756
891
 
757
892
        /* The page gets invalid for optimistic searches: increment the
758
893
        frame modify clock */
759
894
 
760
 
        buf_frame_modify_clock_inc(page);
761
 
 
762
 
        sup = page_get_supremum_rec(page);
763
 
 
764
 
        comp = page_is_comp(page);
765
 
        if (page_rec_is_infimum_low(rec - page)) {
766
 
                rec = page_rec_get_next(rec);
767
 
        }
768
 
 
769
 
        page_delete_rec_list_write_log(rec, index, comp
 
895
        buf_block_modify_clock_inc(block);
 
896
 
 
897
        page_delete_rec_list_write_log(rec, index, page_is_comp(page)
770
898
                                       ? MLOG_COMP_LIST_END_DELETE
771
899
                                       : MLOG_LIST_END_DELETE, mtr);
772
900
 
773
 
        if (rec == sup) {
774
 
 
 
901
        if (UNIV_LIKELY_NULL(page_zip)) {
 
902
                ulint           log_mode;
 
903
 
 
904
                ut_a(page_is_comp(page));
 
905
                /* Individual deletes are not logged */
 
906
 
 
907
                log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
 
908
 
 
909
                do {
 
910
                        page_cur_t      cur;
 
911
                        page_cur_position(rec, block, &cur);
 
912
 
 
913
                        offsets = rec_get_offsets(rec, index, offsets,
 
914
                                                  ULINT_UNDEFINED, &heap);
 
915
                        rec = rec_get_next_ptr(rec, TRUE);
 
916
#ifdef UNIV_ZIP_DEBUG
 
917
                        ut_a(page_zip_validate(page_zip, page));
 
918
#endif /* UNIV_ZIP_DEBUG */
 
919
                        page_cur_delete_rec(&cur, index, offsets, mtr);
 
920
                } while (page_offset(rec) != PAGE_NEW_SUPREMUM);
 
921
 
 
922
                if (UNIV_LIKELY_NULL(heap)) {
 
923
                        mem_heap_free(heap);
 
924
                }
 
925
 
 
926
                /* Restore log mode */
 
927
 
 
928
                mtr_set_log_mode(mtr, log_mode);
775
929
                return;
776
930
        }
777
931
 
778
932
        prev_rec = page_rec_get_prev(rec);
779
933
 
780
 
        last_rec = page_rec_get_prev(sup);
 
934
        last_rec = page_rec_get_prev(page_get_supremum_rec(page));
781
935
 
782
936
        if ((size == ULINT_UNDEFINED) || (n_recs == ULINT_UNDEFINED)) {
783
 
                mem_heap_t*     heap            = NULL;
784
 
                ulint           offsets_[REC_OFFS_NORMAL_SIZE];
785
 
                ulint*          offsets         = offsets_;
786
 
                *offsets_ = (sizeof offsets_) / sizeof *offsets_;
 
937
                rec_t*          rec2            = rec;
787
938
                /* Calculate the sum of sizes and the number of records */
788
939
                size = 0;
789
940
                n_recs = 0;
790
 
                rec2 = rec;
791
941
 
792
 
                while (rec2 != sup) {
 
942
                do {
793
943
                        ulint   s;
794
944
                        offsets = rec_get_offsets(rec2, index, offsets,
795
945
                                                  ULINT_UNDEFINED, &heap);
801
951
                        n_recs++;
802
952
 
803
953
                        rec2 = page_rec_get_next(rec2);
804
 
                }
 
954
                } while (!page_rec_is_supremum(rec2));
805
955
 
806
956
                if (UNIV_LIKELY_NULL(heap)) {
807
957
                        mem_heap_free(heap);
814
964
        of the records owned by the supremum record, as it is allowed to be
815
965
        less than PAGE_DIR_SLOT_MIN_N_OWNED */
816
966
 
817
 
        rec2 = rec;
818
 
        count = 0;
819
 
 
820
 
        while (rec_get_n_owned(rec2, comp) == 0) {
821
 
                count++;
822
 
 
823
 
                rec2 = page_rec_get_next(rec2);
 
967
        if (page_is_comp(page)) {
 
968
                rec_t*  rec2    = rec;
 
969
                ulint   count   = 0;
 
970
 
 
971
                while (rec_get_n_owned_new(rec2) == 0) {
 
972
                        count++;
 
973
 
 
974
                        rec2 = rec_get_next_ptr(rec2, TRUE);
 
975
                }
 
976
 
 
977
                ut_ad(rec_get_n_owned_new(rec2) > count);
 
978
 
 
979
                n_owned = rec_get_n_owned_new(rec2) - count;
 
980
                slot_index = page_dir_find_owner_slot(rec2);
 
981
                slot = page_dir_get_nth_slot(page, slot_index);
 
982
        } else {
 
983
                rec_t*  rec2    = rec;
 
984
                ulint   count   = 0;
 
985
 
 
986
                while (rec_get_n_owned_old(rec2) == 0) {
 
987
                        count++;
 
988
 
 
989
                        rec2 = rec_get_next_ptr(rec2, FALSE);
 
990
                }
 
991
 
 
992
                ut_ad(rec_get_n_owned_old(rec2) > count);
 
993
 
 
994
                n_owned = rec_get_n_owned_old(rec2) - count;
 
995
                slot_index = page_dir_find_owner_slot(rec2);
 
996
                slot = page_dir_get_nth_slot(page, slot_index);
824
997
        }
825
998
 
826
 
        ut_ad(rec_get_n_owned(rec2, comp) - count > 0);
827
 
 
828
 
        n_owned = rec_get_n_owned(rec2, comp) - count;
829
 
 
830
 
        slot_index = page_dir_find_owner_slot(rec2);
831
 
        slot = page_dir_get_nth_slot(page, slot_index);
832
 
 
833
 
        page_dir_slot_set_rec(slot, sup);
834
 
        page_dir_slot_set_n_owned(slot, n_owned);
835
 
 
836
 
        page_dir_set_n_slots(page, slot_index + 1);
 
999
        page_dir_slot_set_rec(slot, page_get_supremum_rec(page));
 
1000
        page_dir_slot_set_n_owned(slot, NULL, n_owned);
 
1001
 
 
1002
        page_dir_set_n_slots(page, NULL, slot_index + 1);
837
1003
 
838
1004
        /* Remove the record chain segment from the record chain */
839
1005
        page_rec_set_next(prev_rec, page_get_supremum_rec(page));
840
1006
 
841
1007
        /* Catenate the deleted chain segment to the page free list */
842
1008
 
843
 
        free = page_header_get_ptr(page, PAGE_FREE);
844
 
 
845
 
        page_rec_set_next(last_rec, free);
846
 
        page_header_set_ptr(page, PAGE_FREE, rec);
847
 
 
848
 
        page_header_set_field(page, PAGE_GARBAGE, size
 
1009
        page_rec_set_next(last_rec, page_header_get_ptr(page, PAGE_FREE));
 
1010
        page_header_set_ptr(page, NULL, PAGE_FREE, rec);
 
1011
 
 
1012
        page_header_set_field(page, NULL, PAGE_GARBAGE, size
849
1013
                              + page_header_get_field(page, PAGE_GARBAGE));
850
1014
 
851
 
        page_header_set_field(page, PAGE_N_RECS,
 
1015
        page_header_set_field(page, NULL, PAGE_N_RECS,
852
1016
                              (ulint)(page_get_n_recs(page) - n_recs));
853
1017
}
854
1018
 
855
1019
/*****************************************************************
856
1020
Deletes records from page, up to the given record, NOT including
857
1021
that record. Infimum and supremum records are not deleted. */
858
 
 
 
1022
UNIV_INTERN
859
1023
void
860
1024
page_delete_rec_list_start(
861
1025
/*=======================*/
862
 
        page_t*         page,   /* in: index page */
863
1026
        rec_t*          rec,    /* in: record on page */
 
1027
        buf_block_t*    block,  /* in: buffer block of the page */
864
1028
        dict_index_t*   index,  /* in: record descriptor */
865
1029
        mtr_t*          mtr)    /* in: mtr */
866
1030
{
870
1034
        ulint*          offsets         = offsets_;
871
1035
        mem_heap_t*     heap            = NULL;
872
1036
        byte            type;
873
 
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
874
 
 
875
 
        ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
876
 
 
877
 
        if (page_is_comp(page)) {
 
1037
 
 
1038
        rec_offs_init(offsets_);
 
1039
 
 
1040
        ut_ad((ibool) !!page_rec_is_comp(rec)
 
1041
              == dict_table_is_comp(index->table));
 
1042
        /* page_zip_validate() would detect a min_rec_mark mismatch
 
1043
        in btr_page_split_and_insert()
 
1044
        between btr_attach_half_pages() and insert_page = ...
 
1045
        when btr_page_get_split_rec_to_left() holds (direction == FSP_DOWN). */
 
1046
 
 
1047
        if (page_rec_is_infimum(rec)) {
 
1048
 
 
1049
                return;
 
1050
        }
 
1051
 
 
1052
        if (page_rec_is_comp(rec)) {
878
1053
                type = MLOG_COMP_LIST_START_DELETE;
879
1054
        } else {
880
1055
                type = MLOG_LIST_START_DELETE;
882
1057
 
883
1058
        page_delete_rec_list_write_log(rec, index, type, mtr);
884
1059
 
885
 
        page_cur_set_before_first(page, &cur1);
886
 
 
887
 
        if (rec == page_cur_get_rec(&cur1)) {
888
 
 
889
 
                return;
890
 
        }
891
 
 
 
1060
        page_cur_set_before_first(block, &cur1);
892
1061
        page_cur_move_to_next(&cur1);
893
1062
 
894
1063
        /* Individual deletes are not logged */
913
1082
/*****************************************************************
914
1083
Moves record list end to another page. Moved records include
915
1084
split_rec. */
916
 
 
917
 
void
 
1085
UNIV_INTERN
 
1086
ibool
918
1087
page_move_rec_list_end(
919
1088
/*===================*/
920
 
        page_t*         new_page,       /* in: index page where to move */
921
 
        page_t*         page,           /* in: index page */
 
1089
                                        /* out: TRUE on success; FALSE on
 
1090
                                        compression failure
 
1091
                                        (new_block will be decompressed) */
 
1092
        buf_block_t*    new_block,      /* in/out: index page where to move */
 
1093
        buf_block_t*    block,          /* in: index page from where to move */
922
1094
        rec_t*          split_rec,      /* in: first record to move */
923
1095
        dict_index_t*   index,          /* in: record descriptor */
924
1096
        mtr_t*          mtr)            /* in: mtr */
925
1097
{
926
 
        ulint   old_data_size;
927
 
        ulint   new_data_size;
928
 
        ulint   old_n_recs;
929
 
        ulint   new_n_recs;
 
1098
        page_t*         new_page        = buf_block_get_frame(new_block);
 
1099
        ulint           old_data_size;
 
1100
        ulint           new_data_size;
 
1101
        ulint           old_n_recs;
 
1102
        ulint           new_n_recs;
930
1103
 
931
1104
        old_data_size = page_get_data_size(new_page);
932
1105
        old_n_recs = page_get_n_recs(new_page);
 
1106
#ifdef UNIV_ZIP_DEBUG
 
1107
        {
 
1108
                page_zip_des_t* new_page_zip
 
1109
                        = buf_block_get_page_zip(new_block);
 
1110
                page_zip_des_t* page_zip
 
1111
                        = buf_block_get_page_zip(block);
 
1112
                ut_a(!new_page_zip == !page_zip);
 
1113
                ut_a(!new_page_zip
 
1114
                     || page_zip_validate(new_page_zip, new_page));
 
1115
                ut_a(!page_zip
 
1116
                     || page_zip_validate(page_zip, page_align(split_rec)));
 
1117
        }
 
1118
#endif /* UNIV_ZIP_DEBUG */
933
1119
 
934
 
        page_copy_rec_list_end(new_page, page, split_rec, index, mtr);
 
1120
        if (UNIV_UNLIKELY(!page_copy_rec_list_end(new_block, block,
 
1121
                                                  split_rec, index, mtr))) {
 
1122
                return(FALSE);
 
1123
        }
935
1124
 
936
1125
        new_data_size = page_get_data_size(new_page);
937
1126
        new_n_recs = page_get_n_recs(new_page);
938
1127
 
939
1128
        ut_ad(new_data_size >= old_data_size);
940
1129
 
941
 
        page_delete_rec_list_end(page, split_rec, index,
 
1130
        page_delete_rec_list_end(split_rec, block, index,
942
1131
                                 new_n_recs - old_n_recs,
943
1132
                                 new_data_size - old_data_size, mtr);
 
1133
 
 
1134
        return(TRUE);
944
1135
}
945
1136
 
946
1137
/*****************************************************************
947
1138
Moves record list start to another page. Moved records do not include
948
1139
split_rec. */
949
 
 
950
 
void
 
1140
UNIV_INTERN
 
1141
ibool
951
1142
page_move_rec_list_start(
952
1143
/*=====================*/
953
 
        page_t*         new_page,       /* in: index page where to move */
954
 
        page_t*         page,           /* in: index page */
 
1144
                                        /* out: TRUE on success; FALSE on
 
1145
                                        compression failure */
 
1146
        buf_block_t*    new_block,      /* in/out: index page where to move */
 
1147
        buf_block_t*    block,          /* in/out: page containing split_rec */
955
1148
        rec_t*          split_rec,      /* in: first record not to move */
956
1149
        dict_index_t*   index,          /* in: record descriptor */
957
1150
        mtr_t*          mtr)            /* in: mtr */
958
1151
{
959
 
        page_copy_rec_list_start(new_page, page, split_rec, index, mtr);
960
 
 
961
 
        page_delete_rec_list_start(page, split_rec, index, mtr);
 
1152
        if (UNIV_UNLIKELY(!page_copy_rec_list_start(new_block, block,
 
1153
                                                    split_rec, index, mtr))) {
 
1154
                return(FALSE);
 
1155
        }
 
1156
 
 
1157
        page_delete_rec_list_start(split_rec, block, index, mtr);
 
1158
 
 
1159
        return(TRUE);
962
1160
}
963
1161
 
964
1162
/***************************************************************************
965
1163
This is a low-level operation which is used in a database index creation
966
1164
to update the page number of a created B-tree to a data dictionary record. */
967
 
 
 
1165
UNIV_INTERN
968
1166
void
969
1167
page_rec_write_index_page_no(
970
1168
/*=========================*/
989
1187
the deleted ones inherits the records of the deleted slots. */
990
1188
UNIV_INLINE
991
1189
void
992
 
page_dir_delete_slots(
993
 
/*==================*/
994
 
        page_t* page,   /* in: the index page */
995
 
        ulint   start,  /* in: first slot to be deleted */
996
 
        ulint   n)      /* in: number of slots to delete (currently
997
 
                        only n == 1 allowed) */
 
1190
page_dir_delete_slot(
 
1191
/*=================*/
 
1192
        page_t*         page,   /* in/out: the index page */
 
1193
        page_zip_des_t* page_zip,/* in/out: compressed page, or NULL */
 
1194
        ulint           slot_no)/* in: slot to be deleted */
998
1195
{
999
1196
        page_dir_slot_t*        slot;
 
1197
        ulint                   n_owned;
1000
1198
        ulint                   i;
1001
 
        ulint                   sum_owned = 0;
1002
1199
        ulint                   n_slots;
1003
 
        rec_t*                  rec;
1004
1200
 
1005
 
        ut_ad(n == 1);
1006
 
        ut_ad(start > 0);
1007
 
        ut_ad(start + n < page_dir_get_n_slots(page));
 
1201
        ut_ad(!page_zip || page_is_comp(page));
 
1202
        ut_ad(slot_no > 0);
 
1203
        ut_ad(slot_no + 1 < page_dir_get_n_slots(page));
1008
1204
 
1009
1205
        n_slots = page_dir_get_n_slots(page);
1010
1206
 
1011
1207
        /* 1. Reset the n_owned fields of the slots to be
1012
1208
        deleted */
1013
 
        for (i = start; i < start + n; i++) {
1014
 
                slot = page_dir_get_nth_slot(page, i);
1015
 
                sum_owned += page_dir_slot_get_n_owned(slot);
1016
 
                page_dir_slot_set_n_owned(slot, 0);
1017
 
        }
 
1209
        slot = page_dir_get_nth_slot(page, slot_no);
 
1210
        n_owned = page_dir_slot_get_n_owned(slot);
 
1211
        page_dir_slot_set_n_owned(slot, page_zip, 0);
1018
1212
 
1019
1213
        /* 2. Update the n_owned value of the first non-deleted slot */
1020
1214
 
1021
 
        slot = page_dir_get_nth_slot(page, start + n);
1022
 
        page_dir_slot_set_n_owned(slot,
1023
 
                                  sum_owned + page_dir_slot_get_n_owned(slot));
1024
 
 
1025
 
        /* 3. Destroy start and other slots by copying slots */
1026
 
        for (i = start + n; i < n_slots; i++) {
1027
 
                slot = page_dir_get_nth_slot(page, i);
1028
 
                rec = page_dir_slot_get_rec(slot);
1029
 
 
1030
 
                slot = page_dir_get_nth_slot(page, i - n);
1031
 
                page_dir_slot_set_rec(slot, rec);
 
1215
        slot = page_dir_get_nth_slot(page, slot_no + 1);
 
1216
        page_dir_slot_set_n_owned(slot, page_zip,
 
1217
                                  n_owned + page_dir_slot_get_n_owned(slot));
 
1218
 
 
1219
        /* 3. Destroy the slot by copying slots */
 
1220
        for (i = slot_no + 1; i < n_slots; i++) {
 
1221
                rec_t*  rec = (rec_t*)
 
1222
                        page_dir_slot_get_rec(page_dir_get_nth_slot(page, i));
 
1223
                page_dir_slot_set_rec(page_dir_get_nth_slot(page, i - 1), rec);
1032
1224
        }
1033
1225
 
1034
 
        /* 4. Update the page header */
1035
 
        page_header_set_field(page, PAGE_N_DIR_SLOTS, n_slots - n);
 
1226
        /* 4. Zero out the last slot, which will be removed */
 
1227
        mach_write_to_2(page_dir_get_nth_slot(page, n_slots - 1), 0);
 
1228
 
 
1229
        /* 5. Update the page header */
 
1230
        page_header_set_field(page, page_zip, PAGE_N_DIR_SLOTS, n_slots - 1);
1036
1231
}
1037
1232
 
1038
1233
/******************************************************************
1041
1236
of the caller. */
1042
1237
UNIV_INLINE
1043
1238
void
1044
 
page_dir_add_slots(
1045
 
/*===============*/
1046
 
        page_t* page,   /* in: the index page */
1047
 
        ulint   start,  /* in: the slot above which the new slots are added */
1048
 
        ulint   n)      /* in: number of slots to add (currently only n == 1
1049
 
                        allowed) */
 
1239
page_dir_add_slot(
 
1240
/*==============*/
 
1241
        page_t*         page,   /* in/out: the index page */
 
1242
        page_zip_des_t* page_zip,/* in/out: comprssed page, or NULL */
 
1243
        ulint           start)  /* in: the slot above which the new slots
 
1244
                                are added */
1050
1245
{
1051
1246
        page_dir_slot_t*        slot;
1052
1247
        ulint                   n_slots;
1053
 
        ulint                   i;
1054
 
        rec_t*                  rec;
1055
 
 
1056
 
        ut_ad(n == 1);
1057
1248
 
1058
1249
        n_slots = page_dir_get_n_slots(page);
1059
1250
 
1060
1251
        ut_ad(start < n_slots - 1);
1061
1252
 
1062
1253
        /* Update the page header */
1063
 
        page_dir_set_n_slots(page, n_slots + n);
 
1254
        page_dir_set_n_slots(page, page_zip, n_slots + 1);
1064
1255
 
1065
1256
        /* Move slots up */
1066
 
 
1067
 
        for (i = n_slots - 1; i > start; i--) {
1068
 
 
1069
 
                slot = page_dir_get_nth_slot(page, i);
1070
 
                rec = page_dir_slot_get_rec(slot);
1071
 
 
1072
 
                slot = page_dir_get_nth_slot(page, i + n);
1073
 
                page_dir_slot_set_rec(slot, rec);
1074
 
        }
 
1257
        slot = page_dir_get_nth_slot(page, n_slots);
 
1258
        memmove(slot, slot + PAGE_DIR_SLOT_SIZE,
 
1259
                (n_slots - 1 - start) * PAGE_DIR_SLOT_SIZE);
1075
1260
}
1076
1261
 
1077
1262
/********************************************************************
1078
1263
Splits a directory slot which owns too many records. */
1079
 
 
 
1264
UNIV_INTERN
1080
1265
void
1081
1266
page_dir_split_slot(
1082
1267
/*================*/
1083
 
        page_t* page,           /* in: the index page in question */
1084
 
        ulint   slot_no)        /* in: the directory slot */
 
1268
        page_t*         page,   /* in/out: index page */
 
1269
        page_zip_des_t* page_zip,/* in/out: compressed page whose
 
1270
                                uncompressed part will be written, or NULL */
 
1271
        ulint           slot_no)/* in: the directory slot */
1085
1272
{
1086
1273
        rec_t*                  rec;
1087
1274
        page_dir_slot_t*        new_slot;
1091
1278
        ulint                   n_owned;
1092
1279
 
1093
1280
        ut_ad(page);
 
1281
        ut_ad(!page_zip || page_is_comp(page));
1094
1282
        ut_ad(slot_no > 0);
1095
1283
 
1096
1284
        slot = page_dir_get_nth_slot(page, slot_no);
1102
1290
        records owned by the slot. */
1103
1291
 
1104
1292
        prev_slot = page_dir_get_nth_slot(page, slot_no - 1);
1105
 
        rec = page_dir_slot_get_rec(prev_slot);
 
1293
        rec = (rec_t*) page_dir_slot_get_rec(prev_slot);
1106
1294
 
1107
1295
        for (i = 0; i < n_owned / 2; i++) {
1108
1296
                rec = page_rec_get_next(rec);
1113
1301
        /* 2. We add one directory slot immediately below the slot to be
1114
1302
        split. */
1115
1303
 
1116
 
        page_dir_add_slots(page, slot_no - 1, 1);
 
1304
        page_dir_add_slot(page, page_zip, slot_no - 1);
1117
1305
 
1118
1306
        /* The added slot is now number slot_no, and the old slot is
1119
1307
        now number slot_no + 1 */
1124
1312
        /* 3. We store the appropriate values to the new slot. */
1125
1313
 
1126
1314
        page_dir_slot_set_rec(new_slot, rec);
1127
 
        page_dir_slot_set_n_owned(new_slot, n_owned / 2);
 
1315
        page_dir_slot_set_n_owned(new_slot, page_zip, n_owned / 2);
1128
1316
 
1129
1317
        /* 4. Finally, we update the number of records field of the
1130
1318
        original slot */
1131
1319
 
1132
 
        page_dir_slot_set_n_owned(slot, n_owned - (n_owned / 2));
 
1320
        page_dir_slot_set_n_owned(slot, page_zip, n_owned - (n_owned / 2));
1133
1321
}
1134
1322
 
1135
1323
/*****************************************************************
1136
1324
Tries to balance the given directory slot with too few records with the upper
1137
1325
neighbor, so that there are at least the minimum number of records owned by
1138
1326
the slot; this may result in the merging of two slots. */
1139
 
 
 
1327
UNIV_INTERN
1140
1328
void
1141
1329
page_dir_balance_slot(
1142
1330
/*==================*/
1143
 
        page_t* page,           /* in: index page */
1144
 
        ulint   slot_no)        /* in: the directory slot */
 
1331
        page_t*         page,   /* in/out: index page */
 
1332
        page_zip_des_t* page_zip,/* in/out: compressed page, or NULL */
 
1333
        ulint           slot_no)/* in: the directory slot */
1145
1334
{
1146
1335
        page_dir_slot_t*        slot;
1147
1336
        page_dir_slot_t*        up_slot;
1151
1340
        rec_t*                  new_rec;
1152
1341
 
1153
1342
        ut_ad(page);
 
1343
        ut_ad(!page_zip || page_is_comp(page));
1154
1344
        ut_ad(slot_no > 0);
1155
1345
 
1156
1346
        slot = page_dir_get_nth_slot(page, slot_no);
1158
1348
        /* The last directory slot cannot be balanced with the upper
1159
1349
        neighbor, as there is none. */
1160
1350
 
1161
 
        if (slot_no == page_dir_get_n_slots(page) - 1) {
 
1351
        if (UNIV_UNLIKELY(slot_no == page_dir_get_n_slots(page) - 1)) {
1162
1352
 
1163
1353
                return;
1164
1354
        }
1178
1368
 
1179
1369
                /* In this case we can just transfer one record owned
1180
1370
                by the upper slot to the property of the lower slot */
1181
 
                old_rec = page_dir_slot_get_rec(slot);
1182
 
                new_rec = page_rec_get_next(old_rec);
1183
 
 
1184
 
                rec_set_n_owned(old_rec, page_is_comp(page), 0);
1185
 
                rec_set_n_owned(new_rec, page_is_comp(page), n_owned + 1);
 
1371
                old_rec = (rec_t*) page_dir_slot_get_rec(slot);
 
1372
 
 
1373
                if (page_is_comp(page)) {
 
1374
                        new_rec = rec_get_next_ptr(old_rec, TRUE);
 
1375
 
 
1376
                        rec_set_n_owned_new(old_rec, page_zip, 0);
 
1377
                        rec_set_n_owned_new(new_rec, page_zip, n_owned + 1);
 
1378
                } else {
 
1379
                        new_rec = rec_get_next_ptr(old_rec, FALSE);
 
1380
 
 
1381
                        rec_set_n_owned_old(old_rec, 0);
 
1382
                        rec_set_n_owned_old(new_rec, n_owned + 1);
 
1383
                }
1186
1384
 
1187
1385
                page_dir_slot_set_rec(slot, new_rec);
1188
1386
 
1189
 
                page_dir_slot_set_n_owned(up_slot, up_n_owned -1);
 
1387
                page_dir_slot_set_n_owned(up_slot, page_zip, up_n_owned -1);
1190
1388
        } else {
1191
1389
                /* In this case we may merge the two slots */
1192
 
                page_dir_delete_slots(page, slot_no, 1);
 
1390
                page_dir_delete_slot(page, page_zip, slot_no);
1193
1391
        }
1194
1392
}
1195
1393
 
1196
1394
/****************************************************************
1197
1395
Returns the middle record of the record list. If there are an even number
1198
1396
of records in the list, returns the first record of the upper half-list. */
1199
 
 
 
1397
UNIV_INTERN
1200
1398
rec_t*
1201
1399
page_get_middle_rec(
1202
1400
/*================*/
1211
1409
        rec_t*                  rec;
1212
1410
 
1213
1411
        /* This many records we must leave behind */
1214
 
        middle = (page_get_n_recs(page) + 2) / 2;
 
1412
        middle = (page_get_n_recs(page) + PAGE_HEAP_NO_USER_LOW) / 2;
1215
1413
 
1216
1414
        count = 0;
1217
1415
 
1229
1427
 
1230
1428
        ut_ad(i > 0);
1231
1429
        slot = page_dir_get_nth_slot(page, i - 1);
1232
 
        rec = page_dir_slot_get_rec(slot);
 
1430
        rec = (rec_t*) page_dir_slot_get_rec(slot);
1233
1431
        rec = page_rec_get_next(rec);
1234
1432
 
1235
1433
        /* There are now count records behind rec */
1244
1442
/*******************************************************************
1245
1443
Returns the number of records before the given record in chain.
1246
1444
The number includes infimum and supremum records. */
1247
 
 
 
1445
UNIV_INTERN
1248
1446
ulint
1249
1447
page_rec_get_n_recs_before(
1250
1448
/*=======================*/
1251
 
                        /* out: number of records */
1252
 
        rec_t*  rec)    /* in: the physical record */
 
1449
                                /* out: number of records */
 
1450
        const rec_t*    rec)    /* in: the physical record */
1253
1451
{
1254
 
        page_dir_slot_t*        slot;
1255
 
        rec_t*                  slot_rec;
1256
 
        page_t*                 page;
 
1452
        const page_dir_slot_t*  slot;
 
1453
        const rec_t*            slot_rec;
 
1454
        const page_t*           page;
1257
1455
        ulint                   i;
1258
 
        ulint                   comp;
1259
1456
        lint                    n       = 0;
1260
1457
 
1261
1458
        ut_ad(page_rec_check(rec));
1262
1459
 
1263
 
        page = buf_frame_align(rec);
1264
 
        comp = page_is_comp(page);
1265
 
 
1266
 
        while (rec_get_n_owned(rec, comp) == 0) {
1267
 
 
1268
 
                rec = page_rec_get_next(rec);
1269
 
                n--;
1270
 
        }
1271
 
 
1272
 
        for (i = 0; ; i++) {
1273
 
                slot = page_dir_get_nth_slot(page, i);
1274
 
                slot_rec = page_dir_slot_get_rec(slot);
1275
 
 
1276
 
                n += rec_get_n_owned(slot_rec, comp);
1277
 
 
1278
 
                if (rec == slot_rec) {
1279
 
 
1280
 
                        break;
 
1460
        page = page_align(rec);
 
1461
        if (page_is_comp(page)) {
 
1462
                while (rec_get_n_owned_new(rec) == 0) {
 
1463
 
 
1464
                        rec = rec_get_next_ptr_const(rec, TRUE);
 
1465
                        n--;
 
1466
                }
 
1467
 
 
1468
                for (i = 0; ; i++) {
 
1469
                        slot = page_dir_get_nth_slot(page, i);
 
1470
                        slot_rec = page_dir_slot_get_rec(slot);
 
1471
 
 
1472
                        n += rec_get_n_owned_new(slot_rec);
 
1473
 
 
1474
                        if (rec == slot_rec) {
 
1475
 
 
1476
                                break;
 
1477
                        }
 
1478
                }
 
1479
        } else {
 
1480
                while (rec_get_n_owned_old(rec) == 0) {
 
1481
 
 
1482
                        rec = rec_get_next_ptr_const(rec, FALSE);
 
1483
                        n--;
 
1484
                }
 
1485
 
 
1486
                for (i = 0; ; i++) {
 
1487
                        slot = page_dir_get_nth_slot(page, i);
 
1488
                        slot_rec = page_dir_slot_get_rec(slot);
 
1489
 
 
1490
                        n += rec_get_n_owned_old(slot_rec);
 
1491
 
 
1492
                        if (rec == slot_rec) {
 
1493
 
 
1494
                                break;
 
1495
                        }
1281
1496
                }
1282
1497
        }
1283
1498
 
1291
1506
/****************************************************************
1292
1507
Prints record contents including the data relevant only in
1293
1508
the index page context. */
1294
 
 
 
1509
UNIV_INTERN
1295
1510
void
1296
1511
page_rec_print(
1297
1512
/*===========*/
1298
 
        rec_t*          rec,    /* in: physical record */
 
1513
        const rec_t*    rec,    /* in: physical record */
1299
1514
        const ulint*    offsets)/* in: record descriptor */
1300
1515
{
1301
 
        ulint   comp    = page_is_comp(buf_frame_align(rec));
1302
 
 
1303
 
        ut_a(!comp == !rec_offs_comp(offsets));
 
1516
        ut_a(!page_rec_is_comp(rec) == !rec_offs_comp(offsets));
1304
1517
        rec_print_new(stderr, rec, offsets);
1305
 
        fprintf(stderr,
1306
 
                "            n_owned: %lu; heap_no: %lu; next rec: %lu\n",
1307
 
                (ulong) rec_get_n_owned(rec, comp),
1308
 
                (ulong) rec_get_heap_no(rec, comp),
1309
 
                (ulong) rec_get_next_offs(rec, comp));
 
1518
        if (page_rec_is_comp(rec)) {
 
1519
                fprintf(stderr,
 
1520
                        " n_owned: %lu; heap_no: %lu; next rec: %lu\n",
 
1521
                        (ulong) rec_get_n_owned_new(rec),
 
1522
                        (ulong) rec_get_heap_no_new(rec),
 
1523
                        (ulong) rec_get_next_offs(rec, TRUE));
 
1524
        } else {
 
1525
                fprintf(stderr,
 
1526
                        " n_owned: %lu; heap_no: %lu; next rec: %lu\n",
 
1527
                        (ulong) rec_get_n_owned_old(rec),
 
1528
                        (ulong) rec_get_heap_no_old(rec),
 
1529
                        (ulong) rec_get_next_offs(rec, TRUE));
 
1530
        }
1310
1531
 
1311
1532
        page_rec_check(rec);
1312
1533
        rec_validate(rec, offsets);
1315
1536
/*******************************************************************
1316
1537
This is used to print the contents of the directory for
1317
1538
debugging purposes. */
1318
 
 
 
1539
UNIV_INTERN
1319
1540
void
1320
1541
page_dir_print(
1321
1542
/*===========*/
1332
1553
                "PAGE DIRECTORY\n"
1333
1554
                "Page address %p\n"
1334
1555
                "Directory stack top at offs: %lu; number of slots: %lu\n",
1335
 
                page, (ulong)(page_dir_get_nth_slot(page, n - 1) - page),
 
1556
                page, (ulong) page_offset(page_dir_get_nth_slot(page, n - 1)),
1336
1557
                (ulong) n);
1337
1558
        for (i = 0; i < n; i++) {
1338
1559
                slot = page_dir_get_nth_slot(page, i);
1345
1566
                                " rec offs: %lu\n",
1346
1567
                                (ulong) i,
1347
1568
                                (ulong) page_dir_slot_get_n_owned(slot),
1348
 
                                (ulong)(page_dir_slot_get_rec(slot) - page));
 
1569
                                (ulong)
 
1570
                                page_offset(page_dir_slot_get_rec(slot)));
1349
1571
                }
1350
1572
        }
1351
1573
        fprintf(stderr, "Total of %lu records\n"
1352
1574
                "--------------------------------\n",
1353
 
                (ulong) (2 + page_get_n_recs(page)));
 
1575
                (ulong) (PAGE_HEAP_NO_USER_LOW + page_get_n_recs(page)));
1354
1576
}
1355
1577
 
1356
1578
/*******************************************************************
1357
1579
This is used to print the contents of the page record list for
1358
1580
debugging purposes. */
1359
 
 
 
1581
UNIV_INTERN
1360
1582
void
1361
1583
page_print_list(
1362
1584
/*============*/
1363
 
        page_t*         page,   /* in: index page */
 
1585
        buf_block_t*    block,  /* in: index page */
1364
1586
        dict_index_t*   index,  /* in: dictionary index of the page */
1365
1587
        ulint           pr_n)   /* in: print n first and n last entries */
1366
1588
{
 
1589
        page_t*         page            = block->frame;
1367
1590
        page_cur_t      cur;
1368
1591
        ulint           count;
1369
1592
        ulint           n_recs;
1370
1593
        mem_heap_t*     heap            = NULL;
1371
1594
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
1372
1595
        ulint*          offsets         = offsets_;
1373
 
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
 
1596
        rec_offs_init(offsets_);
1374
1597
 
1375
1598
        ut_a((ibool)!!page_is_comp(page) == dict_table_is_comp(index->table));
1376
1599
 
1381
1604
 
1382
1605
        n_recs = page_get_n_recs(page);
1383
1606
 
1384
 
        page_cur_set_before_first(page, &cur);
 
1607
        page_cur_set_before_first(block, &cur);
1385
1608
        count = 0;
1386
1609
        for (;;) {
1387
1610
                offsets = rec_get_offsets(cur.rec, index, offsets,
1425
1648
 
1426
1649
/*******************************************************************
1427
1650
Prints the info in a page header. */
1428
 
 
 
1651
UNIV_INTERN
1429
1652
void
1430
1653
page_header_print(
1431
1654
/*==============*/
1432
 
        page_t* page)
 
1655
        const page_t*   page)
1433
1656
{
1434
1657
        fprintf(stderr,
1435
1658
                "--------------------------------\n"
1453
1676
/*******************************************************************
1454
1677
This is used to print the contents of the page for
1455
1678
debugging purposes. */
1456
 
 
 
1679
UNIV_INTERN
1457
1680
void
1458
1681
page_print(
1459
1682
/*=======*/
1460
 
        page_t*         page,   /* in: index page */
 
1683
        buf_block_t*    block,  /* in: index page */
1461
1684
        dict_index_t*   index,  /* in: dictionary index of the page */
1462
1685
        ulint           dn,     /* in: print dn first and last entries
1463
1686
                                in directory */
1464
1687
        ulint           rn)     /* in: print rn first and last records
1465
1688
                                in directory */
1466
1689
{
 
1690
        page_t* page = block->frame;
 
1691
 
1467
1692
        page_header_print(page);
1468
1693
        page_dir_print(page, dn);
1469
 
        page_print_list(page, index, rn);
 
1694
        page_print_list(block, index, rn);
1470
1695
}
1471
1696
 
1472
1697
/*******************************************************************
1473
1698
The following is used to validate a record on a page. This function
1474
1699
differs from rec_validate as it can also check the n_owned field and
1475
1700
the heap_no field. */
1476
 
 
 
1701
UNIV_INTERN
1477
1702
ibool
1478
1703
page_rec_validate(
1479
1704
/*==============*/
1484
1709
        ulint   n_owned;
1485
1710
        ulint   heap_no;
1486
1711
        page_t* page;
1487
 
        ulint   comp;
1488
1712
 
1489
 
        page = buf_frame_align(rec);
1490
 
        comp = page_is_comp(page);
1491
 
        ut_a(!comp == !rec_offs_comp(offsets));
 
1713
        page = page_align(rec);
 
1714
        ut_a(!page_is_comp(page) == !rec_offs_comp(offsets));
1492
1715
 
1493
1716
        page_rec_check(rec);
1494
1717
        rec_validate(rec, offsets);
1495
1718
 
1496
 
        n_owned = rec_get_n_owned(rec, comp);
1497
 
        heap_no = rec_get_heap_no(rec, comp);
 
1719
        if (page_rec_is_comp(rec)) {
 
1720
                n_owned = rec_get_n_owned_new(rec);
 
1721
                heap_no = rec_get_heap_no_new(rec);
 
1722
        } else {
 
1723
                n_owned = rec_get_n_owned_old(rec);
 
1724
                heap_no = rec_get_heap_no_old(rec);
 
1725
        }
1498
1726
 
1499
 
        if (!(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED)) {
 
1727
        if (UNIV_UNLIKELY(!(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED))) {
1500
1728
                fprintf(stderr,
1501
1729
                        "InnoDB: Dir slot of rec %lu, n owned too big %lu\n",
1502
 
                        (ulong)(rec - page), (ulong) n_owned);
 
1730
                        (ulong) page_offset(rec), (ulong) n_owned);
1503
1731
                return(FALSE);
1504
1732
        }
1505
1733
 
1506
 
        if (!(heap_no < page_dir_get_n_heap(page))) {
 
1734
        if (UNIV_UNLIKELY(!(heap_no < page_dir_get_n_heap(page)))) {
1507
1735
                fprintf(stderr,
1508
1736
                        "InnoDB: Heap no of rec %lu too big %lu %lu\n",
1509
 
                        (ulong)(rec - page), (ulong) heap_no,
 
1737
                        (ulong) page_offset(rec), (ulong) heap_no,
1510
1738
                        (ulong) page_dir_get_n_heap(page));
1511
1739
                return(FALSE);
1512
1740
        }
1518
1746
Checks that the first directory slot points to the infimum record and
1519
1747
the last to the supremum. This function is intended to track if the
1520
1748
bug fixed in 4.0.14 has caused corruption to users' databases. */
1521
 
 
 
1749
UNIV_INTERN
1522
1750
void
1523
1751
page_check_dir(
1524
1752
/*===========*/
1525
 
        page_t* page)   /* in: index page */
 
1753
        const page_t*   page)   /* in: index page */
1526
1754
{
1527
1755
        ulint   n_slots;
 
1756
        ulint   infimum_offs;
 
1757
        ulint   supremum_offs;
1528
1758
 
1529
1759
        n_slots = page_dir_get_n_slots(page);
 
1760
        infimum_offs = mach_read_from_2(page_dir_get_nth_slot(page, 0));
 
1761
        supremum_offs = mach_read_from_2(page_dir_get_nth_slot(page,
 
1762
                                                               n_slots - 1));
1530
1763
 
1531
 
        if (page_dir_slot_get_rec(page_dir_get_nth_slot(page, 0))
1532
 
            != page_get_infimum_rec(page)) {
 
1764
        if (UNIV_UNLIKELY(!page_rec_is_infimum_low(infimum_offs))) {
1533
1765
 
1534
1766
                fprintf(stderr,
1535
1767
                        "InnoDB: Page directory corruption:"
1536
1768
                        " infimum not pointed to\n");
1537
 
                buf_page_print(page);
 
1769
                buf_page_print(page, 0);
1538
1770
        }
1539
1771
 
1540
 
        if (page_dir_slot_get_rec(page_dir_get_nth_slot(page, n_slots - 1))
1541
 
            != page_get_supremum_rec(page)) {
 
1772
        if (UNIV_UNLIKELY(!page_rec_is_supremum_low(supremum_offs))) {
1542
1773
 
1543
1774
                fprintf(stderr,
1544
1775
                        "InnoDB: Page directory corruption:"
1545
1776
                        " supremum not pointed to\n");
1546
 
                buf_page_print(page);
 
1777
                buf_page_print(page, 0);
1547
1778
        }
1548
1779
}
1549
1780
 
1551
1782
This function checks the consistency of an index page when we do not
1552
1783
know the index. This is also resilient so that this should never crash
1553
1784
even if the page is total garbage. */
1554
 
 
 
1785
UNIV_INTERN
1555
1786
ibool
1556
 
page_simple_validate(
1557
 
/*=================*/
 
1787
page_simple_validate_old(
 
1788
/*=====================*/
1558
1789
                        /* out: TRUE if ok */
1559
 
        page_t* page)   /* in: index page */
 
1790
        page_t* page)   /* in: old-style index page */
1560
1791
{
1561
 
        page_cur_t      cur;
1562
1792
        page_dir_slot_t* slot;
1563
1793
        ulint           slot_no;
1564
1794
        ulint           n_slots;
1567
1797
        ulint           count;
1568
1798
        ulint           own_count;
1569
1799
        ibool           ret     = FALSE;
1570
 
        ulint           comp    = page_is_comp(page);
 
1800
 
 
1801
        ut_a(!page_is_comp(page));
1571
1802
 
1572
1803
        /* Check first that the record heap and the directory do not
1573
1804
        overlap. */
1574
1805
 
1575
1806
        n_slots = page_dir_get_n_slots(page);
1576
1807
 
1577
 
        if (n_slots > UNIV_PAGE_SIZE / 4) {
 
1808
        if (UNIV_UNLIKELY(n_slots > UNIV_PAGE_SIZE / 4)) {
1578
1809
                fprintf(stderr,
1579
1810
                        "InnoDB: Nonsensical number %lu of page dir slots\n",
1580
1811
                        (ulong) n_slots);
1584
1815
 
1585
1816
        rec_heap_top = page_header_get_ptr(page, PAGE_HEAP_TOP);
1586
1817
 
1587
 
        if (rec_heap_top > page_dir_get_nth_slot(page, n_slots - 1)) {
 
1818
        if (UNIV_UNLIKELY(rec_heap_top
 
1819
                          > page_dir_get_nth_slot(page, n_slots - 1))) {
1588
1820
 
1589
1821
                fprintf(stderr,
1590
1822
                        "InnoDB: Record heap and dir overlap on a page,"
1591
1823
                        " heap top %lu, dir %lu\n",
1592
 
                        (ulong)
1593
 
                        (page_header_get_ptr(page, PAGE_HEAP_TOP) - page),
1594
 
                        (ulong)
1595
 
                        (page_dir_get_nth_slot(page, n_slots - 1) - page));
 
1824
                        (ulong) page_header_get_field(page, PAGE_HEAP_TOP),
 
1825
                        (ulong)
 
1826
                        page_offset(page_dir_get_nth_slot(page, n_slots - 1)));
1596
1827
 
1597
1828
                goto func_exit;
1598
1829
        }
1605
1836
        slot_no = 0;
1606
1837
        slot = page_dir_get_nth_slot(page, slot_no);
1607
1838
 
1608
 
        page_cur_set_before_first(page, &cur);
 
1839
        rec = page_get_infimum_rec(page);
1609
1840
 
1610
1841
        for (;;) {
1611
 
                rec = (&cur)->rec;
1612
 
 
1613
 
                if (rec > rec_heap_top) {
 
1842
                if (UNIV_UNLIKELY(rec > rec_heap_top)) {
1614
1843
                        fprintf(stderr,
1615
1844
                                "InnoDB: Record %lu is above"
1616
1845
                                " rec heap top %lu\n",
1620
1849
                        goto func_exit;
1621
1850
                }
1622
1851
 
1623
 
                if (rec_get_n_owned(rec, comp) != 0) {
 
1852
                if (UNIV_UNLIKELY(rec_get_n_owned_old(rec))) {
1624
1853
                        /* This is a record pointed to by a dir slot */
1625
 
                        if (rec_get_n_owned(rec, comp) != own_count) {
 
1854
                        if (UNIV_UNLIKELY(rec_get_n_owned_old(rec)
 
1855
                                          != own_count)) {
1626
1856
 
1627
1857
                                fprintf(stderr,
1628
1858
                                        "InnoDB: Wrong owned count %lu, %lu,"
1629
1859
                                        " rec %lu\n",
1630
 
                                        (ulong) rec_get_n_owned(rec, comp),
 
1860
                                        (ulong) rec_get_n_owned_old(rec),
1631
1861
                                        (ulong) own_count,
1632
1862
                                        (ulong)(rec - page));
1633
1863
 
1634
1864
                                goto func_exit;
1635
1865
                        }
1636
1866
 
1637
 
                        if (page_dir_slot_get_rec(slot) != rec) {
 
1867
                        if (UNIV_UNLIKELY
 
1868
                            (page_dir_slot_get_rec(slot) != rec)) {
1638
1869
                                fprintf(stderr,
1639
1870
                                        "InnoDB: Dir slot does not point"
1640
1871
                                        " to right rec %lu\n",
1645
1876
 
1646
1877
                        own_count = 0;
1647
1878
 
1648
 
                        if (!page_cur_is_after_last(&cur)) {
 
1879
                        if (!page_rec_is_supremum(rec)) {
1649
1880
                                slot_no++;
1650
1881
                                slot = page_dir_get_nth_slot(page, slot_no);
1651
1882
                        }
1652
1883
                }
1653
1884
 
1654
 
                if (page_cur_is_after_last(&cur)) {
 
1885
                if (page_rec_is_supremum(rec)) {
1655
1886
 
1656
1887
                        break;
1657
1888
                }
1658
1889
 
1659
 
                if (rec_get_next_offs(rec, comp) < FIL_PAGE_DATA
1660
 
                    || rec_get_next_offs(rec, comp) >= UNIV_PAGE_SIZE) {
 
1890
                if (UNIV_UNLIKELY
 
1891
                    (rec_get_next_offs(rec, FALSE) < FIL_PAGE_DATA
 
1892
                     || rec_get_next_offs(rec, FALSE) >= UNIV_PAGE_SIZE)) {
1661
1893
                        fprintf(stderr,
1662
1894
                                "InnoDB: Next record offset"
1663
1895
                                " nonsensical %lu for rec %lu\n",
1664
 
                                (ulong) rec_get_next_offs(rec, comp),
1665
 
                                (ulong)(rec - page));
 
1896
                                (ulong) rec_get_next_offs(rec, FALSE),
 
1897
                                (ulong) (rec - page));
1666
1898
 
1667
1899
                        goto func_exit;
1668
1900
                }
1669
1901
 
1670
1902
                count++;
1671
1903
 
1672
 
                if (count > UNIV_PAGE_SIZE) {
 
1904
                if (UNIV_UNLIKELY(count > UNIV_PAGE_SIZE)) {
1673
1905
                        fprintf(stderr,
1674
1906
                                "InnoDB: Page record list appears"
1675
1907
                                " to be circular %lu\n",
1677
1909
                        goto func_exit;
1678
1910
                }
1679
1911
 
1680
 
                page_cur_move_to_next(&cur);
 
1912
                rec = page_rec_get_next(rec);
1681
1913
                own_count++;
1682
1914
        }
1683
1915
 
1684
 
        if (rec_get_n_owned(rec, comp) == 0) {
 
1916
        if (UNIV_UNLIKELY(rec_get_n_owned_old(rec) == 0)) {
1685
1917
                fprintf(stderr, "InnoDB: n owned is zero in a supremum rec\n");
1686
1918
 
1687
1919
                goto func_exit;
1688
1920
        }
1689
1921
 
1690
 
        if (slot_no != n_slots - 1) {
 
1922
        if (UNIV_UNLIKELY(slot_no != n_slots - 1)) {
1691
1923
                fprintf(stderr, "InnoDB: n slots wrong %lu, %lu\n",
1692
1924
                        (ulong) slot_no, (ulong) (n_slots - 1));
1693
1925
                goto func_exit;
1694
1926
        }
1695
1927
 
1696
 
        if (page_header_get_field(page, PAGE_N_RECS) + 2 != count + 1) {
 
1928
        if (UNIV_UNLIKELY(page_header_get_field(page, PAGE_N_RECS)
 
1929
                          + PAGE_HEAP_NO_USER_LOW
 
1930
                          != count + 1)) {
1697
1931
                fprintf(stderr, "InnoDB: n recs wrong %lu %lu\n",
1698
 
                        (ulong) page_header_get_field(page, PAGE_N_RECS) + 2,
 
1932
                        (ulong) page_header_get_field(page, PAGE_N_RECS)
 
1933
                        + PAGE_HEAP_NO_USER_LOW,
1699
1934
                        (ulong) (count + 1));
1700
1935
 
1701
1936
                goto func_exit;
1705
1940
        rec = page_header_get_ptr(page, PAGE_FREE);
1706
1941
 
1707
1942
        while (rec != NULL) {
1708
 
                if (rec < page + FIL_PAGE_DATA
1709
 
                    || rec >= page + UNIV_PAGE_SIZE) {
 
1943
                if (UNIV_UNLIKELY(rec < page + FIL_PAGE_DATA
 
1944
                                  || rec >= page + UNIV_PAGE_SIZE)) {
1710
1945
                        fprintf(stderr,
1711
1946
                                "InnoDB: Free list record has"
1712
1947
                                " a nonsensical offset %lu\n",
1715
1950
                        goto func_exit;
1716
1951
                }
1717
1952
 
1718
 
                if (rec > rec_heap_top) {
 
1953
                if (UNIV_UNLIKELY(rec > rec_heap_top)) {
1719
1954
                        fprintf(stderr,
1720
1955
                                "InnoDB: Free list record %lu"
1721
1956
                                " is above rec heap top %lu\n",
1727
1962
 
1728
1963
                count++;
1729
1964
 
1730
 
                if (count > UNIV_PAGE_SIZE) {
1731
 
                        fprintf(stderr,
1732
 
                                "InnoDB: Page free list appears"
1733
 
                                " to be circular %lu\n",
1734
 
                                (ulong) count);
1735
 
                        goto func_exit;
1736
 
                }
1737
 
 
1738
 
                rec = page_rec_get_next(rec);
1739
 
        }
1740
 
 
1741
 
        if (page_dir_get_n_heap(page) != count + 1) {
 
1965
                if (UNIV_UNLIKELY(count > UNIV_PAGE_SIZE)) {
 
1966
                        fprintf(stderr,
 
1967
                                "InnoDB: Page free list appears"
 
1968
                                " to be circular %lu\n",
 
1969
                                (ulong) count);
 
1970
                        goto func_exit;
 
1971
                }
 
1972
 
 
1973
                rec = page_rec_get_next(rec);
 
1974
        }
 
1975
 
 
1976
        if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) {
 
1977
 
 
1978
                fprintf(stderr, "InnoDB: N heap is wrong %lu, %lu\n",
 
1979
                        (ulong) page_dir_get_n_heap(page),
 
1980
                        (ulong) (count + 1));
 
1981
 
 
1982
                goto func_exit;
 
1983
        }
 
1984
 
 
1985
        ret = TRUE;
 
1986
 
 
1987
func_exit:
 
1988
        return(ret);
 
1989
}
 
1990
 
 
1991
/*******************************************************************
 
1992
This function checks the consistency of an index page when we do not
 
1993
know the index. This is also resilient so that this should never crash
 
1994
even if the page is total garbage. */
 
1995
UNIV_INTERN
 
1996
ibool
 
1997
page_simple_validate_new(
 
1998
/*=====================*/
 
1999
                        /* out: TRUE if ok */
 
2000
        page_t* page)   /* in: new-style index page */
 
2001
{
 
2002
        page_dir_slot_t* slot;
 
2003
        ulint           slot_no;
 
2004
        ulint           n_slots;
 
2005
        rec_t*          rec;
 
2006
        byte*           rec_heap_top;
 
2007
        ulint           count;
 
2008
        ulint           own_count;
 
2009
        ibool           ret     = FALSE;
 
2010
 
 
2011
        ut_a(page_is_comp(page));
 
2012
 
 
2013
        /* Check first that the record heap and the directory do not
 
2014
        overlap. */
 
2015
 
 
2016
        n_slots = page_dir_get_n_slots(page);
 
2017
 
 
2018
        if (UNIV_UNLIKELY(n_slots > UNIV_PAGE_SIZE / 4)) {
 
2019
                fprintf(stderr,
 
2020
                        "InnoDB: Nonsensical number %lu"
 
2021
                        " of page dir slots\n", (ulong) n_slots);
 
2022
 
 
2023
                goto func_exit;
 
2024
        }
 
2025
 
 
2026
        rec_heap_top = page_header_get_ptr(page, PAGE_HEAP_TOP);
 
2027
 
 
2028
        if (UNIV_UNLIKELY(rec_heap_top
 
2029
                          > page_dir_get_nth_slot(page, n_slots - 1))) {
 
2030
 
 
2031
                fprintf(stderr,
 
2032
                        "InnoDB: Record heap and dir overlap on a page,"
 
2033
                        " heap top %lu, dir %lu\n",
 
2034
                        (ulong) page_header_get_field(page, PAGE_HEAP_TOP),
 
2035
                        (ulong)
 
2036
                        page_offset(page_dir_get_nth_slot(page, n_slots - 1)));
 
2037
 
 
2038
                goto func_exit;
 
2039
        }
 
2040
 
 
2041
        /* Validate the record list in a loop checking also that it is
 
2042
        consistent with the page record directory. */
 
2043
 
 
2044
        count = 0;
 
2045
        own_count = 1;
 
2046
        slot_no = 0;
 
2047
        slot = page_dir_get_nth_slot(page, slot_no);
 
2048
 
 
2049
        rec = page_get_infimum_rec(page);
 
2050
 
 
2051
        for (;;) {
 
2052
                if (UNIV_UNLIKELY(rec > rec_heap_top)) {
 
2053
                        fprintf(stderr,
 
2054
                                "InnoDB: Record %lu is above rec"
 
2055
                                " heap top %lu\n",
 
2056
                                (ulong) page_offset(rec),
 
2057
                                (ulong) page_offset(rec_heap_top));
 
2058
 
 
2059
                        goto func_exit;
 
2060
                }
 
2061
 
 
2062
                if (UNIV_UNLIKELY(rec_get_n_owned_new(rec))) {
 
2063
                        /* This is a record pointed to by a dir slot */
 
2064
                        if (UNIV_UNLIKELY(rec_get_n_owned_new(rec)
 
2065
                                          != own_count)) {
 
2066
 
 
2067
                                fprintf(stderr,
 
2068
                                        "InnoDB: Wrong owned count %lu, %lu,"
 
2069
                                        " rec %lu\n",
 
2070
                                        (ulong) rec_get_n_owned_new(rec),
 
2071
                                        (ulong) own_count,
 
2072
                                        (ulong) page_offset(rec));
 
2073
 
 
2074
                                goto func_exit;
 
2075
                        }
 
2076
 
 
2077
                        if (UNIV_UNLIKELY
 
2078
                            (page_dir_slot_get_rec(slot) != rec)) {
 
2079
                                fprintf(stderr,
 
2080
                                        "InnoDB: Dir slot does not point"
 
2081
                                        " to right rec %lu\n",
 
2082
                                        (ulong) page_offset(rec));
 
2083
 
 
2084
                                goto func_exit;
 
2085
                        }
 
2086
 
 
2087
                        own_count = 0;
 
2088
 
 
2089
                        if (!page_rec_is_supremum(rec)) {
 
2090
                                slot_no++;
 
2091
                                slot = page_dir_get_nth_slot(page, slot_no);
 
2092
                        }
 
2093
                }
 
2094
 
 
2095
                if (page_rec_is_supremum(rec)) {
 
2096
 
 
2097
                        break;
 
2098
                }
 
2099
 
 
2100
                if (UNIV_UNLIKELY
 
2101
                    (rec_get_next_offs(rec, TRUE) < FIL_PAGE_DATA
 
2102
                     || rec_get_next_offs(rec, TRUE) >= UNIV_PAGE_SIZE)) {
 
2103
                        fprintf(stderr,
 
2104
                                "InnoDB: Next record offset nonsensical %lu"
 
2105
                                " for rec %lu\n",
 
2106
                                (ulong) rec_get_next_offs(rec, TRUE),
 
2107
                                (ulong) page_offset(rec));
 
2108
 
 
2109
                        goto func_exit;
 
2110
                }
 
2111
 
 
2112
                count++;
 
2113
 
 
2114
                if (UNIV_UNLIKELY(count > UNIV_PAGE_SIZE)) {
 
2115
                        fprintf(stderr,
 
2116
                                "InnoDB: Page record list appears"
 
2117
                                " to be circular %lu\n",
 
2118
                                (ulong) count);
 
2119
                        goto func_exit;
 
2120
                }
 
2121
 
 
2122
                rec = page_rec_get_next(rec);
 
2123
                own_count++;
 
2124
        }
 
2125
 
 
2126
        if (UNIV_UNLIKELY(rec_get_n_owned_new(rec) == 0)) {
 
2127
                fprintf(stderr, "InnoDB: n owned is zero"
 
2128
                        " in a supremum rec\n");
 
2129
 
 
2130
                goto func_exit;
 
2131
        }
 
2132
 
 
2133
        if (UNIV_UNLIKELY(slot_no != n_slots - 1)) {
 
2134
                fprintf(stderr, "InnoDB: n slots wrong %lu, %lu\n",
 
2135
                        (ulong) slot_no, (ulong) (n_slots - 1));
 
2136
                goto func_exit;
 
2137
        }
 
2138
 
 
2139
        if (UNIV_UNLIKELY(page_header_get_field(page, PAGE_N_RECS)
 
2140
                          + PAGE_HEAP_NO_USER_LOW
 
2141
                          != count + 1)) {
 
2142
                fprintf(stderr, "InnoDB: n recs wrong %lu %lu\n",
 
2143
                        (ulong) page_header_get_field(page, PAGE_N_RECS)
 
2144
                        + PAGE_HEAP_NO_USER_LOW,
 
2145
                        (ulong) (count + 1));
 
2146
 
 
2147
                goto func_exit;
 
2148
        }
 
2149
 
 
2150
        /* Check then the free list */
 
2151
        rec = page_header_get_ptr(page, PAGE_FREE);
 
2152
 
 
2153
        while (rec != NULL) {
 
2154
                if (UNIV_UNLIKELY(rec < page + FIL_PAGE_DATA
 
2155
                                  || rec >= page + UNIV_PAGE_SIZE)) {
 
2156
                        fprintf(stderr,
 
2157
                                "InnoDB: Free list record has"
 
2158
                                " a nonsensical offset %lu\n",
 
2159
                                (ulong) page_offset(rec));
 
2160
 
 
2161
                        goto func_exit;
 
2162
                }
 
2163
 
 
2164
                if (UNIV_UNLIKELY(rec > rec_heap_top)) {
 
2165
                        fprintf(stderr,
 
2166
                                "InnoDB: Free list record %lu"
 
2167
                                " is above rec heap top %lu\n",
 
2168
                                (ulong) page_offset(rec),
 
2169
                                (ulong) page_offset(rec_heap_top));
 
2170
 
 
2171
                        goto func_exit;
 
2172
                }
 
2173
 
 
2174
                count++;
 
2175
 
 
2176
                if (UNIV_UNLIKELY(count > UNIV_PAGE_SIZE)) {
 
2177
                        fprintf(stderr,
 
2178
                                "InnoDB: Page free list appears"
 
2179
                                " to be circular %lu\n",
 
2180
                                (ulong) count);
 
2181
                        goto func_exit;
 
2182
                }
 
2183
 
 
2184
                rec = page_rec_get_next(rec);
 
2185
        }
 
2186
 
 
2187
        if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) {
1742
2188
 
1743
2189
                fprintf(stderr, "InnoDB: N heap is wrong %lu, %lu\n",
1744
2190
                        (ulong) page_dir_get_n_heap(page),
1755
2201
 
1756
2202
/*******************************************************************
1757
2203
This function checks the consistency of an index page. */
1758
 
 
 
2204
UNIV_INTERN
1759
2205
ibool
1760
2206
page_validate(
1761
2207
/*==========*/
1764
2210
        dict_index_t*   index)  /* in: data dictionary index containing
1765
2211
                                the page record type definition */
1766
2212
{
1767
 
        page_dir_slot_t* slot;
 
2213
        page_dir_slot_t*slot;
1768
2214
        mem_heap_t*     heap;
1769
 
        page_cur_t      cur;
1770
2215
        byte*           buf;
1771
2216
        ulint           count;
1772
2217
        ulint           own_count;
 
2218
        ulint           rec_own_count;
1773
2219
        ulint           slot_no;
1774
2220
        ulint           data_size;
1775
2221
        rec_t*          rec;
1778
2224
        ulint           n_slots;
1779
2225
        ibool           ret             = FALSE;
1780
2226
        ulint           i;
1781
 
        ulint           comp            = page_is_comp(page);
1782
2227
        ulint*          offsets         = NULL;
1783
2228
        ulint*          old_offsets     = NULL;
1784
2229
 
1785
 
        if ((ibool)!!comp != dict_table_is_comp(index->table)) {
 
2230
        if (UNIV_UNLIKELY((ibool) !!page_is_comp(page)
 
2231
                          != dict_table_is_comp(index->table))) {
1786
2232
                fputs("InnoDB: 'compact format' flag mismatch\n", stderr);
1787
2233
                goto func_exit2;
1788
2234
        }
1789
 
        if (!page_simple_validate(page)) {
1790
 
                goto func_exit2;
 
2235
        if (page_is_comp(page)) {
 
2236
                if (UNIV_UNLIKELY(!page_simple_validate_new(page))) {
 
2237
                        goto func_exit2;
 
2238
                }
 
2239
        } else {
 
2240
                if (UNIV_UNLIKELY(!page_simple_validate_old(page))) {
 
2241
                        goto func_exit2;
 
2242
                }
1791
2243
        }
1792
2244
 
1793
2245
        heap = mem_heap_create(UNIV_PAGE_SIZE + 200);
1795
2247
        /* The following buffer is used to check that the
1796
2248
        records in the page record heap do not overlap */
1797
2249
 
1798
 
        buf = mem_heap_alloc(heap, UNIV_PAGE_SIZE);
1799
 
        memset(buf, 0, UNIV_PAGE_SIZE);
 
2250
        buf = mem_heap_zalloc(heap, UNIV_PAGE_SIZE);
1800
2251
 
1801
2252
        /* Check first that the record heap and the directory do not
1802
2253
        overlap. */
1803
2254
 
1804
2255
        n_slots = page_dir_get_n_slots(page);
1805
2256
 
1806
 
        if (!(page_header_get_ptr(page, PAGE_HEAP_TOP)
1807
 
              <= page_dir_get_nth_slot(page, n_slots - 1))) {
 
2257
        if (UNIV_UNLIKELY(!(page_header_get_ptr(page, PAGE_HEAP_TOP)
 
2258
                            <= page_dir_get_nth_slot(page, n_slots - 1)))) {
1808
2259
 
1809
2260
                fputs("InnoDB: Record heap and dir overlap on a page ",
1810
2261
                      stderr);
1824
2275
        slot_no = 0;
1825
2276
        slot = page_dir_get_nth_slot(page, slot_no);
1826
2277
 
1827
 
        page_cur_set_before_first(page, &cur);
 
2278
        rec = page_get_infimum_rec(page);
1828
2279
 
1829
2280
        for (;;) {
1830
 
                rec = cur.rec;
1831
2281
                offsets = rec_get_offsets(rec, index, offsets,
1832
2282
                                          ULINT_UNDEFINED, &heap);
1833
2283
 
1834
 
                if (comp && page_rec_is_user_rec(rec)
1835
 
                    && rec_get_node_ptr_flag(rec)
1836
 
                    != (ibool)
1837
 
                    (btr_page_get_level_low(page) != 0)) {
 
2284
                if (page_is_comp(page) && page_rec_is_user_rec(rec)
 
2285
                    && UNIV_UNLIKELY(rec_get_node_ptr_flag(rec)
 
2286
                                     == page_is_leaf(page))) {
1838
2287
                        fputs("InnoDB: node_ptr flag mismatch\n", stderr);
1839
2288
                        goto func_exit;
1840
2289
                }
1841
2290
 
1842
 
                if (!page_rec_validate(rec, offsets)) {
 
2291
                if (UNIV_UNLIKELY(!page_rec_validate(rec, offsets))) {
1843
2292
                        goto func_exit;
1844
2293
                }
1845
2294
 
1846
2295
                /* Check that the records are in the ascending order */
1847
 
                if ((count >= 2) && (!page_cur_is_after_last(&cur))) {
1848
 
                        if (!(1 == cmp_rec_rec(rec, old_rec,
1849
 
                                               offsets, old_offsets, index))) {
 
2296
                if (UNIV_LIKELY(count >= PAGE_HEAP_NO_USER_LOW)
 
2297
                    && !page_rec_is_supremum(rec)) {
 
2298
                        if (UNIV_UNLIKELY
 
2299
                            (1 != cmp_rec_rec(rec, old_rec,
 
2300
                                              offsets, old_offsets, index))) {
1850
2301
                                fprintf(stderr,
1851
2302
                                        "InnoDB: Records in wrong order"
1852
2303
                                        " on page %lu ",
1853
 
                                        (ulong) buf_frame_get_page_no(page));
 
2304
                                        (ulong) page_get_page_no(page));
1854
2305
                                dict_index_name_print(stderr, NULL, index);
1855
2306
                                fputs("\nInnoDB: previous record ", stderr);
1856
2307
                                rec_print_new(stderr, old_rec, old_offsets);
1867
2318
                        data_size += rec_offs_size(offsets);
1868
2319
                }
1869
2320
 
1870
 
                offs = rec_get_start(rec, offsets) - page;
 
2321
                offs = page_offset(rec_get_start(rec, offsets));
1871
2322
 
1872
 
                for (i = 0; i < rec_offs_size(offsets); i++) {
1873
 
                        if (!buf[offs + i] == 0) {
 
2323
                for (i = rec_offs_size(offsets); i--; ) {
 
2324
                        if (UNIV_UNLIKELY(buf[offs + i])) {
1874
2325
                                /* No other record may overlap this */
1875
2326
 
1876
2327
                                fputs("InnoDB: Record overlaps another\n",
1881
2332
                        buf[offs + i] = 1;
1882
2333
                }
1883
2334
 
1884
 
                if (rec_get_n_owned(rec, comp) != 0) {
 
2335
                if (page_is_comp(page)) {
 
2336
                        rec_own_count = rec_get_n_owned_new(rec);
 
2337
                } else {
 
2338
                        rec_own_count = rec_get_n_owned_old(rec);
 
2339
                }
 
2340
 
 
2341
                if (UNIV_UNLIKELY(rec_own_count)) {
1885
2342
                        /* This is a record pointed to by a dir slot */
1886
 
                        if (rec_get_n_owned(rec, comp) != own_count) {
 
2343
                        if (UNIV_UNLIKELY(rec_own_count != own_count)) {
1887
2344
                                fprintf(stderr,
1888
2345
                                        "InnoDB: Wrong owned count %lu, %lu\n",
1889
 
                                        (ulong) rec_get_n_owned(rec, comp),
 
2346
                                        (ulong) rec_own_count,
1890
2347
                                        (ulong) own_count);
1891
2348
                                goto func_exit;
1892
2349
                        }
1901
2358
                        page_dir_slot_check(slot);
1902
2359
 
1903
2360
                        own_count = 0;
1904
 
                        if (!page_cur_is_after_last(&cur)) {
 
2361
                        if (!page_rec_is_supremum(rec)) {
1905
2362
                                slot_no++;
1906
2363
                                slot = page_dir_get_nth_slot(page, slot_no);
1907
2364
                        }
1908
2365
                }
1909
2366
 
1910
 
                if (page_cur_is_after_last(&cur)) {
 
2367
                if (page_rec_is_supremum(rec)) {
1911
2368
                        break;
1912
2369
                }
1913
2370
 
1914
 
                if (rec_get_next_offs(rec, comp) < FIL_PAGE_DATA
1915
 
                    || rec_get_next_offs(rec, comp) >= UNIV_PAGE_SIZE) {
1916
 
                        fprintf(stderr,
1917
 
                                "InnoDB: Next record offset wrong %lu\n",
1918
 
                                (ulong) rec_get_next_offs(rec, comp));
1919
 
                        goto func_exit;
1920
 
                }
1921
 
 
1922
2371
                count++;
1923
 
                page_cur_move_to_next(&cur);
1924
2372
                own_count++;
1925
2373
                old_rec = rec;
 
2374
                rec = page_rec_get_next(rec);
 
2375
 
1926
2376
                /* set old_offsets to offsets; recycle offsets */
1927
2377
                {
1928
2378
                        ulint* offs = old_offsets;
1931
2381
                }
1932
2382
        }
1933
2383
 
1934
 
        if (rec_get_n_owned(rec, comp) == 0) {
 
2384
        if (page_is_comp(page)) {
 
2385
                if (UNIV_UNLIKELY(rec_get_n_owned_new(rec) == 0)) {
 
2386
 
 
2387
                        goto n_owned_zero;
 
2388
                }
 
2389
        } else if (UNIV_UNLIKELY(rec_get_n_owned_old(rec) == 0)) {
 
2390
n_owned_zero:
1935
2391
                fputs("InnoDB: n owned is zero\n", stderr);
1936
2392
                goto func_exit;
1937
2393
        }
1938
2394
 
1939
 
        if (slot_no != n_slots - 1) {
 
2395
        if (UNIV_UNLIKELY(slot_no != n_slots - 1)) {
1940
2396
                fprintf(stderr, "InnoDB: n slots wrong %lu %lu\n",
1941
2397
                        (ulong) slot_no, (ulong) (n_slots - 1));
1942
2398
                goto func_exit;
1943
2399
        }
1944
2400
 
1945
 
        if (page_header_get_field(page, PAGE_N_RECS) + 2 != count + 1) {
 
2401
        if (UNIV_UNLIKELY(page_header_get_field(page, PAGE_N_RECS)
 
2402
                          + PAGE_HEAP_NO_USER_LOW
 
2403
                          != count + 1)) {
1946
2404
                fprintf(stderr, "InnoDB: n recs wrong %lu %lu\n",
1947
 
                        (ulong) page_header_get_field(page, PAGE_N_RECS) + 2,
 
2405
                        (ulong) page_header_get_field(page, PAGE_N_RECS)
 
2406
                        + PAGE_HEAP_NO_USER_LOW,
1948
2407
                        (ulong) (count + 1));
1949
2408
                goto func_exit;
1950
2409
        }
1951
2410
 
1952
 
        if (data_size != page_get_data_size(page)) {
 
2411
        if (UNIV_UNLIKELY(data_size != page_get_data_size(page))) {
1953
2412
                fprintf(stderr,
1954
2413
                        "InnoDB: Summed data size %lu, returned by func %lu\n",
1955
2414
                        (ulong) data_size, (ulong) page_get_data_size(page));
1962
2421
        while (rec != NULL) {
1963
2422
                offsets = rec_get_offsets(rec, index, offsets,
1964
2423
                                          ULINT_UNDEFINED, &heap);
1965
 
                if (!page_rec_validate(rec, offsets)) {
 
2424
                if (UNIV_UNLIKELY(!page_rec_validate(rec, offsets))) {
1966
2425
 
1967
2426
                        goto func_exit;
1968
2427
                }
1969
2428
 
1970
2429
                count++;
1971
 
                offs = rec_get_start(rec, offsets) - page;
1972
 
 
1973
 
                for (i = 0; i < rec_offs_size(offsets); i++) {
1974
 
 
1975
 
                        if (buf[offs + i] != 0) {
 
2430
                offs = page_offset(rec_get_start(rec, offsets));
 
2431
 
 
2432
                for (i = rec_offs_size(offsets); i--; ) {
 
2433
 
 
2434
                        if (UNIV_UNLIKELY(buf[offs + i])) {
1976
2435
                                fputs("InnoDB: Record overlaps another"
1977
2436
                                      " in free list\n", stderr);
1978
2437
                                goto func_exit;
1984
2443
                rec = page_rec_get_next(rec);
1985
2444
        }
1986
2445
 
1987
 
        if (page_dir_get_n_heap(page) != count + 1) {
 
2446
        if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) {
1988
2447
                fprintf(stderr, "InnoDB: N heap is wrong %lu %lu\n",
1989
2448
                        (ulong) page_dir_get_n_heap(page),
1990
2449
                        (ulong) count + 1);
1996
2455
func_exit:
1997
2456
        mem_heap_free(heap);
1998
2457
 
1999
 
        if (ret == FALSE) {
 
2458
        if (UNIV_UNLIKELY(ret == FALSE)) {
2000
2459
func_exit2:
2001
2460
                fprintf(stderr, "InnoDB: Apparent corruption in page %lu in ",
2002
 
                        (ulong) buf_frame_get_page_no(page));
 
2461
                        (ulong) page_get_page_no(page));
2003
2462
                dict_index_name_print(stderr, NULL, index);
2004
2463
                putc('\n', stderr);
2005
 
                buf_page_print(page);
 
2464
                buf_page_print(page, 0);
2006
2465
        }
2007
2466
 
2008
2467
        return(ret);
2010
2469
 
2011
2470
/*******************************************************************
2012
2471
Looks in the page record list for a record with the given heap number. */
2013
 
 
2014
 
rec_t*
 
2472
UNIV_INTERN
 
2473
const rec_t*
2015
2474
page_find_rec_with_heap_no(
2016
2475
/*=======================*/
2017
 
                        /* out: record, NULL if not found */
2018
 
        page_t* page,   /* in: index page */
2019
 
        ulint   heap_no)/* in: heap number */
 
2476
                                /* out: record, NULL if not found */
 
2477
        const page_t*   page,   /* in: index page */
 
2478
        ulint           heap_no)/* in: heap number */
2020
2479
{
2021
 
        page_cur_t      cur;
2022
 
 
2023
 
        page_cur_set_before_first(page, &cur);
2024
 
 
2025
 
        for (;;) {
2026
 
                if (rec_get_heap_no(cur.rec, page_is_comp(page)) == heap_no) {
2027
 
 
2028
 
                        return(cur.rec);
2029
 
                }
2030
 
 
2031
 
                if (page_cur_is_after_last(&cur)) {
2032
 
 
2033
 
                        return(NULL);
2034
 
                }
2035
 
 
2036
 
                page_cur_move_to_next(&cur);
 
2480
        const rec_t*    rec;
 
2481
 
 
2482
        if (page_is_comp(page)) {
 
2483
                rec = page + PAGE_NEW_INFIMUM;
 
2484
 
 
2485
                for(;;) {
 
2486
                        ulint   rec_heap_no = rec_get_heap_no_new(rec);
 
2487
 
 
2488
                        if (rec_heap_no == heap_no) {
 
2489
 
 
2490
                                return(rec);
 
2491
                        } else if (rec_heap_no == PAGE_HEAP_NO_SUPREMUM) {
 
2492
 
 
2493
                                return(NULL);
 
2494
                        }
 
2495
 
 
2496
                        rec = page + rec_get_next_offs(rec, TRUE);
 
2497
                }
 
2498
        } else {
 
2499
                rec = page + PAGE_OLD_INFIMUM;
 
2500
 
 
2501
                for (;;) {
 
2502
                        ulint   rec_heap_no = rec_get_heap_no_old(rec);
 
2503
 
 
2504
                        if (rec_heap_no == heap_no) {
 
2505
 
 
2506
                                return(rec);
 
2507
                        } else if (rec_heap_no == PAGE_HEAP_NO_SUPREMUM) {
 
2508
 
 
2509
                                return(NULL);
 
2510
                        }
 
2511
 
 
2512
                        rec = page + rec_get_next_offs(rec, FALSE);
 
2513
                }
2037
2514
        }
2038
2515
}