mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
ut0mem.c Merge changes in InnoDB-3.23.43b
ut0ut.c Merge changes in InnoDB-3.23.43b trx0purge.c Merge changes in InnoDB-3.23.43b trx0rec.c Merge changes in InnoDB-3.23.43b trx0trx.c Merge changes in InnoDB-3.23.43b trx0undo.c Merge changes in InnoDB-3.23.43b thr0loc.c Merge changes in InnoDB-3.23.43b sync0arr.c Merge changes in InnoDB-3.23.43b sync0rw.c Merge changes in InnoDB-3.23.43b sync0sync.c Merge changes in InnoDB-3.23.43b srv0srv.c Merge changes in InnoDB-3.23.43b srv0start.c Merge changes in InnoDB-3.23.43b row0ins.c Merge changes in InnoDB-3.23.43b row0mysql.c Merge changes in InnoDB-3.23.43b row0purge.c Merge changes in InnoDB-3.23.43b row0sel.c Merge changes in InnoDB-3.23.43b row0umod.c Merge changes in InnoDB-3.23.43b row0upd.c Merge changes in InnoDB-3.23.43b row0vers.c Merge changes in InnoDB-3.23.43b rem0cmp.c Merge changes in InnoDB-3.23.43b que0que.c Merge changes in InnoDB-3.23.43b pars0opt.c Merge changes in InnoDB-3.23.43b pars0pars.c Merge changes in InnoDB-3.23.43b lexyy.c Merge changes in InnoDB-3.23.43b pars0grm.c Merge changes in InnoDB-3.23.43b page0page.c Merge changes in InnoDB-3.23.43b os0file.c Merge changes in InnoDB-3.23.43b mtr0log.c Merge changes in InnoDB-3.23.43b mem0pool.c Merge changes in InnoDB-3.23.43b log0log.c Merge changes in InnoDB-3.23.43b log0recv.c Merge changes in InnoDB-3.23.43b lock0lock.c Merge changes in InnoDB-3.23.43b ibuf0ibuf.c Merge changes in InnoDB-3.23.43b fil0fil.c Merge changes in InnoDB-3.23.43b dict0crea.c Merge changes in InnoDB-3.23.43b dict0dict.c Merge changes in InnoDB-3.23.43b dict0load.c Merge changes in InnoDB-3.23.43b dict0mem.c Merge changes in InnoDB-3.23.43b data0data.c Merge changes in InnoDB-3.23.43b data0type.c Merge changes in InnoDB-3.23.43b buf0buf.c Merge changes in InnoDB-3.23.43b buf0lru.c Merge changes in InnoDB-3.23.43b btr0btr.c Merge changes in InnoDB-3.23.43b btr0cur.c Merge changes in InnoDB-3.23.43b btr0pcur.c Merge changes in InnoDB-3.23.43b btr0sea.c Merge changes in InnoDB-3.23.43b data0type.ic Merge changes in InnoDB-3.23.43b dict0dict.ic Merge changes in InnoDB-3.23.43b mtr0mtr.ic Merge changes in InnoDB-3.23.43b row0upd.ic Merge changes in InnoDB-3.23.43b sync0ipm.ic Merge changes in InnoDB-3.23.43b sync0rw.ic Merge changes in InnoDB-3.23.43b sync0sync.ic Merge changes in InnoDB-3.23.43b trx0rseg.ic Merge changes in InnoDB-3.23.43b btr0pcur.ic Merge changes in InnoDB-3.23.43b buf0buf.ic Merge changes in InnoDB-3.23.43b data0data.ic Merge changes in InnoDB-3.23.43b row0upd.h Merge changes in InnoDB-3.23.43b srv0srv.h Merge changes in InnoDB-3.23.43b sync0arr.h Merge changes in InnoDB-3.23.43b sync0rw.h Merge changes in InnoDB-3.23.43b sync0sync.h Merge changes in InnoDB-3.23.43b trx0trx.h Merge changes in InnoDB-3.23.43b ut0mem.h Merge changes in InnoDB-3.23.43b data0data.h Merge changes in InnoDB-3.23.43b data0type.h Merge changes in InnoDB-3.23.43b db0err.h Merge changes in InnoDB-3.23.43b dict0crea.h Merge changes in InnoDB-3.23.43b dict0dict.h Merge changes in InnoDB-3.23.43b dict0load.h Merge changes in InnoDB-3.23.43b dict0mem.h Merge changes in InnoDB-3.23.43b dict0types.h Merge changes in InnoDB-3.23.43b fil0fil.h Merge changes in InnoDB-3.23.43b ibuf0ibuf.h Merge changes in InnoDB-3.23.43b lock0lock.h Merge changes in InnoDB-3.23.43b log0log.h Merge changes in InnoDB-3.23.43b mtr0mtr.h Merge changes in InnoDB-3.23.43b rem0cmp.h Merge changes in InnoDB-3.23.43b row0ins.h Merge changes in InnoDB-3.23.43b row0mysql.h Merge changes in InnoDB-3.23.43b btr0cur.h Merge changes in InnoDB-3.23.43b btr0pcur.h Merge changes in InnoDB-3.23.43b btr0sea.h Merge changes in InnoDB-3.23.43b buf0buf.h Merge changes in InnoDB-3.23.43b sql_table.cc Merge changes in InnoDB-3.23.43b sql_db.cc Merge changes in InnoDB-3.23.43b ha_innobase.cc Merge changes in InnoDB-3.23.43b handler.cc Merge changes in InnoDB-3.23.43b ha_innobase.h Merge changes in InnoDB-3.23.43b handler.h Merge changes in InnoDB-3.23.43b
This commit is contained in:
@@ -4,3 +4,4 @@ paul@central.snake.net
|
||||
serg@serg.mysql.com
|
||||
monty@work.mysql.com
|
||||
sasha@mysql.sashanet.com
|
||||
heikki@donna.mysql.fi
|
||||
|
@@ -2347,6 +2347,8 @@ btr_validate_level(
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
mtr_x_lock(dict_tree_get_lock(tree), &mtr);
|
||||
|
||||
page = btr_root_get(tree, &mtr);
|
||||
|
||||
space = buf_frame_get_space_id(page);
|
||||
|
@@ -256,7 +256,8 @@ btr_cur_search_to_nth_level(
|
||||
#ifdef UNIV_SEARCH_PERF_STAT
|
||||
info->n_searches++;
|
||||
#endif
|
||||
if (latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ
|
||||
if (btr_search_latch.writer != RW_LOCK_NOT_LOCKED
|
||||
&& latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ
|
||||
&& !estimate
|
||||
&& btr_search_guess_on_hash(index, info, tuple, mode,
|
||||
latch_mode, cursor,
|
||||
@@ -344,9 +345,7 @@ btr_cur_search_to_nth_level(
|
||||
retry_page_get:
|
||||
page = buf_page_get_gen(space, page_no, rw_latch, guess,
|
||||
buf_mode,
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
IB__FILE__, __LINE__,
|
||||
#endif
|
||||
mtr);
|
||||
|
||||
if (page == NULL) {
|
||||
@@ -515,9 +514,7 @@ btr_cur_open_at_index_side(
|
||||
for (;;) {
|
||||
page = buf_page_get_gen(space, page_no, RW_NO_LATCH, NULL,
|
||||
BUF_GET,
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
IB__FILE__, __LINE__,
|
||||
#endif
|
||||
mtr);
|
||||
ut_ad(0 == ut_dulint_cmp(tree->id,
|
||||
btr_page_get_index_id(page)));
|
||||
@@ -604,9 +601,7 @@ btr_cur_open_at_rnd_pos(
|
||||
for (;;) {
|
||||
page = buf_page_get_gen(space, page_no, RW_NO_LATCH, NULL,
|
||||
BUF_GET,
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
IB__FILE__, __LINE__,
|
||||
#endif
|
||||
mtr);
|
||||
ut_ad(0 == ut_dulint_cmp(tree->id,
|
||||
btr_page_get_index_id(page)));
|
||||
@@ -1222,6 +1217,57 @@ btr_cur_parse_update_in_place(
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Updates a secondary index record when the update causes no size
|
||||
changes in its fields. The only case when this function is currently
|
||||
called is that in a char field characters change to others which
|
||||
are identified in the collation order. */
|
||||
|
||||
ulint
|
||||
btr_cur_update_sec_rec_in_place(
|
||||
/*============================*/
|
||||
/* out: DB_SUCCESS or error number */
|
||||
btr_cur_t* cursor, /* in: cursor on the record to update;
|
||||
cursor stays valid and positioned on the
|
||||
same record */
|
||||
upd_t* update, /* in: update vector */
|
||||
que_thr_t* thr, /* in: query thread */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
dict_index_t* index = cursor->index;
|
||||
dict_index_t* clust_index;
|
||||
ulint err;
|
||||
rec_t* rec;
|
||||
dulint roll_ptr = ut_dulint_zero;
|
||||
trx_t* trx = thr_get_trx(thr);
|
||||
|
||||
/* Only secondary index records are updated using this function */
|
||||
ut_ad(0 == (index->type & DICT_CLUSTERED));
|
||||
|
||||
rec = btr_cur_get_rec(cursor);
|
||||
|
||||
err = lock_sec_rec_modify_check_and_lock(0, rec, index, thr);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
/* Remove possible hash index pointer to this record */
|
||||
btr_search_update_hash_on_delete(cursor);
|
||||
|
||||
row_upd_rec_in_place(rec, update);
|
||||
|
||||
clust_index = dict_table_get_first_index(index->table);
|
||||
|
||||
/* Note that roll_ptr is really just a dummy value since
|
||||
a secondary index record does not contain any sys columns */
|
||||
|
||||
btr_cur_update_in_place_log(BTR_KEEP_SYS_FLAG, rec, clust_index,
|
||||
update, trx, roll_ptr, mtr);
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Updates a record when the update causes no size changes in its fields. */
|
||||
|
||||
@@ -1248,7 +1294,7 @@ btr_cur_update_in_place(
|
||||
ibool was_delete_marked;
|
||||
|
||||
/* Only clustered index records are updated using this function */
|
||||
ut_ad((cursor->index)->type & DICT_CLUSTERED);
|
||||
ut_ad(cursor->index->type & DICT_CLUSTERED);
|
||||
|
||||
rec = btr_cur_get_rec(cursor);
|
||||
index = cursor->index;
|
||||
@@ -2477,27 +2523,33 @@ btr_estimate_n_rows_in_range(
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
Estimates the number of different key values in a given index. */
|
||||
Estimates the number of different key values in a given index, for
|
||||
each n-column prefix of the index where n <= dict_index_get_n_unique(index).
|
||||
The estimates are stored in the array index->stat_n_diff_key_vals. */
|
||||
|
||||
ulint
|
||||
void
|
||||
btr_estimate_number_of_different_key_vals(
|
||||
/*======================================*/
|
||||
/* out: estimated number of key values */
|
||||
dict_index_t* index) /* in: index */
|
||||
{
|
||||
btr_cur_t cursor;
|
||||
page_t* page;
|
||||
rec_t* rec;
|
||||
ulint total_n_recs = 0;
|
||||
ulint n_diff_in_page;
|
||||
ulint n_diff = 0;
|
||||
ulint n_cols;
|
||||
ulint matched_fields;
|
||||
ulint matched_bytes;
|
||||
ulint* n_diff;
|
||||
ulint not_empty_flag = 0;
|
||||
ulint i;
|
||||
ulint j;
|
||||
mtr_t mtr;
|
||||
|
||||
if (index->type & DICT_UNIQUE) {
|
||||
return(index->table->stat_n_rows);
|
||||
n_cols = dict_index_get_n_unique(index);
|
||||
|
||||
n_diff = mem_alloc((n_cols + 1) * sizeof(ib_longlong));
|
||||
|
||||
for (j = 0; j <= n_cols; j++) {
|
||||
n_diff[j] = 0;
|
||||
}
|
||||
|
||||
/* We sample some pages in the index to get an estimate */
|
||||
@@ -2507,17 +2559,19 @@ btr_estimate_number_of_different_key_vals(
|
||||
|
||||
btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr);
|
||||
|
||||
/* Count the number of different key values minus one on this
|
||||
index page: we subtract one because otherwise our algorithm
|
||||
would give a wrong estimate for an index where there is
|
||||
just one key value */
|
||||
/* Count the number of different key values minus one
|
||||
for each prefix of the key on this index page: we subtract
|
||||
one because otherwise our algorithm would give a wrong
|
||||
estimate for an index where there is just one key value */
|
||||
|
||||
page = btr_cur_get_page(&cursor);
|
||||
|
||||
rec = page_get_infimum_rec(page);
|
||||
rec = page_rec_get_next(rec);
|
||||
|
||||
n_diff_in_page = 0;
|
||||
if (rec != page_get_supremum_rec(page)) {
|
||||
not_empty_flag = 1;
|
||||
}
|
||||
|
||||
while (rec != page_get_supremum_rec(page)
|
||||
&& page_rec_get_next(rec)
|
||||
@@ -2528,30 +2582,30 @@ btr_estimate_number_of_different_key_vals(
|
||||
cmp_rec_rec_with_match(rec, page_rec_get_next(rec),
|
||||
index, &matched_fields,
|
||||
&matched_bytes);
|
||||
if (matched_fields <
|
||||
dict_index_get_n_ordering_defined_by_user(
|
||||
index)) {
|
||||
n_diff_in_page++;
|
||||
|
||||
for (j = matched_fields + 1; j <= n_cols; j++) {
|
||||
n_diff[j]++;
|
||||
}
|
||||
|
||||
rec = page_rec_get_next(rec);
|
||||
}
|
||||
|
||||
n_diff += n_diff_in_page;
|
||||
|
||||
total_n_recs += page_get_n_recs(page);
|
||||
|
||||
mtr_commit(&mtr);
|
||||
}
|
||||
|
||||
if (n_diff == 0) {
|
||||
/* We play safe and assume that there are just two different
|
||||
key values in the index */
|
||||
/* If we saw k borders between different key values on
|
||||
BTR_KEY_VAL_ESTIMATE_N_PAGES leaf pages, we can estimate how many
|
||||
there will be in index->stat_n_leaf_pages */
|
||||
|
||||
return(2);
|
||||
for (j = 0; j <= n_cols; j++) {
|
||||
index->stat_n_diff_key_vals[j] =
|
||||
(n_diff[j] * index->stat_n_leaf_pages
|
||||
+ BTR_KEY_VAL_ESTIMATE_N_PAGES - 1
|
||||
+ not_empty_flag)
|
||||
/ BTR_KEY_VAL_ESTIMATE_N_PAGES;
|
||||
}
|
||||
|
||||
return(index->table->stat_n_rows / (total_n_recs / n_diff));
|
||||
mem_free(n_diff);
|
||||
}
|
||||
|
||||
/*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/
|
||||
|
@@ -62,8 +62,10 @@ btr_pcur_free_for_mysql(
|
||||
/******************************************************************
|
||||
The position of the cursor is stored by taking an initial segment of the
|
||||
record the cursor is positioned on, before, or after, and copying it to the
|
||||
cursor data structure. NOTE that the page where the cursor is positioned
|
||||
must not be empty! */
|
||||
cursor data structure, or just setting a flag if the cursor id before the
|
||||
first in an EMPTY tree, or after the last in an EMPTY tree. NOTE that the
|
||||
page where the cursor is positioned must not be empty if the index tree is
|
||||
not totally empty! */
|
||||
|
||||
void
|
||||
btr_pcur_store_position(
|
||||
@@ -93,9 +95,21 @@ btr_pcur_store_position(
|
||||
ut_a(cursor->latch_mode != BTR_NO_LATCHES);
|
||||
|
||||
if (page_get_n_recs(page) == 0) {
|
||||
/* It must be an empty index tree */
|
||||
|
||||
/* Cannot store position! */
|
||||
btr_pcur_close(cursor);
|
||||
ut_a(btr_page_get_next(page, mtr) == FIL_NULL
|
||||
&& btr_page_get_prev(page, mtr) == FIL_NULL);
|
||||
|
||||
if (rec == page_get_supremum_rec(page)) {
|
||||
|
||||
cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
|
||||
cursor->old_stored = BTR_PCUR_OLD_STORED;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cursor->rel_pos = BTR_PCUR_BEFORE_FIRST_IN_TREE;
|
||||
cursor->old_stored = BTR_PCUR_OLD_STORED;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -140,13 +154,15 @@ btr_pcur_copy_stored_position(
|
||||
|
||||
ut_memcpy((byte*)pcur_receive, (byte*)pcur_donate, sizeof(btr_pcur_t));
|
||||
|
||||
if (pcur_donate->old_rec_buf) {
|
||||
|
||||
pcur_receive->old_rec_buf = mem_alloc(pcur_donate->buf_size);
|
||||
|
||||
ut_memcpy(pcur_receive->old_rec_buf, pcur_donate->old_rec_buf,
|
||||
pcur_donate->buf_size);
|
||||
pcur_receive->old_rec = pcur_receive->old_rec_buf
|
||||
+ (pcur_donate->old_rec - pcur_donate->old_rec_buf);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
@@ -158,7 +174,9 @@ to the last record LESS OR EQUAL to the stored record;
|
||||
the last record LESS than the user record which was the successor of the page
|
||||
infimum;
|
||||
(3) cursor was positioned on the page supremum: restores to the first record
|
||||
GREATER than the user record which was the predecessor of the supremum. */
|
||||
GREATER than the user record which was the predecessor of the supremum.
|
||||
(4) cursor was positioned before the first or after the last in an empty tree:
|
||||
restores to before first or after the last in the tree. */
|
||||
|
||||
ibool
|
||||
btr_pcur_restore_position(
|
||||
@@ -177,17 +195,33 @@ btr_pcur_restore_position(
|
||||
dtuple_t* tuple;
|
||||
ulint mode;
|
||||
ulint old_mode;
|
||||
ibool from_left;
|
||||
mem_heap_t* heap;
|
||||
|
||||
ut_a((cursor->pos_state == BTR_PCUR_WAS_POSITIONED)
|
||||
|| (cursor->pos_state == BTR_PCUR_IS_POSITIONED));
|
||||
ut_a(cursor->pos_state == BTR_PCUR_WAS_POSITIONED
|
||||
|| cursor->pos_state == BTR_PCUR_IS_POSITIONED);
|
||||
ut_a(cursor->old_stored == BTR_PCUR_OLD_STORED);
|
||||
|
||||
if (cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
|
||||
|| cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) {
|
||||
|
||||
if (cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) {
|
||||
from_left = TRUE;
|
||||
} else {
|
||||
from_left = FALSE;
|
||||
}
|
||||
|
||||
btr_cur_open_at_index_side(from_left,
|
||||
btr_pcur_get_btr_cur(cursor)->index, latch_mode,
|
||||
btr_pcur_get_btr_cur(cursor), mtr);
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
ut_a(cursor->old_rec);
|
||||
|
||||
page = btr_cur_get_page(btr_pcur_get_btr_cur(cursor));
|
||||
|
||||
if ((latch_mode == BTR_SEARCH_LEAF)
|
||||
|| (latch_mode == BTR_MODIFY_LEAF)) {
|
||||
if (latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF) {
|
||||
/* Try optimistic restoration */
|
||||
|
||||
if (buf_page_optimistic_get(latch_mode, page,
|
||||
@@ -242,16 +276,15 @@ btr_pcur_restore_position(
|
||||
/* Restore the old search mode */
|
||||
cursor->search_mode = old_mode;
|
||||
|
||||
if ((cursor->rel_pos == BTR_PCUR_ON)
|
||||
if (cursor->rel_pos == BTR_PCUR_ON
|
||||
&& btr_pcur_is_on_user_rec(cursor, mtr)
|
||||
&& (0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor)))) {
|
||||
&& 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor))) {
|
||||
|
||||
/* We have to store the NEW value for the modify clock, since
|
||||
the cursor can now be on a different page! */
|
||||
|
||||
cursor->modify_clock = buf_frame_get_modify_clock(
|
||||
buf_frame_align(
|
||||
btr_pcur_get_rec(cursor)));
|
||||
buf_frame_align(btr_pcur_get_rec(cursor)));
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(TRUE);
|
||||
@@ -366,6 +399,7 @@ btr_pcur_move_backward_from_page(
|
||||
|
||||
latch_mode2 = BTR_MODIFY_PREV;
|
||||
} else {
|
||||
latch_mode2 = 0; /* To eliminate compiler warning */
|
||||
ut_error;
|
||||
}
|
||||
|
||||
|
@@ -680,9 +680,7 @@ btr_search_guess_on_hash(
|
||||
|
||||
success = buf_page_get_known_nowait(latch_mode, page,
|
||||
BUF_MAKE_YOUNG,
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
IB__FILE__, __LINE__,
|
||||
#endif
|
||||
mtr);
|
||||
|
||||
rw_lock_s_unlock(&btr_search_latch);
|
||||
|
@@ -34,6 +34,8 @@ Created 11/5/1995 Heikki Tuuri
|
||||
#include "ibuf0ibuf.h"
|
||||
#include "dict0dict.h"
|
||||
#include "log0recv.h"
|
||||
#include "trx0undo.h"
|
||||
#include "srv0srv.h"
|
||||
|
||||
/*
|
||||
IMPLEMENTATION OF THE BUFFER POOL
|
||||
@@ -240,6 +242,11 @@ buf_page_is_corrupted(
|
||||
|
||||
checksum = buf_calc_page_checksum(read_buf);
|
||||
|
||||
/* Note that InnoDB initializes empty pages to zero, and
|
||||
early versions of InnoDB did not store page checksum to
|
||||
the 4 most significant bytes of the page lsn field at the
|
||||
end of a page: */
|
||||
|
||||
if ((mach_read_from_4(read_buf + FIL_PAGE_LSN + 4)
|
||||
!= mach_read_from_4(read_buf + UNIV_PAGE_SIZE
|
||||
- FIL_PAGE_END_LSN + 4))
|
||||
@@ -256,6 +263,71 @@ buf_page_is_corrupted(
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Prints a page to stderr. */
|
||||
|
||||
void
|
||||
buf_page_print(
|
||||
/*===========*/
|
||||
byte* read_buf) /* in: a database page */
|
||||
{
|
||||
dict_index_t* index;
|
||||
ulint checksum;
|
||||
char* buf;
|
||||
|
||||
buf = mem_alloc(4 * UNIV_PAGE_SIZE);
|
||||
|
||||
ut_sprintf_buf(buf, read_buf, UNIV_PAGE_SIZE);
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Page dump in ascii and hex (%lu bytes):\n%s",
|
||||
UNIV_PAGE_SIZE, buf);
|
||||
fprintf(stderr, "InnoDB: End of page dump\n");
|
||||
|
||||
mem_free(buf);
|
||||
|
||||
checksum = buf_calc_page_checksum(read_buf);
|
||||
|
||||
fprintf(stderr, "InnoDB: Page checksum %lu stored checksum %lu\n",
|
||||
checksum, mach_read_from_4(read_buf
|
||||
+ UNIV_PAGE_SIZE
|
||||
- FIL_PAGE_END_LSN));
|
||||
fprintf(stderr,
|
||||
"InnoDB: Page lsn %lu %lu, low 4 bytes of lsn at page end %lu\n",
|
||||
mach_read_from_4(read_buf + FIL_PAGE_LSN),
|
||||
mach_read_from_4(read_buf + FIL_PAGE_LSN + 4),
|
||||
mach_read_from_4(read_buf + UNIV_PAGE_SIZE
|
||||
- FIL_PAGE_END_LSN + 4));
|
||||
if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE)
|
||||
== TRX_UNDO_INSERT) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Page may be an insert undo log page\n");
|
||||
} else if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR
|
||||
+ TRX_UNDO_PAGE_TYPE)
|
||||
== TRX_UNDO_UPDATE) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Page may be an update undo log page\n");
|
||||
}
|
||||
|
||||
if (fil_page_get_type(read_buf) == FIL_PAGE_INDEX) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Page may be an index page ");
|
||||
|
||||
fprintf(stderr,
|
||||
"where index id is %lu %lu\n",
|
||||
ut_dulint_get_high(btr_page_get_index_id(read_buf)),
|
||||
ut_dulint_get_low(btr_page_get_index_id(read_buf)));
|
||||
|
||||
index = dict_index_find_on_id_low(
|
||||
btr_page_get_index_id(read_buf));
|
||||
if (index) {
|
||||
fprintf(stderr, "InnoDB: and table %s index %s\n",
|
||||
index->table_name,
|
||||
index->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Initializes a buffer control block when the buf_pool is created. */
|
||||
static
|
||||
@@ -334,6 +406,8 @@ buf_pool_create(
|
||||
frame = ut_align(buf_pool->frame_mem, UNIV_PAGE_SIZE);
|
||||
buf_pool->frame_zero = frame;
|
||||
|
||||
buf_pool->high_end = frame + UNIV_PAGE_SIZE * curr_size;
|
||||
|
||||
/* Init block structs and assign frames for them */
|
||||
for (i = 0; i < max_size; i++) {
|
||||
|
||||
@@ -345,6 +419,9 @@ buf_pool_create(
|
||||
buf_pool->page_hash = hash_create(2 * max_size);
|
||||
|
||||
buf_pool->n_pend_reads = 0;
|
||||
|
||||
buf_pool->last_printout_time = time(NULL);
|
||||
|
||||
buf_pool->n_pages_read = 0;
|
||||
buf_pool->n_pages_written = 0;
|
||||
buf_pool->n_pages_created = 0;
|
||||
@@ -352,6 +429,8 @@ buf_pool_create(
|
||||
buf_pool->n_page_gets = 0;
|
||||
buf_pool->n_page_gets_old = 0;
|
||||
buf_pool->n_pages_read_old = 0;
|
||||
buf_pool->n_pages_written_old = 0;
|
||||
buf_pool->n_pages_created_old = 0;
|
||||
|
||||
/* 2. Initialize flushing fields
|
||||
---------------------------- */
|
||||
@@ -379,6 +458,10 @@ buf_pool_create(
|
||||
for (i = 0; i < curr_size; i++) {
|
||||
|
||||
block = buf_pool_get_nth_block(buf_pool, i);
|
||||
|
||||
/* Wipe contents of page to eliminate a Purify warning */
|
||||
memset(block->frame, '\0', UNIV_PAGE_SIZE);
|
||||
|
||||
UT_LIST_ADD_FIRST(free, buf_pool->free, block);
|
||||
}
|
||||
|
||||
@@ -650,10 +733,8 @@ buf_page_get_gen(
|
||||
buf_frame_t* guess, /* in: guessed frame or NULL */
|
||||
ulint mode, /* in: BUF_GET, BUF_GET_IF_IN_POOL,
|
||||
BUF_GET_NO_LATCH, BUF_GET_NOWAIT */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
char* file, /* in: file name */
|
||||
ulint line, /* in: line where called */
|
||||
#endif
|
||||
mtr_t* mtr) /* in: mini-transaction */
|
||||
{
|
||||
buf_block_t* block;
|
||||
@@ -759,19 +840,13 @@ loop:
|
||||
|
||||
if (mode == BUF_GET_NOWAIT) {
|
||||
if (rw_latch == RW_S_LATCH) {
|
||||
success = rw_lock_s_lock_func_nowait(&(block->lock)
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,file, line
|
||||
#endif
|
||||
);
|
||||
success = rw_lock_s_lock_func_nowait(&(block->lock),
|
||||
file, line);
|
||||
fix_type = MTR_MEMO_PAGE_S_FIX;
|
||||
} else {
|
||||
ut_ad(rw_latch == RW_X_LATCH);
|
||||
success = rw_lock_x_lock_func_nowait(&(block->lock)
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,file, line
|
||||
#endif
|
||||
);
|
||||
success = rw_lock_x_lock_func_nowait(&(block->lock),
|
||||
file, line);
|
||||
fix_type = MTR_MEMO_PAGE_X_FIX;
|
||||
}
|
||||
|
||||
@@ -796,18 +871,12 @@ loop:
|
||||
fix_type = MTR_MEMO_BUF_FIX;
|
||||
} else if (rw_latch == RW_S_LATCH) {
|
||||
|
||||
rw_lock_s_lock_func(&(block->lock)
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,0, file, line
|
||||
#endif
|
||||
);
|
||||
rw_lock_s_lock_func(&(block->lock), 0, file, line);
|
||||
|
||||
fix_type = MTR_MEMO_PAGE_S_FIX;
|
||||
} else {
|
||||
rw_lock_x_lock_func(&(block->lock), 0
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
, file, line
|
||||
#endif
|
||||
);
|
||||
rw_lock_x_lock_func(&(block->lock), 0, file, line);
|
||||
|
||||
fix_type = MTR_MEMO_PAGE_X_FIX;
|
||||
}
|
||||
|
||||
@@ -838,10 +907,8 @@ buf_page_optimistic_get_func(
|
||||
buf_frame_t* guess, /* in: guessed frame */
|
||||
dulint modify_clock,/* in: modify clock value if mode is
|
||||
..._GUESS_ON_CLOCK */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
char* file, /* in: file name */
|
||||
ulint line, /* in: line where called */
|
||||
#endif
|
||||
mtr_t* mtr) /* in: mini-transaction */
|
||||
{
|
||||
buf_block_t* block;
|
||||
@@ -883,18 +950,12 @@ buf_page_optimistic_get_func(
|
||||
ut_ad(!ibuf_inside() || ibuf_page(block->space, block->offset));
|
||||
|
||||
if (rw_latch == RW_S_LATCH) {
|
||||
success = rw_lock_s_lock_func_nowait(&(block->lock)
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
, file, line
|
||||
#endif
|
||||
);
|
||||
success = rw_lock_s_lock_func_nowait(&(block->lock),
|
||||
file, line);
|
||||
fix_type = MTR_MEMO_PAGE_S_FIX;
|
||||
} else {
|
||||
success = rw_lock_x_lock_func_nowait(&(block->lock)
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
, file, line
|
||||
#endif
|
||||
);
|
||||
success = rw_lock_x_lock_func_nowait(&(block->lock),
|
||||
file, line);
|
||||
fix_type = MTR_MEMO_PAGE_X_FIX;
|
||||
}
|
||||
|
||||
@@ -971,10 +1032,8 @@ buf_page_get_known_nowait(
|
||||
ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */
|
||||
buf_frame_t* guess, /* in: the known page frame */
|
||||
ulint mode, /* in: BUF_MAKE_YOUNG or BUF_KEEP_OLD */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
char* file, /* in: file name */
|
||||
ulint line, /* in: line where called */
|
||||
#endif
|
||||
mtr_t* mtr) /* in: mini-transaction */
|
||||
{
|
||||
buf_block_t* block;
|
||||
@@ -1017,18 +1076,12 @@ buf_page_get_known_nowait(
|
||||
ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD));
|
||||
|
||||
if (rw_latch == RW_S_LATCH) {
|
||||
success = rw_lock_s_lock_func_nowait(&(block->lock)
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
, file, line
|
||||
#endif
|
||||
);
|
||||
success = rw_lock_s_lock_func_nowait(&(block->lock),
|
||||
file, line);
|
||||
fix_type = MTR_MEMO_PAGE_S_FIX;
|
||||
} else {
|
||||
success = rw_lock_x_lock_func_nowait(&(block->lock)
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
, file, line
|
||||
#endif
|
||||
);
|
||||
success = rw_lock_x_lock_func_nowait(&(block->lock),
|
||||
file, line);
|
||||
fix_type = MTR_MEMO_PAGE_X_FIX;
|
||||
}
|
||||
|
||||
@@ -1318,10 +1371,27 @@ buf_page_io_complete(
|
||||
fprintf(stderr,
|
||||
"InnoDB: Database page corruption or a failed\n"
|
||||
"InnoDB: file read of page %lu.\n", block->offset);
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: You may have to recover from a backup.\n");
|
||||
|
||||
buf_page_print(block->frame);
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Database page corruption or a failed\n"
|
||||
"InnoDB: file read of page %lu.\n", block->offset);
|
||||
fprintf(stderr,
|
||||
"InnoDB: You may have to recover from a backup.\n");
|
||||
fprintf(stderr,
|
||||
"InnoDB: It is also possible that your operating\n"
|
||||
"InnoDB: system has corrupted its own file cache\n"
|
||||
"InnoDB: and rebooting your computer removes the\n"
|
||||
"InnoDB: error.\n");
|
||||
|
||||
if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (recv_recovery_is_on()) {
|
||||
recv_recover_page(TRUE, block->frame, block->space,
|
||||
@@ -1622,6 +1692,19 @@ buf_print(void)
|
||||
ut_a(buf_validate());
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Returns the number of pending buf pool ios. */
|
||||
|
||||
ulint
|
||||
buf_get_n_pending_ios(void)
|
||||
/*=======================*/
|
||||
{
|
||||
return(buf_pool->n_pend_reads
|
||||
+ buf_pool->n_flush[BUF_FLUSH_LRU]
|
||||
+ buf_pool->n_flush[BUF_FLUSH_LIST]
|
||||
+ buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Prints info of the buffer i/o. */
|
||||
|
||||
@@ -1629,6 +1712,8 @@ void
|
||||
buf_print_io(void)
|
||||
/*==============*/
|
||||
{
|
||||
time_t current_time;
|
||||
double time_elapsed;
|
||||
ulint size;
|
||||
|
||||
ut_ad(buf_pool);
|
||||
@@ -1637,11 +1722,11 @@ buf_print_io(void)
|
||||
|
||||
mutex_enter(&(buf_pool->mutex));
|
||||
|
||||
printf("LRU list length %lu \n", UT_LIST_GET_LEN(buf_pool->LRU));
|
||||
printf("Free list length %lu \n", UT_LIST_GET_LEN(buf_pool->free));
|
||||
printf("LRU list length %lu \n", UT_LIST_GET_LEN(buf_pool->LRU));
|
||||
printf("Flush list length %lu \n",
|
||||
UT_LIST_GET_LEN(buf_pool->flush_list));
|
||||
printf("Buffer pool size in pages %lu\n", size);
|
||||
printf("Buffer pool size %lu\n", size);
|
||||
|
||||
printf("Pending reads %lu \n", buf_pool->n_pend_reads);
|
||||
|
||||
@@ -1650,9 +1735,21 @@ buf_print_io(void)
|
||||
buf_pool->n_flush[BUF_FLUSH_LIST],
|
||||
buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
|
||||
|
||||
current_time = time(NULL);
|
||||
time_elapsed = difftime(current_time, buf_pool->last_printout_time);
|
||||
|
||||
buf_pool->last_printout_time = current_time;
|
||||
|
||||
printf("Pages read %lu, created %lu, written %lu\n",
|
||||
buf_pool->n_pages_read, buf_pool->n_pages_created,
|
||||
buf_pool->n_pages_written);
|
||||
printf("%.2f reads/s, %.2f creates/s, %.2f writes/s\n",
|
||||
(buf_pool->n_pages_read - buf_pool->n_pages_read_old)
|
||||
/ time_elapsed,
|
||||
(buf_pool->n_pages_created - buf_pool->n_pages_created_old)
|
||||
/ time_elapsed,
|
||||
(buf_pool->n_pages_written - buf_pool->n_pages_written_old)
|
||||
/ time_elapsed);
|
||||
|
||||
if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) {
|
||||
printf("Buffer pool hit rate %lu / 1000\n",
|
||||
@@ -1660,10 +1757,14 @@ buf_print_io(void)
|
||||
- ((1000 *
|
||||
(buf_pool->n_pages_read - buf_pool->n_pages_read_old))
|
||||
/ (buf_pool->n_page_gets - buf_pool->n_page_gets_old)));
|
||||
} else {
|
||||
printf("No buffer pool activity since the last printout\n");
|
||||
}
|
||||
|
||||
buf_pool->n_page_gets_old = buf_pool->n_page_gets;
|
||||
buf_pool->n_pages_read_old = buf_pool->n_pages_read;
|
||||
buf_pool->n_pages_created_old = buf_pool->n_pages_created;
|
||||
buf_pool->n_pages_written_old = buf_pool->n_pages_written;
|
||||
|
||||
mutex_exit(&(buf_pool->mutex));
|
||||
}
|
||||
|
@@ -551,6 +551,10 @@ buf_LRU_block_free_non_file_page(
|
||||
|
||||
block->state = BUF_BLOCK_NOT_USED;
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
/* Wipe contents of page to reveal possible stale pointers to it */
|
||||
memset(block->frame, '\0', UNIV_PAGE_SIZE);
|
||||
#endif
|
||||
UT_LIST_ADD_FIRST(free, buf_pool->free, block);
|
||||
}
|
||||
|
||||
|
@@ -14,6 +14,7 @@ Created 5/30/1994 Heikki Tuuri
|
||||
|
||||
#include "ut0rnd.h"
|
||||
#include "rem0rec.h"
|
||||
#include "rem0cmp.h"
|
||||
#include "page0page.h"
|
||||
#include "dict0dict.h"
|
||||
#include "btr0cur.h"
|
||||
@@ -63,6 +64,53 @@ dtuple_get_nth_field_noninline(
|
||||
return(dtuple_get_nth_field(tuple, n));
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Returns TRUE if lengths of two dtuples are equal and respective data fields
|
||||
in them are equal when compared with collation in char fields (not as binary
|
||||
strings). */
|
||||
|
||||
ibool
|
||||
dtuple_datas_are_ordering_equal(
|
||||
/*============================*/
|
||||
/* out: TRUE if length and fieds are equal
|
||||
when compared with cmp_data_data:
|
||||
NOTE: in character type fields some letters
|
||||
are identified with others! (collation) */
|
||||
dtuple_t* tuple1, /* in: tuple 1 */
|
||||
dtuple_t* tuple2) /* in: tuple 2 */
|
||||
{
|
||||
dfield_t* field1;
|
||||
dfield_t* field2;
|
||||
ulint n_fields;
|
||||
ulint i;
|
||||
|
||||
ut_ad(tuple1 && tuple2);
|
||||
ut_ad(tuple1->magic_n = DATA_TUPLE_MAGIC_N);
|
||||
ut_ad(tuple2->magic_n = DATA_TUPLE_MAGIC_N);
|
||||
ut_ad(dtuple_check_typed(tuple1));
|
||||
ut_ad(dtuple_check_typed(tuple2));
|
||||
|
||||
n_fields = dtuple_get_n_fields(tuple1);
|
||||
|
||||
if (n_fields != dtuple_get_n_fields(tuple2)) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
for (i = 0; i < n_fields; i++) {
|
||||
|
||||
field1 = dtuple_get_nth_field(tuple1, i);
|
||||
field2 = dtuple_get_nth_field(tuple2, i);
|
||||
|
||||
if (0 != cmp_dfield_dfield(field1, field2)) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Creates a dtuple for use in MySQL. */
|
||||
|
||||
@@ -408,7 +456,7 @@ dtuple_convert_big_rec(
|
||||
ulint size;
|
||||
ulint n_fields;
|
||||
ulint longest;
|
||||
ulint longest_i;
|
||||
ulint longest_i = ULINT_MAX;
|
||||
ibool is_externally_stored;
|
||||
ulint i;
|
||||
ulint j;
|
||||
|
@@ -28,7 +28,6 @@ dtype_validate(
|
||||
ut_a((type->mtype >= DATA_VARCHAR) && (type->mtype <= DATA_MYSQL));
|
||||
|
||||
if (type->mtype == DATA_SYS) {
|
||||
ut_a(type->prtype >= DATA_ROW_ID);
|
||||
ut_a(type->prtype <= DATA_MIX_ID);
|
||||
}
|
||||
|
||||
@@ -45,11 +44,10 @@ dtype_print(
|
||||
{
|
||||
ulint mtype;
|
||||
ulint prtype;
|
||||
ulint len;
|
||||
|
||||
ut_a(type);
|
||||
|
||||
printf("DATA TYPE: ");
|
||||
|
||||
mtype = type->mtype;
|
||||
prtype = type->prtype;
|
||||
if (mtype == DATA_VARCHAR) {
|
||||
@@ -65,17 +63,24 @@ dtype_print(
|
||||
} else if (mtype == DATA_SYS) {
|
||||
printf("DATA_SYS");
|
||||
} else {
|
||||
printf("unknown type %lu", mtype);
|
||||
printf("type %lu", mtype);
|
||||
}
|
||||
|
||||
len = type->len;
|
||||
|
||||
if ((type->mtype == DATA_SYS)
|
||||
|| (type->mtype == DATA_VARCHAR)
|
||||
|| (type->mtype == DATA_CHAR)) {
|
||||
printf(" ");
|
||||
if (prtype == DATA_ROW_ID) {
|
||||
printf("DATA_ROW_ID");
|
||||
len = DATA_ROW_ID_LEN;
|
||||
} else if (prtype == DATA_ROLL_PTR) {
|
||||
printf("DATA_ROLL_PTR");
|
||||
len = DATA_ROLL_PTR_LEN;
|
||||
} else if (prtype == DATA_TRX_ID) {
|
||||
printf("DATA_TRX_ID");
|
||||
len = DATA_TRX_ID_LEN;
|
||||
} else if (prtype == DATA_MIX_ID) {
|
||||
printf("DATA_MIX_ID");
|
||||
} else if (prtype == DATA_ENGLISH) {
|
||||
@@ -83,9 +88,9 @@ dtype_print(
|
||||
} else if (prtype == DATA_FINNISH) {
|
||||
printf("DATA_FINNISH");
|
||||
} else {
|
||||
printf("unknown prtype %lu", mtype);
|
||||
printf("prtype %lu", mtype);
|
||||
}
|
||||
}
|
||||
|
||||
printf("; len %lu prec %lu\n", type->len, type->prec);
|
||||
printf(" len %lu prec %lu", len, type->prec);
|
||||
}
|
||||
|
@@ -17,9 +17,13 @@ Created 1/8/1996 Heikki Tuuri
|
||||
#include "page0page.h"
|
||||
#include "mach0data.h"
|
||||
#include "dict0boot.h"
|
||||
#include "dict0dict.h"
|
||||
#include "que0que.h"
|
||||
#include "row0ins.h"
|
||||
#include "row0mysql.h"
|
||||
#include "pars0pars.h"
|
||||
#include "trx0roll.h"
|
||||
#include "usr0sess.h"
|
||||
|
||||
/*********************************************************************
|
||||
Based on a table object, this function builds the entry to be inserted
|
||||
@@ -1019,3 +1023,228 @@ function_exit:
|
||||
|
||||
return(thr);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Creates the foreign key constraints system tables inside InnoDB
|
||||
at database creation or database start if they are not found or are
|
||||
not of the right form. */
|
||||
|
||||
ulint
|
||||
dict_create_or_check_foreign_constraint_tables(void)
|
||||
/*================================================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
{
|
||||
dict_table_t* table1;
|
||||
dict_table_t* table2;
|
||||
que_thr_t* thr;
|
||||
que_t* graph;
|
||||
ulint error;
|
||||
trx_t* trx;
|
||||
char* str;
|
||||
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
table1 = dict_table_get_low("SYS_FOREIGN");
|
||||
table2 = dict_table_get_low("SYS_FOREIGN_COLS");
|
||||
|
||||
if (table1 && table2
|
||||
&& UT_LIST_GET_LEN(table1->indexes) == 3
|
||||
&& UT_LIST_GET_LEN(table2->indexes) == 1) {
|
||||
|
||||
/* Foreign constraint system tables have already been
|
||||
created, and they are ok */
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
trx = trx_allocate_for_mysql();
|
||||
|
||||
trx->op_info = "creating foreign key sys tables";
|
||||
|
||||
if (table1) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: dropping incompletely created SYS_FOREIGN table\n");
|
||||
row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
|
||||
}
|
||||
|
||||
if (table2) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: dropping incompletely created SYS_FOREIGN_COLS table\n");
|
||||
row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: creating foreign key constraint system tables\n");
|
||||
|
||||
/* NOTE: in dict_load_foreigns we use the fact that
|
||||
there are 2 secondary indexes on SYS_FOREIGN, and they
|
||||
are defined just like below */
|
||||
|
||||
str =
|
||||
"PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
|
||||
"BEGIN\n"
|
||||
"CREATE TABLE\n"
|
||||
"SYS_FOREIGN(ID CHAR, FOR_NAME CHAR, REF_NAME CHAR, N_COLS INT);\n"
|
||||
"CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN (ID);\n"
|
||||
"CREATE INDEX FOR_IND ON SYS_FOREIGN (FOR_NAME);\n"
|
||||
"CREATE INDEX REF_IND ON SYS_FOREIGN (REF_NAME);\n"
|
||||
"CREATE TABLE\n"
|
||||
"SYS_FOREIGN_COLS(ID CHAR, POS INT, FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
|
||||
"CREATE UNIQUE CLUSTERED INDEX ID_IND ON SYS_FOREIGN_COLS (ID, POS);\n"
|
||||
"COMMIT WORK;\n"
|
||||
"END;\n";
|
||||
|
||||
graph = pars_sql(str);
|
||||
|
||||
ut_a(graph);
|
||||
|
||||
graph->trx = trx;
|
||||
trx->graph = NULL;
|
||||
|
||||
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
||||
|
||||
ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0));
|
||||
|
||||
que_run_threads(thr);
|
||||
|
||||
error = trx->error_state;
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
ut_a(error == DB_OUT_OF_FILE_SPACE);
|
||||
|
||||
fprintf(stderr, "InnoDB: creation failed\n");
|
||||
fprintf(stderr, "InnoDB: tablespace is full\n");
|
||||
fprintf(stderr,
|
||||
"InnoDB: dropping incompletely created SYS_FOREIGN tables\n");
|
||||
|
||||
row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
|
||||
row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
|
||||
|
||||
error = DB_MUST_GET_MORE_FILE_SPACE;
|
||||
}
|
||||
|
||||
que_graph_free(graph);
|
||||
|
||||
trx->op_info = "";
|
||||
|
||||
trx_free_for_mysql(trx);
|
||||
|
||||
if (error == DB_SUCCESS) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: foreign key constraint system tables created\n");
|
||||
}
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Adds foreign key definitions to data dictionary tables in the database. */
|
||||
|
||||
ulint
|
||||
dict_create_add_foreigns_to_dictionary(
|
||||
/*===================================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
dict_table_t* table, /* in: table */
|
||||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
dict_foreign_t* foreign;
|
||||
que_thr_t* thr;
|
||||
que_t* graph;
|
||||
dulint id;
|
||||
ulint len;
|
||||
ulint error;
|
||||
ulint i;
|
||||
char buf2[50];
|
||||
char buf[10000];
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
if (NULL == dict_table_get_low("SYS_FOREIGN")) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: table SYS_FOREIGN not found from internal data dictionary\n");
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
foreign = UT_LIST_GET_FIRST(table->foreign_list);
|
||||
loop:
|
||||
if (foreign == NULL) {
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/* Build an InnoDB stored procedure which will insert the necessary
|
||||
rows to SYS_FOREIGN and SYS_FOREIGN_COLS */
|
||||
|
||||
len = 0;
|
||||
|
||||
len += sprintf(buf,
|
||||
"PROCEDURE ADD_FOREIGN_DEFS_PROC () IS\n"
|
||||
"BEGIN\n");
|
||||
|
||||
/* We allocate the new id from the sequence of table id's */
|
||||
id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
|
||||
|
||||
sprintf(buf2, "%lu_%lu", ut_dulint_get_high(id),
|
||||
ut_dulint_get_low(id));
|
||||
foreign->id = mem_heap_alloc(foreign->heap, ut_strlen(buf2) + 1);
|
||||
ut_memcpy(foreign->id, buf2, ut_strlen(buf2) + 1);
|
||||
|
||||
len += sprintf(buf + len,
|
||||
"INSERT INTO SYS_FOREIGN VALUES('%lu_%lu', '%s', '%s', %lu);\n",
|
||||
ut_dulint_get_high(id),
|
||||
ut_dulint_get_low(id),
|
||||
table->name,
|
||||
foreign->referenced_table_name,
|
||||
foreign->n_fields);
|
||||
|
||||
for (i = 0; i < foreign->n_fields; i++) {
|
||||
|
||||
len += sprintf(buf + len,
|
||||
"INSERT INTO SYS_FOREIGN_COLS VALUES('%lu_%lu', %lu, '%s', '%s');\n",
|
||||
ut_dulint_get_high(id),
|
||||
ut_dulint_get_low(id),
|
||||
i,
|
||||
foreign->foreign_col_names[i],
|
||||
foreign->referenced_col_names[i]);
|
||||
}
|
||||
|
||||
len += sprintf(buf + len,"COMMIT WORK;\nEND;\n");
|
||||
|
||||
graph = pars_sql(buf);
|
||||
|
||||
ut_a(graph);
|
||||
|
||||
graph->trx = trx;
|
||||
trx->graph = NULL;
|
||||
|
||||
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
||||
|
||||
ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0));
|
||||
|
||||
que_run_threads(thr);
|
||||
|
||||
error = trx->error_state;
|
||||
|
||||
que_graph_free(graph);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
ut_a(error == DB_OUT_OF_FILE_SPACE);
|
||||
|
||||
fprintf(stderr, "InnoDB: foreign constraint creation failed\n");
|
||||
fprintf(stderr, "InnoDB: tablespace is full\n");
|
||||
|
||||
trx_general_rollback_for_mysql(trx, FALSE, NULL);
|
||||
|
||||
error = DB_MUST_GET_MORE_FILE_SPACE;
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
|
||||
|
||||
goto loop;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -47,9 +47,172 @@ dict_load_fields(
|
||||
mem_heap_t* heap); /* in: memory heap for temporary storage */
|
||||
|
||||
|
||||
/************************************************************************
|
||||
Finds the first table name in the given database. */
|
||||
|
||||
char*
|
||||
dict_get_first_table_name_in_db(
|
||||
/*============================*/
|
||||
/* out, own: table name, NULL if does not exist;
|
||||
the caller must free the memory in the string! */
|
||||
char* name) /* in: database name which ends to '/' */
|
||||
{
|
||||
dict_table_t* sys_tables;
|
||||
btr_pcur_t pcur;
|
||||
dict_index_t* sys_index;
|
||||
dtuple_t* tuple;
|
||||
mem_heap_t* heap;
|
||||
dfield_t* dfield;
|
||||
rec_t* rec;
|
||||
byte* field;
|
||||
ulint len;
|
||||
char* table_name;
|
||||
mtr_t mtr;
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
heap = mem_heap_create(1000);
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
sys_tables = dict_table_get_low("SYS_TABLES");
|
||||
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
|
||||
|
||||
tuple = dtuple_create(heap, 1);
|
||||
dfield = dtuple_get_nth_field(tuple, 0);
|
||||
|
||||
dfield_set_data(dfield, name, ut_strlen(name));
|
||||
dict_index_copy_types(tuple, sys_index, 1);
|
||||
|
||||
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
|
||||
BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||
loop:
|
||||
rec = btr_pcur_get_rec(&pcur);
|
||||
|
||||
if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
|
||||
/* Not found */
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
field = rec_get_nth_field(rec, 0, &len);
|
||||
|
||||
if (len < strlen(name)
|
||||
|| ut_memcmp(name, field, strlen(name)) != 0) {
|
||||
/* Not found */
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
if (!rec_get_deleted_flag(rec)) {
|
||||
|
||||
/* We found one */
|
||||
|
||||
table_name = mem_alloc(len + 1);
|
||||
ut_memcpy(table_name, field, len);
|
||||
table_name[len] = '\0';
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(table_name);
|
||||
}
|
||||
|
||||
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
|
||||
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Prints to the standard output information on all tables found in the data
|
||||
dictionary system table. */
|
||||
|
||||
void
|
||||
dict_print(void)
|
||||
/*============*/
|
||||
{
|
||||
dict_table_t* sys_tables;
|
||||
dict_index_t* sys_index;
|
||||
dict_table_t* table;
|
||||
btr_pcur_t pcur;
|
||||
rec_t* rec;
|
||||
byte* field;
|
||||
ulint len;
|
||||
char table_name[10000];
|
||||
mtr_t mtr;
|
||||
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
sys_tables = dict_table_get_low("SYS_TABLES");
|
||||
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
|
||||
|
||||
btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
|
||||
TRUE, &mtr);
|
||||
loop:
|
||||
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
|
||||
|
||||
rec = btr_pcur_get_rec(&pcur);
|
||||
|
||||
if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
|
||||
/* end of index */
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
field = rec_get_nth_field(rec, 0, &len);
|
||||
|
||||
if (!rec_get_deleted_flag(rec)) {
|
||||
|
||||
/* We found one */
|
||||
|
||||
ut_memcpy(table_name, field, len);
|
||||
table_name[len] = '\0';
|
||||
|
||||
btr_pcur_store_position(&pcur, &mtr);
|
||||
|
||||
mtr_commit(&mtr);
|
||||
|
||||
table = dict_table_get_low(table_name);
|
||||
|
||||
if (table == NULL) {
|
||||
fprintf(stderr, "InnoDB: Failed to load table %s\n",
|
||||
table_name);
|
||||
} else {
|
||||
dict_update_statistics_low(table, TRUE);
|
||||
|
||||
dict_table_print_low(table);
|
||||
}
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||
}
|
||||
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Loads a table definition and also all its index definitions, and also
|
||||
the cluster definition if the table is a member in a cluster. */
|
||||
the cluster definition if the table is a member in a cluster. Also loads
|
||||
all foreign key constraints where the foreign key is in the table or where
|
||||
a foreign key references columns in this table. Adds all these to the data
|
||||
dictionary cache. */
|
||||
|
||||
dict_table_t*
|
||||
dict_load_table(
|
||||
@@ -59,7 +222,6 @@ dict_load_table(
|
||||
{
|
||||
dict_table_t* table;
|
||||
dict_table_t* sys_tables;
|
||||
mtr_t mtr;
|
||||
btr_pcur_t pcur;
|
||||
dict_index_t* sys_index;
|
||||
dtuple_t* tuple;
|
||||
@@ -71,6 +233,7 @@ dict_load_table(
|
||||
char* buf;
|
||||
ulint space;
|
||||
ulint n_cols;
|
||||
mtr_t mtr;
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
@@ -178,6 +341,106 @@ dict_load_table(
|
||||
|
||||
dict_load_indexes(table, heap);
|
||||
|
||||
ut_a(DB_SUCCESS == dict_load_foreigns(table->name));
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(table);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Loads a table object based on the table id. */
|
||||
|
||||
dict_table_t*
|
||||
dict_load_table_on_id(
|
||||
/*==================*/
|
||||
/* out: table; NULL if table does not exist */
|
||||
dulint table_id) /* in: table id */
|
||||
{
|
||||
byte id_buf[8];
|
||||
btr_pcur_t pcur;
|
||||
mem_heap_t* heap;
|
||||
dtuple_t* tuple;
|
||||
dfield_t* dfield;
|
||||
dict_index_t* sys_table_ids;
|
||||
dict_table_t* sys_tables;
|
||||
rec_t* rec;
|
||||
byte* field;
|
||||
ulint len;
|
||||
dict_table_t* table;
|
||||
char* name;
|
||||
mtr_t mtr;
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
/* NOTE that the operation of this function is protected by
|
||||
the dictionary mutex, and therefore no deadlocks can occur
|
||||
with other dictionary operations. */
|
||||
|
||||
mtr_start(&mtr);
|
||||
/*---------------------------------------------------*/
|
||||
/* Get the secondary index based on ID for table SYS_TABLES */
|
||||
sys_tables = dict_sys->sys_tables;
|
||||
sys_table_ids = dict_table_get_next_index(
|
||||
dict_table_get_first_index(sys_tables));
|
||||
heap = mem_heap_create(256);
|
||||
|
||||
tuple = dtuple_create(heap, 1);
|
||||
dfield = dtuple_get_nth_field(tuple, 0);
|
||||
|
||||
/* Write the table id in byte format to id_buf */
|
||||
mach_write_to_8(id_buf, table_id);
|
||||
|
||||
dfield_set_data(dfield, id_buf, 8);
|
||||
dict_index_copy_types(tuple, sys_table_ids, 1);
|
||||
|
||||
btr_pcur_open_on_user_rec(sys_table_ids, tuple, PAGE_CUR_GE,
|
||||
BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||
rec = btr_pcur_get_rec(&pcur);
|
||||
|
||||
if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
|
||||
|| rec_get_deleted_flag(rec)) {
|
||||
/* Not found */
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/* Now we have the record in the secondary index containing the
|
||||
table ID and NAME */
|
||||
|
||||
rec = btr_pcur_get_rec(&pcur);
|
||||
field = rec_get_nth_field(rec, 0, &len);
|
||||
ut_ad(len == 8);
|
||||
|
||||
/* Check if the table id in record is the one searched for */
|
||||
if (ut_dulint_cmp(table_id, mach_read_from_8(field)) != 0) {
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Now we get the table name from the record */
|
||||
field = rec_get_nth_field(rec, 1, &len);
|
||||
|
||||
name = mem_heap_alloc(heap, len + 1);
|
||||
ut_memcpy(name, field, len);
|
||||
name[len] = '\0';
|
||||
|
||||
/* Load the table definition to memory */
|
||||
table = dict_load_table(name);
|
||||
|
||||
ut_a(table);
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(table);
|
||||
@@ -305,7 +568,8 @@ dict_load_columns(
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Loads definitions for table indexes. */
|
||||
Loads definitions for table indexes. Adds them to the data dictionary cache.
|
||||
*/
|
||||
static
|
||||
void
|
||||
dict_load_indexes(
|
||||
@@ -446,7 +710,6 @@ dict_load_fields(
|
||||
{
|
||||
dict_table_t* sys_fields;
|
||||
dict_index_t* sys_index;
|
||||
mtr_t mtr;
|
||||
btr_pcur_t pcur;
|
||||
dtuple_t* tuple;
|
||||
dfield_t* dfield;
|
||||
@@ -456,6 +719,7 @@ dict_load_fields(
|
||||
ulint len;
|
||||
byte* buf;
|
||||
ulint i;
|
||||
mtr_t mtr;
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
@@ -512,53 +776,125 @@ dict_load_fields(
|
||||
mtr_commit(&mtr);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Loads a table object based on the table id. */
|
||||
|
||||
dict_table_t*
|
||||
dict_load_table_on_id(
|
||||
/*==================*/
|
||||
/* out: table; NULL if table does not exist */
|
||||
dulint table_id) /* in: table id */
|
||||
/************************************************************************
|
||||
Loads foreign key constraint col names (also for the referenced table). */
|
||||
static
|
||||
void
|
||||
dict_load_foreign_cols(
|
||||
/*===================*/
|
||||
char* id, /* in: foreign constraint id as a null-
|
||||
terminated string */
|
||||
dict_foreign_t* foreign)/* in: foreign constraint object */
|
||||
{
|
||||
mtr_t mtr;
|
||||
byte id_buf[8];
|
||||
dict_table_t* sys_foreign_cols;
|
||||
dict_index_t* sys_index;
|
||||
btr_pcur_t pcur;
|
||||
mem_heap_t* heap;
|
||||
dtuple_t* tuple;
|
||||
dfield_t* dfield;
|
||||
dict_index_t* sys_table_ids;
|
||||
dict_table_t* sys_tables;
|
||||
char* col_name;
|
||||
rec_t* rec;
|
||||
byte* field;
|
||||
ulint len;
|
||||
dict_table_t* table;
|
||||
char* name;
|
||||
ulint i;
|
||||
mtr_t mtr;
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
/* NOTE that the operation of this function is protected by
|
||||
the dictionary mutex, and therefore no deadlocks can occur
|
||||
with other dictionary operations. */
|
||||
foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
|
||||
foreign->n_fields * sizeof(void*));
|
||||
|
||||
foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
|
||||
foreign->n_fields * sizeof(void*));
|
||||
mtr_start(&mtr);
|
||||
/*---------------------------------------------------*/
|
||||
/* Get the secondary index based on ID for table SYS_TABLES */
|
||||
sys_tables = dict_sys->sys_tables;
|
||||
sys_table_ids = dict_table_get_next_index(
|
||||
dict_table_get_first_index(sys_tables));
|
||||
heap = mem_heap_create(256);
|
||||
|
||||
tuple = dtuple_create(heap, 1);
|
||||
sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS");
|
||||
sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes);
|
||||
|
||||
tuple = dtuple_create(foreign->heap, 1);
|
||||
dfield = dtuple_get_nth_field(tuple, 0);
|
||||
|
||||
/* Write the table id in byte format to id_buf */
|
||||
mach_write_to_8(id_buf, table_id);
|
||||
dfield_set_data(dfield, id, ut_strlen(id));
|
||||
dict_index_copy_types(tuple, sys_index, 1);
|
||||
|
||||
dfield_set_data(dfield, id_buf, 8);
|
||||
dict_index_copy_types(tuple, sys_table_ids, 1);
|
||||
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
|
||||
BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||
for (i = 0; i < foreign->n_fields; i++) {
|
||||
|
||||
btr_pcur_open_on_user_rec(sys_table_ids, tuple, PAGE_CUR_GE,
|
||||
rec = btr_pcur_get_rec(&pcur);
|
||||
|
||||
ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
|
||||
ut_a(!rec_get_deleted_flag(rec));
|
||||
|
||||
field = rec_get_nth_field(rec, 0, &len);
|
||||
ut_a(len == ut_strlen(id));
|
||||
ut_a(ut_memcmp(id, field, len) == 0);
|
||||
|
||||
field = rec_get_nth_field(rec, 1, &len);
|
||||
ut_a(len == 4);
|
||||
ut_a(i == mach_read_from_4(field));
|
||||
|
||||
field = rec_get_nth_field(rec, 4, &len);
|
||||
|
||||
col_name = mem_heap_alloc(foreign->heap, len + 1);
|
||||
ut_memcpy(col_name, field, len);
|
||||
col_name[len] = '\0';
|
||||
|
||||
foreign->foreign_col_names[i] = col_name;
|
||||
|
||||
field = rec_get_nth_field(rec, 5, &len);
|
||||
|
||||
col_name = mem_heap_alloc(foreign->heap, len + 1);
|
||||
ut_memcpy(col_name, field, len);
|
||||
col_name[len] = '\0';
|
||||
|
||||
foreign->referenced_col_names[i] = col_name;
|
||||
|
||||
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
|
||||
}
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Loads a foreign key constraint to the dictionary cache. */
|
||||
static
|
||||
ulint
|
||||
dict_load_foreign(
|
||||
/*==============*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
char* id) /* in: foreign constraint id as a null-terminated
|
||||
string */
|
||||
{
|
||||
dict_foreign_t* foreign;
|
||||
dict_table_t* sys_foreign;
|
||||
btr_pcur_t pcur;
|
||||
dict_index_t* sys_index;
|
||||
dtuple_t* tuple;
|
||||
mem_heap_t* heap2;
|
||||
dfield_t* dfield;
|
||||
rec_t* rec;
|
||||
byte* field;
|
||||
ulint len;
|
||||
ulint err;
|
||||
mtr_t mtr;
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
heap2 = mem_heap_create(1000);
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
sys_foreign = dict_table_get_low("SYS_FOREIGN");
|
||||
sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes);
|
||||
|
||||
tuple = dtuple_create(heap2, 1);
|
||||
dfield = dtuple_get_nth_field(tuple, 0);
|
||||
|
||||
dfield_set_data(dfield, id, ut_strlen(id));
|
||||
dict_index_copy_types(tuple, sys_index, 1);
|
||||
|
||||
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
|
||||
BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||
rec = btr_pcur_get_rec(&pcur);
|
||||
|
||||
@@ -566,46 +902,202 @@ dict_load_table_on_id(
|
||||
|| rec_get_deleted_flag(rec)) {
|
||||
/* Not found */
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error A: cannot load foreign constraint %s\n", id);
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
mem_heap_free(heap);
|
||||
mem_heap_free(heap2);
|
||||
|
||||
return(NULL);
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
/* Now we have the record in the secondary index containing the
|
||||
table ID and NAME */
|
||||
field = rec_get_nth_field(rec, 0, &len);
|
||||
|
||||
/* Check if the id in record is the searched one */
|
||||
if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) {
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error B: cannot load foreign constraint %s\n", id);
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
mem_heap_free(heap2);
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
/* Read the table names and the number of columns associated
|
||||
with the constraint */
|
||||
|
||||
mem_heap_free(heap2);
|
||||
|
||||
foreign = dict_mem_foreign_create();
|
||||
|
||||
foreign->n_fields = mach_read_from_4(rec_get_nth_field(rec, 5, &len));
|
||||
|
||||
ut_a(len == 4);
|
||||
|
||||
foreign->id = mem_heap_alloc(foreign->heap, ut_strlen(id) + 1);
|
||||
|
||||
ut_memcpy(foreign->id, id, ut_strlen(id) + 1);
|
||||
|
||||
field = rec_get_nth_field(rec, 3, &len);
|
||||
|
||||
foreign->foreign_table_name = mem_heap_alloc(foreign->heap, 1 + len);
|
||||
|
||||
ut_memcpy(foreign->foreign_table_name, field, len);
|
||||
foreign->foreign_table_name[len] = '\0';
|
||||
|
||||
field = rec_get_nth_field(rec, 4, &len);
|
||||
|
||||
foreign->referenced_table_name = mem_heap_alloc(foreign->heap, 1 + len);
|
||||
|
||||
ut_memcpy(foreign->referenced_table_name, field, len);
|
||||
foreign->referenced_table_name[len] = '\0';
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
|
||||
dict_load_foreign_cols(id, foreign);
|
||||
|
||||
/* Note that there may already be a foreign constraint object in
|
||||
the dictionary cache for this constraint: then the following
|
||||
call only sets the pointers in it to point to the appropriate table
|
||||
and index objects and frees the newly created object foreign. */
|
||||
|
||||
err = dict_foreign_add_to_cache(foreign);
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Loads foreign key constraints where the table is either the foreign key
|
||||
holder or where the table is referenced by a foreign key. Adds these
|
||||
constraints to the data dictionary. Note that we know that the dictionary
|
||||
cache already contains all constraints where the other relevant table is
|
||||
already in the dictionary cache. */
|
||||
|
||||
ulint
|
||||
dict_load_foreigns(
|
||||
/*===============*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
char* table_name) /* in: table name */
|
||||
{
|
||||
btr_pcur_t pcur;
|
||||
mem_heap_t* heap;
|
||||
dtuple_t* tuple;
|
||||
dfield_t* dfield;
|
||||
dict_index_t* sec_index;
|
||||
dict_table_t* sys_foreign;
|
||||
rec_t* rec;
|
||||
byte* field;
|
||||
ulint len;
|
||||
char* id ;
|
||||
ulint err;
|
||||
mtr_t mtr;
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
sys_foreign = dict_table_get_low("SYS_FOREIGN");
|
||||
|
||||
if (sys_foreign == NULL) {
|
||||
/* No foreign keys defined yet in this database */
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: no foreign key system tables in the database\n");
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
/* Get the secondary index based on FOR_NAME from table
|
||||
SYS_FOREIGN */
|
||||
|
||||
sec_index = dict_table_get_next_index(
|
||||
dict_table_get_first_index(sys_foreign));
|
||||
start_load:
|
||||
heap = mem_heap_create(256);
|
||||
|
||||
tuple = dtuple_create(heap, 1);
|
||||
dfield = dtuple_get_nth_field(tuple, 0);
|
||||
|
||||
dfield_set_data(dfield, table_name, ut_strlen(table_name));
|
||||
dict_index_copy_types(tuple, sec_index, 1);
|
||||
|
||||
btr_pcur_open_on_user_rec(sec_index, tuple, PAGE_CUR_GE,
|
||||
BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||
loop:
|
||||
rec = btr_pcur_get_rec(&pcur);
|
||||
|
||||
if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
|
||||
/* End of index */
|
||||
|
||||
goto load_next_index;
|
||||
}
|
||||
|
||||
/* Now we have the record in the secondary index containing a table
|
||||
name and a foreign constraint ID */
|
||||
|
||||
rec = btr_pcur_get_rec(&pcur);
|
||||
field = rec_get_nth_field(rec, 0, &len);
|
||||
ut_ad(len == 8);
|
||||
|
||||
/* Check if the table id in record is the one searched for */
|
||||
if (ut_dulint_cmp(table_id, mach_read_from_8(field)) != 0) {
|
||||
/* Check if the table name in record is the one searched for */
|
||||
if (len != ut_strlen(table_name)
|
||||
|| 0 != ut_memcmp(field, table_name, len)) {
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(NULL);
|
||||
goto load_next_index;
|
||||
}
|
||||
|
||||
/* Now we get the table name from the record */
|
||||
if (rec_get_deleted_flag(rec)) {
|
||||
|
||||
goto next_rec;
|
||||
}
|
||||
|
||||
/* Now we get a foreign key constraint id */
|
||||
field = rec_get_nth_field(rec, 1, &len);
|
||||
|
||||
name = mem_heap_alloc(heap, len + 1);
|
||||
ut_memcpy(name, field, len);
|
||||
name[len] = '\0';
|
||||
id = mem_heap_alloc(heap, len + 1);
|
||||
ut_memcpy(id, field, len);
|
||||
id[len] = '\0';
|
||||
|
||||
/* Load the table definition to memory */
|
||||
table = dict_load_table(name);
|
||||
btr_pcur_store_position(&pcur, &mtr);
|
||||
|
||||
ut_a(table);
|
||||
mtr_commit(&mtr);
|
||||
|
||||
/* Load the foreign constraint definition to the dictionary cache */
|
||||
|
||||
err = dict_load_foreign(id);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
btr_pcur_close(&pcur);
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||
next_rec:
|
||||
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
|
||||
|
||||
goto loop;
|
||||
|
||||
load_next_index:
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(table);
|
||||
sec_index = dict_table_get_next_index(sec_index);
|
||||
|
||||
if (sec_index != NULL) {
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
goto start_load;
|
||||
}
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ Created 1/8/1996 Heikki Tuuri
|
||||
#include "dict0dict.h"
|
||||
#include "que0que.h"
|
||||
#include "pars0pars.h"
|
||||
#include "lock0lock.h"
|
||||
|
||||
#define DICT_HEAP_SIZE 100 /* initial memory heap size when
|
||||
creating a table or index object */
|
||||
@@ -63,7 +64,12 @@ dict_mem_table_create(
|
||||
table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS)
|
||||
* sizeof(dict_col_t));
|
||||
UT_LIST_INIT(table->indexes);
|
||||
|
||||
table->auto_inc_lock = mem_heap_alloc(heap, lock_get_size());
|
||||
|
||||
UT_LIST_INIT(table->locks);
|
||||
UT_LIST_INIT(table->foreign_list);
|
||||
UT_LIST_INIT(table->referenced_list);
|
||||
|
||||
table->does_not_fit_in_memory = FALSE;
|
||||
|
||||
@@ -199,12 +205,49 @@ dict_mem_index_create(
|
||||
* sizeof(dict_field_t));
|
||||
/* The '1 +' above prevents allocation
|
||||
of an empty mem block */
|
||||
index->stat_n_diff_key_vals = NULL;
|
||||
|
||||
index->cached = FALSE;
|
||||
index->magic_n = DICT_INDEX_MAGIC_N;
|
||||
|
||||
return(index);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Creates and initializes a foreign constraint memory object. */
|
||||
|
||||
dict_foreign_t*
|
||||
dict_mem_foreign_create(void)
|
||||
/*=========================*/
|
||||
/* out, own: foreign constraint struct */
|
||||
{
|
||||
dict_foreign_t* foreign;
|
||||
mem_heap_t* heap;
|
||||
|
||||
heap = mem_heap_create(100);
|
||||
|
||||
foreign = mem_heap_alloc(heap, sizeof(dict_foreign_t));
|
||||
|
||||
foreign->heap = heap;
|
||||
|
||||
foreign->id = NULL;
|
||||
|
||||
foreign->foreign_table_name = NULL;
|
||||
foreign->foreign_table = NULL;
|
||||
foreign->foreign_col_names = NULL;
|
||||
|
||||
foreign->referenced_table_name = NULL;
|
||||
foreign->referenced_table = NULL;
|
||||
foreign->referenced_col_names = NULL;
|
||||
|
||||
foreign->n_fields = 0;
|
||||
|
||||
foreign->foreign_index = NULL;
|
||||
foreign->referenced_index = NULL;
|
||||
|
||||
return(foreign);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Adds a field definition to an index. NOTE: does not take a copy
|
||||
of the column name if the field is a column. The memory occupied
|
||||
|
@@ -77,6 +77,9 @@ out of the LRU-list and keep a count of pending operations. When an operation
|
||||
completes, we decrement the count and return the file node to the LRU-list if
|
||||
the count drops to zero. */
|
||||
|
||||
ulint fil_n_pending_log_flushes = 0;
|
||||
ulint fil_n_pending_tablespace_flushes = 0;
|
||||
|
||||
/* Null file address */
|
||||
fil_addr_t fil_addr_null = {FIL_NULL, 0};
|
||||
|
||||
@@ -856,6 +859,15 @@ fil_node_prepare_for_io(
|
||||
|
||||
last_node = UT_LIST_GET_LAST(system->LRU);
|
||||
|
||||
if (last_node == NULL) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: cannot close any file to open another for i/o\n"
|
||||
"InnoDB: Pending i/o's on %lu files exist\n",
|
||||
system->n_open_pending);
|
||||
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
fil_node_close(last_node, system);
|
||||
}
|
||||
|
||||
@@ -973,6 +985,7 @@ fil_io(
|
||||
ibool ret;
|
||||
ulint is_log;
|
||||
ulint wake_later;
|
||||
ulint count;
|
||||
|
||||
is_log = type & OS_FILE_LOG;
|
||||
type = type & ~OS_FILE_LOG;
|
||||
@@ -996,7 +1009,7 @@ fil_io(
|
||||
#endif
|
||||
if (sync) {
|
||||
mode = OS_AIO_SYNC;
|
||||
} else if ((type == OS_FILE_READ) && !is_log
|
||||
} else if (type == OS_FILE_READ && !is_log
|
||||
&& ibuf_page(space_id, block_offset)) {
|
||||
mode = OS_AIO_IBUF;
|
||||
} else if (is_log) {
|
||||
@@ -1006,9 +1019,44 @@ fil_io(
|
||||
}
|
||||
|
||||
system = fil_system;
|
||||
|
||||
count = 0;
|
||||
loop:
|
||||
count++;
|
||||
|
||||
/* NOTE that there is a possibility of a hang here:
|
||||
if the read i/o-handler thread needs to complete
|
||||
a read by reading from the insert buffer, it may need to
|
||||
post another read. But if the maximum number of files
|
||||
are already open, it cannot proceed from here! */
|
||||
|
||||
mutex_enter(&(system->mutex));
|
||||
|
||||
if (count < 500 && !is_log && !ibuf_inside()
|
||||
&& system->n_open_pending >= (3 * system->max_n_open) / 4) {
|
||||
|
||||
/* We are not doing an ibuf operation: leave a
|
||||
safety margin of openable files for possible ibuf
|
||||
merges needed in page read completion */
|
||||
|
||||
mutex_exit(&(system->mutex));
|
||||
|
||||
/* Wake the i/o-handler threads to make sure pending
|
||||
i/o's are handled and eventually we can open the file */
|
||||
|
||||
os_aio_simulated_wake_handler_threads();
|
||||
|
||||
os_thread_sleep(100000);
|
||||
|
||||
if (count > 50) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Warning: waiting for file closes to proceed\n"
|
||||
"InnoDB: round %lu\n", count);
|
||||
}
|
||||
|
||||
goto loop;
|
||||
}
|
||||
|
||||
if (system->n_open_pending == system->max_n_open) {
|
||||
|
||||
/* It is not sure we can open the file if it is closed: wait */
|
||||
@@ -1018,6 +1066,14 @@ loop:
|
||||
|
||||
mutex_exit(&(system->mutex));
|
||||
|
||||
/* Wake the i/o-handler threads to make sure pending
|
||||
i/o's are handled and eventually we can open the file */
|
||||
|
||||
os_aio_simulated_wake_handler_threads();
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Warning: max allowed number of files is open\n");
|
||||
|
||||
os_event_wait(event);
|
||||
|
||||
goto loop;
|
||||
@@ -1160,6 +1216,7 @@ fil_aio_wait(
|
||||
#elif defined(POSIX_ASYNC_IO)
|
||||
ret = os_aio_posix_handle(segment, &fil_node, &message);
|
||||
#else
|
||||
ret = 0; /* Eliminate compiler warning */
|
||||
ut_a(0);
|
||||
#endif
|
||||
} else {
|
||||
@@ -1220,6 +1277,12 @@ fil_flush(
|
||||
|
||||
node->is_modified = FALSE;
|
||||
|
||||
if (space->purpose == FIL_TABLESPACE) {
|
||||
fil_n_pending_tablespace_flushes++;
|
||||
} else {
|
||||
fil_n_pending_log_flushes++;
|
||||
}
|
||||
|
||||
mutex_exit(&(system->mutex));
|
||||
|
||||
/* Note that it is not certain, when we have
|
||||
@@ -1233,6 +1296,12 @@ fil_flush(
|
||||
os_file_flush(file);
|
||||
|
||||
mutex_enter(&(system->mutex));
|
||||
|
||||
if (space->purpose == FIL_TABLESPACE) {
|
||||
fil_n_pending_tablespace_flushes--;
|
||||
} else {
|
||||
fil_n_pending_log_flushes--;
|
||||
}
|
||||
}
|
||||
|
||||
node = UT_LIST_GET_NEXT(chain, node);
|
||||
@@ -1377,7 +1446,7 @@ fil_page_set_type(
|
||||
ulint type) /* in: type */
|
||||
{
|
||||
ut_ad(page);
|
||||
ut_ad((type == FIL_PAGE_INDEX) || (type == FIL_PAGE_INDEX));
|
||||
ut_ad((type == FIL_PAGE_INDEX) || (type == FIL_PAGE_UNDO_LOG));
|
||||
|
||||
mach_write_to_2(page + FIL_PAGE_TYPE, type);
|
||||
}
|
||||
|
@@ -1013,7 +1013,7 @@ ibuf_rec_get_volume(
|
||||
ulint i;
|
||||
|
||||
ut_ad(ibuf_inside());
|
||||
ut_ad(rec_get_n_fields(rec) > 2);
|
||||
ut_ad(rec_get_n_fields(ibuf_rec) > 2);
|
||||
|
||||
n_fields = rec_get_n_fields(ibuf_rec) - 2;
|
||||
|
||||
@@ -1624,13 +1624,14 @@ ibuf_get_merge_page_nos(
|
||||
|
||||
/*************************************************************************
|
||||
Contracts insert buffer trees by reading pages to the buffer pool. */
|
||||
|
||||
static
|
||||
ulint
|
||||
ibuf_contract(
|
||||
/*==========*/
|
||||
ibuf_contract_ext(
|
||||
/*==============*/
|
||||
/* out: a lower limit for the combined size in bytes
|
||||
of entries which will be merged from ibuf trees to the
|
||||
pages read, 0 if ibuf is empty */
|
||||
ulint* n_pages,/* out: number of pages to which merged */
|
||||
ibool sync) /* in: TRUE if the caller wants to wait for the
|
||||
issued read with the highest tablespace address
|
||||
to complete */
|
||||
@@ -1644,6 +1645,8 @@ ibuf_contract(
|
||||
ulint n_stored;
|
||||
ulint sum_sizes;
|
||||
mtr_t mtr;
|
||||
|
||||
*n_pages = 0;
|
||||
loop:
|
||||
ut_ad(!ibuf_inside());
|
||||
|
||||
@@ -1730,9 +1733,64 @@ loop:
|
||||
|
||||
buf_read_ibuf_merge_pages(sync, space, page_nos, n_stored);
|
||||
|
||||
*n_pages = n_stored;
|
||||
|
||||
return(sum_sizes + 1);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Contracts insert buffer trees by reading pages to the buffer pool. */
|
||||
|
||||
ulint
|
||||
ibuf_contract(
|
||||
/*==========*/
|
||||
/* out: a lower limit for the combined size in bytes
|
||||
of entries which will be merged from ibuf trees to the
|
||||
pages read, 0 if ibuf is empty */
|
||||
ibool sync) /* in: TRUE if the caller wants to wait for the
|
||||
issued read with the highest tablespace address
|
||||
to complete */
|
||||
{
|
||||
ulint n_pages;
|
||||
|
||||
return(ibuf_contract_ext(&n_pages, sync));
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Contracts insert buffer trees by reading pages to the buffer pool. */
|
||||
|
||||
ulint
|
||||
ibuf_contract_for_n_pages(
|
||||
/*======================*/
|
||||
/* out: a lower limit for the combined size in bytes
|
||||
of entries which will be merged from ibuf trees to the
|
||||
pages read, 0 if ibuf is empty */
|
||||
ibool sync, /* in: TRUE if the caller wants to wait for the
|
||||
issued read with the highest tablespace address
|
||||
to complete */
|
||||
ulint n_pages)/* in: try to read at least this many pages to
|
||||
the buffer pool and merge the ibuf contents to
|
||||
them */
|
||||
{
|
||||
ulint sum_bytes = 0;
|
||||
ulint sum_pages = 0;
|
||||
ulint n_bytes;
|
||||
ulint n_pag2;
|
||||
|
||||
while (sum_pages < n_pages) {
|
||||
n_bytes = ibuf_contract_ext(&n_pag2, sync);
|
||||
|
||||
if (n_bytes == 0) {
|
||||
return(sum_bytes);
|
||||
}
|
||||
|
||||
sum_bytes += n_bytes;
|
||||
sum_pages += n_pag2;
|
||||
}
|
||||
|
||||
return(sum_bytes);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Contract insert buffer trees after insert if they are too big. */
|
||||
UNIV_INLINE
|
||||
@@ -2253,8 +2311,6 @@ ibuf_insert_to_index_page(
|
||||
if (low_match == dtuple_get_n_fields(entry)) {
|
||||
rec = page_cur_get_rec(&page_cur);
|
||||
|
||||
ut_ad(rec_get_deleted_flag(rec));
|
||||
|
||||
btr_cur_del_unmark_for_ibuf(rec, mtr);
|
||||
} else {
|
||||
rec = page_cur_tuple_insert(&page_cur, entry, mtr);
|
||||
@@ -2306,6 +2362,8 @@ ibuf_delete_rec(
|
||||
should belong */
|
||||
btr_pcur_t* pcur, /* in: pcur positioned on the record to
|
||||
delete, having latch mode BTR_MODIFY_LEAF */
|
||||
dtuple_t* search_tuple,
|
||||
/* in: search tuple for entries of page_no */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
ibool success;
|
||||
@@ -2336,7 +2394,28 @@ ibuf_delete_rec(
|
||||
|
||||
mtr_start(mtr);
|
||||
|
||||
ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
|
||||
success = btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr);
|
||||
|
||||
if (!success) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: ERROR: Send the output to heikki.tuuri@innodb.com\n");
|
||||
fprintf(stderr, "InnoDB: ibuf cursor restoration fails!\n");
|
||||
fprintf(stderr, "InnoDB: ibuf record inserted to page %lu\n",
|
||||
page_no);
|
||||
rec_print(btr_pcur_get_rec(pcur));
|
||||
rec_print(pcur->old_rec);
|
||||
dtuple_print(search_tuple);
|
||||
|
||||
rec_print(page_rec_get_next(btr_pcur_get_rec(pcur)));
|
||||
|
||||
mtr_commit(mtr);
|
||||
|
||||
fprintf(stderr, "InnoDB: Validating insert buffer tree:\n");
|
||||
ut_a(btr_validate_tree(ibuf_data->index->tree));
|
||||
fprintf(stderr, "InnoDB: Ibuf tree ok\n");
|
||||
}
|
||||
|
||||
ut_a(success);
|
||||
|
||||
root = ibuf_tree_root_get(ibuf_data, space, mtr);
|
||||
|
||||
@@ -2393,7 +2472,10 @@ ibuf_merge_or_delete_for_page(
|
||||
dulint max_trx_id;
|
||||
mtr_t mtr;
|
||||
|
||||
/* TODO: get MySQL type info to use in ibuf_insert_to_index_page */
|
||||
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef UNIV_LOG_DEBUG
|
||||
if (space % 2 != 0) {
|
||||
@@ -2451,11 +2533,8 @@ loop:
|
||||
if (page) {
|
||||
success = buf_page_get_known_nowait(RW_X_LATCH, page,
|
||||
BUF_KEEP_OLD,
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
IB__FILE__, __LINE__,
|
||||
#endif
|
||||
&mtr);
|
||||
|
||||
ut_a(success);
|
||||
|
||||
buf_page_dbg_add_level(page, SYNC_TREE_NODE);
|
||||
@@ -2508,13 +2587,13 @@ loop:
|
||||
/ IBUF_PAGE_SIZE_PER_FREE_SPACE);
|
||||
#endif
|
||||
ibuf_insert_to_index_page(entry, page, &mtr);
|
||||
|
||||
n_inserts++;
|
||||
}
|
||||
|
||||
/* Delete the record from ibuf */
|
||||
closed = ibuf_delete_rec(space, page_no, &pcur, &mtr);
|
||||
n_inserts++;
|
||||
|
||||
/* Delete the record from ibuf */
|
||||
closed = ibuf_delete_rec(space, page_no, &pcur, search_tuple,
|
||||
&mtr);
|
||||
if (closed) {
|
||||
/* Deletion was pessimistic and mtr was committed:
|
||||
we start from the beginning again */
|
||||
@@ -2524,6 +2603,7 @@ loop:
|
||||
|
||||
if (btr_pcur_is_after_last_on_page(&pcur, &mtr)) {
|
||||
mtr_commit(&mtr);
|
||||
btr_pcur_close(&pcur);
|
||||
|
||||
goto loop;
|
||||
}
|
||||
@@ -2619,8 +2699,6 @@ ibuf_print(void)
|
||||
#endif
|
||||
mutex_enter(&ibuf_mutex);
|
||||
|
||||
printf("Ibuf size %lu max size %lu\n", ibuf->size, ibuf->max_size);
|
||||
|
||||
data = UT_LIST_GET_FIRST(ibuf->data_list);
|
||||
|
||||
while (data) {
|
||||
|
@@ -188,6 +188,22 @@ btr_cur_pessimistic_insert(
|
||||
que_thr_t* thr, /* in: query thread or NULL */
|
||||
mtr_t* mtr); /* in: mtr */
|
||||
/*****************************************************************
|
||||
Updates a secondary index record when the update causes no size
|
||||
changes in its fields. The only case when this function is currently
|
||||
called is that in a char field characters change to others which
|
||||
are identified in the collation order. */
|
||||
|
||||
ulint
|
||||
btr_cur_update_sec_rec_in_place(
|
||||
/*============================*/
|
||||
/* out: DB_SUCCESS or error number */
|
||||
btr_cur_t* cursor, /* in: cursor on the record to update;
|
||||
cursor stays valid and positioned on the
|
||||
same record */
|
||||
upd_t* update, /* in: update vector */
|
||||
que_thr_t* thr, /* in: query thread */
|
||||
mtr_t* mtr); /* in: mtr */
|
||||
/*****************************************************************
|
||||
Updates a record when the update causes no size changes in its fields. */
|
||||
|
||||
ulint
|
||||
@@ -411,12 +427,13 @@ btr_estimate_n_rows_in_range(
|
||||
dtuple_t* tuple2, /* in: range end, may also be empty tuple */
|
||||
ulint mode2); /* in: search mode for range end */
|
||||
/***********************************************************************
|
||||
Estimates the number of different key values in a given index. */
|
||||
Estimates the number of different key values in a given index, for
|
||||
each n-column prefix of the index where n <= dict_index_get_n_unique(index).
|
||||
The estimates are stored in the array index->stat_n_diff_key_vals. */
|
||||
|
||||
ulint
|
||||
void
|
||||
btr_estimate_number_of_different_key_vals(
|
||||
/*======================================*/
|
||||
/* out: estimated number of key values */
|
||||
dict_index_t* index); /* in: index */
|
||||
/***********************************************************************
|
||||
Marks not updated extern fields as not-owned by this record. The ownership
|
||||
|
@@ -22,6 +22,12 @@ Created 2/23/1996 Heikki Tuuri
|
||||
#define BTR_PCUR_ON 1
|
||||
#define BTR_PCUR_BEFORE 2
|
||||
#define BTR_PCUR_AFTER 3
|
||||
/* Note that if the tree is not empty, btr_pcur_store_position does not
|
||||
use the following, but only uses the above three alternatives, where the
|
||||
position is stored relative to a specific record: this makes implementation
|
||||
of a scroll cursor easier */
|
||||
#define BTR_PCUR_BEFORE_FIRST_IN_TREE 4 /* in an empty tree */
|
||||
#define BTR_PCUR_AFTER_LAST_IN_TREE 5 /* in an empty tree */
|
||||
|
||||
/******************************************************************
|
||||
Allocates memory for a persistent cursor object and initializes the cursor. */
|
||||
@@ -170,8 +176,10 @@ btr_pcur_close(
|
||||
/******************************************************************
|
||||
The position of the cursor is stored by taking an initial segment of the
|
||||
record the cursor is positioned on, before, or after, and copying it to the
|
||||
cursor data structure. NOTE that the page where the cursor is positioned
|
||||
must not be empty! */
|
||||
cursor data structure, or just setting a flag if the cursor id before the
|
||||
first in an EMPTY tree, or after the last in an EMPTY tree. NOTE that the
|
||||
page where the cursor is positioned must not be empty if the index tree is
|
||||
not totally empty! */
|
||||
|
||||
void
|
||||
btr_pcur_store_position(
|
||||
@@ -179,6 +187,30 @@ btr_pcur_store_position(
|
||||
btr_pcur_t* cursor, /* in: persistent cursor */
|
||||
mtr_t* mtr); /* in: mtr */
|
||||
/******************************************************************
|
||||
Restores the stored position of a persistent cursor bufferfixing the page and
|
||||
obtaining the specified latches. If the cursor position was saved when the
|
||||
(1) cursor was positioned on a user record: this function restores the position
|
||||
to the last record LESS OR EQUAL to the stored record;
|
||||
(2) cursor was positioned on a page infimum record: restores the position to
|
||||
the last record LESS than the user record which was the successor of the page
|
||||
infimum;
|
||||
(3) cursor was positioned on the page supremum: restores to the first record
|
||||
GREATER than the user record which was the predecessor of the supremum.
|
||||
(4) cursor was positioned before the first or after the last in an empty tree:
|
||||
restores to before first or after the last in the tree. */
|
||||
|
||||
ibool
|
||||
btr_pcur_restore_position(
|
||||
/*======================*/
|
||||
/* out: TRUE if the cursor position
|
||||
was stored when it was on a user record
|
||||
and it can be restored on a user record
|
||||
whose ordering fields are identical to
|
||||
the ones of the original user record */
|
||||
ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */
|
||||
btr_pcur_t* cursor, /* in: detached persistent cursor */
|
||||
mtr_t* mtr); /* in: mtr */
|
||||
/******************************************************************
|
||||
If the latch mode of the cursor is BTR_LEAF_SEARCH or BTR_LEAF_MODIFY,
|
||||
releases the page latch and bufferfix reserved by the cursor.
|
||||
NOTE! In the case of BTR_LEAF_MODIFY, there should not exist changes
|
||||
@@ -198,28 +230,6 @@ btr_pcur_get_rel_pos(
|
||||
/*=================*/
|
||||
/* out: BTR_PCUR_ON, ... */
|
||||
btr_pcur_t* cursor);/* in: persistent cursor */
|
||||
/******************************************************************
|
||||
Restores the stored position of a persistent cursor bufferfixing the page and
|
||||
obtaining the specified latches. If the cursor position was saved when the
|
||||
(1) cursor was positioned on a user record: this function restores the position
|
||||
to the last record LESS OR EQUAL to the stored record;
|
||||
(2) cursor was positioned on a page infimum record: restores the position to
|
||||
the last record LESS than the user record which was the successor of the page
|
||||
infimum;
|
||||
(3) cursor was positioned on the page supremum: restores to the first record
|
||||
GREATER than the user record which was the predecessor of the supremum. */
|
||||
|
||||
ibool
|
||||
btr_pcur_restore_position(
|
||||
/*======================*/
|
||||
/* out: TRUE if the cursor position
|
||||
was stored when it was on a user record
|
||||
and it can be restored on a user record
|
||||
whose ordering fields are identical to
|
||||
the ones of the original user record */
|
||||
ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */
|
||||
btr_pcur_t* cursor, /* in: detached persistent cursor */
|
||||
mtr_t* mtr); /* in: mtr */
|
||||
/*************************************************************
|
||||
Sets the mtr field for a pcur. */
|
||||
UNIV_INLINE
|
||||
@@ -458,7 +468,7 @@ struct btr_pcur_struct{
|
||||
ulint search_mode; /* PAGE_CUR_G, ... */
|
||||
/*-----------------------------*/
|
||||
/* NOTE that the following fields may possess dynamically allocated
|
||||
memory, which should be freed if not needed anymore! */
|
||||
memory which should be freed if not needed anymore! */
|
||||
|
||||
mtr_t* mtr; /* NULL, or this field may contain
|
||||
a mini-transaction which holds the
|
||||
|
@@ -19,8 +19,8 @@ btr_pcur_get_rel_pos(
|
||||
ut_ad(cursor);
|
||||
ut_ad(cursor->old_rec);
|
||||
ut_ad(cursor->old_stored == BTR_PCUR_OLD_STORED);
|
||||
ut_ad((cursor->pos_state == BTR_PCUR_WAS_POSITIONED)
|
||||
|| (cursor->pos_state == BTR_PCUR_IS_POSITIONED));
|
||||
ut_ad(cursor->pos_state == BTR_PCUR_WAS_POSITIONED
|
||||
|| cursor->pos_state == BTR_PCUR_IS_POSITIONED);
|
||||
|
||||
return(cursor->rel_pos);
|
||||
}
|
||||
|
@@ -262,6 +262,12 @@ index */
|
||||
|
||||
#define BTR_SEARCH_ON_HASH_LIMIT 3
|
||||
|
||||
/* We do this many searches before trying to keep the search latch over calls
|
||||
from MySQL. If we notice someone waiting for the latch, we again set this
|
||||
much timeout. This is to reduce contention. */
|
||||
|
||||
#define BTR_SEA_TIMEOUT 10000
|
||||
|
||||
#ifndef UNIV_NONINL
|
||||
#include "btr0sea.ic"
|
||||
#endif
|
||||
|
@@ -116,53 +116,30 @@ buf_frame_copy(
|
||||
NOTE! The following macros should be used instead of buf_page_get_gen,
|
||||
to improve debugging. Only values RW_S_LATCH and RW_X_LATCH are allowed
|
||||
in LA! */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
#define buf_page_get(SP, OF, LA, MTR) buf_page_get_gen(\
|
||||
SP, OF, LA, NULL,\
|
||||
BUF_GET, IB__FILE__, __LINE__, MTR)
|
||||
#else
|
||||
#define buf_page_get(SP, OF, LA, MTR) buf_page_get_gen(\
|
||||
SP, OF, LA, NULL,\
|
||||
BUF_GET, MTR)
|
||||
#endif
|
||||
/******************************************************************
|
||||
Use these macros to bufferfix a page with no latching. Remember not to
|
||||
read the contents of the page unless you know it is safe. Do not modify
|
||||
the contents of the page! We have separated this case, because it is
|
||||
error-prone programming not to set a latch, and it should be used
|
||||
with care. */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
#define buf_page_get_with_no_latch(SP, OF, MTR) buf_page_get_gen(\
|
||||
SP, OF, RW_NO_LATCH, NULL,\
|
||||
BUF_GET_NO_LATCH, IB__FILE__, __LINE__, MTR)
|
||||
#else
|
||||
#define buf_page_get_with_no_latch(SP, OF, MTR) buf_page_get_gen(\
|
||||
SP, OF, RW_NO_LATCH, NULL,\
|
||||
BUF_GET_NO_LATCH, MTR)
|
||||
#endif
|
||||
/******************************************************************
|
||||
NOTE! The following macros should be used instead of buf_page_get_gen, to
|
||||
improve debugging. Only values RW_S_LATCH and RW_X_LATCH are allowed as LA! */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
#define buf_page_get_nowait(SP, OF, LA, MTR) buf_page_get_gen(\
|
||||
SP, OF, LA, NULL,\
|
||||
BUF_GET_NOWAIT, IB__FILE__, __LINE__, MTR)
|
||||
#else
|
||||
#define buf_page_get_nowait(SP, OF, LA, MTR) buf_page_get_gen(\
|
||||
SP, OF, LA, NULL,\
|
||||
BUF_GET_NOWAIT, MTR)
|
||||
#endif
|
||||
/******************************************************************
|
||||
NOTE! The following macros should be used instead of
|
||||
buf_page_optimistic_get_func, to improve debugging. Only values RW_S_LATCH and
|
||||
RW_X_LATCH are allowed as LA! */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
#define buf_page_optimistic_get(LA, G, MC, MTR) buf_page_optimistic_get_func(\
|
||||
LA, G, MC, IB__FILE__, __LINE__, MTR)
|
||||
#else
|
||||
#define buf_page_optimistic_get(LA, G, MC, MTR) buf_page_optimistic_get_func(\
|
||||
LA, G, MC, MTR)
|
||||
#endif
|
||||
/************************************************************************
|
||||
This is the general function used to get optimistic access to a database
|
||||
page. */
|
||||
@@ -175,10 +152,8 @@ buf_page_optimistic_get_func(
|
||||
buf_frame_t* guess, /* in: guessed frame */
|
||||
dulint modify_clock,/* in: modify clock value if mode is
|
||||
..._GUESS_ON_CLOCK */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
char* file, /* in: file name */
|
||||
ulint line, /* in: line where called */
|
||||
#endif
|
||||
mtr_t* mtr); /* in: mini-transaction */
|
||||
/************************************************************************
|
||||
Tries to get the page, but if file io is required, releases all latches
|
||||
@@ -210,10 +185,8 @@ buf_page_get_known_nowait(
|
||||
ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */
|
||||
buf_frame_t* guess, /* in: the known page frame */
|
||||
ulint mode, /* in: BUF_MAKE_YOUNG or BUF_KEEP_OLD */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
char* file, /* in: file name */
|
||||
ulint line, /* in: line where called */
|
||||
#endif
|
||||
mtr_t* mtr); /* in: mini-transaction */
|
||||
/************************************************************************
|
||||
This is the general function used to get access to a database page. */
|
||||
@@ -228,10 +201,8 @@ buf_page_get_gen(
|
||||
buf_frame_t* guess, /* in: guessed frame or NULL */
|
||||
ulint mode, /* in: BUF_GET, BUF_GET_IF_IN_POOL,
|
||||
BUF_GET_NO_LATCH */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
char* file, /* in: file name */
|
||||
ulint line, /* in: line where called */
|
||||
#endif
|
||||
mtr_t* mtr); /* in: mini-transaction */
|
||||
/************************************************************************
|
||||
Initializes a page to the buffer buf_pool. The page is usually not read
|
||||
@@ -455,6 +426,13 @@ Validates the buffer pool data structure. */
|
||||
ibool
|
||||
buf_validate(void);
|
||||
/*==============*/
|
||||
/************************************************************************
|
||||
Prints a page to stderr. */
|
||||
|
||||
void
|
||||
buf_page_print(
|
||||
/*===========*/
|
||||
byte* read_buf); /* in: a database page */
|
||||
/*************************************************************************
|
||||
Prints info of the buffer pool data structure. */
|
||||
|
||||
@@ -462,6 +440,12 @@ void
|
||||
buf_print(void);
|
||||
/*===========*/
|
||||
/*************************************************************************
|
||||
Returns the number of pending buf pool ios. */
|
||||
|
||||
ulint
|
||||
buf_get_n_pending_ios(void);
|
||||
/*=======================*/
|
||||
/*************************************************************************
|
||||
Prints info of the buffer i/o. */
|
||||
|
||||
void
|
||||
@@ -760,6 +744,8 @@ struct buf_pool_struct{
|
||||
byte* frame_zero; /* pointer to the first buffer frame:
|
||||
this may differ from frame_mem, because
|
||||
this is aligned by the frame size */
|
||||
byte* high_end; /* pointer to the end of the
|
||||
buffer pool */
|
||||
buf_block_t* blocks; /* array of buffer control blocks */
|
||||
ulint max_size; /* number of control blocks ==
|
||||
maximum pool size in pages */
|
||||
@@ -767,6 +753,9 @@ struct buf_pool_struct{
|
||||
hash_table_t* page_hash; /* hash table of the file pages */
|
||||
|
||||
ulint n_pend_reads; /* number of pending read operations */
|
||||
|
||||
time_t last_printout_time; /* when buf_print was last time
|
||||
called */
|
||||
ulint n_pages_read; /* number read operations */
|
||||
ulint n_pages_written;/* number write operations */
|
||||
ulint n_pages_created;/* number of pages created in the pool
|
||||
@@ -782,6 +771,9 @@ struct buf_pool_struct{
|
||||
hit rate */
|
||||
ulint n_pages_read_old;/* n_pages_read when buf_print was
|
||||
last time called */
|
||||
ulint n_pages_written_old;/* number write operations */
|
||||
ulint n_pages_created_old;/* number of pages created in
|
||||
the pool with no read */
|
||||
/* 2. Page flushing algorithm fields */
|
||||
|
||||
UT_LIST_BASE_NODE_T(buf_block_t) flush_list;
|
||||
|
@@ -486,11 +486,7 @@ buf_block_buf_fix_inc_debug(
|
||||
{
|
||||
ibool ret;
|
||||
|
||||
ret = rw_lock_s_lock_func_nowait(&(block->debug_latch)
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,file, line
|
||||
#endif
|
||||
);
|
||||
ret = rw_lock_s_lock_func_nowait(&(block->debug_latch), file, line);
|
||||
|
||||
ut_ad(ret == TRUE);
|
||||
|
||||
@@ -557,9 +553,7 @@ buf_page_get_release_on_io(
|
||||
|
||||
frame = buf_page_get_gen(space, offset, rw_latch, guess,
|
||||
BUF_GET_IF_IN_POOL,
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
IB__FILE__, __LINE__,
|
||||
#endif
|
||||
mtr);
|
||||
if (frame != NULL) {
|
||||
|
||||
|
@@ -116,8 +116,8 @@ dfield_copy(
|
||||
Tests if data length and content is equal for two dfields. */
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
dfield_datas_are_equal(
|
||||
/*===================*/
|
||||
dfield_datas_are_binary_equal(
|
||||
/*==========================*/
|
||||
/* out: TRUE if equal */
|
||||
dfield_t* field1, /* in: field */
|
||||
dfield_t* field2);/* in: field */
|
||||
@@ -125,8 +125,8 @@ dfield_datas_are_equal(
|
||||
Tests if dfield data length and content is equal to the given. */
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
dfield_data_is_equal(
|
||||
/*=================*/
|
||||
dfield_data_is_binary_equal(
|
||||
/*========================*/
|
||||
/* out: TRUE if equal */
|
||||
dfield_t* field, /* in: field */
|
||||
ulint len, /* in: data length or UNIV_SQL_NULL */
|
||||
@@ -230,12 +230,16 @@ dtuple_get_data_size(
|
||||
dtuple_t* tuple); /* in: typed data tuple */
|
||||
/****************************************************************
|
||||
Returns TRUE if lengths of two dtuples are equal and respective data fields
|
||||
in them are equal. */
|
||||
UNIV_INLINE
|
||||
in them are equal when compared with collation in char fields (not as binary
|
||||
strings). */
|
||||
|
||||
ibool
|
||||
dtuple_datas_are_equal(
|
||||
/*===================*/
|
||||
/* out: TRUE if length and datas are equal */
|
||||
dtuple_datas_are_ordering_equal(
|
||||
/*============================*/
|
||||
/* out: TRUE if length and fieds are equal
|
||||
when compared with cmp_data_data:
|
||||
NOTE: in character type fields some letters
|
||||
are identified with others! (collation) */
|
||||
dtuple_t* tuple1, /* in: tuple 1 */
|
||||
dtuple_t* tuple2);/* in: tuple 2 */
|
||||
/****************************************************************
|
||||
@@ -447,7 +451,7 @@ struct dfield_struct{
|
||||
|
||||
struct dtuple_struct {
|
||||
ulint info_bits; /* info bits of an index record:
|
||||
default is 0; this field is used
|
||||
the default is 0; this field is used
|
||||
if an index record is built from
|
||||
a data tuple */
|
||||
ulint n_fields; /* number of fields in dtuple */
|
||||
|
@@ -133,8 +133,8 @@ dfield_copy(
|
||||
Tests if data length and content is equal for two dfields. */
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
dfield_datas_are_equal(
|
||||
/*===================*/
|
||||
dfield_datas_are_binary_equal(
|
||||
/*==========================*/
|
||||
/* out: TRUE if equal */
|
||||
dfield_t* field1, /* in: field */
|
||||
dfield_t* field2) /* in: field */
|
||||
@@ -157,8 +157,8 @@ dfield_datas_are_equal(
|
||||
Tests if dfield data length and content is equal to the given. */
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
dfield_data_is_equal(
|
||||
/*=================*/
|
||||
dfield_data_is_binary_equal(
|
||||
/*========================*/
|
||||
/* out: TRUE if equal */
|
||||
dfield_t* field, /* in: field */
|
||||
ulint len, /* in: data length or UNIV_SQL_NULL */
|
||||
@@ -169,8 +169,7 @@ dfield_data_is_equal(
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if ((len != UNIV_SQL_NULL)
|
||||
&& (0 != ut_memcmp(field->data, data, len))) {
|
||||
if (len != UNIV_SQL_NULL && 0 != ut_memcmp(field->data, data, len)) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
@@ -342,65 +341,6 @@ dtuple_get_data_size(
|
||||
return(sum);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Returns TRUE if lengths of two dtuples are equal and respective data fields
|
||||
in them are equal. */
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
dtuple_datas_are_equal(
|
||||
/*===================*/
|
||||
/* out: TRUE if length and datas are equal */
|
||||
dtuple_t* tuple1, /* in: tuple 1 */
|
||||
dtuple_t* tuple2) /* in: tuple 2 */
|
||||
{
|
||||
dfield_t* field1;
|
||||
dfield_t* field2;
|
||||
ulint n_fields;
|
||||
byte* data1;
|
||||
byte* data2;
|
||||
ulint len1;
|
||||
ulint len2;
|
||||
ulint i;
|
||||
|
||||
ut_ad(tuple1 && tuple2);
|
||||
ut_ad(tuple1->magic_n = DATA_TUPLE_MAGIC_N);
|
||||
ut_ad(tuple2->magic_n = DATA_TUPLE_MAGIC_N);
|
||||
ut_ad(dtuple_check_typed(tuple1));
|
||||
ut_ad(dtuple_check_typed(tuple2));
|
||||
|
||||
n_fields = dtuple_get_n_fields(tuple1);
|
||||
|
||||
if (n_fields != dtuple_get_n_fields(tuple2)) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
for (i = 0; i < n_fields; i++) {
|
||||
|
||||
field1 = dtuple_get_nth_field(tuple1, i);
|
||||
data1 = (byte*) dfield_get_data(field1);
|
||||
len1 = dfield_get_len(field1);
|
||||
|
||||
field2 = dtuple_get_nth_field(tuple2, i);
|
||||
data2 = (byte*) dfield_get_data(field2);
|
||||
len2 = dfield_get_len(field2);
|
||||
|
||||
if (len1 != len2) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if (len1 != UNIV_SQL_NULL) {
|
||||
if (ut_memcmp(data1, data2, len1) != 0) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
Sets types of fields binary in a tuple. */
|
||||
UNIV_INLINE
|
||||
|
@@ -124,17 +124,6 @@ dtype_get_pad_char(
|
||||
/* out: padding character code, or
|
||||
ULINT_UNDEFINED if no padding specified */
|
||||
dtype_t* type); /* in: typeumn */
|
||||
/*************************************************************************
|
||||
Transforms the character code so that it is ordered appropriately
|
||||
for the language. */
|
||||
UNIV_INLINE
|
||||
ulint
|
||||
dtype_collate(
|
||||
/*==========*/
|
||||
/* out: padding character */
|
||||
dtype_t* type, /* in: type */
|
||||
ulint code); /* in: character code stored in database
|
||||
record */
|
||||
/***************************************************************************
|
||||
Returns the size of a fixed size data type, 0 if not a fixed size type. */
|
||||
UNIV_INLINE
|
||||
|
@@ -120,23 +120,6 @@ dtype_get_pad_char(
|
||||
return(ULINT_UNDEFINED);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Transforms the character code so that it is ordered appropriately for the
|
||||
language. */
|
||||
UNIV_INLINE
|
||||
ulint
|
||||
dtype_collate(
|
||||
/*==========*/
|
||||
/* out: collation order position */
|
||||
dtype_t* type, /* in: type */
|
||||
ulint code) /* in: character code stored in database
|
||||
record */
|
||||
{
|
||||
ut_ad((type->mtype == DATA_CHAR) || (type->mtype == DATA_VARCHAR));
|
||||
|
||||
return(toupper(code));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Stores to a type the information which determines its alphabetical
|
||||
ordering. */
|
||||
@@ -198,6 +181,10 @@ dtype_get_fixed_size(
|
||||
|
||||
case DATA_SYS: if (type->prtype == DATA_ROW_ID) {
|
||||
return(DATA_ROW_ID_LEN);
|
||||
} else if (type->prtype == DATA_TRX_ID) {
|
||||
return(DATA_TRX_ID_LEN);
|
||||
} else if (type->prtype == DATA_ROLL_PTR) {
|
||||
return(DATA_ROLL_PTR_LEN);
|
||||
} else {
|
||||
return(0);
|
||||
}
|
||||
|
@@ -27,11 +27,20 @@ Created 5/24/1996 Heikki Tuuri
|
||||
#define DB_CLUSTER_NOT_FOUND 30
|
||||
#define DB_TABLE_NOT_FOUND 31
|
||||
#define DB_MUST_GET_MORE_FILE_SPACE 32 /* the database has to be stopped
|
||||
and restrated with more file space */
|
||||
and restarted with more file space */
|
||||
#define DB_TABLE_IS_BEING_USED 33
|
||||
#define DB_TOO_BIG_RECORD 34 /* a record in an index would become
|
||||
bigger than 1/2 free space in a page
|
||||
frame */
|
||||
#define DB_LOCK_WAIT_TIMEOUT 35 /* lock wait lasted too long */
|
||||
#define DB_NO_REFERENCED_ROW 36 /* referenced key value not found
|
||||
for a foreign key in an insert or
|
||||
update of a row */
|
||||
#define DB_ROW_IS_REFERENCED 37 /* cannot delete or update a row
|
||||
because it contains a key value
|
||||
which is referenced */
|
||||
#define DB_CANNOT_ADD_CONSTRAINT 38 /* adding a foreign key constraint
|
||||
to a table failed */
|
||||
|
||||
/* The following are partial failure codes */
|
||||
#define DB_FAIL 1000
|
||||
|
@@ -71,6 +71,24 @@ dict_drop_index_tree(
|
||||
rec_t* rec, /* in: record in the clustered index of SYS_INDEXES
|
||||
table */
|
||||
mtr_t* mtr); /* in: mtr having the latch on the record page */
|
||||
/********************************************************************
|
||||
Creates the foreign key constraints system tables inside InnoDB
|
||||
at database creation or database start if they are not found or are
|
||||
not of the right form. */
|
||||
|
||||
ulint
|
||||
dict_create_or_check_foreign_constraint_tables(void);
|
||||
/*================================================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
/************************************************************************
|
||||
Adds foreign key definitions to data dictionary tables in the database. */
|
||||
|
||||
ulint
|
||||
dict_create_add_foreigns_to_dictionary(
|
||||
/*===================================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
dict_table_t* table, /* in: table */
|
||||
trx_t* trx); /* in: transaction */
|
||||
|
||||
|
||||
/* Table create node structure */
|
||||
|
@@ -138,6 +138,38 @@ dict_table_rename_in_cache(
|
||||
dict_table_t* table, /* in: table */
|
||||
char* new_name); /* in: new name */
|
||||
/**************************************************************************
|
||||
Adds a foreign key constraint object to the dictionary cache. May free
|
||||
the object if there already is an object with the same identifier in.
|
||||
At least one of foreign table or referenced table must already be in
|
||||
the dictionary cache! */
|
||||
|
||||
ulint
|
||||
dict_foreign_add_to_cache(
|
||||
/*======================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
dict_foreign_t* foreign); /* in, own: foreign key constraint */
|
||||
/*************************************************************************
|
||||
Scans a table create SQL string and adds to the data dictionary
|
||||
the foreign key constraints declared in the string. This function
|
||||
should be called after the indexes for a table have been created.
|
||||
Each foreign key constraint must be accompanied with indexes in
|
||||
bot participating tables. The indexes are allowed to contain more
|
||||
fields than mentioned in the constraint. */
|
||||
|
||||
ulint
|
||||
dict_create_foreign_constraints(
|
||||
/*============================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
trx_t* trx, /* in: transaction */
|
||||
char* sql_string, /* in: table create statement where
|
||||
foreign keys are declared like:
|
||||
FOREIGN KEY (a, b) REFERENCES table2(c, d),
|
||||
table2 can be written also with the database
|
||||
name before it: test.table2; the default
|
||||
database id the database of parameter name */
|
||||
char* name); /* in: table full name in the normalized form
|
||||
database_name/table_name */
|
||||
/**************************************************************************
|
||||
Returns a table object and memoryfixes it. NOTE! This is a high-level
|
||||
function to be used mainly from outside the 'dict' directory. Inside this
|
||||
directory dict_table_get_low is usually the appropriate function. */
|
||||
@@ -174,6 +206,14 @@ dict_table_release(
|
||||
/*===============*/
|
||||
dict_table_t* table); /* in: table to be released */
|
||||
/**************************************************************************
|
||||
Checks if a table is in the dictionary cache. */
|
||||
UNIV_INLINE
|
||||
dict_table_t*
|
||||
dict_table_check_if_in_cache_low(
|
||||
/*==============================*/
|
||||
/* out: table, NULL if not found */
|
||||
char* table_name); /* in: table name */
|
||||
/**************************************************************************
|
||||
Gets a table; loads it to the dictionary cache if necessary. A low-level
|
||||
function. */
|
||||
UNIV_INLINE
|
||||
@@ -208,6 +248,13 @@ dict_table_print(
|
||||
/*=============*/
|
||||
dict_table_t* table); /* in: table */
|
||||
/**************************************************************************
|
||||
Prints a table data. */
|
||||
|
||||
void
|
||||
dict_table_print_low(
|
||||
/*=================*/
|
||||
dict_table_t* table); /* in: table */
|
||||
/**************************************************************************
|
||||
Prints a table data when we know the table name. */
|
||||
|
||||
void
|
||||
@@ -319,6 +366,16 @@ dict_table_copy_types(
|
||||
dtuple_t* tuple, /* in: data tuple */
|
||||
dict_table_t* table); /* in: index */
|
||||
/**************************************************************************
|
||||
Looks for an index with the given id. NOTE that we do not reserve
|
||||
the dictionary mutex: this function is for emergency purposes like
|
||||
printing info of a corrupt database page! */
|
||||
|
||||
dict_index_t*
|
||||
dict_index_find_on_id_low(
|
||||
/*======================*/
|
||||
/* out: index or NULL if not found from cache */
|
||||
dulint id); /* in: index id */
|
||||
/**************************************************************************
|
||||
Adds an index to dictionary cache. */
|
||||
|
||||
ibool
|
||||
@@ -640,6 +697,23 @@ dict_tree_get_space_reserve(
|
||||
reserved for updates */
|
||||
dict_tree_t* tree); /* in: a tree */
|
||||
/*************************************************************************
|
||||
Calculates the minimum record length in an index. */
|
||||
|
||||
ulint
|
||||
dict_index_calc_min_rec_len(
|
||||
/*========================*/
|
||||
dict_index_t* index); /* in: index */
|
||||
/*************************************************************************
|
||||
Calculates new estimates for table and index statistics. The statistics
|
||||
are used in query optimization. */
|
||||
|
||||
void
|
||||
dict_update_statistics_low(
|
||||
/*=======================*/
|
||||
dict_table_t* table, /* in: table */
|
||||
ibool has_dict_mutex);/* in: TRUE if the caller has the
|
||||
dictionary mutex */
|
||||
/*************************************************************************
|
||||
Calculates new estimates for table and index statistics. The statistics
|
||||
are used in query optimization. */
|
||||
|
||||
@@ -662,6 +736,7 @@ dict_mutex_exit_for_mysql(void);
|
||||
|
||||
|
||||
extern dict_sys_t* dict_sys; /* the dictionary system */
|
||||
extern rw_lock_t dict_foreign_key_check_lock;
|
||||
|
||||
/* Dictionary system struct */
|
||||
struct dict_sys_struct{
|
||||
|
@@ -532,12 +532,11 @@ dict_tree_get_space_reserve(
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Gets a table; loads it to the dictionary cache if necessary. A low-level
|
||||
function. */
|
||||
Checks if a table is in the dictionary cache. */
|
||||
UNIV_INLINE
|
||||
dict_table_t*
|
||||
dict_table_get_low(
|
||||
/*===============*/
|
||||
dict_table_check_if_in_cache_low(
|
||||
/*==============================*/
|
||||
/* out: table, NULL if not found */
|
||||
char* table_name) /* in: table name */
|
||||
{
|
||||
@@ -552,6 +551,26 @@ dict_table_get_low(
|
||||
|
||||
HASH_SEARCH(name_hash, dict_sys->table_hash, table_fold, table,
|
||||
ut_strcmp(table->name, table_name) == 0);
|
||||
return(table);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Gets a table; loads it to the dictionary cache if necessary. A low-level
|
||||
function. */
|
||||
UNIV_INLINE
|
||||
dict_table_t*
|
||||
dict_table_get_low(
|
||||
/*===============*/
|
||||
/* out: table, NULL if not found */
|
||||
char* table_name) /* in: table name */
|
||||
{
|
||||
dict_table_t* table;
|
||||
|
||||
ut_ad(table_name);
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
table = dict_table_check_if_in_cache_low(table_name);
|
||||
|
||||
if (table == NULL) {
|
||||
table = dict_load_table(table_name);
|
||||
}
|
||||
@@ -603,6 +622,7 @@ dict_table_get_on_id_low(
|
||||
dict_table_t* table;
|
||||
ulint fold;
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
UT_NOT_USED(trx);
|
||||
|
||||
/* Look for the table name in the hash table */
|
||||
|
@@ -14,9 +14,20 @@ Created 4/24/1996 Heikki Tuuri
|
||||
#include "dict0types.h"
|
||||
#include "ut0byte.h"
|
||||
|
||||
/************************************************************************
|
||||
Finds the first table name in the given database. */
|
||||
|
||||
char*
|
||||
dict_get_first_table_name_in_db(
|
||||
/*============================*/
|
||||
/* out, own: table name, NULL if does not exist;
|
||||
the caller must free the memory in the string! */
|
||||
char* name); /* in: database name which ends to '/' */
|
||||
/************************************************************************
|
||||
Loads a table definition and also all its index definitions, and also
|
||||
the cluster definition, if the table is a member in a cluster. */
|
||||
the cluster definition if the table is a member in a cluster. Also loads
|
||||
all foreign key constraints where the foreign key is in the table or where
|
||||
a foreign key references columns in this table. */
|
||||
|
||||
dict_table_t*
|
||||
dict_load_table(
|
||||
@@ -40,6 +51,25 @@ void
|
||||
dict_load_sys_table(
|
||||
/*================*/
|
||||
dict_table_t* table); /* in: system table */
|
||||
/***************************************************************************
|
||||
Loads foreign key constraints where the table is either the foreign key
|
||||
holder or where the table is referenced by a foreign key. Adds these
|
||||
constraints to the data dictionary. Note that we know that the dictionary
|
||||
cache already contains all constraints where the other relevant table is
|
||||
already in the dictionary cache. */
|
||||
|
||||
ulint
|
||||
dict_load_foreigns(
|
||||
/*===============*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
char* table_name); /* in: table name */
|
||||
/************************************************************************
|
||||
Prints to the standard output information on all tables found in the data
|
||||
dictionary system table. */
|
||||
|
||||
void
|
||||
dict_print(void);
|
||||
/*============*/
|
||||
|
||||
|
||||
#ifndef UNIV_NONINL
|
||||
|
@@ -123,6 +123,13 @@ dict_mem_index_free(
|
||||
/*================*/
|
||||
dict_index_t* index); /* in: index */
|
||||
/**************************************************************************
|
||||
Creates and initializes a foreign constraint memory object. */
|
||||
|
||||
dict_foreign_t*
|
||||
dict_mem_foreign_create(void);
|
||||
/*=========================*/
|
||||
/* out, own: foreign constraint struct */
|
||||
/**************************************************************************
|
||||
Creates a procedure memory object. */
|
||||
|
||||
dict_proc_t*
|
||||
@@ -221,15 +228,56 @@ struct dict_index_struct{
|
||||
dictionary cache */
|
||||
btr_search_t* search_info; /* info used in optimistic searches */
|
||||
/*----------------------*/
|
||||
ulint stat_n_diff_key_vals;
|
||||
ib_longlong* stat_n_diff_key_vals;
|
||||
/* approximate number of different key values
|
||||
for this index; we periodically calculate
|
||||
new estimates */
|
||||
for this index, for each n-column prefix
|
||||
where n <= dict_get_n_unique(index); we
|
||||
periodically calculate new estimates */
|
||||
ulint stat_index_size;
|
||||
/* approximate index size in database pages */
|
||||
ulint stat_n_leaf_pages;
|
||||
/* approximate number of leaf pages in the
|
||||
index tree */
|
||||
ulint magic_n;/* magic number */
|
||||
};
|
||||
|
||||
/* Data structure for a foreign key constraint; an example:
|
||||
FOREIGN KEY (A, B) REFERENCES TABLE2 (C, D) */
|
||||
|
||||
struct dict_foreign_struct{
|
||||
mem_heap_t* heap; /* this object is allocated from
|
||||
this memory heap */
|
||||
char* id; /* id of the constraint as a
|
||||
null-terminated string */
|
||||
char* foreign_table_name;/* foreign table name */
|
||||
dict_table_t* foreign_table; /* table where the foreign key is */
|
||||
char** foreign_col_names;/* names of the columns in the
|
||||
foreign key */
|
||||
char* referenced_table_name;/* referenced table name */
|
||||
dict_table_t* referenced_table;/* table where the referenced key
|
||||
is */
|
||||
char** referenced_col_names;/* names of the referenced
|
||||
columns in the referenced table */
|
||||
ulint n_fields; /* number of indexes' first fields
|
||||
for which the the foreign key
|
||||
constraint is defined: we allow the
|
||||
indexes to contain more fields than
|
||||
mentioned in the constraint, as long
|
||||
as the first fields are as mentioned */
|
||||
dict_index_t* foreign_index; /* foreign index; we require that
|
||||
both tables contain explicitly defined
|
||||
indexes for the constraint: InnoDB
|
||||
does not generate new indexes
|
||||
implicitly */
|
||||
dict_index_t* referenced_index;/* referenced index */
|
||||
UT_LIST_NODE_T(dict_foreign_t)
|
||||
foreign_list; /* list node for foreign keys of the
|
||||
table */
|
||||
UT_LIST_NODE_T(dict_foreign_t)
|
||||
referenced_list;/* list node for referenced keys of the
|
||||
table */
|
||||
};
|
||||
|
||||
#define DICT_INDEX_MAGIC_N 76789786
|
||||
|
||||
/* Data structure for a database table */
|
||||
@@ -247,6 +295,13 @@ struct dict_table_struct{
|
||||
dict_col_t* cols; /* array of column descriptions */
|
||||
UT_LIST_BASE_NODE_T(dict_index_t)
|
||||
indexes; /* list of indexes of the table */
|
||||
UT_LIST_BASE_NODE_T(dict_foreign_t)
|
||||
foreign_list;/* list of foreign key constraints
|
||||
in the table; these refer to columns
|
||||
in other tables */
|
||||
UT_LIST_BASE_NODE_T(dict_foreign_t)
|
||||
referenced_list;/* list of foreign key constraints
|
||||
which refer to this table */
|
||||
UT_LIST_NODE_T(dict_table_t)
|
||||
table_LRU; /* node of the LRU list of tables */
|
||||
ulint mem_fix;/* count of how many times the table
|
||||
@@ -254,6 +309,13 @@ struct dict_table_struct{
|
||||
currently NOT used */
|
||||
ibool cached; /* TRUE if the table object has been added
|
||||
to the dictionary cache */
|
||||
lock_t* auto_inc_lock;/* a buffer for an auto-inc lock
|
||||
for this table: we allocate the memory here
|
||||
so that individual transactions can get it
|
||||
and release it without a need to allocate
|
||||
space from the lock heap of the trx:
|
||||
otherwise the lock heap would grow rapidly
|
||||
if we do a large insert from a select */
|
||||
UT_LIST_BASE_NODE_T(lock_t)
|
||||
locks; /* list of locks on the table */
|
||||
/*----------------------*/
|
||||
@@ -278,7 +340,7 @@ struct dict_table_struct{
|
||||
forget about value TRUE if it has to reload
|
||||
the table definition from disk */
|
||||
/*----------------------*/
|
||||
ulint stat_n_rows;
|
||||
ib_longlong stat_n_rows;
|
||||
/* approximate number of rows in the table;
|
||||
we periodically calculate new estimates */
|
||||
ulint stat_clustered_index_size;
|
||||
|
@@ -16,6 +16,7 @@ typedef struct dict_index_struct dict_index_t;
|
||||
typedef struct dict_tree_struct dict_tree_t;
|
||||
typedef struct dict_table_struct dict_table_t;
|
||||
typedef struct dict_proc_struct dict_proc_t;
|
||||
typedef struct dict_foreign_struct dict_foreign_t;
|
||||
|
||||
/* A cluster object is a table object with the type field set to
|
||||
DICT_CLUSTERED */
|
||||
|
@@ -76,6 +76,9 @@ extern fil_addr_t fil_addr_null;
|
||||
#define FIL_TABLESPACE 501
|
||||
#define FIL_LOG 502
|
||||
|
||||
extern ulint fil_n_pending_log_flushes;
|
||||
extern ulint fil_n_pending_tablespace_flushes;
|
||||
|
||||
/***********************************************************************
|
||||
Reserves a right to open a single file. The right must be released with
|
||||
fil_release_right_to_open. */
|
||||
|
@@ -226,6 +226,21 @@ ibuf_contract(
|
||||
issued read with the highest tablespace address
|
||||
to complete */
|
||||
/*************************************************************************
|
||||
Contracts insert buffer trees by reading pages to the buffer pool. */
|
||||
|
||||
ulint
|
||||
ibuf_contract_for_n_pages(
|
||||
/*======================*/
|
||||
/* out: a lower limit for the combined size in bytes
|
||||
of entries which will be merged from ibuf trees to the
|
||||
pages read, 0 if ibuf is empty */
|
||||
ibool sync, /* in: TRUE if the caller wants to wait for the
|
||||
issued read with the highest tablespace address
|
||||
to complete */
|
||||
ulint n_pages);/* in: try to read at least this many pages to
|
||||
the buffer pool and merge the ibuf contents to
|
||||
them */
|
||||
/*************************************************************************
|
||||
Parses a redo log record of an ibuf bitmap page init. */
|
||||
|
||||
byte*
|
||||
|
@@ -21,15 +21,13 @@ Created 5/7/1996 Heikki Tuuri
|
||||
|
||||
extern ibool lock_print_waits;
|
||||
|
||||
/*****************************************************************
|
||||
Cancels a waiting record lock request and releases the waiting transaction
|
||||
that requested it. NOTE: does NOT check if waiting lock requests behind this
|
||||
one can now be granted! */
|
||||
/*************************************************************************
|
||||
Gets the size of a lock struct. */
|
||||
|
||||
void
|
||||
lock_rec_cancel(
|
||||
/*============*/
|
||||
lock_t* lock); /* in: waiting record lock request */
|
||||
ulint
|
||||
lock_get_size(void);
|
||||
/*===============*/
|
||||
/* out: size in bytes */
|
||||
/*************************************************************************
|
||||
Creates the lock system at database start. */
|
||||
|
||||
@@ -388,6 +386,14 @@ lock_is_on_table(
|
||||
/* out: TRUE if there are lock(s) */
|
||||
dict_table_t* table); /* in: database table in dictionary cache */
|
||||
/*************************************************************************
|
||||
Releases an auto-inc lock a transaction possibly has on a table.
|
||||
Releases possible other transactions waiting for this lock. */
|
||||
|
||||
void
|
||||
lock_table_unlock_auto_inc(
|
||||
/*=======================*/
|
||||
trx_t* trx); /* in: transaction */
|
||||
/*************************************************************************
|
||||
Releases transaction locks, and releases possible other transactions waiting
|
||||
because of these locks. */
|
||||
|
||||
@@ -396,6 +402,14 @@ lock_release_off_kernel(
|
||||
/*====================*/
|
||||
trx_t* trx); /* in: transaction */
|
||||
/*************************************************************************
|
||||
Cancels a waiting lock request and releases possible other transactions
|
||||
waiting behind it. */
|
||||
|
||||
void
|
||||
lock_cancel_waiting_and_release(
|
||||
/*============================*/
|
||||
lock_t* lock); /* in: waiting lock request */
|
||||
/*************************************************************************
|
||||
Resets all locks, both table and record locks, on a table to be dropped.
|
||||
No lock is allowed to be a wait lock. */
|
||||
|
||||
@@ -495,6 +509,8 @@ extern lock_sys_t* lock_sys;
|
||||
#define LOCK_IX 3 /* intention exclusive */
|
||||
#define LOCK_S 4 /* shared */
|
||||
#define LOCK_X 5 /* exclusive */
|
||||
#define LOCK_AUTO_INC 6 /* locks the auto-inc counter of a table
|
||||
in an exclusive mode */
|
||||
#define LOCK_MODE_MASK 0xF /* mask used to extract mode from the
|
||||
type_mode field in a lock */
|
||||
#define LOCK_TABLE 16 /* these type values should be so high that */
|
||||
|
@@ -659,6 +659,11 @@ struct log_struct{
|
||||
mutex! */
|
||||
ulint n_log_ios; /* number of log i/os initiated thus
|
||||
far */
|
||||
ulint n_log_ios_old; /* number of log i/o's at the
|
||||
previous printout */
|
||||
time_t last_printout_time;/* when log_print was last time
|
||||
called */
|
||||
|
||||
/* Fields involved in checkpoints */
|
||||
ulint max_modified_age_async;
|
||||
/* when this recommended value for lsn
|
||||
|
@@ -203,20 +203,12 @@ mtr_read_dulint(
|
||||
mtr_t* mtr); /* in: mini-transaction handle */
|
||||
/*************************************************************************
|
||||
This macro locks an rw-lock in s-mode. */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
#define mtr_s_lock(B, MTR) mtr_s_lock_func((B), IB__FILE__, __LINE__,\
|
||||
(MTR))
|
||||
#else
|
||||
#define mtr_s_lock(B, MTR) mtr_s_lock_func((B), (MTR))
|
||||
#endif
|
||||
/*************************************************************************
|
||||
This macro locks an rw-lock in x-mode. */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
#define mtr_x_lock(B, MTR) mtr_x_lock_func((B), IB__FILE__, __LINE__,\
|
||||
(MTR))
|
||||
#else
|
||||
#define mtr_x_lock(B, MTR) mtr_x_lock_func((B), (MTR))
|
||||
#endif
|
||||
/*************************************************************************
|
||||
NOTE! Use the macro above!
|
||||
Locks a lock in s-mode. */
|
||||
@@ -225,10 +217,8 @@ void
|
||||
mtr_s_lock_func(
|
||||
/*============*/
|
||||
rw_lock_t* lock, /* in: rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
char* file, /* in: file name */
|
||||
ulint line, /* in: line number */
|
||||
#endif
|
||||
mtr_t* mtr); /* in: mtr */
|
||||
/*************************************************************************
|
||||
NOTE! Use the macro above!
|
||||
@@ -238,10 +228,8 @@ void
|
||||
mtr_x_lock_func(
|
||||
/*============*/
|
||||
rw_lock_t* lock, /* in: rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
char* file, /* in: file name */
|
||||
ulint line, /* in: line number */
|
||||
#endif
|
||||
mtr_t* mtr); /* in: mtr */
|
||||
|
||||
/*******************************************************
|
||||
|
@@ -217,20 +217,14 @@ void
|
||||
mtr_s_lock_func(
|
||||
/*============*/
|
||||
rw_lock_t* lock, /* in: rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
char* file, /* in: file name */
|
||||
ulint line, /* in: line number */
|
||||
#endif
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
ut_ad(mtr);
|
||||
ut_ad(lock);
|
||||
|
||||
rw_lock_s_lock_func(lock
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,0, file, line
|
||||
#endif
|
||||
);
|
||||
rw_lock_s_lock_func(lock, 0, file, line);
|
||||
|
||||
mtr_memo_push(mtr, lock, MTR_MEMO_S_LOCK);
|
||||
}
|
||||
@@ -242,20 +236,14 @@ void
|
||||
mtr_x_lock_func(
|
||||
/*============*/
|
||||
rw_lock_t* lock, /* in: rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
char* file, /* in: file name */
|
||||
ulint line, /* in: line number */
|
||||
#endif
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
ut_ad(mtr);
|
||||
ut_ad(lock);
|
||||
|
||||
rw_lock_x_lock_func(lock, 0
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
, file, line
|
||||
#endif
|
||||
);
|
||||
rw_lock_x_lock_func(lock, 0, file, line);
|
||||
|
||||
mtr_memo_push(mtr, lock, MTR_MEMO_X_LOCK);
|
||||
}
|
||||
|
@@ -15,6 +15,32 @@ Created 7/1/1994 Heikki Tuuri
|
||||
#include "dict0dict.h"
|
||||
#include "rem0rec.h"
|
||||
|
||||
/*****************************************************************
|
||||
Returns TRUE if two types are equal for comparison purposes. */
|
||||
|
||||
ibool
|
||||
cmp_types_are_equal(
|
||||
/*================*/
|
||||
/* out: TRUE if the types are considered
|
||||
equal in comparisons */
|
||||
dtype_t* type1, /* in: type 1 */
|
||||
dtype_t* type2); /* in: type 2 */
|
||||
/*****************************************************************
|
||||
This function is used to compare two data fields for which we know the
|
||||
data type. */
|
||||
UNIV_INLINE
|
||||
int
|
||||
cmp_data_data(
|
||||
/*==========*/
|
||||
/* out: 1, 0, -1, if data1 is greater, equal,
|
||||
less than data2, respectively */
|
||||
dtype_t* cur_type,/* in: data type of the fields */
|
||||
byte* data1, /* in: data field (== a pointer to a memory
|
||||
buffer) */
|
||||
ulint len1, /* in: data field length or UNIV_SQL_NULL */
|
||||
byte* data2, /* in: data field (== a pointer to a memory
|
||||
buffer) */
|
||||
ulint len2); /* in: data field length or UNIV_SQL_NULL */
|
||||
/*****************************************************************
|
||||
This function is used to compare two dfields where at least the first
|
||||
has its data type field set. */
|
||||
|
@@ -16,6 +16,28 @@ Created 4/20/1996 Heikki Tuuri
|
||||
#include "trx0types.h"
|
||||
#include "row0types.h"
|
||||
|
||||
/*******************************************************************
|
||||
Checks if foreign key constraint fails for an index entry. Sets shared locks
|
||||
which lock either the success or the failure of the constraint. NOTE that
|
||||
the caller must have a shared latch on dict_foreign_key_check_lock. */
|
||||
|
||||
ulint
|
||||
row_ins_check_foreign_constraint(
|
||||
/*=============================*/
|
||||
/* out: DB_SUCCESS, DB_LOCK_WAIT,
|
||||
DB_NO_REFERENCED_ROW,
|
||||
or DB_ROW_IS_REFERENCED */
|
||||
ibool check_ref,/* in: TRUE If we want to check that
|
||||
the referenced table is ok, FALSE if we
|
||||
want to to check the foreign key table */
|
||||
dict_foreign_t* foreign,/* in: foreign constraint; NOTE that the
|
||||
tables mentioned in it must be in the
|
||||
dictionary cache if they exist at all */
|
||||
dict_table_t* table, /* in: if check_ref is TRUE, then the foreign
|
||||
table, else the referenced table */
|
||||
dict_index_t* index, /* in: index in table */
|
||||
dtuple_t* entry, /* in: index entry for index */
|
||||
que_thr_t* thr); /* in: query thread */
|
||||
/*************************************************************************
|
||||
Creates an insert node struct. */
|
||||
|
||||
|
@@ -133,6 +133,26 @@ row_update_prebuilt_trx(
|
||||
handle */
|
||||
trx_t* trx); /* in: transaction handle */
|
||||
/*************************************************************************
|
||||
Unlocks an AUTO_INC type lock possibly reserved by trx. */
|
||||
|
||||
void
|
||||
row_unlock_table_autoinc_for_mysql(
|
||||
/*===============================*/
|
||||
trx_t* trx); /* in: transaction */
|
||||
/*************************************************************************
|
||||
Sets an AUTO_INC type lock on the table mentioned in prebuilt. The
|
||||
AUTO_INC lock gives exclusive access to the auto-inc counter of the
|
||||
table. The lock is reserved only for the duration of an SQL statement.
|
||||
It is not compatible with another AUTO_INC or exclusive lock on the
|
||||
table. */
|
||||
|
||||
int
|
||||
row_lock_table_autoinc_for_mysql(
|
||||
/*=============================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
row_prebuilt_t* prebuilt); /* in: prebuilt struct in the MySQL
|
||||
table handle */
|
||||
/*************************************************************************
|
||||
Does an insert for MySQL. */
|
||||
|
||||
int
|
||||
@@ -211,6 +231,26 @@ row_create_index_for_mysql(
|
||||
dict_index_t* index, /* in: index defintion */
|
||||
trx_t* trx); /* in: transaction handle */
|
||||
/*************************************************************************
|
||||
Scans a table create SQL string and adds to the data dictionary
|
||||
the foreign key constraints declared in the string. This function
|
||||
should be called after the indexes for a table have been created.
|
||||
Each foreign key constraint must be accompanied with indexes in
|
||||
bot participating tables. The indexes are allowed to contain more
|
||||
fields than mentioned in the constraint. */
|
||||
|
||||
int
|
||||
row_table_add_foreign_constraints(
|
||||
/*==============================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
trx_t* trx, /* in: transaction */
|
||||
char* sql_string, /* in: table create statement where
|
||||
foreign keys are declared like:
|
||||
FOREIGN KEY (a, b) REFERENCES table2(c, d),
|
||||
table2 can be written also with the database
|
||||
name before it: test.table2 */
|
||||
char* name); /* in: table full name in the normalized form
|
||||
database_name/table_name */
|
||||
/*************************************************************************
|
||||
Drops a table for MySQL. If the name of the dropped table ends to
|
||||
characters INNODB_MONITOR, then this also stops printing of monitor
|
||||
output by the master thread. */
|
||||
@@ -224,6 +264,15 @@ row_drop_table_for_mysql(
|
||||
ibool has_dict_mutex);/* in: TRUE if the caller already owns the
|
||||
dictionary system mutex */
|
||||
/*************************************************************************
|
||||
Drops a database for MySQL. */
|
||||
|
||||
int
|
||||
row_drop_database_for_mysql(
|
||||
/*========================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
char* name, /* in: database name which ends to '/' */
|
||||
trx_t* trx); /* in: transaction handle */
|
||||
/*************************************************************************
|
||||
Renames a table for MySQL. */
|
||||
|
||||
int
|
||||
|
@@ -47,8 +47,7 @@ upd_get_nth_field(
|
||||
upd_t* update, /* in: update vector */
|
||||
ulint n); /* in: field position in update vector */
|
||||
/*************************************************************************
|
||||
Sets the clustered index field number to be updated by an update vector
|
||||
field. */
|
||||
Sets an index field number to be updated by an update vector field. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
upd_field_set_field_no(
|
||||
@@ -56,7 +55,7 @@ upd_field_set_field_no(
|
||||
upd_field_t* upd_field, /* in: update vector field */
|
||||
ulint field_no, /* in: field number in a clustered
|
||||
index */
|
||||
dict_index_t* index); /* in: clustered index */
|
||||
dict_index_t* index); /* in: index */
|
||||
/*************************************************************************
|
||||
Writes into the redo log the values of trx id and roll ptr and enough info
|
||||
to determine their positions within a clustered index record. */
|
||||
@@ -136,13 +135,27 @@ row_upd_rec_in_place(
|
||||
rec_t* rec, /* in/out: record where replaced */
|
||||
upd_t* update);/* in: update vector */
|
||||
/*******************************************************************
|
||||
Builds an update vector from those fields, excluding the roll ptr and
|
||||
trx id fields, which in an index entry differ from a record that has
|
||||
the equal ordering fields. */
|
||||
Builds an update vector from those fields which in a secondary index entry
|
||||
differ from a record that has the equal ordering fields. NOTE: we compare
|
||||
the fields as binary strings! */
|
||||
|
||||
upd_t*
|
||||
row_upd_build_difference(
|
||||
/*=====================*/
|
||||
row_upd_build_sec_rec_difference_binary(
|
||||
/*====================================*/
|
||||
/* out, own: update vector of differing
|
||||
fields */
|
||||
dict_index_t* index, /* in: index */
|
||||
dtuple_t* entry, /* in: entry to insert */
|
||||
rec_t* rec, /* in: secondary index record */
|
||||
mem_heap_t* heap); /* in: memory heap from which allocated */
|
||||
/*******************************************************************
|
||||
Builds an update vector from those fields, excluding the roll ptr and
|
||||
trx id fields, which in an index entry differ from a record that has
|
||||
the equal ordering fields. NOTE: we compare the fields as binary strings! */
|
||||
|
||||
upd_t*
|
||||
row_upd_build_difference_binary(
|
||||
/*============================*/
|
||||
/* out, own: update vector of differing
|
||||
fields, excluding roll ptr and trx id */
|
||||
dict_index_t* index, /* in: clustered index */
|
||||
@@ -175,13 +188,16 @@ row_upd_clust_index_replace_new_col_vals(
|
||||
/***************************************************************
|
||||
Checks if an update vector changes an ordering field of an index record.
|
||||
This function is fast if the update vector is short or the number of ordering
|
||||
fields in the index is small. Otherwise, this can be quadratic. */
|
||||
fields in the index is small. Otherwise, this can be quadratic.
|
||||
NOTE: we compare the fields as binary strings! */
|
||||
|
||||
ibool
|
||||
row_upd_changes_ord_field(
|
||||
/*======================*/
|
||||
row_upd_changes_ord_field_binary(
|
||||
/*=============================*/
|
||||
/* out: TRUE if update vector changes
|
||||
an ordering field in the index record */
|
||||
an ordering field in the index record;
|
||||
NOTE: the fields are compared as binary
|
||||
strings */
|
||||
dtuple_t* row, /* in: old value of row, or NULL if the
|
||||
row and the data values in update are not
|
||||
known when this function is called, e.g., at
|
||||
@@ -191,11 +207,12 @@ row_upd_changes_ord_field(
|
||||
/***************************************************************
|
||||
Checks if an update vector changes an ordering field of an index record.
|
||||
This function is fast if the update vector is short or the number of ordering
|
||||
fields in the index is small. Otherwise, this can be quadratic. */
|
||||
fields in the index is small. Otherwise, this can be quadratic.
|
||||
NOTE: we compare the fields as binary strings! */
|
||||
|
||||
ibool
|
||||
row_upd_changes_some_index_ord_field(
|
||||
/*=================================*/
|
||||
row_upd_changes_some_index_ord_field_binary(
|
||||
/*========================================*/
|
||||
/* out: TRUE if update vector may change
|
||||
an ordering field in an index record */
|
||||
dict_table_t* table, /* in: table */
|
||||
|
@@ -70,8 +70,7 @@ upd_get_nth_field(
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Sets the clustered index field number to be updated by an update vector
|
||||
field. */
|
||||
Sets an index field number to be updated by an update vector field. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
upd_field_set_field_no(
|
||||
@@ -79,12 +78,18 @@ upd_field_set_field_no(
|
||||
upd_field_t* upd_field, /* in: update vector field */
|
||||
ulint field_no, /* in: field number in a clustered
|
||||
index */
|
||||
dict_index_t* index) /* in: clustered index */
|
||||
dict_index_t* index) /* in: index */
|
||||
{
|
||||
ut_ad(index->type & DICT_CLUSTERED);
|
||||
|
||||
upd_field->field_no = field_no;
|
||||
|
||||
if (field_no >= dict_index_get_n_fields(index)) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to access field %lu in table %s\n"
|
||||
"InnoDB: index %s, but index has only %lu fields\n",
|
||||
field_no, index->table_name, index->name,
|
||||
dict_index_get_n_fields(index));
|
||||
}
|
||||
|
||||
dtype_copy(dfield_get_type(&(upd_field->new_val)),
|
||||
dict_index_get_nth_type(index, field_no));
|
||||
}
|
||||
|
@@ -16,6 +16,11 @@ Created 10/10/1995 Heikki Tuuri
|
||||
#include "com0com.h"
|
||||
#include "que0types.h"
|
||||
|
||||
|
||||
/* When this event is set the lock timeout and InnoDB monitor
|
||||
thread starts running */
|
||||
extern os_event_t srv_lock_timeout_thread_event;
|
||||
|
||||
/* Server parameters which are read from the initfile */
|
||||
|
||||
extern char* srv_data_home;
|
||||
@@ -27,6 +32,8 @@ extern char** srv_data_file_names;
|
||||
extern ulint* srv_data_file_sizes;
|
||||
extern ulint* srv_data_file_is_raw_partition;
|
||||
|
||||
extern ibool srv_created_new_raw;
|
||||
|
||||
#define SRV_NEW_RAW 1
|
||||
#define SRV_OLD_RAW 2
|
||||
|
||||
@@ -39,6 +46,8 @@ extern ibool srv_log_archive_on;
|
||||
extern ulint srv_log_buffer_size;
|
||||
extern ibool srv_flush_log_at_trx_commit;
|
||||
|
||||
extern byte srv_latin1_ordering[256];/* The sort order table of the latin1
|
||||
character set */
|
||||
extern ibool srv_use_native_aio;
|
||||
|
||||
extern ulint srv_pool_size;
|
||||
@@ -54,6 +63,7 @@ extern ulint srv_lock_wait_timeout;
|
||||
|
||||
extern char* srv_unix_file_flush_method_str;
|
||||
extern ulint srv_unix_file_flush_method;
|
||||
extern ulint srv_force_recovery;
|
||||
|
||||
extern ibool srv_use_doublewrite_buf;
|
||||
|
||||
@@ -70,6 +80,7 @@ extern ulint srv_n_rows_read;
|
||||
extern ibool srv_print_innodb_monitor;
|
||||
extern ibool srv_print_innodb_lock_monitor;
|
||||
extern ibool srv_print_innodb_tablespace_monitor;
|
||||
extern ibool srv_print_innodb_table_monitor;
|
||||
|
||||
extern ulint srv_n_spin_wait_rounds;
|
||||
extern ulint srv_spin_wait_delay;
|
||||
@@ -132,6 +143,25 @@ what these mean */
|
||||
#define SRV_UNIX_LITTLESYNC 3
|
||||
#define SRV_UNIX_NOSYNC 4
|
||||
|
||||
/* Alternatives for srv_force_recovery. Non-zero values are intended
|
||||
to help the user get a damaged database up so that he can dump intact
|
||||
tables and rows with SELECT INTO OUTFILE. The database must not otherwise
|
||||
be used with these options! A bigger number below means that all precautions
|
||||
of lower numbers are included. */
|
||||
|
||||
#define SRV_FORCE_IGNORE_CORRUPT 1 /* let the server run even if it
|
||||
detects a corrupt page */
|
||||
#define SRV_FORCE_NO_BACKGROUND 2 /* prevent the main thread from
|
||||
running: if a crash would occur
|
||||
in purge, this prevents it */
|
||||
#define SRV_FORCE_NO_TRX_UNDO 3 /* do not run trx rollback after
|
||||
recovery */
|
||||
#define SRV_FORCE_NO_IBUF_MERGE 4 /* prevent also ibuf operations:
|
||||
if they would cause a crash, better
|
||||
not do them */
|
||||
#define SRV_FORCE_NO_LOG_REDO 5 /* do not do the log roll-forward
|
||||
in connection with recovery */
|
||||
|
||||
/*************************************************************************
|
||||
Boots Innobase server. */
|
||||
|
||||
@@ -224,15 +254,30 @@ srv_release_mysql_thread_if_suspended(
|
||||
que_thr_t* thr); /* in: query thread associated with the
|
||||
MySQL OS thread */
|
||||
/*************************************************************************
|
||||
A thread which wakes up threads whose lock wait may have lasted too long. */
|
||||
A thread which wakes up threads whose lock wait may have lasted too long.
|
||||
This also prints the info output by various InnoDB monitors. */
|
||||
|
||||
#ifndef __WIN__
|
||||
void*
|
||||
#else
|
||||
ulint
|
||||
#endif
|
||||
srv_lock_timeout_monitor_thread(
|
||||
/*============================*/
|
||||
srv_lock_timeout_and_monitor_thread(
|
||||
/*================================*/
|
||||
/* out: a dummy parameter */
|
||||
void* arg); /* in: a dummy parameter required by
|
||||
os_thread_create */
|
||||
/*************************************************************************
|
||||
A thread which prints warnings about semaphore waits which have lasted
|
||||
too long. These can be used to track bugs which cause hangs. */
|
||||
|
||||
#ifndef __WIN__
|
||||
void*
|
||||
#else
|
||||
ulint
|
||||
#endif
|
||||
srv_error_monitor_thread(
|
||||
/*=====================*/
|
||||
/* out: a dummy parameter */
|
||||
void* arg); /* in: a dummy parameter required by
|
||||
os_thread_create */
|
||||
|
@@ -51,12 +51,8 @@ sync_array_reserve_cell(
|
||||
sync_array_t* arr, /* in: wait array */
|
||||
void* object, /* in: pointer to the object to wait for */
|
||||
ulint type, /* in: lock request type */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
char* file, /* in: in debug version file where
|
||||
requested */
|
||||
ulint line, /* in: in the debug version line where
|
||||
requested */
|
||||
#endif
|
||||
char* file, /* in: file where requested */
|
||||
ulint line, /* in: line where requested */
|
||||
ulint* index); /* out: index of the reserved cell */
|
||||
/**********************************************************************
|
||||
This function should be called when a thread starts to wait on
|
||||
@@ -90,6 +86,20 @@ sync_array_signal_object(
|
||||
/*=====================*/
|
||||
sync_array_t* arr, /* in: wait array */
|
||||
void* object);/* in: wait object */
|
||||
/**************************************************************************
|
||||
If the wakeup algorithm does not work perfectly at semaphore relases,
|
||||
this function will do the waking (see the comment in mutex_exit). This
|
||||
function should be called about every 1 second in the server. */
|
||||
|
||||
void
|
||||
sync_arr_wake_threads_if_sema_free(void);
|
||||
/*====================================*/
|
||||
/**************************************************************************
|
||||
Prints warnings of long semaphore waits to stderr. Currently > 120 sec. */
|
||||
|
||||
void
|
||||
sync_array_print_long_waits(void);
|
||||
/*=============================*/
|
||||
/************************************************************************
|
||||
Validates the integrity of the wait array. Checks
|
||||
that the number of reserved cells equals the count variable. */
|
||||
|
@@ -92,7 +92,7 @@ loop:
|
||||
loop_count++;
|
||||
ut_ad(loop_count < 15);
|
||||
|
||||
if (mutex_enter_nowait(mutex) == 0) {
|
||||
if (mutex_enter_nowait(mutex, IB__FILE__, __LINE__) == 0) {
|
||||
/* Succeeded! */
|
||||
|
||||
return(0);
|
||||
@@ -105,7 +105,7 @@ loop:
|
||||
/* Order is important here: FIRST reset event, then set waiters */
|
||||
ip_mutex_set_waiters(ip_mutex, 1);
|
||||
|
||||
if (mutex_enter_nowait(mutex) == 0) {
|
||||
if (mutex_enter_nowait(mutex, IB__FILE__, __LINE__) == 0) {
|
||||
/* Succeeded! */
|
||||
|
||||
return(0);
|
||||
|
@@ -46,9 +46,10 @@ extern ibool rw_lock_debug_waiters; /* This is set to TRUE, if
|
||||
extern ulint rw_s_system_call_count;
|
||||
extern ulint rw_s_spin_wait_count;
|
||||
extern ulint rw_s_exit_count;
|
||||
|
||||
extern ulint rw_s_os_wait_count;
|
||||
extern ulint rw_x_system_call_count;
|
||||
extern ulint rw_x_spin_wait_count;
|
||||
extern ulint rw_x_os_wait_count;
|
||||
extern ulint rw_x_exit_count;
|
||||
|
||||
/**********************************************************************
|
||||
@@ -92,32 +93,20 @@ rw_lock_validate(
|
||||
NOTE! The following macros should be used in rw s-locking, not the
|
||||
corresponding function. */
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
#define rw_lock_s_lock(M) rw_lock_s_lock_func(\
|
||||
(M), 0, IB__FILE__, __LINE__)
|
||||
#else
|
||||
#define rw_lock_s_lock(M) rw_lock_s_lock_func(M)
|
||||
#endif
|
||||
/******************************************************************
|
||||
NOTE! The following macros should be used in rw s-locking, not the
|
||||
corresponding function. */
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
#define rw_lock_s_lock_gen(M, P) rw_lock_s_lock_func(\
|
||||
(M), (P), IB__FILE__, __LINE__)
|
||||
#else
|
||||
#define rw_lock_s_lock_gen(M, P) rw_lock_s_lock_func(M)
|
||||
#endif
|
||||
/******************************************************************
|
||||
NOTE! The following macros should be used in rw s-locking, not the
|
||||
corresponding function. */
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
#define rw_lock_s_lock_nowait(M) rw_lock_s_lock_func_nowait(\
|
||||
(M), IB__FILE__, __LINE__)
|
||||
#else
|
||||
#define rw_lock_s_lock_nowait(M) rw_lock_s_lock_func_nowait(M)
|
||||
#endif
|
||||
/**********************************************************************
|
||||
NOTE! Use the corresponding macro, not directly this function, except if
|
||||
you supply the file name and line number. Lock an rw-lock in shared mode
|
||||
@@ -129,14 +118,11 @@ UNIV_INLINE
|
||||
void
|
||||
rw_lock_s_lock_func(
|
||||
/*================*/
|
||||
rw_lock_t* lock /* in: pointer to rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,ulint pass, /* in: pass value; != 0, if the lock will
|
||||
rw_lock_t* lock, /* in: pointer to rw-lock */
|
||||
ulint pass, /* in: pass value; != 0, if the lock will
|
||||
be passed to another thread to unlock */
|
||||
char* file_name,/* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
);
|
||||
ulint line); /* in: line where requested */
|
||||
/**********************************************************************
|
||||
NOTE! Use the corresponding macro, not directly this function, except if
|
||||
you supply the file name and line number. Lock an rw-lock in shared mode
|
||||
@@ -146,12 +132,9 @@ ibool
|
||||
rw_lock_s_lock_func_nowait(
|
||||
/*=======================*/
|
||||
/* out: TRUE if success */
|
||||
rw_lock_t* lock /* in: pointer to rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,char* file_name, /* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
);
|
||||
rw_lock_t* lock, /* in: pointer to rw-lock */
|
||||
char* file_name,/* in: file name where lock requested */
|
||||
ulint line); /* in: line where requested */
|
||||
/**********************************************************************
|
||||
NOTE! Use the corresponding macro, not directly this function! Lock an
|
||||
rw-lock in exclusive mode for the current thread if the lock can be
|
||||
@@ -161,12 +144,9 @@ ibool
|
||||
rw_lock_x_lock_func_nowait(
|
||||
/*=======================*/
|
||||
/* out: TRUE if success */
|
||||
rw_lock_t* lock /* in: pointer to rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,char* file_name, /* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
);
|
||||
rw_lock_t* lock, /* in: pointer to rw-lock */
|
||||
char* file_name,/* in: file name where lock requested */
|
||||
ulint line); /* in: line where requested */
|
||||
/**********************************************************************
|
||||
Releases a shared mode lock. */
|
||||
UNIV_INLINE
|
||||
@@ -199,32 +179,20 @@ Releases a shared mode lock. */
|
||||
NOTE! The following macro should be used in rw x-locking, not the
|
||||
corresponding function. */
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
#define rw_lock_x_lock(M) rw_lock_x_lock_func(\
|
||||
(M), 0, IB__FILE__, __LINE__)
|
||||
#else
|
||||
#define rw_lock_x_lock(M) rw_lock_x_lock_func(M, 0)
|
||||
#endif
|
||||
/******************************************************************
|
||||
NOTE! The following macro should be used in rw x-locking, not the
|
||||
corresponding function. */
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
#define rw_lock_x_lock_gen(M, P) rw_lock_x_lock_func(\
|
||||
(M), (P), IB__FILE__, __LINE__)
|
||||
#else
|
||||
#define rw_lock_x_lock_gen(M, P) rw_lock_x_lock_func(M, P)
|
||||
#endif
|
||||
/******************************************************************
|
||||
NOTE! The following macros should be used in rw x-locking, not the
|
||||
corresponding function. */
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
#define rw_lock_x_lock_nowait(M) rw_lock_x_lock_func_nowait(\
|
||||
(M), IB__FILE__, __LINE__)
|
||||
#else
|
||||
#define rw_lock_x_lock_nowait(M) rw_lock_x_lock_func_nowait(M)
|
||||
#endif
|
||||
/**********************************************************************
|
||||
NOTE! Use the corresponding macro, not directly this function! Lock an
|
||||
rw-lock in exclusive mode for the current thread. If the rw-lock is locked
|
||||
@@ -239,13 +207,10 @@ void
|
||||
rw_lock_x_lock_func(
|
||||
/*================*/
|
||||
rw_lock_t* lock, /* in: pointer to rw-lock */
|
||||
ulint pass /* in: pass value; != 0, if the lock will
|
||||
ulint pass, /* in: pass value; != 0, if the lock will
|
||||
be passed to another thread to unlock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,char* file_name, /* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
);
|
||||
char* file_name,/* in: file name where lock requested */
|
||||
ulint line); /* in: line where requested */
|
||||
/**********************************************************************
|
||||
Releases an exclusive mode lock. */
|
||||
UNIV_INLINE
|
||||
@@ -283,10 +248,8 @@ void
|
||||
rw_lock_s_lock_direct(
|
||||
/*==================*/
|
||||
rw_lock_t* lock /* in: pointer to rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,char* file_name, /* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
);
|
||||
/**********************************************************************
|
||||
Low-level function which locks an rw-lock in x-mode when we know that it
|
||||
@@ -297,10 +260,8 @@ void
|
||||
rw_lock_x_lock_direct(
|
||||
/*==================*/
|
||||
rw_lock_t* lock /* in: pointer to rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,char* file_name, /* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
);
|
||||
/**********************************************************************
|
||||
This function is used in the insert buffer to move the ownership of an
|
||||
@@ -349,6 +310,23 @@ rw_lock_get_x_lock_count(
|
||||
/*=====================*/
|
||||
/* out: value of writer_count */
|
||||
rw_lock_t* lock); /* in: rw-lock */
|
||||
/************************************************************************
|
||||
Accessor functions for rw lock. */
|
||||
UNIV_INLINE
|
||||
ulint
|
||||
rw_lock_get_waiters(
|
||||
/*================*/
|
||||
rw_lock_t* lock);
|
||||
UNIV_INLINE
|
||||
ulint
|
||||
rw_lock_get_writer(
|
||||
/*===============*/
|
||||
rw_lock_t* lock);
|
||||
UNIV_INLINE
|
||||
ulint
|
||||
rw_lock_get_reader_count(
|
||||
/*=====================*/
|
||||
rw_lock_t* lock);
|
||||
/**********************************************************************
|
||||
Checks if the thread has locked the rw-lock in the specified mode, with
|
||||
the pass value == 0. */
|
||||
@@ -414,9 +392,6 @@ rw_lock_debug_print(
|
||||
/*================*/
|
||||
rw_lock_debug_t* info); /* in: debug struct */
|
||||
|
||||
|
||||
#define RW_CNAME_LEN 8
|
||||
|
||||
/* NOTE! The structure appears here only for the compiler to know its size.
|
||||
Do not use its fields directly! The structure used in the spin lock
|
||||
implementation of a read-write lock. Several threads may have a shared lock
|
||||
@@ -447,7 +422,7 @@ struct rw_lock_struct {
|
||||
ulint waiters; /* This ulint is set to 1 if there are
|
||||
waiters (readers or writers) in the global
|
||||
wait array, waiting for this rw_lock.
|
||||
Otherwise, = 0. */
|
||||
Otherwise, == 0. */
|
||||
ibool writer_is_wait_ex;
|
||||
/* This is TRUE if the writer field is
|
||||
RW_LOCK_WAIT_EX; this field is located far
|
||||
@@ -463,9 +438,12 @@ struct rw_lock_struct {
|
||||
info list of the lock */
|
||||
ulint level; /* Debug version: level in the global latching
|
||||
order; default SYNC_LEVEL_NONE */
|
||||
char cfile_name[RW_CNAME_LEN];
|
||||
/* File name where lock created */
|
||||
char* cfile_name; /* File name where lock created */
|
||||
ulint cline; /* Line where created */
|
||||
char* last_s_file_name;/* File name where last time s-locked */
|
||||
char* last_x_file_name;/* File name where last time x-locked */
|
||||
ulint last_s_line; /* Line number where last time s-locked */
|
||||
ulint last_x_line; /* Line number where last time x-locked */
|
||||
ulint magic_n;
|
||||
};
|
||||
|
||||
|
@@ -15,14 +15,11 @@ waiting for the lock before suspending the thread. */
|
||||
void
|
||||
rw_lock_s_lock_spin(
|
||||
/*================*/
|
||||
rw_lock_t* lock /* in: pointer to rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,ulint pass, /* in: pass value; != 0, if the lock will
|
||||
rw_lock_t* lock, /* in: pointer to rw-lock */
|
||||
ulint pass, /* in: pass value; != 0, if the lock will
|
||||
be passed to another thread to unlock */
|
||||
char* file_name,/* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
);
|
||||
ulint line); /* in: line where requested */
|
||||
/**********************************************************************
|
||||
Inserts the debug information for an rw-lock. */
|
||||
|
||||
@@ -128,14 +125,11 @@ ibool
|
||||
rw_lock_s_lock_low(
|
||||
/*===============*/
|
||||
/* out: TRUE if success */
|
||||
rw_lock_t* lock /* in: pointer to rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,ulint pass, /* in: pass value; != 0, if the lock will be
|
||||
rw_lock_t* lock, /* in: pointer to rw-lock */
|
||||
ulint pass, /* in: pass value; != 0, if the lock will be
|
||||
passed to another thread to unlock */
|
||||
char* file_name, /* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
)
|
||||
ulint line) /* in: line where requested */
|
||||
{
|
||||
ut_ad(mutex_own(rw_lock_get_mutex(lock)));
|
||||
|
||||
@@ -150,6 +144,9 @@ rw_lock_s_lock_low(
|
||||
line);
|
||||
#endif
|
||||
|
||||
lock->last_s_file_name = file_name;
|
||||
lock->last_s_line = line;
|
||||
|
||||
return(TRUE); /* locking succeeded */
|
||||
}
|
||||
|
||||
@@ -164,12 +161,9 @@ UNIV_INLINE
|
||||
void
|
||||
rw_lock_s_lock_direct(
|
||||
/*==================*/
|
||||
rw_lock_t* lock /* in: pointer to rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,char* file_name, /* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
)
|
||||
rw_lock_t* lock, /* in: pointer to rw-lock */
|
||||
char* file_name,/* in: file name where lock requested */
|
||||
ulint line) /* in: line where requested */
|
||||
{
|
||||
ut_ad(lock->writer == RW_LOCK_NOT_LOCKED);
|
||||
ut_ad(rw_lock_get_reader_count(lock) == 0);
|
||||
@@ -177,6 +171,9 @@ rw_lock_s_lock_direct(
|
||||
/* Set the shared lock by incrementing the reader count */
|
||||
lock->reader_count++;
|
||||
|
||||
lock->last_s_file_name = file_name;
|
||||
lock->last_s_line = line;
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
rw_lock_add_debug_info(lock, 0, RW_LOCK_SHARED, file_name, line);
|
||||
#endif
|
||||
@@ -190,12 +187,9 @@ UNIV_INLINE
|
||||
void
|
||||
rw_lock_x_lock_direct(
|
||||
/*==================*/
|
||||
rw_lock_t* lock /* in: pointer to rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,char* file_name, /* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
)
|
||||
rw_lock_t* lock, /* in: pointer to rw-lock */
|
||||
char* file_name, /* in: file name where lock requested */
|
||||
ulint line) /* in: line where requested */
|
||||
{
|
||||
ut_ad(rw_lock_validate(lock));
|
||||
ut_ad(rw_lock_get_reader_count(lock) == 0);
|
||||
@@ -206,6 +200,9 @@ rw_lock_x_lock_direct(
|
||||
lock->writer_count++;
|
||||
lock->pass = 0;
|
||||
|
||||
lock->last_x_file_name = file_name;
|
||||
lock->last_x_line = line;
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
|
||||
#endif
|
||||
@@ -221,14 +218,11 @@ UNIV_INLINE
|
||||
void
|
||||
rw_lock_s_lock_func(
|
||||
/*================*/
|
||||
rw_lock_t* lock /* in: pointer to rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,ulint pass, /* in: pass value; != 0, if the lock will
|
||||
rw_lock_t* lock, /* in: pointer to rw-lock */
|
||||
ulint pass, /* in: pass value; != 0, if the lock will
|
||||
be passed to another thread to unlock */
|
||||
char* file_name, /* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
)
|
||||
ulint line) /* in: line where requested */
|
||||
{
|
||||
/* NOTE: As we do not know the thread ids for threads which have
|
||||
s-locked a latch, and s-lockers will be served only after waiting
|
||||
@@ -245,11 +239,7 @@ rw_lock_s_lock_func(
|
||||
|
||||
mutex_enter(rw_lock_get_mutex(lock));
|
||||
|
||||
if (TRUE == rw_lock_s_lock_low(lock
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,pass, file_name, line
|
||||
#endif
|
||||
)) {
|
||||
if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
|
||||
mutex_exit(rw_lock_get_mutex(lock));
|
||||
|
||||
return; /* Success */
|
||||
@@ -257,11 +247,8 @@ rw_lock_s_lock_func(
|
||||
/* Did not succeed, try spin wait */
|
||||
mutex_exit(rw_lock_get_mutex(lock));
|
||||
|
||||
rw_lock_s_lock_spin(lock
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,pass, file_name, line
|
||||
#endif
|
||||
);
|
||||
rw_lock_s_lock_spin(lock, pass, file_name, line);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -275,12 +262,9 @@ ibool
|
||||
rw_lock_s_lock_func_nowait(
|
||||
/*=======================*/
|
||||
/* out: TRUE if success */
|
||||
rw_lock_t* lock /* in: pointer to rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,char* file_name, /* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
)
|
||||
rw_lock_t* lock, /* in: pointer to rw-lock */
|
||||
char* file_name,/* in: file name where lock requested */
|
||||
ulint line) /* in: line where requested */
|
||||
{
|
||||
ibool success = FALSE;
|
||||
|
||||
@@ -295,6 +279,9 @@ rw_lock_s_lock_func_nowait(
|
||||
line);
|
||||
#endif
|
||||
|
||||
lock->last_s_file_name = file_name;
|
||||
lock->last_s_line = line;
|
||||
|
||||
success = TRUE;
|
||||
}
|
||||
|
||||
@@ -312,12 +299,9 @@ ibool
|
||||
rw_lock_x_lock_func_nowait(
|
||||
/*=======================*/
|
||||
/* out: TRUE if success */
|
||||
rw_lock_t* lock /* in: pointer to rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,char* file_name, /* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
)
|
||||
rw_lock_t* lock, /* in: pointer to rw-lock */
|
||||
char* file_name, /* in: file name where lock requested */
|
||||
ulint line) /* in: line where requested */
|
||||
{
|
||||
ibool success = FALSE;
|
||||
|
||||
@@ -338,6 +322,9 @@ rw_lock_x_lock_func_nowait(
|
||||
rw_lock_add_debug_info(lock, 0, RW_LOCK_EX, file_name, line);
|
||||
#endif
|
||||
|
||||
lock->last_x_file_name = file_name;
|
||||
lock->last_x_line = line;
|
||||
|
||||
success = TRUE;
|
||||
}
|
||||
|
||||
|
@@ -64,23 +64,14 @@ mutex_free(
|
||||
NOTE! The following macro should be used in mutex locking, not the
|
||||
corresponding function. */
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
#define mutex_enter(M) mutex_enter_func((M), IB__FILE__, __LINE__)
|
||||
#else
|
||||
#define mutex_enter(M) mutex_enter_func(M)
|
||||
#endif
|
||||
/******************************************************************
|
||||
NOTE! The following macro should be used in mutex locking, not the
|
||||
corresponding function. */
|
||||
|
||||
/* NOTE! currently same as mutex_enter! */
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
#define mutex_enter_fast(M) mutex_enter_func((M), IB__FILE__, __LINE__)
|
||||
#else
|
||||
#define mutex_enter_fast(M) mutex_enter_func(M)
|
||||
#endif
|
||||
|
||||
#define mutex_enter_fast_func mutex_enter_func;
|
||||
/**********************************************************************
|
||||
NOTE! Use the corresponding macro in the header file, not this function
|
||||
@@ -91,12 +82,9 @@ UNIV_INLINE
|
||||
void
|
||||
mutex_enter_func(
|
||||
/*=============*/
|
||||
mutex_t* mutex /* in: pointer to mutex */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,char* file_name, /* in: file name where locked */
|
||||
ulint line /* in: line where locked */
|
||||
#endif
|
||||
);
|
||||
mutex_t* mutex, /* in: pointer to mutex */
|
||||
char* file_name, /* in: file name where locked */
|
||||
ulint line); /* in: line where locked */
|
||||
/************************************************************************
|
||||
Tries to lock the mutex for the current thread. If the lock is not acquired
|
||||
immediately, returns with return value 1. */
|
||||
@@ -105,7 +93,10 @@ ulint
|
||||
mutex_enter_nowait(
|
||||
/*===============*/
|
||||
/* out: 0 if succeed, 1 if not */
|
||||
mutex_t* mutex); /* in: pointer to mutex */
|
||||
mutex_t* mutex, /* in: pointer to mutex */
|
||||
char* file_name, /* in: file name where mutex
|
||||
requested */
|
||||
ulint line); /* in: line where requested */
|
||||
/**********************************************************************
|
||||
Unlocks a mutex owned by the current thread. */
|
||||
UNIV_INLINE
|
||||
@@ -373,6 +364,7 @@ Memory pool mutex */
|
||||
#define SYNC_LEVEL_NONE 2000 /* default: level not defined */
|
||||
#define SYNC_DICT 1000
|
||||
#define SYNC_DICT_AUTOINC_MUTEX 999
|
||||
#define SYNC_FOREIGN_KEY_CHECK 998
|
||||
#define SYNC_PURGE_IS_RUNNING 997
|
||||
#define SYNC_DICT_HEADER 995
|
||||
#define SYNC_IBUF_HEADER 914
|
||||
@@ -418,6 +410,7 @@ Memory pool mutex */
|
||||
#define SYNC_BUF_BLOCK 149
|
||||
#define SYNC_DOUBLEWRITE 140
|
||||
#define SYNC_ANY_LATCH 135
|
||||
#define SYNC_THR_LOCAL 133
|
||||
#define SYNC_MEM_HASH 131
|
||||
#define SYNC_MEM_POOL 130
|
||||
|
||||
@@ -429,8 +422,6 @@ Memory pool mutex */
|
||||
#define RW_LOCK_WAIT_EX 353
|
||||
#define SYNC_MUTEX 354
|
||||
|
||||
#define MUTEX_CNAME_LEN 8
|
||||
|
||||
/* NOTE! The structure appears here only for the compiler to know its size.
|
||||
Do not use its fields directly! The structure used in the spin lock
|
||||
implementation of a mutual exclusion semaphore. */
|
||||
@@ -457,8 +448,7 @@ struct mutex_struct {
|
||||
locked */
|
||||
ulint level; /* Debug version: level in the global latching
|
||||
order; default SYNC_LEVEL_NONE */
|
||||
char cfile_name[MUTEX_CNAME_LEN];
|
||||
/* File name where mutex created */
|
||||
char* cfile_name; /* File name where mutex created */
|
||||
ulint cline; /* Line where created */
|
||||
ulint magic_n;
|
||||
};
|
||||
|
@@ -22,13 +22,9 @@ for the mutex before suspending the thread. */
|
||||
void
|
||||
mutex_spin_wait(
|
||||
/*============*/
|
||||
mutex_t* mutex /* in: pointer to mutex */
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,char* file_name, /* in: file name where mutex requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
);
|
||||
mutex_t* mutex, /* in: pointer to mutex */
|
||||
char* file_name,/* in: file name where mutex requested */
|
||||
ulint line); /* in: line where requested */
|
||||
/**********************************************************************
|
||||
Sets the debug information for a reserved mutex. */
|
||||
|
||||
@@ -209,6 +205,18 @@ mutex_exit(
|
||||
#endif
|
||||
mutex_reset_lock_word(mutex);
|
||||
|
||||
/* A problem: we assume that mutex_reset_lock word
|
||||
is a memory barrier, that is when we read the waiters
|
||||
field next, the read must be serialized in memory
|
||||
after the reset. A speculative processor might
|
||||
perform the read first, which could leave a waiting
|
||||
thread hanging indefinitely.
|
||||
|
||||
Our current solution call every 10 seconds
|
||||
sync_arr_wake_threads_if_sema_free()
|
||||
to wake up possible hanging threads if
|
||||
they are missed in mutex_signal_object. */
|
||||
|
||||
if (mutex_get_waiters(mutex) != 0) {
|
||||
|
||||
mutex_signal_object(mutex);
|
||||
@@ -227,12 +235,9 @@ UNIV_INLINE
|
||||
void
|
||||
mutex_enter_func(
|
||||
/*=============*/
|
||||
mutex_t* mutex /* in: pointer to mutex */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,char* file_name, /* in: file name where locked */
|
||||
ulint line /* in: line where locked */
|
||||
#endif
|
||||
)
|
||||
mutex_t* mutex, /* in: pointer to mutex */
|
||||
char* file_name,/* in: file name where locked */
|
||||
ulint line) /* in: line where locked */
|
||||
{
|
||||
ut_ad(mutex_validate(mutex));
|
||||
|
||||
@@ -245,13 +250,11 @@ mutex_enter_func(
|
||||
mutex_set_debug_info(mutex, file_name, line);
|
||||
#endif
|
||||
|
||||
mutex->file_name = file_name;
|
||||
mutex->line = line;
|
||||
|
||||
return; /* Succeeded! */
|
||||
}
|
||||
|
||||
mutex_spin_wait(mutex
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,file_name,
|
||||
line
|
||||
#endif
|
||||
);
|
||||
mutex_spin_wait(mutex, file_name, line);
|
||||
}
|
||||
|
@@ -61,7 +61,11 @@ trx_rsegf_get_nth_undo(
|
||||
ulint n, /* in: index of slot */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
ut_ad(n < TRX_RSEG_N_SLOTS);
|
||||
if (n >= TRX_RSEG_N_SLOTS) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to get slot %lu of rseg\n", n);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
return(mtr_read_ulint(rsegf + TRX_RSEG_UNDO_SLOTS +
|
||||
n * TRX_RSEG_SLOT_SIZE, MLOG_4BYTES, mtr));
|
||||
@@ -78,7 +82,11 @@ trx_rsegf_set_nth_undo(
|
||||
ulint page_no,/* in: page number of the undo log segment */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
ut_ad(n < TRX_RSEG_N_SLOTS);
|
||||
if (n >= TRX_RSEG_N_SLOTS) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to set slot %lu of rseg\n", n);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
mlog_write_ulint(rsegf + TRX_RSEG_UNDO_SLOTS + n * TRX_RSEG_SLOT_SIZE,
|
||||
page_no, MLOG_4BYTES, mtr);
|
||||
|
@@ -317,6 +317,19 @@ struct trx_struct{
|
||||
ibool has_search_latch;
|
||||
/* TRUE if this trx has latched the
|
||||
search system latch in S-mode */
|
||||
ulint search_latch_timeout;
|
||||
/* If we notice that someone is
|
||||
waiting for our S-lock on the search
|
||||
latch to be released, we wait in
|
||||
row0sel.c for BTR_SEA_TIMEOUT new
|
||||
searches until we try to keep
|
||||
the search latch again over
|
||||
calls from MySQL; this is intended
|
||||
to reduce contention on the search
|
||||
latch */
|
||||
lock_t* auto_inc_lock; /* possible auto-inc lock reserved by
|
||||
the transaction; note that it is also
|
||||
in the lock list trx_locks */
|
||||
ibool ignore_duplicates_in_insert;
|
||||
/* in an insert roll back only insert
|
||||
of the latest row in case
|
||||
@@ -401,11 +414,9 @@ struct trx_struct{
|
||||
checking algorithm */
|
||||
/*------------------------------*/
|
||||
mem_heap_t* lock_heap; /* memory heap for the locks of the
|
||||
transaction; protected by
|
||||
lock_heap_mutex */
|
||||
transaction */
|
||||
UT_LIST_BASE_NODE_T(lock_t)
|
||||
trx_locks; /* locks reserved by the transaction;
|
||||
protected by lock_heap_mutex */
|
||||
trx_locks; /* locks reserved by the transaction */
|
||||
/*------------------------------*/
|
||||
mem_heap_t* read_view_heap; /* memory heap for the read view */
|
||||
read_view_t* read_view; /* consistent read view or NULL */
|
||||
|
@@ -13,6 +13,9 @@ Created 5/30/1994 Heikki Tuuri
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* The total amount of memory currently allocated from the OS with malloc */
|
||||
extern ulint ut_total_allocated_memory;
|
||||
|
||||
UNIV_INLINE
|
||||
void*
|
||||
ut_memcpy(void* dest, void* sour, ulint n);
|
||||
|
@@ -577,6 +577,17 @@ lock_sys_create(
|
||||
/* hash_create_mutexes(lock_sys->rec_hash, 2, SYNC_REC_LOCK); */
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Gets the size of a lock struct. */
|
||||
|
||||
ulint
|
||||
lock_get_size(void)
|
||||
/*===============*/
|
||||
/* out: size in bytes */
|
||||
{
|
||||
return((ulint)sizeof(lock_t));
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Gets the mode of a lock. */
|
||||
UNIV_INLINE
|
||||
@@ -709,13 +720,17 @@ lock_mode_stronger_or_eq(
|
||||
ulint mode2) /* in: lock mode */
|
||||
{
|
||||
ut_ad(mode1 == LOCK_X || mode1 == LOCK_S || mode1 == LOCK_IX
|
||||
|| mode1 == LOCK_IS);
|
||||
|| mode1 == LOCK_IS || mode1 == LOCK_AUTO_INC);
|
||||
ut_ad(mode2 == LOCK_X || mode2 == LOCK_S || mode2 == LOCK_IX
|
||||
|| mode2 == LOCK_IS);
|
||||
|| mode2 == LOCK_IS || mode2 == LOCK_AUTO_INC);
|
||||
if (mode1 == LOCK_X) {
|
||||
|
||||
return(TRUE);
|
||||
|
||||
} else if (mode1 == LOCK_AUTO_INC && mode2 == LOCK_AUTO_INC) {
|
||||
|
||||
return(TRUE);
|
||||
|
||||
} else if (mode1 == LOCK_S
|
||||
&& (mode2 == LOCK_S || mode2 == LOCK_IS)) {
|
||||
return(TRUE);
|
||||
@@ -743,9 +758,9 @@ lock_mode_compatible(
|
||||
ulint mode2) /* in: lock mode */
|
||||
{
|
||||
ut_ad(mode1 == LOCK_X || mode1 == LOCK_S || mode1 == LOCK_IX
|
||||
|| mode1 == LOCK_IS);
|
||||
|| mode1 == LOCK_IS || mode1 == LOCK_AUTO_INC);
|
||||
ut_ad(mode2 == LOCK_X || mode2 == LOCK_S || mode2 == LOCK_IX
|
||||
|| mode2 == LOCK_IS);
|
||||
|| mode2 == LOCK_IS || mode2 == LOCK_AUTO_INC);
|
||||
|
||||
if (mode1 == LOCK_S && (mode2 == LOCK_IS || mode2 == LOCK_S)) {
|
||||
|
||||
@@ -755,12 +770,18 @@ lock_mode_compatible(
|
||||
|
||||
return(FALSE);
|
||||
|
||||
} else if (mode1 == LOCK_AUTO_INC && (mode2 == LOCK_IS
|
||||
|| mode2 == LOCK_IX)) {
|
||||
return(TRUE);
|
||||
|
||||
} else if (mode1 == LOCK_IS && (mode2 == LOCK_IS
|
||||
|| mode2 == LOCK_IX
|
||||
|| mode2 == LOCK_AUTO_INC
|
||||
|| mode2 == LOCK_S)) {
|
||||
return(TRUE);
|
||||
|
||||
} else if (mode1 == LOCK_IX && (mode2 == LOCK_IS
|
||||
|| mode2 == LOCK_AUTO_INC
|
||||
|| mode2 == LOCK_IX)) {
|
||||
return(TRUE);
|
||||
}
|
||||
@@ -1836,7 +1857,7 @@ lock_grant(
|
||||
Cancels a waiting record lock request and releases the waiting transaction
|
||||
that requested it. NOTE: does NOT check if waiting lock requests behind this
|
||||
one can now be granted! */
|
||||
|
||||
static
|
||||
void
|
||||
lock_rec_cancel(
|
||||
/*============*/
|
||||
@@ -2812,7 +2833,18 @@ lock_table_create(
|
||||
ut_ad(table && trx);
|
||||
ut_ad(mutex_own(&kernel_mutex));
|
||||
|
||||
if (type_mode == LOCK_AUTO_INC) {
|
||||
/* Only one trx can have the lock on the table
|
||||
at a time: we may use the memory preallocated
|
||||
to the table object */
|
||||
|
||||
lock = table->auto_inc_lock;
|
||||
|
||||
ut_a(trx->auto_inc_lock == NULL);
|
||||
trx->auto_inc_lock = lock;
|
||||
} else {
|
||||
lock = mem_heap_alloc(trx->lock_heap, sizeof(lock_t));
|
||||
}
|
||||
|
||||
if (lock == NULL) {
|
||||
|
||||
@@ -2854,6 +2886,10 @@ lock_table_remove_low(
|
||||
table = lock->un_member.tab_lock.table;
|
||||
trx = lock->trx;
|
||||
|
||||
if (lock == trx->auto_inc_lock) {
|
||||
trx->auto_inc_lock = NULL;
|
||||
}
|
||||
|
||||
UT_LIST_REMOVE(trx_locks, trx->trx_locks, lock);
|
||||
UT_LIST_REMOVE(un_member.tab_lock.locks, table->locks, lock);
|
||||
}
|
||||
@@ -2988,7 +3024,7 @@ lock_table(
|
||||
|
||||
if (lock_table_other_has_incompatible(trx, LOCK_WAIT, table, mode)) {
|
||||
|
||||
/* Another trx has request on the table in an incompatible
|
||||
/* Another trx has a request on the table in an incompatible
|
||||
mode: this trx must wait */
|
||||
|
||||
err = lock_table_enqueue_waiting(mode, table, thr);
|
||||
@@ -3101,6 +3137,24 @@ lock_table_dequeue(
|
||||
|
||||
/*=========================== LOCK RELEASE ==============================*/
|
||||
|
||||
/*************************************************************************
|
||||
Releases an auto-inc lock a transaction possibly has on a table.
|
||||
Releases possible other transactions waiting for this lock. */
|
||||
|
||||
void
|
||||
lock_table_unlock_auto_inc(
|
||||
/*=======================*/
|
||||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
if (trx->auto_inc_lock) {
|
||||
mutex_enter(&kernel_mutex);
|
||||
|
||||
lock_table_dequeue(trx->auto_inc_lock);
|
||||
|
||||
mutex_exit(&kernel_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Releases transaction locks, and releases possible other transactions waiting
|
||||
because of these locks. */
|
||||
@@ -3147,6 +3201,37 @@ lock_release_off_kernel(
|
||||
}
|
||||
|
||||
mem_heap_empty(trx->lock_heap);
|
||||
|
||||
ut_a(trx->auto_inc_lock == NULL);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Cancels a waiting lock request and releases possible other transactions
|
||||
waiting behind it. */
|
||||
|
||||
void
|
||||
lock_cancel_waiting_and_release(
|
||||
/*============================*/
|
||||
lock_t* lock) /* in: waiting lock request */
|
||||
{
|
||||
ut_ad(mutex_own(&kernel_mutex));
|
||||
|
||||
if (lock_get_type(lock) == LOCK_REC) {
|
||||
|
||||
lock_rec_dequeue_from_page(lock);
|
||||
} else {
|
||||
ut_ad(lock_get_type(lock) == LOCK_TABLE);
|
||||
|
||||
lock_table_dequeue(lock);
|
||||
}
|
||||
|
||||
/* Reset the wait flag and the back pointer to lock in trx */
|
||||
|
||||
lock_reset_lock_and_trx_wait(lock);
|
||||
|
||||
/* The following function releases the trx from lock wait */
|
||||
|
||||
trx_end_lock_wait(lock->trx);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
@@ -3237,8 +3322,10 @@ lock_table_print(
|
||||
printf(" lock_mode IS");
|
||||
} else if (lock_get_mode(lock) == LOCK_IX) {
|
||||
printf(" lock_mode IX");
|
||||
} else if (lock_get_mode(lock) == LOCK_AUTO_INC) {
|
||||
printf(" lock_mode AUTO-INC");
|
||||
} else {
|
||||
ut_error;
|
||||
printf(" unknown lock_mode %lu", lock_get_mode(lock));
|
||||
}
|
||||
|
||||
if (lock_get_wait(lock)) {
|
||||
@@ -3304,10 +3391,7 @@ lock_rec_print(
|
||||
|
||||
page = buf_page_get_gen(space, page_no, RW_NO_LATCH,
|
||||
NULL, BUF_GET_IF_IN_POOL,
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
IB__FILE__, __LINE__,
|
||||
#endif
|
||||
&mtr);
|
||||
IB__FILE__, __LINE__, &mtr);
|
||||
if (page) {
|
||||
page = buf_page_get_nowait(space, page_no, RW_S_LATCH, &mtr);
|
||||
}
|
||||
@@ -3418,6 +3502,11 @@ loop:
|
||||
|
||||
i = 0;
|
||||
|
||||
/* Since we temporarily release the kernel mutex when
|
||||
reading a database page in below, variable trx may be
|
||||
obsolete now and we must loop through the trx list to
|
||||
get probably the same trx, or some other trx. */
|
||||
|
||||
while (trx && (i < nth_trx)) {
|
||||
trx = UT_LIST_GET_NEXT(trx_list, trx);
|
||||
i++;
|
||||
@@ -3466,6 +3555,9 @@ loop:
|
||||
|
||||
i = 0;
|
||||
|
||||
/* Look at the note about the trx loop above why we loop here:
|
||||
lock may be an obsolete pointer now. */
|
||||
|
||||
lock = UT_LIST_GET_FIRST(trx->trx_locks);
|
||||
|
||||
while (lock && (i < nth_lock)) {
|
||||
|
@@ -572,6 +572,9 @@ log_init(void)
|
||||
log_sys->buf = ut_align(buf, OS_FILE_LOG_BLOCK_SIZE);
|
||||
|
||||
log_sys->buf_size = LOG_BUFFER_SIZE;
|
||||
|
||||
memset(log_sys->buf, '\0', LOG_BUFFER_SIZE);
|
||||
|
||||
log_sys->max_buf_free = log_sys->buf_size / LOG_BUF_FLUSH_RATIO
|
||||
- LOG_BUF_FLUSH_MARGIN;
|
||||
log_sys->check_flush_or_checkpoint = TRUE;
|
||||
@@ -579,6 +582,8 @@ log_init(void)
|
||||
|
||||
log_sys->n_log_ios = 0;
|
||||
|
||||
log_sys->n_log_ios_old = log_sys->n_log_ios;
|
||||
log_sys->last_printout_time = time(NULL);
|
||||
/*----------------------------*/
|
||||
|
||||
log_sys->buf_next_to_write = 0;
|
||||
@@ -609,6 +614,7 @@ log_init(void)
|
||||
log_sys->checkpoint_buf = ut_align(
|
||||
mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE),
|
||||
OS_FILE_LOG_BLOCK_SIZE);
|
||||
memset(log_sys->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE);
|
||||
/*----------------------------*/
|
||||
|
||||
log_sys->archiving_state = LOG_ARCH_ON;
|
||||
@@ -626,6 +632,8 @@ log_init(void)
|
||||
OS_FILE_LOG_BLOCK_SIZE);
|
||||
log_sys->archive_buf_size = LOG_ARCHIVE_BUF_SIZE;
|
||||
|
||||
memset(log_sys->archive_buf, '\0', LOG_ARCHIVE_BUF_SIZE);
|
||||
|
||||
log_sys->archiving_on = os_event_create(NULL);
|
||||
|
||||
/*----------------------------*/
|
||||
@@ -2791,8 +2799,35 @@ void
|
||||
log_print(void)
|
||||
/*===========*/
|
||||
{
|
||||
printf("Log sequence number %lu %lu\n",
|
||||
ut_dulint_get_high(log_sys->lsn),
|
||||
ut_dulint_get_low(log_sys->lsn));
|
||||
}
|
||||
double time_elapsed;
|
||||
time_t current_time;
|
||||
|
||||
mutex_enter(&(log_sys->mutex));
|
||||
|
||||
printf("Log sequence number %lu %lu\n"
|
||||
"Log flushed up to %lu %lu\n"
|
||||
"Last checkpoint at %lu %lu\n",
|
||||
ut_dulint_get_high(log_sys->lsn),
|
||||
ut_dulint_get_low(log_sys->lsn),
|
||||
ut_dulint_get_high(log_sys->written_to_some_lsn),
|
||||
ut_dulint_get_low(log_sys->written_to_some_lsn),
|
||||
ut_dulint_get_high(log_sys->last_checkpoint_lsn),
|
||||
ut_dulint_get_low(log_sys->last_checkpoint_lsn));
|
||||
|
||||
current_time = time(NULL);
|
||||
|
||||
time_elapsed = difftime(current_time, log_sys->last_printout_time);
|
||||
|
||||
printf(
|
||||
"%lu pending log writes, %lu pending chkp writes\n"
|
||||
"%lu log i/o's done, %.2f log i/o's/second\n",
|
||||
log_sys->n_pending_writes,
|
||||
log_sys->n_pending_checkpoint_writes,
|
||||
log_sys->n_log_ios,
|
||||
(log_sys->n_log_ios - log_sys->n_log_ios_old) / time_elapsed);
|
||||
|
||||
log_sys->n_log_ios_old = log_sys->n_log_ios;
|
||||
log_sys->last_printout_time = current_time;
|
||||
|
||||
mutex_exit(&(log_sys->mutex));
|
||||
}
|
||||
|
@@ -560,6 +560,7 @@ recv_parse_or_apply_log_rec_body(
|
||||
} else if (type <= MLOG_WRITE_STRING) {
|
||||
new_ptr = mlog_parse_string(ptr, end_ptr, page);
|
||||
} else {
|
||||
new_ptr = NULL; /* Eliminate compiler warning */
|
||||
ut_error;
|
||||
}
|
||||
|
||||
@@ -801,9 +802,7 @@ recv_recover_page(
|
||||
mtr_set_log_mode(&mtr, MTR_LOG_NONE);
|
||||
|
||||
success = buf_page_get_known_nowait(RW_X_LATCH, page, BUF_KEEP_OLD,
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
IB__FILE__, __LINE__,
|
||||
#endif
|
||||
&mtr);
|
||||
ut_a(success);
|
||||
|
||||
@@ -1212,9 +1211,7 @@ recv_compare_spaces(
|
||||
|
||||
frame = buf_page_get_gen(space1, page_no, RW_S_LATCH, NULL,
|
||||
BUF_GET_IF_IN_POOL,
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
IB__FILE__, __LINE__,
|
||||
#endif
|
||||
&mtr);
|
||||
if (frame) {
|
||||
buf_page_dbg_add_level(frame, SYNC_NO_ORDER_CHECK);
|
||||
@@ -1227,9 +1224,7 @@ recv_compare_spaces(
|
||||
|
||||
frame = buf_page_get_gen(space2, page_no, RW_S_LATCH, NULL,
|
||||
BUF_GET_IF_IN_POOL,
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
IB__FILE__, __LINE__,
|
||||
#endif
|
||||
&mtr);
|
||||
if (frame) {
|
||||
buf_page_dbg_add_level(frame, SYNC_NO_ORDER_CHECK);
|
||||
@@ -2033,8 +2028,11 @@ recv_recovery_from_checkpoint_start(
|
||||
while (group) {
|
||||
old_scanned_lsn = recv_sys->scanned_lsn;
|
||||
|
||||
if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
|
||||
recv_group_scan_log_recs(group, &contiguous_lsn,
|
||||
&group_scanned_lsn);
|
||||
}
|
||||
|
||||
group->scanned_lsn = group_scanned_lsn;
|
||||
|
||||
if (ut_dulint_cmp(old_scanned_lsn, group_scanned_lsn) < 0) {
|
||||
@@ -2120,7 +2118,9 @@ recv_recovery_from_checkpoint_finish(void)
|
||||
{
|
||||
/* Rollback the uncommitted transactions which have no user session */
|
||||
|
||||
if (srv_force_recovery < SRV_FORCE_NO_TRX_UNDO) {
|
||||
trx_rollback_all_without_sess();
|
||||
}
|
||||
|
||||
/* Apply the hashed log records to the respective file pages */
|
||||
|
||||
|
@@ -76,7 +76,7 @@ pool, and after that its locks will grow into the buffer pool. */
|
||||
#define MEM_AREA_FREE 1
|
||||
|
||||
/* The smallest memory area total size */
|
||||
#define MEM_AREA_MIN_SIZE (2 * sizeof(struct mem_area_struct))
|
||||
#define MEM_AREA_MIN_SIZE (2 * MEM_AREA_EXTRA_SIZE)
|
||||
|
||||
/* Data structure for a memory pool. The space is allocated using the buddy
|
||||
algorithm, where free list i contains areas of size 2 to power i. */
|
||||
@@ -556,7 +556,7 @@ Returns the amount of reserved memory. */
|
||||
ulint
|
||||
mem_pool_get_reserved(
|
||||
/*==================*/
|
||||
/* out: reserved mmeory in bytes */
|
||||
/* out: reserved memory in bytes */
|
||||
mem_pool_t* pool) /* in: memory pool */
|
||||
{
|
||||
ulint reserved;
|
||||
|
@@ -54,6 +54,13 @@ mlog_write_initial_log_record(
|
||||
|
||||
ut_ad(type <= MLOG_BIGGEST_TYPE);
|
||||
|
||||
if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to write to a stray memory location %lx\n",
|
||||
(ulint)ptr);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
log_ptr = mlog_open(mtr, 20);
|
||||
|
||||
/* If no logging is requested, we may return now */
|
||||
@@ -184,6 +191,13 @@ mlog_write_ulint(
|
||||
{
|
||||
byte* log_ptr;
|
||||
|
||||
if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to write to a stray memory location %lx\n",
|
||||
(ulint)ptr);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
if (type == MLOG_1BYTE) {
|
||||
mach_write_to_1(ptr, val);
|
||||
} else if (type == MLOG_2BYTES) {
|
||||
@@ -225,6 +239,13 @@ mlog_write_dulint(
|
||||
{
|
||||
byte* log_ptr;
|
||||
|
||||
if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to write to a stray memory location %lx\n",
|
||||
(ulint)ptr);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
ut_ad(ptr && mtr);
|
||||
ut_ad(type == MLOG_8BYTES);
|
||||
|
||||
@@ -262,6 +283,12 @@ mlog_write_string(
|
||||
{
|
||||
byte* log_ptr;
|
||||
|
||||
if (ptr < buf_pool->frame_zero || ptr >= buf_pool->high_end) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: trying to write to a stray memory location %lx\n",
|
||||
(ulint)ptr);
|
||||
ut_a(0);
|
||||
}
|
||||
ut_ad(ptr && mtr);
|
||||
ut_ad(len < UNIV_PAGE_SIZE);
|
||||
|
||||
|
@@ -11,6 +11,7 @@ Created 10/21/1995 Heikki Tuuri
|
||||
#include "ut0mem.h"
|
||||
#include "srv0srv.h"
|
||||
#include "trx0sys.h"
|
||||
#include "fil0fil.h"
|
||||
|
||||
#undef HAVE_FDATASYNC
|
||||
|
||||
@@ -109,6 +110,14 @@ os_aio_array_t* os_aio_sync_array = NULL;
|
||||
|
||||
ulint os_aio_n_segments = ULINT_UNDEFINED;
|
||||
|
||||
ulint os_n_file_reads = 0;
|
||||
ulint os_n_file_writes = 0;
|
||||
ulint os_n_fsyncs = 0;
|
||||
ulint os_n_file_reads_old = 0;
|
||||
ulint os_n_file_writes_old = 0;
|
||||
ulint os_n_fsyncs_old = 0;
|
||||
time_t os_last_printout;
|
||||
|
||||
/***************************************************************************
|
||||
Gets the operating system version. Currently works only on Windows. */
|
||||
|
||||
@@ -160,7 +169,7 @@ os_file_get_last_error(void)
|
||||
|
||||
if (err != ERROR_FILE_EXISTS) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: operating system error number %li in a file operation.\n",
|
||||
"InnoDB: Warning: operating system error number %li in a file operation.\n",
|
||||
(long) err);
|
||||
}
|
||||
|
||||
@@ -178,7 +187,7 @@ os_file_get_last_error(void)
|
||||
|
||||
if (err != EEXIST) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: operating system error number %i in a file operation.\n",
|
||||
"InnoDB: Warning: operating system error number %i in a file operation.\n",
|
||||
errno);
|
||||
}
|
||||
|
||||
@@ -231,8 +240,10 @@ os_file_handle_error(
|
||||
exit(1);
|
||||
|
||||
} else if (err == OS_FILE_AIO_RESOURCES_RESERVED) {
|
||||
|
||||
return(TRUE);
|
||||
|
||||
} else if (err == OS_FILE_ALREADY_EXISTS) {
|
||||
return(FALSE);
|
||||
} else {
|
||||
fprintf(stderr, "InnoDB: Cannot continue operation.\n");
|
||||
|
||||
@@ -317,15 +328,11 @@ try_again:
|
||||
if (file == INVALID_HANDLE_VALUE) {
|
||||
*success = FALSE;
|
||||
|
||||
if (create_mode != OS_FILE_OPEN
|
||||
&& os_file_get_last_error() == OS_FILE_DISK_FULL) {
|
||||
|
||||
retry = os_file_handle_error(file, name);
|
||||
|
||||
if (retry) {
|
||||
goto try_again;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*success = TRUE;
|
||||
}
|
||||
@@ -369,15 +376,11 @@ try_again:
|
||||
if (file == -1) {
|
||||
*success = FALSE;
|
||||
|
||||
if (create_mode != OS_FILE_OPEN
|
||||
&& errno == ENOSPC) {
|
||||
|
||||
retry = os_file_handle_error(file, name);
|
||||
|
||||
if (retry) {
|
||||
goto try_again;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*success = TRUE;
|
||||
}
|
||||
@@ -407,6 +410,7 @@ os_file_close(
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
os_file_handle_error(file, NULL);
|
||||
return(FALSE);
|
||||
#else
|
||||
int ret;
|
||||
@@ -414,6 +418,7 @@ os_file_close(
|
||||
ret = close(file);
|
||||
|
||||
if (ret == -1) {
|
||||
os_file_handle_error(file, NULL);
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
@@ -551,6 +556,8 @@ os_file_flush(
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
os_file_handle_error(file, NULL);
|
||||
|
||||
return(FALSE);
|
||||
#else
|
||||
int ret;
|
||||
@@ -560,6 +567,8 @@ os_file_flush(
|
||||
#else
|
||||
ret = fsync(file);
|
||||
#endif
|
||||
os_n_fsyncs++;
|
||||
|
||||
if (ret == 0) {
|
||||
return(TRUE);
|
||||
}
|
||||
@@ -589,6 +598,8 @@ os_file_pread(
|
||||
{
|
||||
off_t offs = (off_t)offset;
|
||||
|
||||
os_n_file_reads++;
|
||||
|
||||
#ifdef HAVE_PREAD
|
||||
return(pread(file, buf, n, offs));
|
||||
#else
|
||||
@@ -631,6 +642,8 @@ os_file_pwrite(
|
||||
ssize_t ret;
|
||||
off_t offs = (off_t)offset;
|
||||
|
||||
os_n_file_writes++;
|
||||
|
||||
#ifdef HAVE_PWRITE
|
||||
ret = pwrite(file, buf, n, offs);
|
||||
|
||||
@@ -702,12 +715,13 @@ os_file_read(
|
||||
BOOL ret;
|
||||
DWORD len;
|
||||
DWORD ret2;
|
||||
DWORD err;
|
||||
DWORD low;
|
||||
DWORD high;
|
||||
ibool retry;
|
||||
ulint i;
|
||||
|
||||
os_n_file_reads++;
|
||||
|
||||
try_again:
|
||||
ut_ad(file);
|
||||
ut_ad(buf);
|
||||
@@ -724,7 +738,6 @@ try_again:
|
||||
ret2 = SetFilePointer(file, low, &high, FILE_BEGIN);
|
||||
|
||||
if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
|
||||
err = GetLastError();
|
||||
|
||||
os_mutex_exit(os_file_seek_mutexes[i]);
|
||||
|
||||
@@ -738,8 +751,6 @@ try_again:
|
||||
if (ret && len == n) {
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
err = GetLastError();
|
||||
#else
|
||||
ibool retry;
|
||||
ssize_t ret;
|
||||
@@ -791,12 +802,12 @@ os_file_write(
|
||||
BOOL ret;
|
||||
DWORD len;
|
||||
DWORD ret2;
|
||||
DWORD err;
|
||||
DWORD low;
|
||||
DWORD high;
|
||||
ibool retry;
|
||||
ulint i;
|
||||
|
||||
os_n_file_writes++;
|
||||
try_again:
|
||||
ut_ad(file);
|
||||
ut_ad(buf);
|
||||
@@ -813,7 +824,6 @@ try_again:
|
||||
ret2 = SetFilePointer(file, low, &high, FILE_BEGIN);
|
||||
|
||||
if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
|
||||
err = GetLastError();
|
||||
|
||||
os_mutex_exit(os_file_seek_mutexes[i]);
|
||||
|
||||
@@ -987,6 +997,8 @@ os_aio_init(
|
||||
os_aio_segment_wait_events[i] = os_event_create(NULL);
|
||||
}
|
||||
|
||||
os_last_printout = time(NULL);
|
||||
|
||||
#ifdef POSIX_ASYNC_IO
|
||||
/* Block aio signals from the current thread and its children:
|
||||
for this to work, the current thread must be the first created
|
||||
@@ -1461,6 +1473,7 @@ try_again:
|
||||
} else if (mode == OS_AIO_SYNC) {
|
||||
array = os_aio_sync_array;
|
||||
} else {
|
||||
array = NULL; /* Eliminate compiler warning */
|
||||
ut_error;
|
||||
}
|
||||
|
||||
@@ -1469,6 +1482,7 @@ try_again:
|
||||
if (type == OS_FILE_READ) {
|
||||
if (os_aio_use_native_aio) {
|
||||
#ifdef WIN_ASYNC_IO
|
||||
os_n_file_reads++;
|
||||
ret = ReadFile(file, buf, (DWORD)n, &len,
|
||||
&(slot->control));
|
||||
#elif defined(POSIX_ASYNC_IO)
|
||||
@@ -1485,6 +1499,7 @@ try_again:
|
||||
} else if (type == OS_FILE_WRITE) {
|
||||
if (os_aio_use_native_aio) {
|
||||
#ifdef WIN_ASYNC_IO
|
||||
os_n_file_writes++;
|
||||
ret = WriteFile(file, buf, (DWORD)n, &len,
|
||||
&(slot->control));
|
||||
#elif defined(POSIX_ASYNC_IO)
|
||||
@@ -1583,7 +1598,6 @@ os_aio_windows_handle(
|
||||
ulint n;
|
||||
ulint i;
|
||||
ibool ret_val;
|
||||
ulint err;
|
||||
BOOL ret;
|
||||
DWORD len;
|
||||
|
||||
@@ -1635,7 +1649,8 @@ os_aio_windows_handle(
|
||||
ut_a(TRUE == os_file_flush(slot->file));
|
||||
}
|
||||
} else {
|
||||
err = GetLastError();
|
||||
os_file_get_last_error();
|
||||
|
||||
ut_error;
|
||||
|
||||
ret_val = FALSE;
|
||||
@@ -2032,6 +2047,8 @@ os_aio_print(void)
|
||||
os_aio_array_t* array;
|
||||
os_aio_slot_t* slot;
|
||||
ulint n_reserved;
|
||||
time_t current_time;
|
||||
double time_elapsed;
|
||||
ulint i;
|
||||
|
||||
for (i = 0; i < srv_n_file_io_threads; i++) {
|
||||
@@ -2066,12 +2083,12 @@ loop:
|
||||
|
||||
ut_a(array->n_reserved == n_reserved);
|
||||
|
||||
printf("%lu\n", n_reserved);
|
||||
printf(" %lu", n_reserved);
|
||||
|
||||
os_mutex_exit(array->mutex);
|
||||
|
||||
if (array == os_aio_read_array) {
|
||||
printf("Pending aio writes: ");
|
||||
printf(", aio writes:");
|
||||
|
||||
array = os_aio_write_array;
|
||||
|
||||
@@ -2079,25 +2096,48 @@ loop:
|
||||
}
|
||||
|
||||
if (array == os_aio_write_array) {
|
||||
printf("Pending insert buffer aio reads: ");
|
||||
printf(",\n ibuf aio reads:");
|
||||
array = os_aio_ibuf_array;
|
||||
|
||||
goto loop;
|
||||
}
|
||||
|
||||
if (array == os_aio_ibuf_array) {
|
||||
printf("Pending log writes or reads: ");
|
||||
printf(", log i/o's:");
|
||||
array = os_aio_log_array;
|
||||
|
||||
goto loop;
|
||||
}
|
||||
|
||||
if (array == os_aio_log_array) {
|
||||
printf("Pending synchronous reads or writes: ");
|
||||
printf(", sync i/o's:");
|
||||
array = os_aio_sync_array;
|
||||
|
||||
goto loop;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
current_time = time(NULL);
|
||||
time_elapsed = difftime(current_time, os_last_printout);
|
||||
|
||||
printf("Pending flushes (fsync) log: %lu; buffer pool: %lu\n",
|
||||
fil_n_pending_log_flushes, fil_n_pending_tablespace_flushes);
|
||||
printf("%lu OS file reads, %lu OS file writes, %lu OS fsyncs\n",
|
||||
os_n_file_reads, os_n_file_writes, os_n_fsyncs);
|
||||
printf("%.2f reads/s, %.2f writes/s, %.2f fsyncs/s\n",
|
||||
(os_n_file_reads - os_n_file_reads_old)
|
||||
/ time_elapsed,
|
||||
(os_n_file_writes - os_n_file_writes_old)
|
||||
/ time_elapsed,
|
||||
(os_n_fsyncs - os_n_fsyncs_old)
|
||||
/ time_elapsed);
|
||||
|
||||
os_n_file_reads_old = os_n_file_reads;
|
||||
os_n_file_writes_old = os_n_file_writes;
|
||||
os_n_fsyncs_old = os_n_fsyncs;
|
||||
|
||||
os_last_printout = current_time;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
@@ -1258,8 +1258,8 @@ page_validate(
|
||||
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));
|
||||
index->name, (ulint)page_header_get_ptr(page, PAGE_HEAP_TOP),
|
||||
(ulint)page_dir_get_nth_slot(page, n_slots - 1));
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
@@ -7362,7 +7362,7 @@ static void *yy_flex_alloc( size )
|
||||
unsigned int size;
|
||||
#endif
|
||||
{
|
||||
return (void *) malloc( size );
|
||||
return (void *) mem_alloc( size );
|
||||
}
|
||||
|
||||
#ifdef YY_USE_PROTOS
|
||||
@@ -7373,7 +7373,7 @@ void *ptr;
|
||||
unsigned int size;
|
||||
#endif
|
||||
{
|
||||
return (void *) realloc( ptr, size );
|
||||
return (void *) mem_realloc( ptr, size );
|
||||
}
|
||||
|
||||
#ifdef YY_USE_PROTOS
|
||||
@@ -7383,6 +7383,6 @@ static void yy_flex_free( ptr )
|
||||
void *ptr;
|
||||
#endif
|
||||
{
|
||||
free( ptr );
|
||||
mem_free( ptr );
|
||||
}
|
||||
|
||||
|
@@ -97,11 +97,8 @@ que_node_t */
|
||||
#define YYSTYPE que_node_t*
|
||||
|
||||
#include "univ.i"
|
||||
#undef alloca
|
||||
#define alloca mem_alloc
|
||||
#include <math.h>
|
||||
#include "pars0pars.h"
|
||||
#include "mem0mem.h"
|
||||
#include "que0types.h"
|
||||
#include "que0que.h"
|
||||
#include "row0sel.h"
|
||||
@@ -705,7 +702,7 @@ int yydebug; /* nonzero means print parse trace */
|
||||
/* YYINITDEPTH indicates the initial size of the parser's stacks */
|
||||
|
||||
#ifndef YYINITDEPTH
|
||||
#define YYINITDEPTH 200
|
||||
#define YYINITDEPTH 1000
|
||||
#endif
|
||||
|
||||
/* YYMAXDEPTH is the maximum size the stacks can grow to
|
||||
@@ -896,17 +893,22 @@ yynewstate:
|
||||
if (yystacksize >= YYMAXDEPTH)
|
||||
{
|
||||
yyerror("parser stack overflow");
|
||||
ut_a(0);
|
||||
return 2;
|
||||
}
|
||||
yystacksize *= 2;
|
||||
if (yystacksize > YYMAXDEPTH)
|
||||
yystacksize = YYMAXDEPTH;
|
||||
yyss = (short *) alloca (yystacksize * sizeof (*yyssp));
|
||||
|
||||
ut_a(0); /* Prevent possible memory leaks through the following
|
||||
mem_alloc's */
|
||||
|
||||
yyss = (short *) mem_alloc (yystacksize * sizeof (*yyssp));
|
||||
__yy_memcpy ((char *)yyss, (char *)yyss1, size * sizeof (*yyssp));
|
||||
yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp));
|
||||
yyvs = (YYSTYPE *) mem_alloc (yystacksize * sizeof (*yyvsp));
|
||||
__yy_memcpy ((char *)yyvs, (char *)yyvs1, size * sizeof (*yyvsp));
|
||||
#ifdef YYLSP_NEEDED
|
||||
yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp));
|
||||
yyls = (YYLTYPE *) mem_alloc (yystacksize * sizeof (*yylsp));
|
||||
__yy_memcpy ((char *)yyls, (char *)yyls1, size * sizeof (*yylsp));
|
||||
#endif
|
||||
#endif /* no yyoverflow */
|
||||
@@ -1663,7 +1665,7 @@ yyerrlab: /* here on detecting error */
|
||||
x < (sizeof(yytname) / sizeof(char *)); x++)
|
||||
if (yycheck[x + yyn] == x)
|
||||
size += strlen(yytname[x]) + 15, count++;
|
||||
msg = (char *) malloc(size + 15);
|
||||
msg = (char *) mem_alloc(size + 15);
|
||||
if (msg != 0)
|
||||
{
|
||||
strcpy(msg, "parse error");
|
||||
@@ -1682,7 +1684,7 @@ yyerrlab: /* here on detecting error */
|
||||
}
|
||||
}
|
||||
yyerror(msg);
|
||||
free(msg);
|
||||
mem_free(msg);
|
||||
}
|
||||
else
|
||||
yyerror ("parse error; also virtual memory exceeded");
|
||||
|
@@ -543,6 +543,7 @@ opt_search_plan_for_table(
|
||||
/* Calculate goodness for each index of the table */
|
||||
|
||||
index = dict_table_get_first_index(table);
|
||||
best_index = index; /* Eliminate compiler warning */
|
||||
best_goodness = 0;
|
||||
|
||||
while (index) {
|
||||
|
@@ -922,7 +922,8 @@ pars_process_assign_list(
|
||||
|
||||
changes_ord_field = UPD_NODE_NO_ORD_CHANGE;
|
||||
|
||||
if (row_upd_changes_some_index_ord_field(node->table, node->update)) {
|
||||
if (row_upd_changes_some_index_ord_field_binary(node->table,
|
||||
node->update)) {
|
||||
changes_ord_field = 0;
|
||||
}
|
||||
|
||||
|
@@ -832,7 +832,7 @@ que_thr_dec_refer_count(
|
||||
sess_t* sess;
|
||||
ibool send_srv_msg = FALSE;
|
||||
ibool release_stored_proc = FALSE;
|
||||
ulint msg_len;
|
||||
ulint msg_len = 0;
|
||||
byte msg_buf[ODBC_DATAGRAM_SIZE];
|
||||
ulint fork_type;
|
||||
ibool stopped;
|
||||
|
@@ -12,6 +12,8 @@ Created 7/1/1994 Heikki Tuuri
|
||||
#include "rem0cmp.ic"
|
||||
#endif
|
||||
|
||||
#include "srv0srv.h"
|
||||
|
||||
/* ALPHABETICAL ORDER
|
||||
==================
|
||||
|
||||
@@ -68,6 +70,54 @@ innobase_mysql_cmp(
|
||||
unsigned int b_length); /* in: data field length,
|
||||
not UNIV_SQL_NULL */
|
||||
|
||||
/*************************************************************************
|
||||
Transforms the character code so that it is ordered appropriately for the
|
||||
language. This is only used for the latin1 char set. MySQL does the
|
||||
comparisons for other char sets. */
|
||||
UNIV_INLINE
|
||||
ulint
|
||||
cmp_collate(
|
||||
/*========*/
|
||||
/* out: collation order position */
|
||||
dtype_t* type, /* in: type */
|
||||
ulint code) /* in: code of a character stored in database
|
||||
record */
|
||||
{
|
||||
ut_ad((type->mtype == DATA_CHAR) || (type->mtype == DATA_VARCHAR));
|
||||
|
||||
return((ulint) srv_latin1_ordering[code]);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
Returns TRUE if two types are equal for comparison purposes. */
|
||||
|
||||
ibool
|
||||
cmp_types_are_equal(
|
||||
/*================*/
|
||||
/* out: TRUE if the types are considered
|
||||
equal in comparisons */
|
||||
dtype_t* type1, /* in: type 1 */
|
||||
dtype_t* type2) /* in: type 2 */
|
||||
{
|
||||
if (type1->mtype != type2->mtype) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if (type1->mtype == DATA_MYSQL
|
||||
|| type1->mtype == DATA_VARMYSQL) {
|
||||
|
||||
if ((type1->prtype & ~DATA_NOT_NULL)
|
||||
!= (type2->prtype & ~DATA_NOT_NULL)) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Innobase uses this function is to compare two data fields for which the
|
||||
data type is such that we must compare whole fields. */
|
||||
@@ -269,8 +319,8 @@ cmp_data_data_slow(
|
||||
}
|
||||
|
||||
if (cur_type->mtype <= DATA_CHAR) {
|
||||
data1_byte = dtype_collate(cur_type, data1_byte);
|
||||
data2_byte = dtype_collate(cur_type, data2_byte);
|
||||
data1_byte = cmp_collate(cur_type, data1_byte);
|
||||
data2_byte = cmp_collate(cur_type, data2_byte);
|
||||
}
|
||||
|
||||
if (data1_byte > data2_byte) {
|
||||
@@ -482,8 +532,8 @@ cmp_dtuple_rec_with_match(
|
||||
}
|
||||
|
||||
if (cur_type->mtype <= DATA_CHAR) {
|
||||
rec_byte = dtype_collate(cur_type, rec_byte);
|
||||
dtuple_byte = dtype_collate(cur_type,
|
||||
rec_byte = cmp_collate(cur_type, rec_byte);
|
||||
dtuple_byte = cmp_collate(cur_type,
|
||||
dtuple_byte);
|
||||
}
|
||||
|
||||
@@ -796,8 +846,8 @@ cmp_rec_rec_with_match(
|
||||
}
|
||||
|
||||
if (cur_type->mtype <= DATA_CHAR) {
|
||||
rec1_byte = dtype_collate(cur_type, rec1_byte);
|
||||
rec2_byte = dtype_collate(cur_type, rec2_byte);
|
||||
rec1_byte = cmp_collate(cur_type, rec1_byte);
|
||||
rec2_byte = cmp_collate(cur_type, rec2_byte);
|
||||
}
|
||||
|
||||
if (rec1_byte < rec2_byte) {
|
||||
|
@@ -207,16 +207,33 @@ row_ins_sec_index_entry_by_modify(
|
||||
/*==============================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
btr_cur_t* cursor, /* in: B-tree cursor */
|
||||
dtuple_t* entry, /* in: index entry to insert */
|
||||
que_thr_t* thr, /* in: query thread */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
mem_heap_t* heap;
|
||||
upd_t* update;
|
||||
rec_t* rec;
|
||||
ulint err;
|
||||
|
||||
ut_ad(((cursor->index)->type & DICT_CLUSTERED) == 0);
|
||||
ut_ad(rec_get_deleted_flag(btr_cur_get_rec(cursor)));
|
||||
rec = btr_cur_get_rec(cursor);
|
||||
|
||||
/* We just remove the delete mark from the secondary index record */
|
||||
err = btr_cur_del_mark_set_sec_rec(0, cursor, FALSE, thr, mtr);
|
||||
ut_ad((cursor->index->type & DICT_CLUSTERED) == 0);
|
||||
ut_ad(rec_get_deleted_flag(rec));
|
||||
|
||||
/* We know that in the ordering entry and rec are identified.
|
||||
But in their binary form there may be differences if there
|
||||
are char fields in them. Therefore we have to calculate the
|
||||
difference and do an update-in-place if necessary. */
|
||||
|
||||
heap = mem_heap_create(1024);
|
||||
|
||||
update = row_upd_build_sec_rec_difference_binary(cursor->index,
|
||||
entry, rec, heap);
|
||||
|
||||
err = btr_cur_update_sec_rec_in_place(cursor, update, thr, mtr);
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(err);
|
||||
}
|
||||
@@ -262,7 +279,7 @@ row_ins_clust_index_entry_by_modify(
|
||||
/* Build an update vector containing all the fields to be modified;
|
||||
NOTE that this vector may contain also system columns! */
|
||||
|
||||
update = row_upd_build_difference(cursor->index, entry, ext_vec,
|
||||
update = row_upd_build_difference_binary(cursor->index, entry, ext_vec,
|
||||
n_ext_vec, rec, heap);
|
||||
if (mode == BTR_MODIFY_LEAF) {
|
||||
/* Try optimistic updating of the record, keeping changes
|
||||
@@ -347,6 +364,203 @@ row_ins_set_shared_rec_lock(
|
||||
return(err);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
Checks if foreign key constraint fails for an index entry. Sets shared locks
|
||||
which lock either the success or the failure of the constraint. NOTE that
|
||||
the caller must have a shared latch on dict_foreign_key_check_lock. */
|
||||
|
||||
ulint
|
||||
row_ins_check_foreign_constraint(
|
||||
/*=============================*/
|
||||
/* out: DB_SUCCESS, DB_LOCK_WAIT,
|
||||
DB_NO_REFERENCED_ROW,
|
||||
or DB_ROW_IS_REFERENCED */
|
||||
ibool check_ref,/* in: TRUE If we want to check that
|
||||
the referenced table is ok, FALSE if we
|
||||
want to to check the foreign key table */
|
||||
dict_foreign_t* foreign,/* in: foreign constraint; NOTE that the
|
||||
tables mentioned in it must be in the
|
||||
dictionary cache if they exist at all */
|
||||
dict_table_t* table, /* in: if check_ref is TRUE, then the foreign
|
||||
table, else the referenced table */
|
||||
dict_index_t* index, /* in: index in table */
|
||||
dtuple_t* entry, /* in: index entry for index */
|
||||
que_thr_t* thr) /* in: query thread */
|
||||
{
|
||||
dict_table_t* check_table;
|
||||
dict_index_t* check_index;
|
||||
ulint n_fields_cmp;
|
||||
rec_t* rec;
|
||||
btr_pcur_t pcur;
|
||||
ibool moved;
|
||||
int cmp;
|
||||
ulint err;
|
||||
mtr_t mtr;
|
||||
|
||||
ut_ad(rw_lock_own(&dict_foreign_key_check_lock, RW_LOCK_SHARED));
|
||||
|
||||
if (check_ref) {
|
||||
check_table = foreign->referenced_table;
|
||||
check_index = foreign->referenced_index;
|
||||
} else {
|
||||
check_table = foreign->foreign_table;
|
||||
check_index = foreign->foreign_index;
|
||||
}
|
||||
|
||||
if (check_table == NULL) {
|
||||
if (check_ref) {
|
||||
return(DB_NO_REFERENCED_ROW);
|
||||
}
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
ut_a(check_table && check_index);
|
||||
|
||||
if (check_table != table) {
|
||||
/* We already have a LOCK_IX on table, but not necessarily
|
||||
on check_table */
|
||||
|
||||
err = lock_table(0, check_table, LOCK_IS, thr);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
return(err);
|
||||
}
|
||||
}
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
/* Store old value on n_fields_cmp */
|
||||
|
||||
n_fields_cmp = dtuple_get_n_fields_cmp(entry);
|
||||
|
||||
dtuple_set_n_fields_cmp(entry, foreign->n_fields);
|
||||
|
||||
btr_pcur_open(check_index, entry, PAGE_CUR_GE,
|
||||
BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||
|
||||
/* Scan index records and check if there is a matching record */
|
||||
|
||||
for (;;) {
|
||||
rec = btr_pcur_get_rec(&pcur);
|
||||
|
||||
if (rec == page_get_infimum_rec(buf_frame_align(rec))) {
|
||||
|
||||
goto next_rec;
|
||||
}
|
||||
|
||||
/* Try to place a lock on the index record */
|
||||
|
||||
err = row_ins_set_shared_rec_lock(rec, check_index, thr);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
|
||||
|
||||
goto next_rec;
|
||||
}
|
||||
|
||||
cmp = cmp_dtuple_rec(entry, rec);
|
||||
|
||||
if (cmp == 0) {
|
||||
if (!rec_get_deleted_flag(rec)) {
|
||||
/* Found a matching record */
|
||||
|
||||
if (check_ref) {
|
||||
err = DB_SUCCESS;
|
||||
} else {
|
||||
err = DB_ROW_IS_REFERENCED;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmp < 0) {
|
||||
if (check_ref) {
|
||||
err = DB_NO_REFERENCED_ROW;
|
||||
} else {
|
||||
err = DB_SUCCESS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
ut_a(cmp == 0);
|
||||
next_rec:
|
||||
moved = btr_pcur_move_to_next(&pcur, &mtr);
|
||||
|
||||
if (!moved) {
|
||||
if (check_ref) {
|
||||
err = DB_NO_REFERENCED_ROW;
|
||||
} else {
|
||||
err = DB_SUCCESS;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mtr_commit(&mtr);
|
||||
|
||||
/* Restore old value */
|
||||
dtuple_set_n_fields_cmp(entry, n_fields_cmp);
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
Checks if foreign key constraints fail for an index entry. If index
|
||||
is not mentioned in any constraint, this function does nothing,
|
||||
Otherwise does searches to the indexes of referenced tables and
|
||||
sets shared locks which lock either the success or the failure of
|
||||
a constraint. */
|
||||
static
|
||||
ulint
|
||||
row_ins_check_foreign_constraints(
|
||||
/*==============================*/
|
||||
/* out: DB_SUCCESS, DB_LOCK_WAIT, or error
|
||||
code */
|
||||
dict_table_t* table, /* in: table */
|
||||
dict_index_t* index, /* in: index */
|
||||
dtuple_t* entry, /* in: index entry for index */
|
||||
que_thr_t* thr) /* in: query thread */
|
||||
{
|
||||
dict_foreign_t* foreign;
|
||||
ulint err;
|
||||
|
||||
foreign = UT_LIST_GET_FIRST(table->foreign_list);
|
||||
|
||||
while (foreign) {
|
||||
if (foreign->foreign_index == index) {
|
||||
|
||||
if (foreign->referenced_table == NULL) {
|
||||
dict_table_get(foreign->referenced_table_name,
|
||||
thr_get_trx(thr));
|
||||
}
|
||||
|
||||
rw_lock_s_lock(&dict_foreign_key_check_lock);
|
||||
|
||||
err = row_ins_check_foreign_constraint(TRUE, foreign,
|
||||
table, index, entry, thr);
|
||||
|
||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
return(err);
|
||||
}
|
||||
}
|
||||
|
||||
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
|
||||
}
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
Scans a unique non-clustered index at a given index entry to determine
|
||||
whether a uniqueness violation has occurred for the key value of the entry.
|
||||
@@ -365,7 +579,6 @@ row_ins_scan_sec_index_for_duplicate(
|
||||
ulint n_fields_cmp;
|
||||
rec_t* rec;
|
||||
btr_pcur_t pcur;
|
||||
trx_t* trx = thr_get_trx(thr);
|
||||
ulint err = DB_SUCCESS;
|
||||
ibool moved;
|
||||
mtr_t mtr;
|
||||
@@ -414,7 +627,7 @@ row_ins_scan_sec_index_for_duplicate(
|
||||
|
||||
err = DB_DUPLICATE_KEY;
|
||||
|
||||
trx->error_info = index;
|
||||
thr_get_trx(thr)->error_info = index;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -699,7 +912,7 @@ row_ins_index_entry_low(
|
||||
ext_vec, n_ext_vec,
|
||||
thr, &mtr);
|
||||
} else {
|
||||
err = row_ins_sec_index_entry_by_modify(&cursor,
|
||||
err = row_ins_sec_index_entry_by_modify(&cursor, entry,
|
||||
thr, &mtr);
|
||||
}
|
||||
|
||||
@@ -765,6 +978,15 @@ row_ins_index_entry(
|
||||
{
|
||||
ulint err;
|
||||
|
||||
if (UT_LIST_GET_FIRST(index->table->foreign_list)) {
|
||||
err = row_ins_check_foreign_constraints(index->table, index,
|
||||
entry, thr);
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
return(err);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try first optimistic descent to the B-tree */
|
||||
|
||||
err = row_ins_index_entry_low(BTR_MODIFY_LEAF, index, entry,
|
||||
@@ -812,7 +1034,7 @@ row_ins_index_entry_set_vals(
|
||||
|
||||
/***************************************************************
|
||||
Inserts a single index entry to the table. */
|
||||
UNIV_INLINE
|
||||
static
|
||||
ulint
|
||||
row_ins_index_entry_step(
|
||||
/*=====================*/
|
||||
|
@@ -21,6 +21,7 @@ Created 9/17/2000 Heikki Tuuri
|
||||
#include "pars0pars.h"
|
||||
#include "dict0dict.h"
|
||||
#include "dict0crea.h"
|
||||
#include "dict0load.h"
|
||||
#include "trx0roll.h"
|
||||
#include "trx0purge.h"
|
||||
#include "lock0lock.h"
|
||||
@@ -151,7 +152,7 @@ row_mysql_handle_errors(
|
||||
during the function entry */
|
||||
trx_t* trx, /* in: transaction */
|
||||
que_thr_t* thr, /* in: query thread */
|
||||
trx_savept_t* savept) /* in: savepoint */
|
||||
trx_savept_t* savept) /* in: savepoint or NULL */
|
||||
{
|
||||
ibool timeout_expired;
|
||||
ulint err;
|
||||
@@ -172,12 +173,16 @@ handle_new_error:
|
||||
}
|
||||
} else if (err == DB_TOO_BIG_RECORD) {
|
||||
/* MySQL will roll back the latest SQL statement */
|
||||
} else if (err == DB_ROW_IS_REFERENCED
|
||||
|| err == DB_NO_REFERENCED_ROW
|
||||
|| err == DB_CANNOT_ADD_CONSTRAINT) {
|
||||
/* MySQL will roll back the latest SQL statement */
|
||||
} else if (err == DB_LOCK_WAIT) {
|
||||
|
||||
timeout_expired = srv_suspend_mysql_thread(thr);
|
||||
|
||||
if (timeout_expired) {
|
||||
trx->error_state = DB_DEADLOCK;
|
||||
trx->error_state = DB_LOCK_WAIT_TIMEOUT;
|
||||
|
||||
que_thr_stop_for_mysql(thr);
|
||||
|
||||
@@ -188,8 +193,11 @@ handle_new_error:
|
||||
|
||||
return(TRUE);
|
||||
|
||||
} else if (err == DB_DEADLOCK) {
|
||||
/* MySQL will roll back the latest SQL statement */
|
||||
} else if (err == DB_DEADLOCK || err == DB_LOCK_WAIT_TIMEOUT) {
|
||||
/* Roll back the whole transaction; this resolution was added
|
||||
to version 3.23.43 */
|
||||
|
||||
trx_general_rollback_for_mysql(trx, FALSE, NULL);
|
||||
|
||||
} else if (err == DB_OUT_OF_FILE_SPACE) {
|
||||
/* MySQL will roll back the latest SQL statement */
|
||||
@@ -203,6 +211,7 @@ handle_new_error:
|
||||
|
||||
exit(1);
|
||||
} else {
|
||||
fprintf(stderr, "InnoDB: unknown error code %lu\n", err);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
@@ -441,6 +450,93 @@ row_update_statistics_if_needed(
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Unlocks an AUTO_INC type lock possibly reserved by trx. */
|
||||
|
||||
void
|
||||
row_unlock_table_autoinc_for_mysql(
|
||||
/*===============================*/
|
||||
trx_t* trx) /* in: transaction */
|
||||
{
|
||||
if (!trx->auto_inc_lock) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
lock_table_unlock_auto_inc(trx);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Sets an AUTO_INC type lock on the table mentioned in prebuilt. The
|
||||
AUTO_INC lock gives exclusive access to the auto-inc counter of the
|
||||
table. The lock is reserved only for the duration of an SQL statement.
|
||||
It is not compatible with another AUTO_INC or exclusive lock on the
|
||||
table. */
|
||||
|
||||
int
|
||||
row_lock_table_autoinc_for_mysql(
|
||||
/*=============================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
row_prebuilt_t* prebuilt) /* in: prebuilt struct in the MySQL
|
||||
table handle */
|
||||
{
|
||||
trx_t* trx = prebuilt->trx;
|
||||
ins_node_t* node = prebuilt->ins_node;
|
||||
que_thr_t* thr;
|
||||
ulint err;
|
||||
ibool was_lock_wait;
|
||||
|
||||
ut_ad(trx);
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
|
||||
trx->op_info = "setting auto-inc lock";
|
||||
|
||||
if (node == NULL) {
|
||||
row_get_prebuilt_insert_row(prebuilt);
|
||||
node = prebuilt->ins_node;
|
||||
}
|
||||
|
||||
/* We use the insert query graph as the dummy graph needed
|
||||
in the lock module call */
|
||||
|
||||
thr = que_fork_get_first_thr(prebuilt->ins_graph);
|
||||
|
||||
que_thr_move_to_run_state_for_mysql(thr, trx);
|
||||
|
||||
run_again:
|
||||
thr->run_node = node;
|
||||
thr->prev_node = node;
|
||||
|
||||
/* It may be that the current session has not yet started
|
||||
its transaction, or it has been committed: */
|
||||
|
||||
trx_start_if_not_started(trx);
|
||||
|
||||
err = lock_table(0, prebuilt->table, LOCK_AUTO_INC, thr);
|
||||
|
||||
trx->error_state = err;
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
que_thr_stop_for_mysql(thr);
|
||||
|
||||
was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
|
||||
|
||||
if (was_lock_wait) {
|
||||
goto run_again;
|
||||
}
|
||||
|
||||
trx->op_info = "";
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
que_thr_stop_for_mysql_no_error(thr, trx);
|
||||
|
||||
trx->op_info = "";
|
||||
|
||||
return((int) err);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Does an insert for MySQL. */
|
||||
|
||||
@@ -462,6 +558,17 @@ row_insert_for_mysql(
|
||||
ut_ad(trx);
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
|
||||
if (srv_created_new_raw || srv_force_recovery) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: A new raw disk partition was initialized or\n"
|
||||
"InnoDB: innodb_force_recovery is on: we do not allow\n"
|
||||
"InnoDB: database modifications by the user. Shut down\n"
|
||||
"InnoDB: mysqld and edit my.cnf so that newraw is replaced\n"
|
||||
"InnoDB: with raw, and innodb_force_... is removed.\n");
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
trx->op_info = "inserting";
|
||||
|
||||
if (node == NULL) {
|
||||
@@ -634,6 +741,17 @@ row_update_for_mysql(
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
UT_NOT_USED(mysql_rec);
|
||||
|
||||
if (srv_created_new_raw || srv_force_recovery) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: A new raw disk partition was initialized or\n"
|
||||
"InnoDB: innodb_force_recovery is on: we do not allow\n"
|
||||
"InnoDB: database modifications by the user. Shut down\n"
|
||||
"InnoDB: mysqld and edit my.cnf so that newraw is replaced\n"
|
||||
"InnoDB: with raw, and innodb_force_... is removed.\n");
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
trx->op_info = "updating or deleting";
|
||||
|
||||
node = prebuilt->upd_node;
|
||||
@@ -816,8 +934,69 @@ row_create_table_for_mysql(
|
||||
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
|
||||
if (srv_created_new_raw || srv_force_recovery) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: A new raw disk partition was initialized or\n"
|
||||
"InnoDB: innodb_force_recovery is on: we do not allow\n"
|
||||
"InnoDB: database modifications by the user. Shut down\n"
|
||||
"InnoDB: mysqld and edit my.cnf so that newraw is replaced\n"
|
||||
"InnoDB: with raw, and innodb_force_... is removed.\n");
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
trx->op_info = "creating table";
|
||||
|
||||
namelen = ut_strlen(table->name);
|
||||
|
||||
keywordlen = ut_strlen("innodb_monitor");
|
||||
|
||||
if (namelen >= keywordlen
|
||||
&& 0 == ut_memcmp(table->name + namelen - keywordlen,
|
||||
"innodb_monitor", keywordlen)) {
|
||||
|
||||
/* Table name ends to characters innodb_monitor:
|
||||
start monitor prints */
|
||||
|
||||
srv_print_innodb_monitor = TRUE;
|
||||
|
||||
/* The lock timeout monitor thread also takes care
|
||||
of InnoDB monitor prints */
|
||||
|
||||
os_event_set(srv_lock_timeout_thread_event);
|
||||
}
|
||||
|
||||
keywordlen = ut_strlen("innodb_lock_monitor");
|
||||
|
||||
if (namelen >= keywordlen
|
||||
&& 0 == ut_memcmp(table->name + namelen - keywordlen,
|
||||
"innodb_lock_monitor", keywordlen)) {
|
||||
|
||||
srv_print_innodb_monitor = TRUE;
|
||||
srv_print_innodb_lock_monitor = TRUE;
|
||||
os_event_set(srv_lock_timeout_thread_event);
|
||||
}
|
||||
|
||||
keywordlen = ut_strlen("innodb_tablespace_monitor");
|
||||
|
||||
if (namelen >= keywordlen
|
||||
&& 0 == ut_memcmp(table->name + namelen - keywordlen,
|
||||
"innodb_tablespace_monitor", keywordlen)) {
|
||||
|
||||
srv_print_innodb_tablespace_monitor = TRUE;
|
||||
os_event_set(srv_lock_timeout_thread_event);
|
||||
}
|
||||
|
||||
keywordlen = ut_strlen("innodb_table_monitor");
|
||||
|
||||
if (namelen >= keywordlen
|
||||
&& 0 == ut_memcmp(table->name + namelen - keywordlen,
|
||||
"innodb_table_monitor", keywordlen)) {
|
||||
|
||||
srv_print_innodb_table_monitor = TRUE;
|
||||
os_event_set(srv_lock_timeout_thread_event);
|
||||
}
|
||||
|
||||
/* Serialize data dictionary operations with dictionary mutex:
|
||||
no deadlocks can occur then in these operations */
|
||||
|
||||
@@ -845,9 +1024,12 @@ row_create_table_for_mysql(
|
||||
trx_general_rollback_for_mysql(trx, FALSE, NULL);
|
||||
|
||||
if (err == DB_OUT_OF_FILE_SPACE) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Warning: cannot create table %s because tablespace full\n",
|
||||
table->name);
|
||||
row_drop_table_for_mysql(table->name, trx, TRUE);
|
||||
} else {
|
||||
assert(err == DB_DUPLICATE_KEY);
|
||||
ut_a(err == DB_DUPLICATE_KEY);
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: table %s already exists in InnoDB internal\n"
|
||||
"InnoDB: data dictionary. Have you deleted the .frm file\n"
|
||||
@@ -864,39 +1046,6 @@ row_create_table_for_mysql(
|
||||
}
|
||||
|
||||
trx->error_state = DB_SUCCESS;
|
||||
} else {
|
||||
namelen = ut_strlen(table->name);
|
||||
|
||||
keywordlen = ut_strlen("innodb_monitor");
|
||||
|
||||
if (namelen >= keywordlen
|
||||
&& 0 == ut_memcmp(table->name + namelen - keywordlen,
|
||||
"innodb_monitor", keywordlen)) {
|
||||
|
||||
/* Table name ends to characters innodb_monitor:
|
||||
start monitor prints */
|
||||
|
||||
srv_print_innodb_monitor = TRUE;
|
||||
}
|
||||
|
||||
keywordlen = ut_strlen("innodb_lock_monitor");
|
||||
|
||||
if (namelen >= keywordlen
|
||||
&& 0 == ut_memcmp(table->name + namelen - keywordlen,
|
||||
"innodb_lock_monitor", keywordlen)) {
|
||||
|
||||
srv_print_innodb_monitor = TRUE;
|
||||
srv_print_innodb_lock_monitor = TRUE;
|
||||
}
|
||||
|
||||
keywordlen = ut_strlen("innodb_tablespace_monitor");
|
||||
|
||||
if (namelen >= keywordlen
|
||||
&& 0 == ut_memcmp(table->name + namelen - keywordlen,
|
||||
"innodb_tablespace_monitor", keywordlen)) {
|
||||
|
||||
srv_print_innodb_tablespace_monitor = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
@@ -969,6 +1118,65 @@ row_create_index_for_mysql(
|
||||
return((int) err);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Scans a table create SQL string and adds to the data dictionary
|
||||
the foreign key constraints declared in the string. This function
|
||||
should be called after the indexes for a table have been created.
|
||||
Each foreign key constraint must be accompanied with indexes in
|
||||
bot participating tables. The indexes are allowed to contain more
|
||||
fields than mentioned in the constraint. Check also that foreign key
|
||||
constraints which reference this table are ok. */
|
||||
|
||||
int
|
||||
row_table_add_foreign_constraints(
|
||||
/*==============================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
trx_t* trx, /* in: transaction */
|
||||
char* sql_string, /* in: table create statement where
|
||||
foreign keys are declared like:
|
||||
FOREIGN KEY (a, b) REFERENCES table2(c, d),
|
||||
table2 can be written also with the database
|
||||
name before it: test.table2 */
|
||||
char* name) /* in: table full name in the normalized form
|
||||
database_name/table_name */
|
||||
{
|
||||
ulint err;
|
||||
|
||||
ut_a(sql_string);
|
||||
|
||||
trx->op_info = "adding foreign keys";
|
||||
|
||||
/* Serialize data dictionary operations with dictionary mutex:
|
||||
no deadlocks can occur then in these operations */
|
||||
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
trx->dict_operation = TRUE;
|
||||
|
||||
err = dict_create_foreign_constraints(trx, sql_string, name);
|
||||
|
||||
if (err == DB_SUCCESS) {
|
||||
/* Check that also referencing constraints are ok */
|
||||
err = dict_load_foreigns(name);
|
||||
}
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
/* We have special error handling here */
|
||||
|
||||
trx->error_state = DB_SUCCESS;
|
||||
|
||||
trx_general_rollback_for_mysql(trx, FALSE, NULL);
|
||||
|
||||
row_drop_table_for_mysql(name, trx, TRUE);
|
||||
|
||||
trx->error_state = DB_SUCCESS;
|
||||
}
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
|
||||
return((int) err);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Drops a table for MySQL. If the name of the dropped table ends to
|
||||
characters INNODB_MONITOR, then this also stops printing of monitor
|
||||
@@ -997,6 +1205,17 @@ row_drop_table_for_mysql(
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
ut_a(name != NULL);
|
||||
|
||||
if (srv_created_new_raw || srv_force_recovery) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: A new raw disk partition was initialized or\n"
|
||||
"InnoDB: innodb_force_recovery is on: we do not allow\n"
|
||||
"InnoDB: database modifications by the user. Shut down\n"
|
||||
"InnoDB: mysqld and edit my.cnf so that newraw is replaced\n"
|
||||
"InnoDB: with raw, and innodb_force_... is removed.\n");
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
trx->op_info = "dropping table";
|
||||
|
||||
namelen = ut_strlen(name);
|
||||
@@ -1032,6 +1251,15 @@ row_drop_table_for_mysql(
|
||||
srv_print_innodb_tablespace_monitor = FALSE;
|
||||
}
|
||||
|
||||
keywordlen = ut_strlen("innodb_table_monitor");
|
||||
|
||||
if (namelen >= keywordlen
|
||||
&& 0 == ut_memcmp(name + namelen - keywordlen,
|
||||
"innodb_table_monitor", keywordlen)) {
|
||||
|
||||
srv_print_innodb_table_monitor = FALSE;
|
||||
}
|
||||
|
||||
/* We use the private SQL parser of Innobase to generate the
|
||||
query graphs needed in deleting the dictionary data from system
|
||||
tables in Innobase. Deleting a row from SYS_INDEXES table also
|
||||
@@ -1039,21 +1267,49 @@ row_drop_table_for_mysql(
|
||||
|
||||
str1 =
|
||||
"PROCEDURE DROP_TABLE_PROC () IS\n"
|
||||
"table_name CHAR;\n"
|
||||
"sys_foreign_id CHAR;\n"
|
||||
"table_id CHAR;\n"
|
||||
"index_id CHAR;\n"
|
||||
"foreign_id CHAR;\n"
|
||||
"found INT;\n"
|
||||
"BEGIN\n"
|
||||
"SELECT ID INTO table_id\n"
|
||||
"FROM SYS_TABLES\n"
|
||||
"WHERE NAME ='";
|
||||
"table_name := '";
|
||||
|
||||
str2 =
|
||||
"';\n"
|
||||
"SELECT ID INTO table_id\n"
|
||||
"FROM SYS_TABLES\n"
|
||||
"WHERE NAME = table_name;\n"
|
||||
"IF (SQL % NOTFOUND) THEN\n"
|
||||
" COMMIT WORK;\n"
|
||||
" RETURN;\n"
|
||||
"END IF;\n"
|
||||
"found := 1;\n"
|
||||
"SELECT ID INTO sys_foreign_id\n"
|
||||
"FROM SYS_TABLES\n"
|
||||
"WHERE NAME = 'SYS_FOREIGN';\n"
|
||||
"IF (SQL % NOTFOUND) THEN\n"
|
||||
" found := 0;\n"
|
||||
"END IF;\n"
|
||||
"IF (table_name = 'SYS_FOREIGN') THEN\n"
|
||||
" found := 0;\n"
|
||||
"END IF;\n"
|
||||
"IF (table_name = 'SYS_FOREIGN_COLS') THEN\n"
|
||||
" found := 0;\n"
|
||||
"END IF;\n"
|
||||
"WHILE found = 1 LOOP\n"
|
||||
" SELECT ID INTO foreign_id\n"
|
||||
" FROM SYS_FOREIGN\n"
|
||||
" WHERE FOR_NAME = table_name;\n"
|
||||
" IF (SQL % NOTFOUND) THEN\n"
|
||||
" found := 0;\n"
|
||||
" ELSE"
|
||||
" DELETE FROM SYS_FOREIGN_COLS WHERE ID = foreign_id;\n"
|
||||
" DELETE FROM SYS_FOREIGN WHERE ID = foreign_id;\n"
|
||||
" END IF;\n"
|
||||
"END LOOP;\n"
|
||||
"found := 1;\n"
|
||||
"WHILE found = 1 LOOP\n"
|
||||
" SELECT ID INTO index_id\n"
|
||||
" FROM SYS_INDEXES\n"
|
||||
@@ -1095,6 +1351,9 @@ row_drop_table_for_mysql(
|
||||
|
||||
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
||||
|
||||
/* Prevent foreign key checks while we are dropping the table */
|
||||
rw_lock_x_lock(&(dict_foreign_key_check_lock));
|
||||
|
||||
/* Prevent purge from running while we are dropping the table */
|
||||
rw_lock_s_lock(&(purge_sys->purge_is_running));
|
||||
|
||||
@@ -1103,6 +1362,12 @@ row_drop_table_for_mysql(
|
||||
if (!table) {
|
||||
err = DB_TABLE_NOT_FOUND;
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: table %s does not exist in the InnoDB internal\n"
|
||||
"InnoDB: data dictionary though MySQL is trying to drop it.\n"
|
||||
"InnoDB: Have you copied the .frm file of the table to the\n"
|
||||
"InnoDB: MySQL database directory from another database?\n",
|
||||
name);
|
||||
goto funct_exit;
|
||||
}
|
||||
|
||||
@@ -1138,6 +1403,8 @@ row_drop_table_for_mysql(
|
||||
funct_exit:
|
||||
rw_lock_s_unlock(&(purge_sys->purge_is_running));
|
||||
|
||||
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
|
||||
|
||||
if (!has_dict_mutex) {
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
}
|
||||
@@ -1149,6 +1416,49 @@ funct_exit:
|
||||
return((int) err);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Drops a database for MySQL. */
|
||||
|
||||
int
|
||||
row_drop_database_for_mysql(
|
||||
/*========================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
char* name, /* in: database name which ends to '/' */
|
||||
trx_t* trx) /* in: transaction handle */
|
||||
{
|
||||
char* table_name;
|
||||
int err = DB_SUCCESS;
|
||||
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
ut_a(name != NULL);
|
||||
ut_a(name[strlen(name) - 1] == '/');
|
||||
|
||||
trx->op_info = "dropping database";
|
||||
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
while (table_name = dict_get_first_table_name_in_db(name)) {
|
||||
ut_a(memcmp(table_name, name, strlen(name)) == 0);
|
||||
|
||||
err = row_drop_table_for_mysql(table_name, trx, TRUE);
|
||||
|
||||
mem_free(table_name);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: DROP DATABASE %s failed with error %lu for table %s\n",
|
||||
name, (ulint)err, table_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
|
||||
trx->op_info = "";
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Renames a table for MySQL. */
|
||||
|
||||
@@ -1174,18 +1484,37 @@ row_rename_table_for_mysql(
|
||||
ut_a(old_name != NULL);
|
||||
ut_a(new_name != NULL);
|
||||
|
||||
if (srv_created_new_raw || srv_force_recovery) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: A new raw disk partition was initialized or\n"
|
||||
"InnoDB: innodb_force_recovery is on: we do not allow\n"
|
||||
"InnoDB: database modifications by the user. Shut down\n"
|
||||
"InnoDB: mysqld and edit my.cnf so that newraw is replaced\n"
|
||||
"InnoDB: with raw, and innodb_force_... is removed.\n");
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
trx->op_info = "renaming table";
|
||||
|
||||
str1 =
|
||||
"PROCEDURE RENAME_TABLE_PROC () IS\n"
|
||||
"new_table_name CHAR;\n"
|
||||
"old_table_name CHAR;\n"
|
||||
"BEGIN\n"
|
||||
"UPDATE SYS_TABLES SET NAME ='";
|
||||
"new_table_name :='";
|
||||
|
||||
str2 =
|
||||
"' WHERE NAME = '";
|
||||
"';\nold_table_name := '";
|
||||
|
||||
str3 =
|
||||
"';\n"
|
||||
"UPDATE SYS_TABLES SET NAME = new_table_name\n"
|
||||
"WHERE NAME = old_table_name;\n"
|
||||
"UPDATE SYS_FOREIGN SET FOR_NAME = new_table_name\n"
|
||||
"WHERE FOR_NAME = old_table_name;\n"
|
||||
"UPDATE SYS_FOREIGN SET REF_NAME = new_table_name\n"
|
||||
"WHERE REF_NAME = old_table_name;\n"
|
||||
"COMMIT WORK;\n"
|
||||
"END;\n";
|
||||
|
||||
@@ -1356,7 +1685,7 @@ row_check_table_for_mysql(
|
||||
dict_table_t* table = prebuilt->table;
|
||||
dict_index_t* index;
|
||||
ulint n_rows;
|
||||
ulint n_rows_in_table;
|
||||
ulint n_rows_in_table = ULINT_UNDEFINED;
|
||||
ulint ret = DB_SUCCESS;
|
||||
|
||||
prebuilt->trx->op_info = "checking table";
|
||||
|
@@ -220,7 +220,7 @@ row_purge_remove_sec_if_poss_low(
|
||||
if (!found) {
|
||||
/* Not found */
|
||||
|
||||
/* FIXME: printf("PURGE:........sec entry not found\n"); */
|
||||
/* printf("PURGE:........sec entry not found\n"); */
|
||||
/* dtuple_print(entry); */
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
@@ -382,7 +382,7 @@ row_purge_upd_exist_or_extern(
|
||||
while (node->index != NULL) {
|
||||
index = node->index;
|
||||
|
||||
if (row_upd_changes_ord_field(NULL, node->index,
|
||||
if (row_upd_changes_ord_field_binary(NULL, node->index,
|
||||
node->update)) {
|
||||
/* Build the older version of the index entry */
|
||||
entry = row_build_index_entry(node->row, index, heap);
|
||||
|
@@ -50,15 +50,21 @@ to que_run_threads: this is to allow canceling runaway queries */
|
||||
|
||||
/************************************************************************
|
||||
Returns TRUE if the user-defined column values in a secondary index record
|
||||
are the same as the corresponding columns in the clustered index record. */
|
||||
are the same as the corresponding columns in the clustered index record.
|
||||
NOTE: the comparison is NOT done as a binary comparison, but character
|
||||
fields are compared with collation! */
|
||||
static
|
||||
ibool
|
||||
row_sel_sec_rec_is_for_clust_rec(
|
||||
/*=============================*/
|
||||
rec_t* sec_rec,
|
||||
dict_index_t* sec_index,
|
||||
rec_t* clust_rec,
|
||||
dict_index_t* clust_index)
|
||||
/* out: TRUE if the secondary
|
||||
record is equal to the corresponding
|
||||
fields in the clustered record,
|
||||
when compared with collation */
|
||||
rec_t* sec_rec, /* in: secondary index record */
|
||||
dict_index_t* sec_index, /* in: secondary index */
|
||||
rec_t* clust_rec, /* in: clustered index record */
|
||||
dict_index_t* clust_index) /* in: clustered index */
|
||||
{
|
||||
dict_col_t* col;
|
||||
byte* sec_field;
|
||||
@@ -84,9 +90,9 @@ row_sel_sec_rec_is_for_clust_rec(
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if (sec_len != UNIV_SQL_NULL
|
||||
&& ut_memcmp(sec_field, clust_field, sec_len) != 0) {
|
||||
|
||||
if (0 != cmp_data_data(dict_col_get_type(col),
|
||||
clust_field, clust_len,
|
||||
sec_field, sec_len)) {
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
@@ -763,7 +769,7 @@ row_sel_open_pcur(
|
||||
|
||||
/*************************************************************************
|
||||
Restores a stored pcur position to a table index. */
|
||||
UNIV_INLINE
|
||||
static
|
||||
ibool
|
||||
row_sel_restore_pcur_pos(
|
||||
/*=====================*/
|
||||
@@ -813,7 +819,8 @@ row_sel_restore_pcur_pos(
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
ut_ad(relative_position == BTR_PCUR_AFTER);
|
||||
ut_ad(relative_position == BTR_PCUR_AFTER
|
||||
|| relative_position == BTR_PCUR_AFTER_LAST_IN_TREE);
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
@@ -835,7 +842,8 @@ row_sel_restore_pcur_pos(
|
||||
plan->stored_cursor_rec_processed is TRUE, we must move to the previous
|
||||
record, else there is no need to move the cursor. */
|
||||
|
||||
if (relative_position == BTR_PCUR_BEFORE) {
|
||||
if (relative_position == BTR_PCUR_BEFORE
|
||||
|| relative_position == BTR_PCUR_BEFORE_FIRST_IN_TREE) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
@@ -850,7 +858,8 @@ row_sel_restore_pcur_pos(
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
ut_ad(relative_position == BTR_PCUR_AFTER);
|
||||
ut_ad(relative_position == BTR_PCUR_AFTER
|
||||
|| relative_position == BTR_PCUR_AFTER_LAST_IN_TREE);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
@@ -1762,7 +1771,7 @@ fetch_step(
|
||||
|
||||
if (sel_node->state == SEL_NODE_CLOSED) {
|
||||
/* SQL error detected */
|
||||
printf("SQL error %lu\n", DB_ERROR);
|
||||
printf("SQL error %lu\n", (ulint)DB_ERROR);
|
||||
|
||||
que_thr_handle_error(thr, DB_ERROR, NULL, 0);
|
||||
|
||||
@@ -2251,7 +2260,7 @@ row_sel_get_clust_rec_for_mysql(
|
||||
|
||||
/************************************************************************
|
||||
Restores cursor position after it has been stored. We have to take into
|
||||
account that the record cursor was positioned on can have been deleted.
|
||||
account that the record cursor was positioned on may have been deleted.
|
||||
Then we may have to move the cursor one step up or down. */
|
||||
static
|
||||
ibool
|
||||
@@ -2284,14 +2293,14 @@ sel_restore_position_for_mysql(
|
||||
|
||||
if (moves_up) {
|
||||
btr_pcur_move_to_next(pcur, mtr);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
if (relative_position == BTR_PCUR_AFTER) {
|
||||
if (relative_position == BTR_PCUR_AFTER
|
||||
|| relative_position == BTR_PCUR_AFTER_LAST_IN_TREE) {
|
||||
|
||||
if (moves_up) {
|
||||
return(TRUE);
|
||||
}
|
||||
@@ -2303,7 +2312,8 @@ sel_restore_position_for_mysql(
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
ut_ad(relative_position == BTR_PCUR_BEFORE);
|
||||
ut_ad(relative_position == BTR_PCUR_BEFORE
|
||||
|| relative_position == BTR_PCUR_BEFORE_FIRST_IN_TREE);
|
||||
|
||||
if (moves_up && btr_pcur_is_on_user_rec(pcur, mtr)) {
|
||||
btr_pcur_move_to_next(pcur, mtr);
|
||||
@@ -2586,17 +2596,26 @@ row_search_for_mysql(
|
||||
let us try a search shortcut through the hash
|
||||
index */
|
||||
|
||||
if (btr_search_latch.writer != RW_LOCK_NOT_LOCKED) {
|
||||
/* There is an x-latch request: release
|
||||
a possible s-latch to reduce starvation
|
||||
and wait for BTR_SEA_TIMEOUT rounds before
|
||||
trying to keep it again over calls from
|
||||
MySQL */
|
||||
|
||||
if (trx->has_search_latch) {
|
||||
rw_lock_s_unlock(&btr_search_latch);
|
||||
trx->has_search_latch = FALSE;
|
||||
}
|
||||
|
||||
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
|
||||
|
||||
goto no_shortcut;
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -2610,6 +2629,15 @@ row_search_for_mysql(
|
||||
|
||||
srv_n_rows_read++;
|
||||
|
||||
if (trx->search_latch_timeout > 0
|
||||
&& trx->has_search_latch) {
|
||||
|
||||
trx->search_latch_timeout--;
|
||||
|
||||
rw_lock_s_unlock(&btr_search_latch);
|
||||
trx->has_search_latch = FALSE;
|
||||
}
|
||||
|
||||
trx->op_info = "";
|
||||
return(DB_SUCCESS);
|
||||
|
||||
@@ -2619,6 +2647,16 @@ row_search_for_mysql(
|
||||
|
||||
/* printf("%s record not found 2\n",
|
||||
index->name); */
|
||||
|
||||
if (trx->search_latch_timeout > 0
|
||||
&& trx->has_search_latch) {
|
||||
|
||||
trx->search_latch_timeout--;
|
||||
|
||||
rw_lock_s_unlock(&btr_search_latch);
|
||||
trx->has_search_latch = FALSE;
|
||||
}
|
||||
|
||||
trx->op_info = "";
|
||||
return(DB_RECORD_NOT_FOUND);
|
||||
}
|
||||
@@ -2627,7 +2665,7 @@ row_search_for_mysql(
|
||||
mtr_start(&mtr);
|
||||
}
|
||||
}
|
||||
|
||||
no_shortcut:
|
||||
if (trx->has_search_latch) {
|
||||
rw_lock_s_unlock(&btr_search_latch);
|
||||
trx->has_search_latch = FALSE;
|
||||
|
@@ -443,6 +443,8 @@ row_undo_mod_del_unmark_sec(
|
||||
"InnoDB: Make a detailed bug report and send it\n");
|
||||
fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n");
|
||||
|
||||
trx_print(thr_get_trx(thr));
|
||||
|
||||
mem_free(err_buf);
|
||||
} else {
|
||||
btr_cur = btr_pcur_get_btr_cur(&pcur);
|
||||
@@ -552,7 +554,7 @@ row_undo_mod_upd_exist_sec(
|
||||
while (node->index != NULL) {
|
||||
index = node->index;
|
||||
|
||||
if (row_upd_changes_ord_field(node->row, node->index,
|
||||
if (row_upd_changes_ord_field_binary(node->row, node->index,
|
||||
node->update)) {
|
||||
|
||||
/* Build the newest version of the index entry */
|
||||
|
@@ -71,6 +71,134 @@ the x-latch freed? The most efficient way for performing a
|
||||
searched delete is obviously to keep the x-latch for several
|
||||
steps of query graph execution. */
|
||||
|
||||
/*************************************************************************
|
||||
Checks if index currently is mentioned as a referenced index in a foreign
|
||||
key constraint. This function also loads into the dictionary cache the
|
||||
possible referencing table. */
|
||||
static
|
||||
ibool
|
||||
row_upd_index_is_referenced(
|
||||
/*========================*/
|
||||
/* out: TRUE if referenced; NOTE that since
|
||||
we do not hold dict_foreign_key_check_lock
|
||||
when leaving the function, it may be that
|
||||
the referencing table has been dropped when
|
||||
we leave this function: this function is only
|
||||
for heuristic use! */
|
||||
dict_index_t* index) /* in: index */
|
||||
{
|
||||
dict_table_t* table = index->table;
|
||||
dict_foreign_t* foreign;
|
||||
ulint phase = 1;
|
||||
|
||||
try_again:
|
||||
if (!UT_LIST_GET_FIRST(table->referenced_list)) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if (phase == 2) {
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
}
|
||||
|
||||
rw_lock_s_lock(&dict_foreign_key_check_lock);
|
||||
|
||||
foreign = UT_LIST_GET_FIRST(table->referenced_list);
|
||||
|
||||
while (foreign) {
|
||||
if (foreign->referenced_index == index) {
|
||||
if (foreign->foreign_table == NULL) {
|
||||
if (phase == 2) {
|
||||
dict_table_get_low(foreign->
|
||||
foreign_table_name);
|
||||
} else {
|
||||
phase = 2;
|
||||
rw_lock_s_unlock(
|
||||
&dict_foreign_key_check_lock);
|
||||
goto try_again;
|
||||
}
|
||||
}
|
||||
|
||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||
|
||||
if (phase == 2) {
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
|
||||
}
|
||||
|
||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||
|
||||
if (phase == 2) {
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Checks if possible foreign key constraints hold after a delete of the record
|
||||
under pcur. NOTE that this function will temporarily commit mtr and lose
|
||||
pcur position! */
|
||||
static
|
||||
ulint
|
||||
row_upd_check_references_constraints(
|
||||
/*=================================*/
|
||||
/* out: DB_SUCCESS, DB_LOCK_WAIT, or an error
|
||||
code */
|
||||
btr_pcur_t* pcur, /* in: cursor positioned on a record; NOTE: the
|
||||
cursor position is lost in this function! */
|
||||
dict_table_t* table, /* in: table in question */
|
||||
dict_index_t* index, /* in: index of the cursor */
|
||||
que_thr_t* thr, /* in: query thread */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
dict_foreign_t* foreign;
|
||||
mem_heap_t* heap;
|
||||
dtuple_t* entry;
|
||||
rec_t* rec;
|
||||
ulint err;
|
||||
|
||||
rec = btr_pcur_get_rec(pcur);
|
||||
|
||||
heap = mem_heap_create(500);
|
||||
|
||||
entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
|
||||
|
||||
mtr_commit(mtr);
|
||||
|
||||
mtr_start(mtr);
|
||||
|
||||
rw_lock_s_lock(&dict_foreign_key_check_lock);
|
||||
|
||||
foreign = UT_LIST_GET_FIRST(table->referenced_list);
|
||||
|
||||
while (foreign) {
|
||||
if (foreign->referenced_index == index) {
|
||||
|
||||
err = row_ins_check_foreign_constraint(FALSE, foreign,
|
||||
table, index, entry, thr);
|
||||
if (err != DB_SUCCESS) {
|
||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(err);
|
||||
}
|
||||
}
|
||||
|
||||
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
|
||||
}
|
||||
|
||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Creates an update node for a query graph. */
|
||||
|
||||
@@ -484,13 +612,73 @@ upd_ext_vec_contains(
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
Builds an update vector from those fields, excluding the roll ptr and
|
||||
trx id fields, which in an index entry differ from a record that has
|
||||
the equal ordering fields. */
|
||||
Builds an update vector from those fields which in a secondary index entry
|
||||
differ from a record that has the equal ordering fields. NOTE: we compare
|
||||
the fields as binary strings! */
|
||||
|
||||
upd_t*
|
||||
row_upd_build_difference(
|
||||
/*=====================*/
|
||||
row_upd_build_sec_rec_difference_binary(
|
||||
/*====================================*/
|
||||
/* out, own: update vector of differing
|
||||
fields */
|
||||
dict_index_t* index, /* in: index */
|
||||
dtuple_t* entry, /* in: entry to insert */
|
||||
rec_t* rec, /* in: secondary index record */
|
||||
mem_heap_t* heap) /* in: memory heap from which allocated */
|
||||
{
|
||||
upd_field_t* upd_field;
|
||||
dfield_t* dfield;
|
||||
byte* data;
|
||||
ulint len;
|
||||
upd_t* update;
|
||||
ulint n_diff;
|
||||
ulint i;
|
||||
|
||||
/* This function is used only for a secondary index */
|
||||
ut_ad(0 == (index->type & DICT_CLUSTERED));
|
||||
|
||||
update = upd_create(dtuple_get_n_fields(entry), heap);
|
||||
|
||||
n_diff = 0;
|
||||
|
||||
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
|
||||
|
||||
data = rec_get_nth_field(rec, i, &len);
|
||||
|
||||
dfield = dtuple_get_nth_field(entry, i);
|
||||
|
||||
ut_a(len == dfield_get_len(dfield));
|
||||
|
||||
/* NOTE: we compare the fields as binary strings!
|
||||
(No collation) */
|
||||
|
||||
if (!dfield_data_is_binary_equal(dfield, len, data)) {
|
||||
|
||||
upd_field = upd_get_nth_field(update, n_diff);
|
||||
|
||||
dfield_copy(&(upd_field->new_val), dfield);
|
||||
|
||||
upd_field_set_field_no(upd_field, i, index);
|
||||
|
||||
upd_field->extern_storage = FALSE;
|
||||
|
||||
n_diff++;
|
||||
}
|
||||
}
|
||||
|
||||
update->n_fields = n_diff;
|
||||
|
||||
return(update);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
Builds an update vector from those fields, excluding the roll ptr and
|
||||
trx id fields, which in an index entry differ from a record that has
|
||||
the equal ordering fields. NOTE: we compare the fields as binary strings! */
|
||||
|
||||
upd_t*
|
||||
row_upd_build_difference_binary(
|
||||
/*============================*/
|
||||
/* out, own: update vector of differing
|
||||
fields, excluding roll ptr and trx id */
|
||||
dict_index_t* index, /* in: clustered index */
|
||||
@@ -527,10 +715,13 @@ row_upd_build_difference(
|
||||
|
||||
dfield = dtuple_get_nth_field(entry, i);
|
||||
|
||||
/* NOTE: we compare the fields as binary strings!
|
||||
(No collation) */
|
||||
|
||||
if ((rec_get_nth_field_extern_bit(rec, i)
|
||||
!= upd_ext_vec_contains(ext_vec, n_ext_vec, i))
|
||||
|| ((i != trx_id_pos) && (i != roll_ptr_pos)
|
||||
&& !dfield_data_is_equal(dfield, len, data))) {
|
||||
&& !dfield_data_is_binary_equal(dfield, len, data))) {
|
||||
|
||||
upd_field = upd_get_nth_field(update, n_diff);
|
||||
|
||||
@@ -630,13 +821,16 @@ row_upd_clust_index_replace_new_col_vals(
|
||||
/***************************************************************
|
||||
Checks if an update vector changes an ordering field of an index record.
|
||||
This function is fast if the update vector is short or the number of ordering
|
||||
fields in the index is small. Otherwise, this can be quadratic. */
|
||||
fields in the index is small. Otherwise, this can be quadratic.
|
||||
NOTE: we compare the fields as binary strings! */
|
||||
|
||||
ibool
|
||||
row_upd_changes_ord_field(
|
||||
/*======================*/
|
||||
row_upd_changes_ord_field_binary(
|
||||
/*=============================*/
|
||||
/* out: TRUE if update vector changes
|
||||
an ordering field in the index record */
|
||||
an ordering field in the index record;
|
||||
NOTE: the fields are compared as binary
|
||||
strings */
|
||||
dtuple_t* row, /* in: old value of row, or NULL if the
|
||||
row and the data values in update are not
|
||||
known when this function is called, e.g., at
|
||||
@@ -671,7 +865,7 @@ row_upd_changes_ord_field(
|
||||
|
||||
if (col_pos == upd_field->field_no
|
||||
&& (row == NULL
|
||||
|| !dfield_datas_are_equal(
|
||||
|| !dfield_datas_are_binary_equal(
|
||||
dtuple_get_nth_field(row, col_no),
|
||||
&(upd_field->new_val)))) {
|
||||
return(TRUE);
|
||||
@@ -683,11 +877,12 @@ row_upd_changes_ord_field(
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
Checks if an update vector changes an ordering field of an index record. */
|
||||
Checks if an update vector changes an ordering field of an index record.
|
||||
NOTE: we compare the fields as binary strings! */
|
||||
|
||||
ibool
|
||||
row_upd_changes_some_index_ord_field(
|
||||
/*=================================*/
|
||||
row_upd_changes_some_index_ord_field_binary(
|
||||
/*========================================*/
|
||||
/* out: TRUE if update vector may change
|
||||
an ordering field in an index record */
|
||||
dict_table_t* table, /* in: table */
|
||||
@@ -812,6 +1007,7 @@ row_upd_sec_index_entry(
|
||||
upd_node_t* node, /* in: row update node */
|
||||
que_thr_t* thr) /* in: query thread */
|
||||
{
|
||||
ibool check_ref;
|
||||
ibool found;
|
||||
dict_index_t* index;
|
||||
dtuple_t* entry;
|
||||
@@ -825,6 +1021,8 @@ row_upd_sec_index_entry(
|
||||
|
||||
index = node->index;
|
||||
|
||||
check_ref = row_upd_index_is_referenced(index);
|
||||
|
||||
heap = mem_heap_create(1024);
|
||||
|
||||
/* Build old index entry */
|
||||
@@ -855,6 +1053,8 @@ row_upd_sec_index_entry(
|
||||
"InnoDB: Make a detailed bug report and send it\n");
|
||||
fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n");
|
||||
|
||||
trx_print(thr_get_trx(thr));
|
||||
|
||||
mem_free(err_buf);
|
||||
} else {
|
||||
/* Delete mark the old index record; it can already be
|
||||
@@ -864,9 +1064,21 @@ row_upd_sec_index_entry(
|
||||
if (!rec_get_deleted_flag(rec)) {
|
||||
err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE,
|
||||
thr, &mtr);
|
||||
if (err == DB_SUCCESS && check_ref) {
|
||||
/* NOTE that the following call loses
|
||||
the position of pcur ! */
|
||||
err = row_upd_check_references_constraints(
|
||||
&pcur, index->table,
|
||||
index, thr, &mtr);
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
goto close_cur;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
close_cur:
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
|
||||
@@ -907,7 +1119,7 @@ row_upd_sec_step(
|
||||
ut_ad(!(node->index->type & DICT_CLUSTERED));
|
||||
|
||||
if (node->state == UPD_NODE_UPDATE_ALL_SEC
|
||||
|| row_upd_changes_ord_field(node->row, node->index,
|
||||
|| row_upd_changes_ord_field_binary(node->row, node->index,
|
||||
node->update)) {
|
||||
err = row_upd_sec_index_entry(node, thr);
|
||||
|
||||
@@ -931,6 +1143,8 @@ row_upd_clust_rec_by_insert(
|
||||
upd_node_t* node, /* in: row update node */
|
||||
dict_index_t* index, /* in: clustered index of the record */
|
||||
que_thr_t* thr, /* in: query thread */
|
||||
ibool check_ref,/* in: TRUE if index may be referenced in
|
||||
a foreign key constraint */
|
||||
mtr_t* mtr) /* in: mtr; gets committed here */
|
||||
{
|
||||
mem_heap_t* heap;
|
||||
@@ -958,6 +1172,7 @@ row_upd_clust_rec_by_insert(
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
/* Mark as not-owned the externally stored fields which the new
|
||||
row inherits from the delete marked record: purge should not
|
||||
free those externally stored fields even if the delete marked
|
||||
@@ -965,6 +1180,19 @@ row_upd_clust_rec_by_insert(
|
||||
|
||||
btr_cur_mark_extern_inherited_fields(btr_cur_get_rec(btr_cur),
|
||||
node->update, mtr);
|
||||
if (check_ref) {
|
||||
/* NOTE that the following call loses
|
||||
the position of pcur ! */
|
||||
err = row_upd_check_references_constraints(
|
||||
pcur, table,
|
||||
index, thr, mtr);
|
||||
if (err != DB_SUCCESS) {
|
||||
mtr_commit(mtr);
|
||||
|
||||
return(err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mtr_commit(mtr);
|
||||
@@ -1095,6 +1323,8 @@ row_upd_del_mark_clust_rec(
|
||||
upd_node_t* node, /* in: row update node */
|
||||
dict_index_t* index, /* in: clustered index */
|
||||
que_thr_t* thr, /* in: query thread */
|
||||
ibool check_ref,/* in: TRUE if index may be referenced in
|
||||
a foreign key constraint */
|
||||
mtr_t* mtr) /* in: mtr; gets committed here */
|
||||
{
|
||||
btr_pcur_t* pcur;
|
||||
@@ -1120,6 +1350,18 @@ row_upd_del_mark_clust_rec(
|
||||
|
||||
err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG, btr_cur,
|
||||
TRUE, thr, mtr);
|
||||
if (err == DB_SUCCESS && check_ref) {
|
||||
/* NOTE that the following call loses
|
||||
the position of pcur ! */
|
||||
err = row_upd_check_references_constraints(pcur, index->table,
|
||||
index, thr, mtr);
|
||||
if (err != DB_SUCCESS) {
|
||||
mtr_commit(mtr);
|
||||
|
||||
return(err);
|
||||
}
|
||||
}
|
||||
|
||||
mtr_commit(mtr);
|
||||
|
||||
return(err);
|
||||
@@ -1140,12 +1382,15 @@ row_upd_clust_step(
|
||||
dict_index_t* index;
|
||||
btr_pcur_t* pcur;
|
||||
ibool success;
|
||||
ibool check_ref;
|
||||
ulint err;
|
||||
mtr_t mtr_buf;
|
||||
mtr_t* mtr;
|
||||
mtr_t mtr_buf;
|
||||
|
||||
index = dict_table_get_first_index(node->table);
|
||||
|
||||
check_ref = row_upd_index_is_referenced(index);
|
||||
|
||||
pcur = node->pcur;
|
||||
|
||||
/* We have to restore the cursor to its position */
|
||||
@@ -1210,8 +1455,8 @@ row_upd_clust_step(
|
||||
/* NOTE: the following function calls will also commit mtr */
|
||||
|
||||
if (node->is_delete) {
|
||||
err = row_upd_del_mark_clust_rec(node, index, thr, mtr);
|
||||
|
||||
err = row_upd_del_mark_clust_rec(node, index, thr, check_ref,
|
||||
mtr);
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
return(err);
|
||||
@@ -1244,7 +1489,7 @@ row_upd_clust_step(
|
||||
|
||||
row_upd_store_row(node);
|
||||
|
||||
if (row_upd_changes_ord_field(node->row, index, node->update)) {
|
||||
if (row_upd_changes_ord_field_binary(node->row, index, node->update)) {
|
||||
|
||||
/* Update causes an ordering field (ordering fields within
|
||||
the B-tree) of the clustered index record to change: perform
|
||||
@@ -1257,8 +1502,8 @@ row_upd_clust_step(
|
||||
choosing records to update. MySQL solves now the problem
|
||||
externally! */
|
||||
|
||||
err = row_upd_clust_rec_by_insert(node, index, thr, mtr);
|
||||
|
||||
err = row_upd_clust_rec_by_insert(node, index, thr, check_ref,
|
||||
mtr);
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
return(err);
|
||||
@@ -1304,8 +1549,8 @@ row_upd(
|
||||
interpreter: we must calculate it on the fly: */
|
||||
|
||||
if (node->is_delete ||
|
||||
row_upd_changes_some_index_ord_field(node->table,
|
||||
node->update)) {
|
||||
row_upd_changes_some_index_ord_field_binary(
|
||||
node->table, node->update)) {
|
||||
node->cmpl_info = 0;
|
||||
} else {
|
||||
node->cmpl_info = UPD_NODE_NO_ORD_CHANGE;
|
||||
|
@@ -269,7 +269,13 @@ row_vers_old_has_index_entry(
|
||||
row = row_build(ROW_COPY_POINTERS, clust_index, rec, heap);
|
||||
entry = row_build_index_entry(row, index, heap);
|
||||
|
||||
if (dtuple_datas_are_equal(ientry, entry)) {
|
||||
/* NOTE that we cannot do the comparison as binary
|
||||
fields because the row is maybe being modified so that
|
||||
the clustered index record has already been updated
|
||||
to a different binary value in a char field, but the
|
||||
collation identifies the old and new value anyway! */
|
||||
|
||||
if (dtuple_datas_are_ordering_equal(ientry, entry)) {
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
||||
@@ -307,7 +313,13 @@ row_vers_old_has_index_entry(
|
||||
prev_version, heap);
|
||||
entry = row_build_index_entry(row, index, heap);
|
||||
|
||||
if (dtuple_datas_are_equal(ientry, entry)) {
|
||||
/* NOTE that we cannot do the comparison as binary
|
||||
fields because maybe the secondary index record has
|
||||
already been updated to a different binary value in
|
||||
a char field, but the collation identifies the old
|
||||
and new value anyway! */
|
||||
|
||||
if (dtuple_datas_are_ordering_equal(ientry, entry)) {
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
||||
|
@@ -30,6 +30,7 @@ Created 10/8/1995 Heikki Tuuri
|
||||
#include "ut0mem.h"
|
||||
#include "os0proc.h"
|
||||
#include "mem0mem.h"
|
||||
#include "mem0pool.h"
|
||||
#include "sync0sync.h"
|
||||
#include "sync0ipm.h"
|
||||
#include "thr0loc.h"
|
||||
@@ -46,11 +47,14 @@ Created 10/8/1995 Heikki Tuuri
|
||||
#include "ibuf0ibuf.h"
|
||||
#include "buf0flu.h"
|
||||
#include "btr0sea.h"
|
||||
#include "dict0load.h"
|
||||
|
||||
/* The following counter is incremented whenever there is some user activity
|
||||
in the server */
|
||||
ulint srv_activity_count = 0;
|
||||
|
||||
char* srv_main_thread_op_info = "";
|
||||
|
||||
/* Server parameters which are read from the initfile */
|
||||
|
||||
/* The following three are dir paths which are catenated before file
|
||||
@@ -66,6 +70,11 @@ ulint* srv_data_file_sizes = NULL; /* size in database pages */
|
||||
|
||||
ulint* srv_data_file_is_raw_partition = NULL;
|
||||
|
||||
/* If the following is TRUE we do not allow inserts etc. This protects
|
||||
the user from forgetting the 'newraw' keyword to my.cnf */
|
||||
|
||||
ibool srv_created_new_raw = FALSE;
|
||||
|
||||
char** srv_log_group_home_dirs = NULL;
|
||||
|
||||
ulint srv_n_log_groups = ULINT_MAX;
|
||||
@@ -75,6 +84,9 @@ ibool srv_log_archive_on = TRUE;
|
||||
ulint srv_log_buffer_size = ULINT_MAX; /* size in database pages */
|
||||
ibool srv_flush_log_at_trx_commit = TRUE;
|
||||
|
||||
byte srv_latin1_ordering[256]; /* The sort order table of the latin1
|
||||
character set */
|
||||
|
||||
ibool srv_use_native_aio = FALSE;
|
||||
|
||||
ulint srv_pool_size = ULINT_MAX; /* size in database pages;
|
||||
@@ -93,6 +105,11 @@ ulint srv_lock_wait_timeout = 1024 * 1024 * 1024;
|
||||
char* srv_unix_file_flush_method_str = NULL;
|
||||
ulint srv_unix_file_flush_method = 0;
|
||||
|
||||
/* If the following is != 0 we do not allow inserts etc. This protects
|
||||
the user from forgetting innodb_force_recovery keyword to my.cnf */
|
||||
|
||||
ulint srv_force_recovery = 0;
|
||||
|
||||
ibool srv_use_doublewrite_buf = TRUE;
|
||||
|
||||
ibool srv_set_thread_priorities = TRUE;
|
||||
@@ -115,10 +132,15 @@ ulint srv_n_rows_inserted = 0;
|
||||
ulint srv_n_rows_updated = 0;
|
||||
ulint srv_n_rows_deleted = 0;
|
||||
ulint srv_n_rows_read = 0;
|
||||
ulint srv_n_rows_inserted_old = 0;
|
||||
ulint srv_n_rows_updated_old = 0;
|
||||
ulint srv_n_rows_deleted_old = 0;
|
||||
ulint srv_n_rows_read_old = 0;
|
||||
|
||||
ibool srv_print_innodb_monitor = FALSE;
|
||||
ibool srv_print_innodb_lock_monitor = FALSE;
|
||||
ibool srv_print_innodb_tablespace_monitor = FALSE;
|
||||
ibool srv_print_innodb_table_monitor = FALSE;
|
||||
|
||||
/* The parameters below are obsolete: */
|
||||
|
||||
@@ -1739,31 +1761,153 @@ srv_release_mysql_thread_if_suspended(
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
A thread which wakes up threads whose lock wait may have lasted too long. */
|
||||
A thread which wakes up threads whose lock wait may have lasted too long.
|
||||
This also prints the info output by various InnoDB monitors. */
|
||||
|
||||
#ifndef __WIN__
|
||||
void*
|
||||
#else
|
||||
ulint
|
||||
#endif
|
||||
srv_lock_timeout_monitor_thread(
|
||||
/*============================*/
|
||||
srv_lock_timeout_and_monitor_thread(
|
||||
/*================================*/
|
||||
/* out: a dummy parameter */
|
||||
void* arg) /* in: a dummy parameter required by
|
||||
os_thread_create */
|
||||
{
|
||||
double time_elapsed;
|
||||
time_t current_time;
|
||||
time_t last_monitor_time;
|
||||
ibool some_waits;
|
||||
srv_slot_t* slot;
|
||||
double wait_time;
|
||||
ulint i;
|
||||
|
||||
UT_NOT_USED(arg);
|
||||
last_monitor_time = time(NULL);
|
||||
loop:
|
||||
/* When someone is waiting for a lock, we wake up every second
|
||||
and check if a timeout has passed for a lock wait */
|
||||
|
||||
os_thread_sleep(1000000);
|
||||
|
||||
/* In case mutex_exit is not a memory barrier, it is
|
||||
theoretically possible some threads are left waiting though
|
||||
the semaphore is already released. Wake up those threads: */
|
||||
|
||||
sync_arr_wake_threads_if_sema_free();
|
||||
|
||||
current_time = time(NULL);
|
||||
|
||||
time_elapsed = difftime(current_time, last_monitor_time);
|
||||
|
||||
if (time_elapsed > 15) {
|
||||
|
||||
last_monitor_time = time(NULL);
|
||||
|
||||
if (srv_print_innodb_monitor) {
|
||||
|
||||
printf("=====================================\n");
|
||||
ut_print_timestamp(stdout);
|
||||
|
||||
printf(" INNODB MONITOR OUTPUT\n"
|
||||
"=====================================\n");
|
||||
printf("----------\n"
|
||||
"SEMAPHORES\n"
|
||||
"----------\n");
|
||||
sync_print();
|
||||
printf("------------\n"
|
||||
"TRANSACTIONS\n"
|
||||
"------------\n");
|
||||
lock_print_info();
|
||||
printf("--------\n"
|
||||
"FILE I/O\n"
|
||||
"--------\n");
|
||||
os_aio_print();
|
||||
printf("-------------\n"
|
||||
"INSERT BUFFER\n"
|
||||
"-------------\n");
|
||||
ibuf_print();
|
||||
printf("---\n"
|
||||
"LOG\n"
|
||||
"---\n");
|
||||
log_print();
|
||||
printf("----------------------\n"
|
||||
"BUFFER POOL AND MEMORY\n"
|
||||
"----------------------\n");
|
||||
printf(
|
||||
"Total memory allocated %lu; in additional pool allocated %lu\n",
|
||||
ut_total_allocated_memory,
|
||||
mem_pool_get_reserved(mem_comm_pool));
|
||||
buf_print_io();
|
||||
printf("--------------\n"
|
||||
"ROW OPERATIONS\n"
|
||||
"--------------\n");
|
||||
printf("InnoDB main thread state: %s\n",
|
||||
srv_main_thread_op_info);
|
||||
printf(
|
||||
"Number of rows inserted %lu, updated %lu, deleted %lu, read %lu\n",
|
||||
srv_n_rows_inserted,
|
||||
srv_n_rows_updated,
|
||||
srv_n_rows_deleted,
|
||||
srv_n_rows_read);
|
||||
printf(
|
||||
"%.2f inserts/s, %.2f updates/s, %.2f deletes/s, %.2f reads/s\n",
|
||||
(srv_n_rows_inserted - srv_n_rows_inserted_old)
|
||||
/ time_elapsed,
|
||||
(srv_n_rows_updated - srv_n_rows_updated_old)
|
||||
/ time_elapsed,
|
||||
(srv_n_rows_deleted - srv_n_rows_deleted_old)
|
||||
/ time_elapsed,
|
||||
(srv_n_rows_read - srv_n_rows_read_old)
|
||||
/ time_elapsed);
|
||||
|
||||
srv_n_rows_inserted_old = srv_n_rows_inserted;
|
||||
srv_n_rows_updated_old = srv_n_rows_updated;
|
||||
srv_n_rows_deleted_old = srv_n_rows_deleted;
|
||||
srv_n_rows_read_old = srv_n_rows_read;
|
||||
|
||||
printf("----------------------------\n"
|
||||
"END OF INNODB MONITOR OUTPUT\n"
|
||||
"============================\n");
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (srv_print_innodb_tablespace_monitor) {
|
||||
|
||||
printf("================================================\n");
|
||||
|
||||
ut_print_timestamp(stdout);
|
||||
|
||||
printf(" INNODB TABLESPACE MONITOR OUTPUT\n"
|
||||
"================================================\n");
|
||||
|
||||
fsp_print(0);
|
||||
fprintf(stderr, "Validating tablespace\n");
|
||||
fsp_validate(0);
|
||||
fprintf(stderr, "Validation ok\n");
|
||||
printf("---------------------------------------\n"
|
||||
"END OF INNODB TABLESPACE MONITOR OUTPUT\n"
|
||||
"=======================================\n");
|
||||
}
|
||||
|
||||
if (srv_print_innodb_table_monitor) {
|
||||
|
||||
printf("===========================================\n");
|
||||
|
||||
ut_print_timestamp(stdout);
|
||||
|
||||
printf(" INNODB TABLE MONITOR OUTPUT\n"
|
||||
"===========================================\n");
|
||||
dict_print();
|
||||
|
||||
printf("-----------------------------------\n"
|
||||
"END OF INNODB TABLE MONITOR OUTPUT\n"
|
||||
"==================================\n");
|
||||
}
|
||||
}
|
||||
|
||||
mutex_enter(&kernel_mutex);
|
||||
|
||||
some_waits = FALSE;
|
||||
@@ -1786,11 +1930,10 @@ loop:
|
||||
|
||||
/* Timeout exceeded or a wrap over in system
|
||||
time counter: cancel the lock request queued
|
||||
by the transaction; NOTE that currently only
|
||||
a record lock request can be waiting in
|
||||
MySQL! */
|
||||
by the transaction and release possible
|
||||
other transactions waiting behind */
|
||||
|
||||
lock_rec_cancel(
|
||||
lock_cancel_waiting_and_release(
|
||||
thr_get_trx(slot->thr)->wait_lock);
|
||||
}
|
||||
}
|
||||
@@ -1800,11 +1943,15 @@ loop:
|
||||
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
if (some_waits) {
|
||||
if (some_waits || srv_print_innodb_monitor
|
||||
|| srv_print_innodb_lock_monitor
|
||||
|| srv_print_innodb_tablespace_monitor
|
||||
|| srv_print_innodb_table_monitor) {
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/* No one was waiting for a lock: suspend this thread */
|
||||
/* No one was waiting for a lock and no monitor was active:
|
||||
suspend this thread */
|
||||
|
||||
os_event_wait(srv_lock_timeout_thread_event);
|
||||
|
||||
@@ -1817,6 +1964,36 @@ loop:
|
||||
#endif
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
A thread which prints warnings about semaphore waits which have lasted
|
||||
too long. These can be used to track bugs which cause hangs. */
|
||||
|
||||
#ifndef __WIN__
|
||||
void*
|
||||
#else
|
||||
ulint
|
||||
#endif
|
||||
srv_error_monitor_thread(
|
||||
/*=====================*/
|
||||
/* out: a dummy parameter */
|
||||
void* arg) /* in: a dummy parameter required by
|
||||
os_thread_create */
|
||||
{
|
||||
UT_NOT_USED(arg);
|
||||
loop:
|
||||
os_thread_sleep(10000000);
|
||||
|
||||
sync_array_print_long_waits();
|
||||
|
||||
goto loop;
|
||||
|
||||
#ifndef __WIN__
|
||||
return(NULL);
|
||||
#else
|
||||
return(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
Tells the InnoDB server that there has been activity in the database
|
||||
and wakes up the master thread if it is suspended (not sleeping). Used
|
||||
@@ -1855,15 +2032,18 @@ srv_master_thread(
|
||||
os_thread_create */
|
||||
{
|
||||
os_event_t event;
|
||||
time_t last_flush_time;
|
||||
time_t current_time;
|
||||
ulint old_activity_count;
|
||||
ulint n_pages_purged;
|
||||
ulint n_bytes_merged;
|
||||
ulint n_pages_flushed;
|
||||
ulint n_bytes_archived;
|
||||
ulint n_ios;
|
||||
ulint n_ios_old;
|
||||
ulint n_ios_very_old;
|
||||
ulint n_pend_ios;
|
||||
ulint i;
|
||||
time_t last_flush_time;
|
||||
time_t current_time;
|
||||
time_t last_monitor_time;
|
||||
|
||||
UT_NOT_USED(arg);
|
||||
|
||||
@@ -1876,26 +2056,56 @@ srv_master_thread(
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
os_event_set(srv_sys->operational);
|
||||
|
||||
last_monitor_time = time(NULL);
|
||||
loop:
|
||||
srv_main_thread_op_info = "reserving kernel mutex";
|
||||
|
||||
n_ios_very_old = log_sys->n_log_ios + buf_pool->n_pages_read
|
||||
+ buf_pool->n_pages_written;
|
||||
mutex_enter(&kernel_mutex);
|
||||
|
||||
old_activity_count = srv_activity_count;
|
||||
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
/* We run purge every 10 seconds, even if the server were active: */
|
||||
/* We run purge and a batch of ibuf_contract every 10 seconds, even
|
||||
if the server were active: */
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
n_ios_old = log_sys->n_log_ios + buf_pool->n_pages_read
|
||||
+ buf_pool->n_pages_written;
|
||||
|
||||
srv_main_thread_op_info = "sleeping";
|
||||
os_thread_sleep(1000000);
|
||||
|
||||
if (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND) {
|
||||
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/* We flush the log once in a second even if no commit
|
||||
is issued or the we have specified in my.cnf no flush
|
||||
at transaction commit */
|
||||
|
||||
srv_main_thread_op_info = "flushing log";
|
||||
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
|
||||
|
||||
/* If there were less than 10 i/os during the
|
||||
one second sleep, we assume that there is free
|
||||
disk i/o capacity available, and it makes sense to
|
||||
do an insert buffer merge. */
|
||||
|
||||
n_pend_ios = buf_get_n_pending_ios()
|
||||
+ log_sys->n_pending_writes;
|
||||
n_ios = log_sys->n_log_ios + buf_pool->n_pages_read
|
||||
+ buf_pool->n_pages_written;
|
||||
if (n_pend_ios < 3 && (n_ios - n_ios_old < 10)) {
|
||||
srv_main_thread_op_info = "doing insert buffer merge";
|
||||
ibuf_contract_for_n_pages(TRUE, 5);
|
||||
|
||||
srv_main_thread_op_info = "flushing log";
|
||||
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
|
||||
}
|
||||
|
||||
if (srv_activity_count == old_activity_count) {
|
||||
|
||||
if (srv_print_thread_releases) {
|
||||
@@ -1910,28 +2120,48 @@ loop:
|
||||
printf("Master thread wakes up!\n");
|
||||
}
|
||||
|
||||
/* If there were less than 200 i/os during the 10 second period,
|
||||
we assume that there is free disk i/o capacity available, and it
|
||||
makes sense to do a buffer pool flush. */
|
||||
|
||||
n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes;
|
||||
n_ios = log_sys->n_log_ios + buf_pool->n_pages_read
|
||||
+ buf_pool->n_pages_written;
|
||||
if (n_pend_ios < 3 && (n_ios - n_ios_very_old < 200)) {
|
||||
|
||||
srv_main_thread_op_info = "flushing buffer pool pages";
|
||||
buf_flush_batch(BUF_FLUSH_LIST, 50, ut_dulint_max);
|
||||
|
||||
srv_main_thread_op_info = "flushing log";
|
||||
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
|
||||
}
|
||||
|
||||
/* We run a batch of insert buffer merge every 10 seconds,
|
||||
even if the server were active */
|
||||
|
||||
srv_main_thread_op_info = "doing insert buffer merge";
|
||||
ibuf_contract_for_n_pages(TRUE, 5);
|
||||
|
||||
srv_main_thread_op_info = "flushing log";
|
||||
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
|
||||
|
||||
/* We run a full purge every 10 seconds, even if the server
|
||||
were active */
|
||||
|
||||
n_pages_purged = 1;
|
||||
|
||||
last_flush_time = time(NULL);
|
||||
|
||||
while (n_pages_purged) {
|
||||
/* TODO: replace this by a check if we are running
|
||||
out of file space! */
|
||||
if (srv_print_innodb_monitor) {
|
||||
ut_print_timestamp(stdout);
|
||||
printf(" InnoDB starts purge\n");
|
||||
}
|
||||
|
||||
srv_main_thread_op_info = "purging";
|
||||
n_pages_purged = trx_purge();
|
||||
|
||||
if (srv_print_innodb_monitor) {
|
||||
ut_print_timestamp(stdout);
|
||||
printf(" InnoDB purged %lu pages\n", n_pages_purged);
|
||||
}
|
||||
|
||||
current_time = time(NULL);
|
||||
|
||||
if (difftime(current_time, last_flush_time) > 1) {
|
||||
srv_main_thread_op_info = "flushing log";
|
||||
|
||||
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
|
||||
last_flush_time = current_time;
|
||||
}
|
||||
@@ -1941,67 +2171,7 @@ background_loop:
|
||||
/* In this loop we run background operations when the server
|
||||
is quiet */
|
||||
|
||||
current_time = time(NULL);
|
||||
|
||||
if (difftime(current_time, last_monitor_time) > 15) {
|
||||
|
||||
last_monitor_time = time(NULL);
|
||||
|
||||
if (srv_print_innodb_monitor) {
|
||||
|
||||
printf("=====================================\n");
|
||||
ut_print_timestamp(stdout);
|
||||
|
||||
printf(" INNODB MONITOR OUTPUT\n"
|
||||
"=====================================\n");
|
||||
printf("------------\n"
|
||||
"TRANSACTIONS\n"
|
||||
"------------\n");
|
||||
lock_print_info();
|
||||
printf("-----------------------------------------------\n"
|
||||
"CURRENT SEMAPHORES RESERVED AND SEMAPHORE WAITS\n"
|
||||
"-----------------------------------------------\n");
|
||||
sync_print();
|
||||
printf("CURRENT PENDING FILE I/O'S\n"
|
||||
"--------------------------\n");
|
||||
os_aio_print();
|
||||
printf("-----------\n"
|
||||
"BUFFER POOL\n"
|
||||
"-----------\n");
|
||||
buf_print_io();
|
||||
printf("--------------\n"
|
||||
"ROW OPERATIONS\n"
|
||||
"--------------\n");
|
||||
printf(
|
||||
"Number of rows inserted %lu, updated %lu, deleted %lu, read %lu\n",
|
||||
srv_n_rows_inserted,
|
||||
srv_n_rows_updated,
|
||||
srv_n_rows_deleted,
|
||||
srv_n_rows_read);
|
||||
printf("Server activity counter %lu\n", srv_activity_count);
|
||||
printf("----------------------------\n"
|
||||
"END OF INNODB MONITOR OUTPUT\n"
|
||||
"============================\n");
|
||||
}
|
||||
|
||||
if (srv_print_innodb_tablespace_monitor) {
|
||||
|
||||
printf("================================================\n");
|
||||
|
||||
ut_print_timestamp(stdout);
|
||||
|
||||
printf(" INNODB TABLESPACE MONITOR OUTPUT\n"
|
||||
"================================================\n");
|
||||
|
||||
fsp_print(0);
|
||||
fprintf(stderr, "Validating tablespace\n");
|
||||
fsp_validate(0);
|
||||
fprintf(stderr, "Validation ok\n");
|
||||
printf("---------------------------------------\n"
|
||||
"END OF INNODB TABLESPACE MONITOR OUTPUT\n"
|
||||
"=======================================\n");
|
||||
}
|
||||
}
|
||||
srv_main_thread_op_info = "reserving kernel mutex";
|
||||
|
||||
mutex_enter(&kernel_mutex);
|
||||
if (srv_activity_count != old_activity_count) {
|
||||
@@ -2014,17 +2184,11 @@ background_loop:
|
||||
/* The server has been quiet for a while: start running background
|
||||
operations */
|
||||
|
||||
if (srv_print_innodb_monitor) {
|
||||
ut_print_timestamp(stdout);
|
||||
printf(" InnoDB starts purge\n");
|
||||
}
|
||||
srv_main_thread_op_info = "purging";
|
||||
|
||||
n_pages_purged = trx_purge();
|
||||
|
||||
if (srv_print_innodb_monitor) {
|
||||
ut_print_timestamp(stdout);
|
||||
printf(" InnoDB purged %lu pages\n", n_pages_purged);
|
||||
}
|
||||
srv_main_thread_op_info = "reserving kernel mutex";
|
||||
|
||||
mutex_enter(&kernel_mutex);
|
||||
if (srv_activity_count != old_activity_count) {
|
||||
@@ -2033,17 +2197,10 @@ background_loop:
|
||||
}
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
if (srv_print_innodb_monitor) {
|
||||
ut_print_timestamp(stdout);
|
||||
printf(" InnoDB starts insert buffer merge\n");
|
||||
}
|
||||
srv_main_thread_op_info = "doing insert buffer merge";
|
||||
n_bytes_merged = ibuf_contract_for_n_pages(TRUE, 20);
|
||||
|
||||
n_bytes_merged = ibuf_contract(TRUE);
|
||||
|
||||
if (srv_print_innodb_monitor) {
|
||||
ut_print_timestamp(stdout);
|
||||
printf(" InnoDB merged %lu bytes\n", n_bytes_merged);
|
||||
}
|
||||
srv_main_thread_op_info = "reserving kernel mutex";
|
||||
|
||||
mutex_enter(&kernel_mutex);
|
||||
if (srv_activity_count != old_activity_count) {
|
||||
@@ -2052,17 +2209,10 @@ background_loop:
|
||||
}
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
if (srv_print_innodb_monitor) {
|
||||
ut_print_timestamp(stdout);
|
||||
printf(" InnoDB (main thread) starts buffer pool flush\n");
|
||||
}
|
||||
|
||||
srv_main_thread_op_info = "flushing buffer pool pages";
|
||||
n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max);
|
||||
|
||||
if (srv_print_innodb_monitor) {
|
||||
ut_print_timestamp(stdout);
|
||||
printf(" InnoDB flushed %lu pages\n", n_pages_flushed);
|
||||
}
|
||||
srv_main_thread_op_info = "reserving kernel mutex";
|
||||
|
||||
mutex_enter(&kernel_mutex);
|
||||
if (srv_activity_count != old_activity_count) {
|
||||
@@ -2071,10 +2221,15 @@ background_loop:
|
||||
}
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
srv_main_thread_op_info = "waiting for buffer pool flush to end";
|
||||
buf_flush_wait_batch_end(BUF_FLUSH_LIST);
|
||||
|
||||
srv_main_thread_op_info = "making checkpoint";
|
||||
|
||||
log_checkpoint(TRUE, FALSE);
|
||||
|
||||
srv_main_thread_op_info = "reserving kernel mutex";
|
||||
|
||||
mutex_enter(&kernel_mutex);
|
||||
if (srv_activity_count != old_activity_count) {
|
||||
mutex_exit(&kernel_mutex);
|
||||
@@ -2082,6 +2237,8 @@ background_loop:
|
||||
}
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
srv_main_thread_op_info = "archiving log (if log archive is on)";
|
||||
|
||||
log_archive_do(FALSE, &n_bytes_archived);
|
||||
|
||||
if (n_pages_purged + n_bytes_merged + n_pages_flushed
|
||||
@@ -2098,12 +2255,16 @@ background_loop:
|
||||
/* There is no work for background operations either: suspend
|
||||
master thread to wait for more server activity */
|
||||
|
||||
srv_main_thread_op_info = "suspending";
|
||||
|
||||
mutex_enter(&kernel_mutex);
|
||||
|
||||
event = srv_suspend_thread();
|
||||
|
||||
mutex_exit(&kernel_mutex);
|
||||
|
||||
srv_main_thread_op_info = "waiting for server activity";
|
||||
|
||||
os_event_wait(event);
|
||||
|
||||
goto loop;
|
||||
|
@@ -73,7 +73,10 @@ os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 5];
|
||||
#define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD
|
||||
#define SRV_MAX_N_PENDING_SYNC_IOS 100
|
||||
|
||||
#define SRV_MAX_N_OPEN_FILES 25
|
||||
/* The following limit may be too big in some old operating systems:
|
||||
we may get an assertion failure in os0file.c */
|
||||
|
||||
#define SRV_MAX_N_OPEN_FILES 500
|
||||
|
||||
#define SRV_LOG_SPACE_FIRST_ID 1000000000
|
||||
|
||||
@@ -315,7 +318,12 @@ open_or_create_data_files(
|
||||
ulint size_high;
|
||||
char name[10000];
|
||||
|
||||
ut_a(srv_n_data_files < 1000);
|
||||
if (srv_n_data_files >= 1000) {
|
||||
fprintf(stderr, "InnoDB: can only have < 1000 data files\n"
|
||||
"InnoDB: you have defined %lu\n",
|
||||
srv_n_data_files);
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
*sum_of_new_sizes = 0;
|
||||
|
||||
@@ -336,6 +344,8 @@ open_or_create_data_files(
|
||||
/* The partition is opened, not created; then it is
|
||||
written over */
|
||||
|
||||
srv_created_new_raw = TRUE;
|
||||
|
||||
files[i] = os_file_create(
|
||||
name, OS_FILE_OPEN, OS_FILE_NORMAL,
|
||||
OS_DATA_FILE, &ret);
|
||||
@@ -375,6 +385,7 @@ open_or_create_data_files(
|
||||
if (!ret) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error in opening %s\n", name);
|
||||
os_file_get_last_error();
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
@@ -537,9 +548,6 @@ innobase_start_or_create_for_mysql(void)
|
||||
/*====================================*/
|
||||
/* out: DB_SUCCESS or error code */
|
||||
{
|
||||
ulint i;
|
||||
ulint k;
|
||||
ulint err;
|
||||
ibool create_new_db;
|
||||
ibool log_file_created;
|
||||
ibool log_created = FALSE;
|
||||
@@ -550,6 +558,9 @@ innobase_start_or_create_for_mysql(void)
|
||||
ulint max_arch_log_no;
|
||||
ibool start_archive;
|
||||
ulint sum_of_new_sizes;
|
||||
ulint err;
|
||||
ulint i;
|
||||
ulint k;
|
||||
mtr_t mtr;
|
||||
|
||||
log_do_write = TRUE;
|
||||
@@ -866,17 +877,19 @@ innobase_start_or_create_for_mysql(void)
|
||||
SRV_MAX_N_IO_THREADS); */
|
||||
}
|
||||
|
||||
/* Create the master thread which monitors the database
|
||||
server, and does purge and other utility operations */
|
||||
|
||||
os_thread_create(&srv_master_thread, NULL, thread_ids + 1 +
|
||||
SRV_MAX_N_IO_THREADS);
|
||||
/* fprintf(stderr, "Max allowed record size %lu\n",
|
||||
page_get_free_space_of_empty() / 2); */
|
||||
|
||||
/* Create the thread which watches the timeouts for lock waits */
|
||||
os_thread_create(&srv_lock_timeout_monitor_thread, NULL,
|
||||
/* Create the thread which watches the timeouts for lock waits
|
||||
and prints InnoDB monitor info */
|
||||
|
||||
os_thread_create(&srv_lock_timeout_and_monitor_thread, NULL,
|
||||
thread_ids + 2 + SRV_MAX_N_IO_THREADS);
|
||||
|
||||
/* Create the thread which warns of long semaphore waits */
|
||||
os_thread_create(&srv_error_monitor_thread, NULL,
|
||||
thread_ids + 3 + SRV_MAX_N_IO_THREADS);
|
||||
|
||||
srv_was_started = TRUE;
|
||||
srv_is_being_started = FALSE;
|
||||
|
||||
@@ -886,6 +899,17 @@ innobase_start_or_create_for_mysql(void)
|
||||
trx_sys_create_doublewrite_buf();
|
||||
}
|
||||
|
||||
err = dict_create_or_check_foreign_constraint_tables();
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
return((int)DB_ERROR);
|
||||
}
|
||||
|
||||
/* Create the master thread which monitors the database
|
||||
server, and does purge and other utility operations */
|
||||
|
||||
os_thread_create(&srv_master_thread, NULL, thread_ids + 1 +
|
||||
SRV_MAX_N_IO_THREADS);
|
||||
/* buf_debug_prints = TRUE; */
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
@@ -906,8 +930,12 @@ innobase_shutdown_for_mysql(void)
|
||||
if (srv_is_being_started) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: Warning: shutting down a not properly started database\n");
|
||||
" InnoDB: Warning: shutting down a not properly started\n");
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: or created database!\n");
|
||||
}
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
|
@@ -14,6 +14,7 @@ Created 9/5/1995 Heikki Tuuri
|
||||
#include "sync0sync.h"
|
||||
#include "sync0rw.h"
|
||||
#include "os0sync.h"
|
||||
#include "srv0srv.h"
|
||||
|
||||
/*
|
||||
WAIT ARRAY
|
||||
@@ -64,6 +65,8 @@ struct sync_cell_struct {
|
||||
ibool event_set; /* TRUE if the event is set */
|
||||
os_event_t event; /* operating system event
|
||||
semaphore handle */
|
||||
time_t reservation_time;/* time when the thread reserved
|
||||
the wait cell */
|
||||
};
|
||||
|
||||
/* NOTE: It is allowed for a thread to wait
|
||||
@@ -321,16 +324,12 @@ sync_array_reserve_cell(
|
||||
sync_array_t* arr, /* in: wait array */
|
||||
void* object, /* in: pointer to the object to wait for */
|
||||
ulint type, /* in: lock request type */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
char* file, /* in: in debug version file where
|
||||
requested */
|
||||
ulint line, /* in: in the debug version line where
|
||||
requested */
|
||||
#endif
|
||||
char* file, /* in: file where requested */
|
||||
ulint line, /* in: line where requested */
|
||||
ulint* index) /* out: index of the reserved cell */
|
||||
{
|
||||
ulint i;
|
||||
sync_cell_t* cell;
|
||||
ulint i;
|
||||
|
||||
ut_a(object);
|
||||
ut_a(index);
|
||||
@@ -350,18 +349,15 @@ sync_array_reserve_cell(
|
||||
sync_cell_event_reset(cell);
|
||||
}
|
||||
|
||||
cell->reservation_time = time(NULL);
|
||||
cell->thread = os_thread_get_curr_id();
|
||||
|
||||
cell->wait_object = object;
|
||||
cell->request_type = type;
|
||||
cell->thread = os_thread_get_curr_id();
|
||||
cell->waiting = FALSE;
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
cell->file = file;
|
||||
cell->line = line;
|
||||
#else
|
||||
cell->file = "NOT KNOWN";
|
||||
cell->line = 0;
|
||||
#endif
|
||||
|
||||
arr->n_reserved++;
|
||||
|
||||
@@ -436,6 +432,7 @@ static
|
||||
void
|
||||
sync_array_cell_print(
|
||||
/*==================*/
|
||||
FILE* file, /* in: file where to print */
|
||||
sync_cell_t* cell) /* in: sync cell */
|
||||
{
|
||||
mutex_t* mutex;
|
||||
@@ -445,53 +442,63 @@ sync_array_cell_print(
|
||||
|
||||
type = cell->request_type;
|
||||
|
||||
fprintf(file,
|
||||
"--Thread %lu has waited at %s line %lu for %.2f seconds the semaphore:\n",
|
||||
(ulint)cell->thread, cell->file, cell->line,
|
||||
difftime(time(NULL), cell->reservation_time));
|
||||
|
||||
if (type == SYNC_MUTEX) {
|
||||
str = "MUTEX ENTER";
|
||||
mutex = (mutex_t*)cell->wait_object;
|
||||
|
||||
printf("Mutex created in file %s line %lu",
|
||||
mutex->cfile_name, mutex->cline);
|
||||
fprintf(file,
|
||||
"Mutex at %lx created file %s line %lu, lock var %lu\n",
|
||||
(ulint)mutex, mutex->cfile_name, mutex->cline,
|
||||
mutex->lock_word);
|
||||
fprintf(file,
|
||||
"Last time reserved in file %s line %lu, waiters flag %lu\n",
|
||||
mutex->file_name, mutex->line, mutex->waiters);
|
||||
|
||||
} else if (type == RW_LOCK_EX || type == RW_LOCK_SHARED) {
|
||||
|
||||
if (type == RW_LOCK_EX) {
|
||||
str = "X-LOCK";
|
||||
fprintf(file, "X-lock on");
|
||||
} else {
|
||||
str = "S_LOCK";
|
||||
fprintf(file, "S-lock on");
|
||||
}
|
||||
|
||||
rwlock = (rw_lock_t*)cell->wait_object;
|
||||
|
||||
printf("Rw-latch created in file %s line %lu",
|
||||
rwlock->cfile_name, rwlock->cline);
|
||||
fprintf(file, " RW-latch at %lx created in file %s line %lu\n",
|
||||
(ulint)rwlock, rwlock->cfile_name, rwlock->cline);
|
||||
if (rwlock->writer != RW_LOCK_NOT_LOCKED) {
|
||||
printf(" writer reserved with %lu", rwlock->writer);
|
||||
}
|
||||
|
||||
if (rwlock->writer == RW_LOCK_EX) {
|
||||
printf(" reserv. thread id %lu",
|
||||
fprintf(file,
|
||||
"a writer (thread id %lu) has reserved it in mode",
|
||||
(ulint)rwlock->writer_thread);
|
||||
if (rwlock->writer == RW_LOCK_EX) {
|
||||
fprintf(file, " exclusive\n");
|
||||
} else {
|
||||
fprintf(file, " wait exclusive\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (rwlock->reader_count > 0) {
|
||||
printf(" readers %lu", rwlock->reader_count);
|
||||
}
|
||||
fprintf(file, "number of readers %lu, waiters flag %lu\n",
|
||||
rwlock->reader_count, rwlock->waiters);
|
||||
|
||||
fprintf(file, "Last time read locked in file %s line %lu\n",
|
||||
rwlock->last_s_file_name, rwlock->last_s_line);
|
||||
fprintf(file, "Last time write locked in file %s line %lu\n",
|
||||
rwlock->last_x_file_name, rwlock->last_x_line);
|
||||
} else {
|
||||
ut_error;
|
||||
}
|
||||
|
||||
printf(" at addr %lx waited for by thread %lu op. %s file %s line %lu ",
|
||||
(ulint)cell->wait_object,
|
||||
(ulint)cell->thread,
|
||||
str, cell->file, cell->line);
|
||||
if (!cell->waiting) {
|
||||
printf("WAIT ENDED ");
|
||||
fprintf(file, "wait has ended\n");
|
||||
}
|
||||
|
||||
if (cell->event_set) {
|
||||
printf("EVENT SET");
|
||||
fprintf(file, "wait is ending\n");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
@@ -620,6 +627,7 @@ sync_array_detect_deadlock(
|
||||
released the mutex: in this case no deadlock
|
||||
can occur, as the wait array cannot contain
|
||||
a thread with ID_UNDEFINED value. */
|
||||
|
||||
ret = sync_array_deadlock_step(arr, start, thread, 0,
|
||||
depth);
|
||||
if (ret) {
|
||||
@@ -627,7 +635,7 @@ sync_array_detect_deadlock(
|
||||
"Mutex %lx owned by thread %lu file %s line %lu\n",
|
||||
(ulint)mutex, mutex->thread_id,
|
||||
mutex->file_name, mutex->line);
|
||||
sync_array_cell_print(cell);
|
||||
sync_array_cell_print(stdout, cell);
|
||||
return(TRUE);
|
||||
}
|
||||
}
|
||||
@@ -661,7 +669,7 @@ sync_array_detect_deadlock(
|
||||
if (ret) {
|
||||
printf("rw-lock %lx ", (ulint) lock);
|
||||
rw_lock_debug_print(debug);
|
||||
sync_array_cell_print(cell);
|
||||
sync_array_cell_print(stdout, cell);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
@@ -694,7 +702,7 @@ sync_array_detect_deadlock(
|
||||
if (ret) {
|
||||
printf("rw-lock %lx ", (ulint) lock);
|
||||
rw_lock_debug_print(debug);
|
||||
sync_array_cell_print(cell);
|
||||
sync_array_cell_print(stdout, cell);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
@@ -713,6 +721,55 @@ sync_array_detect_deadlock(
|
||||
fooling only */
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Determines if we can wake up the thread waiting for a sempahore. */
|
||||
static
|
||||
ibool
|
||||
sync_arr_cell_can_wake_up(
|
||||
/*======================*/
|
||||
sync_cell_t* cell) /* in: cell to search */
|
||||
{
|
||||
mutex_t* mutex;
|
||||
rw_lock_t* lock;
|
||||
|
||||
if (cell->request_type == SYNC_MUTEX) {
|
||||
|
||||
mutex = cell->wait_object;
|
||||
|
||||
if (mutex_get_lock_word(mutex) == 0) {
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
} else if (cell->request_type == RW_LOCK_EX) {
|
||||
|
||||
lock = cell->wait_object;
|
||||
|
||||
if (rw_lock_get_reader_count(lock) == 0
|
||||
&& rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) {
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
if (rw_lock_get_reader_count(lock) == 0
|
||||
&& rw_lock_get_writer(lock) == RW_LOCK_WAIT_EX
|
||||
&& lock->writer_thread == cell->thread) {
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
} else if (cell->request_type == RW_LOCK_SHARED) {
|
||||
lock = cell->wait_object;
|
||||
|
||||
if (rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED) {
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Frees the cell. NOTE! sync_array_wait_event frees the cell
|
||||
automatically! */
|
||||
@@ -740,9 +797,8 @@ sync_array_free_cell(
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Looks for the cells in the wait array which refer
|
||||
to the wait object specified,
|
||||
and sets their corresponding events to the signaled state. In this
|
||||
Looks for the cells in the wait array which refer to the wait object
|
||||
specified, and sets their corresponding events to the signaled state. In this
|
||||
way releases the threads waiting for the object to contend for the object.
|
||||
It is possible that no such cell is found, in which case does nothing. */
|
||||
|
||||
@@ -782,6 +838,88 @@ sync_array_signal_object(
|
||||
sync_array_exit(arr);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
If the wakeup algorithm does not work perfectly at semaphore relases,
|
||||
this function will do the waking (see the comment in mutex_exit). This
|
||||
function should be called about every 1 second in the server. */
|
||||
|
||||
void
|
||||
sync_arr_wake_threads_if_sema_free(void)
|
||||
/*====================================*/
|
||||
{
|
||||
sync_array_t* arr = sync_primary_wait_array;
|
||||
sync_cell_t* cell;
|
||||
ulint count;
|
||||
ulint i;
|
||||
|
||||
sync_array_enter(arr);
|
||||
|
||||
i = 0;
|
||||
count = 0;
|
||||
|
||||
while (count < arr->n_reserved) {
|
||||
|
||||
cell = sync_array_get_nth_cell(arr, i);
|
||||
|
||||
if (cell->wait_object != NULL) {
|
||||
|
||||
count++;
|
||||
|
||||
if (sync_arr_cell_can_wake_up(cell)) {
|
||||
|
||||
sync_cell_event_set(cell);
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
sync_array_exit(arr);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Prints warnings of long semaphore waits to stderr. Currently > 120 sec. */
|
||||
|
||||
void
|
||||
sync_array_print_long_waits(void)
|
||||
/*=============================*/
|
||||
{
|
||||
sync_cell_t* cell;
|
||||
ibool old_val;
|
||||
ibool noticed = FALSE;
|
||||
ulint i;
|
||||
|
||||
for (i = 0; i < sync_primary_wait_array->n_cells; i++) {
|
||||
|
||||
cell = sync_array_get_nth_cell(sync_primary_wait_array, i);
|
||||
|
||||
if (cell->wait_object != NULL
|
||||
&& difftime(time(NULL), cell->reservation_time) > 120) {
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Warning: a long semaphore wait:\n");
|
||||
sync_array_cell_print(stderr, cell);
|
||||
|
||||
noticed = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (noticed) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: ###### Starts InnoDB Monitor for 30 secs to print diagnostic info:\n");
|
||||
old_val = srv_print_innodb_monitor;
|
||||
|
||||
srv_print_innodb_monitor = TRUE;
|
||||
os_event_set(srv_lock_timeout_thread_event);
|
||||
|
||||
os_thread_sleep(30000000);
|
||||
|
||||
srv_print_innodb_monitor = old_val;
|
||||
fprintf(stderr,
|
||||
"InnoDB: ###### Diagnostic info printed to the standard output\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Prints info of the wait array. */
|
||||
static
|
||||
@@ -795,8 +933,7 @@ sync_array_output_info(
|
||||
ulint count;
|
||||
ulint i;
|
||||
|
||||
printf("-----------------------------------------------------\n");
|
||||
printf("SYNC ARRAY INFO: reservation count %ld, signal count %ld\n",
|
||||
printf("OS WAIT ARRAY INFO: reservation count %ld, signal count %ld\n",
|
||||
arr->res_count, arr->sg_count);
|
||||
i = 0;
|
||||
count = 0;
|
||||
@@ -807,7 +944,7 @@ sync_array_output_info(
|
||||
|
||||
if (cell->wait_object != NULL) {
|
||||
count++;
|
||||
sync_array_cell_print(cell);
|
||||
sync_array_cell_print(stdout, cell);
|
||||
}
|
||||
|
||||
i++;
|
||||
|
@@ -17,11 +17,13 @@ Created 9/11/1995 Heikki Tuuri
|
||||
|
||||
ulint rw_s_system_call_count = 0;
|
||||
ulint rw_s_spin_wait_count = 0;
|
||||
ulint rw_s_os_wait_count = 0;
|
||||
|
||||
ulint rw_s_exit_count = 0;
|
||||
|
||||
ulint rw_x_system_call_count = 0;
|
||||
ulint rw_x_spin_wait_count = 0;
|
||||
ulint rw_x_os_wait_count = 0;
|
||||
|
||||
ulint rw_x_exit_count = 0;
|
||||
|
||||
@@ -95,8 +97,7 @@ rw_lock_create_func(
|
||||
mutex_create(rw_lock_get_mutex(lock));
|
||||
mutex_set_level(rw_lock_get_mutex(lock), SYNC_NO_ORDER_CHECK);
|
||||
|
||||
ut_memcpy(&(lock->mutex.cfile_name), cfile_name,
|
||||
ut_min(RW_CNAME_LEN - 1, ut_strlen(cfile_name)));
|
||||
lock->mutex.cfile_name = cfile_name;
|
||||
lock->mutex.cline = cline;
|
||||
|
||||
rw_lock_set_waiters(lock, 0);
|
||||
@@ -111,11 +112,14 @@ rw_lock_create_func(
|
||||
lock->magic_n = RW_LOCK_MAGIC_N;
|
||||
lock->level = SYNC_LEVEL_NONE;
|
||||
|
||||
ut_memcpy(&(lock->cfile_name), cfile_name,
|
||||
ut_min(RW_CNAME_LEN - 1, ut_strlen(cfile_name)));
|
||||
lock->cfile_name[RW_CNAME_LEN - 1] = '\0';
|
||||
lock->cfile_name = cfile_name;
|
||||
lock->cline = cline;
|
||||
|
||||
lock->last_s_file_name = "not yet reserved";
|
||||
lock->last_x_file_name = "not yet reserved";
|
||||
lock->last_s_line = 0;
|
||||
lock->last_x_line = 0;
|
||||
|
||||
mutex_enter(&rw_lock_list_mutex);
|
||||
|
||||
UT_LIST_ADD_FIRST(list, rw_lock_list, lock);
|
||||
@@ -186,14 +190,11 @@ for the lock, before suspending the thread. */
|
||||
void
|
||||
rw_lock_s_lock_spin(
|
||||
/*================*/
|
||||
rw_lock_t* lock /* in: pointer to rw-lock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,ulint pass, /* in: pass value; != 0, if the lock
|
||||
rw_lock_t* lock, /* in: pointer to rw-lock */
|
||||
ulint pass, /* in: pass value; != 0, if the lock
|
||||
will be passed to another thread to unlock */
|
||||
char* file_name, /* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
)
|
||||
ulint line) /* in: line where requested */
|
||||
{
|
||||
ulint index; /* index of the reserved wait cell */
|
||||
ulint i; /* spin round count */
|
||||
@@ -223,19 +224,14 @@ lock_loop:
|
||||
printf(
|
||||
"Thread %lu spin wait rw-s-lock at %lx cfile %s cline %lu rnds %lu\n",
|
||||
os_thread_get_curr_id(), (ulint)lock,
|
||||
&(lock->cfile_name), lock->cline, i);
|
||||
lock->cfile_name, lock->cline, i);
|
||||
}
|
||||
|
||||
mutex_enter(rw_lock_get_mutex(lock));
|
||||
|
||||
/* We try once again to obtain the lock */
|
||||
|
||||
if (TRUE == rw_lock_s_lock_low(lock
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
, pass, file_name,
|
||||
line
|
||||
#endif
|
||||
)) {
|
||||
if (TRUE == rw_lock_s_lock_low(lock, pass, file_name, line)) {
|
||||
mutex_exit(rw_lock_get_mutex(lock));
|
||||
|
||||
return; /* Success */
|
||||
@@ -247,9 +243,7 @@ lock_loop:
|
||||
|
||||
sync_array_reserve_cell(sync_primary_wait_array,
|
||||
lock, RW_LOCK_SHARED,
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
file_name, line,
|
||||
#endif
|
||||
&index);
|
||||
|
||||
rw_lock_set_waiters(lock, 1);
|
||||
@@ -260,10 +254,11 @@ lock_loop:
|
||||
printf(
|
||||
"Thread %lu OS wait rw-s-lock at %lx cfile %s cline %lu\n",
|
||||
os_thread_get_curr_id(), (ulint)lock,
|
||||
&(lock->cfile_name), lock->cline);
|
||||
lock->cfile_name, lock->cline);
|
||||
}
|
||||
|
||||
rw_s_system_call_count++;
|
||||
rw_s_os_wait_count++;
|
||||
|
||||
sync_array_wait_event(sync_primary_wait_array, index);
|
||||
|
||||
@@ -307,13 +302,10 @@ rw_lock_x_lock_low(
|
||||
not succeed, RW_LOCK_EX if success,
|
||||
RW_LOCK_WAIT_EX, if got wait reservation */
|
||||
rw_lock_t* lock, /* in: pointer to rw-lock */
|
||||
ulint pass /* in: pass value; != 0, if the lock will
|
||||
ulint pass, /* in: pass value; != 0, if the lock will
|
||||
be passed to another thread to unlock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,char* file_name, /* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
)
|
||||
char* file_name,/* in: file name where lock requested */
|
||||
ulint line) /* in: line where requested */
|
||||
{
|
||||
ut_ad(mutex_own(rw_lock_get_mutex(lock)));
|
||||
|
||||
@@ -330,6 +322,8 @@ rw_lock_x_lock_low(
|
||||
rw_lock_add_debug_info(lock, pass, RW_LOCK_EX,
|
||||
file_name, line);
|
||||
#endif
|
||||
lock->last_x_file_name = file_name;
|
||||
lock->last_x_line = line;
|
||||
|
||||
/* Locking succeeded, we may return */
|
||||
return(RW_LOCK_EX);
|
||||
@@ -364,6 +358,9 @@ rw_lock_x_lock_low(
|
||||
file_name, line);
|
||||
#endif
|
||||
|
||||
lock->last_x_file_name = file_name;
|
||||
lock->last_x_line = line;
|
||||
|
||||
/* Locking succeeded, we may return */
|
||||
return(RW_LOCK_EX);
|
||||
}
|
||||
@@ -382,6 +379,9 @@ rw_lock_x_lock_low(
|
||||
line);
|
||||
#endif
|
||||
|
||||
lock->last_x_file_name = file_name;
|
||||
lock->last_x_line = line;
|
||||
|
||||
/* Locking succeeded, we may return */
|
||||
return(RW_LOCK_EX);
|
||||
}
|
||||
@@ -404,13 +404,10 @@ void
|
||||
rw_lock_x_lock_func(
|
||||
/*================*/
|
||||
rw_lock_t* lock, /* in: pointer to rw-lock */
|
||||
ulint pass /* in: pass value; != 0, if the lock will
|
||||
ulint pass, /* in: pass value; != 0, if the lock will
|
||||
be passed to another thread to unlock */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,char* file_name, /* in: file name where lock requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
)
|
||||
char* file_name,/* in: file name where lock requested */
|
||||
ulint line) /* in: line where requested */
|
||||
{
|
||||
ulint index; /* index of the reserved wait cell */
|
||||
ulint state; /* lock state acquired */
|
||||
@@ -422,11 +419,7 @@ lock_loop:
|
||||
/* Acquire the mutex protecting the rw-lock fields */
|
||||
mutex_enter_fast(&(lock->mutex));
|
||||
|
||||
state = rw_lock_x_lock_low(lock, pass
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,file_name, line
|
||||
#endif
|
||||
);
|
||||
state = rw_lock_x_lock_low(lock, pass, file_name, line);
|
||||
|
||||
mutex_exit(&(lock->mutex));
|
||||
|
||||
@@ -469,6 +462,7 @@ lock_loop:
|
||||
os_thread_yield();
|
||||
}
|
||||
} else {
|
||||
i = 0; /* Eliminate a compiler warning */
|
||||
ut_error;
|
||||
}
|
||||
|
||||
@@ -476,7 +470,7 @@ lock_loop:
|
||||
printf(
|
||||
"Thread %lu spin wait rw-x-lock at %lx cfile %s cline %lu rnds %lu\n",
|
||||
os_thread_get_curr_id(), (ulint)lock,
|
||||
&(lock->cfile_name), lock->cline, i);
|
||||
lock->cfile_name, lock->cline, i);
|
||||
}
|
||||
|
||||
rw_x_spin_wait_count++;
|
||||
@@ -486,11 +480,7 @@ lock_loop:
|
||||
|
||||
mutex_enter(rw_lock_get_mutex(lock));
|
||||
|
||||
state = rw_lock_x_lock_low(lock, pass
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,file_name, line
|
||||
#endif
|
||||
);
|
||||
state = rw_lock_x_lock_low(lock, pass, file_name, line);
|
||||
|
||||
if (state == RW_LOCK_EX) {
|
||||
mutex_exit(rw_lock_get_mutex(lock));
|
||||
@@ -502,9 +492,7 @@ lock_loop:
|
||||
|
||||
sync_array_reserve_cell(sync_primary_wait_array,
|
||||
lock, RW_LOCK_EX,
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
file_name, line,
|
||||
#endif
|
||||
&index);
|
||||
|
||||
rw_lock_set_waiters(lock, 1);
|
||||
@@ -514,11 +502,12 @@ lock_loop:
|
||||
if (srv_print_latch_waits) {
|
||||
printf(
|
||||
"Thread %lu OS wait for rw-x-lock at %lx cfile %s cline %lu\n",
|
||||
os_thread_get_curr_id(), (ulint)lock, &(lock->cfile_name),
|
||||
os_thread_get_curr_id(), (ulint)lock, lock->cfile_name,
|
||||
lock->cline);
|
||||
}
|
||||
|
||||
rw_x_system_call_count++;
|
||||
rw_x_os_wait_count++;
|
||||
|
||||
sync_array_wait_event(sync_primary_wait_array, index);
|
||||
|
||||
@@ -537,8 +526,8 @@ rw_lock_debug_mutex_enter(void)
|
||||
/*==========================*/
|
||||
{
|
||||
loop:
|
||||
if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) {
|
||||
|
||||
if (0 == mutex_enter_nowait(&rw_lock_debug_mutex,
|
||||
IB__FILE__, __LINE__)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -546,8 +535,8 @@ loop:
|
||||
|
||||
rw_lock_debug_waiters = TRUE;
|
||||
|
||||
if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) {
|
||||
|
||||
if (0 == mutex_enter_nowait(&rw_lock_debug_mutex,
|
||||
IB__FILE__, __LINE__)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -747,8 +736,6 @@ rw_lock_list_print_info(void)
|
||||
/*=========================*/
|
||||
{
|
||||
#ifndef UNIV_SYNC_DEBUG
|
||||
printf(
|
||||
"Sorry, cannot give rw-lock list info in non-debug version!\n");
|
||||
#else
|
||||
rw_lock_t* lock;
|
||||
ulint count = 0;
|
||||
@@ -756,8 +743,9 @@ rw_lock_list_print_info(void)
|
||||
|
||||
mutex_enter(&rw_lock_list_mutex);
|
||||
|
||||
printf("----------------------------------------------\n");
|
||||
printf("RW-LOCK INFO\n");
|
||||
printf("-------------\n");
|
||||
printf("RW-LATCH INFO\n");
|
||||
printf("-------------\n");
|
||||
|
||||
lock = UT_LIST_GET_FIRST(rw_lock_list);
|
||||
|
||||
@@ -810,9 +798,9 @@ rw_lock_print(
|
||||
ulint count = 0;
|
||||
rw_lock_debug_t* info;
|
||||
|
||||
printf("-------------------------------------------------\n");
|
||||
printf("RW-LOCK INFO\n");
|
||||
printf("RW-LOCK: %lx ", (ulint)lock);
|
||||
printf("-------------\n");
|
||||
printf("RW-LATCH INFO\n");
|
||||
printf("RW-LATCH: %lx ", (ulint)lock);
|
||||
|
||||
if ((rw_lock_get_writer(lock) != RW_LOCK_NOT_LOCKED)
|
||||
|| (rw_lock_get_reader_count(lock) != 0)
|
||||
|
@@ -119,6 +119,7 @@ ulint mutex_system_call_count = 0;
|
||||
|
||||
ulint mutex_spin_round_count = 0;
|
||||
ulint mutex_spin_wait_count = 0;
|
||||
ulint mutex_os_wait_count = 0;
|
||||
ulint mutex_exit_count = 0;
|
||||
|
||||
/* The global array of wait cells for implementation of the database's own
|
||||
@@ -228,12 +229,10 @@ mutex_create_func(
|
||||
mutex_set_waiters(mutex, 0);
|
||||
mutex->magic_n = MUTEX_MAGIC_N;
|
||||
mutex->line = 0;
|
||||
mutex->file_name = "FILE NOT KNOWN";
|
||||
mutex->file_name = "not yet reserved";
|
||||
mutex->thread_id = ULINT_UNDEFINED;
|
||||
mutex->level = SYNC_LEVEL_NONE;
|
||||
ut_memcpy(&(mutex->cfile_name), cfile_name,
|
||||
ut_min(MUTEX_CNAME_LEN - 1, ut_strlen(cfile_name)));
|
||||
mutex->cfile_name[MUTEX_CNAME_LEN - 1] = '\0';
|
||||
mutex->cfile_name = cfile_name;
|
||||
mutex->cline = cline;
|
||||
|
||||
/* Check that lock_word is aligned; this is important on Intel */
|
||||
@@ -292,16 +291,22 @@ ulint
|
||||
mutex_enter_nowait(
|
||||
/*===============*/
|
||||
/* out: 0 if succeed, 1 if not */
|
||||
mutex_t* mutex) /* in: pointer to mutex */
|
||||
mutex_t* mutex, /* in: pointer to mutex */
|
||||
char* file_name, /* in: file name where mutex
|
||||
requested */
|
||||
ulint line) /* in: line where requested */
|
||||
{
|
||||
ut_ad(mutex_validate(mutex));
|
||||
|
||||
if (!mutex_test_and_set(mutex)) {
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
mutex_set_debug_info(mutex, IB__FILE__, __LINE__);
|
||||
mutex_set_debug_info(mutex, file_name, line);
|
||||
#endif
|
||||
|
||||
mutex->file_name = file_name;
|
||||
mutex->line = line;
|
||||
|
||||
return(0); /* Succeeded! */
|
||||
}
|
||||
|
||||
@@ -349,13 +354,9 @@ for the mutex before suspending the thread. */
|
||||
void
|
||||
mutex_spin_wait(
|
||||
/*============*/
|
||||
mutex_t* mutex /* in: pointer to mutex */
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
,char* file_name, /* in: file name where mutex requested */
|
||||
ulint line /* in: line where requested */
|
||||
#endif
|
||||
)
|
||||
mutex_t* mutex, /* in: pointer to mutex */
|
||||
char* file_name, /* in: file name where mutex requested */
|
||||
ulint line) /* in: line where requested */
|
||||
{
|
||||
ulint index; /* index of the reserved wait cell */
|
||||
ulint i; /* spin round count */
|
||||
@@ -391,7 +392,7 @@ spin_loop:
|
||||
if (srv_print_latch_waits) {
|
||||
printf(
|
||||
"Thread %lu spin wait mutex at %lx cfile %s cline %lu rnds %lu\n",
|
||||
os_thread_get_curr_id(), (ulint)mutex, &(mutex->cfile_name),
|
||||
os_thread_get_curr_id(), (ulint)mutex, mutex->cfile_name,
|
||||
mutex->cline, i);
|
||||
}
|
||||
|
||||
@@ -404,6 +405,9 @@ spin_loop:
|
||||
mutex_set_debug_info(mutex, file_name, line);
|
||||
#endif
|
||||
|
||||
mutex->file_name = file_name;
|
||||
mutex->line = line;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -423,9 +427,7 @@ spin_loop:
|
||||
|
||||
sync_array_reserve_cell(sync_primary_wait_array, mutex,
|
||||
SYNC_MUTEX,
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
file_name, line,
|
||||
#endif
|
||||
&index);
|
||||
|
||||
mutex_system_call_count++;
|
||||
@@ -438,6 +440,8 @@ spin_loop:
|
||||
|
||||
mutex_set_waiters(mutex, 1);
|
||||
|
||||
/* Try to reserve still a few times */
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (mutex_test_and_set(mutex) == 0) {
|
||||
|
||||
/* Succeeded! Free the reserved wait cell */
|
||||
@@ -448,6 +452,9 @@ spin_loop:
|
||||
mutex_set_debug_info(mutex, file_name, line);
|
||||
#endif
|
||||
|
||||
mutex->file_name = file_name;
|
||||
mutex->line = line;
|
||||
|
||||
if (srv_print_latch_waits) {
|
||||
printf(
|
||||
"Thread %lu spin wait succeeds at 2: mutex at %lx\n",
|
||||
@@ -460,6 +467,7 @@ spin_loop:
|
||||
set to 1. We cannot reset it to zero, as we do not know
|
||||
if there are other waiters. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we know that there has been some thread holding the mutex
|
||||
after the change in the wait array and the waiters field was made.
|
||||
@@ -468,11 +476,13 @@ spin_loop:
|
||||
if (srv_print_latch_waits) {
|
||||
printf(
|
||||
"Thread %lu OS wait mutex at %lx cfile %s cline %lu rnds %lu\n",
|
||||
os_thread_get_curr_id(), (ulint)mutex, &(mutex->cfile_name),
|
||||
os_thread_get_curr_id(), (ulint)mutex, mutex->cfile_name,
|
||||
mutex->cline, i);
|
||||
}
|
||||
|
||||
mutex_system_call_count++;
|
||||
mutex_os_wait_count++;
|
||||
|
||||
sync_array_wait_event(sync_primary_wait_array, index);
|
||||
|
||||
goto mutex_loop;
|
||||
@@ -578,7 +588,6 @@ mutex_list_print_info(void)
|
||||
/*=======================*/
|
||||
{
|
||||
#ifndef UNIV_SYNC_DEBUG
|
||||
printf("Sorry, cannot give mutex list info in non-debug version!\n");
|
||||
#else
|
||||
mutex_t* mutex;
|
||||
char* file_name;
|
||||
@@ -586,8 +595,9 @@ mutex_list_print_info(void)
|
||||
os_thread_id_t thread_id;
|
||||
ulint count = 0;
|
||||
|
||||
printf("-----------------------------------------------\n");
|
||||
printf("----------\n");
|
||||
printf("MUTEX INFO\n");
|
||||
printf("----------\n");
|
||||
|
||||
mutex_enter(&mutex_list_mutex);
|
||||
|
||||
@@ -597,10 +607,10 @@ mutex_list_print_info(void)
|
||||
count++;
|
||||
|
||||
if (mutex_get_lock_word(mutex) != 0) {
|
||||
|
||||
mutex_get_debug_info(mutex, &file_name, &line, &thread_id);
|
||||
|
||||
printf("Locked mutex: addr %lx thread %ld file %s line %ld\n",
|
||||
mutex_get_debug_info(mutex, &file_name, &line,
|
||||
&thread_id);
|
||||
printf(
|
||||
"Locked mutex: addr %lx thread %ld file %s line %ld\n",
|
||||
(ulint)mutex, thread_id, file_name, line);
|
||||
}
|
||||
|
||||
@@ -791,7 +801,7 @@ sync_thread_levels_g(
|
||||
limit, slot->level);
|
||||
|
||||
if (mutex->magic_n == MUTEX_MAGIC_N) {
|
||||
printf("Mutex created at %s %lu\n", &(mutex->cfile_name),
|
||||
printf("Mutex created at %s %lu\n", mutex->cfile_name,
|
||||
mutex->cline);
|
||||
|
||||
if (mutex_get_lock_word(mutex) != 0) {
|
||||
@@ -890,6 +900,7 @@ sync_thread_levels_empty_gen(
|
||||
|
||||
if (slot->latch != NULL && (!dict_mutex_allowed ||
|
||||
(slot->level != SYNC_DICT
|
||||
&& slot->level != SYNC_FOREIGN_KEY_CHECK
|
||||
&& slot->level != SYNC_PURGE_IS_RUNNING))) {
|
||||
|
||||
lock = slot->latch;
|
||||
@@ -993,6 +1004,8 @@ sync_thread_add_level(
|
||||
ut_a(sync_thread_levels_g(array, SYNC_RECV));
|
||||
} else if (level == SYNC_LOG) {
|
||||
ut_a(sync_thread_levels_g(array, SYNC_LOG));
|
||||
} else if (level == SYNC_THR_LOCAL) {
|
||||
ut_a(sync_thread_levels_g(array, SYNC_THR_LOCAL));
|
||||
} else if (level == SYNC_ANY_LATCH) {
|
||||
ut_a(sync_thread_levels_g(array, SYNC_ANY_LATCH));
|
||||
} else if (level == SYNC_TRX_SYS_HEADER) {
|
||||
@@ -1071,6 +1084,8 @@ sync_thread_add_level(
|
||||
SYNC_IBUF_PESS_INSERT_MUTEX));
|
||||
} else if (level == SYNC_DICT_AUTOINC_MUTEX) {
|
||||
ut_a(sync_thread_levels_g(array, SYNC_DICT_AUTOINC_MUTEX));
|
||||
} else if (level == SYNC_FOREIGN_KEY_CHECK) {
|
||||
ut_a(sync_thread_levels_g(array, SYNC_FOREIGN_KEY_CHECK));
|
||||
} else if (level == SYNC_DICT_HEADER) {
|
||||
ut_a(sync_thread_levels_g(array, SYNC_DICT_HEADER));
|
||||
} else if (level == SYNC_PURGE_IS_RUNNING) {
|
||||
@@ -1231,15 +1246,17 @@ void
|
||||
sync_print_wait_info(void)
|
||||
/*======================*/
|
||||
{
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
printf("Mutex exits %lu, rws exits %lu, rwx exits %lu\n",
|
||||
mutex_exit_count, rw_s_exit_count, rw_x_exit_count);
|
||||
#endif
|
||||
printf(
|
||||
"Mut ex %lu sp %lu r %lu sys %lu; rws %lu %lu %lu; rwx %lu %lu %lu\n",
|
||||
mutex_exit_count,
|
||||
"Mutex spin waits %lu, rounds %lu, OS waits %lu\n"
|
||||
"RW-shared spins %lu, OS waits %lu; RW-excl spins %lu, OS waits %lu\n",
|
||||
mutex_spin_wait_count, mutex_spin_round_count,
|
||||
mutex_system_call_count,
|
||||
rw_s_exit_count,
|
||||
rw_s_spin_wait_count, rw_s_system_call_count,
|
||||
rw_x_exit_count,
|
||||
rw_x_spin_wait_count, rw_x_system_call_count);
|
||||
mutex_os_wait_count,
|
||||
rw_s_spin_wait_count, rw_s_os_wait_count,
|
||||
rw_x_spin_wait_count, rw_x_os_wait_count);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
@@ -1249,10 +1266,8 @@ void
|
||||
sync_print(void)
|
||||
/*============*/
|
||||
{
|
||||
printf("SYNC INFO:\n");
|
||||
mutex_list_print_info();
|
||||
rw_lock_list_print_info();
|
||||
sync_array_print_info(sync_primary_wait_array);
|
||||
sync_print_wait_info();
|
||||
printf("-----------------------------------------------------\n");
|
||||
}
|
||||
|
@@ -224,5 +224,5 @@ thr_local_init(void)
|
||||
thr_local_hash = hash_create(OS_THREAD_MAX_N + 100);
|
||||
|
||||
mutex_create(&thr_local_mutex);
|
||||
mutex_set_level(&thr_local_mutex, SYNC_ANY_LATCH);
|
||||
mutex_set_level(&thr_local_mutex, SYNC_THR_LOCAL);
|
||||
}
|
||||
|
@@ -276,6 +276,12 @@ trx_purge_add_update_undo_to_history(
|
||||
if (undo->state != TRX_UNDO_CACHED) {
|
||||
/* The undo log segment will not be reused */
|
||||
|
||||
if (undo->id >= TRX_RSEG_N_SLOTS) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: undo->id is %lu\n", undo->id);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
trx_rsegf_set_nth_undo(rseg_header, undo->id, FIL_NULL, mtr);
|
||||
|
||||
hist_size = mtr_read_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
|
||||
|
@@ -1078,9 +1078,7 @@ trx_undo_report_row_operation(
|
||||
undo_page = buf_page_get_gen(undo->space, page_no,
|
||||
RW_X_LATCH, undo->guess_page,
|
||||
BUF_GET,
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
IB__FILE__, __LINE__,
|
||||
#endif
|
||||
&mtr);
|
||||
|
||||
buf_page_dbg_add_level(undo_page, SYNC_TRX_UNDO_PAGE);
|
||||
|
@@ -109,6 +109,9 @@ trx_create(
|
||||
UT_LIST_INIT(trx->trx_locks);
|
||||
|
||||
trx->has_search_latch = FALSE;
|
||||
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
|
||||
|
||||
trx->auto_inc_lock = NULL;
|
||||
|
||||
trx->read_view_heap = mem_heap_create(256);
|
||||
trx->read_view = NULL;
|
||||
@@ -193,6 +196,7 @@ trx_free(
|
||||
ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
|
||||
|
||||
ut_a(!trx->has_search_latch);
|
||||
ut_a(!trx->auto_inc_lock);
|
||||
|
||||
if (trx->lock_heap) {
|
||||
mem_heap_free(trx->lock_heap);
|
||||
|
@@ -361,6 +361,8 @@ trx_undo_page_init(
|
||||
mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE,
|
||||
TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
|
||||
|
||||
fil_page_set_type(undo_page, FIL_PAGE_UNDO_LOG);
|
||||
|
||||
trx_undo_page_init_log(undo_page, type, mtr);
|
||||
}
|
||||
|
||||
@@ -1106,6 +1108,12 @@ trx_undo_mem_create_at_db_start(
|
||||
page_t* last_page;
|
||||
trx_undo_rec_t* rec;
|
||||
|
||||
if (id >= TRX_RSEG_N_SLOTS) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: undo->id is %lu\n", id);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
undo_page = trx_undo_page_get(rseg->space, page_no, mtr);
|
||||
|
||||
page_header = undo_page + TRX_UNDO_PAGE_HDR;
|
||||
@@ -1252,6 +1260,12 @@ trx_undo_mem_create(
|
||||
|
||||
ut_ad(mutex_own(&(rseg->mutex)));
|
||||
|
||||
if (id >= TRX_RSEG_N_SLOTS) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: undo->id is %lu\n", id);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
undo = mem_alloc(sizeof(trx_undo_t));
|
||||
|
||||
undo->id = id;
|
||||
@@ -1290,6 +1304,12 @@ trx_undo_mem_init_for_reuse(
|
||||
{
|
||||
ut_ad(mutex_own(&((undo->rseg)->mutex)));
|
||||
|
||||
if (undo->id >= TRX_RSEG_N_SLOTS) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: undo->id is %lu\n", undo->id);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
undo->state = TRX_UNDO_ACTIVE;
|
||||
undo->del_marks = FALSE;
|
||||
undo->trx_id = trx_id;
|
||||
@@ -1308,6 +1328,12 @@ trx_undo_mem_free(
|
||||
/*==============*/
|
||||
trx_undo_t* undo) /* in: the undo object to be freed */
|
||||
{
|
||||
if (undo->id >= TRX_RSEG_N_SLOTS) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: undo->id is %lu\n", undo->id);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
mem_free(undo);
|
||||
}
|
||||
|
||||
@@ -1493,6 +1519,9 @@ trx_undo_assign_undo(
|
||||
mutex_exit(&(rseg->mutex));
|
||||
mtr_commit(&mtr);
|
||||
|
||||
fprintf(stderr, "InnoDB: no undo log slots free\n");
|
||||
ut_a(0);
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
@@ -1536,6 +1565,12 @@ trx_undo_set_state_at_finish(
|
||||
|
||||
ut_ad(trx && undo && mtr);
|
||||
|
||||
if (undo->id >= TRX_RSEG_N_SLOTS) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: undo->id is %lu\n", undo->id);
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
undo_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr);
|
||||
|
||||
seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
|
||||
|
@@ -13,15 +13,22 @@ Created 5/11/1994 Heikki Tuuri
|
||||
#endif
|
||||
|
||||
#include "mem0mem.h"
|
||||
|
||||
#include "os0sync.h"
|
||||
|
||||
/* This struct is placed first in every allocated memory block */
|
||||
typedef struct ut_mem_block_struct ut_mem_block_t;
|
||||
|
||||
/* The total amount of memory currently allocated from the OS with malloc */
|
||||
ulint ut_total_allocated_memory = 0;
|
||||
|
||||
struct ut_mem_block_struct{
|
||||
UT_LIST_NODE_T(ut_mem_block_t) mem_block_list;/* mem block list node */
|
||||
UT_LIST_NODE_T(ut_mem_block_t) mem_block_list;
|
||||
/* mem block list node */
|
||||
ulint size; /* size of allocated memory */
|
||||
ulint magic_n;
|
||||
};
|
||||
|
||||
#define UT_MEM_MAGIC_N 1601650166
|
||||
|
||||
/* List of all memory blocks allocated from the operating system
|
||||
with malloc */
|
||||
@@ -70,11 +77,12 @@ ut_malloc_low(
|
||||
if (ret == NULL) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Fatal error: cannot allocate %lu bytes of\n"
|
||||
"InnoDB: memory with malloc!\n"
|
||||
"InnoDB: Operating system errno: %lu\n"
|
||||
"InnoDB: memory with malloc! Total allocated memory\n"
|
||||
"InnoDB: by InnoDB %lu bytes. Operating system errno: %lu\n"
|
||||
"InnoDB: Cannot continue operation!\n"
|
||||
"InnoDB: Check if you should increase the swap file or\n"
|
||||
"InnoDB: ulimits of your operating system.\n", n, errno);
|
||||
"InnoDB: ulimits of your operating system.\n",
|
||||
n, ut_total_allocated_memory, errno);
|
||||
|
||||
os_fast_mutex_unlock(&ut_list_mutex);
|
||||
|
||||
@@ -87,6 +95,11 @@ ut_malloc_low(
|
||||
#endif
|
||||
}
|
||||
|
||||
((ut_mem_block_t*)ret)->size = n + sizeof(ut_mem_block_t);
|
||||
((ut_mem_block_t*)ret)->magic_n = UT_MEM_MAGIC_N;
|
||||
|
||||
ut_total_allocated_memory += n + sizeof(ut_mem_block_t);
|
||||
|
||||
UT_LIST_ADD_FIRST(mem_block_list, ut_mem_block_list,
|
||||
((ut_mem_block_t*)ret));
|
||||
os_fast_mutex_unlock(&ut_list_mutex);
|
||||
@@ -107,7 +120,7 @@ ut_malloc(
|
||||
return(ut_malloc_low(n, TRUE));
|
||||
}
|
||||
/**************************************************************************
|
||||
Frees a memory bloock allocated with ut_malloc. */
|
||||
Frees a memory block allocated with ut_malloc. */
|
||||
|
||||
void
|
||||
ut_free(
|
||||
@@ -120,6 +133,11 @@ ut_free(
|
||||
|
||||
os_fast_mutex_lock(&ut_list_mutex);
|
||||
|
||||
ut_a(block->magic_n == UT_MEM_MAGIC_N);
|
||||
ut_a(ut_total_allocated_memory >= block->size);
|
||||
|
||||
ut_total_allocated_memory -= block->size;
|
||||
|
||||
UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
|
||||
free(block);
|
||||
|
||||
@@ -139,11 +157,18 @@ ut_free_all_mem(void)
|
||||
|
||||
while (block = UT_LIST_GET_FIRST(ut_mem_block_list)) {
|
||||
|
||||
ut_a(block->magic_n == UT_MEM_MAGIC_N);
|
||||
ut_a(ut_total_allocated_memory >= block->size);
|
||||
|
||||
ut_total_allocated_memory -= block->size;
|
||||
|
||||
UT_LIST_REMOVE(mem_block_list, ut_mem_block_list, block);
|
||||
free(block);
|
||||
}
|
||||
|
||||
os_fast_mutex_unlock(&ut_list_mutex);
|
||||
|
||||
ut_a(ut_total_allocated_memory == 0);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
@@ -187,6 +187,8 @@ ut_sprintf_buf(
|
||||
for (i = 0; i < len; i++) {
|
||||
if (isprint((char)(*data))) {
|
||||
n += sprintf(str + n, "%c", (char)*data);
|
||||
} else {
|
||||
n += sprintf(str + n, ".");
|
||||
}
|
||||
|
||||
data++;
|
||||
|
@@ -155,7 +155,23 @@ convert_error_code_to_mysql(
|
||||
|
||||
} else if (error == (int) DB_DEADLOCK) {
|
||||
|
||||
return(1000000);
|
||||
return(HA_ERR_LOCK_DEADLOCK);
|
||||
|
||||
} else if (error == (int) DB_LOCK_WAIT_TIMEOUT) {
|
||||
|
||||
return(1000001);
|
||||
|
||||
} else if (error == (int) DB_NO_REFERENCED_ROW) {
|
||||
|
||||
return(1000010);
|
||||
|
||||
} else if (error == (int) DB_ROW_IS_REFERENCED) {
|
||||
|
||||
return(1000011);
|
||||
|
||||
} else if (error == (int) DB_CANNOT_ADD_CONSTRAINT) {
|
||||
|
||||
return(1000012);
|
||||
|
||||
} else if (error == (int) DB_OUT_OF_FILE_SPACE) {
|
||||
|
||||
@@ -172,7 +188,6 @@ convert_error_code_to_mysql(
|
||||
} else if (error == (int) DB_TOO_BIG_RECORD) {
|
||||
|
||||
return(HA_ERR_TO_BIG_ROW);
|
||||
|
||||
} else {
|
||||
dbug_assert(0);
|
||||
|
||||
@@ -214,7 +229,7 @@ innobase_mysql_print_thd(
|
||||
}
|
||||
|
||||
if (thd->query) {
|
||||
printf(" %0.100s", thd->query);
|
||||
printf("\n%0.100s", thd->query);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
@@ -548,8 +563,9 @@ innobase_init(void)
|
||||
"to the [mysqld] section of init parameters in your my.cnf\n"
|
||||
"or my.ini. If you want to use InnoDB tables, add for example,\n"
|
||||
"innodb_data_file_path = /mysql/data/ibdata1:20M\n"
|
||||
"More information on setting the parameters you find in the\n"
|
||||
"manual.\n");
|
||||
"But to get good performance you should adjust for your hardware\n"
|
||||
"the InnoDB stratup options listed in section 7.6 at\n"
|
||||
"http://www.mysql.com/doc/\n");
|
||||
|
||||
innodb_skip=1;
|
||||
DBUG_RETURN(FALSE); // Continue without innobase
|
||||
@@ -597,6 +613,16 @@ innobase_init(void)
|
||||
|
||||
srv_lock_wait_timeout = (ulint) innobase_lock_wait_timeout;
|
||||
|
||||
if (strcmp(default_charset_info->name, "latin1") == 0) {
|
||||
/* Store the character ordering table to InnoDB.
|
||||
For non-latin1 charsets we use the MySQL comparison
|
||||
functions, and consequently we do not need to know
|
||||
the ordering internally in InnoDB. */
|
||||
|
||||
memcpy(srv_latin1_ordering,
|
||||
default_charset_info->sort_order, 256);
|
||||
}
|
||||
|
||||
err = innobase_start_or_create_for_mysql();
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
@@ -645,7 +671,7 @@ innobase_flush_logs(void)
|
||||
|
||||
DBUG_ENTER("innobase_flush_logs");
|
||||
|
||||
log_make_checkpoint_at(ut_dulint_max, TRUE);
|
||||
log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP);
|
||||
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
@@ -878,10 +904,10 @@ ha_innobase::open(
|
||||
if (NULL == (ib_table = dict_table_get(norm_name, NULL))) {
|
||||
|
||||
fprintf(stderr,
|
||||
"Cannot find table %s from the internal data dictionary\n"
|
||||
"of InnoDB though the .frm file for the table exists. Maybe you have deleted\n"
|
||||
"and created again an InnoDB database but forgotten to delete the\n"
|
||||
"corresponding .frm files of old InnoDB tables?\n",
|
||||
"InnoDB: Cannot find table %s from the internal data dictionary\n"
|
||||
"InnoDB: of InnoDB though the .frm file for the table exists. Maybe you\n"
|
||||
"InnoDB: have deleted and recreated InnoDB data files but have forgotten\n"
|
||||
"InnoDB: to delete the corresponding .frm files of InnoDB tables?\n",
|
||||
norm_name);
|
||||
|
||||
free_share(share);
|
||||
@@ -1401,8 +1427,36 @@ ha_innobase::write_row(
|
||||
current value and the value supplied by the user, if
|
||||
the auto_inc counter is already initialized
|
||||
for the table */
|
||||
|
||||
/* We have to use the transactional lock mechanism
|
||||
on the auto-inc counter of the table to ensure
|
||||
that replication and roll-forward of the binlog
|
||||
exactly imitates also the given auto-inc values.
|
||||
The lock is released at each SQL statement's
|
||||
end. */
|
||||
|
||||
error = row_lock_table_autoinc_for_mysql(prebuilt);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
|
||||
error = convert_error_code_to_mysql(error);
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
dict_table_autoinc_update(prebuilt->table, auto_inc);
|
||||
} else {
|
||||
if (!prebuilt->trx->auto_inc_lock) {
|
||||
|
||||
error = row_lock_table_autoinc_for_mysql(
|
||||
prebuilt);
|
||||
if (error != DB_SUCCESS) {
|
||||
|
||||
error = convert_error_code_to_mysql(
|
||||
error);
|
||||
goto func_exit;
|
||||
}
|
||||
}
|
||||
|
||||
auto_inc = dict_table_autoinc_get(prebuilt->table);
|
||||
|
||||
/* If auto_inc is now != 0 the autoinc counter
|
||||
@@ -1460,7 +1514,7 @@ ha_innobase::write_row(
|
||||
|
||||
/* Tell InnoDB server that there might be work for
|
||||
utility threads: */
|
||||
|
||||
func_exit:
|
||||
innobase_active_small();
|
||||
|
||||
DBUG_RETURN(error);
|
||||
@@ -1737,7 +1791,7 @@ ha_innobase::index_init(
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
?????????????????????????????????? */
|
||||
Currently does nothing. */
|
||||
|
||||
int
|
||||
ha_innobase::index_end(void)
|
||||
@@ -2299,6 +2353,15 @@ ha_innobase::external_lock(
|
||||
trx_search_latch_release_if_reserved(trx);
|
||||
}
|
||||
|
||||
if (trx->auto_inc_lock) {
|
||||
|
||||
/* If we had reserved the auto-inc lock for
|
||||
some table in this SQL statement, we release
|
||||
it now */
|
||||
|
||||
row_unlock_table_autoinc_for_mysql(trx);
|
||||
}
|
||||
|
||||
if (!(thd->options
|
||||
& (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))) {
|
||||
innobase_commit(thd, trx);
|
||||
@@ -2461,7 +2524,9 @@ ha_innobase::create(
|
||||
const char* name, /* in: table name */
|
||||
TABLE* form, /* in: information on table
|
||||
columns and indexes */
|
||||
HA_CREATE_INFO* create_info) /* in: ??????? */
|
||||
HA_CREATE_INFO* create_info) /* in: more information of the
|
||||
created table, contains also the
|
||||
create statement string */
|
||||
{
|
||||
int error;
|
||||
dict_table_t* innobase_table;
|
||||
@@ -2552,6 +2617,19 @@ ha_innobase::create(
|
||||
}
|
||||
}
|
||||
|
||||
error = row_table_add_foreign_constraints(trx,
|
||||
create_info->create_statement, norm_name);
|
||||
|
||||
error = convert_error_code_to_mysql(error);
|
||||
|
||||
if (error) {
|
||||
trx_commit_for_mysql(trx);
|
||||
|
||||
trx_free_for_mysql(trx);
|
||||
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
trx_commit_for_mysql(trx);
|
||||
|
||||
innobase_table = dict_table_get(norm_name, NULL);
|
||||
@@ -2572,8 +2650,8 @@ ha_innobase::create(
|
||||
Drops a table from an InnoDB database. Before calling this function,
|
||||
MySQL calls innobase_commit to commit the transaction of the current user.
|
||||
Then the current user cannot have locks set on the table. Drop table
|
||||
operation inside InnoDB will wait sleeping in a loop until no other
|
||||
user has locks on the table. */
|
||||
operation inside InnoDB will remove all locks any user has on the table
|
||||
inside InnoDB. */
|
||||
|
||||
int
|
||||
ha_innobase::delete_table(
|
||||
@@ -2615,6 +2693,53 @@ ha_innobase::delete_table(
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Removes all tables in the named database inside InnoDB. */
|
||||
|
||||
int
|
||||
innobase_drop_database(
|
||||
/*===================*/
|
||||
/* out: error number */
|
||||
char* path) /* in: database path; inside InnoDB the name
|
||||
of the last directory in the path is used as
|
||||
the database name: for example, in 'mysql/data/test'
|
||||
the database name is 'test' */
|
||||
{
|
||||
ulint len = 0;
|
||||
trx_t* trx;
|
||||
char* ptr;
|
||||
int error;
|
||||
char namebuf[10000];
|
||||
|
||||
ptr = strend(path) - 2;
|
||||
|
||||
while (ptr >= path && *ptr != '\\' && *ptr != '/') {
|
||||
ptr--;
|
||||
len++;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
|
||||
memcpy(namebuf, ptr, len);
|
||||
namebuf[len] = '/';
|
||||
namebuf[len + 1] = '\0';
|
||||
|
||||
trx = trx_allocate_for_mysql();
|
||||
|
||||
error = row_drop_database_for_mysql(namebuf, trx);
|
||||
|
||||
/* Tell the InnoDB server that there might be work for
|
||||
utility threads: */
|
||||
|
||||
srv_active_wake_master_thread();
|
||||
|
||||
trx_free_for_mysql(trx);
|
||||
|
||||
error = convert_error_code_to_mysql(error);
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Renames an InnoDB table. */
|
||||
|
||||
@@ -2751,11 +2876,12 @@ improve the algorithm of filesort.cc. */
|
||||
ha_rows
|
||||
ha_innobase::estimate_number_of_rows(void)
|
||||
/*======================================*/
|
||||
/* out: upper bound of rows, currently 32-bit int
|
||||
or uint */
|
||||
/* out: upper bound of rows */
|
||||
{
|
||||
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
|
||||
dict_table_t* ib_table;
|
||||
dict_index_t* index;
|
||||
ulonglong estimate;
|
||||
ulonglong data_file_length;
|
||||
|
||||
if (prebuilt->trx) {
|
||||
prebuilt->trx->op_info =
|
||||
@@ -2764,21 +2890,21 @@ ha_innobase::estimate_number_of_rows(void)
|
||||
|
||||
DBUG_ENTER("info");
|
||||
|
||||
ib_table = prebuilt->table;
|
||||
dict_update_statistics(prebuilt->table);
|
||||
|
||||
dict_update_statistics(ib_table);
|
||||
index = dict_table_get_first_index_noninline(prebuilt->table);
|
||||
|
||||
data_file_length = ((ulonglong)
|
||||
ib_table->stat_clustered_index_size)
|
||||
data_file_length = ((ulonglong) index->stat_n_leaf_pages)
|
||||
* UNIV_PAGE_SIZE;
|
||||
/* Calculate a minimum length for a clustered index record */
|
||||
|
||||
/* The minimum clustered index record size is 20 bytes */
|
||||
estimate = data_file_length / dict_index_calc_min_rec_len(index);
|
||||
|
||||
if (prebuilt->trx) {
|
||||
prebuilt->trx->op_info = "";
|
||||
}
|
||||
|
||||
return((ha_rows) (1000 + data_file_length / 20));
|
||||
return((ha_rows) estimate);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
@@ -2793,10 +2919,10 @@ ha_innobase::scan_time()
|
||||
{
|
||||
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
|
||||
|
||||
/* In the following formula we assume that scanning 5 pages
|
||||
/* In the following formula we assume that scanning 10 pages
|
||||
takes the same time as a disk seek: */
|
||||
|
||||
return((double) (1 + prebuilt->table->stat_clustered_index_size / 5));
|
||||
return((double) (prebuilt->table->stat_clustered_index_size / 10));
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
@@ -2811,8 +2937,9 @@ ha_innobase::info(
|
||||
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
|
||||
dict_table_t* ib_table;
|
||||
dict_index_t* index;
|
||||
uint rec_per_key;
|
||||
uint i;
|
||||
ulong rec_per_key;
|
||||
ulong j;
|
||||
ulong i;
|
||||
|
||||
DBUG_ENTER("info");
|
||||
|
||||
@@ -2830,7 +2957,7 @@ ha_innobase::info(
|
||||
}
|
||||
|
||||
if (flag & HA_STATUS_VARIABLE) {
|
||||
records = ib_table->stat_n_rows;
|
||||
records = (ha_rows)ib_table->stat_n_rows;
|
||||
deleted = 0;
|
||||
data_file_length = ((ulonglong)
|
||||
ib_table->stat_clustered_index_size)
|
||||
@@ -2856,16 +2983,24 @@ ha_innobase::info(
|
||||
}
|
||||
|
||||
for (i = 0; i < table->keys; i++) {
|
||||
if (index->stat_n_diff_key_vals == 0) {
|
||||
for (j = 0; j < table->key_info[i].key_parts; j++) {
|
||||
|
||||
if (index->stat_n_diff_key_vals[j + 1] == 0) {
|
||||
|
||||
rec_per_key = records;
|
||||
} else {
|
||||
rec_per_key = records /
|
||||
index->stat_n_diff_key_vals;
|
||||
rec_per_key = (ulong)(records /
|
||||
index->stat_n_diff_key_vals[j + 1]);
|
||||
}
|
||||
|
||||
table->key_info[i].rec_per_key[
|
||||
table->key_info[i].key_parts - 1]
|
||||
if (rec_per_key == 0) {
|
||||
rec_per_key = 1;
|
||||
}
|
||||
|
||||
table->key_info[i].rec_per_key[j]
|
||||
= rec_per_key;
|
||||
}
|
||||
|
||||
index = dict_table_get_next_index_noninline(index);
|
||||
}
|
||||
}
|
||||
|
@@ -177,3 +177,5 @@ uint innobase_get_free_space(void);
|
||||
int innobase_commit(THD *thd, void* trx_handle);
|
||||
int innobase_rollback(THD *thd, void* trx_handle);
|
||||
int innobase_close_connection(THD *thd);
|
||||
int innobase_drop_database(char *path);
|
||||
|
||||
|
@@ -211,6 +211,13 @@ int ha_panic(enum ha_panic_function flag)
|
||||
return error;
|
||||
} /* ha_panic */
|
||||
|
||||
void ha_drop_database(char* path)
|
||||
{
|
||||
#ifdef HAVE_INNOBASE_DB
|
||||
if (!innodb_skip)
|
||||
innobase_drop_database(path);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ha_close_connection(THD* thd)
|
||||
{
|
||||
|
@@ -143,6 +143,7 @@ typedef struct st_ha_create_information
|
||||
ulonglong max_rows,min_rows;
|
||||
ulonglong auto_increment_value;
|
||||
char *comment,*password;
|
||||
char *create_statement;
|
||||
uint options; /* OR of HA_CREATE_ options */
|
||||
uint raid_type,raid_chunks;
|
||||
ulong raid_chunksize;
|
||||
@@ -348,6 +349,7 @@ enum db_type ha_checktype(enum db_type database_type);
|
||||
int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
|
||||
bool update_create_info);
|
||||
int ha_delete_table(enum db_type db_type, const char *path);
|
||||
void ha_drop_database(char* path);
|
||||
void ha_key_cache(void);
|
||||
int ha_start_stmt(THD *thd);
|
||||
int ha_commit_trans(THD *thd, THD_TRANS *trans);
|
||||
|
@@ -164,6 +164,8 @@ void mysql_rm_db(THD *thd,char *db,bool if_exists)
|
||||
}
|
||||
remove_db_from_cache(db);
|
||||
|
||||
ha_drop_database(path);
|
||||
|
||||
if ((deleted=mysql_rm_known_files(thd, dirp, path,0)) >= 0)
|
||||
{
|
||||
if (!thd->query)
|
||||
|
@@ -587,6 +587,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
|
||||
|
||||
thd->proc_info="creating table";
|
||||
|
||||
create_info->create_statement = thd->query;
|
||||
create_info->table_options=db_options;
|
||||
if (rea_create_table(path, create_info, fields, key_count,
|
||||
key_info_buffer))
|
||||
|
Reference in New Issue
Block a user