OpenGuass开源代码评注赛-针对Executor的代码评注 #38

Open
TerryTongJ wants to merge 31 commits from TerryTongJ/openGauss-server:master into master
1 changed files with 93 additions and 86 deletions
Showing only changes of commit b6594788c8 - Show all commits

View File

@ -1,15 +1,13 @@
/* -------------------------------------------------------------------------
*
* execScan.cpp
* This code provides support for generalized relation scans. ExecScan
* is passed a node and a pointer to a function to "do the right thing"
* and return a tuple from the relation. ExecScan then does the tedious
* stuff - checking the qualification and projecting the tuple
* appropriately.
* 广ExecScan被传递一个节点和一个指向函数的指针
*
* ExecScan然后做一些乏味的工作
*
* Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
* c2020
* c1996-2012PostgreSQL
* c1994
*
*
* IDENTIFICATION
@ -25,21 +23,30 @@
#include "utils/memutils.h"
/*
* ExecScanFetch -- fetch next potential tuple
* ExecScanFetch --
*
* This routine is concerned with substituting a test tuple if we are
* inside an EvalPlanQual recheck. If we aren't, just execute
* the access method's next-tuple routine.
* EvalPlanQual复查中
* 访
*/
static TupleTableSlot* ExecScanFetch(ScanState* node, ExecScanAccessMtd access_mtd, ExecScanRecheckMtd recheck_mtd)
/*
* ScanState对象
* access_mtd和recheck_mtd
* access_mtd是指向负责访问元组数据的函数的指针
* 访
* recheck_mtd是指向一个函数的指针
*
*
* TupleTableSlot对象NULL
*/
{
EState* estate = node->ps.state;
if (estate->es_epqTuple != NULL) {
/*
* We are inside an EvalPlanQual recheck. Return the test tuple if
* one is available, after rechecking any access-method-specific
* conditions.
* EvalPlanQual复查
* 访
*/
Index scan_rel_id = ((Scan*)node->ps.plan)->scanrelid;
@ -47,29 +54,29 @@ static TupleTableSlot* ExecScanFetch(ScanState* node, ExecScanAccessMtd access_m
if (estate->es_epqTupleSet[scan_rel_id - 1]) {
TupleTableSlot* slot = node->ss_ScanTupleSlot;
/* Return empty slot if we already returned a tuple */
/* 如果我们已经返回了元组,则返回空槽 */
if (estate->es_epqScanDone[scan_rel_id - 1])
return ExecClearTuple(slot);
/* Else mark to remember that we shouldn't return more */
return ExecClearTuple(slot);
/* 否则请记住,我们不应该再回来了 */
estate->es_epqScanDone[scan_rel_id - 1] = true;
/* Return empty slot if we haven't got a test tuple */
/* 如果我们没有测试元组,则返回空槽 */
if (estate->es_epqTuple[scan_rel_id - 1] == NULL)
return ExecClearTuple(slot);
/* Store test tuple in the plan node's scan slot */
/* 将测试元组存储在计划节点的扫描槽中 */
(void)ExecStoreTuple(estate->es_epqTuple[scan_rel_id - 1], slot, InvalidBuffer, false);
/* Check if it meets the access-method conditions */
/* 检查是否符合访问方法条件 */
if (!(*recheck_mtd)(node, slot))
(void)ExecClearTuple(slot); /* would not be returned by scan */
(void)ExecClearTuple(slot); /* 不会通过扫描返回 */
return slot;
}
}
/*
* Run the node-type-specific access method function to get the next tuple
* 访
*/
return (*access_mtd)(node);
}
@ -77,27 +84,28 @@ static TupleTableSlot* ExecScanFetch(ScanState* node, ExecScanAccessMtd access_m
/* ----------------------------------------------------------------
* ExecScan
*
* Scans the relation using the 'access method' indicated and
* returns the next qualifying tuple in the direction specified
* in the global variable ExecDirection.
* The access method returns the next tuple and execScan() is
* responsible for checking the tuple returned against the qual-clause.
* 使访ExecDirection中指定的方向返回下一个符合条件的元组
* access方法返回下一个元组execScanqual子句检查返回的元组
*
* A 'recheck method' must also be provided that can check an
* arbitrary tuple of the relation against any qual conditions
* that are implemented internal to the access method.
* 访qual条件检查关系的任意元组
*
* Conditions:
* -- the "cursor" maintained by the AMI is positioned at the tuple
* returned previously.
* :
* -- AMI维护的
*
* Initial States:
* -- the relation indicated is opened for scanning so that the
* "cursor" is positioned before the first qualifying tuple.
* :
* -- 便
* ----------------------------------------------------------------
*/
TupleTableSlot* ExecScan(ScanState* node, ExecScanAccessMtd access_mtd, /* function returning a tuple */
TupleTableSlot* ExecScan(ScanState* node, ExecScanAccessMtd access_mtd, /* 返回元组的函数 */
ExecScanRecheckMtd recheck_mtd)
/* 此函数负责扫描关系并返回下一个匹配的元组。它接受一个ScanState对象该对象包含有关扫描的信息以及两个函数指针access_mtd和recheck_mtd。
* access_mtd是指向负责访问元组数据的函数的指针
* 访
* recheck_mtd是指向一个函数的指针
*
* TupleTableSlot对象NULL
*/
{
ExprContext* econtext = NULL;
List* qual = NIL;
@ -109,15 +117,14 @@ TupleTableSlot* ExecScan(ScanState* node, ExecScanAccessMtd access_mtd, /* funct
return NULL;
/*
* Fetch data from node
*
*/
qual = node->ps.qual;
proj_info = node->ps.ps_ProjInfo;
econtext = node->ps.ps_ExprContext;
/*
* If we have neither a qual to check nor a projection to do, just skip
* all the overhead and return the raw scan tuple.
* qual
*/
if (qual == NULL && proj_info == NULL) {
ResetExprContext(econtext);
@ -125,38 +132,36 @@ TupleTableSlot* ExecScan(ScanState* node, ExecScanAccessMtd access_mtd, /* funct
}
/*
* Check to see if we're still projecting out tuples from a previous scan
* tuple (because there is a function-returning-set in the projection
* expressions). If so, try to project another one.
*
*
* u如果是
*/
if (node->ps.ps_TupFromTlist) {
Assert(proj_info); /* can't get here if not projecting */
Assert(proj_info); /* 如果不投影就不能到达这里 */
result_slot = ExecProject(proj_info, &is_done);
if (is_done == ExprMultipleResult)
return result_slot;
/* Done with that source tuple... */
/* 已完成该源元组... */
node->ps.ps_TupFromTlist = false;
}
/*
* @hdfs
* Optimize scan bu using informational constraint.
* if the is_scan_false is true, the iteration is over.
* 使bu
* isscanfalse为true
*/
if (node->is_scan_end) {
return NULL;
}
/*
* Reset per-tuple memory context to free any expression evaluation
* storage allocated in the previous tuple cycle. Note this can't happen
* until we're done projecting out tuples from a scan tuple.
*
*
*/
ResetExprContext(econtext);
/*
* get a tuple from the access method. Loop until we obtain a tuple that
* passes the qualification.
* access方法获取一个元组
*/
for (;;) {
TupleTableSlot* slot = NULL;
@ -164,13 +169,11 @@ TupleTableSlot* ExecScan(ScanState* node, ExecScanAccessMtd access_mtd, /* funct
CHECK_FOR_INTERRUPTS();
slot = ExecScanFetch(node, access_mtd, recheck_mtd);
/* refresh qual every loop */
/* 刷新qual每个循环 */
qual = node->ps.qual;
/*
* if the slot returned by the accessMtd contains NULL, then it means
* there is nothing more to scan so we just return an empty slot,
* being careful to use the projection result slot so it has correct
* tupleDesc.
* accessMtd返回的槽包含NULL西
* 使tupleDesc
*/
if (TupIsNull(slot) || unlikely(executorEarlyStop())) {
if (proj_info != NULL)
@ -180,30 +183,28 @@ TupleTableSlot* ExecScan(ScanState* node, ExecScanAccessMtd access_mtd, /* funct
}
/*
* place the current tuple into the expr context
* expr上下文
*/
econtext->ecxt_scantuple = slot;
/*
* check that the current tuple satisfies the qual-clause
* qual子句
*
* check for non-nil qual here to avoid a function call to ExecQual()
* when the qual is nil ... saves only a few cycles, but they add up
* nil qualqual为nil时调用ExecQual...
* ...
*/
if (qual == NULL || ExecQual(qual, econtext, false)) {
/*
* Found a satisfactory scan tuple.
*
*/
if (proj_info != NULL) {
/*
* Form a projection tuple, store it in the result tuple slot
* and return it --- unless we find we can project no tuples
* from this scan tuple, in which case continue scan.
*
*
*/
result_slot = ExecProject(proj_info, &is_done);
#ifdef PGXC
/* Copy the xcnodeoid if underlying scanned slot has one */
/* 复制xcnodeoid如果底层扫描的插槽有一个 */
result_slot->tts_xcnodeoid = slot->tts_xcnodeoid;
#endif /* PGXC */
if (is_done != ExprEndResult) {
@ -211,15 +212,14 @@ TupleTableSlot* ExecScan(ScanState* node, ExecScanAccessMtd access_mtd, /* funct
/*
* @hdfs
* Optimize foreign scan by using informational constraint.
* 使
*/
if (IsA(node->ps.plan, ForeignScan)) {
ForeignScan* foreign_scan = (ForeignScan*)(node->ps.plan);
if (foreign_scan->scan.scan_qual_optimized) {
/*
* If we find a suitable tuple, set is_scan_end value is true.
* It means that we do not find suitable tuple in the next iteration,
* the iteration is over.
* set is_scan_end值为true
*
*/
node->is_scan_end = true;
}
@ -228,21 +228,20 @@ TupleTableSlot* ExecScan(ScanState* node, ExecScanAccessMtd access_mtd, /* funct
}
} else {
/*
* Optimize foreign scan by using informational constraint.
* 使
*/
if (IsA(node->ps.plan, ForeignScan)) {
ForeignScan* foreign_scan = (ForeignScan*)(node->ps.plan);
if (foreign_scan->scan.scan_qual_optimized) {
/*
* If we find a suitable tuple, set is_scan_end value is true.
* It means that we do not find suitable tuple in the next iteration,
* the iteration is over.
* set is_scan_end值为true
*
*/
node->is_scan_end = true;
}
}
/*
* Here, we aren't projecting, so just return scan tuple.
*
*/
return slot;
}
@ -250,7 +249,7 @@ TupleTableSlot* ExecScan(ScanState* node, ExecScanAccessMtd access_mtd, /* funct
InstrCountFiltered1(node, 1);
/*
* Tuple fails qual, so free per-tuple memory and try again.
* qual
*/
ResetExprContext(econtext);
}
@ -258,23 +257,21 @@ TupleTableSlot* ExecScan(ScanState* node, ExecScanAccessMtd access_mtd, /* funct
/*
* ExecAssignScanProjectionInfo
* Set up projection info for a scan node, if necessary.
*
*
* We can avoid a projection step if the requested tlist exactly matches
* the underlying tuple type. If so, we just set ps_ProjInfo to NULL.
* Note that this case occurs not only for simple "SELECT * FROM ...", but
* also in most cases where there are joins or other processing nodes above
* the scan node, because the planner will preferentially generate a matching
* tlist.
* tlist与底层元组类型完全匹配
* ps_ProjegInfo设置为NULL
* SELECT*FROM
* tlist
*
* ExecAssignScanType must have been called already.
* ExecAssignScanType
*/
void ExecAssignScanProjectionInfo(ScanState* node)
{
Scan* scan = (Scan*)node->ps.plan;
Index var_no;
/* Vars in an index-only scan's tlist should be INDEX_VAR */
/* 仅索引扫描的tlist中的变量应为index_VAR */
if (IsA(scan, IndexOnlyScan))
var_no = INDEX_VAR;
else
@ -285,6 +282,16 @@ void ExecAssignScanProjectionInfo(ScanState* node)
else
ExecAssignProjectionInfo(&node->ps, node->ss_ScanTupleSlot->tts_tupleDescriptor);
}
/* 函数ExecAssignScanProjectionInfo负责将投影信息分配给ScanState节点。让我们分解代码
ScanState指针作为输入
使Scan*node->ps.plan将ScanState强制转换为Scan节点
var_no
使IsAscanIndexOnlyScanvar_no设置为index_var
var_no设置为scan->scanrelid
使tlist_matches_tupdesc函数检查扫描的目标列表是否与扫描元组槽的元组描述符匹配node->ps.ps_ProjInfo设置为NULL
ExecAssignProjectionInfo使ScanState节点
ScanState节点
*/
/*
* ExecAssignScanProjectionInfoWithVarno