zoukankan      html  css  js  c++  java
  • myrocks记录格式分析

    概况

    rocksdb作为KV存储引擎,那么myrocks记录最终会以kv的形式存储在rocksdb中。MySQL中的表一般由若干索引组成, 在innodb存储引擎中,每个索引对应一颗B树,而在rocksdb存储引擎中,索引对应于rocksdb中一段连续范围的数据。
    具体来说,这个范围是此索引id和id+1之间的所有数据。如果表的所有索引都在一个column family, 那表的这些索引数据在物理上基本是连续的。
    可以参考之前文章中的图示

    myrocks记录格式

    myrocks以索引为单位,将表的所有索引分别存储在rocksdb中。
    根据索引的类型,myrocks记录的格式有所不同。下面以下表不同索引类型来分别介绍

    CREATE TABLE t1(a INT, 
                    b VARCHAR(20), 
                    c char(5), 
                    d int, 
                    pk INT AUTO_INCREMENT, 
                    PRIMARY KEY(pk) comment 'cf_1', 
                    unique key idx2(b) comment 'cf_2') 
                    engine= rocksdb;
    
    INSERT INTO t1 (pk,a,b,c) VALUES (1,1,'bbbbbbbbbb','c');
    • 主键
      主键索引记录kv结构如下

      key: index_id, M(pk)
      value: unpack_info, NULL-bitmap,b,c,d

      key由索引id和主键组成。 index_id是索引的唯一标识占用4个字节,M(pk) 表示pk转化后的数据,此转化后的数据可以直接用于memcmp比较

      rocksdb数据都是根据key排序的,为了便于比较,不同类型数据都会经过一些转化,转化后可以直接用于memcmp比较。
      关于memcmp转化,下一节会详细介绍

      value存储unpack_info和非主键外的其他字段数据, Null-bitmap标识哪些字段为空。
      unpace_info存储将M(pk)逆转化为pk的信息,如果不需要额外转换信息则unpace_info为null,此例中pk为int类型,不需要额外信息unpace_info为null

    • 二级索引 idx2
      二级索引记录kv结构如下

      key: index_id,NULL-byte, M(b),M(pk)
      value: unpack_info

      key由index_id,二级索引键和主键组成, 其中NULL-byte表示b是否为空。pk为主键非空,所以不需要NULL-byte
      value只有unpack_info,表示 M(b),M(pk)逆转化信息,如果不需要额外转换信息则unpace_info为null。此例中b为varchar类型,需要额外信息unpace_info不为null

      唯一索引和普通二级索引存储方式没有区别
      联合索引每多一个字段会在字段前增加一个NULL-byte,来表示此字段是否为空

    Memcomparable format

    rocksdb为了比较方便,将key字段转化为可以直接memcmp比较的形式。所以MyRocks 一般建议使用sensitive collations (latin1_bin, utf8_bin, binary).
    这样可以避免转化的开销。

    • 整形

    整形转化比较简单,但对于有符号类型需要特殊处理,如果直接存储会导致比较是负数比正数大。
    这里对有符号类型处理的方式是将符号位反转,这样正数就比负数大了,
    关键代码段如下

    Field_long::make_sort_key:
    
    if (!table->s->db_low_byte_first)  
    {
      if (unsigned_flag)
        to[0] = ptr[0];
      else
        to[0] = (char) (ptr[0] ^ 128);            /* Revers signbit */
      to[1]   = ptr[1];                
      to[2]   = ptr[2];                
      to[3]   = ptr[3];                
    }
    • 字符型

    char类型直接补空格

    varchar类型为了节省空间处理起来就复杂多了
    以源码中的注释为例

    const int VARCHAR_CMP_LESS_THAN_SPACES = 1;
    const int VARCHAR_CMP_EQUAL_TO_SPACES = 2;
    const int VARCHAR_CMP_GREATER_THAN_SPACES = 3;
    
     Example: if fpi->m_segment_size=5, and the collation is latin1_bin:
    
      'abcd'   => [ 'abcd' <VARCHAR_CMP_LESS> ]['    ' <VARCHAR_CMP_EQUAL> ]
      'abcd'     => [ 'abcd' <VARCHAR_CMP_EQUAL>]
      'abcd   '  => [ 'abcd' <VARCHAR_CMP_EQUAL>]
      'abcdZZZZ' => [ 'abcd' <VARCHAR_CMP_GREATER>][ 'ZZZZ' <VARCHAR_CMP_EQUAL>]

    字符串以m_segment_size分段存储,每段前m_segment_size-1个字符是内容,最后一个字符表示和空格比较,VARCHAR_CMP_EQUAL同时也表示字符串结束

    例子中m_segment_size为5,实际实现上值为9

    这里unpace_info会比较复杂,字符串collation不同unpace_info也不同,unpace_info需要保存collation之间的转换映射关系,
    具体可以查看函数(rdb_init_collation_mapping)

    rocksdb内部记录格式

    前面为我们看到的是进入rocksdb之前记录的kv结构形式,实际上数据存储到rocksdb后key还要进一步封装
    进入rocksdb之前的key称为userkey, rocksdb内部称为internalkey

    internalkey=| User key (string) | sequence number (7 bytes) | value type (1 byte) |

    其中sequence number 是记录序列号,每个记录sequence number根据是以记录进入rocksdb先后顺序递增的。
    sequence number是实现rocksdb事务处理的关键,这个下次讨论。

    value type是记录的类型,put, merge,delete等

    示例

    以实例来说明比较直观,还是上面介绍的那个表,插入一条记录,来看看记录的具体结构

    INSERT INTO t1 (pk,a,b,c) VALUES (1,1,'bbbbbbbbbb','c');

    查看主键index_id为260,二级索引index_id为261

    select * from INFORMATION_SCHEMA.ROCKSDB_DDL where TABLE_NAME='t1';
    TABLE_SCHEMA    TABLE_NAME      PARTITION_NAME  INDEX_NAME      COLUMN_FAMILY   INDEX_NUMBER    INDEX_TYPE      KV_FORMAT_VERSION       CF
    test    t1      NULL    PRIMARY 2       260     1       11      cf_1
    test    t1      NULL    idx2    3       261     2       11      cf_2
    • 主键记录

      • key 

    screenshot

      • value

     screenshot

    • 二级索引记录

      • key 

    screenshot

      •  value 

    screenshot 

     

    这里包字段b的空格信息和collation转化映射关系。比较复杂,不详细展开,有兴趣的可以查看函数(rdb_init_collation_mapping)

     

  • 相关阅读:
    数据结构-链式结构-队列
    c数据结构-线性结构-队列
    栈的四则运算的运用
    C++/C—函数指针
    向显存写数据x8086
    结构体内存偏移量
    MFC-ComboBox控件的使用
    MFC的Edit text编辑框控件
    C/C++反汇编-各种表达式(加减乘)
    MFC- 学习控件-静态文本
  • 原文地址:https://www.cnblogs.com/justfortaste/p/6047935.html
Copyright © 2011-2022 走看看