Add more comments to open_table and open_tables. No real changes.
This commit is contained in:
parent
8251e016d7
commit
d9227f159f
114
sql/sql_base.cc
114
sql/sql_base.cc
@ -1210,6 +1210,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
int4store(key + key_length, thd->server_id);
|
int4store(key + key_length, thd->server_id);
|
||||||
int4store(key + key_length + 4, thd->variables.pseudo_thread_id);
|
int4store(key + key_length + 4, thd->variables.pseudo_thread_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Unless requested otherwise, try to resolve this table in the list
|
||||||
|
of temporary tables of this thread. In MySQL temporary tables
|
||||||
|
are always thread-local and "shadow" possible base tables with the
|
||||||
|
same name. This block implements the behaviour.
|
||||||
|
TODO: move this block into a separate function.
|
||||||
|
*/
|
||||||
if (!table_list->skip_temporary)
|
if (!table_list->skip_temporary)
|
||||||
{
|
{
|
||||||
for (table= thd->temporary_tables; table ; table=table->next)
|
for (table= thd->temporary_tables; table ; table=table->next)
|
||||||
@ -1218,6 +1225,12 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
!memcmp(table->s->table_cache_key, key,
|
!memcmp(table->s->table_cache_key, key,
|
||||||
key_length + TMP_TABLE_KEY_EXTRA))
|
key_length + TMP_TABLE_KEY_EXTRA))
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
We're trying to use the same temporary table twice in a query.
|
||||||
|
Right now we don't support this because a temporary table
|
||||||
|
is always represented by only one TABLE object in THD, and
|
||||||
|
it can not be cloned. Emit an error for an unsupported behaviour.
|
||||||
|
*/
|
||||||
if (table->query_id == thd->query_id ||
|
if (table->query_id == thd->query_id ||
|
||||||
thd->prelocked_mode && table->query_id)
|
thd->prelocked_mode && table->query_id)
|
||||||
{
|
{
|
||||||
@ -1233,6 +1246,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The table is not temporary - if we're in pre-locked or LOCK TABLES
|
||||||
|
mode, let's try to find the requested table in the list of pre-opened
|
||||||
|
and locked tables. If the table is not there, return an error - we can't
|
||||||
|
open not pre-opened tables in pre-locked/LOCK TABLES mode.
|
||||||
|
TODO: move this block into a separate function.
|
||||||
|
*/
|
||||||
if (!(flags & MYSQL_OPEN_IGNORE_LOCKED_TABLES) &&
|
if (!(flags & MYSQL_OPEN_IGNORE_LOCKED_TABLES) &&
|
||||||
(thd->locked_tables || thd->prelocked_mode))
|
(thd->locked_tables || thd->prelocked_mode))
|
||||||
{ // Using table locks
|
{ // Using table locks
|
||||||
@ -1304,7 +1324,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
goto reset;
|
goto reset;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
is it view?
|
Is this table a view and not a base table?
|
||||||
(it is work around to allow to open view with locked tables,
|
(it is work around to allow to open view with locked tables,
|
||||||
real fix will be made after definition cache will be made)
|
real fix will be made after definition cache will be made)
|
||||||
*/
|
*/
|
||||||
@ -1338,8 +1358,32 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Non pre-locked/LOCK TABLES mode, and the table is not temporary:
|
||||||
|
this is the normal use case.
|
||||||
|
Now we should:
|
||||||
|
- try to find the table in the table cache.
|
||||||
|
- if one of the discovered TABLE instances is name-locked
|
||||||
|
(table->s->version == 0) or some thread has started FLUSH TABLES
|
||||||
|
(refresh_version > table->s->version), back off -- we have to wait
|
||||||
|
until no one holds a name lock on the table.
|
||||||
|
- if there is no such TABLE in the name cache, read the table definition
|
||||||
|
and insert it into the cache.
|
||||||
|
We perform all of the above under LOCK_open which currently protects
|
||||||
|
the open cache (also known as table cache) and table definitions stored
|
||||||
|
on disk.
|
||||||
|
*/
|
||||||
|
|
||||||
VOID(pthread_mutex_lock(&LOCK_open));
|
VOID(pthread_mutex_lock(&LOCK_open));
|
||||||
|
|
||||||
|
/*
|
||||||
|
If it's the first table from a list of tables used in a query,
|
||||||
|
remember refresh_version (the version of open_cache state).
|
||||||
|
If the version changes while we're opening the remaining tables,
|
||||||
|
we will have to back off, close all the tables opened-so-far,
|
||||||
|
and try to reopen them.
|
||||||
|
Note: refresh_version is currently changed only during FLUSH TABLES.
|
||||||
|
*/
|
||||||
if (!thd->open_tables)
|
if (!thd->open_tables)
|
||||||
thd->version=refresh_version;
|
thd->version=refresh_version;
|
||||||
else if ((thd->version != refresh_version) &&
|
else if ((thd->version != refresh_version) &&
|
||||||
@ -1356,12 +1400,39 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
if (thd->handler_tables)
|
if (thd->handler_tables)
|
||||||
mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE);
|
mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Actually try to find the table in the open_cache.
|
||||||
|
The cache may contain several "TABLE" instances for the same
|
||||||
|
physical table. The instances that are currently "in use" by
|
||||||
|
some thread have their "in_use" member != NULL.
|
||||||
|
There is no good reason for having more than one entry in the
|
||||||
|
hash for the same physical table, except that we use this as
|
||||||
|
an implicit "pending locks queue" - see
|
||||||
|
wait_for_locked_table_names for details.
|
||||||
|
*/
|
||||||
for (table= (TABLE*) hash_first(&open_cache, (byte*) key, key_length,
|
for (table= (TABLE*) hash_first(&open_cache, (byte*) key, key_length,
|
||||||
&state);
|
&state);
|
||||||
table && table->in_use ;
|
table && table->in_use ;
|
||||||
table= (TABLE*) hash_next(&open_cache, (byte*) key, key_length,
|
table= (TABLE*) hash_next(&open_cache, (byte*) key, key_length,
|
||||||
&state))
|
&state))
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
Normally, table->s->version contains the value of
|
||||||
|
refresh_version from the moment when this table was
|
||||||
|
(re-)opened and added to the cache.
|
||||||
|
If since then we did (or just started) FLUSH TABLES
|
||||||
|
statement, refresh_version has been increased.
|
||||||
|
For "name-locked" TABLE instances, table->s->version is set
|
||||||
|
to 0 (see lock_table_name for details).
|
||||||
|
In case there is a pending FLUSH TABLES or a name lock, we
|
||||||
|
need to back off and re-start opening tables.
|
||||||
|
If we do not back off now, we may dead lock in case of lock
|
||||||
|
order mismatch with some other thread:
|
||||||
|
c1: name lock t1; -- sort of exclusive lock
|
||||||
|
c2: open t2; -- sort of shared lock
|
||||||
|
c1: name lock t2; -- blocks
|
||||||
|
c2: open t1; -- blocks
|
||||||
|
*/
|
||||||
if (table->s->version != refresh_version)
|
if (table->s->version != refresh_version)
|
||||||
{
|
{
|
||||||
DBUG_PRINT("note",
|
DBUG_PRINT("note",
|
||||||
@ -1375,16 +1446,35 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
There is a refresh in progress for this table
|
Back off, part 1: mark the table as "unused" for the
|
||||||
Wait until the table is freed or the thread is killed.
|
purpose of name-locking by setting table->db_stat to 0. Do
|
||||||
|
that only for the tables in this thread that have an old
|
||||||
|
table->s->version (this is an optimization (?)).
|
||||||
|
table->db_stat == 0 signals wait_for_locked_table_names
|
||||||
|
that the tables in question are not used any more. See
|
||||||
|
table_is_used call for details.
|
||||||
*/
|
*/
|
||||||
close_old_data_files(thd,thd->open_tables,0,0);
|
close_old_data_files(thd,thd->open_tables,0,0);
|
||||||
|
/*
|
||||||
|
Back-off part 2: try to avoid "busy waiting" on the table:
|
||||||
|
if the table is in use by some other thread, we suspend
|
||||||
|
and wait till the operation is complete: when any
|
||||||
|
operation that juggles with table->s->version completes,
|
||||||
|
it broadcasts COND_refresh condition variable.
|
||||||
|
*/
|
||||||
if (table->in_use != thd)
|
if (table->in_use != thd)
|
||||||
|
{
|
||||||
wait_for_refresh(thd);
|
wait_for_refresh(thd);
|
||||||
|
/* wait_for_refresh will unlock LOCK_open for us */
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
There is a refresh in progress for this table.
|
||||||
|
Signal the caller that it has to try again.
|
||||||
|
*/
|
||||||
if (refresh)
|
if (refresh)
|
||||||
*refresh=1;
|
*refresh=1;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
@ -1392,6 +1482,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
}
|
}
|
||||||
if (table)
|
if (table)
|
||||||
{
|
{
|
||||||
|
/* Unlink the table from "unused_tables" list. */
|
||||||
if (table == unused_tables)
|
if (table == unused_tables)
|
||||||
{ // First unused
|
{ // First unused
|
||||||
unused_tables=unused_tables->next; // Remove from link
|
unused_tables=unused_tables->next; // Remove from link
|
||||||
@ -1404,6 +1495,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* Insert a new TABLE instance into the open cache */
|
||||||
TABLE_SHARE *share;
|
TABLE_SHARE *share;
|
||||||
int error;
|
int error;
|
||||||
/* Free cache if too big */
|
/* Free cache if too big */
|
||||||
@ -2145,6 +2237,10 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
For every table in the list of tables to open, try to find or open
|
||||||
|
a table.
|
||||||
|
*/
|
||||||
for (tables= *start; tables ;tables= tables->next_global)
|
for (tables= *start; tables ;tables= tables->next_global)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -2159,6 +2255,12 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
|||||||
goto process_view_routines;
|
goto process_view_routines;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
If this TABLE_LIST object is a placeholder for an information_schema
|
||||||
|
table, create a temporary table to represent the information_schema
|
||||||
|
table in the query. Do not fill it yet - will be filled during
|
||||||
|
execution.
|
||||||
|
*/
|
||||||
if (tables->schema_table)
|
if (tables->schema_table)
|
||||||
{
|
{
|
||||||
if (!mysql_schema_table(thd, thd->lex, tables))
|
if (!mysql_schema_table(thd, thd->lex, tables))
|
||||||
@ -2167,6 +2269,10 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
|||||||
}
|
}
|
||||||
(*counter)++;
|
(*counter)++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Not a placeholder: must be a base table or a view, and the table is
|
||||||
|
not opened yet. Try to open the table.
|
||||||
|
*/
|
||||||
if (!tables->table &&
|
if (!tables->table &&
|
||||||
!(tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags)))
|
!(tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags)))
|
||||||
{
|
{
|
||||||
@ -2273,7 +2379,7 @@ process_view_routines:
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Serious error during reading stored routines from mysql.proc table.
|
Serious error during reading stored routines from mysql.proc table.
|
||||||
Something's wrong with the table or its contents, and an error has
|
Something is wrong with the table or its contents, and an error has
|
||||||
been emitted; we must abort.
|
been emitted; we must abort.
|
||||||
*/
|
*/
|
||||||
result= -1;
|
result= -1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user