Update userchain.cpp

This commit is contained in:
hyt15810656168 2023-09-30 00:45:16 +08:00
parent 86f1c843dc
commit 975b177d85
1 changed files with 258 additions and 172 deletions

View File

@ -41,114 +41,152 @@
#include "catalog/gs_global_chain.h"
/*
* create_hist_relation -- create a hist table based on the original user table.
* create_hist_relation -- create a hist table based on the original user table.//基于原始用户表创建一个hist表
*
* rel: The original user relation
* reloptions: relation options used to define new relation
* mainTblStmt: Some statement of the query when create the new relation.
* rel: The original user relation//原始用户表
* reloptions: relation options used to define new relation//用于定义新关系的关系选项
* mainTblStmt: Some statement of the query when create the new relation.//创建新关系时的某个查询语句
*/
//根据给定的目标表rel创建历史链表
void create_hist_relation(Relation rel, Datum reloptions, CreateStmt *mainTblStmt)
{
errno_t rc;
char hist_name[NAMEDATALEN];
Oid relid = RelationGetRelid(rel);
Oid nsp_oid = PG_BLOCKCHAIN_NAMESPACE;
Oid relid = RelationGetRelid(rel);//获取目标表的OID
Oid nsp_oid = PG_BLOCKCHAIN_NAMESPACE;//命名空间的OID
Oid hist_oid;
Oid collationObjectId[1];
Oid classObjectId[1];
int16 coloptions[1];
bool shared_relation = rel->rd_rel->relisshared;
bool shared_relation = rel->rd_rel->relisshared;//判断目标表是否为共享关系
get_hist_name(relid, get_rel_name(relid), hist_name);
get_hist_name(relid, get_rel_name(relid), hist_name);//获取历史链表的名称
/*
* history chain table contains all the columns from the origin user table, and then need to
* record the command type, blocknum, and hash value of last block record.
*
*/
TupleDesc chain_desc = CreateTemplateTupleDesc(USERCHAIN_COLUMN_NUM, false);
TupleDesc chain_desc = CreateTemplateTupleDesc(USERCHAIN_COLUMN_NUM, false);//创建历史链表的元组描述符
/* Now consider the additional columns and initilize the description */
TupleDescInitEntry(chain_desc, USERCHAIN_COLUMN_REC_NUM + 1, "rec_num", INT8OID, -1, 0);
TupleDescInitEntry(chain_desc, USERCHAIN_COLUMN_HASH_INS + 1, "hash_ins", HASH16OID, -1, 0);
TupleDescInitEntry(chain_desc, USERCHAIN_COLUMN_HASH_DEL + 1, "hash_del", HASH16OID, -1, 0);
TupleDescInitEntry(chain_desc, USERCHAIN_COLUMN_PREVHASH + 1, "pre_hash", HASH32OID, -1, 0);
/* Now consider the additional columns and initilize the description */ //初始化历史链表的额外列
TupleDescInitEntry(chain_desc, USERCHAIN_COLUMN_REC_NUM + 1, "rec_num", INT8OID, -1, 0);//添加记录号列
TupleDescInitEntry(chain_desc, USERCHAIN_COLUMN_HASH_INS + 1, "hash_ins", HASH16OID, -1, 0);//添加插入操作的哈希值列
TupleDescInitEntry(chain_desc, USERCHAIN_COLUMN_HASH_DEL + 1, "hash_del", HASH16OID, -1, 0);//添加删除操作的哈希值列
TupleDescInitEntry(chain_desc, USERCHAIN_COLUMN_PREVHASH + 1, "pre_hash", HASH32OID, -1, 0);//添加上一个区块的哈希值列
reloptions = AddInternalOption(reloptions, INTERNAL_MASK_DALTER | INTERNAL_MASK_DDELETE |
INTERNAL_MASK_DINSERT | INTERNAL_MASK_DUPDATE);
INTERNAL_MASK_DINSERT | INTERNAL_MASK_DUPDATE);//添加内部选项,通过使用按位或操作符(|将INTERNAL_MASK_DALTER、INTERNAL_MASK_DDELETE、INTERNAL_MASK_DINSERT和INTERNAL_MASK_DUPDATE四个标志位添加到reloptions中
//添加这些内部选项可以用于在处理历史链表时进行相应的操作追踪和记录。
//使用给定的历史链表名称(hist_name)、命名空间OID(nsp_oid)、表空间OID(rel->rd_rel->reltablespace)等参数创建历史链表。
//使用给定的chain_desc元组描述符来定义历史链表的列和属性。
//使用指定的参数(如所有者、持久性、共享关系标志等)来配置历史链表。
//注册历史链表的元数据到系统目录中,以便后续可以在数据库中访问和操作该表
//将创建的历史链表的对象IDOID赋值给hist_oid变量以便后续的处理和引用
hist_oid = heap_create_with_catalog(hist_name, nsp_oid, rel->rd_rel->reltablespace, InvalidOid,
InvalidOid, InvalidOid, rel->rd_rel->relowner, chain_desc, NIL, 'r',
(rel->rd_rel->relpersistence == 't') ? 'u' : rel->rd_rel->relpersistence,
shared_relation, false, true, 0, ONCOMMIT_NOOP, reloptions, false, true,
NULL, REL_CMPRS_NOT_SUPPORT, NULL, false);
NULL, REL_CMPRS_NOT_SUPPORT, NULL, false);//创建历史链表
/* make the history chain relation visible, else heap_open will fail */
CommandCounterIncrement();
CommandCounterIncrement();//提交事务,使历史链表对后续操作可见
#ifdef ENABLE_MULTIPLE_NODES
#ifdef ENABLE_MULTIPLE_NODES//启用了多节点(分布式)功能
bool is_initdb_on_dn = false;
/* Add to pgxc_class */
/* When the sum of shmemNumDataNodes and shmemNumCoords equals to one,
* the create table command is executed on datanode during initialization .
* In this case, we do not write created table info in pgxc_class.
*/
/*当shmemNumDataNodes和shmemNumCoords的总和等于1时
* datanode上执行创建表的命令
* pgxc_class
*/
if ((*t_thrd.pgxc_cxt.shmemNumDataNodes + *t_thrd.pgxc_cxt.shmemNumCoords) == 1) {
is_initdb_on_dn = true;
}
/* only support normal table, do not support foreign table (can be supported in the future) */
//仅支持普通表
if ((!u_sess->attr.attr_common.IsInplaceUpgrade || !IsSystemNamespace(nsp_oid)) &&
(IS_PGXC_COORDINATOR || (isRestoreMode && mainTblStmt->distributeby != NULL && !is_initdb_on_dn))) {
(IS_PGXC_COORDINATOR || (isRestoreMode && mainTblStmt->distributeby != NULL && !is_initdb_on_dn))) {//不是在升级模式下或者不在系统命名空间下,是协调节点,是恢复模式且主表语句中的distributeby不为空且不是在datanode上执行初始化操作
AddRelationDistribution(hist_name, hist_oid, NULL, mainTblStmt->subcluster,
InvalidOid, chain_desc, true);
CommandCounterIncrement();
InvalidOid, chain_desc, true);//将历史链表添加到pgxc_class中以支持分布式
CommandCounterIncrement();//提交事务使pgxc_class对后续操作可见
/* Make sure locator info gets rebuilt */
RelationCacheInvalidateEntry(hist_oid);
RelationCacheInvalidateEntry(hist_oid);//刷新历史链表的关系缓存
}
#endif
/* now create index for this new history table */
//为这个新的历史表创建索引
char hist_index_name[NAMEDATALEN];
rc = snprintf_s(hist_index_name, NAMEDATALEN, NAMEDATALEN - 1, "gs_hist_%u_index", relid);
rc = snprintf_s(hist_index_name, NAMEDATALEN, NAMEDATALEN - 1, "gs_hist_%u_index", relid);//创建历史链表的索引名称
securec_check_ss(rc, "", "");
/* open the previous created history chain table */
Relation hist_rel = heap_open(hist_oid, ShareLock);
IndexInfo *hist_index = makeNode(IndexInfo);
Relation hist_rel = heap_open(hist_oid, ShareLock);//打开先前创建的历史链表
IndexInfo *hist_index = makeNode(IndexInfo);//创建索引信息
hist_index->ii_NumIndexAttrs = 1;
hist_index->ii_NumIndexKeyAttrs = 1;
hist_index->ii_KeyAttrNumbers[0] = 1;
hist_index->ii_NumIndexKeyAttrs = 1;//索引的属性数量和键属性数量都为1
hist_index->ii_KeyAttrNumbers[0] = 1;//索引的键属性为第一个属性
hist_index->ii_Expressions = NIL;
hist_index->ii_ExpressionsState = NIL;
hist_index->ii_Predicate = NIL;
hist_index->ii_PredicateState = NIL;
hist_index->ii_PredicateState = NIL;//设置为空列表,表示索引没有谓词限制
hist_index->ii_ExclusionOps = NULL;
hist_index->ii_ExclusionProcs = NULL;
hist_index->ii_ExclusionStrats = NULL;
hist_index->ii_Unique = true;
hist_index->ii_ReadyForInserts = true;
hist_index->ii_Concurrent = false;
hist_index->ii_BrokenHotChain = false;
hist_index->ii_PgClassAttrId = Anum_pg_class_relhasindex;
hist_index->ii_ExclusionStrats = NULL;//表示索引没有排除约束
hist_index->ii_Unique = true;//索引是唯一的
hist_index->ii_ReadyForInserts = true;//索引已准备好接收插入操作
hist_index->ii_Concurrent = false;//索引不支持并发操作
hist_index->ii_BrokenHotChain = false;//索引的热点链未破裂
hist_index->ii_PgClassAttrId = Anum_pg_class_relhasindex;//设置索引信息的各个字段值,表示索引对应于pg_class表的relhasindex字段
collationObjectId[0] = InvalidOid;
classObjectId[0] = INT4_BTREE_OPS_OID;
coloptions[0] = 0;
collationObjectId[0] = InvalidOid;//设置索引的排序规则对象标识符为无效值InvalidOid表示索引不使用任何特定的排序规则。
classObjectId[0] = INT4_BTREE_OPS_OID;//设置索引的操作符类对象标识符为INT4_BTREE_OPS_OID表示索引使用整型数据的 B-tree 操作符。
coloptions[0] = 0;//索引没有额外的列选项
IndexCreateExtraArgs extra;
extra.existingPSortOid = InvalidOid;
extra.isPartitionedIndex = false;
extra.isGlobalPartitionedIndex = false;
extra.existingPSortOid = InvalidOid;//该索引不依赖于任何预排序对象
extra.isPartitionedIndex = false;//表示该索引不是分区索引
extra.isGlobalPartitionedIndex = false;//该索引不是全局分区索引
/*
hist_rel
hist_index_name
InvalidOid使 InvalidOid
InvalidOid InvalidOid
hist_index IndexInfo
list_make1((void *)"rec_num") "rec_num"
BTREE_AM_OID访使 B-tree
rel->rd_rel->reltablespace
collationObjectId
classObjectId
coloptions
(Datum) 0
true
false
false
false
true
false
false
&extra
false
*/
index_create(hist_rel, hist_index_name, InvalidOid, InvalidOid,
hist_index, list_make1((void *)"rec_num"), BTREE_AM_OID,
rel->rd_rel->reltablespace, collationObjectId, classObjectId,
coloptions, (Datum) 0, true, false, false, false,
true, false, false, &extra, false);
true, false, false, &extra, false);//在历史链表上创建索引
heap_close(hist_rel, NoLock);
heap_close(hist_rel, NoLock);//关闭历史链表关系
/* Specify dependent between history table and origin table with depend option audo. */
//使用depend选项将历史表和原始表之间的依赖关系指定为自动依赖。
ObjectAddress myself;
ObjectAddress referenced;
myself.classId = RelationRelationId;
@ -157,84 +195,92 @@ void create_hist_relation(Relation rel, Datum reloptions, CreateStmt *mainTblStm
referenced.classId = RelationRelationId;
referenced.objectId = relid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);//指定历史链表和原始表之间的依赖关系为自动依赖,当被依赖的对象发生变化时,依赖关系会自动更新
pfree_ext(chain_desc);
pfree_ext(chain_desc);//释放内存
/*
* Make changes visible
*/
CommandCounterIncrement();
CommandCounterIncrement();//提交事务,使更改对后续操作可见
}
/*
* rename_hist_by_usertable -- rename hist table name by its user table and new usertable name
* rename_hist_by_usertable -- rename hist table name by its user table and new usertable name//根据用户表和新的用户表名重命名历史表名
*
* relid: relation oid of user table
* new_usertable_name: the new table name of user table
* relid: relation oid of user table//用户表的关系oid
* new_usertable_name: the new table name of user table//用户表的新表名
*
* Note: This function is used after origin user table renamed, and then caller
* can use this function to rename the corresponding hist table name.
* 使
*/
void rename_hist_by_usertable(Oid relid, const char *new_usertable_name)
{
//获取历史表的OID
Oid hist_oid = get_hist_oid(relid);
//创建一个保存新历史表名的字符数组
char new_hist_name[NAMEDATALEN];
//根据用户表和新的用户表名生成新的历史表名
get_hist_name(relid, new_usertable_name, new_hist_name);
/* Do rename hist table. */
//执行历史表重命名操作
RenameRelationInternal(hist_oid, new_hist_name);
}
/*
* rename_hist_by_newnsp -- rename one hist table while altering schema name
* rename_hist_by_newnsp -- rename one hist table while altering schema name//通过修改模式名称重命名一个历史表
*
* user_relid: relation oid of user table
* new_nsp_name: the new schema name of user table
* user_relid: relation oid of user table//用户表的关系oid
* new_nsp_name: the new schema name of user table//用户表的新模式名称
*/
void rename_hist_by_newnsp(Oid user_relid, const char *new_nsp_name)
{
Oid hist_oid;
char old_hist_name[NAMEDATALEN] = {0};
char new_hist_name[NAMEDATALEN] = {0};
//获取旧的历史表名称
get_hist_name(user_relid, get_rel_name(user_relid), old_hist_name);
//根据旧的历史表名称和指定的命名空间获取历史表的oid
hist_oid = get_relname_relid(old_hist_name, PG_BLOCKCHAIN_NAMESPACE);
/* Some especial tables such as foreign tables have no hist table. So make sure hist exists. */
if (!OidIsValid(hist_oid)) {
if (!OidIsValid(hist_oid)) {//如果历史表不存在,则直接返回
return;
}
//构造新的历史表名称
get_hist_name(user_relid, get_rel_name(user_relid), new_hist_name, get_rel_namespace(user_relid), new_nsp_name);
//执行重命名操作
RenameRelationInternal(hist_oid, new_hist_name);
}
/*
* rename_histlist_by_newnsp -- rename a list of hist table while altering schema name
* rename_histlist_by_newnsp -- rename a list of hist table while altering schema name//在修改模式名称的同时重命名历史表列表
*
* usertable_oid_list: relation oid list of user tables
* new_nsp_name: the new schema name of user table
* usertable_oid_list: relation oid list of user tables//用户表的关系oid列表
* new_nsp_name: the new schema name of user table//用户表的新模式名称
*/
void rename_histlist_by_newnsp(List *usertable_oid_list, const char *new_nsp_name)
{
ListCell *lc = NULL;
foreach (lc, usertable_oid_list) {
Oid relid = (Oid)lfirst_oid(lc);
rename_hist_by_newnsp(relid, new_nsp_name);
foreach (lc, usertable_oid_list) {//批量处理
Oid relid = (Oid)lfirst_oid(lc);//将当前元素转换为Oid类型的relid
rename_hist_by_newnsp(relid, new_nsp_name);//用新的模式名称new_nsp_name重命名历史表
}
}
/*
* user_hash_attrno -- get the attribute number of user table's hash column.
* user_hash_attrno -- get the attribute number of user table's hash column.//获取用户表哈希列的属性编号
*
* rd_att: tuple description of user table
* rd_att: tuple description of user table//用户表的元组描述
*/
int user_hash_attrno(const TupleDesc rd_att)
{
int hash_natt = -1;
Form_pg_attribute rel_attr = NULL;
for (int i = rd_att->natts - 1; i >= 0; i--) {
Form_pg_attribute rel_attr = NULL;//遍历用户表的属性
for (int i = rd_att->natts - 1; i >= 0; i--) {//从最后一个属性开始向前查找
rel_attr = rd_att->attrs[i];
if (strcmp(rel_attr->attname.data, "hash") == 0) {
if (strcmp(rel_attr->attname.data, "hash") == 0) {//如果两者相等,则说明找到了哈希列
hash_natt = i;
break;
}
@ -243,11 +289,11 @@ int user_hash_attrno(const TupleDesc rd_att)
}
/*
* hash_combine_tuple_data -- generate hash of each attribute and return the combination string.
* hash_combine_tuple_data -- generate hash of each attribute and return the combination string.//计算每个属性的哈希值,并返回组合字符串
*
* data_string: combination of hash that calculate from each attribute
* tabledesc: tuple description of user table
* tuple: row data of user table
* data_string: combination of hash that calculate from each attribute//由每个属性计算得到的哈希值的组合字符串
* tabledesc: tuple description of user table//用户表的元组描述
* tuple: row data of user table//用户表的行数据
*/
static void hash_combine_tuple_data(char *buf, int buf_size, TupleDesc tabledesc, HeapTuple tuple)
{
@ -257,178 +303,190 @@ static void hash_combine_tuple_data(char *buf, int buf_size, TupleDesc tabledesc
char hash_str[UINT64STRSIZE + 1] = {0};
Datum *values = (Datum *) palloc0(natts * sizeof(Datum));
bool *nulls = (bool *) palloc0(natts * sizeof(bool));
//将堆元组解码为属性值和空值标志
heap_deform_tuple(tuple, tabledesc, values, nulls);
for (int i = 0; i < natts - 1; ++i) { /* except 'hash' column. */
if (nulls[i]) {
continue;
}
//计算属性的哈希值
uint64 col_hash = compute_hash(tabledesc->attrs[i]->atttypid, values[i], LOCATOR_TYPE_HASH);
//将哈希值转换为字符串
rc = snprintf_s(hash_str, UINT64STRSIZE + 1, UINT64STRSIZE, "%lu", col_hash);
securec_check_ss(rc, "", "");
//将哈希值拼接到结果字符串中
rc = snprintf_s(buf + buflen, buf_size - buflen, buf_size - buflen - 1, "%s", hash_str);
securec_check_ss(rc, "", "");
buflen += strlen(hash_str);
}
//释放内存
pfree_ext(values);
pfree_ext(nulls);
}
/*
* get_user_tuple_hash -- get the hash value of usertable's tuple.
* get_user_tuple_hash -- get the hash value of usertable's tuple.//获取用户表元组的哈希值
*
* tuple: row data of user table
* desc: tuple description of user table
* tuple: row data of user table//用户表的行数据
* desc: tuple description of user table//用户表的元组描述
*/
uint64 get_user_tuple_hash(HeapTuple tuple, TupleDesc desc)
{
Datum value;
bool isnull = false;
//获取哈希列的列号
int hash_attno = user_hash_attrno(desc);
//从元组中获取哈希列的值(最后一列)
value = heap_getattr(tuple, hash_attno + 1, desc, &isnull); /* get last column. */
Assert(!isnull);
Assert(!isnull);//确保获取的值不为空
//将值转换为uint64类型并返回
return DatumGetUInt64(value);
}
/*
* gen_user_tuple_hash -- generate hash of each user table's tuple.
* gen_user_tuple_hash -- generate hash of each user table's tuple.//生成用户表中每个元组的哈希值
*
* rel: user table
* tuple: row data of user table
* rel: user table//用户表
* tuple: row data of user table//用户表的行数据
*/
static uint64 gen_user_tuple_hash(Relation rel, HeapTuple tuple)
{
//获取用户表的元组描述符
TupleDesc tabledesc = RelationGetDescr(rel);
//计算用于存储哈希值以及中间结果的字符串需要的大小
int data_size = UINT64STRSIZE * tabledesc->natts + 1;
//分配内存存储字符串,并清空
char *data_string = (char *)palloc0(data_size * sizeof(char));
//计算元组数据的哈希值并将其拼接到字符串中
hash_combine_tuple_data(data_string, data_size, tabledesc, tuple);
//计算字符串的MD5哈希值存储在sum数组中
uint8 sum[16];
if (pg_md5_binary(data_string, strlen(data_string), sum) == false) {
pfree_ext(data_string);
ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory")));
}
//将sum数组的前8个字节即16个字节中的第5到第12个字节拼接成一个64位整数
uint64 result = 0;
for (int i = 0; i < 7; i++) {
result |= sum[4 + i];
result = (result << 8);
}
result |= sum[11];
//释放分配的内存并返回哈希值
pfree_ext(data_string);
return result;
}
/*
* set_user_tuple_hash -- calculate and fill the hash attribute of user table's tuple.
* set_user_tuple_hash -- calculate and fill the hash attribute of user table's tuple.//计算并填充用户表元组的哈希属性
*
* tup: row data of user table
* rel: user table
* hash_exists: whether tuple comes with tuplehash.
* tup: row data of user table//用户表的行数据
* rel: user table//用户表
* hash_exists: whether tuple comes with tuplehash.//元组是否包含tuplehash
*
* Note: if hash_exists is true, we should recompute
* tuple hash and compare with tuplehash of itself.
* tuple hash and compare with tuplehash of itself.//如果hash_exists为真则我们应该重新计算元组的哈希值并与自身的tuplehash进行比较
*/
HeapTuple set_user_tuple_hash(HeapTuple tup, Relation rel, bool hash_exists)
{
uint64 row_hash = gen_user_tuple_hash(rel, tup);
int hash_attrno = user_hash_attrno(rel->rd_att);
if (hash_exists) {
uint64 row_hash = gen_user_tuple_hash(rel, tup);//生成该行数据的哈希值
int hash_attrno = user_hash_attrno(rel->rd_att);//获取哈希属性在用户表中的属性编号
if (hash_exists) {//如果元组已经包含tuplehash
bool is_null;
Datum hash = heap_getattr(tup, hash_attrno + 1, rel->rd_att, &is_null);
if (is_null || row_hash != DatumGetUInt64(hash)) {
ereport(ERROR, (errcode(ERRCODE_OPERATE_INVALID_PARAM), errmsg("Invalid tuple hash.")));
Datum hash = heap_getattr(tup, hash_attrno + 1, rel->rd_att, &is_null);//从元组中获取已存在的哈希值
if (is_null || row_hash != DatumGetUInt64(hash)) {//比较新计算的哈希值和已存在的哈希值是否相等
ereport(ERROR, (errcode(ERRCODE_OPERATE_INVALID_PARAM), errmsg("Invalid tuple hash.")));//哈希值不一致,抛出错误
}
return tup;
return tup;//返回原始的元组
}
Datum *values = NULL;
bool *nulls = NULL;
bool *replaces = NULL;
/* Build modified tuple */
/* Build modified tuple */ //构建修改后的元组
int2 nattrs = RelationGetNumberOfAttributes(rel);
values = (Datum*)palloc0(nattrs * sizeof(Datum));
nulls = (bool*)palloc0(nattrs * sizeof(bool));
replaces = (bool*)palloc0(nattrs * sizeof(bool));
values[hash_attrno] = UInt64GetDatum(row_hash);
replaces[hash_attrno] = true;
HeapTuple newtup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, replaces);
values[hash_attrno] = UInt64GetDatum(row_hash); //将新计算的哈希值存入对应的属性中
replaces[hash_attrno] = true;//标记该属性为被替换
HeapTuple newtup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, replaces);//修改元组
pfree_ext(values);
pfree_ext(nulls);
pfree_ext(replaces);
return newtup;
return newtup;//返回修改后的元组
}
/*
* get_hist_oid -- get the oid of history table by oid, name and namespace name of user table
* get_hist_oid -- get the oid of history table by oid, name and namespace name of user table//根据用户表的OID、名称和命名空间名称获取历史表的OID
*
* relid: relation oid of user table
* rel_name: relation name of user table
* rel_nsp: namespace name of user table
* relid: relation oid of user table//用户表的关系OID
* rel_name: relation name of user table//用户表的关系名称
* rel_nsp: namespace name of user table//用户表的命名空间名称
*/
Oid get_hist_oid(Oid relid, const char *rel_name, Oid rel_nsp)
{
if (rel_name == NULL) {
rel_name = get_rel_name(relid);
if (rel_name == NULL) {//如果为NULL
rel_name = get_rel_name(relid);//通过get_rel_name(relid)函数获取用户表user table的名称并将其赋值给rel_name
}
char hist_name[NAMEDATALEN];
get_hist_name(relid, rel_name, hist_name, rel_nsp);
Oid hist_oid = get_relname_relid(hist_name, PG_BLOCKCHAIN_NAMESPACE);
get_hist_name(relid, rel_name, hist_name, rel_nsp);//根据用户表的OID、名称和命名空间名称生成历史表的名称
Oid hist_oid = get_relname_relid(hist_name, PG_BLOCKCHAIN_NAMESPACE);//根据历史表的名称和预定义的命名空间PG_BLOCKCHAIN_NAMESPACE获取历史表的OID
return hist_oid;
}
/*
* get_user_tupleid_hash -- get the hash value of usertable's tupleid
* get_user_tupleid_hash -- get the hash value of usertable's tupleid//获取用户表元组的哈希值
*
* relation: relation of user table
* tupleid: tupleid of user tuple
* relation: relation of user table//用户表的关系
* tupleid: tupleid of user tuple//用户元组的tupleid
*/
uint64 get_user_tupleid_hash(Relation relation, ItemPointer tupleid)
{
BlockNumber block;
Buffer buffer;
Buffer vmbuffer = InvalidBuffer;
Page page;
ItemId lp;
HeapTupleData tp;
TupleDesc tabledescr;
uint64 result;
BlockNumber block; //块号
Buffer buffer;//缓冲区
Buffer vmbuffer = InvalidBuffer;//可见度映射缓冲区
Page page;//页面
ItemId lp;//元组标识符
HeapTupleData tp;//堆元组数据
TupleDesc tabledescr;//表描述符
uint64 result;//哈希值
tabledescr = RelationGetDescr(relation);
/* get tuple use tupleid */
block = ItemPointerGetBlockNumber(tupleid);
buffer = ReadBuffer(relation, block);
page = BufferGetPage(buffer);
tabledescr = RelationGetDescr(relation);//获取表描述符
/* get tuple use tupleid */ //使用元组标识符TupleId获取元组
block = ItemPointerGetBlockNumber(tupleid);//获取元组所在的块号
buffer = ReadBuffer(relation, block);//读取关系中的块
page = BufferGetPage(buffer);//获取块对应的页
if (PageIsAllVisible(page)) {
visibilitymap_pin(relation, block, &vmbuffer);
visibilitymap_pin(relation, block, &vmbuffer);//锁定页面
}
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);//对缓冲区进行互斥锁定
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tupleid));
tp.t_tableOid = RelationGetRelid(relation);
tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
tp.t_len = ItemIdGetLength(lp);
tp.t_self = *tupleid;
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tupleid));//获取元组标识符
tp.t_tableOid = RelationGetRelid(relation);//设置表OID
tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);//设置元组的数据
tp.t_len = ItemIdGetLength(lp);//设置元组长度
tp.t_self = *tupleid;//设置元组标识符
result = get_user_tuple_hash(&tp, tabledescr);
result = get_user_tuple_hash(&tp, tabledescr);//计算元组的哈希值
UnlockReleaseBuffer(buffer);
UnlockReleaseBuffer(buffer);//解锁并释放缓冲区
if (vmbuffer != InvalidBuffer) {
ReleaseBuffer(vmbuffer);
ReleaseBuffer(vmbuffer);//如果可见度映射缓冲区不为空,则释放它
}
return result;
return result;//返回哈希值
}
/*
* gen_hist_tuple_hash -- calculate pre_hash of hist table
* gen_hist_tuple_hash -- calculate pre_hash of hist table//计算历史表的预散列哈希值
*
* relid: relation oid of history table
* current_block_data: data of current row, includes hash_ins and hash_del
* pre_row_exist: when current row is the first row, it's true
* pre_row_hash: the pre_hash value of previous row
* hash: the result hash
* relid: relation oid of history table//历史表的关系对象标识符
* current_block_data: data of current row, includes hash_ins and hash_del//当前行的数据,包括要插入和要删除的哈希值
* pre_row_exist: when current row is the first row, it's true//当当前行是第一行时,它的值为 true
* pre_row_hash: the pre_hash value of previous row//前一行的预散列哈希值。
* hash: the result hash//计算结果的哈希值
*/
void gen_hist_tuple_hash(Oid relid, char *current_block_data, bool pre_row_exist,
hash32_t *pre_row_hash, hash32_t *hash)
@ -436,16 +494,22 @@ void gen_hist_tuple_hash(Oid relid, char *current_block_data, bool pre_row_exist
errno_t rc;
int buf_size = strlen(current_block_data) + NAMEDATALEN + 1;
char *data_string = (char *)palloc0(buf_size * sizeof(char));
//如果当前行是第一行
if (pre_row_exist) {
//将前一行的预散列哈希值转换为字符串
char *pre_hash_str = DatumGetCString(DirectFunctionCall1(hash32out, HASH32GetDatum(pre_row_hash)));
//将当前行的数据和前一行的预散列哈希值连接起来
rc = snprintf_s(data_string, buf_size, buf_size - 1, "%s%s", current_block_data, pre_hash_str);
//释放前一行的预散列哈希值字符串
pfree_ext(pre_hash_str);
} else {
//获取历史表的关系名
char *rel_name = get_rel_name(relid);
//将当前行的数据和关系名连接起来
rc = snprintf_s(data_string, buf_size, buf_size - 1, "%s%s", current_block_data, rel_name);
}
securec_check_ss(rc, "", "");
//使用MD5算法计算数据字符串的哈希值
if (!pg_md5_binary(data_string, strlen(data_string), hash->data)) {
pfree_ext(data_string);
ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory")));
@ -454,12 +518,12 @@ void gen_hist_tuple_hash(Oid relid, char *current_block_data, bool pre_row_exist
}
/*
* fill_hist_block -- get newest preblock in cache, and prepare new block for flushing.
* fill_hist_block -- get newest preblock in cache, and prepare new block for flushing.//从缓存中获取最新的预块,并准备新的块用于刷新
*
* histoid: relation oid of history table
* hash_ins: hash_ins value of current row
* hash_del: hash_del value of current row
* block: row id and pre_hash from current row
* histoid: relation oid of history table//历史表的关系OID
* hash_ins: hash_ins value of current row//当前行的hash_ins值
* hash_del: hash_del value of current row//当前行的hash_del值
* block: row id and pre_hash from current row//当前行的行ID和预哈希值
*/
static void fill_hist_block(Oid histoid, uint64 hash_ins, uint64 hash_del, HistBlock *block)
{
@ -467,6 +531,7 @@ static void fill_hist_block(Oid histoid, uint64 hash_ins, uint64 hash_del, HistB
block->rec_num = get_next_recnum(histoid);
/* Before generate previous hash, we should get current block information */
//在生成前一个哈希值之前,我们应该获取当前块的信息
error_t rc = sprintf_s(data, NAMEDATALEN, "%lu%lu%lu", block->rec_num, hash_ins, hash_del);
securec_check_ss(rc, "", "");
@ -474,20 +539,24 @@ static void fill_hist_block(Oid histoid, uint64 hash_ins, uint64 hash_del, HistB
}
/*
* hist_table_record_internal -- append record to history table when user table is modified
* hist_table_record_internal -- append record to history table when user table is modified//当用户表被修改时,将记录追加到历史表中
*
* hist_oid: relation oid of history table
* hash_ins: hash of row that added by current operation
* hash_del: hash of row that deleted by current operation
* hist_oid: relation oid of history table//历史表的关系OID
* hash_ins: hash of row that added by current operation//当前操作添加的行的哈希值
* hash_del: hash of row that deleted by current operation//当前操作删除的行的哈希值
*/
bool hist_table_record_internal(Oid hist_oid, const uint64 *hash_ins, const uint64 *hash_del)
{
//定义一个values数组来存储要插入的字段值同时定义一个nulls数组来表示每个字段是否为NULL。
Datum values[USERCHAIN_COLUMN_NUM] = {0};
bool nulls[USERCHAIN_COLUMN_NUM] = {false};
//判断hash_ins和hash_del是否为NULL并分别赋值给ins_null和del_null。
bool ins_null = hash_ins == NULL;
bool del_null = hash_del == NULL;
//将实际的哈希值赋给t_ins和t_del如果对应的指针是NULL则赋值为0。
uint64 t_ins = ins_null ? 0 : *hash_ins;
uint64 t_del = del_null ? 0 : *hash_del;
//声明一个HistBlock结构体变量block并调用fill_hist_block函数获取当前块的信息。
HistBlock block;
if (!OidIsValid(hist_oid)) {
@ -497,7 +566,7 @@ bool hist_table_record_internal(Oid hist_oid, const uint64 *hash_ins, const uint
/* Before generate previous hash, we should get current block information */
fill_hist_block(hist_oid, t_ins, t_del, &block);
//将block中的字段值赋给values数组对应的位置设置相应的nulls标记。
values[USERCHAIN_COLUMN_REC_NUM] = UInt64GetDatum(block.rec_num);
values[USERCHAIN_COLUMN_HASH_INS] = UInt64GetDatum(t_ins);
values[USERCHAIN_COLUMN_HASH_DEL] = UInt64GetDatum(t_del);
@ -506,98 +575,115 @@ bool hist_table_record_internal(Oid hist_oid, const uint64 *hash_ins, const uint
nulls[USERCHAIN_COLUMN_HASH_INS] = ins_null;
nulls[USERCHAIN_COLUMN_HASH_DEL] = del_null;
nulls[USERCHAIN_COLUMN_PREVHASH] = false;
//打开并加锁历史表,并获取其描述符。
Relation hist_rel = heap_open(hist_oid, RowExclusiveLock);
TupleDesc hist_desc = RelationGetDescr(hist_rel);
//使用heap_form_tuple函数根据hist_desc和values、nulls数组创建一个HeapTuple对象并将其插入到历史表中。
HeapTuple tuple = heap_form_tuple(hist_desc, values, nulls);
simple_heap_insert(hist_rel, tuple);
heap_freetuple(tuple);
heap_freetuple(tuple);//释放tuple的内存
heap_close(hist_rel, RowExclusiveLock);
return true;
}
/*
* hist_table_record_insert -- append a record while inserting into user table
* hist_table_record_insert -- append a record while inserting into user table//在向用户表插入记录时,追加一条记录
*
* rel: relation of user table
* tup: the tuple which is inserted into user table
* res_hash: delta of user table hash
* rel: relation of user table//用户表的关系对象
* tup: the tuple which is inserted into user table//要插入到用户表的元组
* res_hash: delta of user table hash//用户表哈希的增量
*/
bool hist_table_record_insert(Relation rel, HeapTuple tup, uint64 *res_hash)
{
/* check all inputs are avaliable */
//检查所有输入是否有效
if (tup == NULL || rel == NULL) {
return false; /* Do some thing */
return false; /* Do some thing */ //可以进行适当的错误处理
}
//计算要插入的元组的哈希值
uint64 hash_ins = get_user_tuple_hash(tup, rel->rd_att);
//获取历史表对象的OID
Oid hist_oid = get_hist_oid(RelationGetRelid(rel), RelationGetRelationName(rel), RelationGetNamespace(rel));
//将插入哈希值赋值给res_hash
*res_hash = hash_ins;
//调用hist_table_record_internal函数向历史表中插入记录
return hist_table_record_internal(hist_oid, &hash_ins, NULL);
}
/*
* hist_table_record_delete -- append a record while deleting from user table
* hist_table_record_delete -- append a record while deleting from user table//在从用户表中删除记录时追加一条记录
*
* rel: relation of user table
* hash_del: the hash of deleted tuple
* res_hash: delta of user table hash
* rel: relation of user table//用户表的关系对象
* hash_del: the hash of deleted tuple//被删除元组的哈希值
* res_hash: delta of user table hash//用户表哈希的增量
*/
bool hist_table_record_delete(Relation rel, uint64 hash_del, uint64 *res_hash)
{
//获取历史表对象的OID
Oid hist_oid = get_hist_oid(RelationGetRelid(rel), RelationGetRelationName(rel), RelationGetNamespace(rel));
//将被删除元组的哈希值取负值并赋给res_hash作为用户表哈希的增量
*res_hash = -hash_del;
/* insert history record into userchain table */
//调用hist_table_record_internal函数执行向历史表插入记录的操作
return hist_table_record_internal(hist_oid, NULL, &hash_del);
}
/*
* hist_table_record_update -- append a record while updating user table
* hist_table_record_update -- append a record while updating user table//在更新用户表时追加一条记录
*
* rel: relation of user table
* newtup: the tupleid which is updated from user table
* hash_del: the hash of deleted tuple
* res_hash: delta of user table hash
* rel: relation of user table//用户表的关系对象
* newtup: the tupleid which is updated from user table//从用户表中更新的元组ID
* hash_del: the hash of deleted tuple//被删除元组的哈希值
* res_hash: delta of user table hash//用户表哈希的增量
*/
bool hist_table_record_update(Relation rel, HeapTuple newtup, uint64 hash_del, uint64 *res_hash)
{
//获取新元组的哈希值
uint64 hash_ins = get_user_tuple_hash(newtup, rel->rd_att);
//获取历史表对象的OID
Oid hist_oid = get_hist_oid(RelationGetRelid(rel), RelationGetRelationName(rel), RelationGetNamespace(rel));
//计算用户表哈希的增量
*res_hash = hash_ins - hash_del;
/* insert history record into userchain table */
//调用hist_table_record_internal函数执行向历史表插入记录的操作
return hist_table_record_internal(hist_oid, &hash_ins, &hash_del);
}
/*
* get_copyfrom_line_relhash -- extract hash from each copyfrom line
* get_copyfrom_line_relhash -- extract hash from each copyfrom line//从每个COPY FROM行中提取哈希值
*
* row_data: string line from txt
* len: length of row_data
* hash_colno: the number of split char before hash text
* split: split char
* hash: the buffer of getting hash.
* row_data: string line from txt//来自txt文件的字符串行
* len: length of row_data//row_data的长度
* hash_colno: the number of split char before hash text//哈希文本之前的分割字符数
* split: split char//分割字符
* hash: the buffer of getting hash.//存储哈希值的缓冲区
*/
bool get_copyfrom_line_relhash(const char *row_data, int len, int hash_colno, char split, uint64 *hash)
{
int pos;
/* Not found hash column. */
//如果未找到哈希列则返回false
if (hash_colno == -1) {
return false;
}
for (pos = 0; pos < len && hash_colno > 0; ++pos) {
//遍历行数据直到找到分割字符减少hash_colno的计数
if (row_data[pos] == split) {
--hash_colno;
}
}
//检查是否找到哈希列
if (hash_colno == 0) {
int remain_len = len - pos;
const char *hash_str = row_data + pos;
//提取哈希值并存储到指定地址
if (remain_len > 0) {
//如果剩余长度大于0则将哈希字符串转换为uint64并存储在hash指针指向的地址上返回true
*hash = DatumGetUInt64(DirectFunctionCall1(hash16in, CStringGetDatum(hash_str)));
return true;
}
}
//到达此处表示未成功提取哈希值返回false
return false;
}