~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Stewart Smith
  • Date: 2008-11-21 16:06:07 UTC
  • mto: This revision was merged to the branch mainline in revision 593.
  • Revision ID: stewart@flamingspork.com-20081121160607-n6gdlt013spuo54r
remove mysql_frm_type
and fix engines to return correct value from delete_table when table doesn't exist.
(it should be ENOENT).

Also fix up some tests that manipulated frm files by hand. These tests are no longer valid and will need to be rewritten in the not too distant future.

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