~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-03-18 12:12:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100318121231-k6g1xe6cshbwa0f8
Tags: upstream-2010.03.1347
ImportĀ upstreamĀ versionĀ 2010.03.1347

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