mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
manual.texi website address change
row0sel.c CHECK TABLE now also for InnoDB, a join speed optimization trx0trx.c CHECK TABLE now also for InnoDB, a join speed optimization rem0cmp.c CHECK TABLE now also for InnoDB, a join speed optimization row0mysql.c CHECK TABLE now also for InnoDB, a join speed optimization page0page.c CHECK TABLE now also for InnoDB, a join speed optimization row0mysql.h CHECK TABLE now also for InnoDB, a join speed optimization trx0trx.h CHECK TABLE now also for InnoDB, a join speed optimization btr0btr.h CHECK TABLE now also for InnoDB, a join speed optimization btr0cur.h CHECK TABLE now also for InnoDB, a join speed optimization btr0pcur.h CHECK TABLE now also for InnoDB, a join speed optimization btr0pcur.ic CHECK TABLE now also for InnoDB, a join speed optimization btr0btr.c CHECK TABLE now also for InnoDB, a join speed optimization btr0cur.c CHECK TABLE now also for InnoDB, a join speed optimization btr0sea.c CHECK TABLE now also for InnoDB, a join speed optimization innodb.result CHECK TABLE now also for InnoDB, a join speed optimization ha_innobase.cc CHECK TABLE now also for InnoDB, a join speed optimization ha_innobase.h CHECK TABLE now also for InnoDB, a join speed optimization sql/ha_innobase.cc: CHECK TABLE now also for InnoDB, a join speed optimization sql/ha_innobase.h: CHECK TABLE now also for InnoDB, a join speed optimization mysql-test/r/innodb.result: CHECK TABLE now also for InnoDB, a join speed optimization innobase/btr/btr0btr.c: CHECK TABLE now also for InnoDB, a join speed optimization innobase/btr/btr0cur.c: CHECK TABLE now also for InnoDB, a join speed optimization innobase/btr/btr0sea.c: CHECK TABLE now also for InnoDB, a join speed optimization innobase/include/btr0btr.h: CHECK TABLE now also for InnoDB, a join speed optimization innobase/include/btr0cur.h: CHECK TABLE now also for InnoDB, a join speed optimization innobase/include/btr0pcur.h: CHECK TABLE now also for InnoDB, a join speed optimization innobase/include/btr0pcur.ic: CHECK TABLE now also for InnoDB, a join speed optimization innobase/include/row0mysql.h: CHECK TABLE now also for InnoDB, a join speed optimization innobase/include/trx0trx.h: CHECK TABLE now also for InnoDB, a join speed optimization innobase/page/page0page.c: CHECK TABLE now also for InnoDB, a join speed optimization innobase/rem/rem0cmp.c: CHECK TABLE now also for InnoDB, a join speed optimization innobase/row/row0mysql.c: CHECK TABLE now also for InnoDB, a join speed optimization innobase/row/row0sel.c: CHECK TABLE now also for InnoDB, a join speed optimization innobase/trx/trx0trx.c: CHECK TABLE now also for InnoDB, a join speed optimization Docs/manual.texi: website address change
This commit is contained in:
@ -26712,7 +26712,7 @@ the maximum size for a table. The minimum tablespace size is 10 MB.
|
||||
Contact information of Innobase Oy, producer of the InnoDB engine:
|
||||
|
||||
@example
|
||||
Website: www.innobase.fi
|
||||
Website: www.innodb.com
|
||||
Heikki.Tuuri@@innobase.inet.fi
|
||||
phone: 358-9-6969 3250 (office) 358-40-5617367 (mobile)
|
||||
InnoDB Oy Inc.
|
||||
|
@ -2238,12 +2238,93 @@ btr_check_node_ptr(
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Checks the size and number of fields in a record based on the definition of
|
||||
the index. */
|
||||
static
|
||||
ibool
|
||||
btr_index_rec_validate(
|
||||
/*====================*/
|
||||
/* out: TRUE if ok */
|
||||
rec_t* rec, /* in: index record */
|
||||
dict_index_t* index) /* in: index */
|
||||
{
|
||||
dtype_t* type;
|
||||
byte* data;
|
||||
ulint len;
|
||||
ulint n;
|
||||
ulint i;
|
||||
|
||||
n = dict_index_get_n_fields(index);
|
||||
|
||||
if (rec_get_n_fields(rec) != n) {
|
||||
fprintf(stderr, "Record has %lu fields, should have %lu\n",
|
||||
rec_get_n_fields(rec), n);
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
data = rec_get_nth_field(rec, i, &len);
|
||||
|
||||
type = dict_index_get_nth_type(index, i);
|
||||
|
||||
if (len != UNIV_SQL_NULL && dtype_is_fixed_size(type)
|
||||
&& len != dtype_get_fixed_size(type)) {
|
||||
fprintf(stderr,
|
||||
"Record field %lu len is %lu, should be %lu\n",
|
||||
i, len, dtype_get_fixed_size(type));
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Checks the size and number of fields in records based on the definition of
|
||||
the index. */
|
||||
static
|
||||
ibool
|
||||
btr_index_page_validate(
|
||||
/*====================*/
|
||||
/* out: TRUE if ok */
|
||||
page_t* page, /* in: index page */
|
||||
dict_index_t* index) /* in: index */
|
||||
{
|
||||
rec_t* rec;
|
||||
page_cur_t cur;
|
||||
ibool ret = TRUE;
|
||||
|
||||
page_cur_set_before_first(page, &cur);
|
||||
page_cur_move_to_next(&cur);
|
||||
|
||||
for (;;) {
|
||||
rec = (&cur)->rec;
|
||||
|
||||
if (page_cur_is_after_last(&cur)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!btr_index_rec_validate(rec, index)) {
|
||||
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
page_cur_move_to_next(&cur);
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Validates index tree level. */
|
||||
static
|
||||
void
|
||||
ibool
|
||||
btr_validate_level(
|
||||
/*===============*/
|
||||
/* out: TRUE if ok */
|
||||
dict_tree_t* tree, /* in: index tree */
|
||||
ulint level) /* in: level number */
|
||||
{
|
||||
@ -2260,7 +2341,9 @@ btr_validate_level(
|
||||
page_cur_t cursor;
|
||||
mem_heap_t* heap;
|
||||
dtuple_t* node_ptr_tuple;
|
||||
|
||||
ibool ret = TRUE;
|
||||
dict_index_t* index;
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
page = btr_root_get(tree, &mtr);
|
||||
@ -2278,13 +2361,31 @@ btr_validate_level(
|
||||
page = btr_node_ptr_get_child(node_ptr, &mtr);
|
||||
}
|
||||
|
||||
index = UT_LIST_GET_FIRST(tree->tree_indexes);
|
||||
|
||||
/* Now we are on the desired level */
|
||||
loop:
|
||||
mtr_x_lock(dict_tree_get_lock(tree), &mtr);
|
||||
|
||||
/* Check ordering of records */
|
||||
page_validate(page, UT_LIST_GET_FIRST(tree->tree_indexes));
|
||||
/* Check ordering etc. of records */
|
||||
|
||||
if (!page_validate(page, index)) {
|
||||
fprintf(stderr, "Error in page %lu in index %s\n",
|
||||
buf_frame_get_page_no(page), index->name);
|
||||
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
if (level == 0) {
|
||||
if (!btr_index_page_validate(page, index)) {
|
||||
fprintf(stderr,
|
||||
"Error in page %lu in index %s\n",
|
||||
buf_frame_get_page_no(page), index->name);
|
||||
|
||||
ret = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
ut_a(btr_page_get_level(page, &mtr) == level);
|
||||
|
||||
right_page_no = btr_page_get_next(page, &mtr);
|
||||
@ -2374,14 +2475,17 @@ loop:
|
||||
|
||||
goto loop;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
Checks the consistency of an index tree. */
|
||||
|
||||
void
|
||||
ibool
|
||||
btr_validate_tree(
|
||||
/*==============*/
|
||||
/* out: TRUE if ok */
|
||||
dict_tree_t* tree) /* in: tree */
|
||||
{
|
||||
mtr_t mtr;
|
||||
@ -2397,8 +2501,15 @@ btr_validate_tree(
|
||||
|
||||
for (i = 0; i <= n; i++) {
|
||||
|
||||
btr_validate_level(tree, n - i);
|
||||
if (!btr_validate_level(tree, n - i)) {
|
||||
|
||||
mtr_commit(&mtr);
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
mtr_commit(&mtr);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
@ -163,9 +163,14 @@ btr_cur_search_to_nth_level(
|
||||
BTR_INSERT and BTR_ESTIMATE;
|
||||
cursor->left_page is used to store a pointer
|
||||
to the left neighbor page, in the cases
|
||||
BTR_SEARCH_PREV and BTR_MODIFY_PREV */
|
||||
BTR_SEARCH_PREV and BTR_MODIFY_PREV;
|
||||
NOTE that if has_search_latch
|
||||
is != 0, we maybe do not have a latch set
|
||||
on the cursor page, we assume
|
||||
the caller uses his search latch
|
||||
to protect the record! */
|
||||
btr_cur_t* cursor, /* in/out: tree cursor; the cursor page is
|
||||
s- or x-latched */
|
||||
s- or x-latched, but see also above! */
|
||||
ulint has_search_latch,/* in: info on the latch mode the
|
||||
caller currently has on btr_search_latch:
|
||||
RW_S_LATCH, or 0 */
|
||||
|
@ -601,7 +601,12 @@ btr_search_guess_on_hash(
|
||||
btr_search_t* info, /* in: index search info */
|
||||
dtuple_t* tuple, /* in: logical record */
|
||||
ulint mode, /* in: PAGE_CUR_L, ... */
|
||||
ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */
|
||||
ulint latch_mode, /* in: BTR_SEARCH_LEAF, ...;
|
||||
NOTE that only if has_search_latch
|
||||
is 0, we will have a latch set on
|
||||
the cursor page, otherwise we assume
|
||||
the caller uses his search latch
|
||||
to protect the record! */
|
||||
btr_cur_t* cursor, /* out: tree cursor */
|
||||
ulint has_search_latch,/* in: latch mode the caller
|
||||
currently has on btr_search_latch:
|
||||
@ -722,7 +727,9 @@ btr_search_guess_on_hash(
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
btr_leaf_page_release(page, latch_mode, mtr);
|
||||
if (!has_search_latch) {
|
||||
btr_leaf_page_release(page, latch_mode, mtr);
|
||||
}
|
||||
|
||||
goto failure;
|
||||
}
|
||||
|
@ -376,9 +376,10 @@ btr_print_tree(
|
||||
/******************************************************************
|
||||
Checks the consistency of an index tree. */
|
||||
|
||||
void
|
||||
ibool
|
||||
btr_validate_tree(
|
||||
/*==============*/
|
||||
/* out: TRUE if ok */
|
||||
dict_tree_t* tree); /* in: tree */
|
||||
|
||||
#define BTR_N_LEAF_PAGES 1
|
||||
|
@ -98,12 +98,18 @@ btr_cur_search_to_nth_level(
|
||||
the previous page of the record! Inserts
|
||||
should always be made using PAGE_CUR_LE to
|
||||
search the position! */
|
||||
ulint latch_mode, /* in: BTR_SEARCH_LEAF, ...;
|
||||
ulint latch_mode, /* in: BTR_SEARCH_LEAF, ..., ORed with
|
||||
BTR_INSERT and BTR_ESTIMATE;
|
||||
cursor->left_page is used to store a pointer
|
||||
to the left neighbor page, in the cases
|
||||
BTR_SEARCH_PREV and BTR_MODIFY_PREV */
|
||||
btr_cur_t* cursor, /* out: tree cursor; the cursor page is s- or
|
||||
x-latched */
|
||||
BTR_SEARCH_PREV and BTR_MODIFY_PREV;
|
||||
NOTE that if has_search_latch
|
||||
is != 0, we maybe do not have a latch set
|
||||
on the cursor page, we assume
|
||||
the caller uses his search latch
|
||||
to protect the record! */
|
||||
btr_cur_t* cursor, /* in/out: tree cursor; the cursor page is
|
||||
s- or x-latched, but see also above! */
|
||||
ulint has_search_latch,/* in: latch mode the caller
|
||||
currently has on btr_search_latch:
|
||||
RW_S_LATCH, or 0 */
|
||||
|
@ -87,7 +87,11 @@ btr_pcur_open_with_no_init(
|
||||
PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
|
||||
may end up on the previous page of the
|
||||
record! */
|
||||
ulint latch_mode,/* in: BTR_SEARCH_LEAF, ... */
|
||||
ulint latch_mode,/* in: BTR_SEARCH_LEAF, ...;
|
||||
NOTE that if has_search_latch != 0 then
|
||||
we maybe do not acquire a latch on the cursor
|
||||
page, but assume that the caller uses his
|
||||
btr search latch to protect the record! */
|
||||
btr_pcur_t* cursor, /* in: memory buffer for persistent cursor */
|
||||
ulint has_search_latch,/* in: latch mode the caller
|
||||
currently has on btr_search_latch:
|
||||
|
@ -492,7 +492,11 @@ btr_pcur_open_with_no_init(
|
||||
PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
|
||||
may end up on the previous page of the
|
||||
record! */
|
||||
ulint latch_mode,/* in: BTR_SEARCH_LEAF, ... */
|
||||
ulint latch_mode,/* in: BTR_SEARCH_LEAF, ...;
|
||||
NOTE that if has_search_latch != 0 then
|
||||
we maybe do not acquire a latch on the cursor
|
||||
page, but assume that the caller uses his
|
||||
btr search latch to protect the record! */
|
||||
btr_pcur_t* cursor, /* in: memory buffer for persistent cursor */
|
||||
ulint has_search_latch,/* in: latch mode the caller
|
||||
currently has on btr_search_latch:
|
||||
|
@ -229,6 +229,15 @@ row_rename_table_for_mysql(
|
||||
char* old_name, /* in: old table name */
|
||||
char* new_name, /* in: new table name */
|
||||
trx_t* trx); /* in: transaction handle */
|
||||
/*************************************************************************
|
||||
Checks a table for corruption. */
|
||||
|
||||
ulint
|
||||
row_check_table_for_mysql(
|
||||
/*======================*/
|
||||
/* out: DB_ERROR or DB_SUCCESS */
|
||||
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
|
||||
handle */
|
||||
|
||||
/* A struct describing a place for an individual column in the MySQL
|
||||
row format which is presented to the table handler in ha_innobase.
|
||||
@ -281,7 +290,8 @@ struct row_prebuilt_struct {
|
||||
is set to TRUE */
|
||||
dict_index_t* index; /* current index for a search, if any */
|
||||
ulint template_type; /* ROW_MYSQL_WHOLE_ROW,
|
||||
ROW_MYSQL_REC_FIELDS or
|
||||
ROW_MYSQL_REC_FIELDS,
|
||||
ROW_MYSQL_DUMMY_TEMPLATE, or
|
||||
ROW_MYSQL_NO_TEMPLATE */
|
||||
ulint n_template; /* number of elements in the
|
||||
template */
|
||||
@ -359,6 +369,8 @@ struct row_prebuilt_struct {
|
||||
#define ROW_MYSQL_WHOLE_ROW 0
|
||||
#define ROW_MYSQL_REC_FIELDS 1
|
||||
#define ROW_MYSQL_NO_TEMPLATE 2
|
||||
#define ROW_MYSQL_DUMMY_TEMPLATE 3 /* dummy template used in
|
||||
row_scan_and_check_index */
|
||||
|
||||
#ifndef UNIV_NONINL
|
||||
#include "row0mysql.ic"
|
||||
|
@ -24,6 +24,13 @@ saving CPU time. The kernel mutex contention is increased, however. */
|
||||
|
||||
extern ulint trx_n_mysql_transactions;
|
||||
|
||||
/************************************************************************
|
||||
Releases the search latch if trx has reserved it. */
|
||||
|
||||
void
|
||||
trx_search_latch_release_if_reserved(
|
||||
/*=================================*/
|
||||
trx_t* trx); /* in: transaction */
|
||||
/********************************************************************
|
||||
Retrieves the error_info field from a trx. */
|
||||
|
||||
@ -282,6 +289,13 @@ struct trx_struct{
|
||||
ulint n_mysql_tables_in_use; /* number of Innobase tables
|
||||
used in the processing of the current
|
||||
SQL statement in MySQL */
|
||||
ulint mysql_n_tables_locked;
|
||||
/* how many tables the current SQL
|
||||
statement uses, except those
|
||||
in consistent read */
|
||||
ibool has_search_latch;
|
||||
/* TRUE if this trx has latched the
|
||||
search system latch in S-mode */
|
||||
ibool ignore_duplicates_in_insert;
|
||||
/* in an insert roll back only insert
|
||||
of the latest row in case
|
||||
|
@ -1199,8 +1199,16 @@ page_rec_validate(
|
||||
n_owned = rec_get_n_owned(rec);
|
||||
heap_no = rec_get_heap_no(rec);
|
||||
|
||||
ut_a(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED);
|
||||
ut_a(heap_no < page_header_get_field(page, PAGE_N_HEAP));
|
||||
if (!(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED)) {
|
||||
fprintf(stderr, "Dir slot n owned too big %lu\n", n_owned);
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if (!(heap_no < page_header_get_field(page, PAGE_N_HEAP))) {
|
||||
fprintf(stderr, "Heap no too big %lu %lu\n", heap_no,
|
||||
page_header_get_field(page, PAGE_N_HEAP));
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
@ -1216,20 +1224,21 @@ page_validate(
|
||||
dict_index_t* index) /* in: data dictionary index containing
|
||||
the page record type definition */
|
||||
{
|
||||
page_dir_slot_t* slot;
|
||||
mem_heap_t* heap;
|
||||
page_cur_t cur;
|
||||
byte* buf;
|
||||
ulint i;
|
||||
ulint count;
|
||||
ulint own_count;
|
||||
ulint slot_no;
|
||||
ulint data_size;
|
||||
page_cur_t cur;
|
||||
rec_t* rec;
|
||||
rec_t* old_rec = NULL;
|
||||
page_dir_slot_t* slot;
|
||||
ulint offs;
|
||||
ulint n_slots;
|
||||
|
||||
ibool ret = FALSE;
|
||||
|
||||
heap = mem_heap_create(UNIV_PAGE_SIZE);
|
||||
|
||||
/* The following buffer is used to check that the
|
||||
@ -1244,8 +1253,16 @@ page_validate(
|
||||
overlap. */
|
||||
|
||||
n_slots = page_dir_get_n_slots(page);
|
||||
ut_ad(page_header_get_ptr(page, PAGE_HEAP_TOP) <=
|
||||
page_dir_get_nth_slot(page, n_slots - 1));
|
||||
|
||||
if (!(page_header_get_ptr(page, PAGE_HEAP_TOP) <=
|
||||
page_dir_get_nth_slot(page, n_slots - 1))) {
|
||||
fprintf(stderr,
|
||||
"Record heap and dir overlap on a page in index %s, %lu, %lu\n",
|
||||
index->name, page_header_get_ptr(page, PAGE_HEAP_TOP),
|
||||
page_dir_get_nth_slot(page, n_slots - 1));
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
/* Validate the record list in a loop checking also that
|
||||
it is consistent with the directory. */
|
||||
@ -1259,11 +1276,20 @@ page_validate(
|
||||
|
||||
for (;;) {
|
||||
rec = (&cur)->rec;
|
||||
page_rec_validate(rec);
|
||||
|
||||
if (!page_rec_validate(rec)) {
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
/* Check that the records are in the ascending order */
|
||||
if ((count >= 2) && (!page_cur_is_after_last(&cur))) {
|
||||
ut_a(1 == cmp_rec_rec(rec, old_rec, index));
|
||||
if (!(1 == cmp_rec_rec(rec, old_rec, index))) {
|
||||
fprintf(stderr,
|
||||
"Records in wrong order in index %s\n",
|
||||
index->name);
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
}
|
||||
|
||||
if ((rec != page_get_supremum_rec(page))
|
||||
@ -1275,16 +1301,38 @@ page_validate(
|
||||
offs = rec_get_start(rec) - page;
|
||||
|
||||
for (i = 0; i < rec_get_size(rec); i++) {
|
||||
ut_a(buf[offs + i] == 0); /* No other record may
|
||||
overlap this */
|
||||
if (!buf[offs + i] == 0) {
|
||||
/* No other record may overlap this */
|
||||
|
||||
fprintf(stderr,
|
||||
"Record overlaps another in index %s \n",
|
||||
index->name);
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
buf[offs + i] = 1;
|
||||
}
|
||||
|
||||
if (rec_get_n_owned(rec) != 0) {
|
||||
/* This is a record pointed to by a dir slot */
|
||||
ut_a(rec_get_n_owned(rec) == own_count);
|
||||
if (rec_get_n_owned(rec) != own_count) {
|
||||
fprintf(stderr,
|
||||
"Wrong owned count %lu, %lu, in index %s\n",
|
||||
rec_get_n_owned(rec), own_count,
|
||||
index->name);
|
||||
|
||||
ut_a(page_dir_slot_get_rec(slot) == rec);
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
if (page_dir_slot_get_rec(slot) != rec) {
|
||||
fprintf(stderr,
|
||||
"Dir slot does not point to right rec in %s\n",
|
||||
index->name);
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
page_dir_slot_check(slot);
|
||||
|
||||
own_count = 0;
|
||||
@ -1297,45 +1345,89 @@ page_validate(
|
||||
if (page_cur_is_after_last(&cur)) {
|
||||
break;
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
if (rec_get_next_offs(rec) < FIL_PAGE_DATA
|
||||
|| rec_get_next_offs(rec) >= UNIV_PAGE_SIZE) {
|
||||
fprintf(stderr,
|
||||
"Next record offset wrong %lu in index %s\n",
|
||||
rec_get_next_offs(rec), index->name);
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
count++;
|
||||
page_cur_move_to_next(&cur);
|
||||
own_count++;
|
||||
old_rec = rec;
|
||||
}
|
||||
|
||||
ut_a(rec_get_n_owned(rec) != 0);
|
||||
ut_a(slot_no == n_slots - 1);
|
||||
ut_a(page_header_get_field(page, PAGE_N_RECS) + 2 == count + 1);
|
||||
if (rec_get_n_owned(rec) == 0) {
|
||||
fprintf(stderr, "n owned is zero in index %s\n", index->name);
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
if (slot_no != n_slots - 1) {
|
||||
fprintf(stderr, "n slots wrong %lu %lu in index %s\n",
|
||||
slot_no, n_slots - 1, index->name);
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
if (page_header_get_field(page, PAGE_N_RECS) + 2 != count + 1) {
|
||||
fprintf(stderr, "n recs wrong %lu %lu in index %s\n",
|
||||
page_header_get_field(page, PAGE_N_RECS) + 2, count + 1,
|
||||
index->name);
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
if (data_size != page_get_data_size(page)) {
|
||||
printf("Summed data size %lu, returned by func %lu\n",
|
||||
fprintf(stderr, "Summed data size %lu, returned by func %lu\n",
|
||||
data_size, page_get_data_size(page));
|
||||
ut_error;
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
/* Check then the free list */
|
||||
rec = page_header_get_ptr(page, PAGE_FREE);
|
||||
|
||||
while (rec != NULL) {
|
||||
page_rec_validate(rec);
|
||||
if (!page_rec_validate(rec)) {
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
count++;
|
||||
offs = rec_get_start(rec) - page;
|
||||
|
||||
for (i = 0; i < rec_get_size(rec); i++) {
|
||||
ut_a(buf[offs + i] == 0);
|
||||
|
||||
if (buf[offs + i] != 0) {
|
||||
fprintf(stderr,
|
||||
"Record overlaps another in free list, index %s \n",
|
||||
index->name);
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
buf[offs + i] = 1;
|
||||
}
|
||||
|
||||
rec = page_rec_get_next(rec);
|
||||
}
|
||||
|
||||
ut_a(page_header_get_field(page, PAGE_N_HEAP) == count + 1);
|
||||
|
||||
if (page_header_get_field(page, PAGE_N_HEAP) != count + 1) {
|
||||
|
||||
fprintf(stderr, "N heap is wrong %lu %lu in index %s\n",
|
||||
page_header_get_field(page, PAGE_N_HEAP), count + 1,
|
||||
index->name);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
func_exit:
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(TRUE);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
|
@ -177,7 +177,9 @@ cmp_whole_field(
|
||||
(int)(type->prtype & ~DATA_NOT_NULL),
|
||||
a, a_length, b, b_length));
|
||||
default:
|
||||
assert(0);
|
||||
fprintf(stderr,
|
||||
"InnoDB: unknown type number %lu\n", data_type);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
return(0);
|
||||
|
@ -1129,3 +1129,146 @@ funct_exit:
|
||||
|
||||
return((int) err);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Checks that the index contains entries in an ascending order, unique
|
||||
constraint is not broken, and calculates the number of index entries
|
||||
in the read view of the current transaction. */
|
||||
static
|
||||
ibool
|
||||
row_scan_and_check_index(
|
||||
/*=====================*/
|
||||
/* out: TRUE if ok */
|
||||
row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL */
|
||||
dict_index_t* index, /* in: index */
|
||||
ulint* n_rows) /* out: number of entries seen in the
|
||||
current consistent read */
|
||||
{
|
||||
mem_heap_t* heap;
|
||||
dtuple_t* prev_entry = NULL;
|
||||
ulint matched_fields;
|
||||
ulint matched_bytes;
|
||||
byte* buf;
|
||||
ulint ret;
|
||||
rec_t* rec;
|
||||
ibool is_ok = TRUE;
|
||||
int cmp;
|
||||
|
||||
*n_rows = 0;
|
||||
|
||||
buf = mem_alloc(UNIV_PAGE_SIZE);
|
||||
heap = mem_heap_create(100);
|
||||
|
||||
/* Make a dummy template in prebuilt, which we will use
|
||||
in scanning the index entries */
|
||||
|
||||
prebuilt->index = index;
|
||||
prebuilt->sql_stat_start = TRUE;
|
||||
prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE;
|
||||
prebuilt->n_template = 0;
|
||||
prebuilt->need_to_access_clustered = FALSE;
|
||||
|
||||
dtuple_set_n_fields(prebuilt->search_tuple, 0);
|
||||
|
||||
prebuilt->select_lock_type = LOCK_NONE;
|
||||
|
||||
ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
|
||||
loop:
|
||||
if (ret != DB_SUCCESS) {
|
||||
|
||||
mem_free(buf);
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(is_ok);
|
||||
}
|
||||
|
||||
*n_rows = *n_rows + 1;
|
||||
|
||||
/* row_search... returns the index record in buf, record origin offset
|
||||
within buf stored in the first 4 bytes, because we have built a dummy
|
||||
template */
|
||||
|
||||
rec = buf + mach_read_from_4(buf);
|
||||
|
||||
if (prev_entry != NULL) {
|
||||
matched_fields = 0;
|
||||
matched_bytes = 0;
|
||||
|
||||
cmp = cmp_dtuple_rec_with_match(prev_entry, rec,
|
||||
&matched_fields,
|
||||
&matched_bytes);
|
||||
if (cmp > 0) {
|
||||
fprintf(stderr,
|
||||
"Error: index records in a wrong order in index %s\n",
|
||||
index->name);
|
||||
|
||||
is_ok = FALSE;
|
||||
} else if ((index->type & DICT_UNIQUE)
|
||||
&& matched_fields >=
|
||||
dict_index_get_n_ordering_defined_by_user(index)) {
|
||||
fprintf(stderr,
|
||||
"Error: duplicate key in index %s\n",
|
||||
index->name);
|
||||
|
||||
is_ok = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
mem_heap_empty(heap);
|
||||
|
||||
prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
|
||||
|
||||
ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT);
|
||||
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Checks a table for corruption. */
|
||||
|
||||
ulint
|
||||
row_check_table_for_mysql(
|
||||
/*======================*/
|
||||
/* out: DB_ERROR or DB_SUCCESS */
|
||||
row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
|
||||
handle */
|
||||
{
|
||||
dict_table_t* table = prebuilt->table;
|
||||
dict_index_t* index;
|
||||
ulint n_rows;
|
||||
ulint n_rows_in_table;
|
||||
ulint ret = DB_SUCCESS;
|
||||
|
||||
index = dict_table_get_first_index(table);
|
||||
|
||||
while (index != NULL) {
|
||||
/* fprintf(stderr, "Validating index %s\n", index->name); */
|
||||
|
||||
if (!btr_validate_tree(index->tree)) {
|
||||
ret = DB_ERROR;
|
||||
} else {
|
||||
if (!row_scan_and_check_index(prebuilt,
|
||||
index, &n_rows)) {
|
||||
ret = DB_ERROR;
|
||||
}
|
||||
|
||||
/* fprintf(stderr, "%lu entries in index %s\n", n_rows,
|
||||
index->name); */
|
||||
|
||||
if (index == dict_table_get_first_index(table)) {
|
||||
n_rows_in_table = n_rows;
|
||||
} else if (n_rows != n_rows_in_table) {
|
||||
|
||||
ret = DB_ERROR;
|
||||
|
||||
fprintf(stderr,
|
||||
"Error: index %s contains %lu entries, should be %lu\n",
|
||||
index->name, n_rows, n_rows_in_table);
|
||||
}
|
||||
}
|
||||
|
||||
index = dict_table_get_next_index(index);
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
@ -2341,6 +2341,65 @@ row_sel_push_cache_row_for_mysql(
|
||||
prebuilt->n_fetch_cached++;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Tries to do a shortcut to fetch a clustered index record with a unique key,
|
||||
using the hash index if possible (not always). We assume that the search
|
||||
mode is PAGE_CUR_GE, it is a consistent read, trx has already a read view,
|
||||
btr search latch has been locked in S-mode. */
|
||||
static
|
||||
ulint
|
||||
row_sel_try_search_shortcut_for_mysql(
|
||||
/*==================================*/
|
||||
/* out: SEL_FOUND, SEL_EXHAUSTED, SEL_RETRY */
|
||||
rec_t** out_rec,/* out: record if found */
|
||||
row_prebuilt_t* prebuilt,/* in: prebuilt struct */
|
||||
mtr_t* mtr) /* in: started mtr */
|
||||
{
|
||||
dict_index_t* index = prebuilt->index;
|
||||
dtuple_t* search_tuple = prebuilt->search_tuple;
|
||||
btr_pcur_t* pcur = prebuilt->pcur;
|
||||
trx_t* trx = prebuilt->trx;
|
||||
rec_t* rec;
|
||||
|
||||
ut_ad(index->type & DICT_CLUSTERED);
|
||||
|
||||
btr_pcur_open_with_no_init(index, search_tuple, PAGE_CUR_GE,
|
||||
BTR_SEARCH_LEAF, pcur,
|
||||
RW_S_LATCH, mtr);
|
||||
rec = btr_pcur_get_rec(pcur);
|
||||
|
||||
if (!page_rec_is_user_rec(rec)) {
|
||||
|
||||
return(SEL_RETRY);
|
||||
}
|
||||
|
||||
/* As the cursor is now placed on a user record after a search with
|
||||
the mode PAGE_CUR_GE, the up_match field in the cursor tells how many
|
||||
fields in the user record matched to the search tuple */
|
||||
|
||||
if (btr_pcur_get_up_match(pcur) < dtuple_get_n_fields(search_tuple)) {
|
||||
|
||||
return(SEL_EXHAUSTED);
|
||||
}
|
||||
|
||||
/* This is a non-locking consistent read: if necessary, fetch
|
||||
a previous version of the record */
|
||||
|
||||
if (!lock_clust_rec_cons_read_sees(rec, index, trx->read_view)) {
|
||||
|
||||
return(SEL_RETRY);
|
||||
}
|
||||
|
||||
if (rec_get_deleted_flag(rec)) {
|
||||
|
||||
return(SEL_EXHAUSTED);
|
||||
}
|
||||
|
||||
*out_rec = rec;
|
||||
|
||||
return(SEL_FOUND);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Searches for rows in the database. This is used in the interface to
|
||||
MySQL. This function opens a cursor, and also implements fetch next
|
||||
@ -2387,6 +2446,7 @@ row_search_for_mysql(
|
||||
ibool cons_read_requires_clust_rec;
|
||||
ibool was_lock_wait;
|
||||
ulint ret;
|
||||
ulint shortcut;
|
||||
ibool unique_search_from_clust_index = FALSE;
|
||||
ibool mtr_has_extra_clust_latch = FALSE;
|
||||
ibool moves_up = FALSE;
|
||||
@ -2452,6 +2512,8 @@ row_search_for_mysql(
|
||||
mode = pcur->search_mode;
|
||||
}
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
if (match_mode == ROW_SEL_EXACT && index->type & DICT_UNIQUE
|
||||
&& index->type & DICT_CLUSTERED
|
||||
&& dtuple_get_n_fields(search_tuple)
|
||||
@ -2464,6 +2526,8 @@ row_search_for_mysql(
|
||||
restore cursor position, and must return
|
||||
immediately */
|
||||
|
||||
mtr_commit(&mtr);
|
||||
|
||||
return(DB_RECORD_NOT_FOUND);
|
||||
}
|
||||
|
||||
@ -2472,8 +2536,51 @@ row_search_for_mysql(
|
||||
mode = PAGE_CUR_GE;
|
||||
|
||||
unique_search_from_clust_index = TRUE;
|
||||
|
||||
if (trx->mysql_n_tables_locked == 0
|
||||
&& !prebuilt->sql_stat_start) {
|
||||
|
||||
/* This is a SELECT query done as a consistent read,
|
||||
and the read view has already been allocated:
|
||||
let us try a search shortcut through the hash
|
||||
index */
|
||||
|
||||
if (!trx->has_search_latch) {
|
||||
rw_lock_s_lock(&btr_search_latch);
|
||||
trx->has_search_latch = TRUE;
|
||||
|
||||
} else if (btr_search_latch.writer_is_wait_ex) {
|
||||
/* There is an x-latch request waiting:
|
||||
release the s-latch for a moment to reduce
|
||||
starvation */
|
||||
|
||||
rw_lock_s_unlock(&btr_search_latch);
|
||||
rw_lock_s_lock(&btr_search_latch);
|
||||
}
|
||||
|
||||
shortcut = row_sel_try_search_shortcut_for_mysql(&rec,
|
||||
prebuilt, &mtr);
|
||||
if (shortcut == SEL_FOUND) {
|
||||
row_sel_store_mysql_rec(buf, prebuilt, rec);
|
||||
|
||||
mtr_commit(&mtr);
|
||||
|
||||
return(DB_SUCCESS);
|
||||
|
||||
} else if (shortcut == SEL_EXHAUSTED) {
|
||||
|
||||
mtr_commit(&mtr);
|
||||
|
||||
return(DB_RECORD_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trx->has_search_latch) {
|
||||
rw_lock_s_unlock(&btr_search_latch);
|
||||
trx->has_search_latch = FALSE;
|
||||
}
|
||||
|
||||
/* Note that if the search mode was GE or G, then the cursor
|
||||
naturally moves upward (in fetch next) in alphabetical order,
|
||||
otherwise downward */
|
||||
@ -2485,8 +2592,6 @@ row_search_for_mysql(
|
||||
} else if (direction == ROW_SEL_NEXT) {
|
||||
moves_up = TRUE;
|
||||
}
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
thr = que_fork_get_first_thr(prebuilt->sel_graph);
|
||||
|
||||
@ -2711,7 +2816,9 @@ rec_loop:
|
||||
if (prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD
|
||||
&& !prebuilt->templ_contains_blob
|
||||
&& prebuilt->select_lock_type == LOCK_NONE
|
||||
&& !prebuilt->clust_index_was_generated) {
|
||||
&& !prebuilt->clust_index_was_generated
|
||||
&& prebuilt->template_type
|
||||
!= ROW_MYSQL_DUMMY_TEMPLATE) {
|
||||
|
||||
/* Inside an update, for example, we do not cache rows,
|
||||
since we may use the cursor position to do the actual
|
||||
@ -2726,7 +2833,13 @@ rec_loop:
|
||||
|
||||
goto next_rec;
|
||||
} else {
|
||||
row_sel_store_mysql_rec(buf, prebuilt, rec);
|
||||
if (prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE) {
|
||||
ut_memcpy(buf + 4, rec - rec_get_extra_size(rec),
|
||||
rec_get_size(rec));
|
||||
mach_write_to_4(buf, rec_get_extra_size(rec) + 4);
|
||||
} else {
|
||||
row_sel_store_mysql_rec(buf, prebuilt, rec);
|
||||
}
|
||||
|
||||
if (prebuilt->clust_index_was_generated) {
|
||||
row_sel_store_row_id_to_prebuilt(prebuilt, index_rec,
|
||||
|
@ -22,6 +22,7 @@ Created 3/26/1996 Heikki Tuuri
|
||||
#include "read0read.h"
|
||||
#include "srv0srv.h"
|
||||
#include "thr0loc.h"
|
||||
#include "btr0sea.h"
|
||||
|
||||
/* Dummy session used currently in MySQL interface */
|
||||
sess_t* trx_dummy_sess = NULL;
|
||||
@ -63,6 +64,7 @@ trx_create(
|
||||
trx->dict_operation = FALSE;
|
||||
|
||||
trx->n_mysql_tables_in_use = 0;
|
||||
trx->mysql_n_tables_locked = 0;
|
||||
|
||||
trx->ignore_duplicates_in_insert = FALSE;
|
||||
|
||||
@ -96,6 +98,8 @@ trx_create(
|
||||
trx->lock_heap = mem_heap_create_in_buffer(256);
|
||||
UT_LIST_INIT(trx->trx_locks);
|
||||
|
||||
trx->has_search_latch = FALSE;
|
||||
|
||||
trx->read_view_heap = mem_heap_create(256);
|
||||
trx->read_view = NULL;
|
||||
|
||||
@ -132,6 +136,21 @@ trx_allocate_for_mysql(void)
|
||||
return(trx);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Releases the search latch if trx has reserved it. */
|
||||
|
||||
void
|
||||
trx_search_latch_release_if_reserved(
|
||||
/*=================================*/
|
||||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
if (trx->has_search_latch) {
|
||||
rw_lock_s_unlock(&btr_search_latch);
|
||||
|
||||
trx->has_search_latch = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Frees a transaction object. */
|
||||
|
||||
@ -149,6 +168,7 @@ trx_free(
|
||||
ut_a(trx->update_undo == NULL);
|
||||
|
||||
ut_a(trx->n_mysql_tables_in_use == 0);
|
||||
ut_a(trx->mysql_n_tables_locked == 0);
|
||||
|
||||
if (trx->undo_no_arr) {
|
||||
trx_undo_arr_free(trx->undo_no_arr);
|
||||
@ -160,6 +180,8 @@ trx_free(
|
||||
ut_a(trx->wait_lock == NULL);
|
||||
ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
|
||||
|
||||
ut_a(!trx->has_search_latch);
|
||||
|
||||
if (trx->lock_heap) {
|
||||
mem_heap_free(trx->lock_heap);
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ test.t1 optimize error The handler for the table doesn't support check/repair
|
||||
a
|
||||
2
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check error The handler for the table doesn't support check/repair
|
||||
test.t1 check status OK
|
||||
a b
|
||||
2 testing
|
||||
Table Op Msg_type Msg_text
|
||||
|
@ -2142,6 +2142,7 @@ ha_innobase::external_lock(
|
||||
prebuilt->in_update_remember_pos = TRUE;
|
||||
|
||||
if (lock_type == F_WRLCK) {
|
||||
|
||||
/* If this is a SELECT, then it is in UPDATE TABLE ...
|
||||
or SELECT ... FOR UPDATE */
|
||||
prebuilt->select_lock_type = LOCK_X;
|
||||
@ -2153,13 +2154,27 @@ ha_innobase::external_lock(
|
||||
}
|
||||
|
||||
trx->n_mysql_tables_in_use++;
|
||||
|
||||
if (prebuilt->select_lock_type != LOCK_NONE) {
|
||||
|
||||
trx->mysql_n_tables_locked++;
|
||||
}
|
||||
} else {
|
||||
trx->n_mysql_tables_in_use--;
|
||||
|
||||
if (trx->n_mysql_tables_in_use == 0 &&
|
||||
!(thd->options
|
||||
& (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))) {
|
||||
innobase_commit(thd, trx);
|
||||
if (trx->n_mysql_tables_in_use == 0) {
|
||||
|
||||
trx->mysql_n_tables_locked = 0;
|
||||
|
||||
if (trx->has_search_latch) {
|
||||
|
||||
trx_search_latch_release_if_reserved(trx);
|
||||
}
|
||||
|
||||
if (!(thd->options
|
||||
& (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))) {
|
||||
innobase_commit(thd, trx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2690,6 +2705,39 @@ ha_innobase::info(
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
Tries to check that an InnoDB table is not corrupted. If corruption is
|
||||
noticed, prints to stderr information about it. In case of corruption
|
||||
may also assert a failure and crash the server. */
|
||||
|
||||
int
|
||||
ha_innobase::check(
|
||||
/*===============*/
|
||||
/* out: HA_ADMIN_CORRUPT or
|
||||
HA_ADMIN_OK */
|
||||
THD* thd, /* in: user thread handle */
|
||||
HA_CHECK_OPT* check_opt) /* in: check options, currently
|
||||
ignored */
|
||||
{
|
||||
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
|
||||
ulint ret;
|
||||
|
||||
if (prebuilt->mysql_template == NULL) {
|
||||
/* Build the template; we will use a dummy template
|
||||
in index scans done in checking */
|
||||
|
||||
build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW);
|
||||
}
|
||||
|
||||
ret = row_check_table_for_mysql(prebuilt);
|
||||
|
||||
if (ret == DB_SUCCESS) {
|
||||
return(HA_ADMIN_OK);
|
||||
}
|
||||
|
||||
return(HA_ADMIN_CORRUPT);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Adds information about free space in the InnoDB tablespace to a
|
||||
table comment which is printed out when a user calls SHOW TABLE STATUS. */
|
||||
|
@ -142,7 +142,7 @@ class ha_innobase: public handler
|
||||
HA_CREATE_INFO *create_info);
|
||||
int delete_table(const char *name);
|
||||
int rename_table(const char* from, const char* to);
|
||||
|
||||
int check(THD* thd, HA_CHECK_OPT* check_opt);
|
||||
char* update_table_comment(const char* comment);
|
||||
|
||||
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
|
||||
|
Reference in New Issue
Block a user