TDR表
TDR表是指通过TDR协议定义和访问的数据表。
除TDR表之外,TcaplusDB同时还提供了PB(Protobuf)表(通过PB协议定义和访问的数据表)。
PB表与TDR表并无本质区别,用户可以根据自己对PB或TDR的熟悉程度,来决定使用PB表还是TDR表。需要注意的是当前TcaplusDB的PB表和TDR表支持的功能范围有些差异,用户在选择使用体种表类型的时候,也需要考虑功能是否能满足业务需求。
1. 关于TDR
TDR(Tencent Data Representation)是腾讯推出的,进行游戏开发的基础组件,所有的组件都是基于TDR进行开发。DR数据表示组件以程序库、TDR工具的形式发布。TDR-API本质是相当于一套独立于数据结构的算法,常用API的功能涉及网络编解码、XML数据输入输出、数据可视化、对象关系映射、数据排序。TDR工具实现各种元数据格式之间的转换,并且可以根据XML格式的元数据描述生成C/C++数据结构定义头文件。TDR工具还能够生成实现指定功能的代码,目前支持生成C++\AS3\C#三种语言的代码,支持的功能包括网络编解码、XML数据输入输出、数据可视化。
TDR使用XML来描述定义协议文件,可用TDR工具转换成对应的头文件和cpp文件。生成结构体,cmdID的定义和对应的打解包函数。生成之后的结构体和函数可以直接在程序中应用。Tdr支持生成C++\AS3\C#语言。因为游戏存在运营过程中动态更新,在实际的游戏协议应用中,最关注的是协议的兼容性问题,包括CS协议和SS协议的兼容性。Tdr通过版本号来进行协议兼容性的处理,新加字段需要增加对应的版本号,和整个TDR的版本号。Tdr打包的时候会打上对应的最大版本号和字段版本号。打包可以根据对方的版本号进行打包,解包的时候根据数据的版本号进行解包。支持高版本对低版本的兼容。
<struct name="users" version="1" primarykey="user_id,username,role_id" splittablekey="user_id" desc="user table">
<entry name="user_id" type="uint64" desc="user id"/>
<entry name="username" type="string" size="64" desc="login username"/>
<entry name="role_id" type="int32" desc="a user can have multiple roles"/>
<entry name="level" type="int32" defaultvalue="1" desc="role's level"/>
<entry name="role_name" type="string" size="1024" desc="role's name" version="100"/>
<entry name="last_login_time" type="string" size="64" defaultvalue="" desc="user login timestamp" version="101"/>
<entry name="last_logout_time" type="string" size="64" defaultvalue="" desc="user logout timestamp" version="102"/>
<index name="index1" column="user_id"/>
</struct>
例如以上的协议中,后面几个字段都是新增字段,需要严格按照版本号递增,除了修改具体结构中的版本号之外,还需要修改整体的版本号。
<metalib name="tcaplus_tb" tagsetversion="1" version="1">
这样TDR打包的数据中就有了具体的整体版本号信息和字段版本号信息。可以做到高版本兼容低版本,但是低版本无法兼容高版本。在实际的上线版本运营中,新增字段必须严格按照版本号升级,要注意具体新增字段和总版本号的同步更新。同时又存在cs协议和ss协议,所以新增字段的时候修改点比较多,检查版本号的步骤比较繁琐,需要人工保证。
2. TDR表定义文件示例
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<metalib name="tcaplus_tb" tagsetversion="1" version="4">
<struct name="TestInfo" version="1" desc="" >
<entry name="d" type="uint64" />
<entry name="test" type="uint64" />
</struct>
<struct name="TableInfo" version="1" desc="" >
<entry name="c" type="TestInfo" />
<entry name="test" type="uint64" />
<entry name="string_array" type="string" size="100" />
<entry name="binary" type="tinyint" />
</struct>
<struct name="simple_struct" version="4">
<entry name="c_int8" type="int8" defaultvalue="-1"/>
<entry name="c_uint8" type="uint8" defaultvalue="2"/>
<entry name="c_int16" type="int16" defaultvalue="-3"/>
<entry name="c_uint16" type="uint16" defaultvalue="4"/>
<entry name="c_int32" type="int32" defaultvalue="-5"/>
<entry name="c_uint32" type="uint32" defaultvalue="6"/>
<entry name="c_int64" type="int64" defaultvalue="-7"/>
<entry name="c_uint64" type="uint64" defaultvalue="8"/>
</struct>
<union name="union_type" version="1">
<entry name="Id" type="int32" id="0" defaultvalue="0" desc="id" />
<entry name="Name" type="string" id="1" size="64" defaultvalue="hello" desc="name" />
</union>
<struct name="struct_type" version="1">
<entry name="x" type="int32" defaultvalue="0" desc="x" />
<entry name="y" type="int32" defaultvalue="0" desc="y" />
<entry name="score" type="double" defaultvalue="1.11" version="2" />
<entry name="rank" type="uint8" defaultvalue="1" version="3" />
<entry name="title" type="string" size="48" desc="title" />
<entry name="level2_struct" type="struct_nested" version="2" />
</struct>
<struct name="table_list" version="1" primarykey="uin,name,key1" splittablekey="uin" customattr2="TableType=LIST;ListNum=100;DataProtocolType=PLAIN">
<entry name="uin" type="uint64" desc="QQ"/>
<entry name="name" type="string" size="255" desc="Name"/>
<entry name="key1" type="uint8" desc="key4"/>
<entry name="level" type="int32" defaultvalue="1" />
<entry name="count" type="uint8" defaultvalue="0" />
<entry name="array_count" type="uint32" defaultvalue="1" />
<entry name="items" type="uint64" count="10" refer="array_count"/>
<entry name="c_int8" type="int8" defaultvalue="-1"/>
<entry name="c_uint8" type="uint8" defaultvalue="2"/>
<entry name="c_int16" type="int16" defaultvalue="-3"/>
<entry name="c_uint16" type="uint16" defaultvalue="4"/>
<entry name="c_int32" type="int32" defaultvalue="-5"/>
<entry name="c_uint32" type="uint32" defaultvalue="6"/>
<entry name="c_int64" type="int64" defaultvalue="-7"/>
<entry name="c_uint64" type="uint64"/>
<entry name="c_float" type="float" defaultvalue="1.23456789" version="2"/>
<entry name="c_double" type="double" defaultvalue="9.87654321" version="3" />
<entry name="c_string" type="string" size="200" version="3" />
<entry name="c_string_128K" type="string" size="VALUE_128KB_SIZE" defaultvalue="123456789"/>
<entry name="c_string_256K" type="string" size="VALUE_256KB_SIZE" defaultvalue="123456789"/>
<entry name="c_binary" type="tinyint" count="10" refer="array_count" />
<entry name="binary" type="tinyint" version="5"/>
<entry name="selector" type="short" />
<entry name="single_struct" type="struct_type"/>
<entry name="simple_struct" type="simple_struct" version="4"/>
<entry name="single_union_selector" type="int8" defaultvalue="0" />
<entry name="single_union" type="union_type" select="single_union_selector" />
<entry name="array" type="TableInfo" count="3" refer="array_count"/>
<entry name="c_union" type="union_type" select="selector"/>
<entry name="union_array" type="union_type" count="3" select="selector" refer="array_count"/>
<entry name="c_struct" type="struct_type"/>
<entry name="struct_array" type="struct_type" count="3" refer="array_count"/>
<index name="index1" column="uin"/>
<index name="index2" column="uin,name"/>
</struct>
</metalib>
说明:
元素metalib是xml文件的根元素。
包含属性primarykey的struct元素定义一个表;否则,它只是一个普通的结构体。
每次修改表结构时,版本属性值需要相应地加1,初始版本始终为1。
primarykey属性指定主键字段;对于generic表,您最多可以指定8个主键字段,对于list表,则可以指定7个。
splittablekey属性等效于分片键(shard key),TcaplusDB表被拆分存储到多个存储节点。 splittablekey必须是主键字段之一,一个好的splittablekey应该具有高度分散性,这意味着值的范围很广。
desc属性包含当前元素的描述。
entry元素定义一个字段。支持的值类型包括int32,string,char,int64,double,short等。
index元素定义一个索引,该索引必须包含splittablekey。由于可以使用主键查询表,因此索引不应与主键属性相同。
另外,您可以使用union创建嵌套类型。
union元素包含原始类型的集合,例如整数和字符串,可以将Union也可以作为自定义类型来引用。
Macro标签用于定义常量。
<union name="union_type" version="1">
<entry name="Id" type="int32" id="0" defaultvalue="0" desc="id" />
<entry name="Name" type="string" id="1" size="64" defaultvalue="hello" desc="name" />
</union>
customattr2:
TableType:用于指定表格类型,如list或者sortlist,若不指定类型默认为generic表,且generic表无需添加customattr2属性,关于表格类型的说明请见 Generic表和List表。
ListNum:用于定义list或者sortlist表中,单个key最多可以指向多少个value值,若超过该值可指定从头部或尾部删除老元素。
SortFieldNum:用于sortlist表中,表示该表有多少个排序字段,每个排序字段需要用customattr2标识,如第一个为“sort1”,第二个“sort2”。
SortRule:用于sortlist表中,表示该表的排序方式,如DESC表示降序,INSC升序。如果有多个排序字段,按照sort的序号进行排序,序号小的字段优先级更高。比如排序是降序:sort1不同时按sort1降序;sort1相同时按sort2降序,以此类推。
<struct name="following_action_list" version="1" primarykey="game,myuin", customattr2="TableType=SORTLIST;ListNum=1023;SortFieldNum=1;SortRule=DESC">
<entry name="TimeStamp" type="uint32" desc="单位为分钟" />
<entry name="time" type="uint32" customattr2="sort1" desc="时间"/>
</struct>
下文会对示例中提到的相关属性进行详细描述。
3. TDR表定义文件说明
3.1. 文件结构
3.1.1. XML文件头
标准的XML文件头如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
前期为了减少字符编码问题带来的影响,先使用GBK作为字符编码。长期来讲,应使用UTF-8作为字符编码,以支持多语言和可移植性。
目前暂时先使用:
<?xml version="1.0" encoding="GBK" standalone="yes" ?>
3.1.2. metalib
一个XML文件只能有一个根元素(Root Element)。对于元数据描述用途的文档,根元素是metalib。表明该XML文件的内容是一个元数据描述集合。
3.2. 属性说明
3.2.1. TcaplusDB相关属性
3.2.1.1. primarykey(主键)
primarykey属性指明此元素对应数据库表的主键,其取值为以当前元素为父元素的特定子元数据成员名串,如果有多个成员组成表的主键,则成员名之间用逗号(',')隔开。
约束:
作为主键的成员不能为复合数据类型,只能是基本内置数据类型。
作为主键的成员其取值不能为NULL。
<struct name="GameItem" primarykey="gameid,itemid">
<entry name="gameid" type="uint" />
<entry name="itemid" type="uint" />
<entry name="buytime" type="datetime" />
<entry name="validtime" type="datetime" />
</struct>
根据上面的描述,GameItem的数据表使用gameid和itemid两个成员作为主键。
3.2.1.2. splittablekey(分表因子/分表属性)
splittablekey属性指明计算当前结构与具体数据表映射关系的数据源,其取值为以当前元素为父元素的特定子元数据成员,支持多个key字段组合成为splittablekey。
约束:
作为此成员不能为复合数据类型,只能是基本内置数据类型(void类型除外)。
<struct name="GameItem" primarykey="gameid,itemid" splittablekey="gameid">
<entry name="gameid" type="uint" />
<entry name="itemid" type="uint" />
<entry name="buytime" type="datetime" />
<entry name="validtime" type="datetime" />
</struct>
3.2.1.3. index(本地索引)
基于TcaplusDB主键字段建立的索引,在建表时随表一起建立,并且一旦表创建后,就不能再增加、修改和删除本地索引了,删除表的时候,本地索引会一并删除。
本地索引是实时索引,当插入或者删除数据时,会同时更新索引数据。
本地索引的字段必须包含在主键字段中,并且字段中还必须包含分表因子,因此,查询时最终只会落到一个数据分片上进行查询。
本地索引只支持等值查询。
一个表可以建立多个本地索引,查询时必须包含某一个本地索引的全部字段。
目前只有Generic表支持本地索引。
<struct name="PLAYERONLINECNT" version="1" primarykey="TimeStamp,GameSvrID,GameAppID" splittablekey="TimeStamp">
<entry name="TimeStamp" type="uint32" desc="单位为分钟" />
<entry name="GameSvrID" type="string" size="64" />
<entry name="GameAppID" type="string" size="64" desc="gameapp id" />
<index name="index_1" column="TimeStamp"/>
<index name="index_2" column="TimeStamp, GameSvrID"/>
<index name="index_3" column="TimeStamp, GameAppID"/>
</struct>
如上文所示,index的name不可以重复,且不同的index必须拥有不同的column。
3.2.2. 通用属性
这里的通用属性是指除了根元素外,所有的非根元素都可以具有的属性。对于那些不通用的属性,在描述相关的元素的时候统一进行描述。但是对于include元素,通用属性中只有name属性才有意义。
3.2.2.1. id
id属性表明了该元素的唯一标识,在DR提供的API中可以利用此id来查找、定位特定的元素。
id的取值可以是一个字面量的数字,也可以是一个Macro的名字(对于非Macro类型的元素)。
约束:
同一父元素下的所有子元素的id属性值不能重复。
metalib元素的id属性只能是一个字面量的数字,不可以是Macro名字。
struc/union元素的id属性值只能是0或者正整数。
3.2.2.2. name
name属性提供该元素的字符类型标识。在DR提供的API中可以利用此Name来查找、定位特定的元素。
约束:
同一父元素下的所有子元素的Name属性的值除后面描述的特例外是不可重复的。
name属性的属性值区分大小写,即name="net"与name="NET"认为是不同的属性值。
元数据描述的所有元素必须包含name属性。
3.2.2.3. cname
cname属性提供该元素的中文标识名。通过提供有意义的中文名,可以对元素的意义有更好的理解。(目前已知的应用领域是从Excel表中读取数据生成所需的内存结构)。
3.2.2.4. version
版本属性指明了该元素被引入时该元数据描述库的版本号。该版本号在打包、解包的时候提供裁减的依据。version的取值可以是一个字面量的数字,也可以是一个Macro的名字(对于非Macro类型的元素)。
约束:
metalib,struct,union元素必须包含version属性。
对于struct和union元素,其version属性指明其基准版本号,即该版本号表明该元素加入到metalib时的库版本号。
metalib,struct,union,entry元素的version属性的约束:
metalib元素必须指定version属性,此属性指明该元数据描述库的当前版本,称为库版本。库版本号的变化反映了整个元数据描述库的变化情况,只要库发生了变化,库版本号就必须同步保持变化。库版本号永远只能增加,不能减少。
每个struct和union元数据都必须包含version属性,此属性表明该Meta创建时的库版本号,称为元数据基准版本号(MetaBaseVersion),一旦表创建后不能更改。
每个元数据成员有自己的当前版本号,该版本号表明该MetaMember被添加时的库版本号,即该版本号表明了该元数据成员是在那个库版本中被引入的。当一个MetaMember没有定义其版本号时,缺省继承它所在的元数据的基准版本号。
一个元数据(Meta)的当前版本号,此版本号为其成员中当前版本号的最大值。
3.2.2.5. desc
描述信息。对该元素的一些简要描述,表明该元素的用途、意义等等。
3.2.3. metalib元素
metalib元素只能包含如下子元素:include, macro, macrosgroup, struct, union。
metalib元素除可以包含以上描述的id,name,version属性外,还可以包含以下属性:tagsetversion。
3.2.3.1. name
只有name属性值相同的XML描述文件才能放在一起生成元数据描述库,除非其name属性为空串。metalib的name属性类似于名字空间。
3.2.3.2. tagsetversion
此属性指明元数据描述使用的XML标签集的版本信息,通过此属性处理程序可以兼容使用不同版本元数据标签集定义的XML描述文件。
此属性的值为无符号整数,并且必须是递增的,每调整一次元数据描述XML标签集定义,必须使用新的版本号。
如果XML文件中,metaLib元素中没有包含此属性,则处理程序缺省按DR API支持的最新版本的标签定义进行解析。
约束:
本文档中元数据描述XML标签集tagsetversion值定义为1,即使用本文档中定义的标签生成的XML描述文件,其metaLib元素的tagsetversion属性值为1。
3.2.3.3. include元素
include元素必须是metalib元素的子元素。
include元素用于指示XML文件间的依赖关系。Include元素只需要定义file属性,但是建议定义name(通用)属性。定义全局唯一的name属性,有助于在TDR进行include元素规范性检测时,对不规范的地方提供详细的定位信息。在严格意义上,include不属于元数据库,include元素不影响元数据库的hash值,不受版本的约束,TDR不对include节点的name属性做唯一性检查。
当使用TDR的xml2h功能时,include元素被转换为头文件中的#include宏定义,file属性值对应的文件路径名中的xml后缀被直接替换为h。
例如,XML文件中的include元素
<include name="head" file="./head.xml">
对应头文件中的如下宏定义:
#include "./head.h"
当使用TDR的cplusplus功能时,include元素被转换为头文件中的#include宏定义,file属性值对应的文件路径名中的xml后缀被直接替换为h,并删除了路径中的目录信息。之所以删除路径中的目录信息,是因为对于cplusplus功能,TDR把所有的文件都生成在相同的目录中。
例如,XML文件中的include元素
<include name="head" file="../comm.xml">
对应头文件中的如下宏定义:
#include "comm.h"
对于XML文件中出现的多个include元素,TDR依次处理这些include元素。
3.2.3.4. file
file属性用于指明当前XML文件依赖的其他XML文件。如果XML文件中include元素的file属性值是当前XML文件路径本身或为””,则此include元素不起作用。
约束:
file属性的值(XML文件路径)指定的文件必须出现在(启动TDR工具时的)命令行指定的XML文件列表中。
3.2.4. macro元素
macro元素可以是metalib元素的子元素,也可以是macrosgoup元素的子元素。macro元素与C语言中的宏的意义类似,在实际的处理中也是映射到C语言的宏。Macro元素相对简单,只需要有name(通用)属性和value属性就可以了。
3.2.4.1. value
value属性用于指明该macro代表的值是多少(相比与C语言中宏的概念,name属性的值是宏的名字,value属性的值是宏的内容)。其取值可以是一个字面量的数字,也可以是一个之前已定义的Macro的名字。
约束:
目前value属性值是通过int数据类型来存储的,因此只能处理int数据类型值域范围里的数据。
3.2.5. macrosgroup元素
macrosgroup元素用于对macro元素进行分类,每一类macro元素组成一个宏定义组。Macrosgroup只需包含name和desc属性就可以了。
macrosgroup元素的子元素为macro元素,当然macro元素也可以不属于任何宏定义组。
约束:
macrosgroup元素必须指定name属性。
macrosgroup的macro子元素的value属性值必须唯一,即value属性值相同的macro元素不能放入同一个macrosgroup元素下。
<macro name="MAX_BODY_LEN" value="32000" />
<macrosgroup name=”MsgID” desc=”id of net message” >
<macro name="CMD_LOGIN" value="0" />
<macro name="CMD_LOGOUT" value="1" />
</macrosgroup >
3.2.6. struct元素
struct元素必须是metalib元素的子元素,在tcaplus中一张表对应一个struct。
struct元素是DR中最复杂的元素,与C语言的struct概念类似。
3.2.6.1. size
size属性指明该struct的内存占用大小。如果不指明size属性,那么该struct的大小会通过计算成员的大小后自动得出该struct的大小。但是通过指定size属性,可以让该struct预占多一些空间,size属性指定的大小不能比自动计算出来的大小更小。entry中的string类型字段必须定义size属性大小
3.2.6.2. align
align属性对应于编译器的#pragma pack指令。利用align属性可以指定该struct内部所有成员的对齐大小。如果不指定align属性,缺省对齐大小为1。指定align属性会影响到该结构体的大小、每个成员的偏移。
3.2.6.3. customattr2
customattr2属性用于定义表格的属性,包括:
TableType:用于指定表格类型,如list或者sortlist,若不指定类型默认为generic表,且generic表无需添加customattr2属性,关于表格类型的说明请见 Generic表和List表。
ListNum:用于定义list或者sortlist表中,单个key最多可以指向多少个value值,若超过该值可指定从头部或尾部删除老元素。
SortFieldNum:用于sortlist表中,表示该表有多少个排序字段,每个排序字段需要用customattr2标识,如第一个为“sort1”,第二个“sort2”。
SortRule:用于sortlist表中,表示该表的排序方式,如DESC表示降序,INSC升序。如果有多个排序字段,按照sort的序号进行排序,序号小的字段优先级更高。比如排序是降序:sort1不同时按sort1降序;sort1相同时按sort2降序,以此类推。
<struct name="table_Sortlist_single" primarykey="key, name" customattr2="TableType=SORTLIST;ListNum=1023;SortFieldNum=1;SortRule=DESC" version="5" desc="用于list表遍历测试, 需要4个shard, 建表list最大1023个元素" >
...
</struct>
3.2.6.4. entry子元素
entry对应的是元数据成员的概念,下面描述了entry元素可以包含的属性。
3.2.6.4.1. type
指明entry数据成员的数据类型;其取值为可以为基本内置数据类型,也可以为自定义的复合数据类型,在DR API中对type属性值不区分大小写。
约束:
自定义复合类型不支持后向引用。
<struct name="type1">
</struct>
<struct name="type2">
<entry name="item1" type="int" />
<entry name="item2" type="float" />
<entry name="item3" type="type1" />
</struct>
目前对于C/C++/c#语言,支持的基本数据类型如下表所示:
类型名 | 分类 | 存储长度(字节) | 取值范围 |
---|---|---|---|
byte | 字节 | 1 | |
char | 单字节字符 | 1 | |
tinyint | 整数 | 1 | -128~127 |
tinyuint | 整数 | 1 | 0~255 |
smallint | 整数 | 2 | -32768~32767 |
smalluint | 整数 | 2 | 0~65535 |
int | 整数 | 4 | -231~231-1 |
uint | 整数 | 4 | 0~232-1 |
bigint | 整数 | 8 | -263~263-1 |
biguint | 整数 | 8 | 0~264-1 |
float | 浮点 | 4 | |
double | 浮点 | 8 | |
date | 日期 | 4 | -9999-00-00 ~9999-12-31 |
time | 时间 | 4 | -999:00:00~999:59:59 |
dateTime | 日期/时间 | 8 | 0000-00-00 00:00:00~9999-12-31 23:59:59 |
string | 字符串 | 可变 | |
wchar | 宽字符 | 2 | |
wstring | 宽字符集 | ||
ip | Ipv4地址 | 4 | 0.0.0.0~255:255:255:255 |
void | 空类型 | ||
int8 | 整数 | 1 | -128~127 |
uint8 | 整数 | 1 | 0~255 |
int16 | 整数 | 2 | -32768~32767 |
uint16 | 整数 | 2 | 0~65535 |
int32 | 整数 | 4 | -231~231-1 |
uint32 | 整数 | 4 | 0~232 -1 |
int64 | 整数 | 8 | -263~263-1 |
uint64 | 整数 | 8 | 0~264-1 |
- date
表示日期数据类型,c/c++支持的范围是-9999-00-00 到9999-12-31, c#支持的范围是0001-01-01到9999-12-31。DR的API采用4字节整数对date数据进行存储,实际存储格式是自定义的;但以"YYYY-MM-DD"格式对date数据类型进行显示,输入和输出; DR提供了存储格式和显示格式相互转换的API接口。
- time
表示时间数据类型,c/c++支持的范围是-999:00:00 到999:59:59, c#支持的范围是00:00:00到23:59:59。DR的API采用4字节整数对time数据进行存储,实际存储格式是自定义的;但以"HHH:MM:SS"格式对time数据类型进行显示,输入和输出; DR提供了存储格式和显示格式相互转换的API接口。
- datetime
表示日期时间组合数据类型,c/c++支持的范围是-9999-00-00 00:00:00~9999-12-31 23:59:59 ,c#支持的范围是0001-01-01 00:00:00 ~9999-12-31 23:59:59。DR的API采用8字节长整数对datetime数据进行存储,实际存储格式是自定义的;但以"YYYY-MM-DD HH:MM:SS"格式对time数据类型进行显示,输入和输出; DR提供了存储格式和显示格式相互转换的API接口。
- ip
基本数据类型Ip表示IPV4地址,以"数字."格式的字符串作为输入和显示,此自符串的具体格式如为:a.b.c.d,其中a,b,c,d为值为0-255之间的数字,这个数字可以采用8,10,16进制进行表示。
ipv4地址串 | 描述 |
---|---|
"4.3.2.16" | 十进制表示 |
"004.003.002.020" | 8进制表示 |
"0x4.0x3.0x2.0x10" | 16进制表示 |
"4.003.002.0x10" | 各种进制混合 |
- void
TDR引入void数据类型的主要目的是为支持通用指针,即void类型必须和指针类型一起使用才有效。
3.2.6.4.2. size
size属性指明该元素的内存占用大小。如果不指明size属性,那么该元素的大小会通过计算成员的大小后自动得出该元素的大小。但是通过指定size属性,可以让该元素预占多一些空间,size属性指定的大小不能比自动计算出来的大小更小。
其取值为正整数或合法的宏定义。
约束:
对于自定义类型(union/struct)元素,entry本身设置的size属性将忽略,将以union/struct元素中定义的size属性为准。
对于内置数据类型,目前只有string,wstring类型支持size属性,其他内置数据类型不支持size属性。
<struct name="type1" >
<entry name="name" type="string" size="32" />
<entry name="pass" type="string" size="32" />
</struct>
3.2.6.4.3. count
count属性指明了当前元数据成员的个数(数组大小)。count可以是字面量的数字,也可以是一个Macro。
count属性如果不指定,缺省值为"1",否则取值必须范围为:>=1的整数,此时必须使用refer属性来指明可以用于确定数组大小的元数据成员。
<macro name="MAX_COUNT" value="100" />
<struct name="type1">
<entry name="item1" type="int" count="10" />
<entry name="item2" type="float" count="MAX_COUNT" />
<entry name="is_exist" type="int" />
<entry name="item3" type="int" refer="is_exist" />
<entry name="total" type="int" />
<entry name="item4" type="int" count="10" refer="total" />
</struct>
注意,一级字段string类型不需要定义count和refer属性,如果要定义可以改成struct嵌套进去,例如:
<macro name="MAX_TEX_ID_LENGTH" value="35" />
<macro name="MAX_TEX_IDS_COUNT" value="150" />
<struct name="Cube1150" version="1" primarykey="FUin" splittablekey="FUin" >
<entry name="TxnIds" type="TxnIdWrapper" count="MAX_TEX_IDS_COUNT" version="2" refer="TxnIdsCount" />
</struct>
<struct name="TxnIdWrapper" version="2" >
<entry name="TxnId" type="string" size="MAX_TEX_ID_LENGTH" />
</struct>
3.2.6.4.4. refer
refer属性通常指向该元数据结构中的另一个元数据成员。
当前元数据成员是数组时,refer属性指向的元素的值指明了该数据成员的实际大小。
当前元数据成员是单一元素时,refer属性指向的元素的值指明了该数据成员是否在实际数据中存在(用于处理Option的数据)。
取值为:该元素的直接父元素包含的特定子元素(不支持后向引用,值元素必须在当前元素之前)。
<struct name="type1">
<entry name="item1" type="int" />
<entry name="item2" type="float" count="10" refer="item1" />
</struct>
扩展情况:有时候还需要引用跟当前元素不在同一层次的子元素,此时使用类似Path.Target的形式来指定。
<struct name="type1">
<entry name="item1" type="int" />
<entry name="item2" type="int" />
</struct>
<struct name="type2">
<entry name="head" type="type1" />
<entry name="item4" type="float" count="10" refer="head.item1" />
</struct>
约束:
refer属性所指元素的值必须小于等于此元素的count属性的值,以上例为例head.item1的值必须不大于10;当元素是单一元素时,count属性取默认值1,这时refer属性所指元素的值只能为1或0,取值为1时表示比元素存在,取值为0时表示此元素不存在。
此元素的refer属性所指元素,不能同时被其它元素或父元素指定为sizeinfo或versionindicator属性。
3.2.6.4.5. defaultvalue
defaultvalue属性指明了如何对该元数据成员的值在没有显式定义时该怎么取值。
取值:合法的字符串,同时该串的内容应该跟该元数据成员的类型匹配。
如果不指定defaultvalue属性,则缺省值为0(同时对于数组不作填充处理)。
约束:
目前支持对内置数据类型设定缺省值,对于自定义复杂数据类型不支持设置缺省值。
<struct name="type1">
<entry name="item1" type="int" count="100" defaultvalue="100" />
<entry name="item2" type="date" defaultvalue="2009-11-03" />
<entry name="item3" type="int"/>
</struct>
3.2.6.4.6. select
select属性和refer属性类似,通常指向该元数据结构中的另一个元数据成员。
select属性指明了如何选择union中数据成员的方法。通常是使用select属性指向的元素的值来决定union中到底使用哪个数据成员。
取值为:该元素的直接父元素包含的特定子元素(不支持后向引用,值元素必须在当前元素之前)。
<union name="type1">
<entry name="item1" type="int" id="1" />
<entry name="item2" type="int" id="2" />
</union>
<struct name="type2">
<entry name="selector" type="short" />
<entry name="item3" type="type1" select="selector" />
</struct>
3.2.6.4.7. customattr2
customattr2属性用于表示字段是否属于排序字段,比如排序是降序:sort1不同时按sort1降序;sort1相同时按sort2降序,以此类推。
<struct name="table_Sortlist_single" primarykey="key, name" customattr2="TableType=SORTLIST;ListNum=1023;SortFieldNum=1;SortRule=DESC" version="5" desc="用于list表遍历测试, 需要4个shard, 建表list最大1023个元素" >
<entry name="key" type="uint32" desc="单个uint32作为KEY的时候, hashcode = key % 10000"/>
<entry name="name" type="int16" />
<entry name="type_int16" type="int16" desc="type_int16" customattr2="sort1"/>
<entry name="type_int64" type="int64" desc="type_int64" customattr2="sort2"/>
</struct>
3.2.7. Union元素
union元素必须是metalib元素的子元素。
union元素与C语言中的union类似。在定义上,union元素和struct元素基本相同。union元素与struct元素的区别与C语言中union和struct的区别相同。
3.2.7.1. entry子元素
和struct元素一样,entry对应的也是元数据成员的概念。union中的entry子元素除了可以拥有struct中的entry子元素一样的属性外,还可以拥有另外两个额外的属性。
约束:
union中不能再包含有union类型的元数据成员。
3.2.7.1.1 minid & maxid
通常使用ID属性来作为确定union中到底选择那个元数据成员的依据。但是在实际应用中,可能需要使用一个范围来对应一个元数据成员,这时候使用minid和maxid属性来表示。
当使用minid和maxid时,表示的意义是区间:[minid, maxid]。
当使用ID时,表示的意义是区间:[ID, ID]。
union类型的数据结构的子元素可以没有ID,此时表示该子元素是缺省的元素。当其他子元素都无法匹配的时候,该子元素匹配选择。
为了支持多重取值范围的情况,对于union类型的元数据结构的子元素的名字可以重复,但是这些同名的子元素的类型必需完全一致(对于这种情况,在编译的时候需要给出一些Info类型的提示)。
约束:
union元素的子元素,有且仅有一个可以没有ID属性。
maxid,minid属性必须同时出现。
如果同时出现了maxid,minid,id属性,则在union结构中选择成员时,以maxid和minid两个属性为准。
ID不能为负数,多个entry的ID也不能交叉
<union name="type1">
<entry name="example" type="int" minid="1" maxid="100" />
<entry name="example" type="int" id="108" />
<entry name="example" type="int" minid="200" maxid="300" />
<entry name="item2" type="int" id="2" />
</union>
则example子元素对应的选择器的取值范围可以是:{[1,100],[108,108],[200,300],[-99,-99]}。
4. TDR表修改说明
表元数据信息变更约束条件具体如下:
XML/TDR文件
(1)一个表内不允许有重复的字段名。要求Key字段名无重名,Value字段名无重名,Value字段名和Key字段名无重名。
(2)TDR meta定义中primarykey的值(即Key字段名)必须属于存在的字段名,splittablekey的值必须属于存在的primarykey的值(即Key字段名)。注意:primarykey定义的就是Key字段。
(3)不允许删除Key字段,不允许添加Key字段,不允许更改Key字段类型。Key字段长度不允许改变。不允许给Key字段配置默认值。
(4)允许添加Value字段,允许更改Value字段默认值,不允许删除Value字段,不允许更改Value字段类型,Value字段最大长度允许加长不允许缩短,允许更改Value字段默认值但默认值实际长度不能超过该Value字段的最大长度。
(5)Index字段必须属于存在的Key字段名,Index字段中必须包含splittablekey所指定的字段,并且Index字段必须全部属于primarykey。
(6)Index字段中不允许有重复的字段名,Index字段的column属性长度不能超过120个字节
(7)List类型表不允许配置Index字段。
(8)List类型表的LIST最多元素个数允许被改大不允许被改小,同时List类型表的LIST最多元素个数不能超过10000个。
(9)Index的数量及Index所包括的字段名均不允许变更。
(10)修改“LIST最多元素个数”需要表所在的tcapsvrs版本均高于3.13.0.115217。
(11)现有的TDR限制: Key字段名不允许变更、Value字段名不允许变更。
(12)如果新增字段定义了count没定义refer的字段,不影响变更表,但之后不允许对count做修改,不允许通过变更; count和size属性一旦定义,表变更时只能改大不能改小,不需要修改版本号。
(13)tcaplus表的entry字段个数上限是256个, 到达110个的时候会有warning提示, list类型表value个数上限需减1
5. TDR表修改示例
原始结构:
<?xml version="1.0" encoding="GBK" standalone="yes" ?>
<metalib name="tcaplus_tb" tagsetversion="1" version="1">
<struct name="PLAYERONLINECNT" version="1" primarykey="TimeKey,GameSvrID" splittablekey="TimeKey">
<entry name="TimeKey" type="uint32" desc="time min" />
<entry name="GameSvrID" type="string" size="32" />
<entry name="GameAppID" type="string" size="64" desc="game app id" />
<entry name="OnlineCntIOS" type="uint32" defaultvalue="0" desc="ios online" />
<entry name="OnlineCntAndroid" type="uint32" defaultvalue="0" desc="android online" />
<entry name="array_count" type="uint32" defaultvalue="1" />
<entry name="items" type="uint64" count="10" refer="array_count"/>
<entry name="strstr" type="string" size="4096" desc="string" />
<entry name="strstr1" type="string" size="4096" desc="string" />
<index name="index1" column="TimeKey"/>
<index name="index2" column="TimeKey,GameSvrID"/>
</struct>
</metalib>
5.1. 示例1:增加struct内的字段的情况
metalib的版本号加一。
新增字段strstr2的版本号为新metalib的版本号。
<?xml version="1.0" encoding="GBK" standalone="yes" ?>
<metalib name="tcaplus_tb" tagsetversion="1" version="2">
<struct name="PLAYERONLINECNT" primarykey="TimeKey,GameSvrID" splittablekey="TimeKey" version="1">
<entry name="TimeKey" type="uint32" desc="time min" />
<entry name="GameSvrID" type="string" size="32" />
<entry name="GameAppID" type="string" size="64" desc="game app id" />
<entry name="OnlineCntIOS" type="uint32" defaultvalue="0" desc="ios online" />
<entry name="OnlineCntAndroid" type="uint32" defaultvalue="0" desc="android online" />
<entry name="array_count" type="uint32" defaultvalue="1" />
<entry name="items" type="uint64" count="10" refer="array_count"/>
<entry name="strstr" type="string" size="4096" desc="string" />
<entry name="strstr1" type="string" size="4096" desc="string" />
<entry name="strstr2" type="string" size="4096" desc="string" version="2"/>
<index name="index1" column="TimeKey"/>
<index name="index2" column="TimeKey,GameSvrID"/>
</struct>
</metalib>
注意:结构体内增加字段的情况
metalib的版本号加一。
结构体TestInfo内新增字段testadd的版本号为新metalib的版本号。
原XML:
<?xml version="1.0" encoding="GBK" standalone="yes" ?>
<metalib name="tcaplus_tb" tagsetversion="1" version="3">
<struct name="TestInfo" version="3" desc="" >
<entry name="d" type="uint64" />
<entry name="test" type="uint64" />
</struct>
<struct name="PLAYERONLINECNT222" primarykey="TimeKey,GameSvrID" splittablekey="TimeKey" version="1">
<entry name="TimeKey" type="uint32" desc="time min" />
<entry name="GameSvrID" type="string" size="32" />
<entry name="strstr1" type="string" size="4096" desc="string" />
<entry name="tableinfo" type="TestInfo" desc="table info" version="3"/>
</struct>
</metalib>
新XML:
<?xml version="1.0" encoding="GBK" standalone="yes" ?>
<metalib name="tcaplus_tb" tagsetversion="1" version="4">
<struct name="TestInfo" version="3" desc="" >
<entry name="d" type="uint64" />
<entry name="test" type="uint64" />
<entry name="testadd" type="uint64" version="4"/>
</struct>
<struct name="PLAYERONLINECNT222" primarykey="TimeKey,GameSvrID" splittablekey="TimeKey" version="1">
<entry name="TimeKey" type="uint32" desc="time min" />
<entry name="GameSvrID" type="string" size="32" />
<entry name="strstr1" type="string" size="4096" desc="string" />
<entry name="tableinfo" type="TestInfo" desc="table info" version="3"/>
</struct>
</metalib>
5.2. 示例2:增加一个新struct的情况
metalib的版本号加一。
新增结构体TestInfo的版本号为新metalib版本号。
新增字段tableinfo的版本号为新metalib版本号。
<?xml version="1.0" encoding="GBK" standalone="yes" ?>
<metalib name="tcaplus_tb" tagsetversion="1" version="3">
<struct name="TestInfo" version="3" desc="" >
<entry name="d" type="uint64" />
<entry name="test" type="uint64" />
</struct>
<struct name="PLAYERONLINECNT" primarykey="TimeKey,GameSvrID" splittablekey="TimeKey" version="1">
<entry name="TimeKey" type="uint32" desc="time min" />
<entry name="GameSvrID" type="string" size="32" />
<entry name="GameAppID" type="string" size="64" desc="game app id" />
<entry name="OnlineCntIOS" type="uint32" defaultvalue="0" desc="ios online" />
<entry name="OnlineCntAndroid" type="uint32" defaultvalue="0" desc="android online" />
<entry name="array_count" type="uint32" defaultvalue="1" />
<entry name="items" type="uint64" count="10" refer="array_count"/>
<entry name="strstr" type="string" size="4096" desc="string" />
<entry name="strstr1" type="string" size="4096" desc="string" />
<entry name="strstr2" type="string" size="4096" desc="string" version="2"/>
<entry name="tableinfo" type="TestInfo" desc="table info" version="3"/>
<index name="index1" column="TimeKey"/>
<index name="index2" column="TimeKey,GameSvrID"/>
</struct>
</metalib>
5.3. 示例3:扩大数组大小的情况(不需要修改版本号)
- 被修改字段items的count变成15。
<?xml version="1.0" encoding="GBK" standalone="yes" ?>
<metalib name="tcaplus_tb" tagsetversion="1" version="3">
<struct name="TestInfo" version="3" desc="" >
<entry name="d" type="uint64" />
<entry name="test" type="uint64" />
</struct>
<struct name="PLAYERONLINECNT" primarykey="TimeKey,GameSvrID" splittablekey="TimeKey" version="1">
<entry name="TimeKey" type="uint32" desc="time min" />
<entry name="GameSvrID" type="string" size="32" />
<entry name="GameAppID" type="string" size="64" desc="game app id" />
<entry name="OnlineCntIOS" type="uint32" defaultvalue="0" desc="ios online" />
<entry name="OnlineCntAndroid" type="uint32" defaultvalue="0" desc="android online" />
<entry name="array_count" type="uint32" defaultvalue="1" />
<entry name="items" type="uint64" count="15" refer="array_count" />
<entry name="strstr" type="string" size="4096" desc="string" />
<entry name="strstr1" type="string" size="4096" desc="string" />
<entry name="strstr2" type="string" size="4096" desc="string" version="2"/>
<entry name="tableinfo" type="TestInfo" desc="table info" version="3"/>
<index name="index1" column="TimeKey"/>
<index name="index2" column="TimeKey,GameSvrID"/>
</struct>
</metalib>