~ubuntu-branches/ubuntu/lucid/mysql-dfsg-5.1/lucid-security

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2012-02-22 22:33:55 UTC
  • mto: (1.2.1) (37.1.1 lucid-security)
  • mto: This revision was merged to the branch mainline in revision 36.
  • Revision ID: package-import@ubuntu.com-20120222223355-ku1tb4r70osci6v2
Tags: upstream-5.1.61
ImportĀ upstreamĀ versionĀ 5.1.61

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*****************************************************************************
2
2
 
3
 
Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
 
3
Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved.
4
4
 
5
5
This program is free software; you can redistribute it and/or modify it under
6
6
the terms of the GNU General Public License as published by the Free Software
42
42
#include "ibuf0ibuf.h"
43
43
#include "trx0trx.h"
44
44
 
 
45
#ifdef UNIV_BLOB_DEBUG
 
46
# include "srv0srv.h"
 
47
# include "ut0rbt.h"
 
48
 
 
49
/** TRUE when messages about index->blobs modification are enabled. */
 
50
static ibool btr_blob_dbg_msg;
 
51
 
 
52
/** Issue a message about an operation on index->blobs.
 
53
@param op       operation
 
54
@param b        the entry being subjected to the operation
 
55
@param ctx      the context of the operation */
 
56
#define btr_blob_dbg_msg_issue(op, b, ctx)                      \
 
57
        fprintf(stderr, op " %u:%u:%u->%u %s(%u,%u,%u)\n",      \
 
58
                (b)->ref_page_no, (b)->ref_heap_no,             \
 
59
                (b)->ref_field_no, (b)->blob_page_no, ctx,      \
 
60
                (b)->owner, (b)->always_owner, (b)->del)
 
61
 
 
62
/** Insert to index->blobs a reference to an off-page column.
 
63
@param index    the index tree
 
64
@param b        the reference
 
65
@param ctx      context (for logging) */
 
66
UNIV_INTERN
 
67
void
 
68
btr_blob_dbg_rbt_insert(
 
69
/*====================*/
 
70
        dict_index_t*           index,  /*!< in/out: index tree */
 
71
        const btr_blob_dbg_t*   b,      /*!< in: the reference */
 
72
        const char*             ctx)    /*!< in: context (for logging) */
 
73
{
 
74
        if (btr_blob_dbg_msg) {
 
75
                btr_blob_dbg_msg_issue("insert", b, ctx);
 
76
        }
 
77
        mutex_enter(&index->blobs_mutex);
 
78
        rbt_insert(index->blobs, b, b);
 
79
        mutex_exit(&index->blobs_mutex);
 
80
}
 
81
 
 
82
/** Remove from index->blobs a reference to an off-page column.
 
83
@param index    the index tree
 
84
@param b        the reference
 
85
@param ctx      context (for logging) */
 
86
UNIV_INTERN
 
87
void
 
88
btr_blob_dbg_rbt_delete(
 
89
/*====================*/
 
90
        dict_index_t*           index,  /*!< in/out: index tree */
 
91
        const btr_blob_dbg_t*   b,      /*!< in: the reference */
 
92
        const char*             ctx)    /*!< in: context (for logging) */
 
93
{
 
94
        if (btr_blob_dbg_msg) {
 
95
                btr_blob_dbg_msg_issue("delete", b, ctx);
 
96
        }
 
97
        mutex_enter(&index->blobs_mutex);
 
98
        ut_a(rbt_delete(index->blobs, b));
 
99
        mutex_exit(&index->blobs_mutex);
 
100
}
 
101
 
 
102
/**************************************************************//**
 
103
Comparator for items (btr_blob_dbg_t) in index->blobs.
 
104
The key in index->blobs is (ref_page_no, ref_heap_no, ref_field_no).
 
105
@return negative, 0 or positive if *a<*b, *a=*b, *a>*b */
 
106
static
 
107
int
 
108
btr_blob_dbg_cmp(
 
109
/*=============*/
 
110
        const void*     a,      /*!< in: first btr_blob_dbg_t to compare */
 
111
        const void*     b)      /*!< in: second btr_blob_dbg_t to compare */
 
112
{
 
113
        const btr_blob_dbg_t*   aa      = a;
 
114
        const btr_blob_dbg_t*   bb      = b;
 
115
 
 
116
        ut_ad(aa != NULL);
 
117
        ut_ad(bb != NULL);
 
118
 
 
119
        if (aa->ref_page_no != bb->ref_page_no) {
 
120
                return(aa->ref_page_no < bb->ref_page_no ? -1 : 1);
 
121
        }
 
122
        if (aa->ref_heap_no != bb->ref_heap_no) {
 
123
                return(aa->ref_heap_no < bb->ref_heap_no ? -1 : 1);
 
124
        }
 
125
        if (aa->ref_field_no != bb->ref_field_no) {
 
126
                return(aa->ref_field_no < bb->ref_field_no ? -1 : 1);
 
127
        }
 
128
        return(0);
 
129
}
 
130
 
 
131
/**************************************************************//**
 
132
Add a reference to an off-page column to the index->blobs map. */
 
133
UNIV_INTERN
 
134
void
 
135
btr_blob_dbg_add_blob(
 
136
/*==================*/
 
137
        const rec_t*    rec,            /*!< in: clustered index record */
 
138
        ulint           field_no,       /*!< in: off-page column number */
 
139
        ulint           page_no,        /*!< in: start page of the column */
 
140
        dict_index_t*   index,          /*!< in/out: index tree */
 
141
        const char*     ctx)            /*!< in: context (for logging) */
 
142
{
 
143
        btr_blob_dbg_t  b;
 
144
        const page_t*   page    = page_align(rec);
 
145
 
 
146
        ut_a(index->blobs);
 
147
 
 
148
        b.blob_page_no = page_no;
 
149
        b.ref_page_no = page_get_page_no(page);
 
150
        b.ref_heap_no = page_rec_get_heap_no(rec);
 
151
        b.ref_field_no = field_no;
 
152
        ut_a(b.ref_field_no >= index->n_uniq);
 
153
        b.always_owner = b.owner = TRUE;
 
154
        b.del = FALSE;
 
155
        ut_a(!rec_get_deleted_flag(rec, page_is_comp(page)));
 
156
        btr_blob_dbg_rbt_insert(index, &b, ctx);
 
157
}
 
158
 
 
159
/**************************************************************//**
 
160
Add to index->blobs any references to off-page columns from a record.
 
161
@return number of references added */
 
162
UNIV_INTERN
 
163
ulint
 
164
btr_blob_dbg_add_rec(
 
165
/*=================*/
 
166
        const rec_t*    rec,    /*!< in: record */
 
167
        dict_index_t*   index,  /*!< in/out: index */
 
168
        const ulint*    offsets,/*!< in: offsets */
 
169
        const char*     ctx)    /*!< in: context (for logging) */
 
170
{
 
171
        ulint           count   = 0;
 
172
        ulint           i;
 
173
        btr_blob_dbg_t  b;
 
174
        ibool           del;
 
175
 
 
176
        ut_ad(rec_offs_validate(rec, index, offsets));
 
177
 
 
178
        if (!rec_offs_any_extern(offsets)) {
 
179
                return(0);
 
180
        }
 
181
 
 
182
        b.ref_page_no = page_get_page_no(page_align(rec));
 
183
        b.ref_heap_no = page_rec_get_heap_no(rec);
 
184
        del = (rec_get_deleted_flag(rec, rec_offs_comp(offsets)) != 0);
 
185
 
 
186
        for (i = 0; i < rec_offs_n_fields(offsets); i++) {
 
187
                if (rec_offs_nth_extern(offsets, i)) {
 
188
                        ulint           len;
 
189
                        const byte*     field_ref = rec_get_nth_field(
 
190
                                rec, offsets, i, &len);
 
191
 
 
192
                        ut_a(len != UNIV_SQL_NULL);
 
193
                        ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
 
194
                        field_ref += len - BTR_EXTERN_FIELD_REF_SIZE;
 
195
 
 
196
                        if (!memcmp(field_ref, field_ref_zero,
 
197
                                    BTR_EXTERN_FIELD_REF_SIZE)) {
 
198
                                /* the column has not been stored yet */
 
199
                                continue;
 
200
                        }
 
201
 
 
202
                        b.ref_field_no = i;
 
203
                        b.blob_page_no = mach_read_from_4(
 
204
                                field_ref + BTR_EXTERN_PAGE_NO);
 
205
                        ut_a(b.ref_field_no >= index->n_uniq);
 
206
                        b.always_owner = b.owner
 
207
                                = !(field_ref[BTR_EXTERN_LEN]
 
208
                                    & BTR_EXTERN_OWNER_FLAG);
 
209
                        b.del = del;
 
210
 
 
211
                        btr_blob_dbg_rbt_insert(index, &b, ctx);
 
212
                        count++;
 
213
                }
 
214
        }
 
215
 
 
216
        return(count);
 
217
}
 
218
 
 
219
/**************************************************************//**
 
220
Display the references to off-page columns.
 
221
This function is to be called from a debugger,
 
222
for example when a breakpoint on ut_dbg_assertion_failed is hit. */
 
223
UNIV_INTERN
 
224
void
 
225
btr_blob_dbg_print(
 
226
/*===============*/
 
227
        const dict_index_t*     index)  /*!< in: index tree */
 
228
{
 
229
        const ib_rbt_node_t*    node;
 
230
 
 
231
        if (!index->blobs) {
 
232
                return;
 
233
        }
 
234
 
 
235
        /* We intentionally do not acquire index->blobs_mutex here.
 
236
        This function is to be called from a debugger, and the caller
 
237
        should make sure that the index->blobs_mutex is held. */
 
238
 
 
239
        for (node = rbt_first(index->blobs);
 
240
             node != NULL; node = rbt_next(index->blobs, node)) {
 
241
                const btr_blob_dbg_t*   b
 
242
                        = rbt_value(btr_blob_dbg_t, node);
 
243
                fprintf(stderr, "%u:%u:%u->%u%s%s%s\n",
 
244
                        b->ref_page_no, b->ref_heap_no, b->ref_field_no,
 
245
                        b->blob_page_no,
 
246
                        b->owner ? "" : "(disowned)",
 
247
                        b->always_owner ? "" : "(has disowned)",
 
248
                        b->del ? "(deleted)" : "");
 
249
        }
 
250
}
 
251
 
 
252
/**************************************************************//**
 
253
Remove from index->blobs any references to off-page columns from a record.
 
254
@return number of references removed */
 
255
UNIV_INTERN
 
256
ulint
 
257
btr_blob_dbg_remove_rec(
 
258
/*====================*/
 
259
        const rec_t*    rec,    /*!< in: record */
 
260
        dict_index_t*   index,  /*!< in/out: index */
 
261
        const ulint*    offsets,/*!< in: offsets */
 
262
        const char*     ctx)    /*!< in: context (for logging) */
 
263
{
 
264
        ulint           i;
 
265
        ulint           count   = 0;
 
266
        btr_blob_dbg_t  b;
 
267
 
 
268
        ut_ad(rec_offs_validate(rec, index, offsets));
 
269
 
 
270
        if (!rec_offs_any_extern(offsets)) {
 
271
                return(0);
 
272
        }
 
273
 
 
274
        b.ref_page_no = page_get_page_no(page_align(rec));
 
275
        b.ref_heap_no = page_rec_get_heap_no(rec);
 
276
 
 
277
        for (i = 0; i < rec_offs_n_fields(offsets); i++) {
 
278
                if (rec_offs_nth_extern(offsets, i)) {
 
279
                        ulint           len;
 
280
                        const byte*     field_ref = rec_get_nth_field(
 
281
                                rec, offsets, i, &len);
 
282
 
 
283
                        ut_a(len != UNIV_SQL_NULL);
 
284
                        ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
 
285
                        field_ref += len - BTR_EXTERN_FIELD_REF_SIZE;
 
286
 
 
287
                        b.ref_field_no = i;
 
288
                        b.blob_page_no = mach_read_from_4(
 
289
                                field_ref + BTR_EXTERN_PAGE_NO);
 
290
 
 
291
                        switch (b.blob_page_no) {
 
292
                        case 0:
 
293
                                /* The column has not been stored yet.
 
294
                                The BLOB pointer must be all zero.
 
295
                                There cannot be a BLOB starting at
 
296
                                page 0, because page 0 is reserved for
 
297
                                the tablespace header. */
 
298
                                ut_a(!memcmp(field_ref, field_ref_zero,
 
299
                                             BTR_EXTERN_FIELD_REF_SIZE));
 
300
                                /* fall through */
 
301
                        case FIL_NULL:
 
302
                                /* the column has been freed already */
 
303
                                continue;
 
304
                        }
 
305
 
 
306
                        btr_blob_dbg_rbt_delete(index, &b, ctx);
 
307
                        count++;
 
308
                }
 
309
        }
 
310
 
 
311
        return(count);
 
312
}
 
313
 
 
314
/**************************************************************//**
 
315
Check that there are no references to off-page columns from or to
 
316
the given page. Invoked when freeing or clearing a page.
 
317
@return TRUE when no orphan references exist */
 
318
UNIV_INTERN
 
319
ibool
 
320
btr_blob_dbg_is_empty(
 
321
/*==================*/
 
322
        dict_index_t*   index,          /*!< in: index */
 
323
        ulint           page_no)        /*!< in: page number */
 
324
{
 
325
        const ib_rbt_node_t*    node;
 
326
        ibool                   success = TRUE;
 
327
 
 
328
        if (!index->blobs) {
 
329
                return(success);
 
330
        }
 
331
 
 
332
        mutex_enter(&index->blobs_mutex);
 
333
 
 
334
        for (node = rbt_first(index->blobs);
 
335
             node != NULL; node = rbt_next(index->blobs, node)) {
 
336
                const btr_blob_dbg_t*   b
 
337
                        = rbt_value(btr_blob_dbg_t, node);
 
338
 
 
339
                if (b->ref_page_no != page_no && b->blob_page_no != page_no) {
 
340
                        continue;
 
341
                }
 
342
 
 
343
                fprintf(stderr,
 
344
                        "InnoDB: orphan BLOB ref%s%s%s %u:%u:%u->%u\n",
 
345
                        b->owner ? "" : "(disowned)",
 
346
                        b->always_owner ? "" : "(has disowned)",
 
347
                        b->del ? "(deleted)" : "",
 
348
                        b->ref_page_no, b->ref_heap_no, b->ref_field_no,
 
349
                        b->blob_page_no);
 
350
 
 
351
                if (b->blob_page_no != page_no || b->owner || !b->del) {
 
352
                        success = FALSE;
 
353
                }
 
354
        }
 
355
 
 
356
        mutex_exit(&index->blobs_mutex);
 
357
        return(success);
 
358
}
 
359
 
 
360
/**************************************************************//**
 
361
Count and process all references to off-page columns on a page.
 
362
@return number of references processed */
 
363
UNIV_INTERN
 
364
ulint
 
365
btr_blob_dbg_op(
 
366
/*============*/
 
367
        const page_t*           page,   /*!< in: B-tree leaf page */
 
368
        const rec_t*            rec,    /*!< in: record to start from
 
369
                                        (NULL to process the whole page) */
 
370
        dict_index_t*           index,  /*!< in/out: index */
 
371
        const char*             ctx,    /*!< in: context (for logging) */
 
372
        const btr_blob_dbg_op_f op)     /*!< in: operation on records */
 
373
{
 
374
        ulint           count   = 0;
 
375
        mem_heap_t*     heap    = NULL;
 
376
        ulint           offsets_[REC_OFFS_NORMAL_SIZE];
 
377
        ulint*          offsets = offsets_;
 
378
        rec_offs_init(offsets_);
 
379
 
 
380
        ut_a(fil_page_get_type(page) == FIL_PAGE_INDEX);
 
381
        ut_a(!rec || page_align(rec) == page);
 
382
 
 
383
        if (!index->blobs || !page_is_leaf(page)
 
384
            || !dict_index_is_clust(index)) {
 
385
                return(0);
 
386
        }
 
387
 
 
388
        if (rec == NULL) {
 
389
                rec = page_get_infimum_rec(page);
 
390
        }
 
391
 
 
392
        do {
 
393
                offsets = rec_get_offsets(rec, index, offsets,
 
394
                                          ULINT_UNDEFINED, &heap);
 
395
                count += op(rec, index, offsets, ctx);
 
396
                rec = page_rec_get_next_const(rec);
 
397
        } while (!page_rec_is_supremum(rec));
 
398
 
 
399
        if (UNIV_LIKELY_NULL(heap)) {
 
400
                mem_heap_free(heap);
 
401
        }
 
402
 
 
403
        return(count);
 
404
}
 
405
 
 
406
/**************************************************************//**
 
407
Count and add to index->blobs any references to off-page columns
 
408
from records on a page.
 
409
@return number of references added */
 
410
UNIV_INTERN
 
411
ulint
 
412
btr_blob_dbg_add(
 
413
/*=============*/
 
414
        const page_t*   page,   /*!< in: rewritten page */
 
415
        dict_index_t*   index,  /*!< in/out: index */
 
416
        const char*     ctx)    /*!< in: context (for logging) */
 
417
{
 
418
        btr_blob_dbg_assert_empty(index, page_get_page_no(page));
 
419
 
 
420
        return(btr_blob_dbg_op(page, NULL, index, ctx, btr_blob_dbg_add_rec));
 
421
}
 
422
 
 
423
/**************************************************************//**
 
424
Count and remove from index->blobs any references to off-page columns
 
425
from records on a page.
 
426
Used when reorganizing a page, before copying the records.
 
427
@return number of references removed */
 
428
UNIV_INTERN
 
429
ulint
 
430
btr_blob_dbg_remove(
 
431
/*================*/
 
432
        const page_t*   page,   /*!< in: b-tree page */
 
433
        dict_index_t*   index,  /*!< in/out: index */
 
434
        const char*     ctx)    /*!< in: context (for logging) */
 
435
{
 
436
        ulint   count;
 
437
 
 
438
        count = btr_blob_dbg_op(page, NULL, index, ctx,
 
439
                                btr_blob_dbg_remove_rec);
 
440
 
 
441
        /* Check that no references exist. */
 
442
        btr_blob_dbg_assert_empty(index, page_get_page_no(page));
 
443
 
 
444
        return(count);
 
445
}
 
446
 
 
447
/**************************************************************//**
 
448
Restore in index->blobs any references to off-page columns
 
449
Used when page reorganize fails due to compressed page overflow. */
 
450
UNIV_INTERN
 
451
void
 
452
btr_blob_dbg_restore(
 
453
/*=================*/
 
454
        const page_t*   npage,  /*!< in: page that failed to compress  */
 
455
        const page_t*   page,   /*!< in: copy of original page */
 
456
        dict_index_t*   index,  /*!< in/out: index */
 
457
        const char*     ctx)    /*!< in: context (for logging) */
 
458
{
 
459
        ulint   removed;
 
460
        ulint   added;
 
461
 
 
462
        ut_a(page_get_page_no(npage) == page_get_page_no(page));
 
463
        ut_a(page_get_space_id(npage) == page_get_space_id(page));
 
464
 
 
465
        removed = btr_blob_dbg_remove(npage, index, ctx);
 
466
        added = btr_blob_dbg_add(page, index, ctx);
 
467
        ut_a(added == removed);
 
468
}
 
469
 
 
470
/**************************************************************//**
 
471
Modify the 'deleted' flag of a record. */
 
472
UNIV_INTERN
 
473
void
 
474
btr_blob_dbg_set_deleted_flag(
 
475
/*==========================*/
 
476
        const rec_t*            rec,    /*!< in: record */
 
477
        dict_index_t*           index,  /*!< in/out: index */
 
478
        const ulint*            offsets,/*!< in: rec_get_offs(rec, index) */
 
479
        ibool                   del)    /*!< in: TRUE=deleted, FALSE=exists */
 
480
{
 
481
        const ib_rbt_node_t*    node;
 
482
        btr_blob_dbg_t          b;
 
483
        btr_blob_dbg_t*         c;
 
484
        ulint                   i;
 
485
 
 
486
        ut_ad(rec_offs_validate(rec, index, offsets));
 
487
        ut_a(dict_index_is_clust(index));
 
488
        ut_a(del == !!del);/* must be FALSE==0 or TRUE==1 */
 
489
 
 
490
        if (!rec_offs_any_extern(offsets) || !index->blobs) {
 
491
 
 
492
                return;
 
493
        }
 
494
 
 
495
        b.ref_page_no = page_get_page_no(page_align(rec));
 
496
        b.ref_heap_no = page_rec_get_heap_no(rec);
 
497
 
 
498
        for (i = 0; i < rec_offs_n_fields(offsets); i++) {
 
499
                if (rec_offs_nth_extern(offsets, i)) {
 
500
                        ulint           len;
 
501
                        const byte*     field_ref = rec_get_nth_field(
 
502
                                rec, offsets, i, &len);
 
503
 
 
504
                        ut_a(len != UNIV_SQL_NULL);
 
505
                        ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
 
506
                        field_ref += len - BTR_EXTERN_FIELD_REF_SIZE;
 
507
 
 
508
                        b.ref_field_no = i;
 
509
                        b.blob_page_no = mach_read_from_4(
 
510
                                field_ref + BTR_EXTERN_PAGE_NO);
 
511
 
 
512
                        switch (b.blob_page_no) {
 
513
                        case 0:
 
514
                                ut_a(memcmp(field_ref, field_ref_zero,
 
515
                                            BTR_EXTERN_FIELD_REF_SIZE));
 
516
                                /* page number 0 is for the
 
517
                                page allocation bitmap */
 
518
                        case FIL_NULL:
 
519
                                /* the column has been freed already */
 
520
                                ut_error;
 
521
                        }
 
522
 
 
523
                        mutex_enter(&index->blobs_mutex);
 
524
                        node = rbt_lookup(index->blobs, &b);
 
525
                        ut_a(node);
 
526
 
 
527
                        c = rbt_value(btr_blob_dbg_t, node);
 
528
                        /* The flag should be modified. */
 
529
                        c->del = del;
 
530
                        if (btr_blob_dbg_msg) {
 
531
                                b = *c;
 
532
                                mutex_exit(&index->blobs_mutex);
 
533
                                btr_blob_dbg_msg_issue("del_mk", &b, "");
 
534
                        } else {
 
535
                                mutex_exit(&index->blobs_mutex);
 
536
                        }
 
537
                }
 
538
        }
 
539
}
 
540
 
 
541
/**************************************************************//**
 
542
Change the ownership of an off-page column. */
 
543
UNIV_INTERN
 
544
void
 
545
btr_blob_dbg_owner(
 
546
/*===============*/
 
547
        const rec_t*            rec,    /*!< in: record */
 
548
        dict_index_t*           index,  /*!< in/out: index */
 
549
        const ulint*            offsets,/*!< in: rec_get_offs(rec, index) */
 
550
        ulint                   i,      /*!< in: ith field in rec */
 
551
        ibool                   own)    /*!< in: TRUE=owned, FALSE=disowned */
 
552
{
 
553
        const ib_rbt_node_t*    node;
 
554
        btr_blob_dbg_t          b;
 
555
        const byte*             field_ref;
 
556
        ulint                   len;
 
557
 
 
558
        ut_ad(rec_offs_validate(rec, index, offsets));
 
559
        ut_a(rec_offs_nth_extern(offsets, i));
 
560
 
 
561
        field_ref = rec_get_nth_field(rec, offsets, i, &len);
 
562
        ut_a(len != UNIV_SQL_NULL);
 
563
        ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
 
564
        field_ref += len - BTR_EXTERN_FIELD_REF_SIZE;
 
565
 
 
566
        b.ref_page_no = page_get_page_no(page_align(rec));
 
567
        b.ref_heap_no = page_rec_get_heap_no(rec);
 
568
        b.ref_field_no = i;
 
569
        b.owner = !(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG);
 
570
        b.blob_page_no = mach_read_from_4(field_ref + BTR_EXTERN_PAGE_NO);
 
571
 
 
572
        ut_a(b.owner == own);
 
573
 
 
574
        mutex_enter(&index->blobs_mutex);
 
575
        node = rbt_lookup(index->blobs, &b);
 
576
        /* row_ins_clust_index_entry_by_modify() invokes
 
577
        btr_cur_unmark_extern_fields() also for the newly inserted
 
578
        references, which are all zero bytes until the columns are stored.
 
579
        The node lookup must fail if and only if that is the case. */
 
580
        ut_a(!memcmp(field_ref, field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE)
 
581
             == !node);
 
582
 
 
583
        if (node) {
 
584
                btr_blob_dbg_t* c = rbt_value(btr_blob_dbg_t, node);
 
585
                /* Some code sets ownership from TRUE to TRUE.
 
586
                We do not allow changing ownership from FALSE to FALSE. */
 
587
                ut_a(own || c->owner);
 
588
 
 
589
                c->owner = own;
 
590
                if (!own) {
 
591
                        c->always_owner = FALSE;
 
592
                }
 
593
        }
 
594
 
 
595
        mutex_exit(&index->blobs_mutex);
 
596
}
 
597
#endif /* UNIV_BLOB_DEBUG */
 
598
 
45
599
/*
46
600
Latching strategy of the InnoDB B-tree
47
601
--------------------------------------
136
690
        zip_size = dict_table_zip_size(index->table);
137
691
        root_page_no = dict_index_get_page(index);
138
692
 
139
 
        block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
 
693
        block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH,
 
694
                              index, mtr);
140
695
        ut_a((ibool)!!page_is_comp(buf_block_get_frame(block))
141
696
             == dict_table_is_comp(index->table));
142
697
#ifdef UNIV_BTR_DEBUG
296
851
        page_t*         page = buf_block_get_frame(block);
297
852
 
298
853
        ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
 
854
        btr_blob_dbg_assert_empty(index, buf_block_get_page_no(block));
299
855
 
300
856
        if (UNIV_LIKELY_NULL(page_zip)) {
301
857
                page_create_zip(block, index, level, mtr);
336
892
                                 dict_table_zip_size(index->table),
337
893
                                 node_addr.page, RW_X_LATCH, mtr);
338
894
        new_page = buf_block_get_frame(new_block);
339
 
        buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW);
 
895
        buf_block_dbg_add_level(new_block, SYNC_IBUF_TREE_NODE_NEW);
340
896
 
341
897
        flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
342
898
                    new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE,
489
1045
        modify clock */
490
1046
 
491
1047
        buf_block_modify_clock_inc(block);
 
1048
        btr_blob_dbg_assert_empty(index, buf_block_get_page_no(block));
492
1049
 
493
1050
        if (dict_index_is_ibuf(index)) {
494
1051
 
508
1065
        fseg_free_page(seg_header,
509
1066
                       buf_block_get_space(block),
510
1067
                       buf_block_get_page_no(block), mtr);
 
1068
 
 
1069
        /* The page was marked free in the allocation bitmap, but it
 
1070
        should remain buffer-fixed until mtr_commit(mtr) or until it
 
1071
        is explicitly freed from the mini-transaction. */
 
1072
        ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
 
1073
        /* TODO: Discard any operations on the page from the redo log
 
1074
        and remove the block from the flush list and the buffer pool.
 
1075
        This would free up buffer pool earlier and reduce writes to
 
1076
        both the tablespace and the redo log. */
511
1077
}
512
1078
 
513
1079
/**************************************************************//**
583
1149
        page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
584
1150
 
585
1151
        return(btr_block_get(space, dict_table_zip_size(index->table),
586
 
                             page_no, RW_X_LATCH, mtr));
 
1152
                             page_no, RW_X_LATCH, index, mtr));
587
1153
}
588
1154
 
589
1155
/************************************************************//**
592
1158
@return rec_get_offsets() of the node pointer record */
593
1159
static
594
1160
ulint*
595
 
btr_page_get_father_node_ptr(
596
 
/*=========================*/
 
1161
btr_page_get_father_node_ptr_func(
 
1162
/*==============================*/
597
1163
        ulint*          offsets,/*!< in: work area for the return value */
598
1164
        mem_heap_t*     heap,   /*!< in: memory heap to use */
599
1165
        btr_cur_t*      cursor, /*!< in: cursor pointing to user record,
600
1166
                                out: cursor on node pointer record,
601
1167
                                its page x-latched */
 
1168
        const char*     file,   /*!< in: file name */
 
1169
        ulint           line,   /*!< in: line where called */
602
1170
        mtr_t*          mtr)    /*!< in: mtr */
603
1171
{
604
1172
        dtuple_t*       tuple;
622
1190
        tuple = dict_index_build_node_ptr(index, user_rec, 0, heap, level);
623
1191
 
624
1192
        btr_cur_search_to_nth_level(index, level + 1, tuple, PAGE_CUR_LE,
625
 
                                    BTR_CONT_MODIFY_TREE, cursor, 0, mtr);
 
1193
                                    BTR_CONT_MODIFY_TREE, cursor, 0,
 
1194
                                    file, line, mtr);
626
1195
 
627
1196
        node_ptr = btr_cur_get_rec(cursor);
628
1197
        ut_ad(!page_rec_is_comp(node_ptr)
660
1229
                      " to fix the\n"
661
1230
                      "InnoDB: corruption. If the crash happens at "
662
1231
                      "the database startup, see\n"
663
 
                      "InnoDB: " REFMAN "forcing-recovery.html about\n"
 
1232
                      "InnoDB: " REFMAN "forcing-innodb-recovery.html about\n"
664
1233
                      "InnoDB: forcing recovery. "
665
1234
                      "Then dump + drop + reimport.\n", stderr);
666
1235
 
670
1239
        return(offsets);
671
1240
}
672
1241
 
 
1242
#define btr_page_get_father_node_ptr(of,heap,cur,mtr)                   \
 
1243
        btr_page_get_father_node_ptr_func(of,heap,cur,__FILE__,__LINE__,mtr)
 
1244
 
673
1245
/************************************************************//**
674
1246
Returns the upper level node pointer to a page. It is assumed that mtr holds
675
1247
an x-latch on the tree.
749
1321
                        space, 0,
750
1322
                        IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr);
751
1323
 
752
 
                buf_block_dbg_add_level(ibuf_hdr_block, SYNC_TREE_NODE_NEW);
 
1324
                buf_block_dbg_add_level(
 
1325
                        ibuf_hdr_block, SYNC_IBUF_TREE_NODE_NEW);
753
1326
 
754
1327
                ut_ad(buf_block_get_page_no(ibuf_hdr_block)
755
1328
                      == IBUF_HEADER_PAGE_NO);
767
1340
                block = buf_page_get(space, zip_size, page_no,
768
1341
                                     RW_X_LATCH, mtr);
769
1342
        } else {
 
1343
#ifdef UNIV_BLOB_DEBUG
 
1344
                if ((type & DICT_CLUSTERED) && !index->blobs) {
 
1345
                        mutex_create(&index->blobs_mutex, SYNC_ANY_LATCH);
 
1346
                        index->blobs = rbt_create(sizeof(btr_blob_dbg_t),
 
1347
                                                  btr_blob_dbg_cmp);
 
1348
                }
 
1349
#endif /* UNIV_BLOB_DEBUG */
770
1350
                block = fseg_create(space, 0,
771
1351
                                    PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr);
772
1352
        }
779
1359
        page_no = buf_block_get_page_no(block);
780
1360
        frame = buf_block_get_frame(block);
781
1361
 
782
 
        buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
783
 
 
784
1362
        if (type & DICT_IBUF) {
785
1363
                /* It is an insert buffer tree: initialize the free list */
 
1364
                buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW);
786
1365
 
787
1366
                ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
788
1367
 
790
1369
        } else {
791
1370
                /* It is a non-ibuf tree: create a file segment for leaf
792
1371
                pages */
793
 
                fseg_create(space, page_no,
794
 
                            PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr);
 
1372
                buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
 
1373
 
 
1374
                if (!fseg_create(space, page_no,
 
1375
                                 PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr)) {
 
1376
                        /* Not enough space for new segment, free root
 
1377
                        segment before return. */
 
1378
                        btr_free_root(space, zip_size, page_no, mtr);
 
1379
 
 
1380
                        return(FIL_NULL);
 
1381
                }
 
1382
 
795
1383
                /* The fseg create acquires a second latch on the page,
796
1384
                therefore we must declare it: */
797
1385
                buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
854
1442
leaf_loop:
855
1443
        mtr_start(&mtr);
856
1444
 
857
 
        root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr);
 
1445
        root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH,
 
1446
                            NULL, &mtr);
858
1447
#ifdef UNIV_BTR_DEBUG
859
1448
        ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
860
1449
                                    + root, space));
876
1465
top_loop:
877
1466
        mtr_start(&mtr);
878
1467
 
879
 
        root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr);
 
1468
        root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH,
 
1469
                            NULL, &mtr);
880
1470
#ifdef UNIV_BTR_DEBUG
881
1471
        ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
882
1472
                                    + root, space));
902
1492
        ulint   zip_size,       /*!< in: compressed page size in bytes
903
1493
                                or 0 for uncompressed pages */
904
1494
        ulint   root_page_no,   /*!< in: root page number */
905
 
        mtr_t*  mtr)            /*!< in: a mini-transaction which has already
906
 
                                been started */
 
1495
        mtr_t*  mtr)            /*!< in/out: mini-transaction */
907
1496
{
908
1497
        buf_block_t*    block;
909
1498
        fseg_header_t*  header;
910
1499
 
911
 
        block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
 
1500
        block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH,
 
1501
                              NULL, mtr);
912
1502
 
913
1503
        btr_search_drop_page_hash_index(block);
914
1504
 
966
1556
        log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
967
1557
 
968
1558
#ifndef UNIV_HOTBACKUP
969
 
        temp_block = buf_block_alloc(0);
 
1559
        temp_block = buf_block_alloc();
970
1560
#else /* !UNIV_HOTBACKUP */
971
1561
        ut_ad(block == back_block1);
972
1562
        temp_block = back_block2;
983
1573
 
984
1574
        block->check_index_page_at_flush = TRUE;
985
1575
#endif /* !UNIV_HOTBACKUP */
 
1576
        btr_blob_dbg_remove(page, index, "btr_page_reorganize");
986
1577
 
987
1578
        /* Recreate the page: note that global data on page (possible
988
1579
        segment headers, next page-field, etc.) is preserved intact */
1011
1602
            (!page_zip_compress(page_zip, page, index, NULL))) {
1012
1603
 
1013
1604
                /* Restore the old page and exit. */
 
1605
                btr_blob_dbg_restore(page, temp_page, index,
 
1606
                                     "btr_page_reorganize_compress_fail");
1014
1607
 
1015
1608
#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
1016
1609
                /* Check that the bytes that we skip are identical. */
1144
1737
#endif /* UNIV_ZIP_DEBUG */
1145
1738
 
1146
1739
        btr_search_drop_page_hash_index(block);
 
1740
        btr_blob_dbg_remove(page, index, "btr_page_empty");
1147
1741
 
1148
1742
        /* Recreate the page: note that global data on page (possible
1149
1743
        segment headers, next page-field, etc.) is preserved intact */
1438
2032
its half-page when the split is performed. We assume in this function
1439
2033
only that the cursor page has at least one user record.
1440
2034
@return split record, or NULL if tuple will be the first record on
1441
 
upper half-page */
 
2035
the lower or upper half-page (determined by btr_page_tuple_smaller()) */
1442
2036
static
1443
2037
rec_t*
1444
 
btr_page_get_sure_split_rec(
1445
 
/*========================*/
 
2038
btr_page_get_split_rec(
 
2039
/*===================*/
1446
2040
        btr_cur_t*      cursor, /*!< in: cursor at which insert should be made */
1447
2041
        const dtuple_t* tuple,  /*!< in: tuple to insert */
1448
2042
        ulint           n_ext)  /*!< in: number of externally stored columns */
1655
2249
that mtr holds an x-latch on the tree. */
1656
2250
UNIV_INTERN
1657
2251
void
1658
 
btr_insert_on_non_leaf_level(
1659
 
/*=========================*/
 
2252
btr_insert_on_non_leaf_level_func(
 
2253
/*==============================*/
1660
2254
        dict_index_t*   index,  /*!< in: index */
1661
2255
        ulint           level,  /*!< in: level, must be > 0 */
1662
2256
        dtuple_t*       tuple,  /*!< in: the record to be inserted */
 
2257
        const char*     file,   /*!< in: file name */
 
2258
        ulint           line,   /*!< in: line where called */
1663
2259
        mtr_t*          mtr)    /*!< in: mtr */
1664
2260
{
1665
2261
        big_rec_t*      dummy_big_rec;
1671
2267
 
1672
2268
        btr_cur_search_to_nth_level(index, level, tuple, PAGE_CUR_LE,
1673
2269
                                    BTR_CONT_MODIFY_TREE,
1674
 
                                    &cursor, 0, mtr);
 
2270
                                    &cursor, 0, file, line, mtr);
1675
2271
 
1676
2272
        err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG
1677
2273
                                         | BTR_KEEP_SYS_FLAG
1690
2286
/*==================*/
1691
2287
        dict_index_t*   index,          /*!< in: the index tree */
1692
2288
        buf_block_t*    block,          /*!< in/out: page to be split */
1693
 
        rec_t*          split_rec,      /*!< in: first record on upper
 
2289
        const rec_t*    split_rec,      /*!< in: first record on upper
1694
2290
                                        half page */
1695
2291
        buf_block_t*    new_block,      /*!< in/out: the new half page */
1696
2292
        ulint           direction,      /*!< in: FSP_UP or FSP_DOWN */
1780
2376
        /* Update page links of the level */
1781
2377
 
1782
2378
        if (prev_page_no != FIL_NULL) {
1783
 
                buf_block_t*    prev_block = btr_block_get(space, zip_size,
1784
 
                                                           prev_page_no,
1785
 
                                                           RW_X_LATCH, mtr);
 
2379
                buf_block_t*    prev_block = btr_block_get(
 
2380
                        space, zip_size, prev_page_no, RW_X_LATCH, index, mtr);
1786
2381
#ifdef UNIV_BTR_DEBUG
1787
2382
                ut_a(page_is_comp(prev_block->frame) == page_is_comp(page));
1788
2383
                ut_a(btr_page_get_next(prev_block->frame, mtr)
1795
2390
        }
1796
2391
 
1797
2392
        if (next_page_no != FIL_NULL) {
1798
 
                buf_block_t*    next_block = btr_block_get(space, zip_size,
1799
 
                                                           next_page_no,
1800
 
                                                           RW_X_LATCH, mtr);
 
2393
                buf_block_t*    next_block = btr_block_get(
 
2394
                        space, zip_size, next_page_no, RW_X_LATCH, index, mtr);
1801
2395
#ifdef UNIV_BTR_DEBUG
1802
2396
                ut_a(page_is_comp(next_block->frame) == page_is_comp(page));
1803
2397
                ut_a(btr_page_get_prev(next_block->frame, mtr)
1817
2411
}
1818
2412
 
1819
2413
/*************************************************************//**
 
2414
Determine if a tuple is smaller than any record on the page.
 
2415
@return TRUE if smaller */
 
2416
static
 
2417
ibool
 
2418
btr_page_tuple_smaller(
 
2419
/*===================*/
 
2420
        btr_cur_t*      cursor, /*!< in: b-tree cursor */
 
2421
        const dtuple_t* tuple,  /*!< in: tuple to consider */
 
2422
        ulint*          offsets,/*!< in/out: temporary storage */
 
2423
        ulint           n_uniq, /*!< in: number of unique fields
 
2424
                                in the index page records */
 
2425
        mem_heap_t**    heap)   /*!< in/out: heap for offsets */
 
2426
{
 
2427
        buf_block_t*    block;
 
2428
        const rec_t*    first_rec;
 
2429
        page_cur_t      pcur;
 
2430
 
 
2431
        /* Read the first user record in the page. */
 
2432
        block = btr_cur_get_block(cursor);
 
2433
        page_cur_set_before_first(block, &pcur);
 
2434
        page_cur_move_to_next(&pcur);
 
2435
        first_rec = page_cur_get_rec(&pcur);
 
2436
 
 
2437
        offsets = rec_get_offsets(
 
2438
                first_rec, cursor->index, offsets,
 
2439
                n_uniq, heap);
 
2440
 
 
2441
        return(cmp_dtuple_rec(tuple, first_rec, offsets) < 0);
 
2442
}
 
2443
 
 
2444
/*************************************************************//**
1820
2445
Splits an index page to halves and inserts the tuple. It is assumed
1821
2446
that mtr holds an x-latch to the index tree. NOTE: the tree x-latch is
1822
2447
released within this function! NOTE that the operation of this
1849
2474
        buf_block_t*    left_block;
1850
2475
        buf_block_t*    right_block;
1851
2476
        buf_block_t*    insert_block;
1852
 
        page_t*         insert_page;
1853
2477
        page_cur_t*     page_cursor;
1854
2478
        rec_t*          first_rec;
1855
2479
        byte*           buf = 0; /* remove warning */
1886
2510
        /* 1. Decide the split record; split_rec == NULL means that the
1887
2511
        tuple to be inserted should be the first record on the upper
1888
2512
        half-page */
 
2513
        insert_left = FALSE;
1889
2514
 
1890
2515
        if (n_iterations > 0) {
1891
2516
                direction = FSP_UP;
1892
2517
                hint_page_no = page_no + 1;
1893
 
                split_rec = btr_page_get_sure_split_rec(cursor, tuple, n_ext);
 
2518
                split_rec = btr_page_get_split_rec(cursor, tuple, n_ext);
1894
2519
 
 
2520
                if (UNIV_UNLIKELY(split_rec == NULL)) {
 
2521
                        insert_left = btr_page_tuple_smaller(
 
2522
                                cursor, tuple, offsets, n_uniq, &heap);
 
2523
                }
1895
2524
        } else if (btr_page_get_split_rec_to_right(cursor, &split_rec)) {
1896
2525
                direction = FSP_UP;
1897
2526
                hint_page_no = page_no + 1;
1899
2528
        } else if (btr_page_get_split_rec_to_left(cursor, &split_rec)) {
1900
2529
                direction = FSP_DOWN;
1901
2530
                hint_page_no = page_no - 1;
 
2531
                ut_ad(split_rec);
1902
2532
        } else {
1903
2533
                direction = FSP_UP;
1904
2534
                hint_page_no = page_no + 1;
1905
2535
 
1906
 
                if (page_get_n_recs(page) == 1) {
1907
 
                        page_cur_t      pcur;
1908
 
 
1909
 
                        /* There is only one record in the index page
1910
 
                        therefore we can't split the node in the middle
1911
 
                        by default. We need to determine whether the
1912
 
                        new record will be inserted to the left or right. */
1913
 
 
1914
 
                        /* Read the first (and only) record in the page. */
1915
 
                        page_cur_set_before_first(block, &pcur);
1916
 
                        page_cur_move_to_next(&pcur);
1917
 
                        first_rec = page_cur_get_rec(&pcur);
1918
 
 
1919
 
                        offsets = rec_get_offsets(
1920
 
                                first_rec, cursor->index, offsets,
1921
 
                                n_uniq, &heap);
1922
 
 
1923
 
                        /* If the new record is less than the existing record
1924
 
                        the split in the middle will copy the existing
1925
 
                        record to the new node. */
1926
 
                        if (cmp_dtuple_rec(tuple, first_rec, offsets) < 0) {
1927
 
                                split_rec = page_get_middle_rec(page);
1928
 
                        } else {
1929
 
                                split_rec = NULL;
1930
 
                        }
1931
 
                } else {
 
2536
                /* If there is only one record in the index page, we
 
2537
                can't split the node in the middle by default. We need
 
2538
                to determine whether the new record will be inserted
 
2539
                to the left or right. */
 
2540
 
 
2541
                if (page_get_n_recs(page) > 1) {
1932
2542
                        split_rec = page_get_middle_rec(page);
 
2543
                } else if (btr_page_tuple_smaller(cursor, tuple,
 
2544
                                                  offsets, n_uniq, &heap)) {
 
2545
                        split_rec = page_rec_get_next(
 
2546
                                page_get_infimum_rec(page));
 
2547
                } else {
 
2548
                        split_rec = NULL;
1933
2549
                }
1934
2550
        }
1935
2551
 
1959
2575
                        avoid further splits by inserting the record
1960
2576
                        to an empty page. */
1961
2577
                        split_rec = NULL;
1962
 
                        goto insert_right;
 
2578
                        goto insert_empty;
1963
2579
                }
 
2580
        } else if (UNIV_UNLIKELY(insert_left)) {
 
2581
                ut_a(n_iterations > 0);
 
2582
                first_rec = page_rec_get_next(page_get_infimum_rec(page));
 
2583
                move_limit = page_rec_get_next(btr_cur_get_rec(cursor));
1964
2584
        } else {
1965
 
insert_right:
1966
 
                insert_left = FALSE;
 
2585
insert_empty:
 
2586
                ut_ad(!split_rec);
 
2587
                ut_ad(!insert_left);
1967
2588
                buf = mem_alloc(rec_get_converted_size(cursor->index,
1968
2589
                                                       tuple, n_ext));
1969
2590
 
1987
2608
                        && btr_page_insert_fits(cursor, split_rec,
1988
2609
                                                offsets, tuple, n_ext, heap);
1989
2610
        } else {
1990
 
                mem_free(buf);
 
2611
                if (!insert_left) {
 
2612
                        mem_free(buf);
 
2613
                        buf = NULL;
 
2614
                }
 
2615
 
1991
2616
                insert_will_fit = !new_page_zip
1992
2617
                        && btr_page_insert_fits(cursor, NULL,
1993
2618
                                                NULL, tuple, n_ext, heap);
2106
2731
                insert_block = right_block;
2107
2732
        }
2108
2733
 
2109
 
        insert_page = buf_block_get_frame(insert_block);
2110
 
 
2111
2734
        /* 7. Reposition the cursor for insert and try insertion */
2112
2735
        page_cursor = btr_cur_get_page_cur(cursor);
2113
2736
 
2119
2742
 
2120
2743
#ifdef UNIV_ZIP_DEBUG
2121
2744
        {
 
2745
                page_t*         insert_page
 
2746
                        = buf_block_get_frame(insert_block);
 
2747
 
2122
2748
                page_zip_des_t* insert_page_zip
2123
2749
                        = buf_block_get_page_zip(insert_block);
 
2750
 
2124
2751
                ut_a(!insert_page_zip
2125
2752
                     || page_zip_validate(insert_page_zip, insert_page));
2126
2753
        }
2186
2813
        return(rec);
2187
2814
}
2188
2815
 
 
2816
#ifdef UNIV_SYNC_DEBUG
 
2817
/*************************************************************//**
 
2818
Removes a page from the level list of pages.
 
2819
@param space    in: space where removed
 
2820
@param zip_size in: compressed page size in bytes, or 0 for uncompressed
 
2821
@param page     in/out: page to remove
 
2822
@param index    in: index tree
 
2823
@param mtr      in/out: mini-transaction */
 
2824
# define btr_level_list_remove(space,zip_size,page,index,mtr)           \
 
2825
        btr_level_list_remove_func(space,zip_size,page,index,mtr)
 
2826
#else /* UNIV_SYNC_DEBUG */
 
2827
/*************************************************************//**
 
2828
Removes a page from the level list of pages.
 
2829
@param space    in: space where removed
 
2830
@param zip_size in: compressed page size in bytes, or 0 for uncompressed
 
2831
@param page     in/out: page to remove
 
2832
@param index    in: index tree
 
2833
@param mtr      in/out: mini-transaction */
 
2834
# define btr_level_list_remove(space,zip_size,page,index,mtr)           \
 
2835
        btr_level_list_remove_func(space,zip_size,page,mtr)
 
2836
#endif /* UNIV_SYNC_DEBUG */
 
2837
 
2189
2838
/*************************************************************//**
2190
2839
Removes a page from the level list of pages. */
2191
 
static
 
2840
static __attribute__((nonnull))
2192
2841
void
2193
 
btr_level_list_remove(
2194
 
/*==================*/
2195
 
        ulint           space,  /*!< in: space where removed */
2196
 
        ulint           zip_size,/*!< in: compressed page size in bytes
2197
 
                                or 0 for uncompressed pages */
2198
 
        page_t*         page,   /*!< in: page to remove */
2199
 
        mtr_t*          mtr)    /*!< in: mtr */
 
2842
btr_level_list_remove_func(
 
2843
/*=======================*/
 
2844
        ulint                   space,  /*!< in: space where removed */
 
2845
        ulint                   zip_size,/*!< in: compressed page size in bytes
 
2846
                                        or 0 for uncompressed pages */
 
2847
        page_t*                 page,   /*!< in/out: page to remove */
 
2848
#ifdef UNIV_SYNC_DEBUG
 
2849
        const dict_index_t*     index,  /*!< in: index tree */
 
2850
#endif /* UNIV_SYNC_DEBUG */
 
2851
        mtr_t*                  mtr)    /*!< in/out: mini-transaction */
2200
2852
{
2201
2853
        ulint   prev_page_no;
2202
2854
        ulint   next_page_no;
2214
2866
        if (prev_page_no != FIL_NULL) {
2215
2867
                buf_block_t*    prev_block
2216
2868
                        = btr_block_get(space, zip_size, prev_page_no,
2217
 
                                        RW_X_LATCH, mtr);
 
2869
                                        RW_X_LATCH, index, mtr);
2218
2870
                page_t*         prev_page
2219
2871
                        = buf_block_get_frame(prev_block);
2220
2872
#ifdef UNIV_BTR_DEBUG
2231
2883
        if (next_page_no != FIL_NULL) {
2232
2884
                buf_block_t*    next_block
2233
2885
                        = btr_block_get(space, zip_size, next_page_no,
2234
 
                                        RW_X_LATCH, mtr);
 
2886
                                        RW_X_LATCH, index, mtr);
2235
2887
                page_t*         next_page
2236
2888
                        = buf_block_get_frame(next_block);
2237
2889
#ifdef UNIV_BTR_DEBUG
2449
3101
                                                       index);
2450
3102
        }
2451
3103
 
 
3104
        btr_blob_dbg_remove(page, index, "btr_lift_page_up");
2452
3105
        lock_update_copy_and_discard(father_block, block);
2453
3106
 
2454
3107
        /* Go upward to root page, decrementing levels by one. */
2513
3166
        ulint           n_recs;
2514
3167
        ulint           max_ins_size;
2515
3168
        ulint           max_ins_size_reorg;
2516
 
        ulint           level;
2517
3169
 
2518
3170
        block = btr_cur_get_block(cursor);
2519
3171
        page = btr_cur_get_page(cursor);
2523
3175
        ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
2524
3176
                                MTR_MEMO_X_LOCK));
2525
3177
        ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
2526
 
        level = btr_page_get_level(page, mtr);
2527
3178
        space = dict_index_get_space(index);
2528
3179
        zip_size = dict_table_zip_size(index->table);
2529
3180
 
2547
3198
        if (is_left) {
2548
3199
 
2549
3200
                merge_block = btr_block_get(space, zip_size, left_page_no,
2550
 
                                            RW_X_LATCH, mtr);
 
3201
                                            RW_X_LATCH, index, mtr);
2551
3202
                merge_page = buf_block_get_frame(merge_block);
2552
3203
#ifdef UNIV_BTR_DEBUG
2553
3204
                ut_a(btr_page_get_next(merge_page, mtr)
2556
3207
        } else if (right_page_no != FIL_NULL) {
2557
3208
 
2558
3209
                merge_block = btr_block_get(space, zip_size, right_page_no,
2559
 
                                            RW_X_LATCH, mtr);
 
3210
                                            RW_X_LATCH, index, mtr);
2560
3211
                merge_page = buf_block_get_frame(merge_block);
2561
3212
#ifdef UNIV_BTR_DEBUG
2562
3213
                ut_a(btr_page_get_prev(merge_page, mtr)
2645
3296
                btr_search_drop_page_hash_index(block);
2646
3297
 
2647
3298
                /* Remove the page from the level list */
2648
 
                btr_level_list_remove(space, zip_size, page, mtr);
 
3299
                btr_level_list_remove(space, zip_size, page, index, mtr);
2649
3300
 
2650
3301
                btr_node_ptr_delete(index, block, mtr);
2651
3302
                lock_update_merge_left(merge_block, orig_pred, block);
2698
3349
#endif /* UNIV_BTR_DEBUG */
2699
3350
 
2700
3351
                /* Remove the page from the level list */
2701
 
                btr_level_list_remove(space, zip_size, page, mtr);
 
3352
                btr_level_list_remove(space, zip_size, page, index, mtr);
2702
3353
 
2703
3354
                /* Replace the address of the old child node (= page) with the
2704
3355
                address of the merge page to the right */
2712
3363
                lock_update_merge_right(merge_block, orig_succ, block);
2713
3364
        }
2714
3365
 
 
3366
        btr_blob_dbg_remove(page, index, "btr_compress");
2715
3367
        mem_heap_free(heap);
2716
3368
 
2717
3369
        if (!dict_index_is_clust(index) && page_is_leaf(merge_page)) {
2880
3532
 
2881
3533
        if (left_page_no != FIL_NULL) {
2882
3534
                merge_block = btr_block_get(space, zip_size, left_page_no,
2883
 
                                            RW_X_LATCH, mtr);
 
3535
                                            RW_X_LATCH, index, mtr);
2884
3536
                merge_page = buf_block_get_frame(merge_block);
2885
3537
#ifdef UNIV_BTR_DEBUG
2886
3538
                ut_a(btr_page_get_next(merge_page, mtr)
2888
3540
#endif /* UNIV_BTR_DEBUG */
2889
3541
        } else if (right_page_no != FIL_NULL) {
2890
3542
                merge_block = btr_block_get(space, zip_size, right_page_no,
2891
 
                                            RW_X_LATCH, mtr);
 
3543
                                            RW_X_LATCH, index, mtr);
2892
3544
                merge_page = buf_block_get_frame(merge_block);
2893
3545
#ifdef UNIV_BTR_DEBUG
2894
3546
                ut_a(btr_page_get_prev(merge_page, mtr)
2923
3575
        btr_node_ptr_delete(index, block, mtr);
2924
3576
 
2925
3577
        /* Remove the page from the level list */
2926
 
        btr_level_list_remove(space, zip_size, page, mtr);
 
3578
        btr_level_list_remove(space, zip_size, page, index, mtr);
2927
3579
#ifdef UNIV_ZIP_DEBUG
2928
3580
        {
2929
3581
                page_zip_des_t* merge_page_zip
2942
3594
                                    block);
2943
3595
        }
2944
3596
 
 
3597
        btr_blob_dbg_remove(page, index, "btr_discard_page");
 
3598
 
2945
3599
        /* Free the file page */
2946
3600
        btr_page_free(index, block, mtr);
2947
3601
 
3439
4093
        if (right_page_no != FIL_NULL) {
3440
4094
                const rec_t*    right_rec;
3441
4095
                right_block = btr_block_get(space, zip_size, right_page_no,
3442
 
                                            RW_X_LATCH, &mtr);
 
4096
                                            RW_X_LATCH, index, &mtr);
3443
4097
                right_page = buf_block_get_frame(right_block);
3444
4098
                if (UNIV_UNLIKELY(btr_page_get_prev(right_page, &mtr)
3445
4099
                                  != page_get_page_no(page))) {
3665
4319
                mtr_start(&mtr);
3666
4320
 
3667
4321
                block = btr_block_get(space, zip_size, right_page_no,
3668
 
                                      RW_X_LATCH, &mtr);
 
4322
                                      RW_X_LATCH, index, &mtr);
3669
4323
                page = buf_block_get_frame(block);
3670
4324
 
3671
4325
                goto loop;