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:
|
Contact information of Innobase Oy, producer of the InnoDB engine:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
Website: www.innobase.fi
|
Website: www.innodb.com
|
||||||
Heikki.Tuuri@@innobase.inet.fi
|
Heikki.Tuuri@@innobase.inet.fi
|
||||||
phone: 358-9-6969 3250 (office) 358-40-5617367 (mobile)
|
phone: 358-9-6969 3250 (office) 358-40-5617367 (mobile)
|
||||||
InnoDB Oy Inc.
|
InnoDB Oy Inc.
|
||||||
|
@ -2238,12 +2238,93 @@ btr_check_node_ptr(
|
|||||||
return(TRUE);
|
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. */
|
Validates index tree level. */
|
||||||
static
|
static
|
||||||
void
|
ibool
|
||||||
btr_validate_level(
|
btr_validate_level(
|
||||||
/*===============*/
|
/*===============*/
|
||||||
|
/* out: TRUE if ok */
|
||||||
dict_tree_t* tree, /* in: index tree */
|
dict_tree_t* tree, /* in: index tree */
|
||||||
ulint level) /* in: level number */
|
ulint level) /* in: level number */
|
||||||
{
|
{
|
||||||
@ -2260,7 +2341,9 @@ btr_validate_level(
|
|||||||
page_cur_t cursor;
|
page_cur_t cursor;
|
||||||
mem_heap_t* heap;
|
mem_heap_t* heap;
|
||||||
dtuple_t* node_ptr_tuple;
|
dtuple_t* node_ptr_tuple;
|
||||||
|
ibool ret = TRUE;
|
||||||
|
dict_index_t* index;
|
||||||
|
|
||||||
mtr_start(&mtr);
|
mtr_start(&mtr);
|
||||||
|
|
||||||
page = btr_root_get(tree, &mtr);
|
page = btr_root_get(tree, &mtr);
|
||||||
@ -2278,13 +2361,31 @@ btr_validate_level(
|
|||||||
page = btr_node_ptr_get_child(node_ptr, &mtr);
|
page = btr_node_ptr_get_child(node_ptr, &mtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
index = UT_LIST_GET_FIRST(tree->tree_indexes);
|
||||||
|
|
||||||
/* Now we are on the desired level */
|
/* Now we are on the desired level */
|
||||||
loop:
|
loop:
|
||||||
mtr_x_lock(dict_tree_get_lock(tree), &mtr);
|
mtr_x_lock(dict_tree_get_lock(tree), &mtr);
|
||||||
|
|
||||||
/* Check ordering of records */
|
/* Check ordering etc. of records */
|
||||||
page_validate(page, UT_LIST_GET_FIRST(tree->tree_indexes));
|
|
||||||
|
|
||||||
|
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);
|
ut_a(btr_page_get_level(page, &mtr) == level);
|
||||||
|
|
||||||
right_page_no = btr_page_get_next(page, &mtr);
|
right_page_no = btr_page_get_next(page, &mtr);
|
||||||
@ -2374,14 +2475,17 @@ loop:
|
|||||||
|
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
Checks the consistency of an index tree. */
|
Checks the consistency of an index tree. */
|
||||||
|
|
||||||
void
|
ibool
|
||||||
btr_validate_tree(
|
btr_validate_tree(
|
||||||
/*==============*/
|
/*==============*/
|
||||||
|
/* out: TRUE if ok */
|
||||||
dict_tree_t* tree) /* in: tree */
|
dict_tree_t* tree) /* in: tree */
|
||||||
{
|
{
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
@ -2397,8 +2501,15 @@ btr_validate_tree(
|
|||||||
|
|
||||||
for (i = 0; i <= n; i++) {
|
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);
|
mtr_commit(&mtr);
|
||||||
|
|
||||||
|
return(TRUE);
|
||||||
}
|
}
|
||||||
|
@ -163,9 +163,14 @@ btr_cur_search_to_nth_level(
|
|||||||
BTR_INSERT and BTR_ESTIMATE;
|
BTR_INSERT and BTR_ESTIMATE;
|
||||||
cursor->left_page is used to store a pointer
|
cursor->left_page is used to store a pointer
|
||||||
to the left neighbor page, in the cases
|
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
|
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
|
ulint has_search_latch,/* in: info on the latch mode the
|
||||||
caller currently has on btr_search_latch:
|
caller currently has on btr_search_latch:
|
||||||
RW_S_LATCH, or 0 */
|
RW_S_LATCH, or 0 */
|
||||||
|
@ -601,7 +601,12 @@ btr_search_guess_on_hash(
|
|||||||
btr_search_t* info, /* in: index search info */
|
btr_search_t* info, /* in: index search info */
|
||||||
dtuple_t* tuple, /* in: logical record */
|
dtuple_t* tuple, /* in: logical record */
|
||||||
ulint mode, /* in: PAGE_CUR_L, ... */
|
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 */
|
btr_cur_t* cursor, /* out: tree cursor */
|
||||||
ulint has_search_latch,/* in: latch mode the caller
|
ulint has_search_latch,/* in: latch mode the caller
|
||||||
currently has on btr_search_latch:
|
currently has on btr_search_latch:
|
||||||
@ -722,7 +727,9 @@ btr_search_guess_on_hash(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
btr_leaf_page_release(page, latch_mode, mtr);
|
if (!has_search_latch) {
|
||||||
|
btr_leaf_page_release(page, latch_mode, mtr);
|
||||||
|
}
|
||||||
|
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
@ -376,9 +376,10 @@ btr_print_tree(
|
|||||||
/******************************************************************
|
/******************************************************************
|
||||||
Checks the consistency of an index tree. */
|
Checks the consistency of an index tree. */
|
||||||
|
|
||||||
void
|
ibool
|
||||||
btr_validate_tree(
|
btr_validate_tree(
|
||||||
/*==============*/
|
/*==============*/
|
||||||
|
/* out: TRUE if ok */
|
||||||
dict_tree_t* tree); /* in: tree */
|
dict_tree_t* tree); /* in: tree */
|
||||||
|
|
||||||
#define BTR_N_LEAF_PAGES 1
|
#define BTR_N_LEAF_PAGES 1
|
||||||
|
@ -98,12 +98,18 @@ btr_cur_search_to_nth_level(
|
|||||||
the previous page of the record! Inserts
|
the previous page of the record! Inserts
|
||||||
should always be made using PAGE_CUR_LE to
|
should always be made using PAGE_CUR_LE to
|
||||||
search the position! */
|
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
|
cursor->left_page is used to store a pointer
|
||||||
to the left neighbor page, in the cases
|
to the left neighbor page, in the cases
|
||||||
BTR_SEARCH_PREV and BTR_MODIFY_PREV */
|
BTR_SEARCH_PREV and BTR_MODIFY_PREV;
|
||||||
btr_cur_t* cursor, /* out: tree cursor; the cursor page is s- or
|
NOTE that if has_search_latch
|
||||||
x-latched */
|
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
|
ulint has_search_latch,/* in: latch mode the caller
|
||||||
currently has on btr_search_latch:
|
currently has on btr_search_latch:
|
||||||
RW_S_LATCH, or 0 */
|
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
|
PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
|
||||||
may end up on the previous page of the
|
may end up on the previous page of the
|
||||||
record! */
|
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 */
|
btr_pcur_t* cursor, /* in: memory buffer for persistent cursor */
|
||||||
ulint has_search_latch,/* in: latch mode the caller
|
ulint has_search_latch,/* in: latch mode the caller
|
||||||
currently has on btr_search_latch:
|
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
|
PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
|
||||||
may end up on the previous page of the
|
may end up on the previous page of the
|
||||||
record! */
|
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 */
|
btr_pcur_t* cursor, /* in: memory buffer for persistent cursor */
|
||||||
ulint has_search_latch,/* in: latch mode the caller
|
ulint has_search_latch,/* in: latch mode the caller
|
||||||
currently has on btr_search_latch:
|
currently has on btr_search_latch:
|
||||||
|
@ -229,6 +229,15 @@ row_rename_table_for_mysql(
|
|||||||
char* old_name, /* in: old table name */
|
char* old_name, /* in: old table name */
|
||||||
char* new_name, /* in: new table name */
|
char* new_name, /* in: new table name */
|
||||||
trx_t* trx); /* in: transaction handle */
|
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
|
/* A struct describing a place for an individual column in the MySQL
|
||||||
row format which is presented to the table handler in ha_innobase.
|
row format which is presented to the table handler in ha_innobase.
|
||||||
@ -281,7 +290,8 @@ struct row_prebuilt_struct {
|
|||||||
is set to TRUE */
|
is set to TRUE */
|
||||||
dict_index_t* index; /* current index for a search, if any */
|
dict_index_t* index; /* current index for a search, if any */
|
||||||
ulint template_type; /* ROW_MYSQL_WHOLE_ROW,
|
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 */
|
ROW_MYSQL_NO_TEMPLATE */
|
||||||
ulint n_template; /* number of elements in the
|
ulint n_template; /* number of elements in the
|
||||||
template */
|
template */
|
||||||
@ -359,6 +369,8 @@ struct row_prebuilt_struct {
|
|||||||
#define ROW_MYSQL_WHOLE_ROW 0
|
#define ROW_MYSQL_WHOLE_ROW 0
|
||||||
#define ROW_MYSQL_REC_FIELDS 1
|
#define ROW_MYSQL_REC_FIELDS 1
|
||||||
#define ROW_MYSQL_NO_TEMPLATE 2
|
#define ROW_MYSQL_NO_TEMPLATE 2
|
||||||
|
#define ROW_MYSQL_DUMMY_TEMPLATE 3 /* dummy template used in
|
||||||
|
row_scan_and_check_index */
|
||||||
|
|
||||||
#ifndef UNIV_NONINL
|
#ifndef UNIV_NONINL
|
||||||
#include "row0mysql.ic"
|
#include "row0mysql.ic"
|
||||||
|
@ -24,6 +24,13 @@ saving CPU time. The kernel mutex contention is increased, however. */
|
|||||||
|
|
||||||
extern ulint trx_n_mysql_transactions;
|
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. */
|
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
|
ulint n_mysql_tables_in_use; /* number of Innobase tables
|
||||||
used in the processing of the current
|
used in the processing of the current
|
||||||
SQL statement in MySQL */
|
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;
|
ibool ignore_duplicates_in_insert;
|
||||||
/* in an insert roll back only insert
|
/* in an insert roll back only insert
|
||||||
of the latest row in case
|
of the latest row in case
|
||||||
|
@ -1199,8 +1199,16 @@ page_rec_validate(
|
|||||||
n_owned = rec_get_n_owned(rec);
|
n_owned = rec_get_n_owned(rec);
|
||||||
heap_no = rec_get_heap_no(rec);
|
heap_no = rec_get_heap_no(rec);
|
||||||
|
|
||||||
ut_a(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED);
|
if (!(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED)) {
|
||||||
ut_a(heap_no < page_header_get_field(page, PAGE_N_HEAP));
|
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);
|
return(TRUE);
|
||||||
}
|
}
|
||||||
@ -1216,20 +1224,21 @@ page_validate(
|
|||||||
dict_index_t* index) /* in: data dictionary index containing
|
dict_index_t* index) /* in: data dictionary index containing
|
||||||
the page record type definition */
|
the page record type definition */
|
||||||
{
|
{
|
||||||
|
page_dir_slot_t* slot;
|
||||||
mem_heap_t* heap;
|
mem_heap_t* heap;
|
||||||
|
page_cur_t cur;
|
||||||
byte* buf;
|
byte* buf;
|
||||||
ulint i;
|
ulint i;
|
||||||
ulint count;
|
ulint count;
|
||||||
ulint own_count;
|
ulint own_count;
|
||||||
ulint slot_no;
|
ulint slot_no;
|
||||||
ulint data_size;
|
ulint data_size;
|
||||||
page_cur_t cur;
|
|
||||||
rec_t* rec;
|
rec_t* rec;
|
||||||
rec_t* old_rec = NULL;
|
rec_t* old_rec = NULL;
|
||||||
page_dir_slot_t* slot;
|
|
||||||
ulint offs;
|
ulint offs;
|
||||||
ulint n_slots;
|
ulint n_slots;
|
||||||
|
ibool ret = FALSE;
|
||||||
|
|
||||||
heap = mem_heap_create(UNIV_PAGE_SIZE);
|
heap = mem_heap_create(UNIV_PAGE_SIZE);
|
||||||
|
|
||||||
/* The following buffer is used to check that the
|
/* The following buffer is used to check that the
|
||||||
@ -1244,8 +1253,16 @@ page_validate(
|
|||||||
overlap. */
|
overlap. */
|
||||||
|
|
||||||
n_slots = page_dir_get_n_slots(page);
|
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
|
/* Validate the record list in a loop checking also that
|
||||||
it is consistent with the directory. */
|
it is consistent with the directory. */
|
||||||
@ -1259,11 +1276,20 @@ page_validate(
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
rec = (&cur)->rec;
|
rec = (&cur)->rec;
|
||||||
page_rec_validate(rec);
|
|
||||||
|
if (!page_rec_validate(rec)) {
|
||||||
|
goto func_exit;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check that the records are in the ascending order */
|
/* Check that the records are in the ascending order */
|
||||||
if ((count >= 2) && (!page_cur_is_after_last(&cur))) {
|
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))
|
if ((rec != page_get_supremum_rec(page))
|
||||||
@ -1275,16 +1301,38 @@ page_validate(
|
|||||||
offs = rec_get_start(rec) - page;
|
offs = rec_get_start(rec) - page;
|
||||||
|
|
||||||
for (i = 0; i < rec_get_size(rec); i++) {
|
for (i = 0; i < rec_get_size(rec); i++) {
|
||||||
ut_a(buf[offs + i] == 0); /* No other record may
|
if (!buf[offs + i] == 0) {
|
||||||
overlap this */
|
/* No other record may overlap this */
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"Record overlaps another in index %s \n",
|
||||||
|
index->name);
|
||||||
|
|
||||||
|
goto func_exit;
|
||||||
|
}
|
||||||
|
|
||||||
buf[offs + i] = 1;
|
buf[offs + i] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rec_get_n_owned(rec) != 0) {
|
if (rec_get_n_owned(rec) != 0) {
|
||||||
/* This is a record pointed to by a dir slot */
|
/* 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);
|
page_dir_slot_check(slot);
|
||||||
|
|
||||||
own_count = 0;
|
own_count = 0;
|
||||||
@ -1297,45 +1345,89 @@ page_validate(
|
|||||||
if (page_cur_is_after_last(&cur)) {
|
if (page_cur_is_after_last(&cur)) {
|
||||||
break;
|
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);
|
page_cur_move_to_next(&cur);
|
||||||
own_count++;
|
own_count++;
|
||||||
old_rec = rec;
|
old_rec = rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
ut_a(rec_get_n_owned(rec) != 0);
|
if (rec_get_n_owned(rec) == 0) {
|
||||||
ut_a(slot_no == n_slots - 1);
|
fprintf(stderr, "n owned is zero in index %s\n", index->name);
|
||||||
ut_a(page_header_get_field(page, PAGE_N_RECS) + 2 == count + 1);
|
|
||||||
|
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)) {
|
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));
|
data_size, page_get_data_size(page));
|
||||||
ut_error;
|
goto func_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check then the free list */
|
/* Check then the free list */
|
||||||
rec = page_header_get_ptr(page, PAGE_FREE);
|
rec = page_header_get_ptr(page, PAGE_FREE);
|
||||||
|
|
||||||
while (rec != NULL) {
|
while (rec != NULL) {
|
||||||
page_rec_validate(rec);
|
if (!page_rec_validate(rec)) {
|
||||||
|
|
||||||
|
goto func_exit;
|
||||||
|
}
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
offs = rec_get_start(rec) - page;
|
offs = rec_get_start(rec) - page;
|
||||||
|
|
||||||
for (i = 0; i < rec_get_size(rec); i++) {
|
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;
|
buf[offs + i] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rec = page_rec_get_next(rec);
|
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);
|
mem_heap_free(heap);
|
||||||
|
|
||||||
return(TRUE);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
|
@ -177,7 +177,9 @@ cmp_whole_field(
|
|||||||
(int)(type->prtype & ~DATA_NOT_NULL),
|
(int)(type->prtype & ~DATA_NOT_NULL),
|
||||||
a, a_length, b, b_length));
|
a, a_length, b, b_length));
|
||||||
default:
|
default:
|
||||||
assert(0);
|
fprintf(stderr,
|
||||||
|
"InnoDB: unknown type number %lu\n", data_type);
|
||||||
|
ut_a(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(0);
|
return(0);
|
||||||
|
@ -1129,3 +1129,146 @@ funct_exit:
|
|||||||
|
|
||||||
return((int) err);
|
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++;
|
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
|
Searches for rows in the database. This is used in the interface to
|
||||||
MySQL. This function opens a cursor, and also implements fetch next
|
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 cons_read_requires_clust_rec;
|
||||||
ibool was_lock_wait;
|
ibool was_lock_wait;
|
||||||
ulint ret;
|
ulint ret;
|
||||||
|
ulint shortcut;
|
||||||
ibool unique_search_from_clust_index = FALSE;
|
ibool unique_search_from_clust_index = FALSE;
|
||||||
ibool mtr_has_extra_clust_latch = FALSE;
|
ibool mtr_has_extra_clust_latch = FALSE;
|
||||||
ibool moves_up = FALSE;
|
ibool moves_up = FALSE;
|
||||||
@ -2452,6 +2512,8 @@ row_search_for_mysql(
|
|||||||
mode = pcur->search_mode;
|
mode = pcur->search_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mtr_start(&mtr);
|
||||||
|
|
||||||
if (match_mode == ROW_SEL_EXACT && index->type & DICT_UNIQUE
|
if (match_mode == ROW_SEL_EXACT && index->type & DICT_UNIQUE
|
||||||
&& index->type & DICT_CLUSTERED
|
&& index->type & DICT_CLUSTERED
|
||||||
&& dtuple_get_n_fields(search_tuple)
|
&& dtuple_get_n_fields(search_tuple)
|
||||||
@ -2464,6 +2526,8 @@ row_search_for_mysql(
|
|||||||
restore cursor position, and must return
|
restore cursor position, and must return
|
||||||
immediately */
|
immediately */
|
||||||
|
|
||||||
|
mtr_commit(&mtr);
|
||||||
|
|
||||||
return(DB_RECORD_NOT_FOUND);
|
return(DB_RECORD_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2472,8 +2536,51 @@ row_search_for_mysql(
|
|||||||
mode = PAGE_CUR_GE;
|
mode = PAGE_CUR_GE;
|
||||||
|
|
||||||
unique_search_from_clust_index = TRUE;
|
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
|
/* Note that if the search mode was GE or G, then the cursor
|
||||||
naturally moves upward (in fetch next) in alphabetical order,
|
naturally moves upward (in fetch next) in alphabetical order,
|
||||||
otherwise downward */
|
otherwise downward */
|
||||||
@ -2485,8 +2592,6 @@ row_search_for_mysql(
|
|||||||
} else if (direction == ROW_SEL_NEXT) {
|
} else if (direction == ROW_SEL_NEXT) {
|
||||||
moves_up = TRUE;
|
moves_up = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
mtr_start(&mtr);
|
|
||||||
|
|
||||||
thr = que_fork_get_first_thr(prebuilt->sel_graph);
|
thr = que_fork_get_first_thr(prebuilt->sel_graph);
|
||||||
|
|
||||||
@ -2711,7 +2816,9 @@ rec_loop:
|
|||||||
if (prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD
|
if (prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD
|
||||||
&& !prebuilt->templ_contains_blob
|
&& !prebuilt->templ_contains_blob
|
||||||
&& prebuilt->select_lock_type == LOCK_NONE
|
&& 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,
|
/* Inside an update, for example, we do not cache rows,
|
||||||
since we may use the cursor position to do the actual
|
since we may use the cursor position to do the actual
|
||||||
@ -2726,7 +2833,13 @@ rec_loop:
|
|||||||
|
|
||||||
goto next_rec;
|
goto next_rec;
|
||||||
} else {
|
} 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) {
|
if (prebuilt->clust_index_was_generated) {
|
||||||
row_sel_store_row_id_to_prebuilt(prebuilt, index_rec,
|
row_sel_store_row_id_to_prebuilt(prebuilt, index_rec,
|
||||||
|
@ -22,6 +22,7 @@ Created 3/26/1996 Heikki Tuuri
|
|||||||
#include "read0read.h"
|
#include "read0read.h"
|
||||||
#include "srv0srv.h"
|
#include "srv0srv.h"
|
||||||
#include "thr0loc.h"
|
#include "thr0loc.h"
|
||||||
|
#include "btr0sea.h"
|
||||||
|
|
||||||
/* Dummy session used currently in MySQL interface */
|
/* Dummy session used currently in MySQL interface */
|
||||||
sess_t* trx_dummy_sess = NULL;
|
sess_t* trx_dummy_sess = NULL;
|
||||||
@ -63,6 +64,7 @@ trx_create(
|
|||||||
trx->dict_operation = FALSE;
|
trx->dict_operation = FALSE;
|
||||||
|
|
||||||
trx->n_mysql_tables_in_use = 0;
|
trx->n_mysql_tables_in_use = 0;
|
||||||
|
trx->mysql_n_tables_locked = 0;
|
||||||
|
|
||||||
trx->ignore_duplicates_in_insert = FALSE;
|
trx->ignore_duplicates_in_insert = FALSE;
|
||||||
|
|
||||||
@ -96,6 +98,8 @@ trx_create(
|
|||||||
trx->lock_heap = mem_heap_create_in_buffer(256);
|
trx->lock_heap = mem_heap_create_in_buffer(256);
|
||||||
UT_LIST_INIT(trx->trx_locks);
|
UT_LIST_INIT(trx->trx_locks);
|
||||||
|
|
||||||
|
trx->has_search_latch = FALSE;
|
||||||
|
|
||||||
trx->read_view_heap = mem_heap_create(256);
|
trx->read_view_heap = mem_heap_create(256);
|
||||||
trx->read_view = NULL;
|
trx->read_view = NULL;
|
||||||
|
|
||||||
@ -132,6 +136,21 @@ trx_allocate_for_mysql(void)
|
|||||||
return(trx);
|
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. */
|
Frees a transaction object. */
|
||||||
|
|
||||||
@ -149,6 +168,7 @@ trx_free(
|
|||||||
ut_a(trx->update_undo == NULL);
|
ut_a(trx->update_undo == NULL);
|
||||||
|
|
||||||
ut_a(trx->n_mysql_tables_in_use == 0);
|
ut_a(trx->n_mysql_tables_in_use == 0);
|
||||||
|
ut_a(trx->mysql_n_tables_locked == 0);
|
||||||
|
|
||||||
if (trx->undo_no_arr) {
|
if (trx->undo_no_arr) {
|
||||||
trx_undo_arr_free(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(trx->wait_lock == NULL);
|
||||||
ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
|
ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
|
||||||
|
|
||||||
|
ut_a(!trx->has_search_latch);
|
||||||
|
|
||||||
if (trx->lock_heap) {
|
if (trx->lock_heap) {
|
||||||
mem_heap_free(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
|
a
|
||||||
2
|
2
|
||||||
Table Op Msg_type Msg_text
|
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
|
a b
|
||||||
2 testing
|
2 testing
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
|
@ -2142,6 +2142,7 @@ ha_innobase::external_lock(
|
|||||||
prebuilt->in_update_remember_pos = TRUE;
|
prebuilt->in_update_remember_pos = TRUE;
|
||||||
|
|
||||||
if (lock_type == F_WRLCK) {
|
if (lock_type == F_WRLCK) {
|
||||||
|
|
||||||
/* If this is a SELECT, then it is in UPDATE TABLE ...
|
/* If this is a SELECT, then it is in UPDATE TABLE ...
|
||||||
or SELECT ... FOR UPDATE */
|
or SELECT ... FOR UPDATE */
|
||||||
prebuilt->select_lock_type = LOCK_X;
|
prebuilt->select_lock_type = LOCK_X;
|
||||||
@ -2153,13 +2154,27 @@ ha_innobase::external_lock(
|
|||||||
}
|
}
|
||||||
|
|
||||||
trx->n_mysql_tables_in_use++;
|
trx->n_mysql_tables_in_use++;
|
||||||
|
|
||||||
|
if (prebuilt->select_lock_type != LOCK_NONE) {
|
||||||
|
|
||||||
|
trx->mysql_n_tables_locked++;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
trx->n_mysql_tables_in_use--;
|
trx->n_mysql_tables_in_use--;
|
||||||
|
|
||||||
if (trx->n_mysql_tables_in_use == 0 &&
|
if (trx->n_mysql_tables_in_use == 0) {
|
||||||
!(thd->options
|
|
||||||
& (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))) {
|
trx->mysql_n_tables_locked = 0;
|
||||||
innobase_commit(thd, trx);
|
|
||||||
|
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;
|
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
|
Adds information about free space in the InnoDB tablespace to a
|
||||||
table comment which is printed out when a user calls SHOW TABLE STATUS. */
|
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);
|
HA_CREATE_INFO *create_info);
|
||||||
int delete_table(const char *name);
|
int delete_table(const char *name);
|
||||||
int rename_table(const char* from, const char* to);
|
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);
|
char* update_table_comment(const char* comment);
|
||||||
|
|
||||||
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
|
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
|
||||||
|
Reference in New Issue
Block a user