~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2008-10-28 08:36:02 UTC
  • mfrom: (520.4.13 merge-innodb-plugin)
  • Revision ID: brian@tangent.org-20081028083602-0p3zzlhlxr5q2sqo
Merging Monty's work

Show diffs side-by-side

added added

removed removed

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