This commit is contained in:
yangke1125 2023-08-23 18:48:17 +08:00
parent 38591f1cda
commit 32c54300a3
1 changed files with 122 additions and 121 deletions

View File

@ -53,34 +53,34 @@
*/
static uint64 gen_usertable_hash_sum(Relation rel)
{
uint64 rel_hash = 0;
bool is_null = false;
int hash_natt = user_hash_attrno(rel->rd_att);
uint64 rel_hash = 0;//初始化关系哈希和为零
bool is_null = false;//初始化标志位为假
int hash_natt = user_hash_attrno(rel->rd_att);//获取用户关系的哈希属性编号
Assert(hash_natt >= 0);
HeapTuple tuple;
TupleDesc desc = rel->rd_att;
Snapshot snapshot = GetActiveSnapshot();
TableScanDesc scan;
if (RELATION_CREATE_BUCKET(rel)) {
Relation bucket_rel = NULL;
oidvector *bucket_list = searchHashBucketByOid(rel->rd_bucketoid);
for (int i = 0; i < bucket_list->dim1; i++) {
bucket_rel = bucketGetRelation(rel, NULL, bucket_list->values[i]);
scan = heap_beginscan(bucket_rel, snapshot, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) {
HeapTuple tuple;//用于存储关系的元组
TupleDesc desc = rel->rd_att;//获取关系的元组描述
Snapshot snapshot = GetActiveSnapshot();//活动快照
TableScanDesc scan;//表扫描器
if (RELATION_CREATE_BUCKET(rel)) {//如果关系是哈希分区表啊
Relation bucket_rel = NULL;//初始化分区关系
oidvector *bucket_list = searchHashBucketByOid(rel->rd_bucketoid);//获取哈希分区列表
for (int i = 0; i < bucket_list->dim1; i++) {//遍历哈希分区列表
bucket_rel = bucketGetRelation(rel, NULL, bucket_list->values[i]);//获取哈希分区关系
scan = heap_beginscan(bucket_rel, snapshot, 0, NULL);//开始扫描分区表
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) {//遍历分区表中的元组
rel_hash += DatumGetUInt64(heap_getattr(tuple, hash_natt + 1, desc, &is_null));
}
heap_endscan(scan);
}//获取哈希值累加到关系哈希和中
heap_endscan(scan);//结束扫描
bucketCloseRelation(bucket_rel);
}
} else {
scan = heap_beginscan(rel, snapshot, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) {
} else {//如果关系不是哈希分区表
scan = heap_beginscan(rel, snapshot, 0, NULL);//开始扫描关系
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) {//遍历关系中的元组
rel_hash += DatumGetUInt64(heap_getattr(tuple, hash_natt + 1, desc, &is_null));
}
heap_endscan(scan);
heap_endscan(scan);//结束扫描
}
return rel_hash;
return rel_hash;//返回关系哈希和
}
/*
@ -92,27 +92,27 @@ static uint64 gen_usertable_hash_sum(Relation rel)
*/
static uint64 get_usertable_hash_sum(Oid relid)
{
uint64 rel_hash = 0;
uint64 rel_hash = 0;//初始化关系哈希和为零
Relation rel = NULL;
rel = heap_open(relid, AccessShareLock);
if (!RelationIsPartitioned(rel)) {
rel_hash = gen_usertable_hash_sum(rel);
} else {
List *partition_list = NIL;
rel = heap_open(relid, AccessShareLock);//打开用户表关系并获取共享锁
if (!RelationIsPartitioned(rel)) {//如果用户表不是分区表
rel_hash = gen_usertable_hash_sum(rel);//调用函数
} else {//如果是分区表
List *partition_list = NIL;//初始化
ListCell *lc = NULL;
Partition part;
Relation fake_rel;
partition_list = relationGetPartitionList(rel, AccessShareLock);
foreach (lc, partition_list) {
part = (Partition)lfirst(lc);
Partition part;//分区
Relation fake_rel;//假分区关系
partition_list = relationGetPartitionList(rel, AccessShareLock);//获取分区列表
foreach (lc, partition_list) {//遍历分区列表
part = (Partition)lfirst(lc);//获取分区
fake_rel = partitionGetRelation(rel, part);
rel_hash += gen_usertable_hash_sum(fake_rel);
releaseDummyRelation(&fake_rel);
rel_hash += gen_usertable_hash_sum(fake_rel);//调用函数计算分区关系哈希和并累加
releaseDummyRelation(&fake_rel);//释放分区关系
}
releasePartitionList(rel, &partition_list, AccessShareLock);
releasePartitionList(rel, &partition_list, AccessShareLock);// 释放分区列表
}
heap_close(rel, AccessShareLock);
return rel_hash;
heap_close(rel, AccessShareLock);// 关闭用户表关系并释放共享锁
return rel_hash;// 返回关系哈希和
}
/*
@ -122,28 +122,28 @@ static uint64 get_usertable_hash_sum(Oid relid)
*/
static uint64 get_histtable_hash_sum(Oid hist_oid)
{
uint64 rel_hash = 0;
bool is_null = false;
Relation hist_rel;
uint64 rel_hash = 0;// 初始化哈希差值为零
bool is_null = false;// 初始化标志位为假
Relation hist_rel;// 初始化历史表关系
TableScanDesc scan;
HeapTuple tuple;
HeapTuple tuple; // 用于存储历史表中的元组
Snapshot snapshot = GetActiveSnapshot();
hist_rel = heap_open(hist_oid, AccessShareLock);
scan = heap_beginscan(hist_rel, snapshot, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) {
hist_rel = heap_open(hist_oid, AccessShareLock);// 打开历史表关系并获取共享锁
scan = heap_beginscan(hist_rel, snapshot, 0, NULL); // 开始扫描历史表
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { // 遍历历史表中的元组
Datum value = heap_getattr(tuple, USERCHAIN_COLUMN_HASH_INS + 1, hist_rel->rd_att, &is_null);
if (!is_null) {
rel_hash += DatumGetUInt64(value);
if (!is_null) {// 如果不是空值
rel_hash += DatumGetUInt64(value);// 累加到哈希差值中
}
value = heap_getattr(tuple, USERCHAIN_COLUMN_HASH_DEL + 1, hist_rel->rd_att, &is_null);
if (!is_null) {
rel_hash -= DatumGetUInt64(value);
if (!is_null) {// 如果不是空值
rel_hash -= DatumGetUInt64(value); // 从哈希差值中减去
}
}
heap_endscan(scan);
heap_close(hist_rel, AccessShareLock);
heap_endscan(scan);// 结束历史表扫描
heap_close(hist_rel, AccessShareLock); // 关闭历史表关系并释放共享锁
return rel_hash;
}
@ -171,23 +171,23 @@ static bool has_ledger_consistent_privilege(Oid relid, Oid namespaceId)
*/
bool is_hist_hash_identity(Oid relid, uint64 *res_hash)
{
uint64 user_hash_sum;
uint64 hist_hash_sum;
uint64 user_hash_sum;// 用户表的哈希和
uint64 hist_hash_sum;// 历史表的哈希和
char hist_name[NAMEDATALEN];
char *rel_name = get_rel_name(relid);
if (!get_hist_name(relid, rel_name, hist_name)) {
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("get hist table name failed.")));
char *rel_name = get_rel_name(relid);// 获取用户表的名称
if (!get_hist_name(relid, rel_name, hist_name)) {// 获取历史表的名称
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("get hist table name failed."))); // 如果获取失败<EFBC8C><E58899><EFBFBD>
}
Oid histoid = get_relname_relid(hist_name, PG_BLOCKCHAIN_NAMESPACE);
if (!OidIsValid(histoid)) {
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find hist table of \"%s\".", rel_name)));
Oid histoid = get_relname_relid(hist_name, PG_BLOCKCHAIN_NAMESPACE);// 获取历史表的 OID
if (!OidIsValid(histoid)) { // 如果 OID 无效
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find hist table of \"%s\".", rel_name)));// 报错,找不到历史表
}
user_hash_sum = get_usertable_hash_sum(relid);
hist_hash_sum = get_histtable_hash_sum(histoid);
user_hash_sum = get_usertable_hash_sum(relid); // 获取用户表的哈希总和
hist_hash_sum = get_histtable_hash_sum(histoid); // 获取历史表的哈希总和
*res_hash = hist_hash_sum;
return user_hash_sum == hist_hash_sum;
*res_hash = hist_hash_sum; // 返回历史表的哈希和
return user_hash_sum == hist_hash_sum; // 返回用户表哈希和和历史表哈希和是否相等的比较结果
}
#ifdef ENABLE_MULTIPLE_NODES
@ -201,28 +201,28 @@ bool is_hist_hash_identity(Oid relid, uint64 *res_hash)
*/
static void StrategyFuncAnd(ParallelFunctionState* state)
{
TupleTableSlot* slot = NULL;
bool result = true;
TupleTableSlot* slot = NULL;// 创建 TupleTableSlot 用于存储结果
bool result = true;// 初始化结果为true
Assert(state);
Assert(state->tupstore);
Assert(state->tupdesc);
slot = MakeSingleTupleTableSlot(state->tupdesc);
Assert(state); // 断言 state 不为空
Assert(state->tupstore);// 断言 tupstore 不为空
Assert(state->tupdesc);// 断言 tupdesc 不为空
slot = MakeSingleTupleTableSlot(state->tupdesc);// 创建单个 TupleTableSlot 用于存储数据
while (true) {
bool isnull = false;
if (!tuplestore_gettupleslot(state->tupstore, true, false, slot))
if (!tuplestore_gettupleslot(state->tupstore, true, false, slot)) // 从 tupstore 获取下一个结果,如果没有更多结果则退出循环
break;
if (!DatumGetBool(tableam_tslot_getattr(slot, 1, &isnull))) {
if (!DatumGetBool(tableam_tslot_getattr(slot, 1, &isnull))) {// 从 TupleTableSlot 中获取属性值,如果为 false 则将结果设置为 false 并退出循环
result = false;
break;
}
(void)ExecClearTuple(slot);
(void)ExecClearTuple(slot); // 清空 TupleTableSlot
}
state->result = result;
state->result = result;// 将结果存储在并行函数状态中
}
/*
@ -235,31 +235,30 @@ static void StrategyFuncAnd(ParallelFunctionState* state)
*/
static void StrategyFuncUInt64Sum(ParallelFunctionState* state)
{
TupleTableSlot* slot = NULL;
int64 result = 0;
TupleTableSlot* slot = NULL;// 创建 TupleTableSlot 用于存储结果
int64 result = 0;// 初始化结果为 0
Assert(state && state->tupstore && state->tupdesc);
slot = MakeSingleTupleTableSlot(state->tupdesc);
Assert(state && state->tupstore && state->tupdesc);// 断言 state、tupstore 和 tupdesc 不为空
slot = MakeSingleTupleTableSlot(state->tupdesc);// 创建单个 TupleTableSlot 用于存储数据
while (true) {
bool isnull = false;
if (!tuplestore_gettupleslot(state->tupstore, true, false, slot))
if (!tuplestore_gettupleslot(state->tupstore, true, false, slot))// 从 tupstore 获取下一个结果,如果没有更多结果则退出循环
break;
result += DatumGetUInt64(tableam_tslot_getattr(slot, 1, &isnull));
ExecClearTuple(slot);
result += DatumGetUInt64(tableam_tslot_getattr(slot, 1, &isnull));// 从 TupleTableSlot 中获取属性值并累加到结果中
ExecClearTuple(slot);// 清空 TupleTableSlot
}
state->result = result;
state->result = result;// 将结果存储在并行函数状态中
}
#endif
/*
* ledger_hist_check -- check whether user table hash and history table hash are equal
* ledger_hist_check --
*
* parameter1: user table name [type: text]
* parameter2: namespace of user table [type: text]
* parameter1: [: text]
* parameter2: [: text]
*/
Datum ledger_hist_check(PG_FUNCTION_ARGS)
{
@ -269,30 +268,32 @@ Datum ledger_hist_check(PG_FUNCTION_ARGS)
bool res = false;
char *table_name;
char *table_nsp;
text *rel_nsp = PG_GETARG_TEXT_PP(0);
text *rel_name = PG_GETARG_TEXT_PP(1);
text *rel_nsp = PG_GETARG_TEXT_PP(0); // 获取第一个参数,用户表的命名空间
text *rel_name = PG_GETARG_TEXT_PP(1); // 获取第二个参数,用户表名
table_nsp = text_to_cstring(rel_nsp);
table_name = text_to_cstring(rel_name);
nsp_oid = get_namespace_oid(table_nsp, false);
relid = get_relname_relid(table_name, nsp_oid);
ledger_usertable_check(relid, nsp_oid, table_name, table_nsp);
if (!has_ledger_consistent_privilege(relid, nsp_oid)) {
table_nsp = text_to_cstring(rel_nsp);// 将文本参数转换为 C 字符串
table_name = text_to_cstring(rel_name);// 将文本参数转换为 C 字符串
nsp_oid = get_namespace_oid(table_nsp, false);// 获取命名空间的 OID
relid = get_relname_relid(table_name, nsp_oid);// 获取用户表的 OID
ledger_usertable_check(relid, nsp_oid, table_name, table_nsp);// 检查用户表是否存在
if (!has_ledger_consistent_privilege(relid, nsp_oid)) { // 检查权限
ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied.")));
}
res = is_hist_hash_identity(relid, &res_hash);
res = is_hist_hash_identity(relid, &res_hash);// 检查用户表哈希和历史表哈希是否相等
#ifdef ENABLE_MULTIPLE_NODES
if (!IsConnFromCoord()) {
StringInfoData buf;
ParallelFunctionState* state = NULL;
initStringInfo(&buf);
if (!IsConnFromCoord()) {// 如果不是从协调器节点调用
StringInfoData buf;// 创建一个字符串缓冲区
ParallelFunctionState* state = NULL;// 创建并行函数状态
initStringInfo(&buf);// 初始化字符串缓冲区
appendStringInfo(&buf, "SELECT pg_catalog.ledger_hist_check('%s', '%s')", table_nsp, table_name);
/* Get all hash diffs from DNs in distribute scenairo. */
state = RemoteFunctionResultHandler(buf.data, NULL, StrategyFuncAnd);
res &= state->result;
FreeParallelFunctionState(state);
res &= state->result;// 更新结果
FreeParallelFunctionState(state);// 释放并行函数状态
}
#endif
return BoolGetDatum(res);
@ -309,19 +310,19 @@ static uint64 get_gchain_relhash_sum(Oid relid)
HeapTuple tuple = NULL;
/* scan the gs_global_chain catalog by relid */
Relation gchain_rel = heap_open(GsGlobalChainRelationId, AccessShareLock);
Relation gchain_rel = heap_open(GsGlobalChainRelationId, AccessShareLock);// 打开 gs_global_chain 关系
Form_gs_global_chain rdata = NULL;
TableScanDesc scan = heap_beginscan(gchain_rel, SnapshotNow, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) {
rdata = (Form_gs_global_chain)GETSTRUCT(tuple);
if (rdata == NULL || rdata->relid != relid) {
TableScanDesc scan = heap_beginscan(gchain_rel, SnapshotNow, 0, NULL);// 创建表扫描描述符
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) {// 循环遍历结果集
rdata = (Form_gs_global_chain)GETSTRUCT(tuple);// 获取结果的数据结构
if (rdata == NULL || rdata->relid != relid) {// 如果数据为空或者 OID 不匹配,则继续下一轮循环
continue;
}
relhash += rdata->relhash;
relhash += rdata->relhash;// 累加关系哈希值
}
heap_endscan(scan);
heap_close(gchain_rel, AccessShareLock);
return relhash;
heap_endscan(scan);// 结束扫描
heap_close(gchain_rel, AccessShareLock);// 关闭关系
return relhash;// 返回关系哈希和
}
/*
@ -336,39 +337,39 @@ static uint64 get_gchain_relhash_sum(Oid relid)
Datum get_dn_hist_relhash(PG_FUNCTION_ARGS)
{
#ifndef ENABLE_MULTIPLE_NODES
DISTRIBUTED_FEATURE_NOT_SUPPORTED();
DISTRIBUTED_FEATURE_NOT_SUPPORTED(); // 不支持分布式特性
return UInt64GetDatum(0);
#else
if (!IsConnFromCoord()) {
if (!IsConnFromCoord()) {// 如果不是从协调器节点调用
ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied.")));
return UInt64GetDatum(0);
}
Oid user_relid;
Oid nsp_oid;
uint64 res_hash;
text *rel_nsp = PG_GETARG_TEXT_PP(0);
text *rel_name = PG_GETARG_TEXT_PP(1);
text *rel_nsp = PG_GETARG_TEXT_PP(0);// 获取第一个参数,用户表的命名空间
text *rel_name = PG_GETARG_TEXT_PP(1);// 获取第二个参数,用户表名
char *table_name;
char *table_nsp;
table_nsp = text_to_cstring(rel_nsp);
table_name = text_to_cstring(rel_name);
nsp_oid = get_namespace_oid(table_nsp, false);
user_relid = get_relname_relid(table_name, nsp_oid);
ledger_usertable_check(user_relid, nsp_oid, table_name, table_nsp);
table_nsp = text_to_cstring(rel_nsp);// 将文本参数转换为 C 字符串
table_name = text_to_cstring(rel_name);// 将文本参数转换为 C 字符串
nsp_oid = get_namespace_oid(table_nsp, false);// 获取命名空间的 OID
user_relid = get_relname_relid(table_name, nsp_oid);// 获取用户表的 OID
ledger_usertable_check(user_relid, nsp_oid, table_name, table_nsp);// 检查用户表是否存在
if (!has_ledger_consistent_privilege(user_relid, nsp_oid)) {
ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Permission denied.")));
}
if (IS_PGXC_DATANODE) {
if (!is_hist_hash_identity(user_relid, &res_hash)) {
if (IS_PGXC_DATANODE) {// 如果当前节点是数据节点
if (!is_hist_hash_identity(user_relid, &res_hash)) {// 检查用户表哈希和历史表哈希是否相等
res_hash = 0;
}
} else {
} else {// 如果当前节点是协调器节点
res_hash = get_gchain_relhash_sum(user_relid);
}
return UInt64GetDatum(res_hash);
return UInt64GetDatum(res_hash);//返回结果
#endif
}