ha_innobase::open

http://mysql.taobao.org/monthly/2015/08/07/

/*****************************************************************//**
Creates and opens a handle to a table which already exists in an InnoDB
database.
@return    1 if error, 0 if success */
UNIV_INTERN
int
ha_innobase::open(
/*==============*/
    const char*        name,        /*!< in: table name */
    int            mode,        /*!< in: not used */
    uint            test_if_locked)    /*!< in: not used */
{
    dict_table_t*        ib_table;
    char            norm_name[1000];
    THD*            thd;
    char*            is_part = NULL;
    ibool            par_case_name_set = FALSE;
    char            par_case_name[MAX_FULL_NAME_LEN + 1];
    dict_err_ignore_t    ignore_err = DICT_ERR_IGNORE_NONE;

    DBUG_ENTER("ha_innobase::open");

    thd = ha_thd();

    normalize_table_name(norm_name, name);

    user_thd = NULL;

    if (!(share=get_share(name))) {

        DBUG_RETURN(1);
    }

    /* Will be allocated if it is needed in ::update_row() */
    upd_buf = NULL;
    upd_buf_size = 0;

   /* Get pointer to a table object in InnoDB dictionary cache */
    ib_table = dict_table_get(norm_name, TRUE, ignore_err);

table_opened:

    prebuilt = row_create_prebuilt(ib_table, table->s->reclength);

    prebuilt->default_rec = table->s->default_values;
    ut_ad(prebuilt->default_rec);

    /* Looks like MySQL-3.23 sometimes has primary key number != 0 */

    primary_key = table->s->primary_key;
    key_used_on_scan = primary_key;

   /* Allocate a buffer for a ‘row reference‘. A row reference is
    a string of bytes of length ref_length which uniquely specifies
    a row in our table. Note that MySQL may also compare two row
    references for equality by doing a simple memcmp on the strings
    of length ref_length! */

    if (!row_table_got_default_clust_index(ib_table)) {

        prebuilt->clust_index_was_generated = FALSE;

        if (UNIV_UNLIKELY(primary_key >= MAX_KEY)) {
            sql_print_error("Table %s has a primary key in "
                    "InnoDB data dictionary, but not "
                    "in MySQL!", name);

            /* This mismatch could cause further problems
            if not attended, bring this to the user‘s attention
            by printing a warning in addition to log a message
            in the errorlog */
            push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                        ER_NO_SUCH_INDEX,
                        "InnoDB: Table %s has a "
                        "primary key in InnoDB data "
                        "dictionary, but not in "
                        "MySQL!", name);

            /* If primary_key >= MAX_KEY, its (primary_key)
            value could be out of bound if continue to index
            into key_info[] array. Find InnoDB primary index,
            and assign its key_length to ref_length.
            In addition, since MySQL indexes are sorted starting
            with primary index, unique index etc., initialize
            ref_length to the first index key length in
            case we fail to find InnoDB cluster index.

            Please note, this will not resolve the primary
            index mismatch problem, other side effects are
            possible if users continue to use the table.
            However, we allow this table to be opened so
            that user can adopt necessary measures for the
            mismatch while still being accessible to the table
            date. */
            ref_length = table->key_info[0].key_length;

            /* Find correspoinding cluster index
            key length in MySQL‘s key_info[] array */
            for (ulint i = 0; i < table->s->keys; i++) {
                dict_index_t*    index;
                index = innobase_get_index(i);
                if (dict_index_is_clust(index)) {
                    ref_length =
                         table->key_info[i].key_length;
                }
            }
        } else {
            /* MySQL allocates the buffer for ref.
            key_info->key_length includes space for all key
            columns + one byte for each column that may be
            NULL. ref_length must be as exact as possible to
            save space, because all row reference buffers are
            allocated based on ref_length. */

            ref_length = table->key_info[primary_key].key_length;
        }
    } else {
        if (primary_key != MAX_KEY) {
            sql_print_error(
                "Table %s has no primary key in InnoDB data "
                "dictionary, but has one in MySQL! If you "
                "created the table with a MySQL version < "
                "3.23.54 and did not define a primary key, "
                "but defined a unique key with all non-NULL "
                "columns, then MySQL internally treats that "
                "key as the primary key. You can fix this "
                "error by dump + DROP + CREATE + reimport "
                "of the table.", name);

            /* This mismatch could cause further problems
            if not attended, bring this to the user attention
            by printing a warning in addition to log a message
            in the errorlog */
            push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                        ER_NO_SUCH_INDEX,
                        "InnoDB: Table %s has no "
                        "primary key in InnoDB data "
                        "dictionary, but has one in "
                        "MySQL!", name);
        }

        prebuilt->clust_index_was_generated = TRUE;

        ref_length = DATA_ROW_ID_LEN;

        /* If we automatically created the clustered index, then
        MySQL does not know about it, and MySQL must NOT be aware
        of the index used on scan, to make it avoid checking if we
        update the column of the index. That is why we assert below
        that key_used_on_scan is the undefined value MAX_KEY.
        The column is the row id in the automatical generation case,
        and it will never be updated anyway. */

        if (key_used_on_scan != MAX_KEY) {
            sql_print_warning(
                "Table %s key_used_on_scan is %lu even "
                "though there is no primary key inside "
                "InnoDB.", name, (ulong) key_used_on_scan);
        }
    }

    /* Index block size in InnoDB: used by MySQL in query optimization */
    stats.block_size = 16 * 1024;

    /* Init table lock structure */
    thr_lock_data_init(&share->lock,&lock,(void*) 0);

    if (prebuilt->table) {
        /* We update the highest file format in the system table
        space, if this table has higher file format setting. */

        trx_sys_file_format_max_upgrade(
            (const char**) &innobase_file_format_max,
            dict_table_get_format(prebuilt->table));
    }

    /* Only if the table has an AUTOINC column. */
    if (prebuilt->table != NULL && table->found_next_number_field != NULL) {
        dict_table_autoinc_lock(prebuilt->table);

        /* Since a table can already be "open" in InnoDB‘s internal
        data dictionary, we only init the autoinc counter once, the
        first time the table is loaded. We can safely reuse the
        autoinc value from a previous MySQL open. */
        if (dict_table_autoinc_read(prebuilt->table) == 0) {

            innobase_initialize_autoinc();
        }

        dict_table_autoinc_unlock(prebuilt->table);
    }

    info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);

    DBUG_RETURN(0);
}
/************************************************************************//**
 Handling the shared INNOBASE_SHARE structure that is needed to provide table
 locking.
****************************************************************************/

static INNOBASE_SHARE* get_share(const char* table_name)
{
    INNOBASE_SHARE *share;
    mysql_mutex_lock(&innobase_share_mutex);

    ulint    fold = ut_fold_string(table_name);

    HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
            INNOBASE_SHARE*, share,
            ut_ad(share->use_count > 0),
            !strcmp(share->table_name, table_name));

    if (!share) {

        uint length = (uint) strlen(table_name);

        /* TODO: invoke HASH_MIGRATE if innobase_open_tables
        grows too big */

        share = (INNOBASE_SHARE *) my_malloc(sizeof(*share)+length+1,
            MYF(MY_FAE | MY_ZEROFILL));

        share->table_name = (char*) memcpy(share + 1,
                           table_name, length + 1);

        HASH_INSERT(INNOBASE_SHARE, table_name_hash,
                innobase_open_tables, fold, share);

        thr_lock_init(&share->lock);

        /* Index translation table initialization */
        share->idx_trans_tbl.index_mapping = NULL;
        share->idx_trans_tbl.index_count = 0;
        share->idx_trans_tbl.array_size = 0;
    }

    share->use_count++;
    mysql_mutex_unlock(&innobase_share_mutex);

    return(share);
}
时间: 2024-12-13 19:37:47

ha_innobase::open的相关文章

class ha_innobase: public handler

/** The class defining a handle to an Innodb table */ class ha_innobase: public handler { row_prebuilt_t* prebuilt; /*!< prebuilt struct in InnoDB, used to save CPU time with prebuilt data structures*/ THD* user_thd; /*!< the thread handle of the us

ha_innobase::general_fetch

/***********************************************************************//** Reads the next or previous row from a cursor, which must have previously been positioned using index_read. @return 0, HA_ERR_END_OF_FILE, or error number */ UNIV_INTERN int

ha_innobase::rnd_next

/*****************************************************************//** Reads the next row in a table scan (also used to read the FIRST row in a table scan). @return 0, HA_ERR_END_OF_FILE, or error number */ UNIV_INTERN int ha_innobase::rnd_next( /*==

MySQL 外键异常分析

外键约束异常现象 如下测例中,没有违反引用约束的插入失败. create database `a-b`; use `a-b`; SET FOREIGN_KEY_CHECKS=0; create table t1(c1 int primary key, c2 int) engine=innodb; create table t2(c1 int primary key, c2 int) engine=innodb; alter table t2 add foreign key(c2) referen

怎么跳出MySQL的10个大坑

淘宝自从2010开始规模使用MySQL,替换了之前商品.交易.用户等原基于IOE方案的核心数据库,目前已部署数千台规模.同时和Oracle, Percona, Mariadb等上游厂商有良好合作,共向上游提交20多个Patch.目前淘宝核心系统研发部数据库组,根据淘宝的业务需求,改进数据库和提升性能,提供高性能.可扩展的.稳定可靠的数据库(存储)解决方案. 目前有以下几个方向:单机,提升单机数据库的性能,增加我们所需特性:集群,提供性能扩展,可靠性,可能涉及分布式事务处理:IO存储体系,跟踪IO

MYSQL INNODB主键使用varchar和int有什么区别?

本文和大家分享的主要是MYSQL 数据库主键使用varchar和int的区别,一起来看看吧,希望对大家学习mysql有所帮助. 我现在总结的3个问题: 1.tablespace中空间浪费 当然我们知道使用varchar可能会导致辅助索引比较大,因为用到varchar可能存储的字符较多,同时 在行头也存在一个可变字段字符区域(1-2)字节 而辅助索引叶子结点毕竟都存储了主键值,这样至少会多varchar数据字节数量+1(或者2) 字节- 4(int)字节空间. 如果辅助索引比较多空间浪费是可想而知

select 数据

http://blog.csdn.net/wudongxu/article/details/6683846 ha_innobase::open ib_table = dict_table_get(norm_name, TRUE, ignore_err); prebuilt = row_create_prebuilt(ib_table, table->s->reclength); ha_innobase::rnd_next if(第一次查找) index_first(buf); else gen

MySQL数据库InnoDB存储引擎多版本控制(MVCC)实现原理分析

文/何登成 导读:   来自网易研究院的MySQL内核技术研究人何登成,把MySQL数据库InnoDB存储引擎的多版本控制(简称:MVCC)实现原理,做了深入的研究与详细的文字图表分析,方便大家理解InnoDB存储引擎实现的多版本控制技术(简称:MVCC). 基本知识 假设对于多版本控制(MVCC)的基础知识,有所了解.MySQL数据库InnoDB存储引擎为了实现多版本的一致性读,采用的是基于回滚段的协议. 行结构 MySQL数据库InnoDB存储引擎表数据的组织方式为主键聚簇索引.由于采用索引

innodb 自增列重复值问题

1 innodb 自增列出现重复值的问题 先从问题入手,重现下这个bug use test; drop table t1; create table t1(id int auto_increment, a int, primary key (id)) engine=innodb; insert into t1 values (1,2);insert into t1 values (null,2); insert into t1 values (null,2); select * from t1;