1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-27 18:02:13 +03:00

merge of mysql-5.5 into mysql-5.5-wl1054

This commit is contained in:
Georgi Kodinov
2010-09-20 17:17:32 +03:00
503 changed files with 25265 additions and 6911 deletions

View File

@ -548,10 +548,25 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list)
DBUG_RETURN(TRUE);
}
if (delayed_get_table(thd, table_list))
/*
In order for the deadlock detector to be able to find any deadlocks
caused by the handler thread locking this table, we take the metadata
lock inside the connection thread. If this goes ok, the ticket is cloned
and added to the list of granted locks held by the handler thread.
*/
MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
if (thd->mdl_context.acquire_lock(&table_list->mdl_request,
thd->variables.lock_wait_timeout))
/*
If a lock can't be acquired, it makes no sense to try normal insert.
Therefore we just abort the statement.
*/
DBUG_RETURN(TRUE);
if (table_list->table)
bool error= FALSE;
if (delayed_get_table(thd, table_list))
error= TRUE;
else if (table_list->table)
{
/*
Open tables used for sub-selects or in stored functions, will also
@ -560,16 +575,36 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list)
if (open_and_lock_tables(thd, table_list->next_global, TRUE, 0))
{
end_delayed_insert(thd);
DBUG_RETURN(TRUE);
error= TRUE;
}
else
{
/*
First table was not processed by open_and_lock_tables(),
we need to set updatability flag "by hand".
*/
if (!table_list->derived && !table_list->view)
table_list->updatable= 1; // usual table
}
/*
First table was not processed by open_and_lock_tables(),
we need to set updatability flag "by hand".
*/
if (!table_list->derived && !table_list->view)
table_list->updatable= 1; // usual table
DBUG_RETURN(FALSE);
}
/*
If a lock was acquired above, we should release it after
handle_delayed_insert() has cloned the ticket. Note that acquire_lock() can
succeed because the connection already has the lock. In this case the ticket
will be before the mdl_savepoint and we should not release it here.
*/
if (!thd->mdl_context.has_lock(mdl_savepoint, table_list->mdl_request.ticket))
thd->mdl_context.release_lock(table_list->mdl_request.ticket);
/*
Reset the ticket in case we end up having to use normal insert and
therefore will reopen the table and reacquire the metadata lock.
*/
table_list->mdl_request.ticket= NULL;
if (error || table_list->table)
DBUG_RETURN(error);
#endif
/*
* This is embedded library and we don't have auxiliary
@ -1801,14 +1836,25 @@ public:
mysql_cond_t cond, cond_client;
volatile uint tables_in_use,stacked_inserts;
volatile bool status;
/*
When the handler thread starts, it clones a metadata lock ticket
for the table to be inserted. This is done to allow the deadlock
detector to detect deadlocks resulting from this lock.
Before this is done, the connection thread cannot safely exit
without causing problems for clone_ticket().
Once handler_thread_initialized has been set, it is safe for the
connection thread to exit.
Access to handler_thread_initialized is protected by di->mutex.
*/
bool handler_thread_initialized;
COPY_INFO info;
I_List<delayed_row> rows;
ulong group_count;
TABLE_LIST table_list; // Argument
Delayed_insert()
:locks_in_memory(0),
table(0),tables_in_use(0),stacked_inserts(0), status(0), group_count(0)
:locks_in_memory(0), table(0),tables_in_use(0),stacked_inserts(0),
status(0), handler_thread_initialized(FALSE), group_count(0)
{
DBUG_ENTER("Delayed_insert constructor");
thd.security_ctx->user=(char*) delayed_user;
@ -2027,6 +2073,10 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
/* Replace volatile strings with local copies */
di->table_list.alias= di->table_list.table_name= di->thd.query();
di->table_list.db= di->thd.db;
/* We need the ticket so that it can be cloned in handle_delayed_insert */
init_mdl_requests(&di->table_list);
di->table_list.mdl_request.ticket= table_list->mdl_request.ticket;
di->lock();
mysql_mutex_lock(&di->mutex);
if ((error= mysql_thread_create(key_thread_delayed_insert,
@ -2043,9 +2093,15 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
goto end_create;
}
/* Wait until table is open */
/*
Wait until table is open unless the handler thread or the connection
thread has been killed. Note that we in all cases must wait until the
handler thread has been properly initialized before exiting. Otherwise
we risk doing clone_ticket() on a ticket that is no longer valid.
*/
thd_proc_info(thd, "waiting for handler open");
while (!di->thd.killed && !di->table && !thd->killed)
while (!di->handler_thread_initialized ||
(!di->thd.killed && !di->table && !thd->killed))
{
mysql_cond_wait(&di->cond_client, &di->mutex);
}
@ -2473,6 +2529,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
/* Can't use my_error since store_globals has not yet been called */
thd->stmt_da->set_error_status(thd, ER_OUT_OF_RESOURCES,
ER(ER_OUT_OF_RESOURCES), NULL);
di->handler_thread_initialized= TRUE;
}
else
{
@ -2483,6 +2540,7 @@ pthread_handler_t handle_delayed_insert(void *arg)
/* Can't use my_error since store_globals has perhaps failed */
thd->stmt_da->set_error_status(thd, ER_OUT_OF_RESOURCES,
ER(ER_OUT_OF_RESOURCES), NULL);
di->handler_thread_initialized= TRUE;
thd->fatal_error();
goto err;
}
@ -2495,7 +2553,24 @@ pthread_handler_t handle_delayed_insert(void *arg)
thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_DELAYED);
thd->set_current_stmt_binlog_format_row_if_mixed();
init_mdl_requests(&di->table_list);
/*
Clone the ticket representing the lock on the target table for
the insert and add it to the list of granted metadata locks held by
the handler thread. This is safe since the handler thread is
not holding nor waiting on any metadata locks.
*/
if (thd->mdl_context.clone_ticket(&di->table_list.mdl_request))
{
di->handler_thread_initialized= TRUE;
goto err;
}
/*
Now that the ticket has been cloned, it is safe for the connection
thread to exit.
*/
di->handler_thread_initialized= TRUE;
di->table_list.mdl_request.ticket= NULL;
if (di->open_and_lock_table())
goto err;
@ -2707,7 +2782,7 @@ bool Delayed_insert::handle_inserts(void)
thd_proc_info(&thd, "insert");
max_rows= delayed_insert_limit;
if (thd.killed || table->s->needs_reopen())
if (thd.killed || table->s->has_old_version())
{
thd.killed= THD::KILL_CONNECTION;
max_rows= ULONG_MAX; // Do as much as possible
@ -3045,6 +3120,9 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
we are fixing fields from insert list.
*/
lex->current_select= &lex->select_lex;
/* Errors during check_insert_fields() should not be ignored. */
lex->current_select->no_error= FALSE;
res= (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0) ||
check_insert_fields(thd, table_list, *fields, values,
!insert_into_view, 1, &map));
@ -3578,19 +3656,8 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
if (!mysql_create_table_no_lock(thd, create_table->db,
create_table->table_name,
create_info, alter_info, 0,
select_field_count))
select_field_count, NULL))
{
if (create_info->table_existed)
{
/*
This means that someone created table underneath server
or it was created via different mysqld front-end to the
cluster. We don't have much options but throw an error.
*/
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_table->table_name);
DBUG_RETURN(0);
}
DBUG_EXECUTE_IF("sleep_create_select_before_open", my_sleep(6000000););
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
@ -3602,11 +3669,9 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
*/
if (open_table(thd, create_table, thd->mem_root, &ot_ctx))
{
mysql_mutex_lock(&LOCK_open);
quick_rm_table(create_info->db_type, create_table->db,
table_case_name(create_info, create_table->table_name),
0);
mysql_mutex_unlock(&LOCK_open);
}
else
table= create_table->table;
@ -3621,7 +3686,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
it preparable for open. But let us do close_temporary_table() here
just in case.
*/
drop_temporary_table(thd, create_table);
drop_temporary_table(thd, create_table, NULL);
}
else
table= create_table->table;
@ -3708,15 +3773,13 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
TABLE const *const table = *tables;
if (thd->is_current_stmt_binlog_format_row() &&
!table->s->tmp_table &&
!ptr->get_create_info()->table_existed)
!table->s->tmp_table)
{
if (int error= ptr->binlog_show_create_table(tables, count))
return error;
}
return 0;
}
select_create *ptr;
TABLE_LIST *create_table;
TABLE_LIST *select_tables;
@ -3739,34 +3802,15 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
thd->binlog_start_trans_and_stmt();
}
DBUG_ASSERT(create_table->table == NULL);
DBUG_EXECUTE_IF("sleep_create_select_before_check_if_exists", my_sleep(6000000););
if (create_table->table)
{
/* Table already exists and was open at open_and_lock_tables() stage. */
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
{
/* Mark that table existed */
create_info->table_existed= 1;
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
create_table->table_name);
if (thd->is_current_stmt_binlog_format_row())
binlog_show_create_table(&(create_table->table), 1);
table= create_table->table;
}
else
{
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_table->table_name);
DBUG_RETURN(-1);
}
}
else
if (!(table= create_table_from_items(thd, create_info, create_table,
alter_info, &values,
&extra_lock, hook_ptr)))
/* abort() deletes table */
DBUG_RETURN(-1);
if (!(table= create_table_from_items(thd, create_info, create_table,
alter_info, &values,
&extra_lock, hook_ptr)))
/* abort() deletes table */
DBUG_RETURN(-1);
if (extra_lock)
{
@ -3886,10 +3930,6 @@ void select_create::send_error(uint errcode,const char *err)
("Current table (at 0x%lu) %s a temporary (or non-existant) table",
(ulong) table,
table && !table->s->tmp_table ? "is NOT" : "is"));
DBUG_PRINT("info",
("Table %s prior to executing this statement",
get_create_info()->table_existed ? "existed" : "did not exist"));
/*
This will execute any rollbacks that are necessary before writing
the transcation cache.
@ -3978,8 +4018,7 @@ void select_create::abort_result_set()
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
table->auto_increment_field_not_null= FALSE;
if (!create_info->table_existed)
drop_open_table(thd, table, create_table->db, create_table->table_name);
drop_open_table(thd, table, create_table->db, create_table->table_name);
table=0; // Safety
}
DBUG_VOID_RETURN;