~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/btr/btr0btr.c

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
The B-tree
 
3
 
 
4
(c) 1994-1996 Innobase Oy
 
5
 
 
6
Created 6/2/1994 Heikki Tuuri
 
7
*******************************************************/
 
8
 
 
9
#include "btr0btr.h"
 
10
 
 
11
#ifdef UNIV_NONINL
 
12
#include "btr0btr.ic"
 
13
#endif
 
14
 
 
15
#include "fsp0fsp.h"
 
16
#include "page0page.h"
 
17
#include "btr0cur.h"
 
18
#include "btr0sea.h"
 
19
#include "btr0pcur.h"
 
20
#include "rem0cmp.h"
 
21
#include "lock0lock.h"
 
22
#include "ibuf0ibuf.h"
 
23
#include "trx0trx.h"
 
24
 
 
25
/*
 
26
Latching strategy of the InnoDB B-tree
 
27
--------------------------------------
 
28
A tree latch protects all non-leaf nodes of the tree. Each node of a tree
 
29
also has a latch of its own.
 
30
 
 
31
A B-tree operation normally first acquires an S-latch on the tree. It
 
32
searches down the tree and releases the tree latch when it has the
 
33
leaf node latch. To save CPU time we do not acquire any latch on
 
34
non-leaf nodes of the tree during a search, those pages are only bufferfixed.
 
35
 
 
36
If an operation needs to restructure the tree, it acquires an X-latch on
 
37
the tree before searching to a leaf node. If it needs, for example, to
 
38
split a leaf,
 
39
(1) InnoDB decides the split point in the leaf,
 
40
(2) allocates a new page,
 
41
(3) inserts the appropriate node pointer to the first non-leaf level,
 
42
(4) releases the tree X-latch,
 
43
(5) and then moves records from the leaf to the new allocated page.
 
44
 
 
45
Node pointers
 
46
-------------
 
47
Leaf pages of a B-tree contain the index records stored in the
 
48
tree. On levels n > 0 we store 'node pointers' to pages on level
 
49
n - 1. For each page there is exactly one node pointer stored:
 
50
thus the our tree is an ordinary B-tree, not a B-link tree.
 
51
 
 
52
A node pointer contains a prefix P of an index record. The prefix
 
53
is long enough so that it determines an index record uniquely.
 
54
The file page number of the child page is added as the last
 
55
field. To the child page we can store node pointers or index records
 
56
which are >= P in the alphabetical order, but < P1 if there is
 
57
a next node pointer on the level, and P1 is its prefix.
 
58
 
 
59
If a node pointer with a prefix P points to a non-leaf child,
 
60
then the leftmost record in the child must have the same
 
61
prefix P. If it points to a leaf node, the child is not required
 
62
to contain any record with a prefix equal to P. The leaf case
 
63
is decided this way to allow arbitrary deletions in a leaf node
 
64
without touching upper levels of the tree.
 
65
 
 
66
We have predefined a special minimum record which we
 
67
define as the smallest record in any alphabetical order.
 
68
A minimum record is denoted by setting a bit in the record
 
69
header. A minimum record acts as the prefix of a node pointer
 
70
which points to a leftmost node on any level of the tree.
 
71
 
 
72
File page allocation
 
73
--------------------
 
74
In the root node of a B-tree there are two file segment headers.
 
75
The leaf pages of a tree are allocated from one file segment, to
 
76
make them consecutive on disk if possible. From the other file segment
 
77
we allocate pages for the non-leaf levels of the tree.
 
78
*/
 
79
 
 
80
/****************************************************************
 
81
Returns the upper level node pointer to a page. It is assumed that
 
82
mtr holds an x-latch on the tree. */
 
83
static
 
84
rec_t*
 
85
btr_page_get_father_node_ptr(
 
86
/*=========================*/
 
87
                                /* out: pointer to node pointer record */
 
88
        dict_index_t*   index,  /* in: index tree */
 
89
        page_t*         page,   /* in: page: must contain at least one
 
90
                                user record */
 
91
        mtr_t*          mtr);   /* in: mtr */
 
92
/*****************************************************************
 
93
Empties an index page. */
 
94
static
 
95
void
 
96
btr_page_empty(
 
97
/*===========*/
 
98
        page_t* page,   /* in: page to be emptied */
 
99
        mtr_t*  mtr);   /* in: mtr */
 
100
/*****************************************************************
 
101
Returns TRUE if the insert fits on the appropriate half-page
 
102
with the chosen split_rec. */
 
103
static
 
104
ibool
 
105
btr_page_insert_fits(
 
106
/*=================*/
 
107
                                        /* out: TRUE if fits */
 
108
        btr_cur_t*      cursor,         /* in: cursor at which insert
 
109
                                        should be made */
 
110
        rec_t*          split_rec,      /* in: suggestion for first record
 
111
                                        on upper half-page, or NULL if
 
112
                                        tuple should be first */
 
113
        const ulint*    offsets,        /* in: rec_get_offsets(
 
114
                                        split_rec, cursor->index) */
 
115
        dtuple_t*       tuple,          /* in: tuple to insert */
 
116
        mem_heap_t*     heap);          /* in: temporary memory heap */
 
117
 
 
118
/******************************************************************
 
119
Gets the root node of a tree and x-latches it. */
 
120
 
 
121
page_t*
 
122
btr_root_get(
 
123
/*=========*/
 
124
                                /* out: root page, x-latched */
 
125
        dict_index_t*   index,  /* in: index tree */
 
126
        mtr_t*          mtr)    /* in: mtr */
 
127
{
 
128
        ulint   space;
 
129
        ulint   root_page_no;
 
130
        page_t* root;
 
131
 
 
132
        space = dict_index_get_space(index);
 
133
        root_page_no = dict_index_get_page(index);
 
134
 
 
135
        root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr);
 
136
        ut_a((ibool)!!page_is_comp(root) == dict_table_is_comp(index->table));
 
137
 
 
138
        return(root);
 
139
}
 
140
 
 
141
/*****************************************************************
 
142
Gets pointer to the previous user record in the tree. It is assumed that
 
143
the caller has appropriate latches on the page and its neighbor. */
 
144
 
 
145
rec_t*
 
146
btr_get_prev_user_rec(
 
147
/*==================*/
 
148
                        /* out: previous user record, NULL if there is none */
 
149
        rec_t*  rec,    /* in: record on leaf level */
 
150
        mtr_t*  mtr)    /* in: mtr holding a latch on the page, and if
 
151
                        needed, also to the previous page */
 
152
{
 
153
        page_t* page;
 
154
        page_t* prev_page;
 
155
        ulint   prev_page_no;
 
156
        ulint   space;
 
157
 
 
158
        if (!page_rec_is_infimum(rec)) {
 
159
 
 
160
                rec_t*  prev_rec = page_rec_get_prev(rec);
 
161
 
 
162
                if (!page_rec_is_infimum(prev_rec)) {
 
163
 
 
164
                        return(prev_rec);
 
165
                }
 
166
        }
 
167
 
 
168
        page = buf_frame_align(rec);
 
169
        prev_page_no = btr_page_get_prev(page, mtr);
 
170
        space = buf_frame_get_space_id(page);
 
171
 
 
172
        if (prev_page_no != FIL_NULL) {
 
173
 
 
174
                prev_page = buf_page_get_with_no_latch(space, prev_page_no,
 
175
                                                       mtr);
 
176
                /* The caller must already have a latch to the brother */
 
177
                ut_ad((mtr_memo_contains(mtr, buf_block_align(prev_page),
 
178
                                         MTR_MEMO_PAGE_S_FIX))
 
179
                      || (mtr_memo_contains(mtr, buf_block_align(prev_page),
 
180
                                            MTR_MEMO_PAGE_X_FIX)));
 
181
                ut_a(page_is_comp(prev_page) == page_is_comp(page));
 
182
#ifdef UNIV_BTR_DEBUG
 
183
                ut_a(btr_page_get_next(prev_page, mtr)
 
184
                     == buf_frame_get_page_no(page));
 
185
#endif /* UNIV_BTR_DEBUG */
 
186
 
 
187
                return(page_rec_get_prev(page_get_supremum_rec(prev_page)));
 
188
        }
 
189
 
 
190
        return(NULL);
 
191
}
 
192
 
 
193
/*****************************************************************
 
194
Gets pointer to the next user record in the tree. It is assumed that the
 
195
caller has appropriate latches on the page and its neighbor. */
 
196
 
 
197
rec_t*
 
198
btr_get_next_user_rec(
 
199
/*==================*/
 
200
                        /* out: next user record, NULL if there is none */
 
201
        rec_t*  rec,    /* in: record on leaf level */
 
202
        mtr_t*  mtr)    /* in: mtr holding a latch on the page, and if
 
203
                        needed, also to the next page */
 
204
{
 
205
        page_t* page;
 
206
        page_t* next_page;
 
207
        ulint   next_page_no;
 
208
        ulint   space;
 
209
 
 
210
        if (!page_rec_is_supremum(rec)) {
 
211
 
 
212
                rec_t*  next_rec = page_rec_get_next(rec);
 
213
 
 
214
                if (!page_rec_is_supremum(next_rec)) {
 
215
 
 
216
                        return(next_rec);
 
217
                }
 
218
        }
 
219
 
 
220
        page = buf_frame_align(rec);
 
221
        next_page_no = btr_page_get_next(page, mtr);
 
222
        space = buf_frame_get_space_id(page);
 
223
 
 
224
        if (next_page_no != FIL_NULL) {
 
225
 
 
226
                next_page = buf_page_get_with_no_latch(space, next_page_no,
 
227
                                                       mtr);
 
228
                /* The caller must already have a latch to the brother */
 
229
                ut_ad((mtr_memo_contains(mtr, buf_block_align(next_page),
 
230
                                         MTR_MEMO_PAGE_S_FIX))
 
231
                      || (mtr_memo_contains(mtr, buf_block_align(next_page),
 
232
                                            MTR_MEMO_PAGE_X_FIX)));
 
233
#ifdef UNIV_BTR_DEBUG
 
234
                ut_a(btr_page_get_prev(next_page, mtr)
 
235
                     == buf_frame_get_page_no(page));
 
236
#endif /* UNIV_BTR_DEBUG */
 
237
 
 
238
                ut_a(page_is_comp(next_page) == page_is_comp(page));
 
239
                return(page_rec_get_next(page_get_infimum_rec(next_page)));
 
240
        }
 
241
 
 
242
        return(NULL);
 
243
}
 
244
 
 
245
/******************************************************************
 
246
Creates a new index page (not the root, and also not
 
247
used in page reorganization). */
 
248
static
 
249
void
 
250
btr_page_create(
 
251
/*============*/
 
252
        page_t*         page,   /* in: page to be created */
 
253
        dict_index_t*   index,  /* in: index */
 
254
        mtr_t*          mtr)    /* in: mtr */
 
255
{
 
256
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
257
                                MTR_MEMO_PAGE_X_FIX));
 
258
        page_create(page, mtr, dict_table_is_comp(index->table));
 
259
        buf_block_align(page)->check_index_page_at_flush = TRUE;
 
260
 
 
261
        btr_page_set_index_id(page, index->id, mtr);
 
262
}
 
263
 
 
264
/******************************************************************
 
265
Allocates a new file page to be used in an ibuf tree. Takes the page from
 
266
the free list of the tree, which must contain pages! */
 
267
static
 
268
page_t*
 
269
btr_page_alloc_for_ibuf(
 
270
/*====================*/
 
271
                                /* out: new allocated page, x-latched */
 
272
        dict_index_t*   index,  /* in: index tree */
 
273
        mtr_t*          mtr)    /* in: mtr */
 
274
{
 
275
        fil_addr_t      node_addr;
 
276
        page_t*         root;
 
277
        page_t*         new_page;
 
278
 
 
279
        root = btr_root_get(index, mtr);
 
280
 
 
281
        node_addr = flst_get_first(root + PAGE_HEADER
 
282
                                   + PAGE_BTR_IBUF_FREE_LIST, mtr);
 
283
        ut_a(node_addr.page != FIL_NULL);
 
284
 
 
285
        new_page = buf_page_get(dict_index_get_space(index), node_addr.page,
 
286
                                RW_X_LATCH, mtr);
 
287
#ifdef UNIV_SYNC_DEBUG
 
288
        buf_page_dbg_add_level(new_page, SYNC_TREE_NODE_NEW);
 
289
#endif /* UNIV_SYNC_DEBUG */
 
290
 
 
291
        flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
 
292
                    new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE,
 
293
                    mtr);
 
294
        ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
 
295
                            mtr));
 
296
 
 
297
        return(new_page);
 
298
}
 
299
 
 
300
/******************************************************************
 
301
Allocates a new file page to be used in an index tree. NOTE: we assume
 
302
that the caller has made the reservation for free extents! */
 
303
 
 
304
page_t*
 
305
btr_page_alloc(
 
306
/*===========*/
 
307
                                        /* out: new allocated page, x-latched;
 
308
                                        NULL if out of space */
 
309
        dict_index_t*   index,          /* in: index */
 
310
        ulint           hint_page_no,   /* in: hint of a good page */
 
311
        byte            file_direction, /* in: direction where a possible
 
312
                                        page split is made */
 
313
        ulint           level,          /* in: level where the page is placed
 
314
                                        in the tree */
 
315
        mtr_t*          mtr)            /* in: mtr */
 
316
{
 
317
        fseg_header_t*  seg_header;
 
318
        page_t*         root;
 
319
        page_t*         new_page;
 
320
        ulint           new_page_no;
 
321
 
 
322
        if (index->type & DICT_IBUF) {
 
323
 
 
324
                return(btr_page_alloc_for_ibuf(index, mtr));
 
325
        }
 
326
 
 
327
        root = btr_root_get(index, mtr);
 
328
 
 
329
        if (level == 0) {
 
330
                seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
 
331
        } else {
 
332
                seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
 
333
        }
 
334
 
 
335
        /* Parameter TRUE below states that the caller has made the
 
336
        reservation for free extents, and thus we know that a page can
 
337
        be allocated: */
 
338
 
 
339
        new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no,
 
340
                                                   file_direction, TRUE, mtr);
 
341
        if (new_page_no == FIL_NULL) {
 
342
 
 
343
                return(NULL);
 
344
        }
 
345
 
 
346
        new_page = buf_page_get(dict_index_get_space(index), new_page_no,
 
347
                                RW_X_LATCH, mtr);
 
348
#ifdef UNIV_SYNC_DEBUG
 
349
        buf_page_dbg_add_level(new_page, SYNC_TREE_NODE_NEW);
 
350
#endif /* UNIV_SYNC_DEBUG */
 
351
 
 
352
        return(new_page);
 
353
}
 
354
 
 
355
/******************************************************************
 
356
Gets the number of pages in a B-tree. */
 
357
 
 
358
ulint
 
359
btr_get_size(
 
360
/*=========*/
 
361
                                /* out: number of pages */
 
362
        dict_index_t*   index,  /* in: index */
 
363
        ulint           flag)   /* in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
 
364
{
 
365
        fseg_header_t*  seg_header;
 
366
        page_t*         root;
 
367
        ulint           n;
 
368
        ulint           dummy;
 
369
        mtr_t           mtr;
 
370
 
 
371
        mtr_start(&mtr);
 
372
 
 
373
        mtr_s_lock(dict_index_get_lock(index), &mtr);
 
374
 
 
375
        root = btr_root_get(index, &mtr);
 
376
 
 
377
        if (flag == BTR_N_LEAF_PAGES) {
 
378
                seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
 
379
 
 
380
                fseg_n_reserved_pages(seg_header, &n, &mtr);
 
381
 
 
382
        } else if (flag == BTR_TOTAL_SIZE) {
 
383
                seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
 
384
 
 
385
                n = fseg_n_reserved_pages(seg_header, &dummy, &mtr);
 
386
 
 
387
                seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
 
388
 
 
389
                n += fseg_n_reserved_pages(seg_header, &dummy, &mtr);
 
390
        } else {
 
391
                ut_error;
 
392
        }
 
393
 
 
394
        mtr_commit(&mtr);
 
395
 
 
396
        return(n);
 
397
}
 
398
 
 
399
/******************************************************************
 
400
Frees a page used in an ibuf tree. Puts the page to the free list of the
 
401
ibuf tree. */
 
402
static
 
403
void
 
404
btr_page_free_for_ibuf(
 
405
/*===================*/
 
406
        dict_index_t*   index,  /* in: index tree */
 
407
        page_t*         page,   /* in: page to be freed, x-latched */
 
408
        mtr_t*          mtr)    /* in: mtr */
 
409
{
 
410
        page_t*         root;
 
411
 
 
412
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
413
                                MTR_MEMO_PAGE_X_FIX));
 
414
        root = btr_root_get(index, mtr);
 
415
 
 
416
        flst_add_first(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
 
417
                       page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, mtr);
 
418
 
 
419
        ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
 
420
                            mtr));
 
421
}
 
422
 
 
423
/******************************************************************
 
424
Frees a file page used in an index tree. Can be used also to (BLOB)
 
425
external storage pages, because the page level 0 can be given as an
 
426
argument. */
 
427
 
 
428
void
 
429
btr_page_free_low(
 
430
/*==============*/
 
431
        dict_index_t*   index,  /* in: index tree */
 
432
        page_t*         page,   /* in: page to be freed, x-latched */
 
433
        ulint           level,  /* in: page level */
 
434
        mtr_t*          mtr)    /* in: mtr */
 
435
{
 
436
        fseg_header_t*  seg_header;
 
437
        page_t*         root;
 
438
        ulint           space;
 
439
        ulint           page_no;
 
440
 
 
441
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
442
                                MTR_MEMO_PAGE_X_FIX));
 
443
        /* The page gets invalid for optimistic searches: increment the frame
 
444
        modify clock */
 
445
 
 
446
        buf_frame_modify_clock_inc(page);
 
447
 
 
448
        if (index->type & DICT_IBUF) {
 
449
 
 
450
                btr_page_free_for_ibuf(index, page, mtr);
 
451
 
 
452
                return;
 
453
        }
 
454
 
 
455
        root = btr_root_get(index, mtr);
 
456
 
 
457
        if (level == 0) {
 
458
                seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
 
459
        } else {
 
460
                seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
 
461
        }
 
462
 
 
463
        space = buf_frame_get_space_id(page);
 
464
        page_no = buf_frame_get_page_no(page);
 
465
 
 
466
        fseg_free_page(seg_header, space, page_no, mtr);
 
467
}
 
468
 
 
469
/******************************************************************
 
470
Frees a file page used in an index tree. NOTE: cannot free field external
 
471
storage pages because the page must contain info on its level. */
 
472
 
 
473
void
 
474
btr_page_free(
 
475
/*==========*/
 
476
        dict_index_t*   index,  /* in: index tree */
 
477
        page_t*         page,   /* in: page to be freed, x-latched */
 
478
        mtr_t*          mtr)    /* in: mtr */
 
479
{
 
480
        ulint           level;
 
481
 
 
482
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
483
                                MTR_MEMO_PAGE_X_FIX));
 
484
        level = btr_page_get_level(page, mtr);
 
485
 
 
486
        btr_page_free_low(index, page, level, mtr);
 
487
}
 
488
 
 
489
/******************************************************************
 
490
Sets the child node file address in a node pointer. */
 
491
UNIV_INLINE
 
492
void
 
493
btr_node_ptr_set_child_page_no(
 
494
/*===========================*/
 
495
        rec_t*          rec,    /* in: node pointer record */
 
496
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
 
497
        ulint           page_no,/* in: child node address */
 
498
        mtr_t*          mtr)    /* in: mtr */
 
499
{
 
500
        byte*   field;
 
501
        ulint   len;
 
502
 
 
503
        ut_ad(rec_offs_validate(rec, NULL, offsets));
 
504
        ut_ad(0 < btr_page_get_level(buf_frame_align(rec), mtr));
 
505
        ut_ad(!rec_offs_comp(offsets) || rec_get_node_ptr_flag(rec));
 
506
 
 
507
        /* The child address is in the last field */
 
508
        field = rec_get_nth_field(rec, offsets,
 
509
                                  rec_offs_n_fields(offsets) - 1, &len);
 
510
 
 
511
        ut_ad(len == 4);
 
512
 
 
513
        mlog_write_ulint(field, page_no, MLOG_4BYTES, mtr);
 
514
}
 
515
 
 
516
/****************************************************************
 
517
Returns the child page of a node pointer and x-latches it. */
 
518
static
 
519
page_t*
 
520
btr_node_ptr_get_child(
 
521
/*===================*/
 
522
                                /* out: child page, x-latched */
 
523
        rec_t*          node_ptr,/* in: node pointer */
 
524
        const ulint*    offsets,/* in: array returned by rec_get_offsets() */
 
525
        mtr_t*          mtr)    /* in: mtr */
 
526
{
 
527
        ulint   page_no;
 
528
        ulint   space;
 
529
        page_t* page;
 
530
 
 
531
        ut_ad(rec_offs_validate(node_ptr, NULL, offsets));
 
532
        space = buf_frame_get_space_id(node_ptr);
 
533
        page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
 
534
 
 
535
        page = btr_page_get(space, page_no, RW_X_LATCH, mtr);
 
536
 
 
537
        return(page);
 
538
}
 
539
 
 
540
/****************************************************************
 
541
Returns the upper level node pointer to a page. It is assumed that mtr holds
 
542
an x-latch on the tree. */
 
543
static
 
544
rec_t*
 
545
btr_page_get_father_for_rec(
 
546
/*========================*/
 
547
                                /* out: pointer to node pointer record,
 
548
                                its page x-latched */
 
549
        dict_index_t*   index,  /* in: index tree */
 
550
        page_t*         page,   /* in: page: must contain at least one
 
551
                                user record */
 
552
        rec_t*          user_rec,/* in: user_record on page */
 
553
        mtr_t*          mtr)    /* in: mtr */
 
554
{
 
555
        mem_heap_t*     heap;
 
556
        dtuple_t*       tuple;
 
557
        btr_cur_t       cursor;
 
558
        rec_t*          node_ptr;
 
559
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
560
        ulint*          offsets = offsets_;
 
561
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
 
562
 
 
563
        ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
 
564
                                MTR_MEMO_X_LOCK));
 
565
        ut_a(page_rec_is_user_rec(user_rec));
 
566
 
 
567
        ut_ad(dict_index_get_page(index) != buf_frame_get_page_no(page));
 
568
 
 
569
        heap = mem_heap_create(100);
 
570
 
 
571
        tuple = dict_index_build_node_ptr(index, user_rec, 0, heap,
 
572
                                          btr_page_get_level(page, mtr));
 
573
 
 
574
        btr_cur_search_to_nth_level(index,
 
575
                                    btr_page_get_level(page, mtr) + 1,
 
576
                                    tuple, PAGE_CUR_LE,
 
577
                                    BTR_CONT_MODIFY_TREE, &cursor, 0, mtr);
 
578
 
 
579
        node_ptr = btr_cur_get_rec(&cursor);
 
580
        offsets = rec_get_offsets(node_ptr, index, offsets,
 
581
                                  ULINT_UNDEFINED, &heap);
 
582
 
 
583
        if (UNIV_UNLIKELY(btr_node_ptr_get_child_page_no(node_ptr, offsets)
 
584
                          != buf_frame_get_page_no(page))) {
 
585
                rec_t*  print_rec;
 
586
                fputs("InnoDB: Dump of the child page:\n", stderr);
 
587
                buf_page_print(buf_frame_align(page));
 
588
                fputs("InnoDB: Dump of the parent page:\n", stderr);
 
589
                buf_page_print(buf_frame_align(node_ptr));
 
590
 
 
591
                fputs("InnoDB: Corruption of an index tree: table ", stderr);
 
592
                ut_print_name(stderr, NULL, TRUE, index->table_name);
 
593
                fputs(", index ", stderr);
 
594
                ut_print_name(stderr, NULL, FALSE, index->name);
 
595
                fprintf(stderr, ",\n"
 
596
                        "InnoDB: father ptr page no %lu, child page no %lu\n",
 
597
                        (ulong)
 
598
                        btr_node_ptr_get_child_page_no(node_ptr, offsets),
 
599
                        (ulong) buf_frame_get_page_no(page));
 
600
                print_rec = page_rec_get_next(page_get_infimum_rec(page));
 
601
                offsets = rec_get_offsets(print_rec, index,
 
602
                                          offsets, ULINT_UNDEFINED, &heap);
 
603
                page_rec_print(print_rec, offsets);
 
604
                offsets = rec_get_offsets(node_ptr, index, offsets,
 
605
                                          ULINT_UNDEFINED, &heap);
 
606
                page_rec_print(node_ptr, offsets);
 
607
 
 
608
                fputs("InnoDB: You should dump + drop + reimport the table"
 
609
                      " to fix the\n"
 
610
                      "InnoDB: corruption. If the crash happens at "
 
611
                      "the database startup, see\n"
 
612
                      "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
 
613
                      "forcing-recovery.html about\n"
 
614
                      "InnoDB: forcing recovery. "
 
615
                      "Then dump + drop + reimport.\n", stderr);
 
616
        }
 
617
 
 
618
        ut_a(btr_node_ptr_get_child_page_no(node_ptr, offsets)
 
619
             == buf_frame_get_page_no(page));
 
620
        mem_heap_free(heap);
 
621
 
 
622
        return(node_ptr);
 
623
}
 
624
 
 
625
/****************************************************************
 
626
Returns the upper level node pointer to a page. It is assumed that
 
627
mtr holds an x-latch on the tree. */
 
628
static
 
629
rec_t*
 
630
btr_page_get_father_node_ptr(
 
631
/*=========================*/
 
632
                                /* out: pointer to node pointer record */
 
633
        dict_index_t*   index,  /* in: index tree */
 
634
        page_t*         page,   /* in: page: must contain at least one
 
635
                                user record */
 
636
        mtr_t*          mtr)    /* in: mtr */
 
637
{
 
638
        return(btr_page_get_father_for_rec(
 
639
                       index, page,
 
640
                       page_rec_get_next(page_get_infimum_rec(page)), mtr));
 
641
}
 
642
 
 
643
/****************************************************************
 
644
Creates the root node for a new index tree. */
 
645
 
 
646
ulint
 
647
btr_create(
 
648
/*=======*/
 
649
                        /* out: page number of the created root, FIL_NULL if
 
650
                        did not succeed */
 
651
        ulint   type,   /* in: type of the index */
 
652
        ulint   space,  /* in: space where created */
 
653
        dulint  index_id,/* in: index id */
 
654
        ulint   comp,   /* in: nonzero=compact page format */
 
655
        mtr_t*  mtr)    /* in: mini-transaction handle */
 
656
{
 
657
        ulint           page_no;
 
658
        buf_frame_t*    ibuf_hdr_frame;
 
659
        buf_frame_t*    frame;
 
660
        page_t*         page;
 
661
 
 
662
        /* Create the two new segments (one, in the case of an ibuf tree) for
 
663
        the index tree; the segment headers are put on the allocated root page
 
664
        (for an ibuf tree, not in the root, but on a separate ibuf header
 
665
        page) */
 
666
 
 
667
        if (type & DICT_IBUF) {
 
668
                /* Allocate first the ibuf header page */
 
669
                ibuf_hdr_frame = fseg_create(
 
670
                        space, 0, IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr);
 
671
 
 
672
#ifdef UNIV_SYNC_DEBUG
 
673
                buf_page_dbg_add_level(ibuf_hdr_frame, SYNC_TREE_NODE_NEW);
 
674
#endif /* UNIV_SYNC_DEBUG */
 
675
                ut_ad(buf_frame_get_page_no(ibuf_hdr_frame)
 
676
                      == IBUF_HEADER_PAGE_NO);
 
677
                /* Allocate then the next page to the segment: it will be the
 
678
                tree root page */
 
679
 
 
680
                page_no = fseg_alloc_free_page(ibuf_hdr_frame + IBUF_HEADER
 
681
                                               + IBUF_TREE_SEG_HEADER,
 
682
                                               IBUF_TREE_ROOT_PAGE_NO,
 
683
                                               FSP_UP, mtr);
 
684
                ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
 
685
 
 
686
                frame = buf_page_get(space, page_no, RW_X_LATCH, mtr);
 
687
        } else {
 
688
                frame = fseg_create(space, 0, PAGE_HEADER + PAGE_BTR_SEG_TOP,
 
689
                                    mtr);
 
690
        }
 
691
 
 
692
        if (frame == NULL) {
 
693
 
 
694
                return(FIL_NULL);
 
695
        }
 
696
 
 
697
        page_no = buf_frame_get_page_no(frame);
 
698
 
 
699
#ifdef UNIV_SYNC_DEBUG
 
700
        buf_page_dbg_add_level(frame, SYNC_TREE_NODE_NEW);
 
701
#endif /* UNIV_SYNC_DEBUG */
 
702
 
 
703
        if (type & DICT_IBUF) {
 
704
                /* It is an insert buffer tree: initialize the free list */
 
705
 
 
706
                ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
 
707
 
 
708
                flst_init(frame + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr);
 
709
        } else {
 
710
                /* It is a non-ibuf tree: create a file segment for leaf
 
711
                pages */
 
712
                fseg_create(space, page_no, PAGE_HEADER + PAGE_BTR_SEG_LEAF,
 
713
                            mtr);
 
714
                /* The fseg create acquires a second latch on the page,
 
715
                therefore we must declare it: */
 
716
#ifdef UNIV_SYNC_DEBUG
 
717
                buf_page_dbg_add_level(frame, SYNC_TREE_NODE_NEW);
 
718
#endif /* UNIV_SYNC_DEBUG */
 
719
        }
 
720
 
 
721
        /* Create a new index page on the the allocated segment page */
 
722
        page = page_create(frame, mtr, comp);
 
723
        buf_block_align(page)->check_index_page_at_flush = TRUE;
 
724
 
 
725
        /* Set the index id of the page */
 
726
        btr_page_set_index_id(page, index_id, mtr);
 
727
 
 
728
        /* Set the level of the new index page */
 
729
        btr_page_set_level(page, 0, mtr);
 
730
 
 
731
        /* Set the next node and previous node fields */
 
732
        btr_page_set_next(page, FIL_NULL, mtr);
 
733
        btr_page_set_prev(page, FIL_NULL, mtr);
 
734
 
 
735
        /* We reset the free bits for the page to allow creation of several
 
736
        trees in the same mtr, otherwise the latch on a bitmap page would
 
737
        prevent it because of the latching order */
 
738
 
 
739
        ibuf_reset_free_bits_with_type(type, page);
 
740
 
 
741
        /* In the following assertion we test that two records of maximum
 
742
        allowed size fit on the root page: this fact is needed to ensure
 
743
        correctness of split algorithms */
 
744
 
 
745
        ut_ad(page_get_max_insert_size(page, 2) > 2 * BTR_PAGE_MAX_REC_SIZE);
 
746
 
 
747
        return(page_no);
 
748
}
 
749
 
 
750
/****************************************************************
 
751
Frees a B-tree except the root page, which MUST be freed after this
 
752
by calling btr_free_root. */
 
753
 
 
754
void
 
755
btr_free_but_not_root(
 
756
/*==================*/
 
757
        ulint   space,          /* in: space where created */
 
758
        ulint   root_page_no)   /* in: root page number */
 
759
{
 
760
        ibool   finished;
 
761
        page_t* root;
 
762
        mtr_t   mtr;
 
763
 
 
764
leaf_loop:
 
765
        mtr_start(&mtr);
 
766
 
 
767
        root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr);
 
768
 
 
769
        /* NOTE: page hash indexes are dropped when a page is freed inside
 
770
        fsp0fsp. */
 
771
 
 
772
        finished = fseg_free_step(root + PAGE_HEADER + PAGE_BTR_SEG_LEAF,
 
773
                                  &mtr);
 
774
        mtr_commit(&mtr);
 
775
 
 
776
        if (!finished) {
 
777
 
 
778
                goto leaf_loop;
 
779
        }
 
780
top_loop:
 
781
        mtr_start(&mtr);
 
782
 
 
783
        root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr);
 
784
 
 
785
        finished = fseg_free_step_not_header(
 
786
                root + PAGE_HEADER + PAGE_BTR_SEG_TOP, &mtr);
 
787
        mtr_commit(&mtr);
 
788
 
 
789
        if (!finished) {
 
790
 
 
791
                goto top_loop;
 
792
        }
 
793
}
 
794
 
 
795
/****************************************************************
 
796
Frees the B-tree root page. Other tree MUST already have been freed. */
 
797
 
 
798
void
 
799
btr_free_root(
 
800
/*==========*/
 
801
        ulint   space,          /* in: space where created */
 
802
        ulint   root_page_no,   /* in: root page number */
 
803
        mtr_t*  mtr)            /* in: a mini-transaction which has already
 
804
                                been started */
 
805
{
 
806
        ibool   finished;
 
807
        page_t* root;
 
808
 
 
809
        root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr);
 
810
 
 
811
        btr_search_drop_page_hash_index(root);
 
812
top_loop:
 
813
        finished = fseg_free_step(root + PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr);
 
814
        if (!finished) {
 
815
 
 
816
                goto top_loop;
 
817
        }
 
818
}
 
819
 
 
820
/*****************************************************************
 
821
Reorganizes an index page. */
 
822
static
 
823
void
 
824
btr_page_reorganize_low(
 
825
/*====================*/
 
826
        ibool           recovery,/* in: TRUE if called in recovery:
 
827
                                locks should not be updated, i.e.,
 
828
                                there cannot exist locks on the
 
829
                                page, and a hash index should not be
 
830
                                dropped: it cannot exist */
 
831
        page_t*         page,   /* in: page to be reorganized */
 
832
        dict_index_t*   index,  /* in: record descriptor */
 
833
        mtr_t*          mtr)    /* in: mtr */
 
834
{
 
835
        page_t* new_page;
 
836
        ulint   log_mode;
 
837
        ulint   data_size1;
 
838
        ulint   data_size2;
 
839
        ulint   max_ins_size1;
 
840
        ulint   max_ins_size2;
 
841
 
 
842
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
843
                                MTR_MEMO_PAGE_X_FIX));
 
844
        ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
 
845
        data_size1 = page_get_data_size(page);
 
846
        max_ins_size1 = page_get_max_insert_size_after_reorganize(page, 1);
 
847
 
 
848
        /* Write the log record */
 
849
        mlog_open_and_write_index(mtr, page, index, page_is_comp(page)
 
850
                                  ? MLOG_COMP_PAGE_REORGANIZE
 
851
                                  : MLOG_PAGE_REORGANIZE, 0);
 
852
 
 
853
        /* Turn logging off */
 
854
        log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
 
855
 
 
856
        new_page = buf_frame_alloc();
 
857
 
 
858
        /* Copy the old page to temporary space */
 
859
        buf_frame_copy(new_page, page);
 
860
 
 
861
        if (!recovery) {
 
862
                btr_search_drop_page_hash_index(page);
 
863
        }
 
864
 
 
865
        /* Recreate the page: note that global data on page (possible
 
866
        segment headers, next page-field, etc.) is preserved intact */
 
867
 
 
868
        page_create(page, mtr, page_is_comp(page));
 
869
        buf_block_align(page)->check_index_page_at_flush = TRUE;
 
870
 
 
871
        /* Copy the records from the temporary space to the recreated page;
 
872
        do not copy the lock bits yet */
 
873
 
 
874
        page_copy_rec_list_end_no_locks(page, new_page,
 
875
                                        page_get_infimum_rec(new_page),
 
876
                                        index, mtr);
 
877
        /* Copy max trx id to recreated page */
 
878
        page_set_max_trx_id(page, page_get_max_trx_id(new_page));
 
879
 
 
880
        if (!recovery) {
 
881
                /* Update the record lock bitmaps */
 
882
                lock_move_reorganize_page(page, new_page);
 
883
        }
 
884
 
 
885
        data_size2 = page_get_data_size(page);
 
886
        max_ins_size2 = page_get_max_insert_size_after_reorganize(page, 1);
 
887
 
 
888
        if (data_size1 != data_size2 || max_ins_size1 != max_ins_size2) {
 
889
                buf_page_print(page);
 
890
                buf_page_print(new_page);
 
891
                fprintf(stderr,
 
892
                        "InnoDB: Error: page old data size %lu"
 
893
                        " new data size %lu\n"
 
894
                        "InnoDB: Error: page old max ins size %lu"
 
895
                        " new max ins size %lu\n"
 
896
                        "InnoDB: Submit a detailed bug report"
 
897
                        " to http://bugs.mysql.com\n",
 
898
                        (unsigned long) data_size1, (unsigned long) data_size2,
 
899
                        (unsigned long) max_ins_size1,
 
900
                        (unsigned long) max_ins_size2);
 
901
        }
 
902
 
 
903
        buf_frame_free(new_page);
 
904
 
 
905
        /* Restore logging mode */
 
906
        mtr_set_log_mode(mtr, log_mode);
 
907
}
 
908
 
 
909
/*****************************************************************
 
910
Reorganizes an index page. */
 
911
 
 
912
void
 
913
btr_page_reorganize(
 
914
/*================*/
 
915
        page_t*         page,   /* in: page to be reorganized */
 
916
        dict_index_t*   index,  /* in: record descriptor */
 
917
        mtr_t*          mtr)    /* in: mtr */
 
918
{
 
919
        btr_page_reorganize_low(FALSE, page, index, mtr);
 
920
}
 
921
 
 
922
/***************************************************************
 
923
Parses a redo log record of reorganizing a page. */
 
924
 
 
925
byte*
 
926
btr_parse_page_reorganize(
 
927
/*======================*/
 
928
                                /* out: end of log record or NULL */
 
929
        byte*           ptr,    /* in: buffer */
 
930
        byte*           end_ptr __attribute__((unused)),
 
931
                                /* in: buffer end */
 
932
        dict_index_t*   index,  /* in: record descriptor */
 
933
        page_t*         page,   /* in: page or NULL */
 
934
        mtr_t*          mtr)    /* in: mtr or NULL */
 
935
{
 
936
        ut_ad(ptr && end_ptr);
 
937
 
 
938
        /* The record is empty, except for the record initial part */
 
939
 
 
940
        if (page) {
 
941
                btr_page_reorganize_low(TRUE, page, index, mtr);
 
942
        }
 
943
 
 
944
        return(ptr);
 
945
}
 
946
 
 
947
/*****************************************************************
 
948
Empties an index page. */
 
949
static
 
950
void
 
951
btr_page_empty(
 
952
/*===========*/
 
953
        page_t* page,   /* in: page to be emptied */
 
954
        mtr_t*  mtr)    /* in: mtr */
 
955
{
 
956
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
957
                                MTR_MEMO_PAGE_X_FIX));
 
958
        btr_search_drop_page_hash_index(page);
 
959
 
 
960
        /* Recreate the page: note that global data on page (possible
 
961
        segment headers, next page-field, etc.) is preserved intact */
 
962
 
 
963
        page_create(page, mtr, page_is_comp(page));
 
964
        buf_block_align(page)->check_index_page_at_flush = TRUE;
 
965
}
 
966
 
 
967
/*****************************************************************
 
968
Makes tree one level higher by splitting the root, and inserts
 
969
the tuple. It is assumed that mtr contains an x-latch on the tree.
 
970
NOTE that the operation of this function must always succeed,
 
971
we cannot reverse it: therefore enough free disk space must be
 
972
guaranteed to be available before this function is called. */
 
973
 
 
974
rec_t*
 
975
btr_root_raise_and_insert(
 
976
/*======================*/
 
977
                                /* out: inserted record */
 
978
        btr_cur_t*      cursor, /* in: cursor at which to insert: must be
 
979
                                on the root page; when the function returns,
 
980
                                the cursor is positioned on the predecessor
 
981
                                of the inserted record */
 
982
        dtuple_t*       tuple,  /* in: tuple to insert */
 
983
        mtr_t*          mtr)    /* in: mtr */
 
984
{
 
985
        dict_index_t*   index;
 
986
        page_t*         root;
 
987
        page_t*         new_page;
 
988
        ulint           new_page_no;
 
989
        rec_t*          rec;
 
990
        mem_heap_t*     heap;
 
991
        dtuple_t*       node_ptr;
 
992
        ulint           level;
 
993
        rec_t*          node_ptr_rec;
 
994
        page_cur_t*     page_cursor;
 
995
 
 
996
        root = btr_cur_get_page(cursor);
 
997
        index = btr_cur_get_index(cursor);
 
998
 
 
999
        ut_ad(dict_index_get_page(index) == buf_frame_get_page_no(root));
 
1000
        ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
 
1001
                                MTR_MEMO_X_LOCK));
 
1002
        ut_ad(mtr_memo_contains(mtr, buf_block_align(root),
 
1003
                                MTR_MEMO_PAGE_X_FIX));
 
1004
        btr_search_drop_page_hash_index(root);
 
1005
 
 
1006
        /* Allocate a new page to the tree. Root splitting is done by first
 
1007
        moving the root records to the new page, emptying the root, putting
 
1008
        a node pointer to the new page, and then splitting the new page. */
 
1009
 
 
1010
        new_page = btr_page_alloc(index, 0, FSP_NO_DIR,
 
1011
                                  btr_page_get_level(root, mtr), mtr);
 
1012
 
 
1013
        btr_page_create(new_page, index, mtr);
 
1014
 
 
1015
        level = btr_page_get_level(root, mtr);
 
1016
 
 
1017
        /* Set the levels of the new index page and root page */
 
1018
        btr_page_set_level(new_page, level, mtr);
 
1019
        btr_page_set_level(root, level + 1, mtr);
 
1020
 
 
1021
        /* Set the next node and previous node fields of new page */
 
1022
        btr_page_set_next(new_page, FIL_NULL, mtr);
 
1023
        btr_page_set_prev(new_page, FIL_NULL, mtr);
 
1024
 
 
1025
        /* Move the records from root to the new page */
 
1026
 
 
1027
        page_move_rec_list_end(new_page, root, page_get_infimum_rec(root),
 
1028
                               index, mtr);
 
1029
        /* If this is a pessimistic insert which is actually done to
 
1030
        perform a pessimistic update then we have stored the lock
 
1031
        information of the record to be inserted on the infimum of the
 
1032
        root page: we cannot discard the lock structs on the root page */
 
1033
 
 
1034
        lock_update_root_raise(new_page, root);
 
1035
 
 
1036
        /* Create a memory heap where the node pointer is stored */
 
1037
        heap = mem_heap_create(100);
 
1038
 
 
1039
        rec = page_rec_get_next(page_get_infimum_rec(new_page));
 
1040
        new_page_no = buf_frame_get_page_no(new_page);
 
1041
 
 
1042
        /* Build the node pointer (= node key and page address) for the
 
1043
        child */
 
1044
 
 
1045
        node_ptr = dict_index_build_node_ptr(index, rec, new_page_no, heap,
 
1046
                                             level);
 
1047
        /* Reorganize the root to get free space */
 
1048
        btr_page_reorganize(root, index, mtr);
 
1049
 
 
1050
        page_cursor = btr_cur_get_page_cur(cursor);
 
1051
 
 
1052
        /* Insert node pointer to the root */
 
1053
 
 
1054
        page_cur_set_before_first(root, page_cursor);
 
1055
 
 
1056
        node_ptr_rec = page_cur_tuple_insert(page_cursor, node_ptr,
 
1057
                                             index, mtr);
 
1058
 
 
1059
        ut_ad(node_ptr_rec);
 
1060
 
 
1061
        /* The node pointer must be marked as the predefined minimum record,
 
1062
        as there is no lower alphabetical limit to records in the leftmost
 
1063
        node of a level: */
 
1064
 
 
1065
        btr_set_min_rec_mark(node_ptr_rec, page_is_comp(root), mtr);
 
1066
 
 
1067
        /* Free the memory heap */
 
1068
        mem_heap_free(heap);
 
1069
 
 
1070
        /* We play safe and reset the free bits for the new page */
 
1071
 
 
1072
#if 0
 
1073
        fprintf(stderr, "Root raise new page no %lu\n",
 
1074
                buf_frame_get_page_no(new_page));
 
1075
#endif
 
1076
 
 
1077
        ibuf_reset_free_bits(index, new_page);
 
1078
        /* Reposition the cursor to the child node */
 
1079
        page_cur_search(new_page, index, tuple,
 
1080
                        PAGE_CUR_LE, page_cursor);
 
1081
 
 
1082
        /* Split the child and insert tuple */
 
1083
        return(btr_page_split_and_insert(cursor, tuple, mtr));
 
1084
}
 
1085
 
 
1086
/*****************************************************************
 
1087
Decides if the page should be split at the convergence point of inserts
 
1088
converging to the left. */
 
1089
 
 
1090
ibool
 
1091
btr_page_get_split_rec_to_left(
 
1092
/*===========================*/
 
1093
                                /* out: TRUE if split recommended */
 
1094
        btr_cur_t*      cursor, /* in: cursor at which to insert */
 
1095
        rec_t**         split_rec) /* out: if split recommended,
 
1096
                                the first record on upper half page,
 
1097
                                or NULL if tuple to be inserted should
 
1098
                                be first */
 
1099
{
 
1100
        page_t* page;
 
1101
        rec_t*  insert_point;
 
1102
        rec_t*  infimum;
 
1103
 
 
1104
        page = btr_cur_get_page(cursor);
 
1105
        insert_point = btr_cur_get_rec(cursor);
 
1106
 
 
1107
        if (page_header_get_ptr(page, PAGE_LAST_INSERT)
 
1108
            == page_rec_get_next(insert_point)) {
 
1109
 
 
1110
                infimum = page_get_infimum_rec(page);
 
1111
 
 
1112
                /* If the convergence is in the middle of a page, include also
 
1113
                the record immediately before the new insert to the upper
 
1114
                page. Otherwise, we could repeatedly move from page to page
 
1115
                lots of records smaller than the convergence point. */
 
1116
 
 
1117
                if (infimum != insert_point
 
1118
                    && page_rec_get_next(infimum) != insert_point) {
 
1119
 
 
1120
                        *split_rec = insert_point;
 
1121
                } else {
 
1122
                        *split_rec = page_rec_get_next(insert_point);
 
1123
                }
 
1124
 
 
1125
                return(TRUE);
 
1126
        }
 
1127
 
 
1128
        return(FALSE);
 
1129
}
 
1130
 
 
1131
/*****************************************************************
 
1132
Decides if the page should be split at the convergence point of inserts
 
1133
converging to the right. */
 
1134
 
 
1135
ibool
 
1136
btr_page_get_split_rec_to_right(
 
1137
/*============================*/
 
1138
                                /* out: TRUE if split recommended */
 
1139
        btr_cur_t*      cursor, /* in: cursor at which to insert */
 
1140
        rec_t**         split_rec) /* out: if split recommended,
 
1141
                                the first record on upper half page,
 
1142
                                or NULL if tuple to be inserted should
 
1143
                                be first */
 
1144
{
 
1145
        page_t* page;
 
1146
        rec_t*  insert_point;
 
1147
 
 
1148
        page = btr_cur_get_page(cursor);
 
1149
        insert_point = btr_cur_get_rec(cursor);
 
1150
 
 
1151
        /* We use eager heuristics: if the new insert would be right after
 
1152
        the previous insert on the same page, we assume that there is a
 
1153
        pattern of sequential inserts here. */
 
1154
 
 
1155
        if (UNIV_LIKELY(page_header_get_ptr(page, PAGE_LAST_INSERT)
 
1156
                        == insert_point)) {
 
1157
 
 
1158
                rec_t*  next_rec;
 
1159
 
 
1160
                next_rec = page_rec_get_next(insert_point);
 
1161
 
 
1162
                if (page_rec_is_supremum(next_rec)) {
 
1163
split_at_new:
 
1164
                        /* Split at the new record to insert */
 
1165
                        *split_rec = NULL;
 
1166
                } else {
 
1167
                        rec_t*  next_next_rec = page_rec_get_next(next_rec);
 
1168
                        if (page_rec_is_supremum(next_next_rec)) {
 
1169
 
 
1170
                                goto split_at_new;
 
1171
                        }
 
1172
 
 
1173
                        /* If there are >= 2 user records up from the insert
 
1174
                        point, split all but 1 off. We want to keep one because
 
1175
                        then sequential inserts can use the adaptive hash
 
1176
                        index, as they can do the necessary checks of the right
 
1177
                        search position just by looking at the records on this
 
1178
                        page. */
 
1179
 
 
1180
                        *split_rec = next_next_rec;
 
1181
                }
 
1182
 
 
1183
                return(TRUE);
 
1184
        }
 
1185
 
 
1186
        return(FALSE);
 
1187
}
 
1188
 
 
1189
/*****************************************************************
 
1190
Calculates a split record such that the tuple will certainly fit on
 
1191
its half-page when the split is performed. We assume in this function
 
1192
only that the cursor page has at least one user record. */
 
1193
static
 
1194
rec_t*
 
1195
btr_page_get_sure_split_rec(
 
1196
/*========================*/
 
1197
                                        /* out: split record, or NULL if
 
1198
                                        tuple will be the first record on
 
1199
                                        upper half-page */
 
1200
        btr_cur_t*      cursor,         /* in: cursor at which insert
 
1201
                                        should be made */
 
1202
        dtuple_t*       tuple)          /* in: tuple to insert */
 
1203
{
 
1204
        page_t* page;
 
1205
        ulint   insert_size;
 
1206
        ulint   free_space;
 
1207
        ulint   total_data;
 
1208
        ulint   total_n_recs;
 
1209
        ulint   total_space;
 
1210
        ulint   incl_data;
 
1211
        rec_t*  ins_rec;
 
1212
        rec_t*  rec;
 
1213
        rec_t*  next_rec;
 
1214
        ulint   n;
 
1215
        mem_heap_t* heap;
 
1216
        ulint*  offsets;
 
1217
 
 
1218
        page = btr_cur_get_page(cursor);
 
1219
 
 
1220
        insert_size = rec_get_converted_size(cursor->index, tuple);
 
1221
        free_space  = page_get_free_space_of_empty(page_is_comp(page));
 
1222
 
 
1223
        /* free_space is now the free space of a created new page */
 
1224
 
 
1225
        total_data   = page_get_data_size(page) + insert_size;
 
1226
        total_n_recs = page_get_n_recs(page) + 1;
 
1227
        ut_ad(total_n_recs >= 2);
 
1228
        total_space  = total_data + page_dir_calc_reserved_space(total_n_recs);
 
1229
 
 
1230
        n = 0;
 
1231
        incl_data = 0;
 
1232
        ins_rec = btr_cur_get_rec(cursor);
 
1233
        rec = page_get_infimum_rec(page);
 
1234
 
 
1235
        heap = NULL;
 
1236
        offsets = NULL;
 
1237
 
 
1238
        /* We start to include records to the left half, and when the
 
1239
        space reserved by them exceeds half of total_space, then if
 
1240
        the included records fit on the left page, they will be put there
 
1241
        if something was left over also for the right page,
 
1242
        otherwise the last included record will be the first on the right
 
1243
        half page */
 
1244
 
 
1245
        for (;;) {
 
1246
                /* Decide the next record to include */
 
1247
                if (rec == ins_rec) {
 
1248
                        rec = NULL;     /* NULL denotes that tuple is
 
1249
                                        now included */
 
1250
                } else if (rec == NULL) {
 
1251
                        rec = page_rec_get_next(ins_rec);
 
1252
                } else {
 
1253
                        rec = page_rec_get_next(rec);
 
1254
                }
 
1255
 
 
1256
                if (rec == NULL) {
 
1257
                        /* Include tuple */
 
1258
                        incl_data += insert_size;
 
1259
                } else {
 
1260
                        offsets = rec_get_offsets(rec, cursor->index,
 
1261
                                                  offsets, ULINT_UNDEFINED,
 
1262
                                                  &heap);
 
1263
                        incl_data += rec_offs_size(offsets);
 
1264
                }
 
1265
 
 
1266
                n++;
 
1267
 
 
1268
                if (incl_data + page_dir_calc_reserved_space(n)
 
1269
                    >= total_space / 2) {
 
1270
 
 
1271
                        if (incl_data + page_dir_calc_reserved_space(n)
 
1272
                            <= free_space) {
 
1273
                                /* The next record will be the first on
 
1274
                                the right half page if it is not the
 
1275
                                supremum record of page */
 
1276
 
 
1277
                                if (rec == ins_rec) {
 
1278
                                        rec = NULL;
 
1279
 
 
1280
                                        goto func_exit;
 
1281
                                } else if (rec == NULL) {
 
1282
                                        next_rec = page_rec_get_next(ins_rec);
 
1283
                                } else {
 
1284
                                        next_rec = page_rec_get_next(rec);
 
1285
                                }
 
1286
                                ut_ad(next_rec);
 
1287
                                if (!page_rec_is_supremum(next_rec)) {
 
1288
                                        rec = next_rec;
 
1289
                                }
 
1290
                        }
 
1291
 
 
1292
func_exit:
 
1293
                        if (UNIV_LIKELY_NULL(heap)) {
 
1294
                                mem_heap_free(heap);
 
1295
                        }
 
1296
                        return(rec);
 
1297
                }
 
1298
        }
 
1299
}
 
1300
 
 
1301
/*****************************************************************
 
1302
Returns TRUE if the insert fits on the appropriate half-page with the
 
1303
chosen split_rec. */
 
1304
static
 
1305
ibool
 
1306
btr_page_insert_fits(
 
1307
/*=================*/
 
1308
                                        /* out: TRUE if fits */
 
1309
        btr_cur_t*      cursor,         /* in: cursor at which insert
 
1310
                                        should be made */
 
1311
        rec_t*          split_rec,      /* in: suggestion for first record
 
1312
                                        on upper half-page, or NULL if
 
1313
                                        tuple to be inserted should be first */
 
1314
        const ulint*    offsets,        /* in: rec_get_offsets(
 
1315
                                        split_rec, cursor->index) */
 
1316
        dtuple_t*       tuple,          /* in: tuple to insert */
 
1317
        mem_heap_t*     heap)           /* in: temporary memory heap */
 
1318
{
 
1319
        page_t* page;
 
1320
        ulint   insert_size;
 
1321
        ulint   free_space;
 
1322
        ulint   total_data;
 
1323
        ulint   total_n_recs;
 
1324
        rec_t*  rec;
 
1325
        rec_t*  end_rec;
 
1326
        ulint*  offs;
 
1327
 
 
1328
        page = btr_cur_get_page(cursor);
 
1329
 
 
1330
        ut_ad(!split_rec == !offsets);
 
1331
        ut_ad(!offsets
 
1332
              || !page_is_comp(page) == !rec_offs_comp(offsets));
 
1333
        ut_ad(!offsets
 
1334
              || rec_offs_validate(split_rec, cursor->index, offsets));
 
1335
 
 
1336
        insert_size = rec_get_converted_size(cursor->index, tuple);
 
1337
        free_space  = page_get_free_space_of_empty(page_is_comp(page));
 
1338
 
 
1339
        /* free_space is now the free space of a created new page */
 
1340
 
 
1341
        total_data   = page_get_data_size(page) + insert_size;
 
1342
        total_n_recs = page_get_n_recs(page) + 1;
 
1343
 
 
1344
        /* We determine which records (from rec to end_rec, not including
 
1345
        end_rec) will end up on the other half page from tuple when it is
 
1346
        inserted. */
 
1347
 
 
1348
        if (split_rec == NULL) {
 
1349
                rec = page_rec_get_next(page_get_infimum_rec(page));
 
1350
                end_rec = page_rec_get_next(btr_cur_get_rec(cursor));
 
1351
 
 
1352
        } else if (cmp_dtuple_rec(tuple, split_rec, offsets) >= 0) {
 
1353
 
 
1354
                rec = page_rec_get_next(page_get_infimum_rec(page));
 
1355
                end_rec = split_rec;
 
1356
        } else {
 
1357
                rec = split_rec;
 
1358
                end_rec = page_get_supremum_rec(page);
 
1359
        }
 
1360
 
 
1361
        if (total_data + page_dir_calc_reserved_space(total_n_recs)
 
1362
            <= free_space) {
 
1363
 
 
1364
                /* Ok, there will be enough available space on the
 
1365
                half page where the tuple is inserted */
 
1366
 
 
1367
                return(TRUE);
 
1368
        }
 
1369
 
 
1370
        offs = NULL;
 
1371
 
 
1372
        while (rec != end_rec) {
 
1373
                /* In this loop we calculate the amount of reserved
 
1374
                space after rec is removed from page. */
 
1375
 
 
1376
                offs = rec_get_offsets(rec, cursor->index, offs,
 
1377
                                       ULINT_UNDEFINED, &heap);
 
1378
 
 
1379
                total_data -= rec_offs_size(offs);
 
1380
                total_n_recs--;
 
1381
 
 
1382
                if (total_data + page_dir_calc_reserved_space(total_n_recs)
 
1383
                    <= free_space) {
 
1384
 
 
1385
                        /* Ok, there will be enough available space on the
 
1386
                        half page where the tuple is inserted */
 
1387
 
 
1388
                        return(TRUE);
 
1389
                }
 
1390
 
 
1391
                rec = page_rec_get_next(rec);
 
1392
        }
 
1393
 
 
1394
        return(FALSE);
 
1395
}
 
1396
 
 
1397
/***********************************************************
 
1398
Inserts a data tuple to a tree on a non-leaf level. It is assumed
 
1399
that mtr holds an x-latch on the tree. */
 
1400
 
 
1401
void
 
1402
btr_insert_on_non_leaf_level(
 
1403
/*=========================*/
 
1404
        dict_index_t*   index,  /* in: index */
 
1405
        ulint           level,  /* in: level, must be > 0 */
 
1406
        dtuple_t*       tuple,  /* in: the record to be inserted */
 
1407
        mtr_t*          mtr)    /* in: mtr */
 
1408
{
 
1409
        big_rec_t*      dummy_big_rec;
 
1410
        btr_cur_t       cursor;
 
1411
        ulint           err;
 
1412
        rec_t*          rec;
 
1413
 
 
1414
        ut_ad(level > 0);
 
1415
 
 
1416
        btr_cur_search_to_nth_level(index, level, tuple, PAGE_CUR_LE,
 
1417
                                    BTR_CONT_MODIFY_TREE,
 
1418
                                    &cursor, 0, mtr);
 
1419
 
 
1420
        err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG
 
1421
                                         | BTR_KEEP_SYS_FLAG
 
1422
                                         | BTR_NO_UNDO_LOG_FLAG,
 
1423
                                         &cursor, tuple, &rec,
 
1424
                                         &dummy_big_rec, NULL, mtr);
 
1425
        ut_a(err == DB_SUCCESS);
 
1426
}
 
1427
 
 
1428
/******************************************************************
 
1429
Attaches the halves of an index page on the appropriate level in an
 
1430
index tree. */
 
1431
static
 
1432
void
 
1433
btr_attach_half_pages(
 
1434
/*==================*/
 
1435
        dict_index_t*   index,          /* in: the index tree */
 
1436
        page_t*         page,           /* in: page to be split */
 
1437
        rec_t*          split_rec,      /* in: first record on upper
 
1438
                                        half page */
 
1439
        page_t*         new_page,       /* in: the new half page */
 
1440
        ulint           direction,      /* in: FSP_UP or FSP_DOWN */
 
1441
        mtr_t*          mtr)            /* in: mtr */
 
1442
{
 
1443
        ulint           space;
 
1444
        rec_t*          node_ptr;
 
1445
        page_t*         prev_page;
 
1446
        page_t*         next_page;
 
1447
        ulint           prev_page_no;
 
1448
        ulint           next_page_no;
 
1449
        ulint           level;
 
1450
        page_t*         lower_page;
 
1451
        page_t*         upper_page;
 
1452
        ulint           lower_page_no;
 
1453
        ulint           upper_page_no;
 
1454
        dtuple_t*       node_ptr_upper;
 
1455
        mem_heap_t*     heap;
 
1456
 
 
1457
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
1458
                                MTR_MEMO_PAGE_X_FIX));
 
1459
        ut_ad(mtr_memo_contains(mtr, buf_block_align(new_page),
 
1460
                                MTR_MEMO_PAGE_X_FIX));
 
1461
        ut_a(page_is_comp(page) == page_is_comp(new_page));
 
1462
 
 
1463
        /* Create a memory heap where the data tuple is stored */
 
1464
        heap = mem_heap_create(1024);
 
1465
 
 
1466
        /* Based on split direction, decide upper and lower pages */
 
1467
        if (direction == FSP_DOWN) {
 
1468
 
 
1469
                lower_page_no = buf_frame_get_page_no(new_page);
 
1470
                upper_page_no = buf_frame_get_page_no(page);
 
1471
                lower_page = new_page;
 
1472
                upper_page = page;
 
1473
 
 
1474
                /* Look up the index for the node pointer to page */
 
1475
                node_ptr = btr_page_get_father_node_ptr(index, page, mtr);
 
1476
 
 
1477
                /* Replace the address of the old child node (= page) with the
 
1478
                address of the new lower half */
 
1479
 
 
1480
                btr_node_ptr_set_child_page_no(node_ptr,
 
1481
                                               rec_get_offsets(
 
1482
                                                       node_ptr, index,
 
1483
                                                       NULL, ULINT_UNDEFINED,
 
1484
                                                       &heap),
 
1485
                                               lower_page_no, mtr);
 
1486
                mem_heap_empty(heap);
 
1487
        } else {
 
1488
                lower_page_no = buf_frame_get_page_no(page);
 
1489
                upper_page_no = buf_frame_get_page_no(new_page);
 
1490
                lower_page = page;
 
1491
                upper_page = new_page;
 
1492
        }
 
1493
 
 
1494
        /* Get the level of the split pages */
 
1495
        level = btr_page_get_level(page, mtr);
 
1496
 
 
1497
        /* Build the node pointer (= node key and page address) for the upper
 
1498
        half */
 
1499
 
 
1500
        node_ptr_upper = dict_index_build_node_ptr(index, split_rec,
 
1501
                                                   upper_page_no, heap, level);
 
1502
 
 
1503
        /* Insert it next to the pointer to the lower half. Note that this
 
1504
        may generate recursion leading to a split on the higher level. */
 
1505
 
 
1506
        btr_insert_on_non_leaf_level(index, level + 1, node_ptr_upper, mtr);
 
1507
 
 
1508
        /* Free the memory heap */
 
1509
        mem_heap_free(heap);
 
1510
 
 
1511
        /* Get the previous and next pages of page */
 
1512
 
 
1513
        prev_page_no = btr_page_get_prev(page, mtr);
 
1514
        next_page_no = btr_page_get_next(page, mtr);
 
1515
        space = buf_frame_get_space_id(page);
 
1516
 
 
1517
        /* Update page links of the level */
 
1518
 
 
1519
        if (prev_page_no != FIL_NULL) {
 
1520
 
 
1521
                prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr);
 
1522
                ut_a(page_is_comp(prev_page) == page_is_comp(page));
 
1523
#ifdef UNIV_BTR_DEBUG
 
1524
                ut_a(btr_page_get_next(prev_page, mtr)
 
1525
                     == buf_frame_get_page_no(page));
 
1526
#endif /* UNIV_BTR_DEBUG */
 
1527
 
 
1528
                btr_page_set_next(prev_page, lower_page_no, mtr);
 
1529
        }
 
1530
 
 
1531
        if (next_page_no != FIL_NULL) {
 
1532
 
 
1533
                next_page = btr_page_get(space, next_page_no, RW_X_LATCH, mtr);
 
1534
                ut_a(page_is_comp(next_page) == page_is_comp(page));
 
1535
 
 
1536
                btr_page_set_prev(next_page, upper_page_no, mtr);
 
1537
        }
 
1538
 
 
1539
        btr_page_set_prev(lower_page, prev_page_no, mtr);
 
1540
        btr_page_set_next(lower_page, upper_page_no, mtr);
 
1541
        btr_page_set_level(lower_page, level, mtr);
 
1542
 
 
1543
        btr_page_set_prev(upper_page, lower_page_no, mtr);
 
1544
        btr_page_set_next(upper_page, next_page_no, mtr);
 
1545
        btr_page_set_level(upper_page, level, mtr);
 
1546
}
 
1547
 
 
1548
/*****************************************************************
 
1549
Splits an index page to halves and inserts the tuple. It is assumed
 
1550
that mtr holds an x-latch to the index tree. NOTE: the tree x-latch
 
1551
is released within this function! NOTE that the operation of this
 
1552
function must always succeed, we cannot reverse it: therefore
 
1553
enough free disk space must be guaranteed to be available before
 
1554
this function is called. */
 
1555
 
 
1556
rec_t*
 
1557
btr_page_split_and_insert(
 
1558
/*======================*/
 
1559
                                /* out: inserted record; NOTE: the tree
 
1560
                                x-latch is released! NOTE: 2 free disk
 
1561
                                pages must be available! */
 
1562
        btr_cur_t*      cursor, /* in: cursor at which to insert; when the
 
1563
                                function returns, the cursor is positioned
 
1564
                                on the predecessor of the inserted record */
 
1565
        dtuple_t*       tuple,  /* in: tuple to insert */
 
1566
        mtr_t*          mtr)    /* in: mtr */
 
1567
{
 
1568
        page_t*         page;
 
1569
        ulint           page_no;
 
1570
        byte            direction;
 
1571
        ulint           hint_page_no;
 
1572
        page_t*         new_page;
 
1573
        rec_t*          split_rec;
 
1574
        page_t*         left_page;
 
1575
        page_t*         right_page;
 
1576
        page_t*         insert_page;
 
1577
        page_cur_t*     page_cursor;
 
1578
        rec_t*          first_rec;
 
1579
        byte*           buf = 0; /* remove warning */
 
1580
        rec_t*          move_limit;
 
1581
        ibool           insert_will_fit;
 
1582
        ulint           n_iterations = 0;
 
1583
        rec_t*          rec;
 
1584
        mem_heap_t*     heap;
 
1585
        ulint           n_uniq;
 
1586
        ulint*          offsets;
 
1587
 
 
1588
        heap = mem_heap_create(1024);
 
1589
        n_uniq = dict_index_get_n_unique_in_tree(cursor->index);
 
1590
func_start:
 
1591
        mem_heap_empty(heap);
 
1592
        offsets = NULL;
 
1593
 
 
1594
        ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index),
 
1595
                                MTR_MEMO_X_LOCK));
 
1596
#ifdef UNIV_SYNC_DEBUG
 
1597
        ut_ad(rw_lock_own(dict_index_get_lock(cursor->index), RW_LOCK_EX));
 
1598
#endif /* UNIV_SYNC_DEBUG */
 
1599
 
 
1600
        page = btr_cur_get_page(cursor);
 
1601
 
 
1602
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
1603
                                MTR_MEMO_PAGE_X_FIX));
 
1604
        ut_ad(page_get_n_recs(page) >= 2);
 
1605
 
 
1606
        page_no = buf_frame_get_page_no(page);
 
1607
 
 
1608
        /* 1. Decide the split record; split_rec == NULL means that the
 
1609
        tuple to be inserted should be the first record on the upper
 
1610
        half-page */
 
1611
 
 
1612
        if (n_iterations > 0) {
 
1613
                direction = FSP_UP;
 
1614
                hint_page_no = page_no + 1;
 
1615
                split_rec = btr_page_get_sure_split_rec(cursor, tuple);
 
1616
 
 
1617
        } else if (btr_page_get_split_rec_to_right(cursor, &split_rec)) {
 
1618
                direction = FSP_UP;
 
1619
                hint_page_no = page_no + 1;
 
1620
 
 
1621
        } else if (btr_page_get_split_rec_to_left(cursor, &split_rec)) {
 
1622
                direction = FSP_DOWN;
 
1623
                hint_page_no = page_no - 1;
 
1624
        } else {
 
1625
                direction = FSP_UP;
 
1626
                hint_page_no = page_no + 1;
 
1627
                split_rec = page_get_middle_rec(page);
 
1628
        }
 
1629
 
 
1630
        /* 2. Allocate a new page to the index */
 
1631
        new_page = btr_page_alloc(cursor->index, hint_page_no, direction,
 
1632
                                  btr_page_get_level(page, mtr), mtr);
 
1633
        btr_page_create(new_page, cursor->index, mtr);
 
1634
 
 
1635
        /* 3. Calculate the first record on the upper half-page, and the
 
1636
        first record (move_limit) on original page which ends up on the
 
1637
        upper half */
 
1638
 
 
1639
        if (split_rec != NULL) {
 
1640
                first_rec = split_rec;
 
1641
                move_limit = split_rec;
 
1642
        } else {
 
1643
                buf = mem_alloc(rec_get_converted_size(cursor->index, tuple));
 
1644
 
 
1645
                first_rec = rec_convert_dtuple_to_rec(buf,
 
1646
                                                      cursor->index, tuple);
 
1647
                move_limit = page_rec_get_next(btr_cur_get_rec(cursor));
 
1648
        }
 
1649
 
 
1650
        /* 4. Do first the modifications in the tree structure */
 
1651
 
 
1652
        btr_attach_half_pages(cursor->index, page, first_rec,
 
1653
                              new_page, direction, mtr);
 
1654
 
 
1655
        if (split_rec == NULL) {
 
1656
                mem_free(buf);
 
1657
        }
 
1658
 
 
1659
        /* If the split is made on the leaf level and the insert will fit
 
1660
        on the appropriate half-page, we may release the tree x-latch.
 
1661
        We can then move the records after releasing the tree latch,
 
1662
        thus reducing the tree latch contention. */
 
1663
 
 
1664
        if (split_rec) {
 
1665
                offsets = rec_get_offsets(split_rec, cursor->index, offsets,
 
1666
                                          n_uniq, &heap);
 
1667
 
 
1668
                insert_will_fit = btr_page_insert_fits(cursor,
 
1669
                                                       split_rec, offsets,
 
1670
                                                       tuple, heap);
 
1671
        } else {
 
1672
                insert_will_fit = btr_page_insert_fits(cursor,
 
1673
                                                       NULL, NULL,
 
1674
                                                       tuple, heap);
 
1675
        }
 
1676
 
 
1677
        if (insert_will_fit && (btr_page_get_level(page, mtr) == 0)) {
 
1678
 
 
1679
                mtr_memo_release(mtr, dict_index_get_lock(cursor->index),
 
1680
                                 MTR_MEMO_X_LOCK);
 
1681
        }
 
1682
 
 
1683
        /* 5. Move then the records to the new page */
 
1684
        if (direction == FSP_DOWN) {
 
1685
                /*              fputs("Split left\n", stderr); */
 
1686
 
 
1687
                page_move_rec_list_start(new_page, page, move_limit,
 
1688
                                         cursor->index, mtr);
 
1689
                left_page = new_page;
 
1690
                right_page = page;
 
1691
 
 
1692
                lock_update_split_left(right_page, left_page);
 
1693
        } else {
 
1694
                /*              fputs("Split right\n", stderr); */
 
1695
 
 
1696
                page_move_rec_list_end(new_page, page, move_limit,
 
1697
                                       cursor->index, mtr);
 
1698
                left_page = page;
 
1699
                right_page = new_page;
 
1700
 
 
1701
                lock_update_split_right(right_page, left_page);
 
1702
        }
 
1703
 
 
1704
        /* 6. The split and the tree modification is now completed. Decide the
 
1705
        page where the tuple should be inserted */
 
1706
 
 
1707
        if (split_rec == NULL) {
 
1708
                insert_page = right_page;
 
1709
 
 
1710
        } else {
 
1711
                offsets = rec_get_offsets(first_rec, cursor->index,
 
1712
                                          offsets, n_uniq, &heap);
 
1713
 
 
1714
                if (cmp_dtuple_rec(tuple, first_rec, offsets) >= 0) {
 
1715
 
 
1716
                        insert_page = right_page;
 
1717
                } else {
 
1718
                        insert_page = left_page;
 
1719
                }
 
1720
        }
 
1721
 
 
1722
        /* 7. Reposition the cursor for insert and try insertion */
 
1723
        page_cursor = btr_cur_get_page_cur(cursor);
 
1724
 
 
1725
        page_cur_search(insert_page, cursor->index, tuple,
 
1726
                        PAGE_CUR_LE, page_cursor);
 
1727
 
 
1728
        rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index, mtr);
 
1729
 
 
1730
        if (rec != NULL) {
 
1731
                /* Insert fit on the page: update the free bits for the
 
1732
                left and right pages in the same mtr */
 
1733
 
 
1734
                ibuf_update_free_bits_for_two_pages_low(cursor->index,
 
1735
                                                        left_page,
 
1736
                                                        right_page, mtr);
 
1737
                /* fprintf(stderr, "Split and insert done %lu %lu\n",
 
1738
                buf_frame_get_page_no(left_page),
 
1739
                buf_frame_get_page_no(right_page)); */
 
1740
                mem_heap_free(heap);
 
1741
                return(rec);
 
1742
        }
 
1743
 
 
1744
        /* 8. If insert did not fit, try page reorganization */
 
1745
 
 
1746
        btr_page_reorganize(insert_page, cursor->index, mtr);
 
1747
 
 
1748
        page_cur_search(insert_page, cursor->index, tuple,
 
1749
                        PAGE_CUR_LE, page_cursor);
 
1750
        rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index, mtr);
 
1751
 
 
1752
        if (rec == NULL) {
 
1753
                /* The insert did not fit on the page: loop back to the
 
1754
                start of the function for a new split */
 
1755
 
 
1756
                /* We play safe and reset the free bits for new_page */
 
1757
                ibuf_reset_free_bits(cursor->index, new_page);
 
1758
 
 
1759
                /* fprintf(stderr, "Split second round %lu\n",
 
1760
                buf_frame_get_page_no(page)); */
 
1761
                n_iterations++;
 
1762
                ut_ad(n_iterations < 2);
 
1763
                ut_ad(!insert_will_fit);
 
1764
 
 
1765
                goto func_start;
 
1766
        }
 
1767
 
 
1768
        /* Insert fit on the page: update the free bits for the
 
1769
        left and right pages in the same mtr */
 
1770
 
 
1771
        ibuf_update_free_bits_for_two_pages_low(cursor->index, left_page,
 
1772
                                                right_page, mtr);
 
1773
#if 0
 
1774
        fprintf(stderr, "Split and insert done %lu %lu\n",
 
1775
                buf_frame_get_page_no(left_page),
 
1776
                buf_frame_get_page_no(right_page));
 
1777
#endif
 
1778
 
 
1779
        ut_ad(page_validate(left_page, cursor->index));
 
1780
        ut_ad(page_validate(right_page, cursor->index));
 
1781
 
 
1782
        mem_heap_free(heap);
 
1783
        return(rec);
 
1784
}
 
1785
 
 
1786
/*****************************************************************
 
1787
Removes a page from the level list of pages. */
 
1788
static
 
1789
void
 
1790
btr_level_list_remove(
 
1791
/*==================*/
 
1792
        page_t*         page,   /* in: page to remove */
 
1793
        mtr_t*          mtr)    /* in: mtr */
 
1794
{
 
1795
        ulint   space;
 
1796
        ulint   prev_page_no;
 
1797
        page_t* prev_page;
 
1798
        ulint   next_page_no;
 
1799
        page_t* next_page;
 
1800
 
 
1801
        ut_ad(page && mtr);
 
1802
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
1803
                                MTR_MEMO_PAGE_X_FIX));
 
1804
        /* Get the previous and next page numbers of page */
 
1805
 
 
1806
        prev_page_no = btr_page_get_prev(page, mtr);
 
1807
        next_page_no = btr_page_get_next(page, mtr);
 
1808
        space = buf_frame_get_space_id(page);
 
1809
 
 
1810
        /* Update page links of the level */
 
1811
 
 
1812
        if (prev_page_no != FIL_NULL) {
 
1813
 
 
1814
                prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr);
 
1815
                ut_a(page_is_comp(prev_page) == page_is_comp(page));
 
1816
#ifdef UNIV_BTR_DEBUG
 
1817
                ut_a(btr_page_get_next(prev_page, mtr)
 
1818
                     == buf_frame_get_page_no(page));
 
1819
#endif /* UNIV_BTR_DEBUG */
 
1820
 
 
1821
                btr_page_set_next(prev_page, next_page_no, mtr);
 
1822
        }
 
1823
 
 
1824
        if (next_page_no != FIL_NULL) {
 
1825
 
 
1826
                next_page = btr_page_get(space, next_page_no, RW_X_LATCH, mtr);
 
1827
                ut_a(page_is_comp(next_page) == page_is_comp(page));
 
1828
#ifdef UNIV_BTR_DEBUG
 
1829
                ut_a(btr_page_get_prev(next_page, mtr)
 
1830
                     == buf_frame_get_page_no(page));
 
1831
#endif /* UNIV_BTR_DEBUG */
 
1832
 
 
1833
                btr_page_set_prev(next_page, prev_page_no, mtr);
 
1834
        }
 
1835
}
 
1836
 
 
1837
/********************************************************************
 
1838
Writes the redo log record for setting an index record as the predefined
 
1839
minimum record. */
 
1840
UNIV_INLINE
 
1841
void
 
1842
btr_set_min_rec_mark_log(
 
1843
/*=====================*/
 
1844
        rec_t*  rec,    /* in: record */
 
1845
        ulint   comp,   /* nonzero=compact record format */
 
1846
        mtr_t*  mtr)    /* in: mtr */
 
1847
{
 
1848
        mlog_write_initial_log_record(
 
1849
                rec, comp ? MLOG_COMP_REC_MIN_MARK : MLOG_REC_MIN_MARK, mtr);
 
1850
 
 
1851
        /* Write rec offset as a 2-byte ulint */
 
1852
        mlog_catenate_ulint(mtr, page_offset(rec), MLOG_2BYTES);
 
1853
}
 
1854
 
 
1855
/********************************************************************
 
1856
Parses the redo log record for setting an index record as the predefined
 
1857
minimum record. */
 
1858
 
 
1859
byte*
 
1860
btr_parse_set_min_rec_mark(
 
1861
/*=======================*/
 
1862
                        /* out: end of log record or NULL */
 
1863
        byte*   ptr,    /* in: buffer */
 
1864
        byte*   end_ptr,/* in: buffer end */
 
1865
        ulint   comp,   /* in: nonzero=compact page format */
 
1866
        page_t* page,   /* in: page or NULL */
 
1867
        mtr_t*  mtr)    /* in: mtr or NULL */
 
1868
{
 
1869
        rec_t*  rec;
 
1870
 
 
1871
        if (end_ptr < ptr + 2) {
 
1872
 
 
1873
                return(NULL);
 
1874
        }
 
1875
 
 
1876
        if (page) {
 
1877
                ut_a(!page_is_comp(page) == !comp);
 
1878
 
 
1879
                rec = page + mach_read_from_2(ptr);
 
1880
 
 
1881
                btr_set_min_rec_mark(rec, comp, mtr);
 
1882
        }
 
1883
 
 
1884
        return(ptr + 2);
 
1885
}
 
1886
 
 
1887
/********************************************************************
 
1888
Sets a record as the predefined minimum record. */
 
1889
 
 
1890
void
 
1891
btr_set_min_rec_mark(
 
1892
/*=================*/
 
1893
        rec_t*  rec,    /* in: record */
 
1894
        ulint   comp,   /* in: nonzero=compact page format */
 
1895
        mtr_t*  mtr)    /* in: mtr */
 
1896
{
 
1897
        ulint   info_bits;
 
1898
 
 
1899
        info_bits = rec_get_info_bits(rec, comp);
 
1900
 
 
1901
        rec_set_info_bits(rec, comp, info_bits | REC_INFO_MIN_REC_FLAG);
 
1902
 
 
1903
        btr_set_min_rec_mark_log(rec, comp, mtr);
 
1904
}
 
1905
 
 
1906
/*****************************************************************
 
1907
Deletes on the upper level the node pointer to a page. */
 
1908
 
 
1909
void
 
1910
btr_node_ptr_delete(
 
1911
/*================*/
 
1912
        dict_index_t*   index,  /* in: index tree */
 
1913
        page_t*         page,   /* in: page whose node pointer is deleted */
 
1914
        mtr_t*          mtr)    /* in: mtr */
 
1915
{
 
1916
        rec_t*          node_ptr;
 
1917
        btr_cur_t       cursor;
 
1918
        ibool           compressed;
 
1919
        ulint           err;
 
1920
 
 
1921
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
1922
                                MTR_MEMO_PAGE_X_FIX));
 
1923
        /* Delete node pointer on father page */
 
1924
 
 
1925
        node_ptr = btr_page_get_father_node_ptr(index, page, mtr);
 
1926
 
 
1927
        btr_cur_position(index, node_ptr, &cursor);
 
1928
        compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, FALSE,
 
1929
                                                mtr);
 
1930
        ut_a(err == DB_SUCCESS);
 
1931
 
 
1932
        if (!compressed) {
 
1933
                btr_cur_compress_if_useful(&cursor, mtr);
 
1934
        }
 
1935
}
 
1936
 
 
1937
/*****************************************************************
 
1938
If page is the only on its level, this function moves its records to the
 
1939
father page, thus reducing the tree height. */
 
1940
static
 
1941
void
 
1942
btr_lift_page_up(
 
1943
/*=============*/
 
1944
        dict_index_t*   index,  /* in: index tree */
 
1945
        page_t*         page,   /* in: page which is the only on its level;
 
1946
                                must not be empty: use
 
1947
                                btr_discard_only_page_on_level if the last
 
1948
                                record from the page should be removed */
 
1949
        mtr_t*          mtr)    /* in: mtr */
 
1950
{
 
1951
        page_t*         father_page;
 
1952
        page_t*         iter_page;
 
1953
        page_t*         pages[BTR_MAX_LEVELS];
 
1954
        ulint           page_level;
 
1955
        ulint           root_page_no;
 
1956
        ulint           ancestors;
 
1957
        ulint           i;
 
1958
 
 
1959
        ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL);
 
1960
        ut_ad(btr_page_get_next(page, mtr) == FIL_NULL);
 
1961
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
1962
                                MTR_MEMO_PAGE_X_FIX));
 
1963
        father_page = buf_frame_align(
 
1964
                btr_page_get_father_node_ptr(index, page, mtr));
 
1965
 
 
1966
        page_level = btr_page_get_level(page, mtr);
 
1967
        root_page_no = dict_index_get_page(index);
 
1968
 
 
1969
        ancestors = 1;
 
1970
        pages[0] = father_page;
 
1971
 
 
1972
        /* Store all ancestor pages so we can reset their levels later on.
 
1973
        We have to do all the searches on the tree now because later on,
 
1974
        after we've replaced the first level, the tree is in an inconsistent
 
1975
        state and can not be searched. */
 
1976
        iter_page = father_page;
 
1977
        for (;;) {
 
1978
                if (buf_block_get_page_no(buf_block_align(iter_page))
 
1979
                    == root_page_no) {
 
1980
 
 
1981
                        break;
 
1982
                }
 
1983
 
 
1984
                ut_a(ancestors < BTR_MAX_LEVELS);
 
1985
 
 
1986
                iter_page = buf_frame_align(
 
1987
                        btr_page_get_father_node_ptr(index, iter_page, mtr));
 
1988
 
 
1989
                pages[ancestors++] = iter_page;
 
1990
        }
 
1991
 
 
1992
        btr_search_drop_page_hash_index(page);
 
1993
 
 
1994
        /* Make the father empty */
 
1995
        btr_page_empty(father_page, mtr);
 
1996
 
 
1997
        /* Move records to the father */
 
1998
        page_copy_rec_list_end(father_page, page, page_get_infimum_rec(page),
 
1999
                               index, mtr);
 
2000
        lock_update_copy_and_discard(father_page, page);
 
2001
 
 
2002
        /* Go upward to root page, decreasing levels by one. */
 
2003
        for (i = 0; i < ancestors; i++) {
 
2004
                iter_page = pages[i];
 
2005
 
 
2006
                ut_ad(btr_page_get_level(iter_page, mtr) == (page_level + 1));
 
2007
 
 
2008
                btr_page_set_level(iter_page, page_level, mtr);
 
2009
                page_level++;
 
2010
        }
 
2011
 
 
2012
        /* Free the file page */
 
2013
        btr_page_free(index, page, mtr);
 
2014
 
 
2015
        /* We play safe and reset the free bits for the father */
 
2016
        ibuf_reset_free_bits(index, father_page);
 
2017
        ut_ad(page_validate(father_page, index));
 
2018
        ut_ad(btr_check_node_ptr(index, father_page, mtr));
 
2019
}
 
2020
 
 
2021
/*****************************************************************
 
2022
Tries to merge the page first to the left immediate brother if such a
 
2023
brother exists, and the node pointers to the current page and to the brother
 
2024
reside on the same page. If the left brother does not satisfy these
 
2025
conditions, looks at the right brother. If the page is the only one on that
 
2026
level lifts the records of the page to the father page, thus reducing the
 
2027
tree height. It is assumed that mtr holds an x-latch on the tree and on the
 
2028
page. If cursor is on the leaf level, mtr must also hold x-latches to the
 
2029
brothers, if they exist. NOTE: it is assumed that the caller has reserved
 
2030
enough free extents so that the compression will always succeed if done! */
 
2031
 
 
2032
void
 
2033
btr_compress(
 
2034
/*=========*/
 
2035
        btr_cur_t*      cursor, /* in: cursor on the page to merge or lift;
 
2036
                                the page must not be empty: in record delete
 
2037
                                use btr_discard_page if the page would become
 
2038
                                empty */
 
2039
        mtr_t*          mtr)    /* in: mtr */
 
2040
{
 
2041
        dict_index_t*   index;
 
2042
        ulint           space;
 
2043
        ulint           left_page_no;
 
2044
        ulint           right_page_no;
 
2045
        page_t*         merge_page;
 
2046
        page_t*         father_page;
 
2047
        ibool           is_left;
 
2048
        page_t*         page;
 
2049
        rec_t*          orig_pred;
 
2050
        rec_t*          orig_succ;
 
2051
        rec_t*          node_ptr;
 
2052
        ulint           data_size;
 
2053
        ulint           n_recs;
 
2054
        ulint           max_ins_size;
 
2055
        ulint           max_ins_size_reorg;
 
2056
        ulint           level;
 
2057
        ulint           comp;
 
2058
 
 
2059
        page = btr_cur_get_page(cursor);
 
2060
        index = btr_cur_get_index(cursor);
 
2061
        comp = page_is_comp(page);
 
2062
        ut_a((ibool)!!comp == dict_table_is_comp(index->table));
 
2063
 
 
2064
        ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
 
2065
                                MTR_MEMO_X_LOCK));
 
2066
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
2067
                                MTR_MEMO_PAGE_X_FIX));
 
2068
        level = btr_page_get_level(page, mtr);
 
2069
        space = dict_index_get_space(index);
 
2070
 
 
2071
        left_page_no = btr_page_get_prev(page, mtr);
 
2072
        right_page_no = btr_page_get_next(page, mtr);
 
2073
 
 
2074
#if 0
 
2075
        fprintf(stderr, "Merge left page %lu right %lu \n",
 
2076
                left_page_no, right_page_no);
 
2077
#endif
 
2078
 
 
2079
        node_ptr = btr_page_get_father_node_ptr(index, page, mtr);
 
2080
        ut_ad(!comp || rec_get_status(node_ptr) == REC_STATUS_NODE_PTR);
 
2081
        father_page = buf_frame_align(node_ptr);
 
2082
        ut_a(comp == page_is_comp(father_page));
 
2083
 
 
2084
        /* Decide the page to which we try to merge and which will inherit
 
2085
        the locks */
 
2086
 
 
2087
        is_left = left_page_no != FIL_NULL;
 
2088
 
 
2089
        if (is_left) {
 
2090
 
 
2091
                merge_page = btr_page_get(space, left_page_no, RW_X_LATCH,
 
2092
                                          mtr);
 
2093
#ifdef UNIV_BTR_DEBUG
 
2094
                ut_a(btr_page_get_next(merge_page, mtr)
 
2095
                     == buf_frame_get_page_no(page));
 
2096
#endif /* UNIV_BTR_DEBUG */
 
2097
        } else if (right_page_no != FIL_NULL) {
 
2098
 
 
2099
                merge_page = btr_page_get(space, right_page_no, RW_X_LATCH,
 
2100
                                          mtr);
 
2101
#ifdef UNIV_BTR_DEBUG
 
2102
                ut_a(btr_page_get_prev(merge_page, mtr)
 
2103
                     == buf_frame_get_page_no(page));
 
2104
#endif /* UNIV_BTR_DEBUG */
 
2105
        } else {
 
2106
                /* The page is the only one on the level, lift the records
 
2107
                to the father */
 
2108
                btr_lift_page_up(index, page, mtr);
 
2109
 
 
2110
                return;
 
2111
        }
 
2112
 
 
2113
        n_recs = page_get_n_recs(page);
 
2114
        data_size = page_get_data_size(page);
 
2115
        ut_a(page_is_comp(merge_page) == comp);
 
2116
 
 
2117
        max_ins_size_reorg = page_get_max_insert_size_after_reorganize(
 
2118
                merge_page, n_recs);
 
2119
        if (data_size > max_ins_size_reorg) {
 
2120
 
 
2121
                /* No space for merge */
 
2122
 
 
2123
                return;
 
2124
        }
 
2125
 
 
2126
        ut_ad(page_validate(merge_page, index));
 
2127
 
 
2128
        max_ins_size = page_get_max_insert_size(merge_page, n_recs);
 
2129
 
 
2130
        if (data_size > max_ins_size) {
 
2131
 
 
2132
                /* We have to reorganize merge_page */
 
2133
 
 
2134
                btr_page_reorganize(merge_page, index, mtr);
 
2135
 
 
2136
                max_ins_size = page_get_max_insert_size(merge_page, n_recs);
 
2137
 
 
2138
                ut_ad(page_validate(merge_page, index));
 
2139
                ut_ad(page_get_max_insert_size(merge_page, n_recs)
 
2140
                      == max_ins_size_reorg);
 
2141
        }
 
2142
 
 
2143
        if (data_size > max_ins_size) {
 
2144
 
 
2145
                /* Add fault tolerance, though this should never happen */
 
2146
 
 
2147
                return;
 
2148
        }
 
2149
 
 
2150
        btr_search_drop_page_hash_index(page);
 
2151
 
 
2152
        /* Remove the page from the level list */
 
2153
        btr_level_list_remove(page, mtr);
 
2154
 
 
2155
        if (is_left) {
 
2156
                btr_node_ptr_delete(index, page, mtr);
 
2157
        } else {
 
2158
                mem_heap_t*     heap            = NULL;
 
2159
                ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
2160
                *offsets_ = (sizeof offsets_) / sizeof *offsets_;
 
2161
                /* Replace the address of the old child node (= page) with the
 
2162
                address of the merge page to the right */
 
2163
 
 
2164
                btr_node_ptr_set_child_page_no(node_ptr,
 
2165
                                               rec_get_offsets(
 
2166
                                                       node_ptr, index,
 
2167
                                                       offsets_,
 
2168
                                                       ULINT_UNDEFINED,
 
2169
                                                       &heap),
 
2170
                                               right_page_no, mtr);
 
2171
                if (UNIV_LIKELY_NULL(heap)) {
 
2172
                        mem_heap_free(heap);
 
2173
                }
 
2174
                btr_node_ptr_delete(index, merge_page, mtr);
 
2175
        }
 
2176
 
 
2177
        /* Move records to the merge page */
 
2178
        if (is_left) {
 
2179
                orig_pred = page_rec_get_prev(
 
2180
                        page_get_supremum_rec(merge_page));
 
2181
                page_copy_rec_list_start(merge_page, page,
 
2182
                                         page_get_supremum_rec(page),
 
2183
                                         index, mtr);
 
2184
 
 
2185
                lock_update_merge_left(merge_page, orig_pred, page);
 
2186
        } else {
 
2187
                orig_succ = page_rec_get_next(
 
2188
                        page_get_infimum_rec(merge_page));
 
2189
                page_copy_rec_list_end(merge_page, page,
 
2190
                                       page_get_infimum_rec(page),
 
2191
                                       index, mtr);
 
2192
 
 
2193
                lock_update_merge_right(orig_succ, page);
 
2194
        }
 
2195
 
 
2196
        /* We have added new records to merge_page: update its free bits */
 
2197
        ibuf_update_free_bits_if_full(index, merge_page,
 
2198
                                      UNIV_PAGE_SIZE, ULINT_UNDEFINED);
 
2199
 
 
2200
        ut_ad(page_validate(merge_page, index));
 
2201
 
 
2202
        /* Free the file page */
 
2203
        btr_page_free(index, page, mtr);
 
2204
 
 
2205
        ut_ad(btr_check_node_ptr(index, merge_page, mtr));
 
2206
}
 
2207
 
 
2208
/*****************************************************************
 
2209
Discards a page that is the only page on its level. */
 
2210
static
 
2211
void
 
2212
btr_discard_only_page_on_level(
 
2213
/*===========================*/
 
2214
        dict_index_t*   index,  /* in: index tree */
 
2215
        page_t*         page,   /* in: page which is the only on its level */
 
2216
        mtr_t*          mtr)    /* in: mtr */
 
2217
{
 
2218
        rec_t*  node_ptr;
 
2219
        page_t* father_page;
 
2220
        ulint   page_level;
 
2221
 
 
2222
        ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL);
 
2223
        ut_ad(btr_page_get_next(page, mtr) == FIL_NULL);
 
2224
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
2225
                                MTR_MEMO_PAGE_X_FIX));
 
2226
        btr_search_drop_page_hash_index(page);
 
2227
 
 
2228
        node_ptr = btr_page_get_father_node_ptr(index, page, mtr);
 
2229
        father_page = buf_frame_align(node_ptr);
 
2230
 
 
2231
        page_level = btr_page_get_level(page, mtr);
 
2232
 
 
2233
        lock_update_discard(page_get_supremum_rec(father_page), page);
 
2234
 
 
2235
        btr_page_set_level(father_page, page_level, mtr);
 
2236
 
 
2237
        /* Free the file page */
 
2238
        btr_page_free(index, page, mtr);
 
2239
 
 
2240
        if (buf_frame_get_page_no(father_page) == dict_index_get_page(index)) {
 
2241
                /* The father is the root page */
 
2242
 
 
2243
                btr_page_empty(father_page, mtr);
 
2244
 
 
2245
                /* We play safe and reset the free bits for the father */
 
2246
                ibuf_reset_free_bits(index, father_page);
 
2247
        } else {
 
2248
                ut_ad(page_get_n_recs(father_page) == 1);
 
2249
 
 
2250
                btr_discard_only_page_on_level(index, father_page, mtr);
 
2251
        }
 
2252
}
 
2253
 
 
2254
/*****************************************************************
 
2255
Discards a page from a B-tree. This is used to remove the last record from
 
2256
a B-tree page: the whole page must be removed at the same time. This cannot
 
2257
be used for the root page, which is allowed to be empty. */
 
2258
 
 
2259
void
 
2260
btr_discard_page(
 
2261
/*=============*/
 
2262
        btr_cur_t*      cursor, /* in: cursor on the page to discard: not on
 
2263
                                the root page */
 
2264
        mtr_t*          mtr)    /* in: mtr */
 
2265
{
 
2266
        dict_index_t*   index;
 
2267
        ulint           space;
 
2268
        ulint           left_page_no;
 
2269
        ulint           right_page_no;
 
2270
        page_t*         merge_page;
 
2271
        page_t*         page;
 
2272
        rec_t*          node_ptr;
 
2273
 
 
2274
        page = btr_cur_get_page(cursor);
 
2275
        index = btr_cur_get_index(cursor);
 
2276
 
 
2277
        ut_ad(dict_index_get_page(index) != buf_frame_get_page_no(page));
 
2278
        ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
 
2279
                                MTR_MEMO_X_LOCK));
 
2280
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
2281
                                MTR_MEMO_PAGE_X_FIX));
 
2282
        space = dict_index_get_space(index);
 
2283
 
 
2284
        /* Decide the page which will inherit the locks */
 
2285
 
 
2286
        left_page_no = btr_page_get_prev(page, mtr);
 
2287
        right_page_no = btr_page_get_next(page, mtr);
 
2288
 
 
2289
        if (left_page_no != FIL_NULL) {
 
2290
                merge_page = btr_page_get(space, left_page_no, RW_X_LATCH,
 
2291
                                          mtr);
 
2292
#ifdef UNIV_BTR_DEBUG
 
2293
                ut_a(btr_page_get_next(merge_page, mtr)
 
2294
                     == buf_frame_get_page_no(page));
 
2295
#endif /* UNIV_BTR_DEBUG */
 
2296
        } else if (right_page_no != FIL_NULL) {
 
2297
                merge_page = btr_page_get(space, right_page_no, RW_X_LATCH,
 
2298
                                          mtr);
 
2299
#ifdef UNIV_BTR_DEBUG
 
2300
                ut_a(btr_page_get_prev(merge_page, mtr)
 
2301
                     == buf_frame_get_page_no(page));
 
2302
#endif /* UNIV_BTR_DEBUG */
 
2303
        } else {
 
2304
                btr_discard_only_page_on_level(index, page, mtr);
 
2305
 
 
2306
                return;
 
2307
        }
 
2308
 
 
2309
        ut_a(page_is_comp(merge_page) == page_is_comp(page));
 
2310
        btr_search_drop_page_hash_index(page);
 
2311
 
 
2312
        if (left_page_no == FIL_NULL && btr_page_get_level(page, mtr) > 0) {
 
2313
 
 
2314
                /* We have to mark the leftmost node pointer on the right
 
2315
                side page as the predefined minimum record */
 
2316
 
 
2317
                node_ptr = page_rec_get_next(page_get_infimum_rec(merge_page));
 
2318
 
 
2319
                ut_ad(page_rec_is_user_rec(node_ptr));
 
2320
 
 
2321
                btr_set_min_rec_mark(node_ptr, page_is_comp(merge_page), mtr);
 
2322
        }
 
2323
 
 
2324
        btr_node_ptr_delete(index, page, mtr);
 
2325
 
 
2326
        /* Remove the page from the level list */
 
2327
        btr_level_list_remove(page, mtr);
 
2328
 
 
2329
        if (left_page_no != FIL_NULL) {
 
2330
                lock_update_discard(page_get_supremum_rec(merge_page), page);
 
2331
        } else {
 
2332
                lock_update_discard(page_rec_get_next(
 
2333
                                            page_get_infimum_rec(merge_page)),
 
2334
                                    page);
 
2335
        }
 
2336
 
 
2337
        /* Free the file page */
 
2338
        btr_page_free(index, page, mtr);
 
2339
 
 
2340
        ut_ad(btr_check_node_ptr(index, merge_page, mtr));
 
2341
}
 
2342
 
 
2343
#ifdef UNIV_BTR_PRINT
 
2344
/*****************************************************************
 
2345
Prints size info of a B-tree. */
 
2346
 
 
2347
void
 
2348
btr_print_size(
 
2349
/*===========*/
 
2350
        dict_index_t*   index)  /* in: index tree */
 
2351
{
 
2352
        page_t*         root;
 
2353
        fseg_header_t*  seg;
 
2354
        mtr_t           mtr;
 
2355
 
 
2356
        if (index->type & DICT_IBUF) {
 
2357
                fputs("Sorry, cannot print info of an ibuf tree:"
 
2358
                      " use ibuf functions\n", stderr);
 
2359
 
 
2360
                return;
 
2361
        }
 
2362
 
 
2363
        mtr_start(&mtr);
 
2364
 
 
2365
        root = btr_root_get(index, &mtr);
 
2366
 
 
2367
        seg = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
 
2368
 
 
2369
        fputs("INFO OF THE NON-LEAF PAGE SEGMENT\n", stderr);
 
2370
        fseg_print(seg, &mtr);
 
2371
 
 
2372
        if (!(index->type & DICT_UNIVERSAL)) {
 
2373
 
 
2374
                seg = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
 
2375
 
 
2376
                fputs("INFO OF THE LEAF PAGE SEGMENT\n", stderr);
 
2377
                fseg_print(seg, &mtr);
 
2378
        }
 
2379
 
 
2380
        mtr_commit(&mtr);
 
2381
}
 
2382
 
 
2383
/****************************************************************
 
2384
Prints recursively index tree pages. */
 
2385
static
 
2386
void
 
2387
btr_print_recursive(
 
2388
/*================*/
 
2389
        dict_index_t*   index,  /* in: index tree */
 
2390
        page_t*         page,   /* in: index page */
 
2391
        ulint           width,  /* in: print this many entries from start
 
2392
                                and end */
 
2393
        mem_heap_t**    heap,   /* in/out: heap for rec_get_offsets() */
 
2394
        ulint**         offsets,/* in/out: buffer for rec_get_offsets() */
 
2395
        mtr_t*          mtr)    /* in: mtr */
 
2396
{
 
2397
        page_cur_t      cursor;
 
2398
        ulint           n_recs;
 
2399
        ulint           i       = 0;
 
2400
        mtr_t           mtr2;
 
2401
        rec_t*          node_ptr;
 
2402
        page_t*         child;
 
2403
 
 
2404
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
2405
                                MTR_MEMO_PAGE_X_FIX));
 
2406
        fprintf(stderr, "NODE ON LEVEL %lu page number %lu\n",
 
2407
                (ulong) btr_page_get_level(page, mtr),
 
2408
                (ulong) buf_frame_get_page_no(page));
 
2409
 
 
2410
        page_print(page, index, width, width);
 
2411
 
 
2412
        n_recs = page_get_n_recs(page);
 
2413
 
 
2414
        page_cur_set_before_first(page, &cursor);
 
2415
        page_cur_move_to_next(&cursor);
 
2416
 
 
2417
        while (!page_cur_is_after_last(&cursor)) {
 
2418
 
 
2419
                if (0 == btr_page_get_level(page, mtr)) {
 
2420
 
 
2421
                        /* If this is the leaf level, do nothing */
 
2422
 
 
2423
                } else if ((i <= width) || (i >= n_recs - width)) {
 
2424
 
 
2425
                        mtr_start(&mtr2);
 
2426
 
 
2427
                        node_ptr = page_cur_get_rec(&cursor);
 
2428
 
 
2429
                        *offsets = rec_get_offsets(node_ptr, index, *offsets,
 
2430
                                                   ULINT_UNDEFINED, heap);
 
2431
                        child = btr_node_ptr_get_child(node_ptr,
 
2432
                                                       *offsets, &mtr2);
 
2433
                        btr_print_recursive(index, child, width,
 
2434
                                            heap, offsets, &mtr2);
 
2435
                        mtr_commit(&mtr2);
 
2436
                }
 
2437
 
 
2438
                page_cur_move_to_next(&cursor);
 
2439
                i++;
 
2440
        }
 
2441
}
 
2442
 
 
2443
/******************************************************************
 
2444
Prints directories and other info of all nodes in the tree. */
 
2445
 
 
2446
void
 
2447
btr_print_index(
 
2448
/*============*/
 
2449
        dict_index_t*   index,  /* in: index */
 
2450
        ulint           width)  /* in: print this many entries from start
 
2451
                                and end */
 
2452
{
 
2453
        mtr_t           mtr;
 
2454
        page_t*         root;
 
2455
        mem_heap_t*     heap    = NULL;
 
2456
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
2457
        ulint*          offsets = offsets_;
 
2458
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
 
2459
 
 
2460
        fputs("--------------------------\n"
 
2461
              "INDEX TREE PRINT\n", stderr);
 
2462
 
 
2463
        mtr_start(&mtr);
 
2464
 
 
2465
        root = btr_root_get(index, &mtr);
 
2466
 
 
2467
        btr_print_recursive(index, root, width, &heap, &offsets, &mtr);
 
2468
        if (UNIV_LIKELY_NULL(heap)) {
 
2469
                mem_heap_free(heap);
 
2470
        }
 
2471
 
 
2472
        mtr_commit(&mtr);
 
2473
 
 
2474
        btr_validate_index(index, NULL);
 
2475
}
 
2476
#endif /* UNIV_BTR_PRINT */
 
2477
 
 
2478
#ifdef UNIV_DEBUG
 
2479
/****************************************************************
 
2480
Checks that the node pointer to a page is appropriate. */
 
2481
 
 
2482
ibool
 
2483
btr_check_node_ptr(
 
2484
/*===============*/
 
2485
                                /* out: TRUE */
 
2486
        dict_index_t*   index,  /* in: index tree */
 
2487
        page_t*         page,   /* in: index page */
 
2488
        mtr_t*          mtr)    /* in: mtr */
 
2489
{
 
2490
        mem_heap_t*     heap;
 
2491
        rec_t*          node_ptr;
 
2492
        dtuple_t*       node_ptr_tuple;
 
2493
 
 
2494
        ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
 
2495
                                MTR_MEMO_PAGE_X_FIX));
 
2496
        if (dict_index_get_page(index) == buf_frame_get_page_no(page)) {
 
2497
 
 
2498
                return(TRUE);
 
2499
        }
 
2500
 
 
2501
        node_ptr = btr_page_get_father_node_ptr(index, page, mtr);
 
2502
 
 
2503
        if (btr_page_get_level(page, mtr) == 0) {
 
2504
 
 
2505
                return(TRUE);
 
2506
        }
 
2507
 
 
2508
        heap = mem_heap_create(256);
 
2509
 
 
2510
        node_ptr_tuple = dict_index_build_node_ptr(
 
2511
                index, page_rec_get_next(page_get_infimum_rec(page)), 0, heap,
 
2512
                btr_page_get_level(page, mtr));
 
2513
 
 
2514
        ut_a(!cmp_dtuple_rec(node_ptr_tuple, node_ptr,
 
2515
                             rec_get_offsets(node_ptr, index,
 
2516
                                             NULL, ULINT_UNDEFINED, &heap)));
 
2517
 
 
2518
        mem_heap_free(heap);
 
2519
 
 
2520
        return(TRUE);
 
2521
}
 
2522
#endif /* UNIV_DEBUG */
 
2523
 
 
2524
/****************************************************************
 
2525
Display identification information for a record. */
 
2526
static
 
2527
void
 
2528
btr_index_rec_validate_report(
 
2529
/*==========================*/
 
2530
        page_t*         page,   /* in: index page */
 
2531
        rec_t*          rec,    /* in: index record */
 
2532
        dict_index_t*   index)  /* in: index */
 
2533
{
 
2534
        fputs("InnoDB: Record in ", stderr);
 
2535
        dict_index_name_print(stderr, NULL, index);
 
2536
        fprintf(stderr, ", page %lu, at offset %lu\n",
 
2537
                buf_frame_get_page_no(page), (ulint)(rec - page));
 
2538
}
 
2539
 
 
2540
/****************************************************************
 
2541
Checks the size and number of fields in a record based on the definition of
 
2542
the index. */
 
2543
 
 
2544
ibool
 
2545
btr_index_rec_validate(
 
2546
/*===================*/
 
2547
                                        /* out: TRUE if ok */
 
2548
        rec_t*          rec,            /* in: index record */
 
2549
        dict_index_t*   index,          /* in: index */
 
2550
        ibool           dump_on_error)  /* in: TRUE if the function
 
2551
                                        should print hex dump of record
 
2552
                                        and page on error */
 
2553
{
 
2554
        ulint           len;
 
2555
        ulint           n;
 
2556
        ulint           i;
 
2557
        page_t*         page;
 
2558
        mem_heap_t*     heap    = NULL;
 
2559
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
2560
        ulint*          offsets = offsets_;
 
2561
        *offsets_ = (sizeof offsets_) / sizeof *offsets_;
 
2562
 
 
2563
        page = buf_frame_align(rec);
 
2564
 
 
2565
        if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
 
2566
                /* The insert buffer index tree can contain records from any
 
2567
                other index: we cannot check the number of fields or
 
2568
                their length */
 
2569
 
 
2570
                return(TRUE);
 
2571
        }
 
2572
 
 
2573
        if (UNIV_UNLIKELY((ibool)!!page_is_comp(page)
 
2574
                          != dict_table_is_comp(index->table))) {
 
2575
                btr_index_rec_validate_report(page, rec, index);
 
2576
                fprintf(stderr, "InnoDB: compact flag=%lu, should be %lu\n",
 
2577
                        (ulong) !!page_is_comp(page),
 
2578
                        (ulong) dict_table_is_comp(index->table));
 
2579
 
 
2580
                return(FALSE);
 
2581
        }
 
2582
 
 
2583
        n = dict_index_get_n_fields(index);
 
2584
 
 
2585
        if (!page_is_comp(page)
 
2586
            && UNIV_UNLIKELY(rec_get_n_fields_old(rec) != n)) {
 
2587
                btr_index_rec_validate_report(page, rec, index);
 
2588
                fprintf(stderr, "InnoDB: has %lu fields, should have %lu\n",
 
2589
                        (ulong) rec_get_n_fields_old(rec), (ulong) n);
 
2590
 
 
2591
                if (dump_on_error) {
 
2592
                        buf_page_print(page);
 
2593
 
 
2594
                        fputs("InnoDB: corrupt record ", stderr);
 
2595
                        rec_print_old(stderr, rec);
 
2596
                        putc('\n', stderr);
 
2597
                }
 
2598
                return(FALSE);
 
2599
        }
 
2600
 
 
2601
        offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
 
2602
 
 
2603
        for (i = 0; i < n; i++) {
 
2604
                ulint   fixed_size = dict_col_get_fixed_size(
 
2605
                        dict_index_get_nth_col(index, i));
 
2606
 
 
2607
                rec_get_nth_field(rec, offsets, i, &len);
 
2608
 
 
2609
                /* Note that if fixed_size != 0, it equals the
 
2610
                length of a fixed-size column in the clustered index.
 
2611
                A prefix index of the column is of fixed, but different
 
2612
                length.  When fixed_size == 0, prefix_len is the maximum
 
2613
                length of the prefix index column. */
 
2614
 
 
2615
                if ((dict_index_get_nth_field(index, i)->prefix_len == 0
 
2616
                     && len != UNIV_SQL_NULL && fixed_size
 
2617
                     && len != fixed_size)
 
2618
                    || (dict_index_get_nth_field(index, i)->prefix_len > 0
 
2619
                        && len != UNIV_SQL_NULL
 
2620
                        && len
 
2621
                        > dict_index_get_nth_field(index, i)->prefix_len)) {
 
2622
 
 
2623
                        btr_index_rec_validate_report(page, rec, index);
 
2624
                        fprintf(stderr,
 
2625
                                "InnoDB: field %lu len is %lu,"
 
2626
                                " should be %lu\n",
 
2627
                                (ulong) i, (ulong) len, (ulong) fixed_size);
 
2628
 
 
2629
                        if (dump_on_error) {
 
2630
                                buf_page_print(page);
 
2631
 
 
2632
                                fputs("InnoDB: corrupt record ", stderr);
 
2633
                                rec_print_new(stderr, rec, offsets);
 
2634
                                putc('\n', stderr);
 
2635
                        }
 
2636
                        if (UNIV_LIKELY_NULL(heap)) {
 
2637
                                mem_heap_free(heap);
 
2638
                        }
 
2639
                        return(FALSE);
 
2640
                }
 
2641
        }
 
2642
 
 
2643
        if (UNIV_LIKELY_NULL(heap)) {
 
2644
                mem_heap_free(heap);
 
2645
        }
 
2646
        return(TRUE);
 
2647
}
 
2648
 
 
2649
/****************************************************************
 
2650
Checks the size and number of fields in records based on the definition of
 
2651
the index. */
 
2652
static
 
2653
ibool
 
2654
btr_index_page_validate(
 
2655
/*====================*/
 
2656
                                /* out: TRUE if ok */
 
2657
        page_t*         page,   /* in: index page */
 
2658
        dict_index_t*   index)  /* in: index */
 
2659
{
 
2660
        page_cur_t      cur;
 
2661
        ibool           ret     = TRUE;
 
2662
 
 
2663
        page_cur_set_before_first(page, &cur);
 
2664
        page_cur_move_to_next(&cur);
 
2665
 
 
2666
        for (;;) {
 
2667
                if (page_cur_is_after_last(&cur)) {
 
2668
 
 
2669
                        break;
 
2670
                }
 
2671
 
 
2672
                if (!btr_index_rec_validate(cur.rec, index, TRUE)) {
 
2673
 
 
2674
                        return(FALSE);
 
2675
                }
 
2676
 
 
2677
                page_cur_move_to_next(&cur);
 
2678
        }
 
2679
 
 
2680
        return(ret);
 
2681
}
 
2682
 
 
2683
/****************************************************************
 
2684
Report an error on one page of an index tree. */
 
2685
static
 
2686
void
 
2687
btr_validate_report1(
 
2688
/*=================*/
 
2689
                                /* out: TRUE if ok */
 
2690
        dict_index_t*   index,  /* in: index */
 
2691
        ulint           level,  /* in: B-tree level */
 
2692
        page_t*         page)   /* in: index page */
 
2693
{
 
2694
        fprintf(stderr, "InnoDB: Error in page %lu of ",
 
2695
                buf_frame_get_page_no(page));
 
2696
        dict_index_name_print(stderr, NULL, index);
 
2697
        if (level) {
 
2698
                fprintf(stderr, ", index tree level %lu", level);
 
2699
        }
 
2700
        putc('\n', stderr);
 
2701
}
 
2702
 
 
2703
/****************************************************************
 
2704
Report an error on two pages of an index tree. */
 
2705
static
 
2706
void
 
2707
btr_validate_report2(
 
2708
/*=================*/
 
2709
                                /* out: TRUE if ok */
 
2710
        dict_index_t*   index,  /* in: index */
 
2711
        ulint           level,  /* in: B-tree level */
 
2712
        page_t*         page1,  /* in: first index page */
 
2713
        page_t*         page2)  /* in: second index page */
 
2714
{
 
2715
        fprintf(stderr, "InnoDB: Error in pages %lu and %lu of ",
 
2716
                buf_frame_get_page_no(page1),
 
2717
                buf_frame_get_page_no(page2));
 
2718
        dict_index_name_print(stderr, NULL, index);
 
2719
        if (level) {
 
2720
                fprintf(stderr, ", index tree level %lu", level);
 
2721
        }
 
2722
        putc('\n', stderr);
 
2723
}
 
2724
 
 
2725
/****************************************************************
 
2726
Validates index tree level. */
 
2727
static
 
2728
ibool
 
2729
btr_validate_level(
 
2730
/*===============*/
 
2731
                                /* out: TRUE if ok */
 
2732
        dict_index_t*   index,  /* in: index tree */
 
2733
        trx_t*          trx,    /* in: transaction or NULL */
 
2734
        ulint           level)  /* in: level number */
 
2735
{
 
2736
        ulint           space;
 
2737
        page_t*         page;
 
2738
        page_t*         right_page = 0; /* remove warning */
 
2739
        page_t*         father_page;
 
2740
        page_t*         right_father_page;
 
2741
        rec_t*          node_ptr;
 
2742
        rec_t*          right_node_ptr;
 
2743
        rec_t*          rec;
 
2744
        ulint           right_page_no;
 
2745
        ulint           left_page_no;
 
2746
        page_cur_t      cursor;
 
2747
        dtuple_t*       node_ptr_tuple;
 
2748
        ibool           ret     = TRUE;
 
2749
        mtr_t           mtr;
 
2750
        mem_heap_t*     heap    = mem_heap_create(256);
 
2751
        ulint*          offsets = NULL;
 
2752
        ulint*          offsets2= NULL;
 
2753
 
 
2754
        mtr_start(&mtr);
 
2755
 
 
2756
        mtr_x_lock(dict_index_get_lock(index), &mtr);
 
2757
 
 
2758
        page = btr_root_get(index, &mtr);
 
2759
 
 
2760
        space = buf_frame_get_space_id(page);
 
2761
 
 
2762
        while (level != btr_page_get_level(page, &mtr)) {
 
2763
 
 
2764
                ut_a(btr_page_get_level(page, &mtr) > 0);
 
2765
 
 
2766
                page_cur_set_before_first(page, &cursor);
 
2767
                page_cur_move_to_next(&cursor);
 
2768
 
 
2769
                node_ptr = page_cur_get_rec(&cursor);
 
2770
                offsets = rec_get_offsets(node_ptr, index, offsets,
 
2771
                                          ULINT_UNDEFINED, &heap);
 
2772
                page = btr_node_ptr_get_child(node_ptr, offsets, &mtr);
 
2773
        }
 
2774
 
 
2775
        /* Now we are on the desired level. Loop through the pages on that
 
2776
        level. */
 
2777
loop:
 
2778
        if (trx_is_interrupted(trx)) {
 
2779
                mtr_commit(&mtr);
 
2780
                mem_heap_free(heap);
 
2781
                return(ret);
 
2782
        }
 
2783
        mem_heap_empty(heap);
 
2784
        offsets = offsets2 = NULL;
 
2785
        mtr_x_lock(dict_index_get_lock(index), &mtr);
 
2786
 
 
2787
        /* Check ordering etc. of records */
 
2788
 
 
2789
        if (!page_validate(page, index)) {
 
2790
                btr_validate_report1(index, level, page);
 
2791
 
 
2792
                ret = FALSE;
 
2793
        } else if (level == 0) {
 
2794
                /* We are on level 0. Check that the records have the right
 
2795
                number of fields, and field lengths are right. */
 
2796
 
 
2797
                if (!btr_index_page_validate(page, index)) {
 
2798
 
 
2799
                        ret = FALSE;
 
2800
                }
 
2801
        }
 
2802
 
 
2803
        ut_a(btr_page_get_level(page, &mtr) == level);
 
2804
 
 
2805
        right_page_no = btr_page_get_next(page, &mtr);
 
2806
        left_page_no = btr_page_get_prev(page, &mtr);
 
2807
 
 
2808
        ut_a((page_get_n_recs(page) > 0)
 
2809
             || ((level == 0)
 
2810
                 && (buf_frame_get_page_no(page)
 
2811
                     == dict_index_get_page(index))));
 
2812
 
 
2813
        if (right_page_no != FIL_NULL) {
 
2814
                rec_t*  right_rec;
 
2815
                right_page = btr_page_get(space, right_page_no, RW_X_LATCH,
 
2816
                                          &mtr);
 
2817
                if (UNIV_UNLIKELY(btr_page_get_prev(right_page, &mtr)
 
2818
                                  != buf_frame_get_page_no(page))) {
 
2819
                        btr_validate_report2(index, level, page, right_page);
 
2820
                        fputs("InnoDB: broken FIL_PAGE_NEXT"
 
2821
                              " or FIL_PAGE_PREV links\n", stderr);
 
2822
                        buf_page_print(page);
 
2823
                        buf_page_print(right_page);
 
2824
 
 
2825
                        ret = FALSE;
 
2826
                }
 
2827
 
 
2828
                if (UNIV_UNLIKELY(page_is_comp(right_page)
 
2829
                                  != page_is_comp(page))) {
 
2830
                        btr_validate_report2(index, level, page, right_page);
 
2831
                        fputs("InnoDB: 'compact' flag mismatch\n", stderr);
 
2832
                        buf_page_print(page);
 
2833
                        buf_page_print(right_page);
 
2834
 
 
2835
                        ret = FALSE;
 
2836
 
 
2837
                        goto node_ptr_fails;
 
2838
                }
 
2839
 
 
2840
                rec = page_rec_get_prev(page_get_supremum_rec(page));
 
2841
                right_rec = page_rec_get_next(page_get_infimum_rec(
 
2842
                                                      right_page));
 
2843
                offsets = rec_get_offsets(rec, index,
 
2844
                                          offsets, ULINT_UNDEFINED, &heap);
 
2845
                offsets2 = rec_get_offsets(right_rec, index,
 
2846
                                           offsets2, ULINT_UNDEFINED, &heap);
 
2847
                if (UNIV_UNLIKELY(cmp_rec_rec(rec, right_rec,
 
2848
                                              offsets, offsets2,
 
2849
                                              index) >= 0)) {
 
2850
 
 
2851
                        btr_validate_report2(index, level, page, right_page);
 
2852
 
 
2853
                        fputs("InnoDB: records in wrong order"
 
2854
                              " on adjacent pages\n", stderr);
 
2855
 
 
2856
                        buf_page_print(page);
 
2857
                        buf_page_print(right_page);
 
2858
 
 
2859
                        fputs("InnoDB: record ", stderr);
 
2860
                        rec = page_rec_get_prev(page_get_supremum_rec(page));
 
2861
                        rec_print(stderr, rec, index);
 
2862
                        putc('\n', stderr);
 
2863
                        fputs("InnoDB: record ", stderr);
 
2864
                        rec = page_rec_get_next(
 
2865
                                page_get_infimum_rec(right_page));
 
2866
                        rec_print(stderr, rec, index);
 
2867
                        putc('\n', stderr);
 
2868
 
 
2869
                        ret = FALSE;
 
2870
                }
 
2871
        }
 
2872
 
 
2873
        if (level > 0 && left_page_no == FIL_NULL) {
 
2874
                ut_a(REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
 
2875
                             page_rec_get_next(page_get_infimum_rec(page)),
 
2876
                             page_is_comp(page)));
 
2877
        }
 
2878
 
 
2879
        if (buf_frame_get_page_no(page) != dict_index_get_page(index)) {
 
2880
 
 
2881
                /* Check father node pointers */
 
2882
 
 
2883
                node_ptr = btr_page_get_father_node_ptr(index, page, &mtr);
 
2884
                father_page = buf_frame_align(node_ptr);
 
2885
                offsets = rec_get_offsets(node_ptr, index,
 
2886
                                          offsets, ULINT_UNDEFINED, &heap);
 
2887
 
 
2888
                if (btr_node_ptr_get_child_page_no(node_ptr, offsets)
 
2889
                    != buf_frame_get_page_no(page)
 
2890
                    || node_ptr != btr_page_get_father_for_rec(
 
2891
                            index, page,
 
2892
                            page_rec_get_prev(page_get_supremum_rec(page)),
 
2893
                            &mtr)) {
 
2894
                        btr_validate_report1(index, level, page);
 
2895
 
 
2896
                        fputs("InnoDB: node pointer to the page is wrong\n",
 
2897
                              stderr);
 
2898
 
 
2899
                        buf_page_print(father_page);
 
2900
                        buf_page_print(page);
 
2901
 
 
2902
                        fputs("InnoDB: node ptr ", stderr);
 
2903
                        rec_print_new(stderr, node_ptr, offsets);
 
2904
 
 
2905
                        fprintf(stderr, "\n"
 
2906
                                "InnoDB: node ptr child page n:o %lu\n",
 
2907
                                (unsigned long) btr_node_ptr_get_child_page_no
 
2908
                                (node_ptr, offsets));
 
2909
 
 
2910
                        fputs("InnoDB: record on page ", stderr);
 
2911
                        rec = btr_page_get_father_for_rec(
 
2912
                                index, page,
 
2913
                                page_rec_get_prev(page_get_supremum_rec(page)),
 
2914
                                &mtr);
 
2915
                        rec_print(stderr, rec, index);
 
2916
                        putc('\n', stderr);
 
2917
                        ret = FALSE;
 
2918
 
 
2919
                        goto node_ptr_fails;
 
2920
                }
 
2921
 
 
2922
                if (btr_page_get_level(page, &mtr) > 0) {
 
2923
                        offsets = rec_get_offsets(node_ptr, index,
 
2924
                                                  offsets, ULINT_UNDEFINED,
 
2925
                                                  &heap);
 
2926
 
 
2927
                        node_ptr_tuple = dict_index_build_node_ptr(
 
2928
                                index,
 
2929
                                page_rec_get_next(page_get_infimum_rec(page)),
 
2930
                                0, heap, btr_page_get_level(page, &mtr));
 
2931
 
 
2932
                        if (cmp_dtuple_rec(node_ptr_tuple, node_ptr,
 
2933
                                           offsets)) {
 
2934
                                rec_t*  first_rec       = page_rec_get_next(
 
2935
                                        page_get_infimum_rec(page));
 
2936
 
 
2937
                                btr_validate_report1(index, level, page);
 
2938
 
 
2939
                                buf_page_print(father_page);
 
2940
                                buf_page_print(page);
 
2941
 
 
2942
                                fputs("InnoDB: Error: node ptrs differ"
 
2943
                                      " on levels > 0\n"
 
2944
                                      "InnoDB: node ptr ", stderr);
 
2945
                                rec_print_new(stderr, node_ptr, offsets);
 
2946
                                fputs("InnoDB: first rec ", stderr);
 
2947
                                rec_print(stderr, first_rec, index);
 
2948
                                putc('\n', stderr);
 
2949
                                ret = FALSE;
 
2950
 
 
2951
                                goto node_ptr_fails;
 
2952
                        }
 
2953
                }
 
2954
 
 
2955
                if (left_page_no == FIL_NULL) {
 
2956
                        ut_a(node_ptr == page_rec_get_next(
 
2957
                                     page_get_infimum_rec(father_page)));
 
2958
                        ut_a(btr_page_get_prev(father_page, &mtr) == FIL_NULL);
 
2959
                }
 
2960
 
 
2961
                if (right_page_no == FIL_NULL) {
 
2962
                        ut_a(node_ptr == page_rec_get_prev(
 
2963
                                     page_get_supremum_rec(father_page)));
 
2964
                        ut_a(btr_page_get_next(father_page, &mtr) == FIL_NULL);
 
2965
                } else {
 
2966
                        right_node_ptr = btr_page_get_father_node_ptr(
 
2967
                                index, right_page, &mtr);
 
2968
                        if (page_rec_get_next(node_ptr)
 
2969
                            != page_get_supremum_rec(father_page)) {
 
2970
 
 
2971
                                if (right_node_ptr
 
2972
                                    != page_rec_get_next(node_ptr)) {
 
2973
                                        ret = FALSE;
 
2974
                                        fputs("InnoDB: node pointer to"
 
2975
                                              " the right page is wrong\n",
 
2976
                                              stderr);
 
2977
 
 
2978
                                        btr_validate_report1(index, level,
 
2979
                                                             page);
 
2980
 
 
2981
                                        buf_page_print(father_page);
 
2982
                                        buf_page_print(page);
 
2983
                                        buf_page_print(right_page);
 
2984
                                }
 
2985
                        } else {
 
2986
                                right_father_page = buf_frame_align(
 
2987
                                        right_node_ptr);
 
2988
 
 
2989
                                if (right_node_ptr != page_rec_get_next(
 
2990
                                            page_get_infimum_rec(
 
2991
                                                    right_father_page))) {
 
2992
                                        ret = FALSE;
 
2993
                                        fputs("InnoDB: node pointer 2 to"
 
2994
                                              " the right page is wrong\n",
 
2995
                                              stderr);
 
2996
 
 
2997
                                        btr_validate_report1(index, level,
 
2998
                                                             page);
 
2999
 
 
3000
                                        buf_page_print(father_page);
 
3001
                                        buf_page_print(right_father_page);
 
3002
                                        buf_page_print(page);
 
3003
                                        buf_page_print(right_page);
 
3004
                                }
 
3005
 
 
3006
                                if (buf_frame_get_page_no(right_father_page)
 
3007
                                    != btr_page_get_next(father_page, &mtr)) {
 
3008
 
 
3009
                                        ret = FALSE;
 
3010
                                        fputs("InnoDB: node pointer 3 to"
 
3011
                                              " the right page is wrong\n",
 
3012
                                              stderr);
 
3013
 
 
3014
                                        btr_validate_report1(index, level,
 
3015
                                                             page);
 
3016
 
 
3017
                                        buf_page_print(father_page);
 
3018
                                        buf_page_print(right_father_page);
 
3019
                                        buf_page_print(page);
 
3020
                                        buf_page_print(right_page);
 
3021
                                }
 
3022
                        }
 
3023
                }
 
3024
        }
 
3025
 
 
3026
node_ptr_fails:
 
3027
        /* Commit the mini-transaction to release the latch on 'page'.
 
3028
        Re-acquire the latch on right_page, which will become 'page'
 
3029
        on the next loop.  The page has already been checked. */
 
3030
        mtr_commit(&mtr);
 
3031
 
 
3032
        if (right_page_no != FIL_NULL) {
 
3033
                mtr_start(&mtr);
 
3034
 
 
3035
                page = btr_page_get(space, right_page_no, RW_X_LATCH, &mtr);
 
3036
 
 
3037
                goto loop;
 
3038
        }
 
3039
 
 
3040
        mem_heap_free(heap);
 
3041
        return(ret);
 
3042
}
 
3043
 
 
3044
/******************************************************************
 
3045
Checks the consistency of an index tree. */
 
3046
 
 
3047
ibool
 
3048
btr_validate_index(
 
3049
/*===============*/
 
3050
                                /* out: TRUE if ok */
 
3051
        dict_index_t*   index,  /* in: index */
 
3052
        trx_t*          trx)    /* in: transaction or NULL */
 
3053
{
 
3054
        mtr_t   mtr;
 
3055
        page_t* root;
 
3056
        ulint   i;
 
3057
        ulint   n;
 
3058
 
 
3059
        mtr_start(&mtr);
 
3060
        mtr_x_lock(dict_index_get_lock(index), &mtr);
 
3061
 
 
3062
        root = btr_root_get(index, &mtr);
 
3063
        n = btr_page_get_level(root, &mtr);
 
3064
 
 
3065
        for (i = 0; i <= n && !trx_is_interrupted(trx); i++) {
 
3066
                if (!btr_validate_level(index, trx, n - i)) {
 
3067
 
 
3068
                        mtr_commit(&mtr);
 
3069
 
 
3070
                        return(FALSE);
 
3071
                }
 
3072
        }
 
3073
 
 
3074
        mtr_commit(&mtr);
 
3075
 
 
3076
        return(TRUE);
 
3077
}