Commit d9227f15 authored by unknown's avatar unknown
Browse files

Add more comments to open_table and open_tables. No real changes.

parent 8251e016
Loading
Loading
Loading
Loading
+111 −5
Original line number Diff line number Diff line
@@ -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 + 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)
  {
    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,
		  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 ||
            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) &&
      (thd->locked_tables || thd->prelocked_mode))
  {						// Using table locks
@@ -1304,7 +1324,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
      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,
      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);
  }

  /*
    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));

  /*
    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)
    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)
    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,
                                  &state);
       table && table->in_use ;
       table= (TABLE*) hash_next(&open_cache, (byte*) key, key_length,
                                 &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)
    {
      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
        Wait until the table is freed or the thread is killed.
        Back off, part 1: mark the table as "unused" for the
        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);
      /*
        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)
      {
	wait_for_refresh(thd);
        /* wait_for_refresh will unlock LOCK_open for us */
      }
      else
      {
	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)
	*refresh=1;
      DBUG_RETURN(0);
@@ -1392,6 +1482,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
  }
  if (table)
  {
    /* Unlink the table from "unused_tables" list. */
    if (table == unused_tables)
    {						// First unused
      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
  {
    /* Insert a new TABLE instance into the open cache */
    TABLE_SHARE *share;
    int error;
    /* 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)
  {
    /*
@@ -2159,6 +2255,12 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
        goto process_view_routines;
      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 (!mysql_schema_table(thd, thd->lex, tables))
@@ -2167,6 +2269,10 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
    }
    (*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 &&
	!(tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags)))
    {
@@ -2273,7 +2379,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
      {
        /*
          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.
        */
        result= -1;