• MySQL Binlog中TABLE ID源码分析 【转】


    文章来源:http://blog.chinaunix.net/uid-26896862-id-3329896.html

    目的
           MySQL的binlog日志中,基于行模式的方式,有table id的信息,而该table id并不是binlog中的操作表的固定id。为了进一步了解table id的改变,研究MySQL源码(MySQL-5.5.20),查看具体的处理逻辑,供开发和DBA参考。
    源码分析
           table id的分配在函数assign_new_table_id()(sql\sql_base.cc:3598)中分配,从处理的逻辑来看,每次分配都是对上一次的table id自增1。核心代码如下所示:

    ulong tid= ++last_table_id; /* get next id */
      /*
        There is one reserved number that cannot be used. Remember to
        change this when 6-byte global table id's are introduced.
      */
      if (unlikely(tid == ~0UL))
        tid= ++last_table_id;
      share->table_map_id= tid;

    而在TABLE_SHARE结构体(sql\table.h:541)的定义中,可以发现,table_map_id变量仅用于行模式的复制操作。具体定义如下所示:

    ulong table_map_id; /* for row-based replication */

    根据以上线索,跟踪调用assign_new_table_id()函数的引用。只在get_table_share()函数(sql\sql_base.cc:560)中调用,该函数首先调用my_hash_search_using_hash_value()函数(mysys\hash.c:218)查找cache中是否有操作的表定义。如果找到表定义,则对其引用数自增1
    并返回该表定义;否则,创建一个TABLE_SHARE变量,并调用assign_new_table_id()函数分配一个新的table id,然后保存在cache中,调用open_table_def()函数(sql\table.cc:594)打开表定义并返回。其中,表定义在cache中是通过hash的方式组织,通过表的hash值获得。
    核心代码如下所示:

    /* Read table definition from cache */
      if ((share= (TABLE_SHARE*) my_hash_search_using_hash_value(&table_def_cache, hash_value, (uchar*) key, key_length)))
        goto found;
      if (!(share= alloc_table_share(table_list, key, key_length)))
      {
        DBUG_RETURN(0);
      }
      /*
        We assign a new table id under the protection of LOCK_open.
        We do this instead of creating a new mutex
        and using it for the sole purpose of serializing accesses to a
        static variable, we assign the table id here. We assign it to the
        share before inserting it into the table_def_cache to be really
        sure that it cannot be read from the cache without having a table
        id assigned.
        CAVEAT. This means that the table cannot be used for
        binlogging/replication purposes, unless get_table_share() has been
        called directly or indirectly.
       */
      assign_new_table_id(share);

    写binlog的时候,在THD::binlog_write_table_map()函数(sql\log.cc:4760)中初始化Table_map_log_event对象the_event,初始化参数table
    id的值,即table_map_id的值,而该值是assign_new_table_id()函数获得的table
    id的值。核心代码如下:

    Table_map_log_event
        the_event(this, table, table->s->table_map_id, is_transactional);

    由以上内容可知,基于行模式的复制中,binlog中的table id是根据初始化的每个Table_map_log_event的时,传入的table_map_id的值。而get_table_share()函数可知,当cache中有该表定义时,该值的table id是不变的;而当cache中没有改表定义时,该值根据上一次操作的table id自增1获得的。
    为了更清晰的了解table id与cache的关系,对table_def_cache进行分析,在get_table_share()函数中,如果在cache中找到表定义,在返回之前,会判断table_def_cache中是否太大,如果太大将清理cache中最久没用的表定义。

    /* Free cache if too big */
      while (table_def_cache.records > table_def_size &&
             oldest_unused_share->next)
        my_hash_delete(&table_def_cache, (uchar*) oldest_unused_share);

    判断大小的标准是table_def_size变量,table_def_size的定义(sql\sys_vars.cc:2148)如下所示:

    static Sys_var_ulong Sys_table_def_size(
           "table_definition_cache",
           "The number of cached table definitions",
           GLOBAL_VAR(table_def_size), CMD_LINE(REQUIRED_ARG),
           VALID_RANGE(TABLE_DEF_CACHE_MIN, 512*1024),
           DEFAULT(TABLE_DEF_CACHE_DEFAULT), BLOCK_SIZE(1));

    从以上代码中可知,table_def_size是全变变量,有效值为:400~512*1024,默认值为:400(TABLE_DEF_CACHE_MIN=400;TABLE_DEF_CACHE_DEFAULT=400)。
           因此,由上面分析可知,当table_def_cache中的记录数大于400时,表定义将被置换出cache。被置换出的表如果有操作时,重新加载时,table id的值就会发生改变。

    结论
           基于行模式复制的binlog中,table id的变化依赖于cache中是否存储了binlog操作表的表定义。如果cache中存在,则table id不变;而当cache中不存在时,该值根据上一次操作的table id自增1。因此,table id与实际操作的数据表没有直接对应关系,而与操作的数据表是否在cache中有关。此外,table_def_cache中默认存放400个表定义,如果超出该范围,会将最久未用的表定义置换出cache。

    相关table_id 的问题:
    http://hickey.in/?p=146

    ~~~~~~~~~~~~~~~ 万物之中,希望至美 ~~~~~~~~~~~~~~~
  • 相关阅读:
    python之生成器
    Python 类(一)
    Python OOP(面向对象编程)
    python 静态方法、类方法(二)
    记一个有想法没能力实现的产品形态——实时公交
    ubuntu12.04离线安装libjpeg62-dev
    linux内核container_of宏定义分析
    signal函数理解或者void (*signal(int signum,void(*handler)(int)))(int)理解
    HttpServlet cannot be resolved to a type解决方法
    ubuntu12.04不能记住上次编辑位置的解决方案
  • 原文地址:https://www.cnblogs.com/zhoujinyi/p/2737940.html
Copyright © 2020-2023  润新知