~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2010-12-24 02:13:05 UTC
  • mto: This revision was merged to the branch mainline in revision 2038.
  • Revision ID: mordred@inaugust.com-20101224021305-e3slv1cyjczqorij
Changed the bzrignore file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 
 
3
Copyright (C) 1994, 2009, Innobase Oy. All Rights Reserved.
 
4
 
 
5
This program is free software; you can redistribute it and/or modify it under
 
6
the terms of the GNU General Public License as published by the Free Software
 
7
Foundation; version 2 of the License.
 
8
 
 
9
This program is distributed in the hope that it will be useful, but WITHOUT
 
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 
12
 
 
13
You should have received a copy of the GNU General Public License along with
 
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 
15
St, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
*****************************************************************************/
 
18
 
 
19
/**************************************************//**
 
20
@file include/page0page.ic
 
21
Index page routines
 
22
 
 
23
Created 2/2/1994 Heikki Tuuri
 
24
*******************************************************/
 
25
 
 
26
#include "mach0data.h"
 
27
#ifdef UNIV_DEBUG
 
28
# include "log0recv.h"
 
29
#endif /* !UNIV_DEBUG */
 
30
#ifndef UNIV_HOTBACKUP
 
31
# include "rem0cmp.h"
 
32
#endif /* !UNIV_HOTBACKUP */
 
33
#include "mtr0log.h"
 
34
#include "page0zip.h"
 
35
 
 
36
#ifdef UNIV_MATERIALIZE
 
37
#undef UNIV_INLINE
 
38
#define UNIV_INLINE
 
39
#endif
 
40
 
 
41
/************************************************************//**
 
42
Gets the start of a page.
 
43
@return start of the page */
 
44
UNIV_INLINE
 
45
page_t*
 
46
page_align(
 
47
/*=======*/
 
48
        const void*     ptr)    /*!< in: pointer to page frame */
 
49
{
 
50
        return((page_t*) ut_align_down(ptr, UNIV_PAGE_SIZE));
 
51
}
 
52
/************************************************************//**
 
53
Gets the offset within a page.
 
54
@return offset from the start of the page */
 
55
UNIV_INLINE
 
56
ulint
 
57
page_offset(
 
58
/*========*/
 
59
        const void*     ptr)    /*!< in: pointer to page frame */
 
60
{
 
61
        return(ut_align_offset(ptr, UNIV_PAGE_SIZE));
 
62
}
 
63
/*************************************************************//**
 
64
Returns the max trx id field value. */
 
65
UNIV_INLINE
 
66
trx_id_t
 
67
page_get_max_trx_id(
 
68
/*================*/
 
69
        const page_t*   page)   /*!< in: page */
 
70
{
 
71
        ut_ad(page);
 
72
 
 
73
        return(mach_read_from_8(page + PAGE_HEADER + PAGE_MAX_TRX_ID));
 
74
}
 
75
 
 
76
/*************************************************************//**
 
77
Sets the max trx id field value if trx_id is bigger than the previous
 
78
value. */
 
79
UNIV_INLINE
 
80
void
 
81
page_update_max_trx_id(
 
82
/*===================*/
 
83
        buf_block_t*    block,  /*!< in/out: page */
 
84
        page_zip_des_t* page_zip,/*!< in/out: compressed page whose
 
85
                                uncompressed part will be updated, or NULL */
 
86
        trx_id_t        trx_id, /*!< in: transaction id */
 
87
        mtr_t*          mtr)    /*!< in/out: mini-transaction */
 
88
{
 
89
        ut_ad(block);
 
90
        ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
 
91
        /* During crash recovery, this function may be called on
 
92
        something else than a leaf page of a secondary index or the
 
93
        insert buffer index tree (dict_index_is_sec_or_ibuf() returns
 
94
        TRUE for the dummy indexes constructed during redo log
 
95
        application).  In that case, PAGE_MAX_TRX_ID is unused,
 
96
        and trx_id is usually zero. */
 
97
        ut_ad(trx_id || recv_recovery_is_on());
 
98
        ut_ad(page_is_leaf(buf_block_get_frame(block)));
 
99
 
 
100
        if (page_get_max_trx_id(buf_block_get_frame(block)) < trx_id) {
 
101
 
 
102
                page_set_max_trx_id(block, page_zip, trx_id, mtr);
 
103
        }
 
104
}
 
105
 
 
106
/*************************************************************//**
 
107
Reads the given header field. */
 
108
UNIV_INLINE
 
109
ulint
 
110
page_header_get_field(
 
111
/*==================*/
 
112
        const page_t*   page,   /*!< in: page */
 
113
        ulint           field)  /*!< in: PAGE_LEVEL, ... */
 
114
{
 
115
        ut_ad(page);
 
116
        ut_ad(field <= PAGE_INDEX_ID);
 
117
 
 
118
        return(mach_read_from_2(page + PAGE_HEADER + field));
 
119
}
 
120
 
 
121
/*************************************************************//**
 
122
Sets the given header field. */
 
123
UNIV_INLINE
 
124
void
 
125
page_header_set_field(
 
126
/*==================*/
 
127
        page_t*         page,   /*!< in/out: page */
 
128
        page_zip_des_t* page_zip,/*!< in/out: compressed page whose
 
129
                                uncompressed part will be updated, or NULL */
 
130
        ulint           field,  /*!< in: PAGE_N_DIR_SLOTS, ... */
 
131
        ulint           val)    /*!< in: value */
 
132
{
 
133
        ut_ad(page);
 
134
        ut_ad(field <= PAGE_N_RECS);
 
135
        ut_ad(field == PAGE_N_HEAP || val < UNIV_PAGE_SIZE);
 
136
        ut_ad(field != PAGE_N_HEAP || (val & 0x7fff) < UNIV_PAGE_SIZE);
 
137
 
 
138
        mach_write_to_2(page + PAGE_HEADER + field, val);
 
139
        if (UNIV_LIKELY_NULL(page_zip)) {
 
140
                page_zip_write_header(page_zip,
 
141
                                      page + PAGE_HEADER + field, 2, NULL);
 
142
        }
 
143
}
 
144
 
 
145
/*************************************************************//**
 
146
Returns the offset stored in the given header field.
 
147
@return offset from the start of the page, or 0 */
 
148
UNIV_INLINE
 
149
ulint
 
150
page_header_get_offs(
 
151
/*=================*/
 
152
        const page_t*   page,   /*!< in: page */
 
153
        ulint           field)  /*!< in: PAGE_FREE, ... */
 
154
{
 
155
        ulint   offs;
 
156
 
 
157
        ut_ad(page);
 
158
        ut_ad((field == PAGE_FREE)
 
159
              || (field == PAGE_LAST_INSERT)
 
160
              || (field == PAGE_HEAP_TOP));
 
161
 
 
162
        offs = page_header_get_field(page, field);
 
163
 
 
164
        ut_ad((field != PAGE_HEAP_TOP) || offs);
 
165
 
 
166
        return(offs);
 
167
}
 
168
 
 
169
/*************************************************************//**
 
170
Sets the pointer stored in the given header field. */
 
171
UNIV_INLINE
 
172
void
 
173
page_header_set_ptr(
 
174
/*================*/
 
175
        page_t*         page,   /*!< in: page */
 
176
        page_zip_des_t* page_zip,/*!< in/out: compressed page whose
 
177
                                uncompressed part will be updated, or NULL */
 
178
        ulint           field,  /*!< in: PAGE_FREE, ... */
 
179
        const byte*     ptr)    /*!< in: pointer or NULL*/
 
180
{
 
181
        ulint   offs;
 
182
 
 
183
        ut_ad(page);
 
184
        ut_ad((field == PAGE_FREE)
 
185
              || (field == PAGE_LAST_INSERT)
 
186
              || (field == PAGE_HEAP_TOP));
 
187
 
 
188
        if (ptr == NULL) {
 
189
                offs = 0;
 
190
        } else {
 
191
                offs = ptr - page;
 
192
        }
 
193
 
 
194
        ut_ad((field != PAGE_HEAP_TOP) || offs);
 
195
 
 
196
        page_header_set_field(page, page_zip, field, offs);
 
197
}
 
198
 
 
199
#ifndef UNIV_HOTBACKUP
 
200
/*************************************************************//**
 
201
Resets the last insert info field in the page header. Writes to mlog
 
202
about this operation. */
 
203
UNIV_INLINE
 
204
void
 
205
page_header_reset_last_insert(
 
206
/*==========================*/
 
207
        page_t*         page,   /*!< in/out: page */
 
208
        page_zip_des_t* page_zip,/*!< in/out: compressed page whose
 
209
                                uncompressed part will be updated, or NULL */
 
210
        mtr_t*          mtr)    /*!< in: mtr */
 
211
{
 
212
        ut_ad(page && mtr);
 
213
 
 
214
        if (UNIV_LIKELY_NULL(page_zip)) {
 
215
                mach_write_to_2(page + (PAGE_HEADER + PAGE_LAST_INSERT), 0);
 
216
                page_zip_write_header(page_zip,
 
217
                                      page + (PAGE_HEADER + PAGE_LAST_INSERT),
 
218
                                      2, mtr);
 
219
        } else {
 
220
                mlog_write_ulint(page + (PAGE_HEADER + PAGE_LAST_INSERT), 0,
 
221
                                 MLOG_2BYTES, mtr);
 
222
        }
 
223
}
 
224
#endif /* !UNIV_HOTBACKUP */
 
225
 
 
226
/************************************************************//**
 
227
Determine whether the page is in new-style compact format.
 
228
@return nonzero if the page is in compact format, zero if it is in
 
229
old-style format */
 
230
UNIV_INLINE
 
231
ulint
 
232
page_is_comp(
 
233
/*=========*/
 
234
        const page_t*   page)   /*!< in: index page */
 
235
{
 
236
        return(UNIV_EXPECT(page_header_get_field(page, PAGE_N_HEAP) & 0x8000,
 
237
                           0x8000));
 
238
}
 
239
 
 
240
/************************************************************//**
 
241
TRUE if the record is on a page in compact format.
 
242
@return nonzero if in compact format */
 
243
UNIV_INLINE
 
244
ulint
 
245
page_rec_is_comp(
 
246
/*=============*/
 
247
        const rec_t*    rec)    /*!< in: record */
 
248
{
 
249
        return(page_is_comp(page_align(rec)));
 
250
}
 
251
 
 
252
/***************************************************************//**
 
253
Returns the heap number of a record.
 
254
@return heap number */
 
255
UNIV_INLINE
 
256
ulint
 
257
page_rec_get_heap_no(
 
258
/*=================*/
 
259
        const rec_t*    rec)    /*!< in: the physical record */
 
260
{
 
261
        if (page_rec_is_comp(rec)) {
 
262
                return(rec_get_heap_no_new(rec));
 
263
        } else {
 
264
                return(rec_get_heap_no_old(rec));
 
265
        }
 
266
}
 
267
 
 
268
/************************************************************//**
 
269
Determine whether the page is a B-tree leaf.
 
270
@return TRUE if the page is a B-tree leaf */
 
271
UNIV_INLINE
 
272
ibool
 
273
page_is_leaf(
 
274
/*=========*/
 
275
        const page_t*   page)   /*!< in: page */
 
276
{
 
277
        return(!*(const uint16*) (page + (PAGE_HEADER + PAGE_LEVEL)));
 
278
}
 
279
 
 
280
/************************************************************//**
 
281
Gets the offset of the first record on the page.
 
282
@return offset of the first record in record list, relative from page */
 
283
UNIV_INLINE
 
284
ulint
 
285
page_get_infimum_offset(
 
286
/*====================*/
 
287
        const page_t*   page)   /*!< in: page which must have record(s) */
 
288
{
 
289
        ut_ad(page);
 
290
        ut_ad(!page_offset(page));
 
291
 
 
292
        if (page_is_comp(page)) {
 
293
                return(PAGE_NEW_INFIMUM);
 
294
        } else {
 
295
                return(PAGE_OLD_INFIMUM);
 
296
        }
 
297
}
 
298
 
 
299
/************************************************************//**
 
300
Gets the offset of the last record on the page.
 
301
@return offset of the last record in record list, relative from page */
 
302
UNIV_INLINE
 
303
ulint
 
304
page_get_supremum_offset(
 
305
/*=====================*/
 
306
        const page_t*   page)   /*!< in: page which must have record(s) */
 
307
{
 
308
        ut_ad(page);
 
309
        ut_ad(!page_offset(page));
 
310
 
 
311
        if (page_is_comp(page)) {
 
312
                return(PAGE_NEW_SUPREMUM);
 
313
        } else {
 
314
                return(PAGE_OLD_SUPREMUM);
 
315
        }
 
316
}
 
317
 
 
318
/************************************************************//**
 
319
TRUE if the record is a user record on the page.
 
320
@return TRUE if a user record */
 
321
UNIV_INLINE
 
322
ibool
 
323
page_rec_is_user_rec_low(
 
324
/*=====================*/
 
325
        ulint   offset) /*!< in: record offset on page */
 
326
{
 
327
        ut_ad(offset >= PAGE_NEW_INFIMUM);
 
328
#if PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM
 
329
# error "PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM"
 
330
#endif
 
331
#if PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM
 
332
# error "PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM"
 
333
#endif
 
334
#if PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM
 
335
# error "PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM"
 
336
#endif
 
337
#if PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM
 
338
# error "PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM"
 
339
#endif
 
340
#if PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END
 
341
# error "PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END"
 
342
#endif
 
343
#if PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END
 
344
# error "PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END"
 
345
#endif
 
346
        ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
 
347
 
 
348
        return(UNIV_LIKELY(offset != PAGE_NEW_SUPREMUM)
 
349
               && UNIV_LIKELY(offset != PAGE_NEW_INFIMUM)
 
350
               && UNIV_LIKELY(offset != PAGE_OLD_INFIMUM)
 
351
               && UNIV_LIKELY(offset != PAGE_OLD_SUPREMUM));
 
352
}
 
353
 
 
354
/************************************************************//**
 
355
TRUE if the record is the supremum record on a page.
 
356
@return TRUE if the supremum record */
 
357
UNIV_INLINE
 
358
ibool
 
359
page_rec_is_supremum_low(
 
360
/*=====================*/
 
361
        ulint   offset) /*!< in: record offset on page */
 
362
{
 
363
        ut_ad(offset >= PAGE_NEW_INFIMUM);
 
364
        ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
 
365
 
 
366
        return(UNIV_UNLIKELY(offset == PAGE_NEW_SUPREMUM)
 
367
               || UNIV_UNLIKELY(offset == PAGE_OLD_SUPREMUM));
 
368
}
 
369
 
 
370
/************************************************************//**
 
371
TRUE if the record is the infimum record on a page.
 
372
@return TRUE if the infimum record */
 
373
UNIV_INLINE
 
374
ibool
 
375
page_rec_is_infimum_low(
 
376
/*====================*/
 
377
        ulint   offset) /*!< in: record offset on page */
 
378
{
 
379
        ut_ad(offset >= PAGE_NEW_INFIMUM);
 
380
        ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
 
381
 
 
382
        return(UNIV_UNLIKELY(offset == PAGE_NEW_INFIMUM)
 
383
               || UNIV_UNLIKELY(offset == PAGE_OLD_INFIMUM));
 
384
}
 
385
 
 
386
/************************************************************//**
 
387
TRUE if the record is a user record on the page.
 
388
@return TRUE if a user record */
 
389
UNIV_INLINE
 
390
ibool
 
391
page_rec_is_user_rec(
 
392
/*=================*/
 
393
        const rec_t*    rec)    /*!< in: record */
 
394
{
 
395
        return(page_rec_is_user_rec_low(page_offset(rec)));
 
396
}
 
397
 
 
398
/************************************************************//**
 
399
TRUE if the record is the supremum record on a page.
 
400
@return TRUE if the supremum record */
 
401
UNIV_INLINE
 
402
ibool
 
403
page_rec_is_supremum(
 
404
/*=================*/
 
405
        const rec_t*    rec)    /*!< in: record */
 
406
{
 
407
        return(page_rec_is_supremum_low(page_offset(rec)));
 
408
}
 
409
 
 
410
/************************************************************//**
 
411
TRUE if the record is the infimum record on a page.
 
412
@return TRUE if the infimum record */
 
413
UNIV_INLINE
 
414
ibool
 
415
page_rec_is_infimum(
 
416
/*================*/
 
417
        const rec_t*    rec)    /*!< in: record */
 
418
{
 
419
        return(page_rec_is_infimum_low(page_offset(rec)));
 
420
}
 
421
 
 
422
#ifndef UNIV_HOTBACKUP
 
423
/*************************************************************//**
 
424
Compares a data tuple to a physical record. Differs from the function
 
425
cmp_dtuple_rec_with_match in the way that the record must reside on an
 
426
index page, and also page infimum and supremum records can be given in
 
427
the parameter rec. These are considered as the negative infinity and
 
428
the positive infinity in the alphabetical order.
 
429
@return 1, 0, -1, if dtuple is greater, equal, less than rec,
 
430
respectively, when only the common first fields are compared */
 
431
UNIV_INLINE
 
432
int
 
433
page_cmp_dtuple_rec_with_match(
 
434
/*===========================*/
 
435
        const dtuple_t* dtuple, /*!< in: data tuple */
 
436
        const rec_t*    rec,    /*!< in: physical record on a page; may also
 
437
                                be page infimum or supremum, in which case
 
438
                                matched-parameter values below are not
 
439
                                affected */
 
440
        const ulint*    offsets,/*!< in: array returned by rec_get_offsets() */
 
441
        ulint*          matched_fields, /*!< in/out: number of already completely
 
442
                                matched fields; when function returns
 
443
                                contains the value for current comparison */
 
444
        ulint*          matched_bytes) /*!< in/out: number of already matched
 
445
                                bytes within the first field not completely
 
446
                                matched; when function returns contains the
 
447
                                value for current comparison */
 
448
{
 
449
        ulint   rec_offset;
 
450
 
 
451
        ut_ad(dtuple_check_typed(dtuple));
 
452
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
453
        ut_ad(!rec_offs_comp(offsets) == !page_rec_is_comp(rec));
 
454
 
 
455
        rec_offset = page_offset(rec);
 
456
 
 
457
        if (UNIV_UNLIKELY(rec_offset == PAGE_NEW_INFIMUM)
 
458
            || UNIV_UNLIKELY(rec_offset == PAGE_OLD_INFIMUM)) {
 
459
                return(1);
 
460
        }
 
461
        if (UNIV_UNLIKELY(rec_offset == PAGE_NEW_SUPREMUM)
 
462
            || UNIV_UNLIKELY(rec_offset == PAGE_OLD_SUPREMUM)) {
 
463
                return(-1);
 
464
        }
 
465
 
 
466
        return(cmp_dtuple_rec_with_match(dtuple, rec, offsets,
 
467
                                         matched_fields,
 
468
                                         matched_bytes));
 
469
}
 
470
#endif /* !UNIV_HOTBACKUP */
 
471
 
 
472
/*************************************************************//**
 
473
Gets the page number.
 
474
@return page number */
 
475
UNIV_INLINE
 
476
ulint
 
477
page_get_page_no(
 
478
/*=============*/
 
479
        const page_t*   page)   /*!< in: page */
 
480
{
 
481
        ut_ad(page == page_align((page_t*) page));
 
482
        return(mach_read_from_4(page + FIL_PAGE_OFFSET));
 
483
}
 
484
 
 
485
/*************************************************************//**
 
486
Gets the tablespace identifier.
 
487
@return space id */
 
488
UNIV_INLINE
 
489
ulint
 
490
page_get_space_id(
 
491
/*==============*/
 
492
        const page_t*   page)   /*!< in: page */
 
493
{
 
494
        ut_ad(page == page_align((page_t*) page));
 
495
        return(mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
 
496
}
 
497
 
 
498
/*************************************************************//**
 
499
Gets the number of user records on page (infimum and supremum records
 
500
are not user records).
 
501
@return number of user records */
 
502
UNIV_INLINE
 
503
ulint
 
504
page_get_n_recs(
 
505
/*============*/
 
506
        const page_t*   page)   /*!< in: index page */
 
507
{
 
508
        return(page_header_get_field(page, PAGE_N_RECS));
 
509
}
 
510
 
 
511
/*************************************************************//**
 
512
Gets the number of dir slots in directory.
 
513
@return number of slots */
 
514
UNIV_INLINE
 
515
ulint
 
516
page_dir_get_n_slots(
 
517
/*=================*/
 
518
        const page_t*   page)   /*!< in: index page */
 
519
{
 
520
        return(page_header_get_field(page, PAGE_N_DIR_SLOTS));
 
521
}
 
522
/*************************************************************//**
 
523
Sets the number of dir slots in directory. */
 
524
UNIV_INLINE
 
525
void
 
526
page_dir_set_n_slots(
 
527
/*=================*/
 
528
        page_t*         page,   /*!< in/out: page */
 
529
        page_zip_des_t* page_zip,/*!< in/out: compressed page whose
 
530
                                uncompressed part will be updated, or NULL */
 
531
        ulint           n_slots)/*!< in: number of slots */
 
532
{
 
533
        page_header_set_field(page, page_zip, PAGE_N_DIR_SLOTS, n_slots);
 
534
}
 
535
 
 
536
/*************************************************************//**
 
537
Gets the number of records in the heap.
 
538
@return number of user records */
 
539
UNIV_INLINE
 
540
ulint
 
541
page_dir_get_n_heap(
 
542
/*================*/
 
543
        const page_t*   page)   /*!< in: index page */
 
544
{
 
545
        return(page_header_get_field(page, PAGE_N_HEAP) & 0x7fff);
 
546
}
 
547
 
 
548
/*************************************************************//**
 
549
Sets the number of records in the heap. */
 
550
UNIV_INLINE
 
551
void
 
552
page_dir_set_n_heap(
 
553
/*================*/
 
554
        page_t*         page,   /*!< in/out: index page */
 
555
        page_zip_des_t* page_zip,/*!< in/out: compressed page whose
 
556
                                uncompressed part will be updated, or NULL.
 
557
                                Note that the size of the dense page directory
 
558
                                in the compressed page trailer is
 
559
                                n_heap * PAGE_ZIP_DIR_SLOT_SIZE. */
 
560
        ulint           n_heap) /*!< in: number of records */
 
561
{
 
562
        ut_ad(n_heap < 0x8000);
 
563
        ut_ad(!page_zip || n_heap
 
564
              == (page_header_get_field(page, PAGE_N_HEAP) & 0x7fff) + 1);
 
565
 
 
566
        page_header_set_field(page, page_zip, PAGE_N_HEAP, n_heap
 
567
                              | (0x8000
 
568
                                 & page_header_get_field(page, PAGE_N_HEAP)));
 
569
}
 
570
 
 
571
#ifdef UNIV_DEBUG
 
572
/*************************************************************//**
 
573
Gets pointer to nth directory slot.
 
574
@return pointer to dir slot */
 
575
UNIV_INLINE
 
576
page_dir_slot_t*
 
577
page_dir_get_nth_slot(
 
578
/*==================*/
 
579
        const page_t*   page,   /*!< in: index page */
 
580
        ulint           n)      /*!< in: position */
 
581
{
 
582
        ut_ad(page_dir_get_n_slots(page) > n);
 
583
 
 
584
        return((page_dir_slot_t*)
 
585
               page + UNIV_PAGE_SIZE - PAGE_DIR
 
586
               - (n + 1) * PAGE_DIR_SLOT_SIZE);
 
587
}
 
588
#endif /* UNIV_DEBUG */
 
589
 
 
590
/**************************************************************//**
 
591
Used to check the consistency of a record on a page.
 
592
@return TRUE if succeed */
 
593
UNIV_INLINE
 
594
ibool
 
595
page_rec_check(
 
596
/*===========*/
 
597
        const rec_t*    rec)    /*!< in: record */
 
598
{
 
599
        const page_t*   page = page_align(rec);
 
600
 
 
601
        ut_a(rec);
 
602
 
 
603
        ut_a(page_offset(rec) <= page_header_get_field(page, PAGE_HEAP_TOP));
 
604
        ut_a(page_offset(rec) >= PAGE_DATA);
 
605
 
 
606
        return(TRUE);
 
607
}
 
608
 
 
609
/***************************************************************//**
 
610
Gets the record pointed to by a directory slot.
 
611
@return pointer to record */
 
612
UNIV_INLINE
 
613
const rec_t*
 
614
page_dir_slot_get_rec(
 
615
/*==================*/
 
616
        const page_dir_slot_t*  slot)   /*!< in: directory slot */
 
617
{
 
618
        return(page_align(slot) + mach_read_from_2(slot));
 
619
}
 
620
 
 
621
/***************************************************************//**
 
622
This is used to set the record offset in a directory slot. */
 
623
UNIV_INLINE
 
624
void
 
625
page_dir_slot_set_rec(
 
626
/*==================*/
 
627
        page_dir_slot_t* slot,  /*!< in: directory slot */
 
628
        rec_t*           rec)   /*!< in: record on the page */
 
629
{
 
630
        ut_ad(page_rec_check(rec));
 
631
 
 
632
        mach_write_to_2(slot, page_offset(rec));
 
633
}
 
634
 
 
635
/***************************************************************//**
 
636
Gets the number of records owned by a directory slot.
 
637
@return number of records */
 
638
UNIV_INLINE
 
639
ulint
 
640
page_dir_slot_get_n_owned(
 
641
/*======================*/
 
642
        const page_dir_slot_t*  slot)   /*!< in: page directory slot */
 
643
{
 
644
        const rec_t*    rec     = page_dir_slot_get_rec(slot);
 
645
        if (page_rec_is_comp(slot)) {
 
646
                return(rec_get_n_owned_new(rec));
 
647
        } else {
 
648
                return(rec_get_n_owned_old(rec));
 
649
        }
 
650
}
 
651
 
 
652
/***************************************************************//**
 
653
This is used to set the owned records field of a directory slot. */
 
654
UNIV_INLINE
 
655
void
 
656
page_dir_slot_set_n_owned(
 
657
/*======================*/
 
658
        page_dir_slot_t*slot,   /*!< in/out: directory slot */
 
659
        page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
 
660
        ulint           n)      /*!< in: number of records owned by the slot */
 
661
{
 
662
        rec_t*  rec     = (rec_t*) page_dir_slot_get_rec(slot);
 
663
        if (page_rec_is_comp(slot)) {
 
664
                rec_set_n_owned_new(rec, page_zip, n);
 
665
        } else {
 
666
                ut_ad(!page_zip);
 
667
                rec_set_n_owned_old(rec, n);
 
668
        }
 
669
}
 
670
 
 
671
/************************************************************//**
 
672
Calculates the space reserved for directory slots of a given number of
 
673
records. The exact value is a fraction number n * PAGE_DIR_SLOT_SIZE /
 
674
PAGE_DIR_SLOT_MIN_N_OWNED, and it is rounded upwards to an integer. */
 
675
UNIV_INLINE
 
676
ulint
 
677
page_dir_calc_reserved_space(
 
678
/*=========================*/
 
679
        ulint   n_recs)         /*!< in: number of records */
 
680
{
 
681
        return((PAGE_DIR_SLOT_SIZE * n_recs + PAGE_DIR_SLOT_MIN_N_OWNED - 1)
 
682
               / PAGE_DIR_SLOT_MIN_N_OWNED);
 
683
}
 
684
 
 
685
/************************************************************//**
 
686
Gets the pointer to the next record on the page.
 
687
@return pointer to next record */
 
688
UNIV_INLINE
 
689
const rec_t*
 
690
page_rec_get_next_low(
 
691
/*==================*/
 
692
        const rec_t*    rec,    /*!< in: pointer to record */
 
693
        ulint           comp)   /*!< in: nonzero=compact page layout */
 
694
{
 
695
        ulint           offs;
 
696
        const page_t*   page;
 
697
 
 
698
        ut_ad(page_rec_check(rec));
 
699
 
 
700
        page = page_align(rec);
 
701
 
 
702
        offs = rec_get_next_offs(rec, comp);
 
703
 
 
704
        if (UNIV_UNLIKELY(offs >= UNIV_PAGE_SIZE)) {
 
705
                fprintf(stderr,
 
706
                        "InnoDB: Next record offset is nonsensical %lu"
 
707
                        " in record at offset %lu\n"
 
708
                        "InnoDB: rec address %p, space id %lu, page %lu\n",
 
709
                        (ulong)offs, (ulong) page_offset(rec),
 
710
                        (void*) rec,
 
711
                        (ulong) page_get_space_id(page),
 
712
                        (ulong) page_get_page_no(page));
 
713
                buf_page_print(page, 0);
 
714
 
 
715
                ut_error;
 
716
        }
 
717
 
 
718
        if (UNIV_UNLIKELY(offs == 0)) {
 
719
 
 
720
                return(NULL);
 
721
        }
 
722
 
 
723
        return(page + offs);
 
724
}
 
725
 
 
726
/************************************************************//**
 
727
Gets the pointer to the next record on the page.
 
728
@return pointer to next record */
 
729
UNIV_INLINE
 
730
rec_t*
 
731
page_rec_get_next(
 
732
/*==============*/
 
733
        rec_t*  rec)    /*!< in: pointer to record */
 
734
{
 
735
        return((rec_t*) page_rec_get_next_low(rec, page_rec_is_comp(rec)));
 
736
}
 
737
 
 
738
/************************************************************//**
 
739
Gets the pointer to the next record on the page.
 
740
@return pointer to next record */
 
741
UNIV_INLINE
 
742
const rec_t*
 
743
page_rec_get_next_const(
 
744
/*====================*/
 
745
        const rec_t*    rec)    /*!< in: pointer to record */
 
746
{
 
747
        return(page_rec_get_next_low(rec, page_rec_is_comp(rec)));
 
748
}
 
749
 
 
750
/************************************************************//**
 
751
Sets the pointer to the next record on the page. */
 
752
UNIV_INLINE
 
753
void
 
754
page_rec_set_next(
 
755
/*==============*/
 
756
        rec_t*  rec,            /*!< in: pointer to record,
 
757
                                must not be page supremum */
 
758
        rec_t*  next)           /*!< in: pointer to next record,
 
759
                                must not be page infimum */
 
760
{
 
761
        ulint   offs;
 
762
 
 
763
        ut_ad(page_rec_check(rec));
 
764
        ut_ad(!page_rec_is_supremum(rec));
 
765
        ut_ad(rec != next);
 
766
 
 
767
        ut_ad(!next || !page_rec_is_infimum(next));
 
768
        ut_ad(!next || page_align(rec) == page_align(next));
 
769
 
 
770
        if (UNIV_LIKELY(next != NULL)) {
 
771
                offs = page_offset(next);
 
772
        } else {
 
773
                offs = 0;
 
774
        }
 
775
 
 
776
        if (page_rec_is_comp(rec)) {
 
777
                rec_set_next_offs_new(rec, offs);
 
778
        } else {
 
779
                rec_set_next_offs_old(rec, offs);
 
780
        }
 
781
}
 
782
 
 
783
/************************************************************//**
 
784
Gets the pointer to the previous record.
 
785
@return pointer to previous record */
 
786
UNIV_INLINE
 
787
const rec_t*
 
788
page_rec_get_prev_const(
 
789
/*====================*/
 
790
        const rec_t*    rec)    /*!< in: pointer to record, must not be page
 
791
                                infimum */
 
792
{
 
793
        const page_dir_slot_t*  slot;
 
794
        ulint                   slot_no;
 
795
        const rec_t*            rec2;
 
796
        const rec_t*            prev_rec = NULL;
 
797
        const page_t*           page;
 
798
 
 
799
        ut_ad(page_rec_check(rec));
 
800
 
 
801
        page = page_align(rec);
 
802
 
 
803
        ut_ad(!page_rec_is_infimum(rec));
 
804
 
 
805
        slot_no = page_dir_find_owner_slot(rec);
 
806
 
 
807
        ut_a(slot_no != 0);
 
808
 
 
809
        slot = page_dir_get_nth_slot(page, slot_no - 1);
 
810
 
 
811
        rec2 = page_dir_slot_get_rec(slot);
 
812
 
 
813
        if (page_is_comp(page)) {
 
814
                while (rec != rec2) {
 
815
                        prev_rec = rec2;
 
816
                        rec2 = page_rec_get_next_low(rec2, TRUE);
 
817
                }
 
818
        } else {
 
819
                while (rec != rec2) {
 
820
                        prev_rec = rec2;
 
821
                        rec2 = page_rec_get_next_low(rec2, FALSE);
 
822
                }
 
823
        }
 
824
 
 
825
        ut_a(prev_rec);
 
826
 
 
827
        return(prev_rec);
 
828
}
 
829
 
 
830
/************************************************************//**
 
831
Gets the pointer to the previous record.
 
832
@return pointer to previous record */
 
833
UNIV_INLINE
 
834
rec_t*
 
835
page_rec_get_prev(
 
836
/*==============*/
 
837
        rec_t*  rec)    /*!< in: pointer to record, must not be page
 
838
                        infimum */
 
839
{
 
840
        return((rec_t*) page_rec_get_prev_const(rec));
 
841
}
 
842
 
 
843
/***************************************************************//**
 
844
Looks for the record which owns the given record.
 
845
@return the owner record */
 
846
UNIV_INLINE
 
847
rec_t*
 
848
page_rec_find_owner_rec(
 
849
/*====================*/
 
850
        rec_t*  rec)    /*!< in: the physical record */
 
851
{
 
852
        ut_ad(page_rec_check(rec));
 
853
 
 
854
        if (page_rec_is_comp(rec)) {
 
855
                while (rec_get_n_owned_new(rec) == 0) {
 
856
                        rec = page_rec_get_next(rec);
 
857
                }
 
858
        } else {
 
859
                while (rec_get_n_owned_old(rec) == 0) {
 
860
                        rec = page_rec_get_next(rec);
 
861
                }
 
862
        }
 
863
 
 
864
        return(rec);
 
865
}
 
866
 
 
867
/**********************************************************//**
 
868
Returns the base extra size of a physical record.  This is the
 
869
size of the fixed header, independent of the record size.
 
870
@return REC_N_NEW_EXTRA_BYTES or REC_N_OLD_EXTRA_BYTES */
 
871
UNIV_INLINE
 
872
ulint
 
873
page_rec_get_base_extra_size(
 
874
/*=========================*/
 
875
        const rec_t*    rec)    /*!< in: physical record */
 
876
{
 
877
#if REC_N_NEW_EXTRA_BYTES + 1 != REC_N_OLD_EXTRA_BYTES
 
878
# error "REC_N_NEW_EXTRA_BYTES + 1 != REC_N_OLD_EXTRA_BYTES"
 
879
#endif
 
880
        return(REC_N_NEW_EXTRA_BYTES + (ulint) !page_rec_is_comp(rec));
 
881
}
 
882
 
 
883
/************************************************************//**
 
884
Returns the sum of the sizes of the records in the record list, excluding
 
885
the infimum and supremum records.
 
886
@return data in bytes */
 
887
UNIV_INLINE
 
888
ulint
 
889
page_get_data_size(
 
890
/*===============*/
 
891
        const page_t*   page)   /*!< in: index page */
 
892
{
 
893
        ulint   ret;
 
894
 
 
895
        ret = (ulint)(page_header_get_field(page, PAGE_HEAP_TOP)
 
896
                      - (page_is_comp(page)
 
897
                         ? PAGE_NEW_SUPREMUM_END
 
898
                         : PAGE_OLD_SUPREMUM_END)
 
899
                      - page_header_get_field(page, PAGE_GARBAGE));
 
900
 
 
901
        ut_ad(ret < UNIV_PAGE_SIZE);
 
902
 
 
903
        return(ret);
 
904
}
 
905
 
 
906
 
 
907
/************************************************************//**
 
908
Allocates a block of memory from the free list of an index page. */
 
909
UNIV_INLINE
 
910
void
 
911
page_mem_alloc_free(
 
912
/*================*/
 
913
        page_t*         page,   /*!< in/out: index page */
 
914
        page_zip_des_t* page_zip,/*!< in/out: compressed page with enough
 
915
                                space available for inserting the record,
 
916
                                or NULL */
 
917
        rec_t*          next_rec,/*!< in: pointer to the new head of the
 
918
                                free record list */
 
919
        ulint           need)   /*!< in: number of bytes allocated */
 
920
{
 
921
        ulint           garbage;
 
922
 
 
923
#ifdef UNIV_DEBUG
 
924
        const rec_t*    old_rec = page_header_get_ptr(page, PAGE_FREE);
 
925
        ulint           next_offs;
 
926
 
 
927
        ut_ad(old_rec);
 
928
        next_offs = rec_get_next_offs(old_rec, page_is_comp(page));
 
929
        ut_ad(next_rec == (next_offs ? page + next_offs : NULL));
 
930
#endif
 
931
 
 
932
        page_header_set_ptr(page, page_zip, PAGE_FREE, next_rec);
 
933
 
 
934
        garbage = page_header_get_field(page, PAGE_GARBAGE);
 
935
        ut_ad(garbage >= need);
 
936
 
 
937
        page_header_set_field(page, page_zip, PAGE_GARBAGE, garbage - need);
 
938
}
 
939
 
 
940
/*************************************************************//**
 
941
Calculates free space if a page is emptied.
 
942
@return free space */
 
943
UNIV_INLINE
 
944
ulint
 
945
page_get_free_space_of_empty(
 
946
/*=========================*/
 
947
        ulint   comp)           /*!< in: nonzero=compact page layout */
 
948
{
 
949
        if (UNIV_LIKELY(comp)) {
 
950
                return((ulint)(UNIV_PAGE_SIZE
 
951
                               - PAGE_NEW_SUPREMUM_END
 
952
                               - PAGE_DIR
 
953
                               - 2 * PAGE_DIR_SLOT_SIZE));
 
954
        }
 
955
 
 
956
        return((ulint)(UNIV_PAGE_SIZE
 
957
                       - PAGE_OLD_SUPREMUM_END
 
958
                       - PAGE_DIR
 
959
                       - 2 * PAGE_DIR_SLOT_SIZE));
 
960
}
 
961
 
 
962
/************************************************************//**
 
963
Each user record on a page, and also the deleted user records in the heap
 
964
takes its size plus the fraction of the dir cell size /
 
965
PAGE_DIR_SLOT_MIN_N_OWNED bytes for it. If the sum of these exceeds the
 
966
value of page_get_free_space_of_empty, the insert is impossible, otherwise
 
967
it is allowed. This function returns the maximum combined size of records
 
968
which can be inserted on top of the record heap.
 
969
@return maximum combined size for inserted records */
 
970
UNIV_INLINE
 
971
ulint
 
972
page_get_max_insert_size(
 
973
/*=====================*/
 
974
        const page_t*   page,   /*!< in: index page */
 
975
        ulint           n_recs) /*!< in: number of records */
 
976
{
 
977
        ulint   occupied;
 
978
        ulint   free_space;
 
979
 
 
980
        if (page_is_comp(page)) {
 
981
                occupied = page_header_get_field(page, PAGE_HEAP_TOP)
 
982
                        - PAGE_NEW_SUPREMUM_END
 
983
                        + page_dir_calc_reserved_space(
 
984
                                n_recs + page_dir_get_n_heap(page) - 2);
 
985
 
 
986
                free_space = page_get_free_space_of_empty(TRUE);
 
987
        } else {
 
988
                occupied = page_header_get_field(page, PAGE_HEAP_TOP)
 
989
                        - PAGE_OLD_SUPREMUM_END
 
990
                        + page_dir_calc_reserved_space(
 
991
                                n_recs + page_dir_get_n_heap(page) - 2);
 
992
 
 
993
                free_space = page_get_free_space_of_empty(FALSE);
 
994
        }
 
995
 
 
996
        /* Above the 'n_recs +' part reserves directory space for the new
 
997
        inserted records; the '- 2' excludes page infimum and supremum
 
998
        records */
 
999
 
 
1000
        if (occupied > free_space) {
 
1001
 
 
1002
                return(0);
 
1003
        }
 
1004
 
 
1005
        return(free_space - occupied);
 
1006
}
 
1007
 
 
1008
/************************************************************//**
 
1009
Returns the maximum combined size of records which can be inserted on top
 
1010
of the record heap if a page is first reorganized.
 
1011
@return maximum combined size for inserted records */
 
1012
UNIV_INLINE
 
1013
ulint
 
1014
page_get_max_insert_size_after_reorganize(
 
1015
/*======================================*/
 
1016
        const page_t*   page,   /*!< in: index page */
 
1017
        ulint           n_recs) /*!< in: number of records */
 
1018
{
 
1019
        ulint   occupied;
 
1020
        ulint   free_space;
 
1021
 
 
1022
        occupied = page_get_data_size(page)
 
1023
                + page_dir_calc_reserved_space(n_recs + page_get_n_recs(page));
 
1024
 
 
1025
        free_space = page_get_free_space_of_empty(page_is_comp(page));
 
1026
 
 
1027
        if (occupied > free_space) {
 
1028
 
 
1029
                return(0);
 
1030
        }
 
1031
 
 
1032
        return(free_space - occupied);
 
1033
}
 
1034
 
 
1035
/************************************************************//**
 
1036
Puts a record to free list. */
 
1037
UNIV_INLINE
 
1038
void
 
1039
page_mem_free(
 
1040
/*==========*/
 
1041
        page_t*         page,   /*!< in/out: index page */
 
1042
        page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
 
1043
        rec_t*          rec,    /*!< in: pointer to the (origin of) record */
 
1044
        dict_index_t*   index,  /*!< in: index of rec */
 
1045
        const ulint*    offsets)/*!< in: array returned by rec_get_offsets() */
 
1046
{
 
1047
        rec_t*          free;
 
1048
        ulint           garbage;
 
1049
 
 
1050
        ut_ad(rec_offs_validate(rec, index, offsets));
 
1051
        free = page_header_get_ptr(page, PAGE_FREE);
 
1052
 
 
1053
        page_rec_set_next(rec, free);
 
1054
        page_header_set_ptr(page, page_zip, PAGE_FREE, rec);
 
1055
 
 
1056
        garbage = page_header_get_field(page, PAGE_GARBAGE);
 
1057
 
 
1058
        page_header_set_field(page, page_zip, PAGE_GARBAGE,
 
1059
                              garbage + rec_offs_size(offsets));
 
1060
 
 
1061
        if (UNIV_LIKELY_NULL(page_zip)) {
 
1062
                page_zip_dir_delete(page_zip, rec, index, offsets, free);
 
1063
        } else {
 
1064
                page_header_set_field(page, page_zip, PAGE_N_RECS,
 
1065
                                      page_get_n_recs(page) - 1);
 
1066
        }
 
1067
}
 
1068
 
 
1069
#ifdef UNIV_MATERIALIZE
 
1070
#undef UNIV_INLINE
 
1071
#define UNIV_INLINE     UNIV_INLINE_ORIGINAL
 
1072
#endif