📄 page0page.c
字号:
sum_owned + page_dir_slot_get_n_owned(slot)); /* 3. Destroy start and other slots by copying slots */ for (i = start + n; i < n_slots; i++) { slot = page_dir_get_nth_slot(page, i); rec = page_dir_slot_get_rec(slot); slot = page_dir_get_nth_slot(page, i - n); page_dir_slot_set_rec(slot, rec); } /* 4. Update the page header */ page_header_set_field(page, PAGE_N_DIR_SLOTS, n_slots - n);}/******************************************************************Used to add n slots to the directory. Does not set the record pointersin the added slots or update n_owned values: this is the responsibilityof the caller. */UNIV_INLINEvoidpage_dir_add_slots(/*===============*/ page_t* page, /* in: the index page */ ulint start, /* in: the slot above which the new slots are added */ ulint n) /* in: number of slots to add (currently only n == 1 allowed) */{ page_dir_slot_t* slot; ulint n_slots; ulint i; rec_t* rec; ut_ad(n == 1); n_slots = page_dir_get_n_slots(page); ut_ad(start < n_slots - 1); /* Update the page header */ page_dir_set_n_slots(page, n_slots + n); /* Move slots up */ for (i = n_slots - 1; i > start; i--) { slot = page_dir_get_nth_slot(page, i); rec = page_dir_slot_get_rec(slot); slot = page_dir_get_nth_slot(page, i + n); page_dir_slot_set_rec(slot, rec); }}/********************************************************************Splits a directory slot which owns too many records. */voidpage_dir_split_slot(/*================*/ page_t* page, /* in: the index page in question */ ulint slot_no) /* in: the directory slot */{ rec_t* rec; page_dir_slot_t* new_slot; page_dir_slot_t* prev_slot; page_dir_slot_t* slot; ulint i; ulint n_owned; ut_ad(page); ut_ad(slot_no > 0); slot = page_dir_get_nth_slot(page, slot_no); n_owned = page_dir_slot_get_n_owned(slot); ut_ad(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED + 1); /* 1. We loop to find a record approximately in the middle of the records owned by the slot. */ prev_slot = page_dir_get_nth_slot(page, slot_no - 1); rec = page_dir_slot_get_rec(prev_slot); for (i = 0; i < n_owned / 2; i++) { rec = page_rec_get_next(rec); } ut_ad(n_owned / 2 >= PAGE_DIR_SLOT_MIN_N_OWNED); /* 2. We add one directory slot immediately below the slot to be split. */ page_dir_add_slots(page, slot_no - 1, 1); /* The added slot is now number slot_no, and the old slot is now number slot_no + 1 */ new_slot = page_dir_get_nth_slot(page, slot_no); slot = page_dir_get_nth_slot(page, slot_no + 1); /* 3. We store the appropriate values to the new slot. */ page_dir_slot_set_rec(new_slot, rec); page_dir_slot_set_n_owned(new_slot, n_owned / 2); /* 4. Finally, we update the number of records field of the original slot */ page_dir_slot_set_n_owned(slot, n_owned - (n_owned / 2));}/*****************************************************************Tries to balance the given directory slot with too few records with the upperneighbor, so that there are at least the minimum number of records owned bythe slot; this may result in the merging of two slots. */voidpage_dir_balance_slot(/*==================*/ page_t* page, /* in: index page */ ulint slot_no) /* in: the directory slot */{ page_dir_slot_t* slot; page_dir_slot_t* up_slot; ulint n_owned; ulint up_n_owned; rec_t* old_rec; rec_t* new_rec; ut_ad(page); ut_ad(slot_no > 0); slot = page_dir_get_nth_slot(page, slot_no); /* The last directory slot cannot be balanced with the upper neighbor, as there is none. */ if (slot_no == page_dir_get_n_slots(page) - 1) { return; } up_slot = page_dir_get_nth_slot(page, slot_no + 1); n_owned = page_dir_slot_get_n_owned(slot); up_n_owned = page_dir_slot_get_n_owned(up_slot); ut_ad(n_owned == PAGE_DIR_SLOT_MIN_N_OWNED - 1); /* If the upper slot has the minimum value of n_owned, we will merge the two slots, therefore we assert: */ ut_ad(2 * PAGE_DIR_SLOT_MIN_N_OWNED - 1 <= PAGE_DIR_SLOT_MAX_N_OWNED); if (up_n_owned > PAGE_DIR_SLOT_MIN_N_OWNED) { /* In this case we can just transfer one record owned by the upper slot to the property of the lower slot */ old_rec = page_dir_slot_get_rec(slot); new_rec = page_rec_get_next(old_rec); rec_set_n_owned(old_rec, page_is_comp(page), 0); rec_set_n_owned(new_rec, page_is_comp(page), n_owned + 1); page_dir_slot_set_rec(slot, new_rec); page_dir_slot_set_n_owned(up_slot, up_n_owned -1); } else { /* In this case we may merge the two slots */ page_dir_delete_slots(page, slot_no, 1); } }/****************************************************************Returns the middle record of the record list. If there are an even numberof records in the list, returns the first record of the upper half-list. */rec_t*page_get_middle_rec(/*================*/ /* out: middle record */ page_t* page) /* in: page */{ page_dir_slot_t* slot; ulint middle; ulint i; ulint n_owned; ulint count; rec_t* rec; /* This many records we must leave behind */ middle = (page_get_n_recs(page) + 2) / 2; count = 0; for (i = 0;; i++) { slot = page_dir_get_nth_slot(page, i); n_owned = page_dir_slot_get_n_owned(slot); if (count + n_owned > middle) { break; } else { count += n_owned; } } ut_ad(i > 0); slot = page_dir_get_nth_slot(page, i - 1); rec = page_dir_slot_get_rec(slot); rec = page_rec_get_next(rec); /* There are now count records behind rec */ for (i = 0; i < middle - count; i++) { rec = page_rec_get_next(rec); } return(rec);} /*******************************************************************Returns the number of records before the given record in chain.The number includes infimum and supremum records. */ulintpage_rec_get_n_recs_before(/*=======================*/ /* out: number of records */ rec_t* rec) /* in: the physical record */{ page_dir_slot_t* slot; rec_t* slot_rec; page_t* page; ulint i; ulint comp; lint n = 0; ut_ad(page_rec_check(rec)); page = buf_frame_align(rec); comp = page_is_comp(page); while (rec_get_n_owned(rec, comp) == 0) { rec = page_rec_get_next(rec); n--; } for (i = 0; ; i++) { slot = page_dir_get_nth_slot(page, i); slot_rec = page_dir_slot_get_rec(slot); n += rec_get_n_owned(slot_rec, comp); if (rec == slot_rec) { break; } } n--; ut_ad(n >= 0); return((ulint) n);}/****************************************************************Prints record contents including the data relevant only inthe index page context. */ voidpage_rec_print(/*===========*/ rec_t* rec, /* in: physical record */ const ulint* offsets)/* in: record descriptor */{ ulint comp = page_is_comp(buf_frame_align(rec)); ut_a(!comp == !rec_offs_comp(offsets)); rec_print_new(stderr, rec, offsets); fprintf(stderr, " n_owned: %lu; heap_no: %lu; next rec: %lu\n", (ulong) rec_get_n_owned(rec, comp), (ulong) rec_get_heap_no(rec, comp), (ulong) rec_get_next_offs(rec, comp)); page_rec_check(rec); rec_validate(rec, offsets);}/*******************************************************************This is used to print the contents of the directory fordebugging purposes. */voidpage_dir_print(/*===========*/ page_t* page, /* in: index page */ ulint pr_n) /* in: print n first and n last entries */{ ulint n; ulint i; page_dir_slot_t* slot; n = page_dir_get_n_slots(page); fprintf(stderr, "--------------------------------\n" "PAGE DIRECTORY\n" "Page address %p\n" "Directory stack top at offs: %lu; number of slots: %lu\n", page, (ulong)(page_dir_get_nth_slot(page, n - 1) - page), (ulong) n); for (i = 0; i < n; i++) { slot = page_dir_get_nth_slot(page, i); if ((i == pr_n) && (i < n - pr_n)) { fputs(" ... \n", stderr); } if ((i < pr_n) || (i >= n - pr_n)) { fprintf(stderr, "Contents of slot: %lu: n_owned: %lu, rec offs: %lu\n", (ulong) i, (ulong) page_dir_slot_get_n_owned(slot), (ulong)(page_dir_slot_get_rec(slot) - page)); } } fprintf(stderr, "Total of %lu records\n" "--------------------------------\n", (ulong) (2 + page_get_n_recs(page)));} /*******************************************************************This is used to print the contents of the page record list fordebugging purposes. */voidpage_print_list(/*============*/ page_t* page, /* in: index page */ dict_index_t* index, /* in: dictionary index of the page */ ulint pr_n) /* in: print n first and n last entries */{ page_cur_t cur; ulint count; ulint n_recs; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; *offsets_ = (sizeof offsets_) / sizeof *offsets_; ut_a((ibool)!!page_is_comp(page) == index->table->comp); fprintf(stderr, "--------------------------------\n" "PAGE RECORD LIST\n" "Page address %p\n", page); n_recs = page_get_n_recs(page); page_cur_set_before_first(page, &cur); count = 0; for (;;) { offsets = rec_get_offsets(cur.rec, index, offsets, ULINT_UNDEFINED, &heap); page_rec_print(cur.rec, offsets); if (count == pr_n) { break; } if (page_cur_is_after_last(&cur)) { break; } page_cur_move_to_next(&cur); count++; } if (n_recs > 2 * pr_n) { fputs(" ... \n", stderr); } while (!page_cur_is_after_last(&cur)) { page_cur_move_to_next(&cur); if (count + pr_n >= n_recs) { offsets = rec_get_offsets(cur.rec, index, offsets, ULINT_UNDEFINED, &heap); page_rec_print(cur.rec, offsets); } count++; } fprintf(stderr, "Total of %lu records \n" "--------------------------------\n", (ulong) (count + 1)); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); }} /*******************************************************************Prints the info in a page header. */voidpage_header_print(/*==============*/ page_t* page){ fprintf(stderr, "--------------------------------\n" "PAGE HEADER INFO\n" "Page address %p, n records %lu (%s)\n" "n dir slots %lu, heap top %lu\n" "Page n heap %lu, free %lu, garbage %lu\n" "Page last insert %lu, direction %lu, n direction %lu\n", page, (ulong) page_header_get_field(page, PAGE_N_RECS), page_is_comp(page) ? "compact format" : "original format", (ulong) page_header_get_field(page, PAGE_N_DIR_SLOTS), (ulong) page_header_get_field(page, PAGE_HEAP_TOP), (ulong) page_dir_get_n_heap(page), (ulong) page_header_get_field(page, PAGE_FREE), (ulong) page_header_get_field(page, PAGE_GARBAGE), (ulong) page_header_get_field(page, PAGE_LAST_INSERT), (ulong) page_header_get_field(page, PAGE_DIRECTION), (ulong) page_header_get_field(page, PAGE_N_DIRECTION));}/*******************************************************************This is used to print the contents of the page fordebugging purposes. */voidpage_print(/*======*/ page_t* page, /* in: index page */ dict_index_t* index, /* in: dictionary index of the page */ ulint dn, /* in: print dn first and last entries in directory */ ulint rn) /* in: print rn first and last records in directory */{ page_header_print(page); page_dir_print(page, dn); page_print_list(page, index, rn);} /*******************************************************************The following is used to validate a record on a page. This functiondiffers from rec_validate as it can also check the n_owned field andthe heap_no field. */iboolpage_rec_validate(/*==============*/ /* out: TRUE if ok */ rec_t* rec, /* in: physical record */ const ulint* offsets)/* in: array returned by rec_get_offsets() */{ ulint n_owned; ulint heap_no; page_t* page; ulint comp; page = buf_frame_align(rec); comp = page_is_comp(page); ut_a(!comp == !rec_offs_comp(offsets)); page_rec_check(rec); rec_validate(rec, offsets); n_owned = rec_get_n_owned(rec, comp); heap_no = rec_get_heap_no(rec, comp); if (!(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED)) { fprintf(stderr, "InnoDB: Dir slot of rec %lu, n owned too big %lu\n", (ulong)(rec - page), (ulong) n_owned); return(FALSE); } if (!(heap_no < page_dir_get_n_heap(page))) { fprintf(stderr, "InnoDB: Heap no of rec %lu too big %lu %lu\n", (ulong)(rec - page), (ulong) heap_no, (ulong) page_dir_get_n_heap(page)); return(FALSE); } return(TRUE);}/*******************************************************************Checks that the first directory slot points to the infimum record andthe last to the supremum. This function is intended to track if thebug fixed in 4.0.14 has caused corruption to users' databases. */voidpage_check_dir(/*===========*/ page_t* page) /* in: index page */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -