~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Devananda
  • Date: 2009-07-04 01:55:13 UTC
  • mto: (1086.10.1 length-plugin)
  • mto: This revision was merged to the branch mainline in revision 1095.
  • Revision ID: deva@myst-20090704015513-gtqliazxtfm7sdvf
refactored function/length into plugin/length

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