~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/include/page0page.ic

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
Index page routines
 
3
 
 
4
(c) 1994-1996 Innobase Oy
 
5
 
 
6
Created 2/2/1994 Heikki Tuuri
 
7
*******************************************************/
 
8
 
 
9
#include "mach0data.h"
 
10
#include "rem0cmp.h"
 
11
#include "mtr0log.h"
 
12
 
 
13
#ifdef UNIV_MATERIALIZE
 
14
#undef UNIV_INLINE
 
15
#define UNIV_INLINE
 
16
#endif
 
17
 
 
18
/****************************************************************
 
19
Gets the start of a page. */
 
20
UNIV_INLINE
 
21
page_t*
 
22
page_align(
 
23
/*=======*/
 
24
                        /* out: start of the page */
 
25
        void*   ptr)    /* in: pointer to page frame */
 
26
{
 
27
        return((page_t*) ut_align_down(ptr, UNIV_PAGE_SIZE));
 
28
}
 
29
/****************************************************************
 
30
Gets the offset within a page. */
 
31
UNIV_INLINE
 
32
ulint
 
33
page_offset(
 
34
/*========*/
 
35
                                /* out: offset from the start of the page */
 
36
        const void*     ptr)    /* in: pointer to page frame */
 
37
{
 
38
        return(ut_align_offset(ptr, UNIV_PAGE_SIZE));
 
39
}
 
40
/*****************************************************************
 
41
Returns the max trx id field value. */
 
42
UNIV_INLINE
 
43
dulint
 
44
page_get_max_trx_id(
 
45
/*================*/
 
46
        page_t* page)   /* in: page */
 
47
{
 
48
        ut_ad(page);
 
49
 
 
50
        return(mach_read_from_8(page + PAGE_HEADER + PAGE_MAX_TRX_ID));
 
51
}
 
52
 
 
53
/*****************************************************************
 
54
Sets the max trx id field value if trx_id is bigger than the previous
 
55
value. */
 
56
UNIV_INLINE
 
57
void
 
58
page_update_max_trx_id(
 
59
/*===================*/
 
60
        page_t* page,   /* in: page */
 
61
        dulint  trx_id) /* in: transaction id */
 
62
{
 
63
        ut_ad(page);
 
64
 
 
65
        if (ut_dulint_cmp(page_get_max_trx_id(page), trx_id) < 0) {
 
66
 
 
67
                page_set_max_trx_id(page, trx_id);
 
68
        }
 
69
}
 
70
 
 
71
/*****************************************************************
 
72
Reads the given header field. */
 
73
UNIV_INLINE
 
74
ulint
 
75
page_header_get_field(
 
76
/*==================*/
 
77
        page_t* page,   /* in: page */
 
78
        ulint   field)  /* in: PAGE_LEVEL, ... */
 
79
{
 
80
        ut_ad(page);
 
81
        ut_ad(field <= PAGE_INDEX_ID);
 
82
 
 
83
        return(mach_read_from_2(page + PAGE_HEADER + field));
 
84
}
 
85
 
 
86
/*****************************************************************
 
87
Sets the given header field. */
 
88
UNIV_INLINE
 
89
void
 
90
page_header_set_field(
 
91
/*==================*/
 
92
        page_t* page,   /* in: page */
 
93
        ulint   field,  /* in: PAGE_LEVEL, ... */
 
94
        ulint   val)    /* in: value */
 
95
{
 
96
        ut_ad(page);
 
97
        ut_ad(field <= PAGE_N_RECS);
 
98
        ut_ad(field == PAGE_N_HEAP || val < UNIV_PAGE_SIZE);
 
99
        ut_ad(field != PAGE_N_HEAP || (val & 0x7fff) < UNIV_PAGE_SIZE);
 
100
 
 
101
        mach_write_to_2(page + PAGE_HEADER + field, val);
 
102
}
 
103
 
 
104
/*****************************************************************
 
105
Returns the pointer stored in the given header field. */
 
106
UNIV_INLINE
 
107
byte*
 
108
page_header_get_ptr(
 
109
/*================*/
 
110
                        /* out: pointer or NULL */
 
111
        page_t* page,   /* in: page */
 
112
        ulint   field)  /* in: PAGE_FREE, ... */
 
113
{
 
114
        ulint   offs;
 
115
 
 
116
        ut_ad(page);
 
117
        ut_ad((field == PAGE_FREE)
 
118
              || (field == PAGE_LAST_INSERT)
 
119
              || (field == PAGE_HEAP_TOP));
 
120
 
 
121
        offs = page_header_get_field(page, field);
 
122
 
 
123
        ut_ad((field != PAGE_HEAP_TOP) || offs);
 
124
 
 
125
        if (offs == 0) {
 
126
 
 
127
                return(NULL);
 
128
        }
 
129
 
 
130
        return(page + offs);
 
131
}
 
132
 
 
133
/*****************************************************************
 
134
Sets the pointer stored in the given header field. */
 
135
UNIV_INLINE
 
136
void
 
137
page_header_set_ptr(
 
138
/*================*/
 
139
        page_t* page,   /* in: page */
 
140
        ulint   field,  /* in: PAGE_FREE, ... */
 
141
        byte*   ptr)    /* in: pointer or NULL*/
 
142
{
 
143
        ulint   offs;
 
144
 
 
145
        ut_ad(page);
 
146
        ut_ad((field == PAGE_FREE)
 
147
              || (field == PAGE_LAST_INSERT)
 
148
              || (field == PAGE_HEAP_TOP));
 
149
 
 
150
        if (ptr == NULL) {
 
151
                offs = 0;
 
152
        } else {
 
153
                offs = ptr - page;
 
154
        }
 
155
 
 
156
        ut_ad((field != PAGE_HEAP_TOP) || offs);
 
157
 
 
158
        page_header_set_field(page, field, offs);
 
159
}
 
160
 
 
161
/*****************************************************************
 
162
Resets the last insert info field in the page header. Writes to mlog
 
163
about this operation. */
 
164
UNIV_INLINE
 
165
void
 
166
page_header_reset_last_insert(
 
167
/*==========================*/
 
168
        page_t* page,   /* in: page */
 
169
        mtr_t*  mtr)    /* in: mtr */
 
170
{
 
171
        ut_ad(page && mtr);
 
172
 
 
173
        mlog_write_ulint(page + PAGE_HEADER + PAGE_LAST_INSERT, 0,
 
174
                         MLOG_2BYTES, mtr);
 
175
}
 
176
 
 
177
/****************************************************************
 
178
Determine whether the page is in new-style compact format. */
 
179
UNIV_INLINE
 
180
ulint
 
181
page_is_comp(
 
182
/*=========*/
 
183
                        /* out: nonzero if the page is in compact
 
184
                        format, zero if it is in old-style format */
 
185
        page_t* page)   /* in: index page */
 
186
{
 
187
        return(UNIV_EXPECT(page_header_get_field(page, PAGE_N_HEAP) & 0x8000,
 
188
                           0x8000));
 
189
}
 
190
 
 
191
/****************************************************************
 
192
TRUE if the record is on a page in compact format. */
 
193
UNIV_INLINE
 
194
ulint
 
195
page_rec_is_comp(
 
196
/*=============*/
 
197
                                /* out: nonzero if in compact format */
 
198
        const rec_t*    rec)    /* in: record */
 
199
{
 
200
        return(page_is_comp(page_align((rec_t*) rec)));
 
201
}
 
202
 
 
203
/****************************************************************
 
204
Gets the first record on the page. */
 
205
UNIV_INLINE
 
206
rec_t*
 
207
page_get_infimum_rec(
 
208
/*=================*/
 
209
                        /* out: the first record in record list */
 
210
        page_t* page)   /* in: page which must have record(s) */
 
211
{
 
212
        ut_ad(page);
 
213
 
 
214
        if (page_is_comp(page)) {
 
215
                return(page + PAGE_NEW_INFIMUM);
 
216
        } else {
 
217
                return(page + PAGE_OLD_INFIMUM);
 
218
        }
 
219
}
 
220
 
 
221
/****************************************************************
 
222
Gets the last record on the page. */
 
223
UNIV_INLINE
 
224
rec_t*
 
225
page_get_supremum_rec(
 
226
/*==================*/
 
227
                        /* out: the last record in record list */
 
228
        page_t* page)   /* in: page which must have record(s) */
 
229
{
 
230
        ut_ad(page);
 
231
 
 
232
        if (page_is_comp(page)) {
 
233
                return(page + PAGE_NEW_SUPREMUM);
 
234
        } else {
 
235
                return(page + PAGE_OLD_SUPREMUM);
 
236
        }
 
237
}
 
238
 
 
239
/****************************************************************
 
240
TRUE if the record is a user record on the page. */
 
241
UNIV_INLINE
 
242
ibool
 
243
page_rec_is_user_rec_low(
 
244
/*=====================*/
 
245
                        /* out: TRUE if a user record */
 
246
        ulint   offset) /* in: record offset on page */
 
247
{
 
248
        ut_ad(offset >= PAGE_NEW_INFIMUM);
 
249
#if PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM
 
250
# error "PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM"
 
251
#endif
 
252
#if PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM
 
253
# error "PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM"
 
254
#endif
 
255
#if PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM
 
256
# error "PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM"
 
257
#endif
 
258
#if PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM
 
259
# error "PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM"
 
260
#endif
 
261
#if PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END
 
262
# error "PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END"
 
263
#endif
 
264
#if PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END
 
265
# error "PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END"
 
266
#endif
 
267
        ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
 
268
 
 
269
        return(UNIV_LIKELY(offset != PAGE_NEW_SUPREMUM)
 
270
               && UNIV_LIKELY(offset != PAGE_NEW_INFIMUM)
 
271
               && UNIV_LIKELY(offset != PAGE_OLD_INFIMUM)
 
272
               && UNIV_LIKELY(offset != PAGE_OLD_SUPREMUM));
 
273
}
 
274
 
 
275
/****************************************************************
 
276
TRUE if the record is the supremum record on a page. */
 
277
UNIV_INLINE
 
278
ibool
 
279
page_rec_is_supremum_low(
 
280
/*=====================*/
 
281
                        /* out: TRUE if the supremum record */
 
282
        ulint   offset) /* in: record offset on page */
 
283
{
 
284
        ut_ad(offset >= PAGE_NEW_INFIMUM);
 
285
        ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
 
286
 
 
287
        return(UNIV_UNLIKELY(offset == PAGE_NEW_SUPREMUM)
 
288
               || UNIV_UNLIKELY(offset == PAGE_OLD_SUPREMUM));
 
289
}
 
290
 
 
291
/****************************************************************
 
292
TRUE if the record is the infimum record on a page. */
 
293
UNIV_INLINE
 
294
ibool
 
295
page_rec_is_infimum_low(
 
296
/*====================*/
 
297
                        /* out: TRUE if the infimum record */
 
298
        ulint   offset) /* in: record offset on page */
 
299
{
 
300
        ut_ad(offset >= PAGE_NEW_INFIMUM);
 
301
        ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
 
302
 
 
303
        return(UNIV_UNLIKELY(offset == PAGE_NEW_INFIMUM)
 
304
               || UNIV_UNLIKELY(offset == PAGE_OLD_INFIMUM));
 
305
}
 
306
 
 
307
/****************************************************************
 
308
TRUE if the record is a user record on the page. */
 
309
UNIV_INLINE
 
310
ibool
 
311
page_rec_is_user_rec(
 
312
/*=================*/
 
313
                                /* out: TRUE if a user record */
 
314
        const rec_t*    rec)    /* in: record */
 
315
{
 
316
        return(page_rec_is_user_rec_low(page_offset(rec)));
 
317
}
 
318
 
 
319
/****************************************************************
 
320
TRUE if the record is the supremum record on a page. */
 
321
UNIV_INLINE
 
322
ibool
 
323
page_rec_is_supremum(
 
324
/*=================*/
 
325
                                /* out: TRUE if the supremum record */
 
326
        const rec_t*    rec)    /* in: record */
 
327
{
 
328
        return(page_rec_is_supremum_low(page_offset(rec)));
 
329
}
 
330
 
 
331
/****************************************************************
 
332
TRUE if the record is the infimum record on a page. */
 
333
UNIV_INLINE
 
334
ibool
 
335
page_rec_is_infimum(
 
336
/*================*/
 
337
                                /* out: TRUE if the infimum record */
 
338
        const rec_t*    rec)    /* in: record */
 
339
{
 
340
        return(page_rec_is_infimum_low(page_offset(rec)));
 
341
}
 
342
 
 
343
/*****************************************************************
 
344
Compares a data tuple to a physical record. Differs from the function
 
345
cmp_dtuple_rec_with_match in the way that the record must reside on an
 
346
index page, and also page infimum and supremum records can be given in
 
347
the parameter rec. These are considered as the negative infinity and
 
348
the positive infinity in the alphabetical order. */
 
349
UNIV_INLINE
 
350
int
 
351
page_cmp_dtuple_rec_with_match(
 
352
/*===========================*/
 
353
                                /* out: 1, 0, -1, if dtuple is greater, equal,
 
354
                                less than rec, respectively, when only the
 
355
                                common first fields are compared */
 
356
        dtuple_t*       dtuple, /* in: data tuple */
 
357
        rec_t*          rec,    /* in: physical record on a page; may also
 
358
                                be page infimum or supremum, in which case
 
359
                                matched-parameter values below are not
 
360
                                affected */
 
361
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
 
362
        ulint*          matched_fields, /* in/out: number of already completely
 
363
                                matched fields; when function returns
 
364
                                contains the value for current comparison */
 
365
        ulint*          matched_bytes) /* in/out: number of already matched
 
366
                                bytes within the first field not completely
 
367
                                matched; when function returns contains the
 
368
                                value for current comparison */
 
369
{
 
370
        ulint   rec_offset;
 
371
 
 
372
        ut_ad(dtuple_check_typed(dtuple));
 
373
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
374
        ut_ad(!rec_offs_comp(offsets) == !page_rec_is_comp(rec));
 
375
 
 
376
        rec_offset = page_offset(rec);
 
377
 
 
378
        if (UNIV_UNLIKELY(rec_offset == PAGE_NEW_INFIMUM)
 
379
            || UNIV_UNLIKELY(rec_offset == PAGE_OLD_INFIMUM)) {
 
380
                return(1);
 
381
        }
 
382
        if (UNIV_UNLIKELY(rec_offset == PAGE_NEW_SUPREMUM)
 
383
            || UNIV_UNLIKELY(rec_offset == PAGE_OLD_SUPREMUM)) {
 
384
                return(-1);
 
385
        }
 
386
 
 
387
        return(cmp_dtuple_rec_with_match(dtuple, rec, offsets,
 
388
                                         matched_fields,
 
389
                                         matched_bytes));
 
390
}
 
391
 
 
392
/*****************************************************************
 
393
Gets the number of user records on page (infimum and supremum records
 
394
are not user records). */
 
395
UNIV_INLINE
 
396
ulint
 
397
page_get_n_recs(
 
398
/*============*/
 
399
                        /* out: number of user records */
 
400
        page_t* page)   /* in: index page */
 
401
{
 
402
        return(page_header_get_field(page, PAGE_N_RECS));
 
403
}
 
404
 
 
405
/*****************************************************************
 
406
Gets the number of dir slots in directory. */
 
407
UNIV_INLINE
 
408
ulint
 
409
page_dir_get_n_slots(
 
410
/*=================*/
 
411
                        /* out: number of slots */
 
412
        page_t* page)   /* in: index page */
 
413
{
 
414
        return(page_header_get_field(page, PAGE_N_DIR_SLOTS));
 
415
}
 
416
/*****************************************************************
 
417
Sets the number of dir slots in directory. */
 
418
UNIV_INLINE
 
419
void
 
420
page_dir_set_n_slots(
 
421
/*=================*/
 
422
                        /* out: number of slots */
 
423
        page_t* page,   /* in: index page */
 
424
        ulint   n_slots)/* in: number of slots */
 
425
{
 
426
        page_header_set_field(page, PAGE_N_DIR_SLOTS, n_slots);
 
427
}
 
428
 
 
429
/*****************************************************************
 
430
Gets the number of records in the heap. */
 
431
UNIV_INLINE
 
432
ulint
 
433
page_dir_get_n_heap(
 
434
/*================*/
 
435
                        /* out: number of user records */
 
436
        page_t* page)   /* in: index page */
 
437
{
 
438
        return(page_header_get_field(page, PAGE_N_HEAP) & 0x7fff);
 
439
}
 
440
 
 
441
/*****************************************************************
 
442
Sets the number of records in the heap. */
 
443
UNIV_INLINE
 
444
void
 
445
page_dir_set_n_heap(
 
446
/*================*/
 
447
        page_t* page,   /* in: index page */
 
448
        ulint   n_heap) /* in: number of records */
 
449
{
 
450
        ut_ad(n_heap < 0x8000);
 
451
 
 
452
        page_header_set_field(page, PAGE_N_HEAP, n_heap
 
453
                              | (0x8000
 
454
                                 & page_header_get_field(page, PAGE_N_HEAP)));
 
455
}
 
456
 
 
457
/*****************************************************************
 
458
Gets pointer to nth directory slot. */
 
459
UNIV_INLINE
 
460
page_dir_slot_t*
 
461
page_dir_get_nth_slot(
 
462
/*==================*/
 
463
                        /* out: pointer to dir slot */
 
464
        page_t* page,   /* in: index page */
 
465
        ulint   n)      /* in: position */
 
466
{
 
467
        ut_ad(page_dir_get_n_slots(page) > n);
 
468
 
 
469
        return(page + UNIV_PAGE_SIZE - PAGE_DIR
 
470
               - (n + 1) * PAGE_DIR_SLOT_SIZE);
 
471
}
 
472
 
 
473
/******************************************************************
 
474
Used to check the consistency of a record on a page. */
 
475
UNIV_INLINE
 
476
ibool
 
477
page_rec_check(
 
478
/*===========*/
 
479
                        /* out: TRUE if succeed */
 
480
        rec_t*  rec)    /* in: record */
 
481
{
 
482
        page_t* page;
 
483
 
 
484
        ut_a(rec);
 
485
 
 
486
        page = buf_frame_align(rec);
 
487
 
 
488
        ut_a(rec <= page_header_get_ptr(page, PAGE_HEAP_TOP));
 
489
        ut_a(rec >= page + PAGE_DATA);
 
490
 
 
491
        return(TRUE);
 
492
}
 
493
 
 
494
/*******************************************************************
 
495
Gets the record pointed to by a directory slot. */
 
496
UNIV_INLINE
 
497
rec_t*
 
498
page_dir_slot_get_rec(
 
499
/*==================*/
 
500
                                        /* out: pointer to record */
 
501
        page_dir_slot_t*        slot)   /* in: directory slot */
 
502
{
 
503
        return(buf_frame_align(slot) + mach_read_from_2(slot));
 
504
}
 
505
 
 
506
/*******************************************************************
 
507
This is used to set the record offset in a directory slot. */
 
508
UNIV_INLINE
 
509
void
 
510
page_dir_slot_set_rec(
 
511
/*==================*/
 
512
        page_dir_slot_t* slot,  /* in: directory slot */
 
513
        rec_t*           rec)   /* in: record on the page */
 
514
{
 
515
        ut_ad(page_rec_check(rec));
 
516
 
 
517
        mach_write_to_2(slot, page_offset(rec));
 
518
}
 
519
 
 
520
/*******************************************************************
 
521
Gets the number of records owned by a directory slot. */
 
522
UNIV_INLINE
 
523
ulint
 
524
page_dir_slot_get_n_owned(
 
525
/*======================*/
 
526
                                        /* out: number of records */
 
527
        page_dir_slot_t*        slot)   /* in: page directory slot */
 
528
{
 
529
        rec_t*  rec     = page_dir_slot_get_rec(slot);
 
530
        return(rec_get_n_owned(rec, page_rec_is_comp(rec)));
 
531
}
 
532
 
 
533
/*******************************************************************
 
534
This is used to set the owned records field of a directory slot. */
 
535
UNIV_INLINE
 
536
void
 
537
page_dir_slot_set_n_owned(
 
538
/*======================*/
 
539
        page_dir_slot_t*        slot,   /* in: directory slot */
 
540
        ulint                   n)      /* in: number of records owned
 
541
                                        by the slot */
 
542
{
 
543
        rec_t*  rec     = page_dir_slot_get_rec(slot);
 
544
        rec_set_n_owned(rec, page_rec_is_comp(rec), n);
 
545
}
 
546
 
 
547
/****************************************************************
 
548
Calculates the space reserved for directory slots of a given number of
 
549
records. The exact value is a fraction number n * PAGE_DIR_SLOT_SIZE /
 
550
PAGE_DIR_SLOT_MIN_N_OWNED, and it is rounded upwards to an integer. */
 
551
UNIV_INLINE
 
552
ulint
 
553
page_dir_calc_reserved_space(
 
554
/*=========================*/
 
555
        ulint   n_recs)         /* in: number of records */
 
556
{
 
557
        return((PAGE_DIR_SLOT_SIZE * n_recs + PAGE_DIR_SLOT_MIN_N_OWNED - 1)
 
558
               / PAGE_DIR_SLOT_MIN_N_OWNED);
 
559
}
 
560
 
 
561
/****************************************************************
 
562
Gets the pointer to the next record on the page. */
 
563
UNIV_INLINE
 
564
rec_t*
 
565
page_rec_get_next(
 
566
/*==============*/
 
567
                        /* out: pointer to next record */
 
568
        rec_t*  rec)    /* in: pointer to record */
 
569
{
 
570
        ulint   offs;
 
571
        page_t* page;
 
572
 
 
573
        ut_ad(page_rec_check(rec));
 
574
 
 
575
        page = page_align(rec);
 
576
 
 
577
        offs = rec_get_next_offs(rec, page_is_comp(page));
 
578
 
 
579
        if (UNIV_UNLIKELY(offs >= UNIV_PAGE_SIZE)) {
 
580
                fprintf(stderr,
 
581
                        "InnoDB: Next record offset is nonsensical %lu"
 
582
                        " in record at offset %lu\n"
 
583
                        "InnoDB: rec address %p, first buffer frame %p\n"
 
584
                        "InnoDB: buffer pool high end %p, buf fix count %lu\n",
 
585
                        (ulong)offs, (ulong)(rec - page),
 
586
                        (void*) rec, (void*) buf_pool->frame_zero,
 
587
                        (void*) buf_pool->high_end,
 
588
                        (ulong) buf_block_align(rec)->buf_fix_count);
 
589
                buf_page_print(page);
 
590
 
 
591
                ut_error;
 
592
        }
 
593
 
 
594
        if (UNIV_UNLIKELY(offs == 0)) {
 
595
 
 
596
                return(NULL);
 
597
        }
 
598
 
 
599
        return(page + offs);
 
600
}
 
601
 
 
602
/****************************************************************
 
603
Sets the pointer to the next record on the page. */
 
604
UNIV_INLINE
 
605
void
 
606
page_rec_set_next(
 
607
/*==============*/
 
608
        rec_t*  rec,    /* in: pointer to record, must not be page supremum */
 
609
        rec_t*  next)   /* in: pointer to next record, must not be page
 
610
                        infimum */
 
611
{
 
612
        page_t* page;
 
613
        ulint   offs;
 
614
 
 
615
        ut_ad(page_rec_check(rec));
 
616
        ut_ad(!page_rec_is_supremum(rec));
 
617
        page = page_align(rec);
 
618
 
 
619
        if (next) {
 
620
                ut_ad(!page_rec_is_infimum(next));
 
621
                ut_ad(page == page_align(next));
 
622
                offs = (ulint) (next - page);
 
623
        } else {
 
624
                offs = 0;
 
625
        }
 
626
 
 
627
        rec_set_next_offs(rec, page_is_comp(page), offs);
 
628
}
 
629
 
 
630
/****************************************************************
 
631
Gets the pointer to the previous record. */
 
632
UNIV_INLINE
 
633
rec_t*
 
634
page_rec_get_prev(
 
635
/*==============*/
 
636
                        /* out: pointer to previous record */
 
637
        rec_t*  rec)    /* in: pointer to record, must not be page
 
638
                        infimum */
 
639
{
 
640
        page_dir_slot_t*        slot;
 
641
        ulint                   slot_no;
 
642
        rec_t*                  rec2;
 
643
        rec_t*                  prev_rec = NULL;
 
644
        page_t*                 page;
 
645
 
 
646
        ut_ad(page_rec_check(rec));
 
647
 
 
648
        page = page_align(rec);
 
649
 
 
650
        ut_ad(!page_rec_is_infimum(rec));
 
651
 
 
652
        slot_no = page_dir_find_owner_slot(rec);
 
653
 
 
654
        ut_a(slot_no != 0);
 
655
 
 
656
        slot = page_dir_get_nth_slot(page, slot_no - 1);
 
657
 
 
658
        rec2 = page_dir_slot_get_rec(slot);
 
659
 
 
660
        while (rec != rec2) {
 
661
                prev_rec = rec2;
 
662
                rec2 = page_rec_get_next(rec2);
 
663
        }
 
664
 
 
665
        ut_a(prev_rec);
 
666
 
 
667
        return(prev_rec);
 
668
}
 
669
 
 
670
/*******************************************************************
 
671
Looks for the record which owns the given record. */
 
672
UNIV_INLINE
 
673
rec_t*
 
674
page_rec_find_owner_rec(
 
675
/*====================*/
 
676
                        /* out: the owner record */
 
677
        rec_t*  rec)    /* in: the physical record */
 
678
{
 
679
        ut_ad(page_rec_check(rec));
 
680
 
 
681
        if (page_rec_is_comp(rec)) {
 
682
                while (rec_get_n_owned(rec, TRUE) == 0) {
 
683
                        rec = page_rec_get_next(rec);
 
684
                }
 
685
        } else {
 
686
                while (rec_get_n_owned(rec, FALSE) == 0) {
 
687
                        rec = page_rec_get_next(rec);
 
688
                }
 
689
        }
 
690
 
 
691
        return(rec);
 
692
}
 
693
 
 
694
/****************************************************************
 
695
Returns the sum of the sizes of the records in the record list, excluding
 
696
the infimum and supremum records. */
 
697
UNIV_INLINE
 
698
ulint
 
699
page_get_data_size(
 
700
/*===============*/
 
701
                        /* out: data in bytes */
 
702
        page_t* page)   /* in: index page */
 
703
{
 
704
        ulint   ret;
 
705
 
 
706
        ret = (ulint)(page_header_get_field(page, PAGE_HEAP_TOP)
 
707
                      - (page_is_comp(page)
 
708
                         ? PAGE_NEW_SUPREMUM_END
 
709
                         : PAGE_OLD_SUPREMUM_END)
 
710
                      - page_header_get_field(page, PAGE_GARBAGE));
 
711
 
 
712
        ut_ad(ret < UNIV_PAGE_SIZE);
 
713
 
 
714
        return(ret);
 
715
}
 
716
 
 
717
/*****************************************************************
 
718
Calculates free space if a page is emptied. */
 
719
UNIV_INLINE
 
720
ulint
 
721
page_get_free_space_of_empty(
 
722
/*=========================*/
 
723
                                /* out: free space */
 
724
        ulint   comp)           /* in: nonzero=compact page layout */
 
725
{
 
726
        if (UNIV_LIKELY(comp)) {
 
727
                return((ulint)(UNIV_PAGE_SIZE
 
728
                               - PAGE_NEW_SUPREMUM_END
 
729
                               - PAGE_DIR
 
730
                               - 2 * PAGE_DIR_SLOT_SIZE));
 
731
        }
 
732
 
 
733
        return((ulint)(UNIV_PAGE_SIZE
 
734
                       - PAGE_OLD_SUPREMUM_END
 
735
                       - PAGE_DIR
 
736
                       - 2 * PAGE_DIR_SLOT_SIZE));
 
737
}
 
738
 
 
739
/****************************************************************
 
740
Each user record on a page, and also the deleted user records in the heap
 
741
takes its size plus the fraction of the dir cell size /
 
742
PAGE_DIR_SLOT_MIN_N_OWNED bytes for it. If the sum of these exceeds the
 
743
value of page_get_free_space_of_empty, the insert is impossible, otherwise
 
744
it is allowed. This function returns the maximum combined size of records
 
745
which can be inserted on top of the record heap. */
 
746
UNIV_INLINE
 
747
ulint
 
748
page_get_max_insert_size(
 
749
/*=====================*/
 
750
                        /* out: maximum combined size for inserted records */
 
751
        page_t* page,   /* in: index page */
 
752
        ulint   n_recs) /* in: number of records */
 
753
{
 
754
        ulint   occupied;
 
755
        ulint   free_space;
 
756
 
 
757
        if (page_is_comp(page)) {
 
758
                occupied = page_header_get_field(page, PAGE_HEAP_TOP)
 
759
                        - PAGE_NEW_SUPREMUM_END
 
760
                        + page_dir_calc_reserved_space(
 
761
                                n_recs + page_dir_get_n_heap(page) - 2);
 
762
 
 
763
                free_space = page_get_free_space_of_empty(TRUE);
 
764
        } else {
 
765
                occupied = page_header_get_field(page, PAGE_HEAP_TOP)
 
766
                        - PAGE_OLD_SUPREMUM_END
 
767
                        + page_dir_calc_reserved_space(
 
768
                                n_recs + page_dir_get_n_heap(page) - 2);
 
769
 
 
770
                free_space = page_get_free_space_of_empty(FALSE);
 
771
        }
 
772
 
 
773
        /* Above the 'n_recs +' part reserves directory space for the new
 
774
        inserted records; the '- 2' excludes page infimum and supremum
 
775
        records */
 
776
 
 
777
        if (occupied > free_space) {
 
778
 
 
779
                return(0);
 
780
        }
 
781
 
 
782
        return(free_space - occupied);
 
783
}
 
784
 
 
785
/****************************************************************
 
786
Returns the maximum combined size of records which can be inserted on top
 
787
of the record heap if a page is first reorganized. */
 
788
UNIV_INLINE
 
789
ulint
 
790
page_get_max_insert_size_after_reorganize(
 
791
/*======================================*/
 
792
                        /* out: maximum combined size for inserted records */
 
793
        page_t* page,   /* in: index page */
 
794
        ulint   n_recs) /* in: number of records */
 
795
{
 
796
        ulint   occupied;
 
797
        ulint   free_space;
 
798
 
 
799
        occupied = page_get_data_size(page)
 
800
                + page_dir_calc_reserved_space(n_recs + page_get_n_recs(page));
 
801
 
 
802
        free_space = page_get_free_space_of_empty(page_is_comp(page));
 
803
 
 
804
        if (occupied > free_space) {
 
805
 
 
806
                return(0);
 
807
        }
 
808
 
 
809
        return(free_space - occupied);
 
810
}
 
811
 
 
812
/****************************************************************
 
813
Puts a record to free list. */
 
814
UNIV_INLINE
 
815
void
 
816
page_mem_free(
 
817
/*==========*/
 
818
        page_t*         page,   /* in: index page */
 
819
        rec_t*          rec,    /* in: pointer to the (origin of) record */
 
820
        const ulint*    offsets)/* in: array returned by rec_get_offsets() */
 
821
{
 
822
        rec_t*          free;
 
823
        ulint           garbage;
 
824
 
 
825
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
826
        ut_ad(!rec_offs_comp(offsets) == !page_rec_is_comp(rec));
 
827
        free = page_header_get_ptr(page, PAGE_FREE);
 
828
 
 
829
        page_rec_set_next(rec, free);
 
830
        page_header_set_ptr(page, PAGE_FREE, rec);
 
831
 
 
832
#if 0   /* It's better not to destroy the user's data. */
 
833
 
 
834
        /* Clear the data bytes of the deleted record in order to improve
 
835
        the compression ratio of the page and to make it easier to read
 
836
        page dumps in corruption reports.  The extra bytes of the record
 
837
        cannot be cleared, because page_mem_alloc() needs them in order
 
838
        to determine the size of the deleted record. */
 
839
        memset(rec, 0, rec_offs_data_size(offsets));
 
840
#endif
 
841
 
 
842
        garbage = page_header_get_field(page, PAGE_GARBAGE);
 
843
 
 
844
        page_header_set_field(page, PAGE_GARBAGE,
 
845
                              garbage + rec_offs_size(offsets));
 
846
}
 
847
 
 
848
#ifdef UNIV_MATERIALIZE
 
849
#undef UNIV_INLINE
 
850
#define UNIV_INLINE     UNIV_INLINE_ORIGINAL
 
851
#endif