Generic表和List表
TcaplusDB根据表记录类型的不同,又分为Generic表和List表,Generic表一个Key(1-8个字段)记录对应一个Record记录,List表一个Key(1-7个字段)记录对应多个Record记录。List表根据是否进行排序分为普通list表和sortlist表,对于普通List表,Tcaplus内部是无序的,用户取出一个Key下的所有Value时,Value内部是无序的,但是业务可以根据插入顺序和淘汰规则来实现不同场景。SortList表按照某个指定的Value字段进行排序插入,用户可以按照从大到小或者从小到大的顺序进行取值。在PB和TDR表中都存在这三种schema模式,用户可以根据需求选择合适的模式。
1. 数据表及相关规则
1.1. 数据表规则
数据表名称不超过32字节(包含'\0'结尾),只能包含字母、数字、下划线,首字母为字母、下划线
字段名不超过32字节(包含'\0'结尾)
每个Key字段不超过1024字节
每个Value字段不超过10MB
单条记录Pack后长度不超过10MB
Pb表的所有key字段,序列后的总buffer长度不超过1022字节
1.2. 变更规则
不允许对primarykey、splitkey、index做任何变更;
Value字段可以增加字段但不能减少字段,并且增加字段时要注意版本号的变更;
Value字段默认值可更改,Value字段最大长度只能改大不能改小;
不允许删除Value字段,不允许更改Value字段名称和类型;
List类型表的最大元素个数只允许改大不允许改小,且最大元素个数不能超过10000;
1.3. Generic表
可以建索引(见本地索引和全局索引)
最多支持8个Key字段,api版本大于等于3.46支持256个Value字段,低于3.46版本支持128个Value字段
1.4. List表
不能建索引
Key字段最多只能有7个,Value字段最多255个, 各有一个要预留给系统使用。
List支持方便的头尾操作, 适合邮件,留言板,战斗记录等场景。
List表需要指定单个Key记录下的最大元素个数(目前最大10000),超过最大元素个数时,可指定从头部或尾部删除老元素。默认采用FIFO方式淘汰。SortList表和普通List表一样有最大元素个数,插入超过最大元素个数N时,对于正序(从小排到大)总是保留最小的N个元素,倒序则反之,总是保留最大的N个元素。
SortList表最多支持同时指定4个排序字段。
可以一次取出单个Key下的所有Value,Value内部的排列无序。
2. Generic表
2.1. TDR-Generic表示例
<struct name="PLAYERONLINECNT" version="1" primarykey="TimeStamp,GameSvrID" 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" />
<entry name="OnlineCntIOS" type="uint32" defaultvalue="0" desc="ios在线人数" />
<entry name="OnlineCntAndroid" type="uint32" defaultvalue="0" desc="android在线人数" />
<entry name="BinaryLen" type="smalluint" defaultvalue="1" desc="数据来源数据长度;长度为0时,忽略来源检查"/>
<entry name="binary" type="tinyint" desc="二进制" count= "1000" refer="BinaryLen" />
<entry name="binary2" type="tinyint" desc="二进制2" count= "1000" refer="BinaryLen" />
<entry name="strstr" type="string" size="64" desc="字符串"/>
<index name="index_id" column="TimeStamp"/>
</struct>
2.2. PB-Gneric表示例
message pb_generic_index_shardingkey {
option(tcaplusservice.tcaplus_primary_key) = "openid,tconndid,timekey,svrid";
option(tcaplusservice.tcaplus_index) = "index_openid(openid)";
option(tcaplusservice.tcaplus_index) = "index_openid_tconndid(openid,tconndid)";
option(tcaplusservice.tcaplus_index) = "index_full_key(openid,tconndid,timekey,svrid)";
option(tcaplusservice.tcaplus_sharding_key) = "openid";
//4个key
required uint32 openid = 1; //QQ Uin
required string timekey = 2[(tcaplusservice.tcaplus_size) = 20, (tcaplusservice.tcaplus_desc) = "bingo"];
required int32 tconndid = 3;
required string svrid = 4;
//value
required string gamesvrid = 5[(tcaplusservice.tcaplus_size) = 11];
repeated property other_property= 6 ;//其他扩展属性
optional item_bag items = 7;
repeated int64 lockid = 8 [packed = true];
optional bytes val = 9;
optional pay_info pay = 10;
optional uint32 id_uint32 = 11;
optional int32 id_int32 = 12;
}
3. List表
TcaplusDB对List表的存储采用分级机制,包括:
索引记录,FullKey + (idx1,idx2,idx3,……,idxn)
数据记录,[FullKey+idx1,value1][FullKey+idx2,value2][……][FullKey+idxn,valuen]
因list表的实现机制上存在系统索引记录(每个key都会存在一条索引记录),所以业务实际记录数会小于TotalSize总记录数(key个数+实际记录数) 例如:遍历查询表里实际记录41条,其中key个数26个,那么count表的TotalSize总记录数为67
3.1. TDR-List表示例
<struct name="following_action_list" version="1" primarykey="game,myuin">
<entry name="game" type="uint64" defaultvalue="0" desc="游戏ID"/>
<entry name="myuin" type="uint32" desc="QQ号"/>
<entry name="actiontype" type="uint8" defaultvalue="0" desc="1-分享图片,2-赞图片,3-评论图片"/>
<entry name="uin2" type="uint32" desc="关注人QQ号"/>
<entry name="nick2" type="string" size="128" desc="关注人昵称"/>
<entry name="sex" type="uint8" defaultvalue="0" desc="关注人性别男0女1"/>
<entry name="pid" type="string" size="33" desc="关注人操作图片ID"/>
<entry name="time" type="uint32" desc="时间"/>
<entry name="content" type="string" size="1024" desc="动态详细内容"/>
</struct>
3.2. PB-List表示例
syntax = "proto3";
package myTcaplusTable;
import "tcaplusservice.optionv1.proto";
message tb_online_list {
option(tcaplusservice.tcaplus_primary_key) = "openid,tconndid,timekey";
option(tcaplusservice.tcaplus_customattr) = "TableType=LIST;ListNum=1900";
int32 openid = 1; //QQ Uin
int32 tconndid = 2;
string timekey = 3;
string gamesvrid = 4;
int32 logintime = 5 ;
repeated int64 lockid = 6;
pay_info pay = 7;
message pay_info {
uint64 total_money = 1;
uint64 pay_times = 2;
}
map<string, pay_info> projects = 8;
}
3.3. list表淘汰策略
/**
@brief 设置LIST满时,插入元素时,删除旧元素的模式--TDR接口才能直接调用此方法
@param [in] chListShiftFlag TCAPLUS_LIST_SHIFT_NONE: 不允许删除元素,若LIST满,插入失败;TCAPLUS_LIST_SHIFT_HEAD: 移除最前面的元素;TCAPLUS_LIST_SHIFT_TAIL: 移除最后面的元素
如果表是排序List,必须要进行淘汰,且淘汰规则是根据字段的排序顺序进行自动制定的,用户调用该接口会失败
@retval 0 设置成功
@retval 非0 设置失败,具体错误参见 \link ErrorCode \endlink
*/
int32_t SetListShiftFlag(IN const char chListShiftFlag = TCAPLUS_API_LIST_SHIFT_HEAD);
当设置为淘汰策略为TCAPLUS_LIST_SHIFT_HEAD(列表满了之后,淘汰列表头部的元素)时,配合尾部插入一起使用,便可实现类似先进先出的队列。
当设置为淘汰策略为TCAPLUS_LIST_SHIFT_TAIL(列表满了之后,淘汰列表尾部的元素)时,配合头部插入一起使用,也可实现类似先进先出的队列。
4. SortList表
最多允许4个排序字段(一级字段),且在建表的xml(tdr)中指定,具体格式如下:
<struct name="following_action_list" version="1" primarykey="game,myuin" customattr2="TableType=SORTLIST;SortRule=INSC;SortFieldNum=1">
<entry name="game" type="uint64" defaultvalue="0" desc="游戏ID"/>
<entry name="myuin" type="uint32" desc="QQ号"/>
<entry name="actiontype" type="uint8" defaultvalue="0" desc="1-分享图片,2-赞图片,3-评论图片"/>
<entry name="uin2" type="uint32" desc="关注人QQ号"/>
<entry name="nick2" type="string" size="128" desc="关注人昵称"/>
<entry name="sex" type="uint8" defaultvalue="0" desc="关注人性别男0女1"/>
<entry name="pid" type="string" size="33" desc="关注人操作图片ID"/>
<entry name="time" type="uint32" customattr2="sort1" desc="时间"/>
<entry name="content" type="string" size="1024" desc="动态详细内容"/>
</struct>
如上customattr2="TableType=SORTLIST;ListNum=1023;SortFieldNum=1"表示该表格类型为SORTLIST,SortRule=INSC表示升序排列,SortFieldNum=1表示排序字段有1个,customattr2="sort1"表示第一个排序字段。
排序默认按照从小到大进行排序
暂时不允许在表变更时从无序List变为SortList,也不允许从SortList变更为无序List,不允许表变更变换排序字段的顺序以及增减排序字段(这个均采用自己写so走表变更Key-Value方式实现)。
排序字段最大字节数8B,排序字段的类型:byte, uint16,uint32,uint64,int16,int32,int64,float,double【string(包含\0最多8B,暂时不支持)】。
排序是指Value字段参与排序,而不是Key。
使用说明:
排序
当已有数据结构排好序后,再采用ListAddAfter进行数据插入时,采用插入排序效果最佳。 允许多个排序字段联合排序(最多4个),先按照第一个字段进行排序,第一个字段相同时,再按照第二个字段排序,依次类推排序。
插入
对于ListAddAfter,流程是:先看是否已经满了,如果满了且不允许淘汰元素,则插入失败,如果满了,允许淘汰,则删掉那个元素,并且获取一个BiggestIndex,将新元素插在对应位置,并挪动其他元素。
而对于SortList,当用户进行ListAddAfter时,List数目超过最大元素个数N时,对于正序(从小排到大)总是保留最小的N个元素,也就是说插入的元素比当前最大值还大时,会插入失败(因为立即被淘汰)返回错误码 SVR_ERR_FULL_SORTLIST_CANT_INSERT,而倒序则反之,总是保留最大的N个元素。(即SetListShiftFlag中的淘汰规则对sortlist表失效,按照排序规则淘汰)
4.1. TDR-Sortlist表示例
<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="level" type="uint32" />
<entry name="value1" type="string" size="102400" defaultvalue="" desc="最大长度:100KB"/>
<entry name="value2" type="string" size="102400" defaultvalue="" desc="最大长度:100KB"/>
<entry name="type_int8" type="int8" desc="type_int8" />
<entry name="type_uint8" type="uint8" desc="type_uint8"/>
<entry name="type_int16" type="int16" desc="type_int16" customattr2="sort1"/>
<entry name="type_uint16" type="uint16" desc="type_uint16"/>
<entry name="type_int32" type="int32" desc="type_int32"/>
<entry name="type_uint32" type="uint32" desc="type_uint32"/>
<entry name="type_int64" type="int64" desc="type_int64"/>
<entry name="type_uint64" type="uint64" desc="type_uint64"/>
<entry name="type_float" type="float" desc="type_float"/>
<entry name="type_double" type="double" desc="type_double"/>
<entry name="type_short" type="short" desc="type_short"/>
<entry name="type_string" type="string" desc="type_string" size="20"/>
<entry name="type_tinyint" type="tinyint" desc="type_tinyint"/>
<entry name="type_datetime" type="datetime" desc="type_datetime"/>
</struct>
4.2. PB-SortList表示例
message pb_sortedlist {
option(tcaplusservice.tcaplus_primary_key) = "openid,tconndid,timekey,svrid";
option(tcaplusservice.tcaplus_customattr) = "TableType=SORTLIST;ListNum=1900;SortField=id_int32";//多字段排序SortField=id_int32,id_uint32..
//4个key
required uint32 openid = 1; //QQ Uin
required string timekey = 2[(tcaplusservice.tcaplus_size) = 20, (tcaplusservice.tcaplus_desc) = "bingo"];
required int32 tconndid = 3;
required string svrid = 4;
//value
required string gamesvrid = 5[(tcaplusservice.tcaplus_size) = 11];
repeated property other_property= 6 ;//其他扩展属性
optional item_bag items = 7;
repeated int64 lockid = 8 [packed = true];
optional bytes val = 9;
optional pay_info pay = 10;
optional uint32 id_uint32 = 11;
optional int32 id_int32 = 12;
}