这里分析一下ObRowkey相关的源码.
引用晓楚师兄的一段话:
- Rowkey是OceanBase诞生之初就引入的概念,最终被确立是在OceanBase 0.3。
- 为了便于理解,不妨把OceanBase想象成一个Key-Value系统,Rowkey就是Key,Value就是返回的行数据。
- 如果你对mysql数据库熟悉,那么不妨把Rowkey理解成primary key,它就是那几个主键列的组合,列的顺序与primary key中定义的顺序一致。
###ObObjType
定义了OceanBase中支持的基本数据类型,我们可以在ob_obj_type.h中看到其定义
###ObRowkeyColumn 定义了RowKey中的每个列Column
###ObRowkeyInfo 定义了RowkeyColumn的集合
###ObCellInfo 从结构上可以看出,定义了一个cell的相关信息,主要包括了
ObString table_name_; //所在表名
uint64_t table_id_; //表id
ObRowkey row_key_; //所在行row_key_
uint64_t column_id_; //列id
ObString column_name_;//列名
ObObj value_; //cell值
如下两个类与之有关联,一并写在这里
###ObRootTableRow:
存储了RootTable中一行的信息,包括了rowkey列的数据和各个replica的版本信息
// 方法
int input_tablet_row(const bool start_key, const ObRootTabletInfo & tablet);
int output_tablet_row(common::ObScanner & result);
// 成员
common::ObObj rowkey_objs_[common::OB_MAX_ROWKEY_COLUMN_NUMBER];
common::ObCellInfo row_cells_[common::OB_MAX_COLUMN_NUMBER];
着重分析一下input_tablet_row方法,首先拷贝rowkey,没有做深拷贝
// copy the range end key as rowkey
rowkey_column_num_ = rowkey_len;
for (int64_t i = 0; i < rowkey_column_num_; ++i)
{
rowkey_objs_[i] = input_key.ptr()[i];
}
然后填充row_cells_,RootTable中一行的各个列信息,
ADD_REPLICA_SERVER(normal_column_num_, i, replica->server_, replica->version_);
ADD_REPLICA_SERVER的定义如下:
#define ADD_REPLICA_SERVER(column, index, server, version) \
{ \
ObRowkey rowkey; \
rowkey.assign(rowkey_objs_, rowkey_column_num_); \
row_cells_[column].row_key_ = rowkey; \
row_cells_[column].table_name_ = ObString::make_string("temp"); \
row_cells_[column].column_name_ = ObString::make_string("version_"#index); \
row_cells_[column].value_.set_int(version); \
column++; \
row_cells_[column].row_key_ = rowkey; \
row_cells_[column].table_name_ = ObString::make_string("temp"); \
row_cells_[column].column_name_ = ObString::make_string("port_"#index); \
row_cells_[column].value_.set_int(server.get_port()); \
column++; \
row_cells_[column].row_key_ = rowkey; \
row_cells_[column].table_name_ = ObString::make_string("temp"); \
row_cells_[column].column_name_ = ObString::make_string("ip_"#index); \
row_cells_[column].value_.set_int(server.get_ipv4()); \
column++; \
}
同时填充了三个cell,分别是version,port,ip,对应了RootTable的表结构,这里顺便说一下RootTable内部表化之后的表结构定义:
range默认前开后闭,也就是说从检索tablet的时候的如果刚好有个tablet是以此endkey结尾的,那么这个tablet会被检索出来。如果检索的关键字是rowkey的话,那么这个rowkey所对应的tablet就是这个tablet而不是下一个tablet(如果tablet没有出现空洞的话),这个是系统里的约定,也是比较基础的规则了。
举个例子,如下的函数负责从一堆tablet里面找到刚好对应当前rowkey的tablet,我们来看函数的逻辑。
int ObRootTabletUtil::find_right_tablet(const ObRootTabletList & list, const uint64_t table_id,
const ObRowkey & rowkey, ObRootTabletInfo & tablet)
{
int ret = OB_ENTRY_NOT_EXIST;
for (int64_t i = 0; i < list.list_.count(); ++i)
{
tablet = list.list_.at(i);
TBSYS_LOG(DEBUG, "iterator tablet:%s", to_cstring(tablet.meta_info_.range_));
if (tablet.meta_info_.range_.table_id_ < table_id)
{
continue;
}
else if (tablet.meta_info_.range_.table_id_ > table_id)
{
break;
}
else if (tablet.meta_info_.range_.end_key_ < rowkey)
{
continue;
}
else
{
if (tablet.meta_info_.range_.start_key_ > rowkey)
{
break;
}
else if (tablet.meta_info_.range_.start_key_ == rowkey)
{
// find the first root tablet
if (rowkey.is_min_row())
{
ret = OB_SUCCESS;
}
break;
}
else
{
ret = OB_SUCCESS;
break;
}
}
}
if (ret != OB_SUCCESS)
{
// find the next tablet but not find the suitable tablet
if (list.list_.count() > 0)
{
TBSYS_LOG(WARN, "not find the tablet in root table has hole:rowkey[%s], tablet[%s]",
to_cstring(rowkey), to_cstring(tablet.meta_info_.range_));
}
}
return ret;
}
###表名
First Root Table 的 Table ID 为 111(固定值,暂定 111)
User Meta Table 和 User Root Table 为 User Table 的衍生 Table, 对外不可见, 在 User Table 创建时自动创建, Table Name 和 Table
ID 取值约定如下:要求 User Table ID 从 3000 以后取值。
如下所示:
###ObScanner