Many files:

  Merge InnoDB-3.23.52b
parent 31359247
...@@ -2076,8 +2076,7 @@ btr_discard_page( ...@@ -2076,8 +2076,7 @@ btr_discard_page(
btr_search_drop_page_hash_index(page); btr_search_drop_page_hash_index(page);
if ((left_page_no == FIL_NULL) if (left_page_no == FIL_NULL && btr_page_get_level(page, mtr) > 0) {
&& (btr_page_get_level(page, mtr) > 0)) {
/* We have to mark the leftmost node pointer on the right /* We have to mark the leftmost node pointer on the right
side page as the predefined minimum record */ side page as the predefined minimum record */
......
...@@ -44,6 +44,8 @@ ulint btr_cur_rnd = 0; ...@@ -44,6 +44,8 @@ ulint btr_cur_rnd = 0;
ulint btr_cur_n_non_sea = 0; ulint btr_cur_n_non_sea = 0;
ulint btr_cur_n_sea = 0; ulint btr_cur_n_sea = 0;
ulint btr_cur_n_non_sea_old = 0;
ulint btr_cur_n_sea_old = 0;
/* In the optimistic insert, if the insert does not fit, but this much space /* In the optimistic insert, if the insert does not fit, but this much space
can be released by page reorganize, then it is reorganized */ can be released by page reorganize, then it is reorganized */
......
...@@ -452,6 +452,8 @@ btr_search_info_update_slow( ...@@ -452,6 +452,8 @@ btr_search_info_update_slow(
} }
if (build_index) { if (build_index) {
ut_a(block->n_fields + block->n_bytes > 0);
btr_search_build_page_hash_index(block->frame, btr_search_build_page_hash_index(block->frame,
block->n_fields, block->n_fields,
block->n_bytes, block->n_bytes,
...@@ -676,6 +678,9 @@ btr_search_guess_on_hash( ...@@ -676,6 +678,9 @@ btr_search_guess_on_hash(
rw_lock_s_lock(&btr_search_latch); rw_lock_s_lock(&btr_search_latch);
} }
ut_a(btr_search_latch.writer != RW_LOCK_EX);
ut_a(btr_search_latch.reader_count > 0);
rec = ha_search_and_get_data(btr_search_sys->hash_index, fold); rec = ha_search_and_get_data(btr_search_sys->hash_index, fold);
if (!rec) { if (!rec) {
...@@ -902,7 +907,7 @@ btr_search_drop_page_hash_index( ...@@ -902,7 +907,7 @@ btr_search_drop_page_hash_index(
fold = rec_fold(rec, n_fields, n_bytes, tree_id); fold = rec_fold(rec, n_fields, n_bytes, tree_id);
if ((fold == prev_fold) && (prev_fold != 0)) { if (fold == prev_fold && prev_fold != 0) {
goto next_rec; goto next_rec;
} }
...@@ -914,6 +919,7 @@ btr_search_drop_page_hash_index( ...@@ -914,6 +919,7 @@ btr_search_drop_page_hash_index(
n_cached++; n_cached++;
next_rec: next_rec:
rec = page_rec_get_next(rec); rec = page_rec_get_next(rec);
prev_fold = fold;
} }
rw_lock_x_lock(&btr_search_latch); rw_lock_x_lock(&btr_search_latch);
...@@ -954,7 +960,7 @@ btr_search_drop_page_hash_when_freed( ...@@ -954,7 +960,7 @@ btr_search_drop_page_hash_when_freed(
mtr_start(&mtr); mtr_start(&mtr);
/* We assume that if the caller has a latch on the page, /* We assume that if the caller has a latch on the page,
then the caller has already drooped the hash index for the page, then the caller has already dropped the hash index for the page,
and we never get here. Therefore we can acquire the s-latch to and we never get here. Therefore we can acquire the s-latch to
the page without fearing a deadlock. */ the page without fearing a deadlock. */
...@@ -1177,6 +1183,8 @@ btr_search_move_or_delete_hash_entries( ...@@ -1177,6 +1183,8 @@ btr_search_move_or_delete_hash_entries(
rw_lock_s_unlock(&btr_search_latch); rw_lock_s_unlock(&btr_search_latch);
ut_a(n_fields + n_bytes > 0);
btr_search_build_page_hash_index(new_page, n_fields, n_bytes, btr_search_build_page_hash_index(new_page, n_fields, n_bytes,
side); side);
ut_a(n_fields == block->curr_n_fields); ut_a(n_fields == block->curr_n_fields);
...@@ -1217,9 +1225,11 @@ btr_search_update_hash_on_delete( ...@@ -1217,9 +1225,11 @@ btr_search_update_hash_on_delete(
return; return;
} }
ut_a(block->curr_n_fields + block->curr_n_bytes > 0);
table = btr_search_sys->hash_index; table = btr_search_sys->hash_index;
tree_id = ((cursor->index)->tree)->id; tree_id = cursor->index->tree->id;
fold = rec_fold(rec, block->curr_n_fields, block->curr_n_bytes, fold = rec_fold(rec, block->curr_n_fields, block->curr_n_bytes,
tree_id); tree_id);
...@@ -1336,7 +1346,6 @@ btr_search_update_hash_on_insert( ...@@ -1336,7 +1346,6 @@ btr_search_update_hash_on_insert(
if (rec != page_get_infimum_rec(page)) { if (rec != page_get_infimum_rec(page)) {
fold = rec_fold(rec, n_fields, n_bytes, tree_id); fold = rec_fold(rec, n_fields, n_bytes, tree_id);
} else { } else {
if (side == BTR_SEARCH_LEFT_SIDE) { if (side == BTR_SEARCH_LEFT_SIDE) {
...@@ -1421,7 +1430,7 @@ btr_search_print_info(void) ...@@ -1421,7 +1430,7 @@ btr_search_print_info(void)
rw_lock_x_lock(&btr_search_latch); rw_lock_x_lock(&btr_search_latch);
ha_print_info(btr_search_sys->hash_index); /* ha_print_info(btr_search_sys->hash_index); */
rw_lock_x_unlock(&btr_search_latch); rw_lock_x_unlock(&btr_search_latch);
} }
...@@ -1487,11 +1496,71 @@ btr_search_validate(void) ...@@ -1487,11 +1496,71 @@ btr_search_validate(void)
/*=====================*/ /*=====================*/
/* out: TRUE if ok */ /* out: TRUE if ok */
{ {
buf_block_t* block;
page_t* page;
ha_node_t* node;
ulint n_page_dumps = 0;
ibool ok = TRUE;
ulint i;
char rec_str[500];
rw_lock_x_lock(&btr_search_latch); rw_lock_x_lock(&btr_search_latch);
ut_a(ha_validate(btr_search_sys->hash_index)); for (i = 0; i < hash_get_n_cells(btr_search_sys->hash_index); i++) {
node = hash_get_nth_cell(btr_search_sys->hash_index, i)->node;
while (node != NULL) {
block = buf_block_align(node->data);
page = buf_frame_align(node->data);
if (!block->is_hashed
|| node->fold != rec_fold((rec_t*)(node->data),
block->curr_n_fields,
block->curr_n_bytes,
btr_page_get_index_id(page))) {
ok = FALSE;
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error in an adaptive hash index pointer to page %lu\n"
"ptr mem address %lu index id %lu %lu, node fold %lu, rec fold %lu\n",
buf_frame_get_page_no(page),
(ulint)(node->data),
ut_dulint_get_high(btr_page_get_index_id(page)),
ut_dulint_get_low(btr_page_get_index_id(page)),
node->fold, rec_fold((rec_t*)(node->data),
block->curr_n_fields,
block->curr_n_bytes,
btr_page_get_index_id(page)));
rec_sprintf(rec_str, 450, (rec_t*)(node->data));
fprintf(stderr,
"InnoDB: Record %s\n"
"InnoDB: on that page.", rec_str);
fprintf(stderr,
"Page mem address %lu, is hashed %lu, n fields %lu, n bytes %lu\n"
"side %lu\n",
(ulint)page, block->is_hashed, block->curr_n_fields,
block->curr_n_bytes, block->curr_side);
if (n_page_dumps < 20) {
buf_page_print(page);
n_page_dumps++;
}
}
node = node->next;
}
}
if (!ha_validate(btr_search_sys->hash_index)) {
ok = FALSE;
}
rw_lock_x_unlock(&btr_search_latch); rw_lock_x_unlock(&btr_search_latch);
return(TRUE); return(ok);
} }
...@@ -1798,8 +1798,10 @@ buf_get_n_pending_ios(void) ...@@ -1798,8 +1798,10 @@ buf_get_n_pending_ios(void)
Prints info of the buffer i/o. */ Prints info of the buffer i/o. */
void void
buf_print_io(void) buf_print_io(
/*==============*/ /*=========*/
char* buf, /* in/out: buffer where to print */
char* buf_end)/* in: buffer end */
{ {
time_t current_time; time_t current_time;
double time_elapsed; double time_elapsed;
...@@ -1807,19 +1809,28 @@ buf_print_io(void) ...@@ -1807,19 +1809,28 @@ buf_print_io(void)
ut_ad(buf_pool); ut_ad(buf_pool);
if (buf_end - buf < 400) {
return;
}
size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE; size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE;
mutex_enter(&(buf_pool->mutex)); mutex_enter(&(buf_pool->mutex));
printf("Free list length %lu \n", UT_LIST_GET_LEN(buf_pool->free)); buf += sprintf(buf,
printf("LRU list length %lu \n", UT_LIST_GET_LEN(buf_pool->LRU)); "Free list length %lu \n", UT_LIST_GET_LEN(buf_pool->free));
printf("Flush list length %lu \n", buf += sprintf(buf,
"LRU list length %lu \n", UT_LIST_GET_LEN(buf_pool->LRU));
buf += sprintf(buf,
"Flush list length %lu \n",
UT_LIST_GET_LEN(buf_pool->flush_list)); UT_LIST_GET_LEN(buf_pool->flush_list));
printf("Buffer pool size %lu\n", size); buf += sprintf(buf, "Buffer pool size %lu\n", size);
printf("Pending reads %lu \n", buf_pool->n_pend_reads); buf += sprintf(buf, "Pending reads %lu \n", buf_pool->n_pend_reads);
printf("Pending writes: LRU %lu, flush list %lu, single page %lu\n", buf += sprintf(buf,
"Pending writes: LRU %lu, flush list %lu, single page %lu\n",
buf_pool->n_flush[BUF_FLUSH_LRU], buf_pool->n_flush[BUF_FLUSH_LRU],
buf_pool->n_flush[BUF_FLUSH_LIST], buf_pool->n_flush[BUF_FLUSH_LIST],
buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]); buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
...@@ -1829,10 +1840,10 @@ buf_print_io(void) ...@@ -1829,10 +1840,10 @@ buf_print_io(void)
buf_pool->last_printout_time = current_time; buf_pool->last_printout_time = current_time;
printf("Pages read %lu, created %lu, written %lu\n", buf += sprintf(buf, "Pages read %lu, created %lu, written %lu\n",
buf_pool->n_pages_read, buf_pool->n_pages_created, buf_pool->n_pages_read, buf_pool->n_pages_created,
buf_pool->n_pages_written); buf_pool->n_pages_written);
printf("%.2f reads/s, %.2f creates/s, %.2f writes/s\n", buf += sprintf(buf, "%.2f reads/s, %.2f creates/s, %.2f writes/s\n",
(buf_pool->n_pages_read - buf_pool->n_pages_read_old) (buf_pool->n_pages_read - buf_pool->n_pages_read_old)
/ time_elapsed, / time_elapsed,
(buf_pool->n_pages_created - buf_pool->n_pages_created_old) (buf_pool->n_pages_created - buf_pool->n_pages_created_old)
...@@ -1841,13 +1852,14 @@ buf_print_io(void) ...@@ -1841,13 +1852,14 @@ buf_print_io(void)
/ time_elapsed); / time_elapsed);
if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) { if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) {
printf("Buffer pool hit rate %lu / 1000\n", buf += sprintf(buf, "Buffer pool hit rate %lu / 1000\n",
1000 1000
- ((1000 * - ((1000 *
(buf_pool->n_pages_read - buf_pool->n_pages_read_old)) (buf_pool->n_pages_read - buf_pool->n_pages_read_old))
/ (buf_pool->n_page_gets - buf_pool->n_page_gets_old))); / (buf_pool->n_page_gets - buf_pool->n_page_gets_old)));
} else { } else {
printf("No buffer pool activity since the last printout\n"); buf += sprintf(buf,
"No buffer pool activity since the last printout\n");
} }
buf_pool->n_page_gets_old = buf_pool->n_page_gets; buf_pool->n_page_gets_old = buf_pool->n_page_gets;
......
...@@ -194,7 +194,7 @@ ha_delete( ...@@ -194,7 +194,7 @@ ha_delete(
node = ha_search_with_data(table, fold, data); node = ha_search_with_data(table, fold, data);
ut_ad(node); ut_a(node);
ha_delete_hash_node(table, node); ha_delete_hash_node(table, node);
} }
...@@ -232,6 +232,16 @@ ha_remove_all_nodes_to_page( ...@@ -232,6 +232,16 @@ ha_remove_all_nodes_to_page(
node = ha_chain_get_next(table, node); node = ha_chain_get_next(table, node);
} }
} }
/* Check that all nodes really got deleted */
node = ha_chain_get_first(table, fold);
while (node) {
ut_a(buf_frame_align(ha_node_get_data(node)) != page);
node = ha_chain_get_next(table, node);
}
} }
/***************************************************************** /*****************************************************************
...@@ -245,6 +255,7 @@ ha_validate( ...@@ -245,6 +255,7 @@ ha_validate(
{ {
hash_cell_t* cell; hash_cell_t* cell;
ha_node_t* node; ha_node_t* node;
ibool ok = TRUE;
ulint i; ulint i;
for (i = 0; i < hash_get_n_cells(table); i++) { for (i = 0; i < hash_get_n_cells(table); i++) {
...@@ -254,13 +265,21 @@ ha_validate( ...@@ -254,13 +265,21 @@ ha_validate(
node = cell->node; node = cell->node;
while (node) { while (node) {
ut_a(hash_calc_hash(node->fold, table) == i); if (hash_calc_hash(node->fold, table) != i) {
ut_print_timestamp(stderr);
fprintf(stderr,
"InnoDB: Error: hash table node fold value %lu does not\n"
"InnoDB: match with the cell number %lu.\n",
node->fold, i);
ok = FALSE;
}
node = node->next; node = node->next;
} }
} }
return(TRUE); return(ok);
} }
/***************************************************************** /*****************************************************************
...@@ -269,16 +288,22 @@ Prints info of a hash table. */ ...@@ -269,16 +288,22 @@ Prints info of a hash table. */
void void
ha_print_info( ha_print_info(
/*==========*/ /*==========*/
char* buf, /* in/out: buffer where to print */
char* buf_end,/* in: buffer end */
hash_table_t* table) /* in: hash table */ hash_table_t* table) /* in: hash table */
{ {
hash_cell_t* cell; hash_cell_t* cell;
ha_node_t* node; /* ha_node_t* node; */
ulint nodes = 0; ulint nodes = 0;
ulint cells = 0; ulint cells = 0;
ulint len = 0; ulint len = 0;
ulint max_len = 0; ulint max_len = 0;
ulint i; ulint i;
if (buf_end - buf < 200) {
return;
}
for (i = 0; i < hash_get_n_cells(table); i++) { for (i = 0; i < hash_get_n_cells(table); i++) {
cell = hash_get_nth_cell(table, i); cell = hash_get_nth_cell(table, i);
...@@ -286,7 +311,7 @@ ha_print_info( ...@@ -286,7 +311,7 @@ ha_print_info(
if (cell->node) { if (cell->node) {
cells++; cells++;
/*
len = 0; len = 0;
node = cell->node; node = cell->node;
...@@ -306,12 +331,10 @@ ha_print_info( ...@@ -306,12 +331,10 @@ ha_print_info(
if (len > max_len) { if (len > max_len) {
max_len = len; max_len = len;
} }
*/
} }
} }
printf("Hash table size %lu, used cells %lu, nodes %lu\n", buf += sprintf(buf, "Hash table size %lu, used cells %lu\n",
hash_get_n_cells(table), cells, nodes); hash_get_n_cells(table), cells);
printf("max chain length %lu\n", max_len);
ut_a(ha_validate(table));
} }
...@@ -2703,22 +2703,30 @@ ibuf_validate_low(void) ...@@ -2703,22 +2703,30 @@ ibuf_validate_low(void)
Prints info of ibuf. */ Prints info of ibuf. */
void void
ibuf_print(void) ibuf_print(
/*============*/ /*=======*/
char* buf, /* in/out: buffer where to print */
char* buf_end)/* in: buffer end */
{ {
ibuf_data_t* data; ibuf_data_t* data;
#ifdef UNIV_IBUF_DEBUG #ifdef UNIV_IBUF_DEBUG
ulint i; ulint i;
#endif #endif
if (buf_end - buf < 500) {
return;
}
mutex_enter(&ibuf_mutex); mutex_enter(&ibuf_mutex);
data = UT_LIST_GET_FIRST(ibuf->data_list); data = UT_LIST_GET_FIRST(ibuf->data_list);
while (data) { while (data) {
printf( buf += sprintf(buf,
"Ibuf for space %lu: size %lu, free list len %lu, seg size %lu,\n", "Ibuf for space %lu: size %lu, free list len %lu, seg size %lu,\n",
data->space, data->size, data->free_list_len, data->seg_size); data->space, data->size, data->free_list_len, data->seg_size);
printf("%lu inserts, %lu merged recs, %lu merges\n",
buf += sprintf(buf,
"%lu inserts, %lu merged recs, %lu merges\n",
data->n_inserts, data->n_merged_recs, data->n_merges); data->n_inserts, data->n_merged_recs, data->n_merges);
#ifdef UNIV_IBUF_DEBUG #ifdef UNIV_IBUF_DEBUG
for (i = 0; i < IBUF_COUNT_N_PAGES; i++) { for (i = 0; i < IBUF_COUNT_N_PAGES; i++) {
......
...@@ -710,6 +710,8 @@ allowed to free an inherited external field. */ ...@@ -710,6 +710,8 @@ allowed to free an inherited external field. */
extern ulint btr_cur_n_non_sea; extern ulint btr_cur_n_non_sea;
extern ulint btr_cur_n_sea; extern ulint btr_cur_n_sea;
extern ulint btr_cur_n_non_sea_old;
extern ulint btr_cur_n_sea_old;
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "btr0cur.ic" #include "btr0cur.ic"
......
...@@ -448,7 +448,7 @@ Prints info of the buffer pool data structure. */ ...@@ -448,7 +448,7 @@ Prints info of the buffer pool data structure. */
void void
buf_print(void); buf_print(void);
/*===========*/ /*============*/
/************************************************************************* /*************************************************************************
Returns the number of pending buf pool ios. */ Returns the number of pending buf pool ios. */
...@@ -459,8 +459,10 @@ buf_get_n_pending_ios(void); ...@@ -459,8 +459,10 @@ buf_get_n_pending_ios(void);
Prints info of the buffer i/o. */ Prints info of the buffer i/o. */
void void
buf_print_io(void); buf_print_io(
/*==============*/ /*=========*/
char* buf, /* in/out: buffer where to print */
char* buf_end);/* in: buffer end */
/************************************************************************* /*************************************************************************
Checks that all file pages in the buffer are in a replaceable state. */ Checks that all file pages in the buffer are in a replaceable state. */
......
...@@ -127,6 +127,8 @@ Prints info of a hash table. */ ...@@ -127,6 +127,8 @@ Prints info of a hash table. */
void void
ha_print_info( ha_print_info(
/*==========*/ /*==========*/
char* buf, /* in/out: buffer where to print */
char* buf_end,/* in: buffer end */
hash_table_t* table); /* in: hash table */ hash_table_t* table); /* in: hash table */
......
...@@ -269,8 +269,10 @@ ibuf_count_get( ...@@ -269,8 +269,10 @@ ibuf_count_get(
Prints info of ibuf. */ Prints info of ibuf. */
void void
ibuf_print(void); ibuf_print(
/*============*/ /*=======*/
char* buf, /* in/out: buffer where to print */
char* buf_end);/* in: buffer end */
#define IBUF_HEADER_PAGE_NO FSP_IBUF_HEADER_PAGE_NO #define IBUF_HEADER_PAGE_NO FSP_IBUF_HEADER_PAGE_NO
#define IBUF_TREE_ROOT_PAGE_NO FSP_IBUF_TREE_ROOT_PAGE_NO #define IBUF_TREE_ROOT_PAGE_NO FSP_IBUF_TREE_ROOT_PAGE_NO
......
...@@ -460,6 +460,8 @@ Prints info of a table lock. */ ...@@ -460,6 +460,8 @@ Prints info of a table lock. */
void void
lock_table_print( lock_table_print(
/*=============*/ /*=============*/
char* buf, /* in/out: buffer where to print, must be at least
500 bytes */
lock_t* lock); /* in: table type lock */ lock_t* lock); /* in: table type lock */
/************************************************************************* /*************************************************************************
Prints info of a record lock. */ Prints info of a record lock. */
...@@ -467,13 +469,17 @@ Prints info of a record lock. */ ...@@ -467,13 +469,17 @@ Prints info of a record lock. */
void void
lock_rec_print( lock_rec_print(
/*===========*/ /*===========*/
char* buf, /* in/out: buffer where to print, must be at least
500 bytes */
lock_t* lock); /* in: record type lock */ lock_t* lock); /* in: record type lock */
/************************************************************************* /*************************************************************************
Prints info of locks for all transactions. */ Prints info of locks for all transactions. */
void void
lock_print_info(void); lock_print_info(
/*=================*/ /*============*/
char* buf, /* in/out: buffer where to print */
char* buf_end);/* in: buffer end */
/************************************************************************* /*************************************************************************
Validates the lock queue on a table. */ Validates the lock queue on a table. */
......
...@@ -493,8 +493,10 @@ log_block_convert_lsn_to_no( ...@@ -493,8 +493,10 @@ log_block_convert_lsn_to_no(
Prints info of the log. */ Prints info of the log. */
void void
log_print(void); log_print(
/*===========*/ /*======*/
char* buf, /* in/out: buffer where to print */
char* buf_end);/* in: buffer end */
extern log_t* log_sys; extern log_t* log_sys;
......
...@@ -403,8 +403,10 @@ os_aio_validate(void); ...@@ -403,8 +403,10 @@ os_aio_validate(void);
Prints info of the aio arrays. */ Prints info of the aio arrays. */
void void
os_aio_print(void); os_aio_print(
/*==============*/ /*=========*/
char* buf, /* in/out: buffer where to print */
char* buf_end);/* in: buffer end */
/************************************************************************** /**************************************************************************
Checks that all slots in the system have been freed, that is, there are Checks that all slots in the system have been freed, that is, there are
no pending io operations. */ no pending io operations. */
......
...@@ -970,8 +970,6 @@ rec_fold( ...@@ -970,8 +970,6 @@ rec_fold(
ut_ad(n_fields <= rec_get_n_fields(rec)); ut_ad(n_fields <= rec_get_n_fields(rec));
ut_ad((n_fields < rec_get_n_fields(rec)) || (n_bytes == 0)); ut_ad((n_fields < rec_get_n_fields(rec)) || (n_bytes == 0));
ut_ad(n_fields + n_bytes > 0); ut_ad(n_fields + n_bytes > 0);
/* Only the page supremum and infimum records have 1 field: */
ut_ad(rec_get_n_fields(rec) > 1);
n_fields_rec = rec_get_n_fields(rec); n_fields_rec = rec_get_n_fields(rec);
......
...@@ -356,6 +356,14 @@ srv_error_monitor_thread( ...@@ -356,6 +356,14 @@ srv_error_monitor_thread(
/* out: a dummy parameter */ /* out: a dummy parameter */
void* arg); /* in: a dummy parameter required by void* arg); /* in: a dummy parameter required by
os_thread_create */ os_thread_create */
/**********************************************************************
Sprintfs to a buffer the output of the InnoDB Monitor. */
void
srv_sprintf_innodb_monitor(
/*=======================*/
char* buf, /* in/out: buffer which must be at least 4 kB */
ulint len); /* in: length of the buffer */
/* Types for the threads existing in the system. Threads of types 4 - 9 /* Types for the threads existing in the system. Threads of types 4 - 9
......
...@@ -114,6 +114,8 @@ Prints info of the wait array. */ ...@@ -114,6 +114,8 @@ Prints info of the wait array. */
void void
sync_array_print_info( sync_array_print_info(
/*==================*/ /*==================*/
char* buf, /* in/out: buffer where to print */
char* buf_end,/* in: buffer end */
sync_array_t* arr); /* in: wait array */ sync_array_t* arr); /* in: wait array */
......
...@@ -117,14 +117,18 @@ FUNCTION PROTOTYPES FOR DEBUGGING */ ...@@ -117,14 +117,18 @@ FUNCTION PROTOTYPES FOR DEBUGGING */
Prints wait info of the sync system. */ Prints wait info of the sync system. */
void void
sync_print_wait_info(void); sync_print_wait_info(
/*======================*/ /*=================*/
char* buf, /* in/out: buffer where to print */
char* buf_end); /* in: buffer end */
/*********************************************************************** /***********************************************************************
Prints info of the sync system. */ Prints info of the sync system. */
void void
sync_print(void); sync_print(
/*============*/ /*=======*/
char* buf, /* in/out: buffer where to print */
char* buf_end); /* in: buffer end */
/********************************************************************** /**********************************************************************
Checks that the mutex has been initialized. */ Checks that the mutex has been initialized. */
......
...@@ -261,6 +261,8 @@ own the kernel mutex. */ ...@@ -261,6 +261,8 @@ own the kernel mutex. */
void void
trx_print( trx_print(
/*======*/ /*======*/
char* buf, /* in/out: buffer where to print, must be at least
500 bytes */
trx_t* trx); /* in: transaction */ trx_t* trx); /* in: transaction */
......
...@@ -3326,34 +3326,37 @@ Prints info of a table lock. */ ...@@ -3326,34 +3326,37 @@ Prints info of a table lock. */
void void
lock_table_print( lock_table_print(
/*=============*/ /*=============*/
char* buf, /* in/out: buffer where to print, must be at least
500 bytes */
lock_t* lock) /* in: table type lock */ lock_t* lock) /* in: table type lock */
{ {
ut_ad(mutex_own(&kernel_mutex)); ut_ad(mutex_own(&kernel_mutex));
ut_a(lock_get_type(lock) == LOCK_TABLE); ut_a(lock_get_type(lock) == LOCK_TABLE);
printf("TABLE LOCK table %s trx id %lu %lu", buf += sprintf(buf, "TABLE LOCK table %s trx id %lu %lu",
lock->un_member.tab_lock.table->name, lock->un_member.tab_lock.table->name,
(lock->trx)->id.high, (lock->trx)->id.low); (lock->trx)->id.high, (lock->trx)->id.low);
if (lock_get_mode(lock) == LOCK_S) { if (lock_get_mode(lock) == LOCK_S) {
printf(" lock mode S"); buf += sprintf(buf, " lock mode S");
} else if (lock_get_mode(lock) == LOCK_X) { } else if (lock_get_mode(lock) == LOCK_X) {
printf(" lock_mode X"); buf += sprintf(buf, " lock_mode X");
} else if (lock_get_mode(lock) == LOCK_IS) { } else if (lock_get_mode(lock) == LOCK_IS) {
printf(" lock_mode IS"); buf += sprintf(buf, " lock_mode IS");
} else if (lock_get_mode(lock) == LOCK_IX) { } else if (lock_get_mode(lock) == LOCK_IX) {
printf(" lock_mode IX"); buf += sprintf(buf, " lock_mode IX");
} else if (lock_get_mode(lock) == LOCK_AUTO_INC) { } else if (lock_get_mode(lock) == LOCK_AUTO_INC) {
printf(" lock_mode AUTO-INC"); buf += sprintf(buf, " lock_mode AUTO-INC");
} else { } else {
printf(" unknown lock_mode %lu", lock_get_mode(lock)); buf += sprintf(buf,
" unknown lock_mode %lu", lock_get_mode(lock));
} }
if (lock_get_wait(lock)) { if (lock_get_wait(lock)) {
printf(" waiting"); buf += sprintf(buf, " waiting");
} }
printf("\n"); buf += sprintf(buf, "\n");
} }
/************************************************************************* /*************************************************************************
...@@ -3362,6 +3365,8 @@ Prints info of a record lock. */ ...@@ -3362,6 +3365,8 @@ Prints info of a record lock. */
void void
lock_rec_print( lock_rec_print(
/*===========*/ /*===========*/
char* buf, /* in/out: buffer where to print, must be at least
500 bytes */
lock_t* lock) /* in: record type lock */ lock_t* lock) /* in: record type lock */
{ {
page_t* page; page_t* page;
...@@ -3369,8 +3374,7 @@ lock_rec_print( ...@@ -3369,8 +3374,7 @@ lock_rec_print(
ulint page_no; ulint page_no;
ulint i; ulint i;
ulint count = 0; ulint count = 0;
ulint len; char* buf_start = buf;
char buf[200];
mtr_t mtr; mtr_t mtr;
ut_ad(mutex_own(&kernel_mutex)); ut_ad(mutex_own(&kernel_mutex));
...@@ -3379,32 +3383,32 @@ lock_rec_print( ...@@ -3379,32 +3383,32 @@ lock_rec_print(
space = lock->un_member.rec_lock.space; space = lock->un_member.rec_lock.space;
page_no = lock->un_member.rec_lock.page_no; page_no = lock->un_member.rec_lock.page_no;
printf("RECORD LOCKS space id %lu page no %lu n bits %lu", buf += sprintf(buf, "RECORD LOCKS space id %lu page no %lu n bits %lu",
space, page_no, lock_rec_get_n_bits(lock)); space, page_no, lock_rec_get_n_bits(lock));
printf(" table %s index %s trx id %lu %lu", buf += sprintf(buf, " table %s index %s trx id %lu %lu",
lock->index->table->name, lock->index->name, lock->index->table->name, lock->index->name,
(lock->trx)->id.high, (lock->trx)->id.low); (lock->trx)->id.high, (lock->trx)->id.low);
if (lock_get_mode(lock) == LOCK_S) { if (lock_get_mode(lock) == LOCK_S) {
printf(" lock mode S"); buf += sprintf(buf, " lock mode S");
} else if (lock_get_mode(lock) == LOCK_X) { } else if (lock_get_mode(lock) == LOCK_X) {
printf(" lock_mode X"); buf += sprintf(buf, " lock_mode X");
} else { } else {
ut_error; ut_error;
} }
if (lock_rec_get_gap(lock)) { if (lock_rec_get_gap(lock)) {
printf(" gap type lock"); buf += sprintf(buf, " gap type lock");
} }
if (lock_get_wait(lock)) { if (lock_get_wait(lock)) {
printf(" waiting"); buf += sprintf(buf, " waiting");
} }
mtr_start(&mtr); mtr_start(&mtr);
printf("\n"); buf += sprintf(buf, "\n");
/* If the page is not in the buffer pool, we cannot load it /* If the page is not in the buffer pool, we cannot load it
because we have the kernel mutex and ibuf operations would because we have the kernel mutex and ibuf operations would
...@@ -3423,28 +3427,28 @@ lock_rec_print( ...@@ -3423,28 +3427,28 @@ lock_rec_print(
for (i = 0; i < lock_rec_get_n_bits(lock); i++) { for (i = 0; i < lock_rec_get_n_bits(lock); i++) {
if (buf - buf_start > 300) {
buf += sprintf(buf,
"Suppressing further record lock prints for this page\n");
return;
}
if (lock_rec_get_nth_bit(lock, i)) { if (lock_rec_get_nth_bit(lock, i)) {
printf("Record lock, heap no %lu ", i); buf += sprintf(buf, "Record lock, heap no %lu ", i);
if (page) { if (page) {
len = rec_sprintf(buf, 190, buf += rec_sprintf(buf, 120,
page_find_rec_with_heap_no(page, i)); page_find_rec_with_heap_no(page, i));
buf[len] = '\0'; *buf = '\0';
printf("%s", buf);
} }
printf("\n"); buf += sprintf(buf, "\n");
count++; count++;
} }
if (count >= 3) {
printf(
"3 LOCKS PRINTED FOR THIS TRX AND PAGE: SUPPRESSING FURTHER PRINTS\n");
goto end_prints;
}
} }
end_prints:
mtr_commit(&mtr); mtr_commit(&mtr);
} }
...@@ -3479,8 +3483,10 @@ lock_get_n_rec_locks(void) ...@@ -3479,8 +3483,10 @@ lock_get_n_rec_locks(void)
Prints info of locks for all transactions. */ Prints info of locks for all transactions. */
void void
lock_print_info(void) lock_print_info(
/*=================*/ /*============*/
char* buf, /* in/out: buffer where to print */
char* buf_end)/* in: buffer end */
{ {
lock_t* lock; lock_t* lock;
trx_t* trx; trx_t* trx;
...@@ -3493,11 +3499,15 @@ lock_print_info(void) ...@@ -3493,11 +3499,15 @@ lock_print_info(void)
ulint i; ulint i;
mtr_t mtr; mtr_t mtr;
printf("Trx id counter %lu %lu\n", if (buf_end - buf < 600) {
return;
}
buf += sprintf(buf, "Trx id counter %lu %lu\n",
ut_dulint_get_high(trx_sys->max_trx_id), ut_dulint_get_high(trx_sys->max_trx_id),
ut_dulint_get_low(trx_sys->max_trx_id)); ut_dulint_get_low(trx_sys->max_trx_id));
printf( buf += sprintf(buf,
"Purge done for trx's n:o < %lu %lu undo n:o < %lu %lu\n", "Purge done for trx's n:o < %lu %lu undo n:o < %lu %lu\n",
ut_dulint_get_high(purge_sys->purge_trx_no), ut_dulint_get_high(purge_sys->purge_trx_no),
ut_dulint_get_low(purge_sys->purge_trx_no), ut_dulint_get_low(purge_sys->purge_trx_no),
...@@ -3506,7 +3516,8 @@ lock_print_info(void) ...@@ -3506,7 +3516,8 @@ lock_print_info(void)
lock_mutex_enter_kernel(); lock_mutex_enter_kernel();
printf("Total number of lock structs in row lock hash table %lu\n", buf += sprintf(buf,
"Total number of lock structs in row lock hash table %lu\n",
lock_get_n_rec_locks()); lock_get_n_rec_locks());
/* First print info on non-active transactions */ /* First print info on non-active transactions */
...@@ -3514,9 +3525,15 @@ lock_print_info(void) ...@@ -3514,9 +3525,15 @@ lock_print_info(void)
trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list); trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list);
while (trx) { while (trx) {
if (buf_end - buf < 600) {
return;
}
if (trx->conc_state == TRX_NOT_STARTED) { if (trx->conc_state == TRX_NOT_STARTED) {
printf("---"); buf += sprintf(buf, "---");
trx_print(trx); trx_print(buf, trx);
buf += strlen(buf);
} }
trx = UT_LIST_GET_NEXT(mysql_trx_list, trx); trx = UT_LIST_GET_NEXT(mysql_trx_list, trx);
...@@ -3545,12 +3562,22 @@ loop: ...@@ -3545,12 +3562,22 @@ loop:
return; return;
} }
if (buf_end - buf < 600) {
return;
}
if (nth_lock == 0) { if (nth_lock == 0) {
printf("---"); buf += sprintf(buf, "---");
trx_print(trx); trx_print(buf, trx);
buf += strlen(buf);
if (buf_end - buf < 500) {
return;
}
if (trx->read_view) { if (trx->read_view) {
printf( buf += sprintf(buf,
"Trx read view will not see trx with id >= %lu %lu, sees < %lu %lu\n", "Trx read view will not see trx with id >= %lu %lu, sees < %lu %lu\n",
ut_dulint_get_high(trx->read_view->low_limit_id), ut_dulint_get_high(trx->read_view->low_limit_id),
ut_dulint_get_low(trx->read_view->low_limit_id), ut_dulint_get_low(trx->read_view->low_limit_id),
...@@ -3559,16 +3586,17 @@ loop: ...@@ -3559,16 +3586,17 @@ loop:
} }
if (trx->que_state == TRX_QUE_LOCK_WAIT) { if (trx->que_state == TRX_QUE_LOCK_WAIT) {
printf( buf += sprintf(buf,
"------------------TRX IS WAITING FOR THE LOCK:\n"); "------------------TRX IS WAITING FOR THE LOCK:\n");
if (lock_get_type(trx->wait_lock) == LOCK_REC) { if (lock_get_type(trx->wait_lock) == LOCK_REC) {
lock_rec_print(trx->wait_lock); lock_rec_print(buf, trx->wait_lock);
} else { } else {
lock_table_print(trx->wait_lock); lock_table_print(buf, trx->wait_lock);
} }
printf( buf += strlen(buf);
buf += sprintf(buf,
"------------------\n"); "------------------\n");
} }
} }
...@@ -3597,6 +3625,10 @@ loop: ...@@ -3597,6 +3625,10 @@ loop:
goto loop; goto loop;
} }
if (buf_end - buf < 500) {
return;
}
if (lock_get_type(lock) == LOCK_REC) { if (lock_get_type(lock) == LOCK_REC) {
space = lock->un_member.rec_lock.space; space = lock->un_member.rec_lock.space;
page_no = lock->un_member.rec_lock.page_no; page_no = lock->un_member.rec_lock.page_no;
...@@ -3617,19 +3649,21 @@ loop: ...@@ -3617,19 +3649,21 @@ loop:
goto loop; goto loop;
} }
lock_rec_print(lock); lock_rec_print(buf, lock);
} else { } else {
ut_ad(lock_get_type(lock) == LOCK_TABLE); ut_ad(lock_get_type(lock) == LOCK_TABLE);
lock_table_print(lock); lock_table_print(buf, lock);
} }
buf += strlen(buf);
load_page_first = TRUE; load_page_first = TRUE;
nth_lock++; nth_lock++;
if (nth_lock >= 10) { if (nth_lock >= 10) {
printf( buf += sprintf(buf,
"10 LOCKS PRINTED FOR THIS TRX: SUPPRESSING FURTHER PRINTS\n"); "10 LOCKS PRINTED FOR THIS TRX: SUPPRESSING FURTHER PRINTS\n");
nth_trx++; nth_trx++;
......
...@@ -3081,15 +3081,22 @@ log_check_log_recs( ...@@ -3081,15 +3081,22 @@ log_check_log_recs(
Prints info of the log. */ Prints info of the log. */
void void
log_print(void) log_print(
/*===========*/ /*======*/
char* buf, /* in/out: buffer where to print */
char* buf_end)/* in: buffer end */
{ {
double time_elapsed; double time_elapsed;
time_t current_time; time_t current_time;
if (buf_end - buf < 300) {
return;
}
mutex_enter(&(log_sys->mutex)); mutex_enter(&(log_sys->mutex));
printf("Log sequence number %lu %lu\n" buf += sprintf(buf, "Log sequence number %lu %lu\n"
"Log flushed up to %lu %lu\n" "Log flushed up to %lu %lu\n"
"Last checkpoint at %lu %lu\n", "Last checkpoint at %lu %lu\n",
ut_dulint_get_high(log_sys->lsn), ut_dulint_get_high(log_sys->lsn),
...@@ -3103,7 +3110,7 @@ log_print(void) ...@@ -3103,7 +3110,7 @@ log_print(void)
time_elapsed = difftime(current_time, log_sys->last_printout_time); time_elapsed = difftime(current_time, log_sys->last_printout_time);
printf( buf += sprintf(buf,
"%lu pending log writes, %lu pending chkp writes\n" "%lu pending log writes, %lu pending chkp writes\n"
"%lu log i/o's done, %.2f log i/o's/second\n", "%lu log i/o's done, %.2f log i/o's/second\n",
log_sys->n_pending_writes, log_sys->n_pending_writes,
......
...@@ -1094,7 +1094,9 @@ os_file_write( ...@@ -1094,7 +1094,9 @@ os_file_write(
fprintf(stderr, fprintf(stderr,
" InnoDB: Error: File pointer positioning to file %s failed at\n" " InnoDB: Error: File pointer positioning to file %s failed at\n"
"InnoDB: offset %lu %lu. Operating system error number %lu.\n", "InnoDB: offset %lu %lu. Operating system error number %lu.\n"
"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n"
"InnoDB: what the error number means.\n",
name, offset_high, offset, name, offset_high, offset,
(ulint)GetLastError()); (ulint)GetLastError());
...@@ -1125,8 +1127,10 @@ os_file_write( ...@@ -1125,8 +1127,10 @@ os_file_write(
" InnoDB: Error: Write to file %s failed at offset %lu %lu.\n" " InnoDB: Error: Write to file %s failed at offset %lu %lu.\n"
"InnoDB: %lu bytes should have been written, only %lu were written.\n" "InnoDB: %lu bytes should have been written, only %lu were written.\n"
"InnoDB: Operating system error number %lu.\n" "InnoDB: Operating system error number %lu.\n"
"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n"
"InnoDB: what the error number means.\n"
"InnoDB: Check that your OS and file system support files of this size.\n" "InnoDB: Check that your OS and file system support files of this size.\n"
"InnoDB: Check also the disk is not full or a disk quota exceeded.\n", "InnoDB: Check also that the disk is not full or a disk quota exceeded.\n",
name, offset_high, offset, n, len, name, offset_high, offset, n, len,
(ulint)GetLastError()); (ulint)GetLastError());
...@@ -1152,8 +1156,10 @@ os_file_write( ...@@ -1152,8 +1156,10 @@ os_file_write(
" InnoDB: Error: Write to file %s failed at offset %lu %lu.\n" " InnoDB: Error: Write to file %s failed at offset %lu %lu.\n"
"InnoDB: %lu bytes should have been written, only %lu were written.\n" "InnoDB: %lu bytes should have been written, only %lu were written.\n"
"InnoDB: Operating system error number %lu.\n" "InnoDB: Operating system error number %lu.\n"
"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n"
"InnoDB: what the error number means or use the perror program of MySQL.\n"
"InnoDB: Check that your OS and file system support files of this size.\n" "InnoDB: Check that your OS and file system support files of this size.\n"
"InnoDB: Check also the disk is not full or a disk quota exceeded.\n", "InnoDB: Check also that the disk is not full or a disk quota exceeded.\n",
name, offset_high, offset, n, (ulint)ret, name, offset_high, offset, n, (ulint)ret,
(ulint)errno); (ulint)errno);
os_has_said_disk_full = TRUE; os_has_said_disk_full = TRUE;
...@@ -1744,7 +1750,6 @@ os_aio( ...@@ -1744,7 +1750,6 @@ os_aio(
ut_ad(buf); ut_ad(buf);
ut_ad(n > 0); ut_ad(n > 0);
ut_ad(n % OS_FILE_LOG_BLOCK_SIZE == 0); ut_ad(n % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_ad((ulint)buf % OS_FILE_LOG_BLOCK_SIZE == 0)
ut_ad(offset % OS_FILE_LOG_BLOCK_SIZE == 0); ut_ad(offset % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_ad(os_aio_validate()); ut_ad(os_aio_validate());
...@@ -2388,8 +2393,10 @@ os_aio_validate(void) ...@@ -2388,8 +2393,10 @@ os_aio_validate(void)
Prints info of the aio arrays. */ Prints info of the aio arrays. */
void void
os_aio_print(void) os_aio_print(
/*==============*/ /*=========*/
char* buf, /* in/out: buffer where to print */
char* buf_end)/* in: buffer end */
{ {
os_aio_array_t* array; os_aio_array_t* array;
os_aio_slot_t* slot; os_aio_slot_t* slot;
...@@ -2399,12 +2406,17 @@ os_aio_print(void) ...@@ -2399,12 +2406,17 @@ os_aio_print(void)
double avg_bytes_read; double avg_bytes_read;
ulint i; ulint i;
if (buf_end - buf < 1000) {
return;
}
for (i = 0; i < srv_n_file_io_threads; i++) { for (i = 0; i < srv_n_file_io_threads; i++) {
printf("I/O thread %lu state: %s\n", i, buf += sprintf(buf, "I/O thread %lu state: %s\n", i,
srv_io_thread_op_info[i]); srv_io_thread_op_info[i]);
} }
printf("Pending normal aio reads:"); buf += sprintf(buf, "Pending normal aio reads:");
array = os_aio_read_array; array = os_aio_read_array;
loop: loop:
...@@ -2431,12 +2443,12 @@ loop: ...@@ -2431,12 +2443,12 @@ loop:
ut_a(array->n_reserved == n_reserved); ut_a(array->n_reserved == n_reserved);
printf(" %lu", n_reserved); buf += sprintf(buf, " %lu", n_reserved);
os_mutex_exit(array->mutex); os_mutex_exit(array->mutex);
if (array == os_aio_read_array) { if (array == os_aio_read_array) {
printf(", aio writes:"); buf += sprintf(buf, ", aio writes:");
array = os_aio_write_array; array = os_aio_write_array;
...@@ -2444,34 +2456,36 @@ loop: ...@@ -2444,34 +2456,36 @@ loop:
} }
if (array == os_aio_write_array) { if (array == os_aio_write_array) {
printf(",\n ibuf aio reads:"); buf += sprintf(buf, ",\n ibuf aio reads:");
array = os_aio_ibuf_array; array = os_aio_ibuf_array;
goto loop; goto loop;
} }
if (array == os_aio_ibuf_array) { if (array == os_aio_ibuf_array) {
printf(", log i/o's:"); buf += sprintf(buf, ", log i/o's:");
array = os_aio_log_array; array = os_aio_log_array;
goto loop; goto loop;
} }
if (array == os_aio_log_array) { if (array == os_aio_log_array) {
printf(", sync i/o's:"); buf += sprintf(buf, ", sync i/o's:");
array = os_aio_sync_array; array = os_aio_sync_array;
goto loop; goto loop;
} }
printf("\n"); buf += sprintf(buf, "\n");
current_time = time(NULL); current_time = time(NULL);
time_elapsed = difftime(current_time, os_last_printout); time_elapsed = difftime(current_time, os_last_printout);
printf("Pending flushes (fsync) log: %lu; buffer pool: %lu\n", buf += sprintf(buf,
"Pending flushes (fsync) log: %lu; buffer pool: %lu\n",
fil_n_pending_log_flushes, fil_n_pending_tablespace_flushes); fil_n_pending_log_flushes, fil_n_pending_tablespace_flushes);
printf("%lu OS file reads, %lu OS file writes, %lu OS fsyncs\n", buf += sprintf(buf,
"%lu OS file reads, %lu OS file writes, %lu OS fsyncs\n",
os_n_file_reads, os_n_file_writes, os_n_fsyncs); os_n_file_reads, os_n_file_writes, os_n_fsyncs);
if (os_n_file_reads == os_n_file_reads_old) { if (os_n_file_reads == os_n_file_reads_old) {
...@@ -2481,7 +2495,7 @@ loop: ...@@ -2481,7 +2495,7 @@ loop:
(os_n_file_reads - os_n_file_reads_old); (os_n_file_reads - os_n_file_reads_old);
} }
printf( buf += sprintf(buf,
"%.2f reads/s, %lu avg bytes/read, %.2f writes/s, %.2f fsyncs/s\n", "%.2f reads/s, %lu avg bytes/read, %.2f writes/s, %.2f fsyncs/s\n",
(os_n_file_reads - os_n_file_reads_old) (os_n_file_reads - os_n_file_reads_old)
/ time_elapsed, / time_elapsed,
......
...@@ -2416,6 +2416,14 @@ row_check_table_for_mysql( ...@@ -2416,6 +2416,14 @@ row_check_table_for_mysql(
index = dict_table_get_next_index(index); index = dict_table_get_next_index(index);
} }
/* We validate also the whole adaptive hash index for all tables
at every CHECK TABLE */
if (!btr_search_validate()) {
ret = DB_ERROR;
}
prebuilt->trx->op_info = ""; prebuilt->trx->op_info = "";
return(ret); return(ret);
......
...@@ -437,11 +437,12 @@ row_undo_mod_del_unmark_sec( ...@@ -437,11 +437,12 @@ row_undo_mod_del_unmark_sec(
rec_sprintf(err_buf, 900, btr_pcur_get_rec(&pcur)); rec_sprintf(err_buf, 900, btr_pcur_get_rec(&pcur));
fprintf(stderr, "InnoDB: record %s\n", err_buf); fprintf(stderr, "InnoDB: record %s\n", err_buf);
trx_print(err_buf, thr_get_trx(thr));
fprintf(stderr, fprintf(stderr,
"InnoDB: Make a detailed bug report and send it\n"); "%s\nInnoDB: Make a detailed bug report and send it\n",
err_buf);
fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n");
trx_print(thr_get_trx(thr));
} else { } else {
btr_cur = btr_pcur_get_btr_cur(&pcur); btr_cur = btr_pcur_get_btr_cur(&pcur);
......
...@@ -1095,11 +1095,12 @@ row_upd_sec_index_entry( ...@@ -1095,11 +1095,12 @@ row_upd_sec_index_entry(
rec_sprintf(err_buf, 900, rec); rec_sprintf(err_buf, 900, rec);
fprintf(stderr, "InnoDB: record %s\n", err_buf); fprintf(stderr, "InnoDB: record %s\n", err_buf);
trx_print(err_buf, thr_get_trx(thr));
fprintf(stderr, fprintf(stderr,
"InnoDB: Make a detailed bug report and send it\n"); "%s\nInnoDB: Make a detailed bug report and send it\n",
err_buf);
fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n");
trx_print(thr_get_trx(thr));
} else { } else {
/* Delete mark the old index record; it can already be /* Delete mark the old index record; it can already be
delete marked if we return after a lock wait in delete marked if we return after a lock wait in
......
...@@ -272,6 +272,8 @@ i/o handler thread */ ...@@ -272,6 +272,8 @@ i/o handler thread */
char* srv_io_thread_op_info[SRV_MAX_N_IO_THREADS]; char* srv_io_thread_op_info[SRV_MAX_N_IO_THREADS];
time_t srv_last_monitor_time;
/* /*
IMPLEMENTATION OF THE SERVER MAIN PROGRAM IMPLEMENTATION OF THE SERVER MAIN PROGRAM
========================================= =========================================
...@@ -2131,106 +2133,106 @@ srv_release_mysql_thread_if_suspended( ...@@ -2131,106 +2133,106 @@ srv_release_mysql_thread_if_suspended(
/* not found */ /* not found */
} }
/************************************************************************* /**********************************************************************
A thread which wakes up threads whose lock wait may have lasted too long. Sprintfs to a buffer the output of the InnoDB Monitor. */
This also prints the info output by various InnoDB monitors. */
#ifndef __WIN__ void
void* srv_sprintf_innodb_monitor(
#else /*=======================*/
ulint char* buf, /* in/out: buffer which must be at least 4 kB */
#endif ulint len) /* in: length of the buffer */
srv_lock_timeout_and_monitor_thread(
/*================================*/
/* out: a dummy parameter */
void* arg) /* in: a dummy parameter required by
os_thread_create */
{ {
srv_slot_t* slot; char* buf_end = buf + len - 2000;
double time_elapsed; double time_elapsed;
time_t current_time; time_t current_time;
time_t last_monitor_time;
time_t last_table_monitor_time;
ibool some_waits;
double wait_time;
ulint i;
UT_NOT_USED(arg);
last_monitor_time = time(NULL);
last_table_monitor_time = time(NULL);
loop:
srv_lock_timeout_and_monitor_active = TRUE;
/* 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); current_time = time(NULL);
time_elapsed = difftime(current_time, last_monitor_time); time_elapsed = difftime(current_time, srv_last_monitor_time);
if (time_elapsed > 15) { srv_last_monitor_time = time(NULL);
if (srv_print_innodb_monitor) { ut_a(len >= 4096);
last_monitor_time = time(NULL); buf += sprintf(buf, "\n=====================================\n");
printf("=====================================\n"); ut_sprintf_timestamp(buf);
ut_print_timestamp(stdout); buf = buf + strlen(buf);
printf(" INNODB MONITOR OUTPUT\n" buf += sprintf(buf, " INNODB MONITOR OUTPUT\n"
"=====================================\n"); "=====================================\n");
printf("----------\n"
buf += sprintf(buf,
"Per second values calculated from the last %lu seconds\n",
(ulint)time_elapsed);
buf += sprintf(buf, "----------\n"
"SEMAPHORES\n" "SEMAPHORES\n"
"----------\n"); "----------\n");
sync_print(); sync_print(buf, buf_end);
printf("------------\n"
buf = buf + strlen(buf);
buf += sprintf(buf, "------------\n"
"TRANSACTIONS\n" "TRANSACTIONS\n"
"------------\n"); "------------\n");
lock_print_info(); lock_print_info(buf, buf_end);
printf("--------\n" buf = buf + strlen(buf);
buf += sprintf(buf, "--------\n"
"FILE I/O\n" "FILE I/O\n"
"--------\n"); "--------\n");
os_aio_print(); os_aio_print(buf, buf_end);
printf("-------------------------------------\n" buf = buf + strlen(buf);
buf += sprintf(buf, "-------------------------------------\n"
"INSERT BUFFER AND ADAPTIVE HASH INDEX\n" "INSERT BUFFER AND ADAPTIVE HASH INDEX\n"
"-------------------------------------\n"); "-------------------------------------\n");
ibuf_print(); ibuf_print(buf, buf_end);
printf("Successful hash searches %lu, non-hash searches %lu\n", buf = buf + strlen(buf);
btr_cur_n_sea, btr_cur_n_non_sea);
printf("---\n" ha_print_info(buf, buf_end, btr_search_sys->hash_index);
buf = buf + strlen(buf);
buf += sprintf(buf,
"%.2f hash searches/s, %.2f non-hash searches/s\n",
(btr_cur_n_sea - btr_cur_n_sea_old)
/ time_elapsed,
(btr_cur_n_non_sea - btr_cur_n_non_sea_old)
/ time_elapsed);
btr_cur_n_sea_old = btr_cur_n_sea;
btr_cur_n_non_sea_old = btr_cur_n_non_sea;
buf += sprintf(buf,"---\n"
"LOG\n" "LOG\n"
"---\n"); "---\n");
log_print(); log_print(buf, buf_end);
printf("----------------------\n" buf = buf + strlen(buf);
buf += sprintf(buf, "----------------------\n"
"BUFFER POOL AND MEMORY\n" "BUFFER POOL AND MEMORY\n"
"----------------------\n"); "----------------------\n");
printf( buf += sprintf(buf,
"Total memory allocated %lu; in additional pool allocated %lu\n", "Total memory allocated %lu; in additional pool allocated %lu\n",
ut_total_allocated_memory, ut_total_allocated_memory,
mem_pool_get_reserved(mem_comm_pool)); mem_pool_get_reserved(mem_comm_pool));
buf_print_io(); buf_print_io(buf, buf_end);
printf("--------------\n" buf = buf + strlen(buf);
buf += sprintf(buf, "--------------\n"
"ROW OPERATIONS\n" "ROW OPERATIONS\n"
"--------------\n"); "--------------\n");
printf( buf += sprintf(buf,
"%ld queries inside InnoDB, %ld queries in queue; main thread: %s\n", "%ld queries inside InnoDB, %ld queries in queue; main thread: %s\n",
srv_conc_n_threads, srv_conc_n_waiting_threads, srv_conc_n_threads, srv_conc_n_waiting_threads,
srv_main_thread_op_info); srv_main_thread_op_info);
printf( buf += sprintf(buf,
"Number of rows inserted %lu, updated %lu, deleted %lu, read %lu\n", "Number of rows inserted %lu, updated %lu, deleted %lu, read %lu\n",
srv_n_rows_inserted, srv_n_rows_inserted,
srv_n_rows_updated, srv_n_rows_updated,
srv_n_rows_deleted, srv_n_rows_deleted,
srv_n_rows_read); srv_n_rows_read);
printf( buf += sprintf(buf,
"%.2f inserts/s, %.2f updates/s, %.2f deletes/s, %.2f reads/s\n", "%.2f inserts/s, %.2f updates/s, %.2f deletes/s, %.2f reads/s\n",
(srv_n_rows_inserted - srv_n_rows_inserted_old) (srv_n_rows_inserted - srv_n_rows_inserted_old)
/ time_elapsed, / time_elapsed,
...@@ -2246,9 +2248,70 @@ loop: ...@@ -2246,9 +2248,70 @@ loop:
srv_n_rows_deleted_old = srv_n_rows_deleted; srv_n_rows_deleted_old = srv_n_rows_deleted;
srv_n_rows_read_old = srv_n_rows_read; srv_n_rows_read_old = srv_n_rows_read;
printf("----------------------------\n" buf += sprintf(buf, "----------------------------\n"
"END OF INNODB MONITOR OUTPUT\n" "END OF INNODB MONITOR OUTPUT\n"
"============================\n"); "============================\n");
}
/*************************************************************************
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_and_monitor_thread(
/*================================*/
/* out: a dummy parameter */
void* arg) /* in: a dummy parameter required by
os_thread_create */
{
srv_slot_t* slot;
double time_elapsed;
time_t current_time;
time_t last_table_monitor_time;
time_t last_monitor_time;
ibool some_waits;
double wait_time;
char* buf;
ulint i;
UT_NOT_USED(arg);
srv_last_monitor_time = time(NULL);
last_table_monitor_time = time(NULL);
last_monitor_time = time(NULL);
loop:
srv_lock_timeout_and_monitor_active = TRUE;
/* 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) {
buf = mem_alloc(100000);
srv_sprintf_innodb_monitor(buf, 100000);
printf("%s", buf);
mem_free(buf);
} }
if (srv_print_innodb_tablespace_monitor if (srv_print_innodb_tablespace_monitor
...@@ -2380,7 +2443,13 @@ loop: ...@@ -2380,7 +2443,13 @@ loop:
srv_error_monitor_active = TRUE; srv_error_monitor_active = TRUE;
os_thread_sleep(10000000); os_thread_sleep(10000000);
/*
printf("Validating has index\n");
btr_search_validate();
printf("Hash index validated\n");
*/
sync_array_print_long_waits(); sync_array_print_long_waits();
/* Flush stdout and stderr so that a database user gets their output /* Flush stdout and stderr so that a database user gets their output
......
...@@ -896,7 +896,7 @@ test_measure_cont( ...@@ -896,7 +896,7 @@ test_measure_cont(
"Mutex res. l %lu, p %lu, k %lu s x %lu s s %lu s mut %lu of %lu\n", "Mutex res. l %lu, p %lu, k %lu s x %lu s s %lu s mut %lu of %lu\n",
lcount, pcount, kcount, s_xcount, s_scount, s_mcount, j); lcount, pcount, kcount, s_xcount, s_scount, s_mcount, j);
sync_print_wait_info(); /* sync_print_wait_info(); */
fprintf(stderr, fprintf(stderr,
"log i/o %lu n non sea %lu n succ %lu n h fail %lu\n", "log i/o %lu n non sea %lu n succ %lu n h fail %lu\n",
......
...@@ -441,7 +441,8 @@ static ...@@ -441,7 +441,8 @@ static
void void
sync_array_cell_print( sync_array_cell_print(
/*==================*/ /*==================*/
FILE* file, /* in: file where to print */ char* buf, /* in: buffer where to print, must be
at least 400 characters */
sync_cell_t* cell) /* in: sync cell */ sync_cell_t* cell) /* in: sync cell */
{ {
mutex_t* mutex; mutex_t* mutex;
...@@ -451,7 +452,7 @@ sync_array_cell_print( ...@@ -451,7 +452,7 @@ sync_array_cell_print(
type = cell->request_type; type = cell->request_type;
fprintf(file, buf += sprintf(buf,
"--Thread %lu has waited at %s line %lu for %.2f seconds the semaphore:\n", "--Thread %lu has waited at %s line %lu for %.2f seconds the semaphore:\n",
(ulint)cell->thread, cell->file, cell->line, (ulint)cell->thread, cell->file, cell->line,
difftime(time(NULL), cell->reservation_time)); difftime(time(NULL), cell->reservation_time));
...@@ -461,54 +462,58 @@ sync_array_cell_print( ...@@ -461,54 +462,58 @@ sync_array_cell_print(
been freed meanwhile */ been freed meanwhile */
mutex = cell->old_wait_mutex; mutex = cell->old_wait_mutex;
fprintf(file, buf += sprintf(buf,
"Mutex at %lx created file %s line %lu, lock var %lu\n", "Mutex at %lx created file %s line %lu, lock var %lu\n",
(ulint)mutex, mutex->cfile_name, mutex->cline, (ulint)mutex, mutex->cfile_name, mutex->cline,
mutex->lock_word); mutex->lock_word);
fprintf(file, buf += sprintf(buf,
"Last time reserved in file %s line %lu, waiters flag %lu\n", "Last time reserved in file %s line %lu, waiters flag %lu\n",
mutex->file_name, mutex->line, mutex->waiters); mutex->file_name, mutex->line, mutex->waiters);
} else if (type == RW_LOCK_EX || type == RW_LOCK_SHARED) { } else if (type == RW_LOCK_EX || type == RW_LOCK_SHARED) {
if (type == RW_LOCK_EX) { if (type == RW_LOCK_EX) {
fprintf(file, "X-lock on"); buf += sprintf(buf, "X-lock on");
} else { } else {
fprintf(file, "S-lock on"); buf += sprintf(buf, "S-lock on");
} }
rwlock = cell->old_wait_rw_lock; rwlock = cell->old_wait_rw_lock;
fprintf(file, " RW-latch at %lx created in file %s line %lu\n", buf += sprintf(buf,
" RW-latch at %lx created in file %s line %lu\n",
(ulint)rwlock, rwlock->cfile_name, rwlock->cline); (ulint)rwlock, rwlock->cfile_name, rwlock->cline);
if (rwlock->writer != RW_LOCK_NOT_LOCKED) { if (rwlock->writer != RW_LOCK_NOT_LOCKED) {
fprintf(file, buf += sprintf(buf,
"a writer (thread id %lu) has reserved it in mode", "a writer (thread id %lu) has reserved it in mode",
(ulint)rwlock->writer_thread); (ulint)rwlock->writer_thread);
if (rwlock->writer == RW_LOCK_EX) { if (rwlock->writer == RW_LOCK_EX) {
fprintf(file, " exclusive\n"); buf += sprintf(buf, " exclusive\n");
} else { } else {
fprintf(file, " wait exclusive\n"); buf += sprintf(buf, " wait exclusive\n");
} }
} }
fprintf(file, "number of readers %lu, waiters flag %lu\n", buf += sprintf(buf,
"number of readers %lu, waiters flag %lu\n",
rwlock->reader_count, rwlock->waiters); rwlock->reader_count, rwlock->waiters);
fprintf(file, "Last time read locked in file %s line %lu\n", buf += sprintf(buf,
"Last time read locked in file %s line %lu\n",
rwlock->last_s_file_name, rwlock->last_s_line); rwlock->last_s_file_name, rwlock->last_s_line);
fprintf(file, "Last time write locked in file %s line %lu\n", buf += sprintf(buf,
"Last time write locked in file %s line %lu\n",
rwlock->last_x_file_name, rwlock->last_x_line); rwlock->last_x_file_name, rwlock->last_x_line);
} else { } else {
ut_error; ut_error;
} }
if (!cell->waiting) { if (!cell->waiting) {
fprintf(file, "wait has ended\n"); buf += sprintf(buf, "wait has ended\n");
} }
if (cell->event_set) { if (cell->event_set) {
fprintf(file, "wait is ending\n"); buf += sprintf(buf, "wait is ending\n");
} }
} }
...@@ -610,6 +615,7 @@ sync_array_detect_deadlock( ...@@ -610,6 +615,7 @@ sync_array_detect_deadlock(
os_thread_id_t thread; os_thread_id_t thread;
ibool ret; ibool ret;
rw_lock_debug_t* debug; rw_lock_debug_t* debug;
char buf[500];
ut_a(arr && start && cell); ut_a(arr && start && cell);
ut_ad(cell->wait_object); ut_ad(cell->wait_object);
...@@ -642,11 +648,12 @@ sync_array_detect_deadlock( ...@@ -642,11 +648,12 @@ sync_array_detect_deadlock(
ret = sync_array_deadlock_step(arr, start, thread, 0, ret = sync_array_deadlock_step(arr, start, thread, 0,
depth); depth);
if (ret) { if (ret) {
sync_array_cell_print(buf, cell);
printf( printf(
"Mutex %lx owned by thread %lu file %s line %lu\n", "Mutex %lx owned by thread %lu file %s line %lu\n%s",
(ulint)mutex, mutex->thread_id, (ulint)mutex, mutex->thread_id,
mutex->file_name, mutex->line); mutex->file_name, mutex->line,
sync_array_cell_print(stdout, cell); buf);
return(TRUE); return(TRUE);
} }
} }
...@@ -678,9 +685,9 @@ sync_array_detect_deadlock( ...@@ -678,9 +685,9 @@ sync_array_detect_deadlock(
debug->pass, debug->pass,
depth); depth);
if (ret) { if (ret) {
printf("rw-lock %lx ", (ulint) lock); sync_array_cell_print(buf, cell);
printf("rw-lock %lx %s ", (ulint) lock, buf);
rw_lock_debug_print(debug); rw_lock_debug_print(debug);
sync_array_cell_print(stdout, cell);
return(TRUE); return(TRUE);
} }
...@@ -711,9 +718,9 @@ sync_array_detect_deadlock( ...@@ -711,9 +718,9 @@ sync_array_detect_deadlock(
debug->pass, debug->pass,
depth); depth);
if (ret) { if (ret) {
printf("rw-lock %lx ", (ulint) lock); sync_array_cell_print(buf, cell);
printf("rw-lock %lx %s ", (ulint) lock, buf);
rw_lock_debug_print(debug); rw_lock_debug_print(debug);
sync_array_cell_print(stdout, cell);
return(TRUE); return(TRUE);
} }
...@@ -898,6 +905,7 @@ sync_array_print_long_waits(void) ...@@ -898,6 +905,7 @@ sync_array_print_long_waits(void)
sync_cell_t* cell; sync_cell_t* cell;
ibool old_val; ibool old_val;
ibool noticed = FALSE; ibool noticed = FALSE;
char buf[500];
ulint i; ulint i;
for (i = 0; i < sync_primary_wait_array->n_cells; i++) { for (i = 0; i < sync_primary_wait_array->n_cells; i++) {
...@@ -907,9 +915,10 @@ sync_array_print_long_waits(void) ...@@ -907,9 +915,10 @@ sync_array_print_long_waits(void)
if (cell->wait_object != NULL if (cell->wait_object != NULL
&& difftime(time(NULL), cell->reservation_time) > 240) { && difftime(time(NULL), cell->reservation_time) > 240) {
sync_array_cell_print(buf, cell);
fprintf(stderr, fprintf(stderr,
"InnoDB: Warning: a long semaphore wait:\n"); "InnoDB: Warning: a long semaphore wait:\n%s", buf);
sync_array_cell_print(stderr, cell);
noticed = TRUE; noticed = TRUE;
} }
...@@ -948,6 +957,8 @@ static ...@@ -948,6 +957,8 @@ static
void void
sync_array_output_info( sync_array_output_info(
/*===================*/ /*===================*/
char* buf, /* in/out: buffer where to print */
char* buf_end,/* in: buffer end */
sync_array_t* arr) /* in: wait array; NOTE! caller must own the sync_array_t* arr) /* in: wait array; NOTE! caller must own the
mutex */ mutex */
{ {
...@@ -955,18 +966,29 @@ sync_array_output_info( ...@@ -955,18 +966,29 @@ sync_array_output_info(
ulint count; ulint count;
ulint i; ulint i;
printf("OS WAIT ARRAY INFO: reservation count %ld, signal count %ld\n", if (buf_end - buf < 500) {
return;
}
buf += sprintf(buf,
"OS WAIT ARRAY INFO: reservation count %ld, signal count %ld\n",
arr->res_count, arr->sg_count); arr->res_count, arr->sg_count);
i = 0; i = 0;
count = 0; count = 0;
while (count < arr->n_reserved) { while (count < arr->n_reserved) {
if (buf_end - buf < 500) {
return;
}
cell = sync_array_get_nth_cell(arr, i); cell = sync_array_get_nth_cell(arr, i);
if (cell->wait_object != NULL) { if (cell->wait_object != NULL) {
count++; count++;
sync_array_cell_print(stdout, cell); sync_array_cell_print(buf, cell);
buf = buf + strlen(buf);
} }
i++; i++;
...@@ -979,11 +1001,13 @@ Prints info of the wait array. */ ...@@ -979,11 +1001,13 @@ Prints info of the wait array. */
void void
sync_array_print_info( sync_array_print_info(
/*==================*/ /*==================*/
char* buf, /* in/out: buffer where to print */
char* buf_end,/* in: buffer end */
sync_array_t* arr) /* in: wait array */ sync_array_t* arr) /* in: wait array */
{ {
sync_array_enter(arr); sync_array_enter(arr);
sync_array_output_info(arr); sync_array_output_info(buf, buf_end, arr);
sync_array_exit(arr); sync_array_exit(arr);
} }
...@@ -874,6 +874,7 @@ sync_thread_levels_empty_gen( ...@@ -874,6 +874,7 @@ sync_thread_levels_empty_gen(
sync_level_t* slot; sync_level_t* slot;
rw_lock_t* lock; rw_lock_t* lock;
mutex_t* mutex; mutex_t* mutex;
char* buf;
ulint i; ulint i;
if (!sync_order_checks_on) { if (!sync_order_checks_on) {
...@@ -907,7 +908,9 @@ sync_thread_levels_empty_gen( ...@@ -907,7 +908,9 @@ sync_thread_levels_empty_gen(
mutex = slot->latch; mutex = slot->latch;
mutex_exit(&sync_thread_mutex); mutex_exit(&sync_thread_mutex);
sync_print(); buf = mem_alloc(20000);
sync_print(buf, buf + 18000);
ut_error; ut_error;
return(FALSE); return(FALSE);
...@@ -1243,14 +1246,21 @@ sync_close(void) ...@@ -1243,14 +1246,21 @@ sync_close(void)
Prints wait info of the sync system. */ Prints wait info of the sync system. */
void void
sync_print_wait_info(void) sync_print_wait_info(
/*======================*/ /*=================*/
char* buf, /* in/out: buffer where to print */
char* buf_end) /* in: buffer end */
{ {
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
printf("Mutex exits %lu, rws exits %lu, rwx exits %lu\n", printf("Mutex exits %lu, rws exits %lu, rwx exits %lu\n",
mutex_exit_count, rw_s_exit_count, rw_x_exit_count); mutex_exit_count, rw_s_exit_count, rw_x_exit_count);
#endif #endif
printf( if (buf_end - buf < 500) {
return;
}
sprintf(buf,
"Mutex spin waits %lu, rounds %lu, OS waits %lu\n" "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", "RW-shared spins %lu, OS waits %lu; RW-excl spins %lu, OS waits %lu\n",
mutex_spin_wait_count, mutex_spin_round_count, mutex_spin_wait_count, mutex_spin_round_count,
...@@ -1263,11 +1273,18 @@ sync_print_wait_info(void) ...@@ -1263,11 +1273,18 @@ sync_print_wait_info(void)
Prints info of the sync system. */ Prints info of the sync system. */
void void
sync_print(void) sync_print(
/*============*/ /*=======*/
char* buf, /* in/out: buffer where to print */
char* buf_end) /* in: buffer end */
{ {
mutex_list_print_info(); mutex_list_print_info();
rw_lock_list_print_info(); rw_lock_list_print_info();
sync_array_print_info(sync_primary_wait_array);
sync_print_wait_info(); sync_array_print_info(buf, buf_end, sync_primary_wait_array);
buf = buf + strlen(buf);
sync_print_wait_info(buf, buf_end);
} }
...@@ -26,9 +26,11 @@ Created 3/26/1996 Heikki Tuuri ...@@ -26,9 +26,11 @@ Created 3/26/1996 Heikki Tuuri
/* Copy of the prototype for innobase_mysql_print_thd: this /* Copy of the prototype for innobase_mysql_print_thd: this
copy must be equal to the one in mysql/sql/ha_innobase.cc ! */ copy MUST be equal to the one in mysql/sql/ha_innobase.cc ! */
void innobase_mysql_print_thd(void* thd); void innobase_mysql_print_thd(
char* buf,
void* thd);
/* Dummy session used currently in MySQL interface */ /* Dummy session used currently in MySQL interface */
sess_t* trx_dummy_sess = NULL; sess_t* trx_dummy_sess = NULL;
...@@ -1459,54 +1461,63 @@ own the kernel mutex. */ ...@@ -1459,54 +1461,63 @@ own the kernel mutex. */
void void
trx_print( trx_print(
/*======*/ /*======*/
char* buf, /* in/out: buffer where to print, must be at least
500 bytes */
trx_t* trx) /* in: transaction */ trx_t* trx) /* in: transaction */
{ {
printf("TRANSACTION %lu %lu, OS thread id %lu", buf += sprintf(buf, "TRANSACTION %lu %lu, OS thread id %lu",
ut_dulint_get_high(trx->id), ut_dulint_get_high(trx->id),
ut_dulint_get_low(trx->id), ut_dulint_get_low(trx->id),
(ulint)trx->mysql_thread_id); (ulint)trx->mysql_thread_id);
if (ut_strlen(trx->op_info) > 0) { if (ut_strlen(trx->op_info) > 0) {
printf(" %s", trx->op_info); buf += sprintf(buf, " %s", trx->op_info);
} }
if (trx->type != TRX_USER) { if (trx->type != TRX_USER) {
printf(" purge trx"); buf += sprintf(buf, " purge trx");
} }
switch (trx->conc_state) { switch (trx->conc_state) {
case TRX_NOT_STARTED: printf(", not started"); break; case TRX_NOT_STARTED: buf += sprintf(buf,
case TRX_ACTIVE: printf(", active"); break; ", not started"); break;
case TRX_COMMITTED_IN_MEMORY: printf(", committed in memory"); case TRX_ACTIVE: buf += sprintf(buf,
", active"); break;
case TRX_COMMITTED_IN_MEMORY: buf += sprintf(buf,
", committed in memory");
break; break;
default: printf(" state %lu", trx->conc_state); default: buf += sprintf(buf, " state %lu", trx->conc_state);
} }
switch (trx->que_state) { switch (trx->que_state) {
case TRX_QUE_RUNNING: printf(", runs or sleeps"); break; case TRX_QUE_RUNNING: buf += sprintf(buf,
case TRX_QUE_LOCK_WAIT: printf(", lock wait"); break; ", runs or sleeps"); break;
case TRX_QUE_ROLLING_BACK: printf(", rolling back"); break; case TRX_QUE_LOCK_WAIT: buf += sprintf(buf,
case TRX_QUE_COMMITTING: printf(", committing"); break; ", lock wait"); break;
default: printf(" que state %lu", trx->que_state); case TRX_QUE_ROLLING_BACK: buf += sprintf(buf,
", rolling back"); break;
case TRX_QUE_COMMITTING: buf += sprintf(buf,
", committing"); break;
default: buf += sprintf(buf, " que state %lu", trx->que_state);
} }
if (0 < UT_LIST_GET_LEN(trx->trx_locks)) { if (0 < UT_LIST_GET_LEN(trx->trx_locks)) {
printf(", has %lu lock struct(s)", buf += sprintf(buf, ", has %lu lock struct(s)",
UT_LIST_GET_LEN(trx->trx_locks)); UT_LIST_GET_LEN(trx->trx_locks));
} }
if (trx->has_search_latch) { if (trx->has_search_latch) {
printf(", holds adaptive hash latch"); buf += sprintf(buf, ", holds adaptive hash latch");
} }
if (ut_dulint_cmp(trx->undo_no, ut_dulint_zero) != 0) { if (ut_dulint_cmp(trx->undo_no, ut_dulint_zero) != 0) {
printf(", undo log entries %lu", buf += sprintf(buf, ", undo log entries %lu",
ut_dulint_get_low(trx->undo_no)); ut_dulint_get_low(trx->undo_no));
} }
printf("\n"); buf += sprintf(buf, "\n");
if (trx->mysql_thd != NULL) { if (trx->mysql_thd != NULL) {
innobase_mysql_print_thd(trx->mysql_thd); innobase_mysql_print_thd(buf, trx->mysql_thd);
} }
} }
...@@ -269,35 +269,37 @@ the prototype for this function! */ ...@@ -269,35 +269,37 @@ the prototype for this function! */
void void
innobase_mysql_print_thd( innobase_mysql_print_thd(
/*=====================*/ /*=====================*/
char* buf, /* in/out: buffer where to print, must be at least
300 bytes */
void* input_thd)/* in: pointer to a MySQL THD object */ void* input_thd)/* in: pointer to a MySQL THD object */
{ {
THD* thd; THD* thd;
thd = (THD*) input_thd; thd = (THD*) input_thd;
printf("MySQL thread id %lu, query id %lu", buf += sprintf(buf, "MySQL thread id %lu, query id %lu",
thd->thread_id, thd->query_id); thd->thread_id, thd->query_id);
if (thd->host) { if (thd->host) {
printf(" %s", thd->host); buf += sprintf(buf, " %.30s", thd->host);
} }
if (thd->ip) { if (thd->ip) {
printf(" %s", thd->ip); buf += sprintf(buf, " %.20s", thd->ip);
} }
if (thd->user) { if (thd->user) {
printf(" %s", thd->user); buf += sprintf(buf, " %.20s", thd->user);
} }
if (thd->proc_info) { if (thd->proc_info) {
printf(" %s", thd->proc_info); buf += sprintf(buf, " %.50s", thd->proc_info);
} }
if (thd->query) { if (thd->query) {
printf("\n%.100s", thd->query); buf += sprintf(buf, "\n%.150s", thd->query);
} }
printf("\n"); buf += sprintf(buf, "\n");
} }
} }
...@@ -314,10 +316,12 @@ check_trx_exists( ...@@ -314,10 +316,12 @@ check_trx_exists(
{ {
trx_t* trx; trx_t* trx;
ut_a(thd == current_thd);
trx = (trx_t*) thd->transaction.all.innobase_tid; trx = (trx_t*) thd->transaction.all.innobase_tid;
if (trx == NULL) { if (trx == NULL) {
dbug_assert(thd != NULL); ut_a(thd != NULL);
trx = trx_allocate_for_mysql(); trx = trx_allocate_for_mysql();
trx->mysql_thd = thd; trx->mysql_thd = thd;
...@@ -1378,6 +1382,9 @@ ha_innobase::write_row( ...@@ -1378,6 +1382,9 @@ ha_innobase::write_row(
DBUG_ENTER("ha_innobase::write_row"); DBUG_ENTER("ha_innobase::write_row");
ut_a(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid);
statistic_increment(ha_write_count, &LOCK_status); statistic_increment(ha_write_count, &LOCK_status);
if (table->time_stamp) { if (table->time_stamp) {
...@@ -1718,6 +1725,9 @@ ha_innobase::update_row( ...@@ -1718,6 +1725,9 @@ ha_innobase::update_row(
DBUG_ENTER("ha_innobase::update_row"); DBUG_ENTER("ha_innobase::update_row");
ut_a(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid);
if (table->time_stamp) { if (table->time_stamp) {
update_timestamp(new_row + table->time_stamp - 1); update_timestamp(new_row + table->time_stamp - 1);
} }
...@@ -1775,6 +1785,9 @@ ha_innobase::delete_row( ...@@ -1775,6 +1785,9 @@ ha_innobase::delete_row(
DBUG_ENTER("ha_innobase::delete_row"); DBUG_ENTER("ha_innobase::delete_row");
ut_a(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid);
if (last_query_id != user_thd->query_id) { if (last_query_id != user_thd->query_id) {
prebuilt->sql_stat_start = TRUE; prebuilt->sql_stat_start = TRUE;
last_query_id = user_thd->query_id; last_query_id = user_thd->query_id;
...@@ -1888,6 +1901,10 @@ ha_innobase::index_read( ...@@ -1888,6 +1901,10 @@ ha_innobase::index_read(
ulint ret; ulint ret;
DBUG_ENTER("index_read"); DBUG_ENTER("index_read");
ut_a(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid);
statistic_increment(ha_read_key_count, &LOCK_status); statistic_increment(ha_read_key_count, &LOCK_status);
if (last_query_id != user_thd->query_id) { if (last_query_id != user_thd->query_id) {
...@@ -2062,6 +2079,9 @@ ha_innobase::general_fetch( ...@@ -2062,6 +2079,9 @@ ha_innobase::general_fetch(
DBUG_ENTER("general_fetch"); DBUG_ENTER("general_fetch");
ut_a(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid);
srv_conc_enter_innodb(prebuilt->trx); srv_conc_enter_innodb(prebuilt->trx);
ret = row_search_for_mysql((byte*)buf, 0, prebuilt, match_mode, ret = row_search_for_mysql((byte*)buf, 0, prebuilt, match_mode,
...@@ -2272,6 +2292,9 @@ ha_innobase::rnd_pos( ...@@ -2272,6 +2292,9 @@ ha_innobase::rnd_pos(
DBUG_ENTER("rnd_pos"); DBUG_ENTER("rnd_pos");
statistic_increment(ha_read_rnd_count, &LOCK_status); statistic_increment(ha_read_rnd_count, &LOCK_status);
ut_a(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid);
if (prebuilt->clust_index_was_generated) { if (prebuilt->clust_index_was_generated) {
/* No primary key was defined for the table and we /* No primary key was defined for the table and we
generated the clustered index from the row id: the generated the clustered index from the row id: the
...@@ -2310,6 +2333,9 @@ ha_innobase::position( ...@@ -2310,6 +2333,9 @@ ha_innobase::position(
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
uint len; uint len;
ut_a(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid);
if (prebuilt->clust_index_was_generated) { if (prebuilt->clust_index_was_generated) {
/* No primary key was defined for the table and we /* No primary key was defined for the table and we
generated the clustered index from row id: the generated the clustered index from row id: the
...@@ -3067,6 +3093,8 @@ ha_innobase::check( ...@@ -3067,6 +3093,8 @@ ha_innobase::check(
ulint ret; ulint ret;
ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N); ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N);
ut_a(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid);
if (prebuilt->mysql_template == NULL) { if (prebuilt->mysql_template == NULL) {
/* Build the template; we will use a dummy template /* Build the template; we will use a dummy template
...@@ -3301,6 +3329,51 @@ ha_innobase::external_lock( ...@@ -3301,6 +3329,51 @@ ha_innobase::external_lock(
DBUG_RETURN(error); DBUG_RETURN(error);
} }
/****************************************************************************
Implements the SHOW INNODB STATUS command. Send the output of the InnoDB
Monitor to the client. */
int
innodb_show_status(
/*===============*/
THD* thd) /* in: the MySQL query thread of the caller */
{
String* packet = &thd->packet;
char* buf;
DBUG_ENTER("innodb_show_status");
/* We let the InnoDB Monitor to output at most 100 kB of text */
buf = (char*)ut_malloc(100 * 1024);
srv_sprintf_innodb_monitor(buf, 100 * 1024);
List<Item> field_list;
field_list.push_back(new Item_empty_string("Status", strlen(buf)));
if(send_fields(thd, field_list, 1)) {
DBUG_RETURN(-1);
}
packet->length(0);
net_store_data(packet, buf);
if (my_net_write(&thd->net, (char*)thd->packet.ptr(),
packet->length())) {
ut_free(buf);
DBUG_RETURN(-1);
}
ut_free(buf);
send_eof(&thd->net);
DBUG_RETURN(0);
}
/**************************************************************************** /****************************************************************************
Handling the shared INNOBASE_SHARE structure that is needed to provide table Handling the shared INNOBASE_SHARE structure that is needed to provide table
locking. locking.
...@@ -3424,6 +3497,9 @@ ha_innobase::get_auto_increment() ...@@ -3424,6 +3497,9 @@ ha_innobase::get_auto_increment()
longlong nr; longlong nr;
int error; int error;
ut_a(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid);
/* Also SHOW TABLE STATUS calls this function. Previously, when we did /* Also SHOW TABLE STATUS calls this function. Previously, when we did
always read the max autoinc key value, setting x-locks, users were always read the max autoinc key value, setting x-locks, users were
surprised that SHOW TABLE STATUS could end up in a deadlock with surprised that SHOW TABLE STATUS could end up in a deadlock with
......
...@@ -195,4 +195,5 @@ int innobase_report_binlog_offset_and_commit( ...@@ -195,4 +195,5 @@ int innobase_report_binlog_offset_and_commit(
int innobase_rollback(THD *thd, void* trx_handle); int innobase_rollback(THD *thd, void* trx_handle);
int innobase_close_connection(THD *thd); int innobase_close_connection(THD *thd);
int innobase_drop_database(char *path); int innobase_drop_database(char *path);
int innodb_show_status(THD* thd);
...@@ -3155,6 +3155,7 @@ struct show_var_st status_vars[]= { ...@@ -3155,6 +3155,7 @@ struct show_var_st status_vars[]= {
{"Com_show_processlist", (char*) (com_stat+(uint) SQLCOM_SHOW_PROCESSLIST),SHOW_LONG}, {"Com_show_processlist", (char*) (com_stat+(uint) SQLCOM_SHOW_PROCESSLIST),SHOW_LONG},
{"Com_show_slave_status", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_STAT),SHOW_LONG}, {"Com_show_slave_status", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_STAT),SHOW_LONG},
{"Com_show_status", (char*) (com_stat+(uint) SQLCOM_SHOW_STATUS),SHOW_LONG}, {"Com_show_status", (char*) (com_stat+(uint) SQLCOM_SHOW_STATUS),SHOW_LONG},
{"Com_show_innodb_status", (char*) (com_stat+(uint) SQLCOM_SHOW_INNODB_STATUS),SHOW_LONG},
{"Com_show_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLES),SHOW_LONG}, {"Com_show_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLES),SHOW_LONG},
{"Com_show_variables", (char*) (com_stat+(uint) SQLCOM_SHOW_VARIABLES),SHOW_LONG}, {"Com_show_variables", (char*) (com_stat+(uint) SQLCOM_SHOW_VARIABLES),SHOW_LONG},
{"Com_slave_start", (char*) (com_stat+(uint) SQLCOM_SLAVE_START),SHOW_LONG}, {"Com_slave_start", (char*) (com_stat+(uint) SQLCOM_SLAVE_START),SHOW_LONG},
......
...@@ -40,6 +40,7 @@ enum enum_sql_command { ...@@ -40,6 +40,7 @@ enum enum_sql_command {
SQLCOM_SHOW_DATABASES, SQLCOM_SHOW_TABLES, SQLCOM_SHOW_FIELDS, SQLCOM_SHOW_DATABASES, SQLCOM_SHOW_TABLES, SQLCOM_SHOW_FIELDS,
SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_LOGS, SQLCOM_SHOW_STATUS, SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_LOGS, SQLCOM_SHOW_STATUS,
SQLCOM_SHOW_INNODB_STATUS,
SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT, SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT,
SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE,
......
...@@ -24,6 +24,10 @@ ...@@ -24,6 +24,10 @@
#include <my_dir.h> #include <my_dir.h>
#include <assert.h> #include <assert.h>
#ifdef HAVE_INNOBASE_DB
#include "ha_innobase.h"
#endif
#define SCRAMBLE_LENGTH 8 #define SCRAMBLE_LENGTH 8
...@@ -1232,6 +1236,15 @@ mysql_execute_command(void) ...@@ -1232,6 +1236,15 @@ mysql_execute_command(void)
res = show_binlog_info(thd); res = show_binlog_info(thd);
break; break;
} }
#ifdef HAVE_INNOBASE_DB
case SQLCOM_SHOW_INNODB_STATUS:
{
if (check_process_priv(thd))
goto error;
res = innodb_show_status(thd);
break;
}
#endif
case SQLCOM_LOAD_MASTER_TABLE: case SQLCOM_LOAD_MASTER_TABLE:
if (!tables->db) if (!tables->db)
......
...@@ -2242,6 +2242,8 @@ show_param: ...@@ -2242,6 +2242,8 @@ show_param:
} }
| STATUS_SYM wild | STATUS_SYM wild
{ Lex->sql_command= SQLCOM_SHOW_STATUS; } { Lex->sql_command= SQLCOM_SHOW_STATUS; }
| INNOBASE_SYM STATUS_SYM
{ Lex->sql_command = SQLCOM_SHOW_INNODB_STATUS;}
| opt_full PROCESSLIST_SYM | opt_full PROCESSLIST_SYM
{ Lex->sql_command= SQLCOM_SHOW_PROCESSLIST;} { Lex->sql_command= SQLCOM_SHOW_PROCESSLIST;}
| VARIABLES wild | VARIABLES wild
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment