传说,在OceanBase 0.4之前,表结构定义,包括系统内部元数据表,都从Schema文件中读取。0.4版本之后,通过SQL语句创建表结构(《OceanBase 0.4.2 SQL 参考指南》、《OceanBase 0.5 SQL 参考指南》)。
在开源的OceanBase 0.4版本(OB唯一开源版本)的RootServer代码中,是可以看到从文件中读取Schema配置的代码段,在src/rootserver/obrootserver2.cpp:340: ()
其中,config.schemafilename的默认值是”etc/schema.ini“,但,这个文件安装以后的内容很简单(源码构建时由src/rootserver/schema.ini拷贝至$/etc/schema.ini):
说明,从0.4版本开始,至少应用的库表Schema结构定义不再从配置文件中读取,而是通过SQL来定义。
Schema配置文件格式
通过一个示例来大致了解Schema配置文件格式:
应用的信息
应用的信息都写在 app_name 这个section 中. 目前主要有两个配置项:
name 用来配置应用的名称, 是一个长度不超过128位的字符串.
maxtableid 用来记录当前已经使用的最大的tableid. 在OceanBase中, 每个表都由tableid唯一标识, 且tableid不可以被重复使用. maxtableid 这个配置项, 主要是为了方便 schema 生成程序记录已经使用过的tableid.
代码入口:src/common/ob_schema.cpp:1970
表的信息
每张表的信息都存放在以表名命名的section中。
table_id
配置了这张表在OceanBase系统中的唯一id,在OceanBase系统中, id的取值范围是0-65535.系统会保留0-1000的table_id供系统自身使用.
table_type 配置表是内存表还是磁盘表,取值为 1 的时候, 表示静态部分放到磁盘上, 为2的时候, 表示全部数据放到内存中.
maxcolumnid 配置本表中已经使用过的最大的列id, 由schema 生成程序维护并使用, 防止对列id的重用.
compressfuncname 可选项, 配置这个表在存储时使用的压缩算法名字.
block_size 可选项配置表在存储成sstable时,采用的block大小.
use_bloomfilter 可选项配置表是否使用布隆过滤器, 非零值为使用.
rowkeymaxlength 配置表中主键的最大长度.
rowkey_split 配置表数据拆分是根据表主键值前多少位分布,把数据存储到多个tablet上存储。这个值告诉ChunkServer, 在分拆数据到不同tablet时哪些数据是不应该被分开的, 比如, 当这个值为9的时候, 表示主键前9个字节完全相同的记录放置到同一个tablet中.
在Schema配置文件读取程序源码,已将属性rowkey_max_length及rowkey_split相关代码注解掉,但做为表属性还是存在的,在后面内部元数据表的属性配置中可以看到在继续使用
代码入口:src/common/ob_schema.cpp:2122
列的定义
column_info 配置项中的内容是具体描述一列的, 用”,”分开, 其内容包含:
列的属性 取值为0或1. 0---表示该列只有动态数据(只存在于UpdateServer); 1---表示该列既有动态数据又有静态数据(既存在于UpdateServer 又存在于 ChunkServer).
列id 列在表中的唯一标识, 不可以被重用. 列id必须大于1, 系统保留id为1的用于表示主键.
列名 是一个长度不超过128位的字符串.
类型 列的数据类型.
列长度
代码入口:src/common/ob_schema.cpp:2303
保留列ID
src/common/ob_define.h:
从上面定义可看到OceanBasew保留1-15列ID内部使用,应用自定义列的ID从16开始,最大65535。ID为2和3的列对应记录创建时间与记录修改时间,这两个列ID不能用于其它列,而且这两个列的类型值为8(ObCreateTimeType)与9(ObModifyTimeType)这个在代码中有所检查,比如:src/common/ob_schema.cpp:2410:
与L2462开始处:
RowKey
表主键配置项,大致格式:
其中,括号部分的内容是可选的。
从Schema定义文件中读取RowKey定义的入口在src/common/ob_schema.cpp:2073:
方法parserowkeyinfo,从Schema定义文件中表列定义中读取“rowkey"属性值,其值由逗号分割的多个主键列组成:
每个主键列完整定义形式: , 括号当中的被称为 (什么鬼东西?),括号与括号的内容是可以省略的。先从表的列定义中根据columename查找列定义(ID、长度、类型),如果不存在 就直接使用列定义相关属性,存在刚从 中解析列长度与类型,对应的方法是parserowkey_column:
联表(Join)关系的配置
join配置项的格式大概是这个样子:
joinedtablename 本表关联的表名称
r1/r2/../rn 本表参与关联的列名称,必须为表主键组成列
jr1/jr2/.../jrn 被关联表参与关联的列名称,必须为表主键组成列
f1\$jf1,f2\$jf2,...
参与join操作的左列和右列. join操作总是用右列的值合并到左列的值上, 然后将合并的结果返给用户(左列和右列的值都不发生变化, 合并只体现在反给用户的结果中).此处,讲的合并,我理解上就是以右列值替代左列的值,相关代码入口:src/chunkserver/objoinoperator.cpp:515
以上所有参与关联的列,类型必须一致。
分析Schema文件中Join关系的分析代码在这:src/common/ob_schema.cpp:3563
Schema文件分析的时序关系
RootServer启动时,会去分析配置文件中指定路径下的Schema定义文件。
内部元数据表的建立
在开源的OceanBase 0.4代码的rootserver目录下,还可以看到内部元数据表的Schema配置文件:metatableschema.ini,但我没发现有地方使用这个文件。在代码中寻找了一番,发现OceanBase内部表至少从0.4版本开始是由程序自动创建的,不再使用外部Schema配置文件。
内部表Schema读取路径
核心表_firsttabletentry、 __allallcolumn、__alljoininfo:ObRootServer2::dobootstrap() => ObBootstrap::bootstrapcoretables() => ObBootstrap::createallcoretables()=> ..... => ObSchemaServiceImpl::gettable_schema() => ...... => ObExtraTablesSchema
表_allsysstat、__allsysparam、__allsysconfig、__triggerevent、__users、__tableprivileges、__allcluster、__allserver、__allclient、__allserverstat、__allserversession、__allsysconfigstat、__allstatement:
ObRootServer2::dobootstrap()=> ObBootstrap::bootstrapsys_tables() => ObExtraTablesSchema
由此可见,所有内部表Schema均在类ObExtraTablesSchema中定义,采用直接填写结构TableSchema的方式。代码中定义表结构的片断如下所示:
表属性设置
在表属性的设置中,可以看到设置了rowkey_split属性,但在为核心表及Sys表建立空Tablet时并没有使用此属性,不知道此属性是否起作用,何时起作用,需要在后续代码观看中关注。
列及列属性设置
上面增加表列及设置属性的语句中,column_id后面的一个参数为非0值的,是标明此列是rowkey(主键)组成列,此参数也同时标明了在rowkey组成中的前后顺序。
内部表结构的大致说明请参见《OceanBase内部表定义》
内部表自举(BootStrap)创建流程
核心三表创建时序图
核心表在RootServer自举(每回看到这个词,总感觉比较邪恶,为毛!?)时创建一次,创建完成后,会产生成一个firstmeta.bin文件,RootServer再次启动时,如果本地存在firstmeta.bin文件,则表明已经自举过,可直接进入服务阶段。
Sys表创建时序图
Schema配置文件中数据表的建立
RootServer自举过程中,在完成内部元数据表创建后,会依次创建Schema配置文件中定义的库表,除不为每个表建立空Tablet外,其余过程基本与内部Sys表创建时序一致。
使用SQL创建表的过程
这个就先不在这里分析了,整的有些累了,回头再给补上。
领取专属 10元无门槛券
私享最新 技术干货