Commit 1311f7ce authored by heikki@donna.mysql.fi's avatar heikki@donna.mysql.fi

trx0roll.c Fix the primary key update + BLOB bug, improve InnoDB Monitor prints

trx0sys.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
trx0trx.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
row0mysql.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
row0purge.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
row0sel.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
row0uins.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
row0umod.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
row0upd.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
srv0srv.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
srv0start.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
sync0arr.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
fil0fil.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
ibuf0ibuf.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
lock0lock.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
os0file.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
btr0btr.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
btr0cur.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
btr0sea.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
buf0buf.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
data0data.c	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
srv0srv.h	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
trx0sys.h	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
trx0trx.h	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
btr0cur.h	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
buf0buf.h	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
data0data.h	Fix the primary key update + BLOB bug, improve InnoDB Monitor prints
ha_innobase.cc	Fix the auto-inc+REPLACE+replication bug, improve InnoDB Monitor prints
parent e4ba2983
...@@ -1738,8 +1738,8 @@ btr_node_ptr_delete( ...@@ -1738,8 +1738,8 @@ btr_node_ptr_delete(
btr_cur_position(UT_LIST_GET_FIRST(tree->tree_indexes), node_ptr, btr_cur_position(UT_LIST_GET_FIRST(tree->tree_indexes), node_ptr,
&cursor); &cursor);
compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, mtr); compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, FALSE,
mtr);
ut_a(err == DB_SUCCESS); ut_a(err == DB_SUCCESS);
if (!compressed) { if (!compressed) {
......
This diff is collapsed.
...@@ -769,6 +769,11 @@ btr_search_guess_on_hash( ...@@ -769,6 +769,11 @@ btr_search_guess_on_hash(
buf_page_make_young(page); buf_page_make_young(page);
} }
/* Increment the page get statistics though we did not really
fix the page: for user info only */
buf_pool->n_page_gets++;
return(TRUE); return(TRUE);
/*-------------------------------------------*/ /*-------------------------------------------*/
......
...@@ -349,6 +349,10 @@ buf_pool_create( ...@@ -349,6 +349,10 @@ buf_pool_create(
buf_pool->n_pages_written = 0; buf_pool->n_pages_written = 0;
buf_pool->n_pages_created = 0; buf_pool->n_pages_created = 0;
buf_pool->n_page_gets = 0;
buf_pool->n_page_gets_old = 0;
buf_pool->n_pages_read_old = 0;
/* 2. Initialize flushing fields /* 2. Initialize flushing fields
---------------------------- */ ---------------------------- */
UT_LIST_INIT(buf_pool->flush_list); UT_LIST_INIT(buf_pool->flush_list);
...@@ -667,6 +671,7 @@ buf_page_get_gen( ...@@ -667,6 +671,7 @@ buf_page_get_gen(
#ifndef UNIV_LOG_DEBUG #ifndef UNIV_LOG_DEBUG
ut_ad(!ibuf_inside() || ibuf_page(space, offset)); ut_ad(!ibuf_inside() || ibuf_page(space, offset));
#endif #endif
buf_pool->n_page_gets++;
loop: loop:
mutex_enter_fast(&(buf_pool->mutex)); mutex_enter_fast(&(buf_pool->mutex));
...@@ -846,6 +851,8 @@ buf_page_optimistic_get_func( ...@@ -846,6 +851,8 @@ buf_page_optimistic_get_func(
ut_ad(mtr && guess); ut_ad(mtr && guess);
ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH)); ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
buf_pool->n_page_gets++;
block = buf_block_align(guess); block = buf_block_align(guess);
mutex_enter(&(buf_pool->mutex)); mutex_enter(&(buf_pool->mutex));
...@@ -976,6 +983,8 @@ buf_page_get_known_nowait( ...@@ -976,6 +983,8 @@ buf_page_get_known_nowait(
ut_ad(mtr); ut_ad(mtr);
ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH)); ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
buf_pool->n_page_gets++;
block = buf_block_align(guess); block = buf_block_align(guess);
mutex_enter(&(buf_pool->mutex)); mutex_enter(&(buf_pool->mutex));
...@@ -1643,6 +1652,18 @@ buf_print_io(void) ...@@ -1643,6 +1652,18 @@ buf_print_io(void)
printf("Pages read %lu, created %lu, written %lu\n", printf("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);
if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) {
printf("Buffer pool hit rate %lu / 1000\n",
1000
- ((1000 *
(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_old = buf_pool->n_page_gets;
buf_pool->n_pages_read_old = buf_pool->n_pages_read;
mutex_exit(&(buf_pool->mutex)); mutex_exit(&(buf_pool->mutex));
} }
......
...@@ -395,7 +395,12 @@ dtuple_convert_big_rec( ...@@ -395,7 +395,12 @@ dtuple_convert_big_rec(
the entry enough, i.e., if there are the entry enough, i.e., if there are
too many short fields in entry */ too many short fields in entry */
dict_index_t* index, /* in: index */ dict_index_t* index, /* in: index */
dtuple_t* entry) /* in: index entry */ dtuple_t* entry, /* in: index entry */
ulint* ext_vec,/* in: array of externally stored fields,
or NULL: if a field already is externally
stored, then we cannot move it to the vector
this function returns */
ulint n_ext_vec)/* in: number of elements is ext_vec */
{ {
mem_heap_t* heap; mem_heap_t* heap;
big_rec_t* vector; big_rec_t* vector;
...@@ -404,7 +409,9 @@ dtuple_convert_big_rec( ...@@ -404,7 +409,9 @@ dtuple_convert_big_rec(
ulint n_fields; ulint n_fields;
ulint longest; ulint longest;
ulint longest_i; ulint longest_i;
ibool is_externally_stored;
ulint i; ulint i;
ulint j;
size = rec_get_converted_size(entry); size = rec_get_converted_size(entry);
...@@ -431,9 +438,23 @@ dtuple_convert_big_rec( ...@@ -431,9 +438,23 @@ dtuple_convert_big_rec(
for (i = dict_index_get_n_unique_in_tree(index); for (i = dict_index_get_n_unique_in_tree(index);
i < dtuple_get_n_fields(entry); i++) { i < dtuple_get_n_fields(entry); i++) {
/* Skip over fields which already are externally
stored */
is_externally_stored = FALSE;
if (ext_vec) {
for (j = 0; j < n_ext_vec; j++) {
if (ext_vec[j] == i) {
is_externally_stored = TRUE;
}
}
}
/* Skip over fields which are ordering in some index */ /* Skip over fields which are ordering in some index */
if (dict_field_get_col( if (!is_externally_stored &&
dict_field_get_col(
dict_index_get_nth_field(index, i)) dict_index_get_nth_field(index, i))
->ord_part == 0) { ->ord_part == 0) {
......
...@@ -19,6 +19,7 @@ Created 10/25/1995 Heikki Tuuri ...@@ -19,6 +19,7 @@ Created 10/25/1995 Heikki Tuuri
#include "log0log.h" #include "log0log.h"
#include "log0recv.h" #include "log0recv.h"
#include "fsp0fsp.h" #include "fsp0fsp.h"
#include "srv0srv.h"
/* /*
IMPLEMENTATION OF THE LOW-LEVEL FILE SYSTEM IMPLEMENTATION OF THE LOW-LEVEL FILE SYSTEM
...@@ -1152,6 +1153,7 @@ fil_aio_wait( ...@@ -1152,6 +1153,7 @@ fil_aio_wait(
ut_ad(fil_validate()); ut_ad(fil_validate());
if (os_aio_use_native_aio) { if (os_aio_use_native_aio) {
srv_io_thread_op_info[segment] = "native aio handle";
#ifdef WIN_ASYNC_IO #ifdef WIN_ASYNC_IO
ret = os_aio_windows_handle(segment, 0, &fil_node, &message, ret = os_aio_windows_handle(segment, 0, &fil_node, &message,
&type); &type);
...@@ -1161,12 +1163,16 @@ fil_aio_wait( ...@@ -1161,12 +1163,16 @@ fil_aio_wait(
ut_a(0); ut_a(0);
#endif #endif
} else { } else {
srv_io_thread_op_info[segment] = "simulated aio handle";
ret = os_aio_simulated_handle(segment, (void**) &fil_node, ret = os_aio_simulated_handle(segment, (void**) &fil_node,
&message, &type); &message, &type);
} }
ut_a(ret); ut_a(ret);
srv_io_thread_op_info[segment] = "complete io for fil node";
mutex_enter(&(system->mutex)); mutex_enter(&(system->mutex));
fil_node_complete_io(fil_node, fil_system, type); fil_node_complete_io(fil_node, fil_system, type);
...@@ -1178,9 +1184,10 @@ fil_aio_wait( ...@@ -1178,9 +1184,10 @@ fil_aio_wait(
/* Do the i/o handling */ /* Do the i/o handling */
if (buf_pool_is_block(message)) { if (buf_pool_is_block(message)) {
srv_io_thread_op_info[segment] = "complete io for buf page";
buf_page_io_complete(message); buf_page_io_complete(message);
} else { } else {
srv_io_thread_op_info[segment] = "complete io for log";
log_io_complete(message); log_io_complete(message);
} }
} }
......
...@@ -2341,7 +2341,7 @@ ibuf_delete_rec( ...@@ -2341,7 +2341,7 @@ ibuf_delete_rec(
root = ibuf_tree_root_get(ibuf_data, space, mtr); root = ibuf_tree_root_get(ibuf_data, space, mtr);
btr_cur_pessimistic_delete(&err, TRUE, btr_pcur_get_btr_cur(pcur), btr_cur_pessimistic_delete(&err, TRUE, btr_pcur_get_btr_cur(pcur),
mtr); FALSE, mtr);
ut_a(err == DB_SUCCESS); ut_a(err == DB_SUCCESS);
#ifdef UNIV_IBUF_DEBUG #ifdef UNIV_IBUF_DEBUG
......
...@@ -353,6 +353,7 @@ btr_cur_pessimistic_delete( ...@@ -353,6 +353,7 @@ btr_cur_pessimistic_delete(
if compression does not occur, the cursor if compression does not occur, the cursor
stays valid: it points to successor of stays valid: it points to successor of
deleted record on function exit */ deleted record on function exit */
ibool in_rollback,/* in: TRUE if called in rollback */
mtr_t* mtr); /* in: mtr */ mtr_t* mtr); /* in: mtr */
/*************************************************************** /***************************************************************
Parses a redo log record of updating a record in-place. */ Parses a redo log record of updating a record in-place. */
...@@ -418,6 +419,52 @@ btr_estimate_number_of_different_key_vals( ...@@ -418,6 +419,52 @@ btr_estimate_number_of_different_key_vals(
/* out: estimated number of key values */ /* out: estimated number of key values */
dict_index_t* index); /* in: index */ dict_index_t* index); /* in: index */
/*********************************************************************** /***********************************************************************
Marks not updated extern fields as not-owned by this record. The ownership
is transferred to the updated record which is inserted elsewhere in the
index tree. In purge only the owner of externally stored field is allowed
to free the field. */
void
btr_cur_mark_extern_inherited_fields(
/*=================================*/
rec_t* rec, /* in: record in a clustered index */
upd_t* update, /* in: update vector */
mtr_t* mtr); /* in: mtr */
/***********************************************************************
The complement of the previous function: in an update entry may inherit
some externally stored fields from a record. We must mark them as inherited
in entry, so that they are not freed in a rollback. */
void
btr_cur_mark_dtuple_inherited_extern(
/*=================================*/
dtuple_t* entry, /* in: updated entry to be inserted to
clustered index */
ulint* ext_vec, /* in: array of extern fields in the
original record */
ulint n_ext_vec, /* in: number of elements in ext_vec */
upd_t* update); /* in: update vector */
/***********************************************************************
Marks all extern fields in a record as owned by the record. This function
should be called if the delete mark of a record is removed: a not delete
marked record always owns all its extern fields. */
void
btr_cur_unmark_extern_fields(
/*=========================*/
rec_t* rec, /* in: record in a clustered index */
mtr_t* mtr); /* in: mtr */
/***********************************************************************
Marks all extern fields in a dtuple as owned by the record. */
void
btr_cur_unmark_dtuple_extern_fields(
/*================================*/
dtuple_t* entry, /* in: clustered index entry */
ulint* ext_vec, /* in: array of numbers of fields
which have been stored externally */
ulint n_ext_vec); /* in: number of elements in ext_vec */
/***********************************************************************
Stores the fields in big_rec_vec to the tablespace and puts pointers to Stores the fields in big_rec_vec to the tablespace and puts pointers to
them in rec. The fields are stored on pages allocated from leaf node them in rec. The fields are stored on pages allocated from leaf node
file segment of the index tree. */ file segment of the index tree. */
...@@ -435,7 +482,9 @@ btr_store_big_rec_extern_fields( ...@@ -435,7 +482,9 @@ btr_store_big_rec_extern_fields(
rec and to the tree */ rec and to the tree */
/*********************************************************************** /***********************************************************************
Frees the space in an externally stored field to the file space Frees the space in an externally stored field to the file space
management. */ management if the field in data is owned the externally stored field,
in a rollback we may have the additional condition that the field must
not be inherited. */
void void
btr_free_externally_stored_field( btr_free_externally_stored_field(
...@@ -446,6 +495,9 @@ btr_free_externally_stored_field( ...@@ -446,6 +495,9 @@ btr_free_externally_stored_field(
+ reference to the externally + reference to the externally
stored part */ stored part */
ulint local_len, /* in: length of data */ ulint local_len, /* in: length of data */
ibool do_not_free_inherited,/* in: TRUE if called in a
rollback and we do not want to free
inherited fields */
mtr_t* local_mtr); /* in: mtr containing the latch to mtr_t* local_mtr); /* in: mtr containing the latch to
data an an X-latch to the index data an an X-latch to the index
tree */ tree */
...@@ -458,6 +510,9 @@ btr_rec_free_externally_stored_fields( ...@@ -458,6 +510,9 @@ btr_rec_free_externally_stored_fields(
dict_index_t* index, /* in: index of the data, the index dict_index_t* index, /* in: index of the data, the index
tree MUST be X-latched */ tree MUST be X-latched */
rec_t* rec, /* in: record */ rec_t* rec, /* in: record */
ibool do_not_free_inherited,/* in: TRUE if called in a
rollback and we do not want to free
inherited fields */
mtr_t* mtr); /* in: mini-transaction handle which contains mtr_t* mtr); /* in: mini-transaction handle which contains
an X-latch to record page and to the index an X-latch to record page and to the index
tree */ tree */
...@@ -620,10 +675,21 @@ and sleep this many microseconds in between */ ...@@ -620,10 +675,21 @@ and sleep this many microseconds in between */
on that page */ on that page */
#define BTR_EXTERN_LEN 12 /* 8 bytes containing the #define BTR_EXTERN_LEN 12 /* 8 bytes containing the
length of the externally length of the externally
stored part of the BLOB */ stored part of the BLOB.
The 2 highest bits are
reserved to the flags below. */
/*--------------------------------------*/ /*--------------------------------------*/
#define BTR_EXTERN_FIELD_REF_SIZE 20 #define BTR_EXTERN_FIELD_REF_SIZE 20
/* The highest bit of BTR_EXTERN_LEN (i.e., the highest bit of the byte
at lowest address) is set to 1 if this field does not 'own' the externally
stored field; only the owner field is allowed to free the field in purge!
If the 2nd highest bit is 1 then it means that the externally stored field
was inherited from an earlier version of the row. In rollback we are not
allowed to free an inherited external field. */
#define BTR_EXTERN_OWNER_FLAG 128
#define BTR_EXTERN_INHERITED_FLAG 64
extern ulint btr_cur_n_non_sea; extern ulint btr_cur_n_non_sea;
......
...@@ -771,6 +771,17 @@ struct buf_pool_struct{ ...@@ -771,6 +771,17 @@ struct buf_pool_struct{
ulint n_pages_written;/* number write operations */ ulint n_pages_written;/* number write operations */
ulint n_pages_created;/* number of pages created in the pool ulint n_pages_created;/* number of pages created in the pool
with no read */ with no read */
ulint n_page_gets; /* number of page gets performed;
also successful seraches through
the adaptive hash index are
counted as page gets; this field
is NOT protected by the buffer
pool mutex */
ulint n_page_gets_old;/* n_page_gets when buf_print was
last time called: used to calculate
hit rate */
ulint n_pages_read_old;/* n_pages_read when buf_print was
last time called */
/* 2. Page flushing algorithm fields */ /* 2. Page flushing algorithm fields */
UT_LIST_BASE_NODE_T(buf_block_t) flush_list; UT_LIST_BASE_NODE_T(buf_block_t) flush_list;
......
...@@ -329,7 +329,12 @@ dtuple_convert_big_rec( ...@@ -329,7 +329,12 @@ dtuple_convert_big_rec(
the entry enough, i.e., if there are the entry enough, i.e., if there are
too many short fields in entry */ too many short fields in entry */
dict_index_t* index, /* in: index */ dict_index_t* index, /* in: index */
dtuple_t* entry); /* in: index entry */ dtuple_t* entry, /* in: index entry */
ulint* ext_vec,/* in: array of externally stored fields,
or NULL: if a field already is externally
stored, then we cannot move it to the vector
this function returns */
ulint n_ext_vec);/* in: number of elements is ext_vec */
/****************************************************************** /******************************************************************
Puts back to entry the data stored in vector. Note that to ensure the Puts back to entry the data stored in vector. Note that to ensure the
fields in entry can accommodate the data, vector must have been created fields in entry can accommodate the data, vector must have been created
......
...@@ -62,7 +62,15 @@ extern int srv_query_thread_priority; ...@@ -62,7 +62,15 @@ extern int srv_query_thread_priority;
/*-------------------------------------------*/ /*-------------------------------------------*/
extern ulint srv_n_rows_inserted;
extern ulint srv_n_rows_updated;
extern ulint srv_n_rows_deleted;
extern ulint srv_n_rows_read;
extern ibool srv_print_innodb_monitor; extern ibool srv_print_innodb_monitor;
extern ibool srv_print_innodb_lock_monitor;
extern ibool srv_print_innodb_tablespace_monitor;
extern ulint srv_n_spin_wait_rounds; extern ulint srv_n_spin_wait_rounds;
extern ulint srv_spin_wait_delay; extern ulint srv_spin_wait_delay;
extern ibool srv_priority_boost; extern ibool srv_priority_boost;
...@@ -106,12 +114,18 @@ extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs, ...@@ -106,12 +114,18 @@ extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs,
same DRAM page as other hotspot semaphores */ same DRAM page as other hotspot semaphores */
#define kernel_mutex (*kernel_mutex_temp) #define kernel_mutex (*kernel_mutex_temp)
#define SRV_MAX_N_IO_THREADS 100
/* Array of English strings describing the current state of an
i/o handler thread */
extern char* srv_io_thread_op_info[];
typedef struct srv_sys_struct srv_sys_t; typedef struct srv_sys_struct srv_sys_t;
/* The server system */ /* The server system */
extern srv_sys_t* srv_sys; extern srv_sys_t* srv_sys;
/* Alternatives for fiel flush option in Unix; see the InnoDB manual about /* Alternatives for the field flush option in Unix; see the InnoDB manual about
what these mean */ what these mean */
#define SRV_UNIX_FDATASYNC 1 #define SRV_UNIX_FDATASYNC 1
#define SRV_UNIX_O_DSYNC 2 #define SRV_UNIX_O_DSYNC 2
......
...@@ -315,6 +315,9 @@ struct trx_sys_struct{ ...@@ -315,6 +315,9 @@ struct trx_sys_struct{
/* List of active and committed in /* List of active and committed in
memory transactions, sorted on trx id, memory transactions, sorted on trx id,
biggest first */ biggest first */
UT_LIST_BASE_NODE_T(trx_t) mysql_trx_list;
/* List of transactions created
for MySQL */
UT_LIST_BASE_NODE_T(trx_rseg_t) rseg_list; UT_LIST_BASE_NODE_T(trx_rseg_t) rseg_list;
/* List of rollback segment objects */ /* List of rollback segment objects */
trx_rseg_t* latest_rseg; /* Latest rollback segment in the trx_rseg_t* latest_rseg; /* Latest rollback segment in the
......
...@@ -130,6 +130,14 @@ void ...@@ -130,6 +130,14 @@ void
trx_mark_sql_stat_end( trx_mark_sql_stat_end(
/*==================*/ /*==================*/
trx_t* trx); /* in: trx handle */ trx_t* trx); /* in: trx handle */
/**************************************************************************
Marks the latest SQL statement ended but does not start a new transaction
if the trx is not started. */
void
trx_mark_sql_stat_end_do_not_start_new(
/*===================================*/
trx_t* trx); /* in: trx handle */
/************************************************************************ /************************************************************************
Assigns a read view for a consistent read query. All the consistent reads Assigns a read view for a consistent read query. All the consistent reads
within the same transaction will get the same read view, which is created within the same transaction will get the same read view, which is created
...@@ -236,6 +244,14 @@ trx_commit_step( ...@@ -236,6 +244,14 @@ trx_commit_step(
/*============*/ /*============*/
/* out: query thread to run next, or NULL */ /* out: query thread to run next, or NULL */
que_thr_t* thr); /* in: query thread */ que_thr_t* thr); /* in: query thread */
/**************************************************************************
Prints info about a transaction to the standard output. The caller must
own the kernel mutex. */
void
trx_print(
/*======*/
trx_t* trx); /* in: transaction */
/* Signal to a transaction */ /* Signal to a transaction */
...@@ -270,6 +286,9 @@ rolling back after a database recovery */ ...@@ -270,6 +286,9 @@ rolling back after a database recovery */
struct trx_struct{ struct trx_struct{
/* All the next fields are protected by the kernel mutex, except the /* All the next fields are protected by the kernel mutex, except the
undo logs which are protected by undo_mutex */ undo logs which are protected by undo_mutex */
char* op_info; /* English text describing the
current operation, or an empty
string */
ulint type; /* TRX_USER, TRX_PURGE */ ulint type; /* TRX_USER, TRX_PURGE */
ulint conc_state; /* state of the trx from the point ulint conc_state; /* state of the trx from the point
of view of concurrency control: of view of concurrency control:
...@@ -284,6 +303,8 @@ struct trx_struct{ ...@@ -284,6 +303,8 @@ struct trx_struct{
table */ table */
dulint table_id; /* table id if the preceding field is dulint table_id; /* table id if the preceding field is
TRUE */ TRUE */
void* mysql_thd; /* MySQL thread handle corresponding
to this trx, or NULL */
os_thread_id_t mysql_thread_id;/* id of the MySQL thread associated os_thread_id_t mysql_thread_id;/* id of the MySQL thread associated
with this transaction object */ with this transaction object */
ulint n_mysql_tables_in_use; /* number of Innobase tables ulint n_mysql_tables_in_use; /* number of Innobase tables
...@@ -302,6 +323,9 @@ struct trx_struct{ ...@@ -302,6 +323,9 @@ struct trx_struct{
of a duplicate key error */ of a duplicate key error */
UT_LIST_NODE_T(trx_t) UT_LIST_NODE_T(trx_t)
trx_list; /* list of transactions */ trx_list; /* list of transactions */
UT_LIST_NODE_T(trx_t)
mysql_trx_list; /* list of transactions created for
MySQL */
/*------------------------------*/ /*------------------------------*/
mutex_t undo_mutex; /* mutex protecting the fields in this mutex_t undo_mutex; /* mutex protecting the fields in this
section (down to undo_no_arr), EXCEPT section (down to undo_no_arr), EXCEPT
......
...@@ -13,6 +13,7 @@ Created 5/7/1996 Heikki Tuuri ...@@ -13,6 +13,7 @@ Created 5/7/1996 Heikki Tuuri
#endif #endif
#include "usr0sess.h" #include "usr0sess.h"
#include "trx0purge.h"
/* When releasing transaction locks, this specifies how often we release /* When releasing transaction locks, this specifies how often we release
the kernel mutex for a moment to give also others access to it */ the kernel mutex for a moment to give also others access to it */
...@@ -3184,7 +3185,7 @@ lock_table_print( ...@@ -3184,7 +3185,7 @@ lock_table_print(
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("\nTABLE LOCK table %s trx id %lu %lu", printf("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);
...@@ -3220,6 +3221,8 @@ lock_rec_print( ...@@ -3220,6 +3221,8 @@ lock_rec_print(
ulint page_no; ulint page_no;
ulint i; ulint i;
ulint count = 0; ulint count = 0;
ulint len;
char buf[200];
mtr_t mtr; mtr_t mtr;
ut_ad(mutex_own(&kernel_mutex)); ut_ad(mutex_own(&kernel_mutex));
...@@ -3228,7 +3231,7 @@ lock_rec_print( ...@@ -3228,7 +3231,7 @@ 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("\nRECORD LOCKS space id %lu page no %lu n bits %lu", printf("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", printf(" table %s index %s trx id %lu %lu",
...@@ -3251,10 +3254,10 @@ lock_rec_print( ...@@ -3251,10 +3254,10 @@ lock_rec_print(
printf(" waiting"); printf(" waiting");
} }
printf("\n");
mtr_start(&mtr); mtr_start(&mtr);
printf("\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
break the latching order */ break the latching order */
...@@ -3280,12 +3283,14 @@ lock_rec_print( ...@@ -3280,12 +3283,14 @@ lock_rec_print(
printf("Record lock, heap no %lu ", i); printf("Record lock, heap no %lu ", i);
if (page) { if (page) {
rec_print(page_find_rec_with_heap_no(page, i)); len = rec_sprintf(buf, 190,
page_find_rec_with_heap_no(page, i));
buf[len] = '\0';
printf("%s", buf);
} }
count++;
printf("\n"); printf("\n");
count++;
} }
if (count >= 3) { if (count >= 3) {
...@@ -3343,11 +3348,31 @@ lock_print_info(void) ...@@ -3343,11 +3348,31 @@ lock_print_info(void)
ulint i; ulint i;
mtr_t mtr; mtr_t mtr;
printf(
"Purge done for all trx's with n:o < %lu %lu, undo n:o < %lu %lu\n",
ut_dulint_get_high(purge_sys->purge_trx_no),
ut_dulint_get_low(purge_sys->purge_trx_no),
ut_dulint_get_high(purge_sys->purge_undo_no),
ut_dulint_get_low(purge_sys->purge_undo_no));
lock_mutex_enter_kernel(); lock_mutex_enter_kernel();
printf("LOCK INFO:\n"); printf("Total number of lock structs in row lock hash table %lu\n",
printf("Number of locks in the record hash table %lu\n",
lock_get_n_rec_locks()); lock_get_n_rec_locks());
/* First print info on non-active transactions */
trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list);
while (trx) {
if (trx->conc_state == TRX_NOT_STARTED) {
printf("---");
trx_print(trx);
}
trx = UT_LIST_GET_NEXT(mysql_trx_list, trx);
}
loop: loop:
trx = UT_LIST_GET_FIRST(trx_sys->trx_list); trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
...@@ -3367,11 +3392,21 @@ loop: ...@@ -3367,11 +3392,21 @@ loop:
} }
if (nth_lock == 0) { if (nth_lock == 0) {
printf("\nLOCKS FOR TRANSACTION ID %lu %lu\n", trx->id.high, printf("---");
trx->id.low); trx_print(trx);
if (trx->read_view) {
printf(
"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_low(trx->read_view->low_limit_id),
ut_dulint_get_high(trx->read_view->up_limit_id),
ut_dulint_get_low(trx->read_view->up_limit_id));
}
if (trx->que_state == TRX_QUE_LOCK_WAIT) { if (trx->que_state == TRX_QUE_LOCK_WAIT) {
printf( printf(
"################# 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(trx->wait_lock);
...@@ -3380,8 +3415,13 @@ loop: ...@@ -3380,8 +3415,13 @@ loop:
} }
printf( printf(
"##################################################\n"); "------------------\n");
}
} }
if (!srv_print_innodb_lock_monitor) {
nth_trx++;
goto loop;
} }
i = 0; i = 0;
...@@ -3431,9 +3471,9 @@ loop: ...@@ -3431,9 +3471,9 @@ loop:
nth_lock++; nth_lock++;
if (nth_lock >= 25) { if (nth_lock >= 10) {
printf( printf(
"25 LOCKS PRINTED FOR THIS TRX: SUPPRESSING FURTHER PRINTS\n"); "10 LOCKS PRINTED FOR THIS TRX: SUPPRESSING FURTHER PRINTS\n");
nth_trx++; nth_trx++;
nth_lock = 0; nth_lock = 0;
......
...@@ -1577,6 +1577,7 @@ os_aio_windows_handle( ...@@ -1577,6 +1577,7 @@ os_aio_windows_handle(
void** message2, void** message2,
ulint* type) /* out: OS_FILE_WRITE or ..._READ */ ulint* type) /* out: OS_FILE_WRITE or ..._READ */
{ {
ulint orig_seg = segment;
os_aio_array_t* array; os_aio_array_t* array;
os_aio_slot_t* slot; os_aio_slot_t* slot;
ulint n; ulint n;
...@@ -1602,10 +1603,14 @@ os_aio_windows_handle( ...@@ -1602,10 +1603,14 @@ os_aio_windows_handle(
n = array->n_slots / array->n_segments; n = array->n_slots / array->n_segments;
if (array == os_aio_sync_array) { if (array == os_aio_sync_array) {
srv_io_thread_op_info[orig_seg] = "wait windows aio for 1 page";
ut_ad(pos < array->n_slots); ut_ad(pos < array->n_slots);
os_event_wait(array->events[pos]); os_event_wait(array->events[pos]);
i = pos; i = pos;
} else { } else {
srv_io_thread_op_info[orig_seg] =
"wait windows aio for n pages";
i = os_event_wait_multiple(n, (array->events) + segment * n); i = os_event_wait_multiple(n, (array->events) + segment * n);
} }
...@@ -1615,6 +1620,7 @@ os_aio_windows_handle( ...@@ -1615,6 +1620,7 @@ os_aio_windows_handle(
ut_a(slot->reserved); ut_a(slot->reserved);
srv_io_thread_op_info[orig_seg] = "get windows aio return value";
ret = GetOverlappedResult(slot->file, &(slot->control), &len, TRUE); ret = GetOverlappedResult(slot->file, &(slot->control), &len, TRUE);
*message1 = slot->message1; *message1 = slot->message1;
...@@ -1887,6 +1893,8 @@ consecutive_loop: ...@@ -1887,6 +1893,8 @@ consecutive_loop:
} }
} }
srv_io_thread_op_info[global_segment] = "doing file i/o";
/* Do the i/o with ordinary, synchronous i/o functions: */ /* Do the i/o with ordinary, synchronous i/o functions: */
if (slot->type == OS_FILE_WRITE) { if (slot->type == OS_FILE_WRITE) {
ret = os_file_write(slot->name, slot->file, combined_buf, ret = os_file_write(slot->name, slot->file, combined_buf,
...@@ -1897,6 +1905,7 @@ consecutive_loop: ...@@ -1897,6 +1905,7 @@ consecutive_loop:
} }
ut_a(ret); ut_a(ret);
srv_io_thread_op_info[global_segment] = "file i/o done";
/* printf("aio: %lu consecutive %lu:th segment, first offs %lu blocks\n", /* printf("aio: %lu consecutive %lu:th segment, first offs %lu blocks\n",
n_consecutive, global_segment, slot->offset n_consecutive, global_segment, slot->offset
...@@ -1953,6 +1962,8 @@ wait_for_io: ...@@ -1953,6 +1962,8 @@ wait_for_io:
os_mutex_exit(array->mutex); os_mutex_exit(array->mutex);
srv_io_thread_op_info[global_segment] = "waiting for i/o request";
os_event_wait(os_aio_segment_wait_events[global_segment]); os_event_wait(os_aio_segment_wait_events[global_segment]);
goto restart; goto restart;
...@@ -2023,7 +2034,12 @@ os_aio_print(void) ...@@ -2023,7 +2034,12 @@ os_aio_print(void)
ulint n_reserved; ulint n_reserved;
ulint i; ulint i;
printf("Pending normal aio reads:\n"); for (i = 0; i < srv_n_file_io_threads; i++) {
printf("I/O thread %lu state: %s\n", i,
srv_io_thread_op_info[i]);
}
printf("Pending normal aio reads: ");
array = os_aio_read_array; array = os_aio_read_array;
loop: loop:
...@@ -2041,21 +2057,21 @@ loop: ...@@ -2041,21 +2057,21 @@ loop:
if (slot->reserved) { if (slot->reserved) {
n_reserved++; n_reserved++;
printf("Reserved slot, messages %lx %lx\n", /* printf("Reserved slot, messages %lx %lx\n",
(ulint)slot->message1, (ulint)slot->message1,
(ulint)slot->message2); (ulint)slot->message2);
ut_a(slot->len > 0); */ ut_a(slot->len > 0);
} }
} }
ut_a(array->n_reserved == n_reserved); ut_a(array->n_reserved == n_reserved);
printf("Total of %lu reserved aio slots\n", n_reserved); printf("%lu\n", 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("Pending aio writes:\n"); printf("Pending aio writes: ");
array = os_aio_write_array; array = os_aio_write_array;
...@@ -2063,21 +2079,21 @@ loop: ...@@ -2063,21 +2079,21 @@ loop:
} }
if (array == os_aio_write_array) { if (array == os_aio_write_array) {
printf("Pending insert buffer aio reads:\n"); printf("Pending insert buffer 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("Pending log writes or reads:\n"); printf("Pending log writes or reads: ");
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("Pending synchronous reads or writes:\n"); printf("Pending synchronous reads or writes: ");
array = os_aio_sync_array; array = os_aio_sync_array;
goto loop; goto loop;
......
...@@ -462,6 +462,8 @@ row_insert_for_mysql( ...@@ -462,6 +462,8 @@ row_insert_for_mysql(
ut_ad(trx); ut_ad(trx);
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
trx->op_info = "inserting";
if (node == NULL) { if (node == NULL) {
row_get_prebuilt_insert_row(prebuilt); row_get_prebuilt_insert_row(prebuilt);
node = prebuilt->ins_node; node = prebuilt->ins_node;
...@@ -499,6 +501,8 @@ run_again: ...@@ -499,6 +501,8 @@ run_again:
goto run_again; goto run_again;
} }
trx->op_info = "";
return(err); return(err);
} }
...@@ -506,12 +510,15 @@ run_again: ...@@ -506,12 +510,15 @@ run_again:
prebuilt->table->stat_n_rows++; prebuilt->table->stat_n_rows++;
srv_n_rows_inserted++;
if (prebuilt->table->stat_n_rows == 0) { if (prebuilt->table->stat_n_rows == 0) {
/* Avoid wrap-over */ /* Avoid wrap-over */
prebuilt->table->stat_n_rows--; prebuilt->table->stat_n_rows--;
} }
row_update_statistics_if_needed(prebuilt); row_update_statistics_if_needed(prebuilt);
trx->op_info = "";
return((int) err); return((int) err);
} }
...@@ -627,6 +634,8 @@ row_update_for_mysql( ...@@ -627,6 +634,8 @@ row_update_for_mysql(
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
UT_NOT_USED(mysql_rec); UT_NOT_USED(mysql_rec);
trx->op_info = "updating or deleting";
node = prebuilt->upd_node; node = prebuilt->upd_node;
clust_index = dict_table_get_first_index(table); clust_index = dict_table_get_first_index(table);
...@@ -700,6 +709,7 @@ run_again: ...@@ -700,6 +709,7 @@ run_again:
if (err == DB_RECORD_NOT_FOUND) { if (err == DB_RECORD_NOT_FOUND) {
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
trx->op_info = "";
return((int) err); return((int) err);
} }
...@@ -710,6 +720,8 @@ run_again: ...@@ -710,6 +720,8 @@ run_again:
goto run_again; goto run_again;
} }
trx->op_info = "";
return(err); return(err);
} }
...@@ -719,10 +731,16 @@ run_again: ...@@ -719,10 +731,16 @@ run_again:
if (prebuilt->table->stat_n_rows > 0) { if (prebuilt->table->stat_n_rows > 0) {
prebuilt->table->stat_n_rows--; prebuilt->table->stat_n_rows--;
} }
srv_n_rows_deleted++;
} else {
srv_n_rows_updated++;
} }
row_update_statistics_if_needed(prebuilt); row_update_statistics_if_needed(prebuilt);
trx->op_info = "";
return((int) err); return((int) err);
} }
...@@ -798,6 +816,8 @@ row_create_table_for_mysql( ...@@ -798,6 +816,8 @@ row_create_table_for_mysql(
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
trx->op_info = "creating table";
/* Serialize data dictionary operations with dictionary mutex: /* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */ no deadlocks can occur then in these operations */
...@@ -832,9 +852,15 @@ row_create_table_for_mysql( ...@@ -832,9 +852,15 @@ row_create_table_for_mysql(
"InnoDB: Error: table %s already exists in InnoDB internal\n" "InnoDB: Error: table %s already exists in InnoDB internal\n"
"InnoDB: data dictionary. Have you deleted the .frm file\n" "InnoDB: data dictionary. Have you deleted the .frm file\n"
"InnoDB: and not used DROP TABLE? Have you used DROP DATABASE\n" "InnoDB: and not used DROP TABLE? Have you used DROP DATABASE\n"
"InnoDB: for InnoDB tables in MySQL version <= 3.23.39?\n" "InnoDB: for InnoDB tables in MySQL version <= 3.23.42?\n"
"InnoDB: See the Restrictions section of the InnoDB manual.\n", "InnoDB: See the Restrictions section of the InnoDB manual.\n",
table->name); table->name);
fprintf(stderr,
"InnoDB: You can drop the orphaned table inside InnoDB by\n"
"InnoDB: creating an InnoDB table with the same name in another\n"
"InnoDB: database and moving the .frm file to the current database.\n"
"InnoDB: Then MySQL thinks the table exists, and DROP TABLE will\n"
"InnoDB: succeed.\n");
} }
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
...@@ -852,11 +878,32 @@ row_create_table_for_mysql( ...@@ -852,11 +878,32 @@ row_create_table_for_mysql(
srv_print_innodb_monitor = TRUE; 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)); mutex_exit(&(dict_sys->mutex));
que_graph_free((que_t*) que_node_get_parent(thr)); que_graph_free((que_t*) que_node_get_parent(thr));
trx->op_info = "";
return((int) err); return((int) err);
} }
...@@ -879,6 +926,8 @@ row_create_index_for_mysql( ...@@ -879,6 +926,8 @@ row_create_index_for_mysql(
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
trx->op_info = "creating index";
/* Serialize data dictionary operations with dictionary mutex: /* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */ no deadlocks can occur then in these operations */
...@@ -915,6 +964,8 @@ row_create_index_for_mysql( ...@@ -915,6 +964,8 @@ row_create_index_for_mysql(
que_graph_free((que_t*) que_node_get_parent(thr)); que_graph_free((que_t*) que_node_get_parent(thr));
trx->op_info = "";
return((int) err); return((int) err);
} }
...@@ -946,6 +997,8 @@ row_drop_table_for_mysql( ...@@ -946,6 +997,8 @@ row_drop_table_for_mysql(
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_a(name != NULL); ut_a(name != NULL);
trx->op_info = "dropping table";
namelen = ut_strlen(name); namelen = ut_strlen(name);
keywordlen = ut_strlen("innodb_monitor"); keywordlen = ut_strlen("innodb_monitor");
...@@ -957,6 +1010,26 @@ row_drop_table_for_mysql( ...@@ -957,6 +1010,26 @@ row_drop_table_for_mysql(
stop monitor prints */ stop monitor prints */
srv_print_innodb_monitor = FALSE; srv_print_innodb_monitor = FALSE;
srv_print_innodb_lock_monitor = FALSE;
}
keywordlen = ut_strlen("innodb_lock_monitor");
if (namelen >= keywordlen
&& 0 == ut_memcmp(name + namelen - keywordlen,
"innodb_lock_monitor", keywordlen)) {
srv_print_innodb_monitor = FALSE;
srv_print_innodb_lock_monitor = FALSE;
}
keywordlen = ut_strlen("innodb_tablespace_monitor");
if (namelen >= keywordlen
&& 0 == ut_memcmp(name + namelen - keywordlen,
"innodb_tablespace_monitor", keywordlen)) {
srv_print_innodb_tablespace_monitor = FALSE;
} }
/* We use the private SQL parser of Innobase to generate the /* We use the private SQL parser of Innobase to generate the
...@@ -1071,6 +1144,8 @@ funct_exit: ...@@ -1071,6 +1144,8 @@ funct_exit:
que_graph_free(graph); que_graph_free(graph);
trx->op_info = "";
return((int) err); return((int) err);
} }
...@@ -1099,6 +1174,8 @@ row_rename_table_for_mysql( ...@@ -1099,6 +1174,8 @@ row_rename_table_for_mysql(
ut_a(old_name != NULL); ut_a(old_name != NULL);
ut_a(new_name != NULL); ut_a(new_name != NULL);
trx->op_info = "renaming table";
str1 = str1 =
"PROCEDURE RENAME_TABLE_PROC () IS\n" "PROCEDURE RENAME_TABLE_PROC () IS\n"
"BEGIN\n" "BEGIN\n"
...@@ -1168,6 +1245,8 @@ funct_exit: ...@@ -1168,6 +1245,8 @@ funct_exit:
que_graph_free(graph); que_graph_free(graph);
trx->op_info = "";
return((int) err); return((int) err);
} }
...@@ -1280,6 +1359,8 @@ row_check_table_for_mysql( ...@@ -1280,6 +1359,8 @@ row_check_table_for_mysql(
ulint n_rows_in_table; ulint n_rows_in_table;
ulint ret = DB_SUCCESS; ulint ret = DB_SUCCESS;
prebuilt->trx->op_info = "checking table";
index = dict_table_get_first_index(table); index = dict_table_get_first_index(table);
while (index != NULL) { while (index != NULL) {
...@@ -1311,5 +1392,7 @@ row_check_table_for_mysql( ...@@ -1311,5 +1392,7 @@ row_check_table_for_mysql(
index = dict_table_get_next_index(index); index = dict_table_get_next_index(index);
} }
prebuilt->trx->op_info = "";
return(ret); return(ret);
} }
...@@ -132,7 +132,7 @@ row_purge_remove_clust_if_poss_low( ...@@ -132,7 +132,7 @@ row_purge_remove_clust_if_poss_low(
success = btr_cur_optimistic_delete(btr_cur, &mtr); success = btr_cur_optimistic_delete(btr_cur, &mtr);
} else { } else {
ut_ad(mode == BTR_MODIFY_TREE); ut_ad(mode == BTR_MODIFY_TREE);
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, &mtr); btr_cur_pessimistic_delete(&err, FALSE, btr_cur, FALSE, &mtr);
if (err == DB_SUCCESS) { if (err == DB_SUCCESS) {
success = TRUE; success = TRUE;
...@@ -254,8 +254,8 @@ row_purge_remove_sec_if_poss_low( ...@@ -254,8 +254,8 @@ row_purge_remove_sec_if_poss_low(
success = btr_cur_optimistic_delete(btr_cur, &mtr); success = btr_cur_optimistic_delete(btr_cur, &mtr);
} else { } else {
ut_ad(mode == BTR_MODIFY_TREE); ut_ad(mode == BTR_MODIFY_TREE);
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, &mtr); btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
FALSE, &mtr);
if (err == DB_SUCCESS) { if (err == DB_SUCCESS) {
success = TRUE; success = TRUE;
} else if (err == DB_OUT_OF_FILE_SPACE) { } else if (err == DB_OUT_OF_FILE_SPACE) {
...@@ -437,7 +437,7 @@ skip_secondaries: ...@@ -437,7 +437,7 @@ skip_secondaries:
data_field_len = ufield->new_val.len; data_field_len = ufield->new_val.len;
btr_free_externally_stored_field(index, data_field, btr_free_externally_stored_field(index, data_field,
data_field_len, &mtr); data_field_len, FALSE, &mtr);
mtr_commit(&mtr); mtr_commit(&mtr);
} }
} }
......
...@@ -2488,6 +2488,8 @@ row_search_for_mysql( ...@@ -2488,6 +2488,8 @@ row_search_for_mysql(
printf("N tables locked %lu\n", trx->mysql_n_tables_locked); printf("N tables locked %lu\n", trx->mysql_n_tables_locked);
*/ */
if (direction == 0) { if (direction == 0) {
trx->op_info = "starting index read";
prebuilt->n_rows_fetched = 0; prebuilt->n_rows_fetched = 0;
prebuilt->n_fetch_cached = 0; prebuilt->n_fetch_cached = 0;
prebuilt->fetch_cache_first = 0; prebuilt->fetch_cache_first = 0;
...@@ -2497,6 +2499,8 @@ row_search_for_mysql( ...@@ -2497,6 +2499,8 @@ row_search_for_mysql(
row_prebuild_sel_graph(prebuilt); row_prebuild_sel_graph(prebuilt);
} }
} else { } else {
trx->op_info = "fetching rows";
if (prebuilt->n_rows_fetched == 0) { if (prebuilt->n_rows_fetched == 0) {
prebuilt->fetch_direction = direction; prebuilt->fetch_direction = direction;
} }
...@@ -2519,6 +2523,9 @@ row_search_for_mysql( ...@@ -2519,6 +2523,9 @@ row_search_for_mysql(
prebuilt->n_rows_fetched++; prebuilt->n_rows_fetched++;
srv_n_rows_read++;
trx->op_info = "";
return(DB_SUCCESS); return(DB_SUCCESS);
} }
...@@ -2529,6 +2536,7 @@ row_search_for_mysql( ...@@ -2529,6 +2536,7 @@ row_search_for_mysql(
cache, but the cache was not full at the time of the cache, but the cache was not full at the time of the
popping: no more rows can exist in the result set */ popping: no more rows can exist in the result set */
trx->op_info = "";
return(DB_RECORD_NOT_FOUND); return(DB_RECORD_NOT_FOUND);
} }
...@@ -2560,6 +2568,7 @@ row_search_for_mysql( ...@@ -2560,6 +2568,7 @@ row_search_for_mysql(
/* printf("%s record not found 1\n", index->name); */ /* printf("%s record not found 1\n", index->name); */
trx->op_info = "";
return(DB_RECORD_NOT_FOUND); return(DB_RECORD_NOT_FOUND);
} }
...@@ -2599,6 +2608,9 @@ row_search_for_mysql( ...@@ -2599,6 +2608,9 @@ row_search_for_mysql(
/* printf("%s shortcut\n", index->name); */ /* printf("%s shortcut\n", index->name); */
srv_n_rows_read++;
trx->op_info = "";
return(DB_SUCCESS); return(DB_SUCCESS);
} else if (shortcut == SEL_EXHAUSTED) { } else if (shortcut == SEL_EXHAUSTED) {
...@@ -2607,6 +2619,7 @@ row_search_for_mysql( ...@@ -2607,6 +2619,7 @@ row_search_for_mysql(
/* printf("%s record not found 2\n", /* printf("%s record not found 2\n",
index->name); */ index->name); */
trx->op_info = "";
return(DB_RECORD_NOT_FOUND); return(DB_RECORD_NOT_FOUND);
} }
...@@ -2980,6 +2993,8 @@ lock_wait_or_error: ...@@ -2980,6 +2993,8 @@ lock_wait_or_error:
/* printf("Using index %s cnt %lu ret value %lu err\n", index->name, /* printf("Using index %s cnt %lu ret value %lu err\n", index->name,
cnt, err); */ cnt, err); */
trx->op_info = "";
return(err); return(err);
normal_return: normal_return:
...@@ -2995,5 +3010,11 @@ normal_return: ...@@ -2995,5 +3010,11 @@ normal_return:
/* printf("Using index %s cnt %lu ret value %lu\n", index->name, /* printf("Using index %s cnt %lu ret value %lu\n", index->name,
cnt, err); */ cnt, err); */
if (ret == DB_SUCCESS) {
srv_n_rows_read++;
}
trx->op_info = "";
return(ret); return(ret);
} }
...@@ -89,7 +89,7 @@ retry: ...@@ -89,7 +89,7 @@ retry:
&(node->pcur), &mtr); &(node->pcur), &mtr);
ut_a(success); ut_a(success);
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, &mtr); btr_cur_pessimistic_delete(&err, FALSE, btr_cur, TRUE, &mtr);
/* The delete operation may fail if we have little /* The delete operation may fail if we have little
file space left: TODO: easiest to crash the database file space left: TODO: easiest to crash the database
...@@ -174,7 +174,7 @@ row_undo_ins_remove_sec_low( ...@@ -174,7 +174,7 @@ row_undo_ins_remove_sec_low(
} else { } else {
ut_ad(mode == BTR_MODIFY_TREE); ut_ad(mode == BTR_MODIFY_TREE);
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, &mtr); btr_cur_pessimistic_delete(&err, FALSE, btr_cur, TRUE, &mtr);
} }
btr_pcur_close(&pcur); btr_pcur_close(&pcur);
......
...@@ -179,7 +179,11 @@ row_undo_mod_remove_clust_low( ...@@ -179,7 +179,11 @@ row_undo_mod_remove_clust_low(
} else { } else {
ut_ad(mode == BTR_MODIFY_TREE); ut_ad(mode == BTR_MODIFY_TREE);
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, mtr); /* Note that since this operation is analogous to purge,
we can free also inherited externally stored fields:
hence the last FALSE in the call below */
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, FALSE, mtr);
/* The delete operation may fail if we have little /* The delete operation may fail if we have little
file space left: TODO: easiest to crash the database file space left: TODO: easiest to crash the database
...@@ -356,7 +360,8 @@ row_undo_mod_del_mark_or_remove_sec_low( ...@@ -356,7 +360,8 @@ row_undo_mod_del_mark_or_remove_sec_low(
} else { } else {
ut_ad(mode == BTR_MODIFY_TREE); ut_ad(mode == BTR_MODIFY_TREE);
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, &mtr); btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
TRUE, &mtr);
/* The delete operation may fail if we have little /* The delete operation may fail if we have little
file space left: TODO: easiest to crash the database file space left: TODO: easiest to crash the database
...@@ -434,11 +439,11 @@ row_undo_mod_del_unmark_sec( ...@@ -434,11 +439,11 @@ 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);
fprintf(stderr, "InnoDB: Make a detailed bug report and send it\n"); fprintf(stderr,
"InnoDB: Make a detailed bug report and send it\n");
fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n");
mem_free(err_buf); mem_free(err_buf);
} else { } else {
btr_cur = btr_pcur_get_btr_cur(&pcur); btr_cur = btr_pcur_get_btr_cur(&pcur);
......
...@@ -840,7 +840,6 @@ row_upd_sec_index_entry( ...@@ -840,7 +840,6 @@ row_upd_sec_index_entry(
rec = btr_cur_get_rec(btr_cur); rec = btr_cur_get_rec(btr_cur);
if (!found) { if (!found) {
err_buf = mem_alloc(1000); err_buf = mem_alloc(1000);
dtuple_sprintf(err_buf, 900, entry); dtuple_sprintf(err_buf, 900, entry);
...@@ -852,19 +851,19 @@ row_upd_sec_index_entry( ...@@ -852,19 +851,19 @@ 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);
fprintf(stderr, "InnoDB: Make a detailed bug report and send it\n"); fprintf(stderr,
"InnoDB: Make a detailed bug report and send it\n");
fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n");
mem_free(err_buf); mem_free(err_buf);
} 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
row_ins_index_entry below */ row_ins_index_entry below */
if (!rec_get_deleted_flag(rec)) { if (!rec_get_deleted_flag(rec)) {
err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE, thr, err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE,
&mtr); thr, &mtr);
} }
} }
...@@ -907,7 +906,7 @@ row_upd_sec_step( ...@@ -907,7 +906,7 @@ row_upd_sec_step(
|| (node->state == UPD_NODE_UPDATE_SOME_SEC)); || (node->state == UPD_NODE_UPDATE_SOME_SEC));
ut_ad(!(node->index->type & DICT_CLUSTERED)); ut_ad(!(node->index->type & DICT_CLUSTERED));
if ((node->state == UPD_NODE_UPDATE_ALL_SEC) if (node->state == UPD_NODE_UPDATE_ALL_SEC
|| row_upd_changes_ord_field(node->row, node->index, || row_upd_changes_ord_field(node->row, node->index,
node->update)) { node->update)) {
err = row_upd_sec_index_entry(node, thr); err = row_upd_sec_index_entry(node, thr);
...@@ -934,14 +933,12 @@ row_upd_clust_rec_by_insert( ...@@ -934,14 +933,12 @@ row_upd_clust_rec_by_insert(
que_thr_t* thr, /* in: query thread */ que_thr_t* thr, /* in: query thread */
mtr_t* mtr) /* in: mtr; gets committed here */ mtr_t* mtr) /* in: mtr; gets committed here */
{ {
mem_heap_t* heap;
btr_pcur_t* pcur; btr_pcur_t* pcur;
btr_cur_t* btr_cur; btr_cur_t* btr_cur;
trx_t* trx; trx_t* trx;
dict_table_t* table; dict_table_t* table;
mem_heap_t* heap;
dtuple_t* entry; dtuple_t* entry;
ulint* ext_vec;
ulint n_ext_vec;
ulint err; ulint err;
ut_ad(node); ut_ad(node);
...@@ -961,17 +958,20 @@ row_upd_clust_rec_by_insert( ...@@ -961,17 +958,20 @@ row_upd_clust_rec_by_insert(
return(err); 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
record is removed from the index tree, or updated. */
btr_cur_mark_extern_inherited_fields(btr_cur_get_rec(btr_cur),
node->update, mtr);
} }
mtr_commit(mtr); mtr_commit(mtr);
node->state = UPD_NODE_INSERT_CLUSTERED; node->state = UPD_NODE_INSERT_CLUSTERED;
heap = mem_heap_create(1024); heap = mem_heap_create(500);
ext_vec = mem_heap_alloc(heap,
sizeof(ulint) * dtuple_get_n_fields(node->row));
n_ext_vec = 0;
entry = row_build_index_entry(node->row, index, heap); entry = row_build_index_entry(node->row, index, heap);
...@@ -979,6 +979,19 @@ row_upd_clust_rec_by_insert( ...@@ -979,6 +979,19 @@ row_upd_clust_rec_by_insert(
row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id); row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id);
/* If we return from a lock wait, for example, we may have
extern fields marked as not-owned in entry (marked if the
if-branch above). We must unmark them. */
btr_cur_unmark_dtuple_extern_fields(entry, node->ext_vec,
node->n_ext_vec);
/* We must mark non-updated extern fields in entry as inherited,
so that a possible rollback will not free them */
btr_cur_mark_dtuple_inherited_extern(entry, node->ext_vec,
node->n_ext_vec,
node->update);
err = row_ins_index_entry(index, entry, node->ext_vec, err = row_ins_index_entry(index, entry, node->ext_vec,
node->n_ext_vec, thr); node->n_ext_vec, thr);
mem_heap_free(heap); mem_heap_free(heap);
......
...@@ -111,7 +111,14 @@ ibool srv_print_buf_io = FALSE; ...@@ -111,7 +111,14 @@ ibool srv_print_buf_io = FALSE;
ibool srv_print_log_io = FALSE; ibool srv_print_log_io = FALSE;
ibool srv_print_latch_waits = FALSE; ibool srv_print_latch_waits = FALSE;
ulint srv_n_rows_inserted = 0;
ulint srv_n_rows_updated = 0;
ulint srv_n_rows_deleted = 0;
ulint srv_n_rows_read = 0;
ibool srv_print_innodb_monitor = FALSE; ibool srv_print_innodb_monitor = FALSE;
ibool srv_print_innodb_lock_monitor = FALSE;
ibool srv_print_innodb_tablespace_monitor = FALSE;
/* The parameters below are obsolete: */ /* The parameters below are obsolete: */
...@@ -137,6 +144,11 @@ ulint srv_test_n_reserved_rnds = ULINT_MAX; ...@@ -137,6 +144,11 @@ ulint srv_test_n_reserved_rnds = ULINT_MAX;
ulint srv_test_array_size = ULINT_MAX; ulint srv_test_array_size = ULINT_MAX;
ulint srv_test_n_mutexes = ULINT_MAX; ulint srv_test_n_mutexes = ULINT_MAX;
/* Array of English strings describing the current state of an
i/o handler thread */
char* srv_io_thread_op_info[SRV_MAX_N_IO_THREADS];
/* /*
IMPLEMENTATION OF THE SERVER MAIN PROGRAM IMPLEMENTATION OF THE SERVER MAIN PROGRAM
========================================= =========================================
...@@ -1926,23 +1938,25 @@ loop: ...@@ -1926,23 +1938,25 @@ loop:
} }
background_loop: background_loop:
/* In this loop we run background operations while the server /* In this loop we run background operations when the server
is quiet */ is quiet */
current_time = time(NULL); current_time = time(NULL);
if (srv_print_innodb_monitor if (difftime(current_time, last_monitor_time) > 15) {
&& difftime(current_time, last_monitor_time) > 8) {
printf("================================\n");
last_monitor_time = time(NULL); last_monitor_time = time(NULL);
if (srv_print_innodb_monitor) {
printf("=====================================\n");
ut_print_timestamp(stdout); ut_print_timestamp(stdout);
printf(" INNODB MONITOR OUTPUT\n" printf(" INNODB MONITOR OUTPUT\n"
"================================\n"); "=====================================\n");
printf("--------------------------\n" printf("------------\n"
"LOCKS HELD BY TRANSACTIONS\n" "TRANSACTIONS\n"
"--------------------------\n"); "------------\n");
lock_print_info(); lock_print_info();
printf("-----------------------------------------------\n" printf("-----------------------------------------------\n"
"CURRENT SEMAPHORES RESERVED AND SEMAPHORE WAITS\n" "CURRENT SEMAPHORES RESERVED AND SEMAPHORE WAITS\n"
...@@ -1955,11 +1969,40 @@ background_loop: ...@@ -1955,11 +1969,40 @@ background_loop:
"BUFFER POOL\n" "BUFFER POOL\n"
"-----------\n"); "-----------\n");
buf_print_io(); 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" printf("----------------------------\n"
"END OF INNODB MONITOR OUTPUT\n" "END OF INNODB MONITOR OUTPUT\n"
"============================\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");
}
}
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) { if (srv_activity_count != old_activity_count) {
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
...@@ -2009,8 +2052,18 @@ background_loop: ...@@ -2009,8 +2052,18 @@ background_loop:
} }
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
if (srv_print_innodb_monitor) {
ut_print_timestamp(stdout);
printf(" InnoDB (main thread) starts buffer pool flush\n");
}
n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max); 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);
}
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
if (srv_activity_count != old_activity_count) { if (srv_activity_count != old_activity_count) {
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
...@@ -2038,12 +2091,7 @@ background_loop: ...@@ -2038,12 +2091,7 @@ background_loop:
/* mem_print_new_info(); /* mem_print_new_info();
*/ */
/*
fsp_print(0);
fprintf(stderr, "Validating tablespace\n");
fsp_validate(0);
fprintf(stderr, "Validation ok\n");
*/
#ifdef UNIV_SEARCH_PERF_STAT #ifdef UNIV_SEARCH_PERF_STAT
/* btr_search_print_info(); */ /* btr_search_print_info(); */
#endif #endif
......
...@@ -67,8 +67,6 @@ os_file_t files[1000]; ...@@ -67,8 +67,6 @@ os_file_t files[1000];
mutex_t ios_mutex; mutex_t ios_mutex;
ulint ios; ulint ios;
#define SRV_MAX_N_IO_THREADS 1000
ulint n[SRV_MAX_N_IO_THREADS + 5]; ulint n[SRV_MAX_N_IO_THREADS + 5];
os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 5]; os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 5];
...@@ -591,6 +589,11 @@ innobase_start_or_create_for_mysql(void) ...@@ -591,6 +589,11 @@ innobase_start_or_create_for_mysql(void)
return((int) err); return((int) err);
} }
/* Restrict the maximum number of file i/o threads */
if (srv_n_file_io_threads > SRV_MAX_N_IO_THREADS) {
srv_n_file_io_threads = SRV_MAX_N_IO_THREADS;
}
#if !(defined(WIN_ASYNC_IO) || defined(POSIX_ASYNC_IO)) #if !(defined(WIN_ASYNC_IO) || defined(POSIX_ASYNC_IO))
/* In simulated aio we currently have use only for 4 threads */ /* In simulated aio we currently have use only for 4 threads */
......
...@@ -438,6 +438,8 @@ sync_array_cell_print( ...@@ -438,6 +438,8 @@ sync_array_cell_print(
/*==================*/ /*==================*/
sync_cell_t* cell) /* in: sync cell */ sync_cell_t* cell) /* in: sync cell */
{ {
mutex_t* mutex;
rw_lock_t* rwlock;
char* str = NULL; char* str = NULL;
ulint type; ulint type;
...@@ -445,15 +447,39 @@ sync_array_cell_print( ...@@ -445,15 +447,39 @@ sync_array_cell_print(
if (type == SYNC_MUTEX) { if (type == SYNC_MUTEX) {
str = "MUTEX ENTER"; str = "MUTEX ENTER";
} else if (type == RW_LOCK_EX) { mutex = (mutex_t*)cell->wait_object;
printf("Mutex created in file %s line %lu",
mutex->cfile_name, mutex->cline);
} else if (type == RW_LOCK_EX || type == RW_LOCK_SHARED) {
if (type == RW_LOCK_EX) {
str = "X-LOCK"; str = "X-LOCK";
} else if (type == RW_LOCK_SHARED) { } else {
str = "S-LOCK"; str = "S_LOCK";
}
rwlock = (rw_lock_t*)cell->wait_object;
printf("Rw-latch created in file %s line %lu",
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",
(ulint)rwlock->writer_thread);
}
if (rwlock->reader_count > 0) {
printf(" readers %lu", rwlock->reader_count);
}
} else { } else {
ut_error; ut_error;
} }
printf("%lx waited for by thread %lu op. %s file %s line %lu ", printf(" at addr %lx waited for by thread %lu op. %s file %s line %lu ",
(ulint)cell->wait_object, (ulint)cell->wait_object,
(ulint)cell->thread, (ulint)cell->thread,
str, cell->file, cell->line); str, cell->file, cell->line);
......
...@@ -99,6 +99,8 @@ trx_rollback_for_mysql( ...@@ -99,6 +99,8 @@ trx_rollback_for_mysql(
return(DB_SUCCESS); return(DB_SUCCESS);
} }
trx->op_info = "rollback";
/* Tell Innobase server that there might be work for /* Tell Innobase server that there might be work for
utility threads: */ utility threads: */
...@@ -111,6 +113,8 @@ trx_rollback_for_mysql( ...@@ -111,6 +113,8 @@ trx_rollback_for_mysql(
srv_active_wake_master_thread(); srv_active_wake_master_thread();
trx->op_info = "";
return(err); return(err);
} }
...@@ -130,6 +134,8 @@ trx_rollback_last_sql_stat_for_mysql( ...@@ -130,6 +134,8 @@ trx_rollback_last_sql_stat_for_mysql(
return(DB_SUCCESS); return(DB_SUCCESS);
} }
trx->op_info = "rollback of SQL statement";
/* Tell Innobase server that there might be work for /* Tell Innobase server that there might be work for
utility threads: */ utility threads: */
...@@ -144,6 +150,8 @@ trx_rollback_last_sql_stat_for_mysql( ...@@ -144,6 +150,8 @@ trx_rollback_last_sql_stat_for_mysql(
srv_active_wake_master_thread(); srv_active_wake_master_thread();
trx->op_info = "";
return(err); return(err);
} }
......
...@@ -511,6 +511,7 @@ trx_sys_init_at_db_start(void) ...@@ -511,6 +511,7 @@ trx_sys_init_at_db_start(void)
TRX_SYS_TRX_ID_WRITE_MARGIN), TRX_SYS_TRX_ID_WRITE_MARGIN),
2 * TRX_SYS_TRX_ID_WRITE_MARGIN); 2 * TRX_SYS_TRX_ID_WRITE_MARGIN);
UT_LIST_INIT(trx_sys->mysql_trx_list);
trx_lists_init_at_db_start(); trx_lists_init_at_db_start();
if (UT_LIST_GET_LEN(trx_sys->trx_list) > 0) { if (UT_LIST_GET_LEN(trx_sys->trx_list) > 0) {
......
...@@ -24,6 +24,12 @@ Created 3/26/1996 Heikki Tuuri ...@@ -24,6 +24,12 @@ Created 3/26/1996 Heikki Tuuri
#include "thr0loc.h" #include "thr0loc.h"
#include "btr0sea.h" #include "btr0sea.h"
/* Copy of the prototype for innobase_mysql_print_thd: this
copy must be equal to the one in mysql/sql/ha_innobase.cc ! */
void innobase_mysql_print_thd(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;
...@@ -58,11 +64,15 @@ trx_create( ...@@ -58,11 +64,15 @@ trx_create(
trx = mem_alloc(sizeof(trx_t)); trx = mem_alloc(sizeof(trx_t));
trx->op_info = "";
trx->type = TRX_USER; trx->type = TRX_USER;
trx->conc_state = TRX_NOT_STARTED; trx->conc_state = TRX_NOT_STARTED;
trx->dict_operation = FALSE; trx->dict_operation = FALSE;
trx->mysql_thd = NULL;
trx->n_mysql_tables_in_use = 0; trx->n_mysql_tables_in_use = 0;
trx->mysql_n_tables_locked = 0; trx->mysql_n_tables_locked = 0;
...@@ -129,6 +139,8 @@ trx_allocate_for_mysql(void) ...@@ -129,6 +139,8 @@ trx_allocate_for_mysql(void)
trx_n_mysql_transactions++; trx_n_mysql_transactions++;
UT_LIST_ADD_FIRST(mysql_trx_list, trx_sys->mysql_trx_list, trx);
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
trx->mysql_thread_id = os_thread_get_curr_id(); trx->mysql_thread_id = os_thread_get_curr_id();
...@@ -209,6 +221,8 @@ trx_free_for_mysql( ...@@ -209,6 +221,8 @@ trx_free_for_mysql(
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
UT_LIST_REMOVE(mysql_trx_list, trx_sys->mysql_trx_list, trx);
trx_free(trx); trx_free(trx);
ut_a(trx_n_mysql_transactions > 0); ut_a(trx_n_mysql_transactions > 0);
...@@ -1268,6 +1282,8 @@ trx_commit_for_mysql( ...@@ -1268,6 +1282,8 @@ trx_commit_for_mysql(
sig to the transaction, we must here make sure that trx has been sig to the transaction, we must here make sure that trx has been
started. */ started. */
trx->op_info = "committing";
trx_start_if_not_started(trx); trx_start_if_not_started(trx);
mutex_enter(&kernel_mutex); mutex_enter(&kernel_mutex);
...@@ -1276,6 +1292,8 @@ trx_commit_for_mysql( ...@@ -1276,6 +1292,8 @@ trx_commit_for_mysql(
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
trx->op_info = "";
return(0); return(0);
} }
...@@ -1295,3 +1313,78 @@ trx_mark_sql_stat_end( ...@@ -1295,3 +1313,78 @@ trx_mark_sql_stat_end(
mutex_exit(&kernel_mutex); mutex_exit(&kernel_mutex);
} }
/**************************************************************************
Marks the latest SQL statement ended but does not start a new transaction
if the trx is not started. */
void
trx_mark_sql_stat_end_do_not_start_new(
/*===================================*/
trx_t* trx) /* in: trx handle */
{
mutex_enter(&kernel_mutex);
trx->last_sql_stat_start.least_undo_no = trx->undo_no;
mutex_exit(&kernel_mutex);
}
/**************************************************************************
Prints info about a transaction to the standard output. The caller must
own the kernel mutex. */
void
trx_print(
/*======*/
trx_t* trx) /* in: transaction */
{
printf("TRANSACTION %lu %lu, OS thread id %lu",
ut_dulint_get_high(trx->id),
ut_dulint_get_low(trx->id),
(ulint)trx->mysql_thread_id);
if (ut_strlen(trx->op_info) > 0) {
printf(" %s", trx->op_info);
}
if (trx->type != TRX_USER) {
printf(" purge trx");
}
switch (trx->conc_state) {
case TRX_NOT_STARTED: printf(", not started"); break;
case TRX_ACTIVE: printf(", active"); break;
case TRX_COMMITTED_IN_MEMORY: printf(", committed in memory");
break;
default: printf(" state %lu", trx->conc_state);
}
switch (trx->que_state) {
case TRX_QUE_RUNNING: printf(", runs or sleeps"); break;
case TRX_QUE_LOCK_WAIT: printf(", lock wait"); break;
case TRX_QUE_ROLLING_BACK: printf(", rolling back"); break;
case TRX_QUE_COMMITTING: printf(", committing"); break;
default: printf(" que state %lu", trx->que_state);
}
if (0 < UT_LIST_GET_LEN(trx->trx_locks)) {
printf(", has %lu lock struct(s)",
UT_LIST_GET_LEN(trx->trx_locks));
}
if (trx->has_search_latch) {
printf(", holds adaptive hash latch");
}
if (ut_dulint_cmp(trx->undo_no, ut_dulint_zero) != 0) {
printf(", undo log entries %lu",
ut_dulint_get_low(trx->undo_no));
}
printf("\n");
if (trx->mysql_thd != NULL) {
innobase_mysql_print_thd(trx->mysql_thd);
}
}
...@@ -180,6 +180,47 @@ convert_error_code_to_mysql( ...@@ -180,6 +180,47 @@ convert_error_code_to_mysql(
} }
} }
extern "C" {
/*****************************************************************
Prints info of a THD object (== user session thread) to the
standatd output. NOTE that mysql/innobase/trx/trx0trx.c must contain
the prototype for this function! */
void
innobase_mysql_print_thd(
/*=====================*/
void* input_thd)/* in: pointer to a MySQL THD object */
{
THD* thd;
thd = (THD*) input_thd;
printf("MySQL thread id %lu, query id %lu",
thd->thread_id, thd->query_id);
if (thd->host) {
printf(" %s", thd->host);
}
if (thd->ip) {
printf(" %s", thd->ip);
}
if (thd->user) {
printf(" %s", thd->user);
}
if (thd->proc_info) {
printf(" %s", thd->proc_info);
}
if (thd->query) {
printf(" %0.100s", thd->query);
}
printf("\n");
}
}
/************************************************************************* /*************************************************************************
Gets the InnoDB transaction handle for a MySQL handler object, creates Gets the InnoDB transaction handle for a MySQL handler object, creates
an InnoDB transaction struct if the corresponding MySQL thread struct still an InnoDB transaction struct if the corresponding MySQL thread struct still
...@@ -199,6 +240,8 @@ check_trx_exists( ...@@ -199,6 +240,8 @@ check_trx_exists(
dbug_assert(thd != NULL); dbug_assert(thd != NULL);
trx = trx_allocate_for_mysql(); trx = trx_allocate_for_mysql();
trx->mysql_thd = thd;
thd->transaction.all.innobase_tid = trx; thd->transaction.all.innobase_tid = trx;
/* The execution of a single SQL statement is denoted by /* The execution of a single SQL statement is denoted by
...@@ -633,7 +676,7 @@ innobase_commit( ...@@ -633,7 +676,7 @@ innobase_commit(
if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) { if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) {
trx_commit_for_mysql(trx); trx_commit_for_mysql(trx);
trx_mark_sql_stat_end(trx); trx_mark_sql_stat_end_do_not_start_new(trx);
} else { } else {
trx_mark_sql_stat_end(trx); trx_mark_sql_stat_end(trx);
} }
...@@ -672,6 +715,7 @@ innobase_rollback( ...@@ -672,6 +715,7 @@ innobase_rollback(
if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) { if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) {
error = trx_rollback_for_mysql(trx); error = trx_rollback_for_mysql(trx);
trx_mark_sql_stat_end_do_not_start_new(trx);
} else { } else {
error = trx_rollback_last_sql_stat_for_mysql(trx); error = trx_rollback_last_sql_stat_for_mysql(trx);
trx_mark_sql_stat_end(trx); trx_mark_sql_stat_end(trx);
...@@ -1334,8 +1378,15 @@ ha_innobase::write_row( ...@@ -1334,8 +1378,15 @@ ha_innobase::write_row(
autoincrement field */ autoincrement field */
auto_inc = table->next_number_field->val_int(); auto_inc = table->next_number_field->val_int();
if (auto_inc == 0)
auto_inc= user_thd->next_insert_id; /* In replication and also otherwise the auto-inc column
can be set with SET INSERT_ID. Then we must look at
user_thd->next_insert_id. If it is nonzero and the user
has not supplied a value, we must use it. */
if (auto_inc == 0 && user_thd->next_insert_id != 0) {
auto_inc = user_thd->next_insert_id;
}
if (auto_inc != 0) { if (auto_inc != 0) {
/* This call will calculate the max of the /* This call will calculate the max of the
...@@ -2221,7 +2272,7 @@ ha_innobase::external_lock( ...@@ -2221,7 +2272,7 @@ ha_innobase::external_lock(
if (trx->n_mysql_tables_in_use == 0) { if (trx->n_mysql_tables_in_use == 0) {
trx_mark_sql_stat_end(trx); trx_mark_sql_stat_end(trx);
} }
thd->transaction.all.innodb_active_trans=1; thd->transaction.all.innodb_active_trans = 1;
trx->n_mysql_tables_in_use++; trx->n_mysql_tables_in_use++;
if (prebuilt->select_lock_type != LOCK_NONE) { if (prebuilt->select_lock_type != LOCK_NONE) {
...@@ -2639,6 +2690,10 @@ ha_innobase::records_in_range( ...@@ -2639,6 +2690,10 @@ ha_innobase::records_in_range(
DBUG_ENTER("records_in_range"); DBUG_ENTER("records_in_range");
if (prebuilt->trx) {
prebuilt->trx->op_info = "estimating range size";
}
active_index = keynr; active_index = keynr;
key = table->key_info + active_index; key = table->key_info + active_index;
...@@ -2671,6 +2726,10 @@ ha_innobase::records_in_range( ...@@ -2671,6 +2726,10 @@ ha_innobase::records_in_range(
my_free((char*) key_val_buff2, MYF(0)); my_free((char*) key_val_buff2, MYF(0));
if (prebuilt->trx) {
prebuilt->trx->op_info = "";
}
DBUG_RETURN((ha_rows) n_rows); DBUG_RETURN((ha_rows) n_rows);
} }
...@@ -2690,6 +2749,11 @@ ha_innobase::estimate_number_of_rows(void) ...@@ -2690,6 +2749,11 @@ ha_innobase::estimate_number_of_rows(void)
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
dict_table_t* ib_table; dict_table_t* ib_table;
if (prebuilt->trx) {
prebuilt->trx->op_info =
"estimating upper bound of table size";
}
DBUG_ENTER("info"); DBUG_ENTER("info");
ib_table = prebuilt->table; ib_table = prebuilt->table;
...@@ -2702,6 +2766,10 @@ ha_innobase::estimate_number_of_rows(void) ...@@ -2702,6 +2766,10 @@ ha_innobase::estimate_number_of_rows(void)
/* The minimum clustered index record size is 20 bytes */ /* The minimum clustered index record size is 20 bytes */
if (prebuilt->trx) {
prebuilt->trx->op_info = "";
}
return((ha_rows) (1000 + data_file_length / 20)); return((ha_rows) (1000 + data_file_length / 20));
} }
...@@ -2740,6 +2808,10 @@ ha_innobase::info( ...@@ -2740,6 +2808,10 @@ ha_innobase::info(
DBUG_ENTER("info"); DBUG_ENTER("info");
if (prebuilt->trx) {
prebuilt->trx->op_info = "calculating table stats";
}
ib_table = prebuilt->table; ib_table = prebuilt->table;
if (flag & HA_STATUS_TIME) { if (flag & HA_STATUS_TIME) {
...@@ -2802,6 +2874,10 @@ ha_innobase::info( ...@@ -2802,6 +2874,10 @@ ha_innobase::info(
trx_get_error_info(prebuilt->trx)); trx_get_error_info(prebuilt->trx));
} }
if (prebuilt->trx) {
prebuilt->trx->op_info = "";
}
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
......
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