open_table
/*
Open a table.
SYNOPSIS
open_table()
thd Thread context.
table_list Open first table in list.
action INOUT Pointer to variable of enum_open_table_action type
which will be set according to action which is
required to remedy problem appeared during attempt
to open table.
flags Bitmap of flags to modify how open works:
MYSQL_OPEN_IGNORE_FLUSH - Open table even if
someone has done a flush or there is a pending
exclusive metadata lock requests against it
(i.e. request high priority metadata lock).
No version number checking is done.
MYSQL_OPEN_TEMPORARY_ONLY - Open only temporary
table not the base table or view.
MYSQL_OPEN_TAKE_UPGRADABLE_MDL - Obtain upgradable
metadata lock for tables on which we are going to
take some kind of write table-level lock.
IMPLEMENTATION
Uses a cache of open tables to find a table not in use.
If TABLE_LIST::open_strategy is set to OPEN_IF_EXISTS, the table is opened
only if it exists. If the open strategy is OPEN_STUB, the underlying table
is never opened. In both cases, metadata locks are always taken according
to the lock strategy.
RETURN
TRUE Open failed. "action" parameter may contain type of action
needed to remedy problem before retrying again.
FALSE Success. Members of TABLE_LIST structure are filled properly (e.g.
TABLE_LIST::table is set for real tables and TABLE_LIST::view is
set for views).
*/
bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
Open_table_context *ot_ctx)
{
reg1 TABLE *table;
char key[MAX_DBKEY_LENGTH];
uint key_length;
char *alias= table_list->alias;
uint flags= ot_ctx->get_flags();
MDL_ticket *mdl_ticket;
int error;
TABLE_SHARE *share;
my_hash_value_type hash_value;
DBUG_ENTER("open_table");
/* an open table operation needs a lot of the stack space */
if (check_stack_overrun(thd, STACK_MIN_SIZE_FOR_OPEN, (uchar *)&alias))
DBUG_RETURN(TRUE);
if (thd->killed)
DBUG_RETURN(TRUE);
key_length= (create_table_def_key(thd, key, table_list, ) -
TMP_TABLE_KEY_EXTRA);
/*
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->open_type != OT_BASE_ONLY &&
! (flags & MYSQL_OPEN_SKIP_TEMPORARY))
{
for (table= thd->temporary_tables; table ; table=table->next)
{
if (table->s->table_cache_key.length == key_length +
TMP_TABLE_KEY_EXTRA &&
!memcmp(table->s->table_cache_key.str, 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)
{
DBUG_PRINT("error",
("query_id: %lu server_id: %u pseudo_thread_id: %lu",
(ulong) table->query_id, (uint) thd->server_id,
(ulong) thd->variables.pseudo_thread_id));
my_error(ER_CANT_REOPEN_TABLE, MYF(), table->alias);
DBUG_RETURN(TRUE);
}
table->query_id= thd->query_id;
thd->thread_specific_used= TRUE;
DBUG_PRINT("info",("Using temporary table"));
goto reset;
}
}
}
if (table_list->open_type == OT_TEMPORARY_ONLY ||
(flags & MYSQL_OPEN_TEMPORARY_ONLY))
{
if (table_list->open_strategy == TABLE_LIST::OPEN_NORMAL)
{
my_error(ER_NO_SUCH_TABLE, MYF(), table_list->db, table_list->table_name);
DBUG_RETURN(TRUE);
}
else
DBUG_RETURN(FALSE);
}
/*
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 (thd->locked_tables_mode &&
! (flags & MYSQL_OPEN_GET_NEW_TABLE))
{ // Using table locks
TABLE *best_table= ;
int best_distance= INT_MIN;
for (table=thd->open_tables; table ; table=table->next)
{
if (table->s->table_cache_key.length == key_length &&
!memcmp(table->s->table_cache_key.str, key, key_length))
{
if (!my_strcasecmp(system_charset_info, table->alias, alias) &&
table->query_id != thd->query_id && /* skip tables already used */
(thd->locked_tables_mode == LTM_LOCK_TABLES ||
table->query_id == ))
{
int distance= ((int) table->reginfo.lock_type -
(int) table_list->lock_type);
/*
Find a table that either has the exact lock type requested,
or has the best suitable lock. In case there is no locked
table that has an equal or higher lock than requested,
we us the closest matching lock to be able to produce an error
message about wrong lock mode on the table. The best_table
is changed if bd < 0 <= d or bd < d < 0 or 0 <= d < bd.
distance < 0 - No suitable lock found
distance > 0 - we have lock mode higher then we require
distance == 0 - we have lock mode exactly which we need
*/
&& distance > best_distance) ||
(distance >= && distance < best_distance))
{
best_distance= distance;
best_table= table;
)
{
/*
We have found a perfect match and can finish iterating
through open tables list. Check for table use conflict
between calling statement and SP/trigger is done in
lock_tables().
*/
break;
}
}
}
}
}
if (best_table)
{
table= best_table;
table->query_id= thd->query_id;
DBUG_PRINT("info",("Using locked table"));
goto reset;
}
/*
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)
Since opening of view which was not explicitly locked by LOCK
TABLES breaks metadata locking protocol (potentially can lead
to deadlocks) it should be disallowed.
*/
if (thd->mdl_context.is_lock_owner(MDL_key::TABLE,
table_list->db,
table_list->table_name,
MDL_SHARED))
{
];
enum legacy_db_type not_used;
build_table_filename(path, ,
table_list->db, table_list->table_name, reg_ext, );
/*
Note that we can't be 100% sure that it is a view since it's
possible that we either simply have not found unused TABLE
instance in THD::open_tables list or were unable to open table
during prelocking process (in this case in theory we still
should hold shared metadata lock on it).
*/
if (dd_frm_type(thd, path, ¬_used) == FRMTYPE_VIEW)
{
if (!tdc_open_view(thd, table_list, alias, key, key_length,
mem_root, ))
{
DBUG_ASSERT(table_list->view != );
DBUG_RETURN(FALSE); // VIEW
}
}
}
/*
No table in the locked tables list. In case of explicit LOCK TABLES
this can happen if a user did not include the able into the list.
In case of pre-locked mode locked tables list is generated automatically,
so we may only end up here if the table did not exist when
locked tables list was created.
*/
if (thd->locked_tables_mode == LTM_PRELOCKED)
my_error(ER_NO_SUCH_TABLE, MYF(), table_list->db, table_list->alias);
else
my_error(ER_TABLE_NOT_LOCKED, MYF(), alias);
DBUG_RETURN(TRUE);
}
/*
Non pre-locked/LOCK TABLES mode, and the table is not temporary.
This is the normal use case.
*/
if (! (flags & MYSQL_OPEN_HAS_MDL_LOCK))
{
/*
We are not under LOCK TABLES and going to acquire write-lock/
modify the base table. We need to acquire protection against
global read lock until end of this statement in order to have
this statement blocked by active FLUSH TABLES WITH READ LOCK.
We don't block acquire this protection under LOCK TABLES as
such protection already acquired at LOCK TABLES time and
not released until UNLOCK TABLES.
We don't block statements which modify only temporary tables
as these tables are not preserved by backup by any form of
backup which uses FLUSH TABLES WITH READ LOCK.
TODO: The fact that we sometimes acquire protection against
GRL only when we encounter table to be write-locked
slightly increases probability of deadlock.
This problem will be solved once Alik pushes his
temporary table refactoring patch and we can start
pre-acquiring metadata locks at the beggining of
open_tables() call.
*/
if (table_list->mdl_request.type >= MDL_SHARED_WRITE &&
! (flags & (MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |
MYSQL_OPEN_FORCE_SHARED_MDL |
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK)) &&
! ot_ctx->has_protection_against_grl())
{
MDL_request protection_request;
MDL_deadlock_handler mdl_deadlock_handler(ot_ctx);
if (thd->global_read_lock.can_acquire_protection())
DBUG_RETURN(TRUE);
protection_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
MDL_STATEMENT);
/*
Install error handler which if possible will convert deadlock error
into request to back-off and restart process of opening tables.
*/
thd->push_internal_handler(&mdl_deadlock_handler);
bool result= thd->mdl_context.acquire_lock(&protection_request,
ot_ctx->get_timeout());
thd->pop_internal_handler();
if (result)
DBUG_RETURN(TRUE);
ot_ctx->set_has_protection_against_grl();
}
if (open_table_get_mdl_lock(thd, ot_ctx, &table_list->mdl_request,
flags, &mdl_ticket) ||
mdl_ticket == NULL)
{
DEBUG_SYNC(thd, "before_open_table_wait_refresh");
DBUG_RETURN(TRUE);
}
DEBUG_SYNC(thd, "after_open_table_mdl_shared");
}
else
{
/*
Grab reference to the MDL lock ticket that was acquired
by the caller.
*/
mdl_ticket= table_list->mdl_request.ticket;
}
hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length);
if (table_list->open_strategy == TABLE_LIST::OPEN_IF_EXISTS)
{
bool exists;
if (check_if_table_exists(thd, table_list, &exists))
DBUG_RETURN(TRUE);
if (!exists)
DBUG_RETURN(FALSE);
/* Table exists. Let us try to open it. */
}
else if (table_list->open_strategy == TABLE_LIST::OPEN_STUB)
DBUG_RETURN(FALSE);
retry_share:
mysql_mutex_lock(&LOCK_open);
/** *如果从table_def_cache中找不到合适的table_share,就要生成一个新的table_share *打开.frm文件,填充数据,并放到table_def_cache哈希中 *同时share的引用值加1 即table_share->ref_count++ *如果table_def_cache中元素个数超过400,从oldest_unused_share开始,定位其table_share在table_def_cache中的位置,并删除
*因为是新生成的table_share,所以它的free_tables肯定为空,所以就要table_share的实例化 *实例化:例如将table_share赋值给table的成员变量s *调用table_share的成员对象used_table的方法push_front(),将table添加进去 * *如果table_share->free_tables为空, *如果table的实例超过400,说明要根据LRU,在unused_tables全局链表中,删除一些table实例 *unused_tables的头结点是最近最久未使用的,尾结点是最新的 *取出头结点 判断table->in_used的值 *如果不为0,说明还在使用 执行table->s->used_tables.remove(table) *如果为0,说明不再使用,执行table->s->free_tales.remove(table),并且删除该头结点 *table->s->ref_count--,如果值为0,将table_share放到end_unused_table_share的前面,符合LRU规则块 * *之所以这里不删除table_def_cache中数据,估计是认为这块只是删除unused_tables中的数据 */
/** *不会主动close_table的,除非用户手动执行alter或flush tales *当close_table(table)时 *设置table->in_used为0, *调用table->s->used_tables.remove(table) *table->s->free_tables.push_front(table) *并将该table作为unused_tables全局链表的头结点 */
if (!(share= get_table_share_with_discover(thd, table_list, key,
key_length, OPEN_VIEW,
&error,
hash_value)))
{
DBUG_RETURN(TRUE);
}
if (!share->free_tables.is_empty())
{
table= share->free_tables.front();
table_def_use_table(thd, table);
/* We need to release share as we have EXTRA reference to it in our hands. */
release_table_share(share);
}
else
{
/* We have too many TABLE instances around let us try to get rid of them. */
while (table_cache_count > table_cache_size && unused_tables)
free_cache_entry(unused_tables);
mysql_mutex_unlock(&LOCK_open);
/* make a new table */
if (!(table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME))))
goto err_lock;
error= open_table_from_share(thd, share, alias,
(uint) (HA_OPEN_KEYFILE |
HA_OPEN_RNDFILE |
HA_GET_INDEX |
HA_TRY_READ_ONLY),
(READ_KEYINFO | COMPUTE_TYPES |
EXTRA_RECORD),
thd->open_options, table, FALSE);
if (open_table_entry_fini(thd, share, table))
{
closefrm(table, );
my_free(table);
goto err_lock;
}
mysql_mutex_lock(&LOCK_open);
/* Add table to the share's used tables list. */
table_def_add_used_table(thd, table);
}
mysql_mutex_unlock(&LOCK_open);
table->mdl_ticket= mdl_ticket;
table->next= thd->open_tables; /* Link into simple list */
thd->set_open_tables(table);
table->reginfo.lock_type=TL_READ; /* Assume read */
reset:
/*
Check that there is no reference to a condtion from an earlier query
(cf. Bug#58553).
*/
DBUG_ASSERT(table->file->pushed_cond == NULL);
table_list->updatable= ; // It is not derived table nor non-updatable VIEW
table_list->table= table;
table->init(thd, table_list);
DBUG_RETURN(FALSE);
err_lock:
mysql_mutex_lock(&LOCK_open);
err_unlock:
release_table_share(share);
mysql_mutex_unlock(&LOCK_open);
DBUG_RETURN(TRUE);
}
/*
Open a table based on a TABLE_SHARE
SYNOPSIS
open_table_from_share()
thd Thread handler
share Table definition
alias Alias for table
db_stat open flags (for example HA_OPEN_KEYFILE|
HA_OPEN_RNDFILE..) can be 0 (example in
ha_example_table)
prgflag READ_ALL etc..
ha_open_flags HA_OPEN_ABORT_IF_LOCKED etc..
outparam result table
RETURN VALUES
0 ok
1 Error (see open_table_error)
2 Error (see open_table_error)
3 Wrong data in .frm file
4 Error (see open_table_error)
5 Error (see open_table_error: charset unavailable)
7 Table definition has changed in engine
*/
int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
uint db_stat, uint prgflag, uint ha_open_flags,
TABLE *outparam, bool is_create_table)
{
int error;
uint records, i, bitmap_size;
bool error_reported= FALSE;
uchar *record, *bitmaps;
Field **field_ptr;
DBUG_ENTER("open_table_from_share");
DBUG_PRINT("enter",("name: '%s.%s' form: 0x%lx", share->db.str,
share->table_name.str, (long) outparam));
error= ;
bzero((char*) outparam, sizeof(*outparam));
outparam->in_use= thd;
outparam->s= share;
outparam->db_stat= db_stat;
outparam->write_row_record= NULL;
init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, );
if (!(outparam->alias= my_strdup(alias, MYF(MY_WME))))
goto err;
outparam->quick_keys.init();
outparam->covering_keys.init();
outparam->merge_keys.init();
outparam->keys_in_use_for_query.init();
/* Allocate handler */
outparam->file= ;
if (!(prgflag & OPEN_FRM_FILE_ONLY))
{ /** *详见 *生成句柄,类型为handler */
if (!(outparam->file= get_new_handler(share, &outparam->mem_root,
share->db_type())))
goto err;
}
else
{
DBUG_ASSERT(!db_stat);
}
error= ;
outparam->reginfo.lock_type= TL_UNLOCK;
outparam->current_lock= F_UNLCK;
records=;
if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN))
records=;
if (prgflag & (READ_ALL+EXTRA_RECORD))
records++;
if (!(record= (uchar*) alloc_root(&outparam->mem_root,
share->rec_buff_length * records)))
goto err; /* purecov: inspected */
)
{
/* We are probably in hard repair, and the buffers should not be used */
outparam->record[]= outparam->record[]= share->default_values;
}
else
{
outparam->record[]= record;
)
outparam->record[]= record+ share->rec_buff_length;
else
outparam->record[]= outparam->record[]; // Safety
}
#ifdef HAVE_purify
/*
We need this because when we read var-length rows, we are not updating
bytes after end of varchar
*/
)
{
memcpy(outparam->record[], share->default_values, share->rec_buff_length);
memcpy(outparam->record[], share->default_values, share->null_bytes);
)
memcpy(outparam->record[], share->default_values,
share->rec_buff_length);
}
#endif
if (!(field_ptr = (Field **) alloc_root(&outparam->mem_root,
()*
sizeof(Field*)))))
goto err; /* purecov: inspected */
outparam->field= field_ptr;
record= (uchar*) outparam->record[]-; /* Fieldstart = 1 */
if (share->null_field_first)
outparam->null_flags= (uchar*) record+;
else
outparam->null_flags= (uchar*) (record+ + share->reclength -
share->null_bytes);
/* Setup copy of fields from share, but use the right alias and record */
; i < share->fields; i++, field_ptr++)
{
if (!((*field_ptr)= share->field[i]->clone(&outparam->mem_root, outparam)))
goto err;
}
(*field_ptr)= ; // End marker
if (share->found_next_number_field)
outparam->found_next_number_field=
outparam->field[(uint) (share->found_next_number_field - share->field)];
if (share->timestamp_field)
outparam->timestamp_field= (Field_timestamp*) outparam->field[share->timestamp_field_offset];
/* Fix key->name and key_part->field */
if (share->key_parts)
{
KEY *key_info, *key_info_end;
KEY_PART_INFO *key_part;
uint n_length;
n_length= share->keys*sizeof(KEY) + share->key_parts*sizeof(KEY_PART_INFO);
if (!(key_info= (KEY*) alloc_root(&outparam->mem_root, n_length)))
goto err;
outparam->key_info= key_info;
key_part= (reinterpret_cast<KEY_PART_INFO*>(key_info+share->keys));
memcpy(key_info, share->key_info, sizeof(*key_info)*share->keys);
memcpy(key_part, share->key_info[].key_part, (sizeof(*key_part) *
share->key_parts));
for (key_info_end= key_info + share->keys ;
key_info < key_info_end ;
key_info++)
{
KEY_PART_INFO *key_part_end;
key_info->table= outparam;
key_info->key_part= key_part;
for (key_part_end= key_part+ key_info->key_parts ;
key_part < key_part_end ;
key_part++)
{
Field *field= key_part->field= outparam->field[key_part->fieldnr-];
if (field->key_length() != key_part->length &&
!(field->flags & BLOB_FLAG))
{
/*
We are using only a prefix of the column as a key:
Create a new field for the key part that matches the index
*/
field= key_part->field=field->new_field(&outparam->mem_root,
outparam, );
field->field_length= key_part->length;
}
}
}
}
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (share->partition_info_str_len && outparam->file)
{
/*
In this execution we must avoid calling thd->change_item_tree since
we might release memory before statement is completed. We do this
by changing to a new statement arena. As part of this arena we also
set the memory root to be the memory root of the table since we
call the parser and fix_fields which both can allocate memory for
item objects. We keep the arena to ensure that we can release the
free_list when closing the table object.
SEE Bug #21658
*/
Query_arena *backup_stmt_arena_ptr= thd->stmt_arena;
Query_arena backup_arena;
Query_arena part_func_arena(&outparam->mem_root,
Query_arena::STMT_INITIALIZED);
thd->set_n_backup_active_arena(&part_func_arena, &backup_arena);
thd->stmt_arena= &part_func_arena;
bool tmp;
bool work_part_info_used;
tmp= mysql_unpack_partition(thd, share->partition_info_str,
share->partition_info_str_len,
outparam, is_create_table,
share->default_part_db_type,
&work_part_info_used);
if (tmp)
{
thd->stmt_arena= backup_stmt_arena_ptr;
thd->restore_active_arena(&part_func_arena, &backup_arena);
goto partititon_err;
}
outparam->part_info->is_auto_partitioned= share->auto_partitioned;
DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned));
/* we should perform the fix_partition_func in either local or
caller's arena depending on work_part_info_used value
*/
if (!work_part_info_used)
tmp= fix_partition_func(thd, outparam, is_create_table);
thd->stmt_arena= backup_stmt_arena_ptr;
thd->restore_active_arena(&part_func_arena, &backup_arena);
if (!tmp)
{
if (work_part_info_used)
tmp= fix_partition_func(thd, outparam, is_create_table);
}
outparam->part_info->item_free_list= part_func_arena.free_list;
partititon_err:
if (tmp)
{
if (is_create_table)
{
/*
During CREATE/ALTER TABLE it is ok to receive errors here.
It is not ok if it happens during the opening of an frm
file as part of a normal query.
*/
error_reported= TRUE;
}
goto err;
}
}
#endif
/* Allocate bitmaps */
bitmap_size= share->column_bitmap_size;
)))
goto err;
bitmap_init(&outparam->def_read_set,
(my_bitmap_map*) bitmaps, share->fields, FALSE);
bitmap_init(&outparam->def_write_set,
(my_bitmap_map*) (bitmaps+bitmap_size), share->fields, FALSE);
bitmap_init(&outparam->tmp_set,
(my_bitmap_map*) (bitmaps+bitmap_size*), share->fields, FALSE);
outparam->default_column_bitmaps();
/* The table struct is now initialized; Open the table */
error= ;
if (db_stat)
{
int ha_err; /** *详见 *打开.ibd文件,初始化dict_table_t */
if ((ha_err= (outparam->file->
ha_open(outparam, share->normalized_path.str,
(db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
(db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
((db_stat & HA_WAIT_IF_LOCKED) ||
(specialflag & SPECIAL_WAIT_IF_LOCKED)) ?
HA_OPEN_WAIT_IF_LOCKED :
(db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ?
HA_OPEN_ABORT_IF_LOCKED :
HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags))))
{
/* Set a flag if the table is crashed and it can be auto. repaired */
share->crashed= ((ha_err == HA_ERR_CRASHED_ON_USAGE) &&
outparam->file->auto_repair() &&
!(ha_open_flags & HA_OPEN_FOR_REPAIR));
switch (ha_err)
{
case HA_ERR_NO_SUCH_TABLE:
/*
The table did not exists in storage engine, use same error message
as if the .frm file didn't exist
*/
error= ;
my_errno= ENOENT;
break;
case EMFILE:
/*
Too many files opened, use same error message as if the .frm
file can't open
*/
DBUG_PRINT("error", ("open file: %s failed, too many files opened (errno: %d)",
share->normalized_path.str, ha_err));
error= ;
my_errno= EMFILE;
break;
default:
outparam->file->print_error(ha_err, MYF());
error_reported= TRUE;
if (ha_err == HA_ERR_TABLE_DEF_CHANGED)
error= ;
break;
}
goto err; /* purecov: inspected */
}
}
#if defined(HAVE_purify) && !defined(DBUG_OFF)
bzero(();
#endif
outparam->no_replicate= outparam->file &&
test(outparam->file->ha_table_flags() &
HA_HAS_OWN_BINLOGGING);
/* Increment the opened_tables counter, only when open flags set. */
if (db_stat)
thd->status_var.opened_tables++;
DBUG_RETURN ();
err:
if (! error_reported)
open_table_error(share, error, my_errno, );
delete outparam->file;
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (outparam->part_info)
free_items(outparam->part_info->item_free_list);
#endif
outparam->file= ; // For easier error checking
outparam->db_stat=;
free_root(&outparam->mem_root, MYF()); // Safe to call on bzero'd root
my_free((void *) outparam->alias);
DBUG_RETURN (error);
}
/**
Mark already existing TABLE instance as used.
*/
static void table_def_use_table(THD *thd, TABLE *table)
{
DBUG_ASSERT(!table->in_use);
/* Unlink table from list of unused tables for this share. */
table->s->free_tables.remove(table);
/* Unlink able from global unused tables list. */
if (table == unused_tables)
{ // First unused
unused_tables=unused_tables->next; // Remove from link
if (table == unused_tables)
unused_tables=;
}
table->prev->next=table->next; /* Remove from unused list */
table->next->prev=table->prev;
check_unused();
/* Add table to list of used tables for this share. */
table->s->used_tables.push_front(table);
table->in_use= thd;
/* The ex-unused table must be fully functional. */
DBUG_ASSERT(table->db_stat && table->file);
/* The children must be detached from the table. */
DBUG_ASSERT(! table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN));
}
static void table_def_add_used_table(THD *thd, TABLE *table)
{
DBUG_ASSERT(table->in_use == thd);
table->s->used_tables.push_front(table);
table_cache_count++;
}
int handler::ha_open(TABLE *table_arg, const char *name, int mode,
int test_if_locked)
{
int error;
DBUG_ENTER("handler::ha_open");
DBUG_PRINT("enter",
("name: %s db_type: %d db_stat: %d mode: %d lock_test: %d",
name, ht->db_type, table_arg->db_stat, mode,
test_if_locked));
table= table_arg;
DBUG_ASSERT(table->s == table_share);
DBUG_ASSERT(alloc_root_inited(&table->mem_root));
if ((error=open(name,mode,test_if_locked)))
{
if ((error == EACCES || error == EROFS) && mode == O_RDWR &&
(table->db_stat & HA_TRY_READ_ONLY))
{
table->db_stat|=HA_READ_ONLY;
error=open(name,O_RDONLY,test_if_locked);
}
}
if (error)
{
my_errno= error; /* Safeguard */
DBUG_PRINT("error",("error: %d errno: %d",error,errno));
}
else
{
if (table->s->db_options_in_use & HA_OPTION_READ_ONLY_DATA)
table->db_stat|=HA_READ_ONLY;
(void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
/* ref is already allocated for us if we're called from handler::clone() */
if (!ref && !(ref= (uchar*) alloc_root(&table->mem_root,
ALIGN_SIZE(ref_length)*)))
{
close();
error=HA_ERR_OUT_OF_MEM;
}
else
dup_ref=ref+ALIGN_SIZE(ref_length);
cached_table_flags= table_flags();
}
DBUG_RETURN(error);
}
open_table的更多相关文章
- open_table与opened_table
好多人在调优Mysql的时候,总是对open_tables和opend_tables两个参数分别不清. 网上好多解释都是这样的:open_tables:当前打开表的数量opened_tables:当前 ...
- open_table与opened_table --2
好多人在调优Mysql的时候,总是对open_tables和opend_tables两个参数分别不清. 网上好多解释都是这样的:open_tables:当前打开表的数量opened_tables:当前 ...
- MySQL备份锁
无论逻辑备份还是物理备份,为了获取一致性位点,都强依赖于FTWRL(Flush Table With Read Lock).这个锁杀伤力非常大,因为持有锁的这段时间,整个数据库实质上不能对外提供写服务 ...
- rabbitmq启动异常之error,{not_a_dets_file recovery.dets
中午,公司群里面测试人员@笔者说,早上测试服务器异常,MQ起不来,重启os了也起不来,报错,上去看下了早上又因为内存oom被内核killed了,启动了下,确实启动报错,erl vm进程起来了,但是be ...
- Mysql查询阻塞初探
第一次值班,报警打电话给我说,数据库复制延时一个多小时,那个时候是半夜啊,但我还是很清醒的起来,开机.vpn.登录.show processlist,结果发现情况是这样的: 红线框表示的是当前每个线程 ...
- 【网络资料】Astar算法详解
关于A*算法,很早就想写点什么,可是貌似天天在忙活着什么,可事实又没有做什么,真是浮躁啊!所以今晚还是来写一下总结吧! A*算法是很经典的只能启发式搜索算法,关于只能搜索算法和一般的搜索算法(例如DF ...
- struct TABLE
struct TABLE { TABLE() {} /* Remove gcc warning */ TABLE_SHARE *s; handler *file; TABLE *next, *prev ...
- MySQL锁系列3 MDL锁
http://www.cnblogs.com/xpchild/p/3790139.html MySQL为了保护数据字典元数据,使用了metadata lock,即MDL锁,保证在并发的情况下,结构 ...
- MySQL锁系列2 表锁
http://www.cnblogs.com/xpchild/p/3789068.html 上一篇介绍了MySQL源码中保护内存结构或变量的锁,这里开始介绍下MySQL事务中的表锁. 注1: 在表 ...
随机推荐
- 论坛类应用双Tableview翻页效果实现
作为一名篮球爱好者,经常使用虎扑体育,虎扑体育应用最核心的部分就是其论坛功能,无论哪个版块,论坛都是其核心,而其论坛部分的实现又别具一格,它以两个tableview的形式翻页滚动显示,而不是常见的那种 ...
- Android Bluetooth Stream Non-blocking Communication Tutorial
This is a tutorial for Android to do non-blocking bluetooth socket communication. I am using 32feet ...
- java 使用 comet4j 主动向客户端推送信息 简单例子
[背景] 今天,一个前端的师弟问我怎样做实时聊天窗口,我毫不犹豫地说:在前台定时访问服务端呀!师弟默默地百度了一番,最后告诉我,有一种技术是后服务端动推送信息给客户端的,这种技术的名字叫comet,我 ...
- SQL SERVER 之 填充因子
填充因子依附索引而存在,但创建索引,就意味着要对表进行DML时,必须处理额外的工作量(也就是对索引结构的维护)以及存储方面的IO开销. 所以创建索引时,需要考虑创建索引所带来的查询性能方面的提高,与引 ...
- SOAP vs REST
Both methods are used by many of the large players. It's a matter of preference. My preference is RE ...
- windows service 安装和卸载指令
添加服务: cd C:\Windows\Microsoft.NET\Framework\v4.0.30319InstallUtil.exe D:\OneKeyWebSiteDeployment\Ser ...
- POJ2586Y2K Accounting Bug
http://poj.org/problem?id=2586 Description Accounting for Computer Machinists (ACM) has sufferred fr ...
- Oracle 9 - redo和undo
1.redo redo 有在线redo日志和归档redo日志, 从Oracle 10g开始还新增加了flashback技术. 每个Oracle数据库至少有2个在线重做日志组,循环写. 只有INSERT ...
- 解决virtualbox 虚拟机不能ping通win7
凭经验猜测是由于防火墙引起的,关闭防火墙再ping,果然可行.google说这是由于“win7 防火墙默认的禁ping策略”引起的.但是关闭防火墙很不安全,可以按照以下步骤为防火墙添加入站规则来解决问 ...
- log4j的基本配置参数
转载:http://blog.csdn.net/fengyifei11228/article/details/6070006 log4j配置文件有三个主要的组件:Logger,Appender和Lay ...