在《Postgresql服务过程中的那些事二:pg服务进程处理简单查询概览》里话说以下面的例子对简单查询分支进行讨论,并给出了简单查询方法调用序列,下面就从这儿开始,先回顾一下上节点内容。
进入简单查询分支处理方法exec_simple_query后的处理基本上涵盖了《数据库系统实现》这本书里的内容。处理量相当大,先根据流程图概览一下处理过程。为了减小图的大小,把PostgresMain以前的调用流程略了。在以后讨论简单查询时PostgresMain以前的调用流程也省略了,要回顾可参见《Postgresql服务过程中的那些事二:pg服务进程处理简单查询概览》里的“Postgres服务进程处理请求的无限循环调用序列图”。
处理简单查询方法exec_simple_query调用序列图
主要的处理过程是先调用@H_403_20@start_xact_command方法开启一个事务,再用@H_403_20@pg_parse_query方法用词法语法解析工具把查询命令解析为解析树parsetree,根据需要调用@H_403_20@PushActiveSnapshot方法搞一个快照,调用@H_403_20@pg_analyze_and_rewrite方法分析、根据规则重写解析树为查询树querytree,调用@H_403_20@pg_plan_queries方法把查询树转换到执行计划树plantree,在调用相应方法创建portal和在postal中执行执行计划树并给客户端发回结果。然后退出当前事务,清理内存。
1
现在描述这个例子:数据库TEST里有表TEST1、TEST2,现在客户端发出查询“@H_403_20@selectcname,comp from test1,test2 where test1.id=test2.id;”。建表的语句在下面。
createtable test1 (ID numeric(10),cname varchar(30));
createtable test2 (ID numeric(10),comp varchar(30));
postgres服务进程分析了查询指令后走了简查查询分支exec_simple_query。
再看一下exec_simple_query方法的简化流程图
exec_simple_query方法的简化流程图
2
进了excu_simple_query分支的第一件事就是开启一个事务命令,pg里所有查询都要在事务里进行。下面是开启事务的调用序列图。
Postgres服务进程简查之开始事务调用序列图
上图大红色方框中显示了启动事物的相关的相关处理,进入StartTransaction方法后,使TransactionStateData *类型静态全局变量CurrentTransactionState指向TransactionStateData类型静态全局变量TopTransactionStateData,在CurrentTransactionState设置当前事务状态,记录当前事务ID和当前命令ID。然后调用AtStart_Memory方法创建内存上下文"TransactionAbortContext"@H_301_125@和"TopTransactionContext",接着调用AtStart_ResourceOwner方法在内存上下文"TopMemoryContext"中创建@H_301_125@资源属@H_301_125@主@H_301_125@ResourceOwnerData@H_301_125@类型变量@H_301_125@curTransationOwner@H_301_125@,并让CurrentTransactionState@H_301_125@的ResourceOwnerData*类型成员curTransactionOwner指向该变量。用以上建立的结构管理该事务涉及到资源。描述着比较难理清关系,看下面的图吧。
记录事务状态及管理事务资源的相关结构图
从图中看见事务相关的资源属主@H_301_125@ResourceOwnerData管理的事务资源包括关系内存缓存、系统表缓存@H_301_125@catcache、关系模式缓存@H_301_125@relcache、执行计划缓存@H_301_125@plancache、查询命令相关元组描述符缓存@H_301_125@tupdesc、事务相关快照以及打开的临时文件等。
事务状态及管理事务资源的相关结构见下面:
/*
* transactionstate structure
*/
@H_403_20@typedefstruct@H_301_125@ TransactionStateData
@H_301_125@{
@H_301_125@ TransactionIdtransactionId@H_301_125@; /* my XID,or Invalid if none */
@H_301_125@ SubTransactionIdsubTransactionId@H_301_125@; /* my subxact ID */
@H_301_125@ @H_403_20@char@H_301_125@ *name@H_301_125@; /* savepoint name,if any*/
@H_301_125@ @H_403_20@int@H_301_125@ savepointLevel@H_301_125@; /* savepoint level */
@H_301_125@ TransState@H_301_125@ state@H_301_125@; /* low-level state */
@H_301_125@ TBlockStateblockState@H_301_125@; /* high-level state */
@H_301_125@ @H_403_20@int@H_301_125@ nestingLevel@H_301_125@; /* transaction nesting depth */
@H_301_125@ @H_403_20@int@H_301_125@ gucNestLevel@H_301_125@; /* GUC context nesting depth */
@H_301_125@ MemoryContextcurTransactionContext@H_301_125@; /* my xact-lifetime context */
@H_301_125@ ResourceOwnercurTransactionOwner@H_301_125@; /* my query resources */
@H_301_125@ TransactionId@H_301_125@ *childXids@H_301_125@; /* subcommitted child XIDs,in XID order */
@H_301_125@ @H_403_20@int@H_301_125@ nChildXids@H_301_125@; /* # of subcommitted childXIDs */
@H_301_125@ @H_403_20@int@H_301_125@ maxChildXids@H_301_125@; /* allocated size of childXids[]*/
@H_301_125@ Oid@H_301_125@ prevUser@H_301_125@; /* prevIoUs CurrentUserId setting*/
@H_301_125@ @H_403_20@int@H_301_125@ prevSecContext@H_301_125@; /* prevIoUs SecurityRestrictionContext */
@H_301_125@ bool@H_301_125@ prevXactReadOnly@H_301_125@; /* entry-time xact r/ostate */
@H_301_125@ bool@H_301_125@ startedInRecovery@H_301_125@; /* did we start in recovery? */
@H_301_125@ @H_403_20@struct@H_301_125@ TransactionStateData *parent@H_301_125@; /* back link to parent */
@H_301_125@} TransactionStateData@H_301_125@;
@H_403_20@typedefTransactionStateData@H_301_125@ *TransactionState@H_301_125@;
/*
* CurrentTransactionState always points to thecurrent transaction state
* block.It will point to TopTransactionStateData when not in a
* transaction at all,or when in a top-leveltransaction.
*/
@H_403_20@staticTransactionStateData@H_301_125@ TopTransactionStateData = {
@H_301_125@ 0,/* transaction id */
@H_301_125@ 0,/* subtransaction id */
@H_301_125@ NULL,/* savepoint name */
@H_301_125@ 0,/* savepoint level */
@H_301_125@ TRANS_DEFAULT@H_301_125@,/* transaction state */
@H_301_125@ TBLOCK_DEFAULT@H_301_125@,/* transaction block state fromthe client
* perspective */
@H_301_125@ 0,/* transaction nesting depth */
@H_301_125@ 0,/* GUC context nesting depth */
@H_301_125@ NULL,/* cur transaction context */
@H_301_125@ NULL,/* cur transaction resource owner*/
@H_301_125@ NULL,/* subcommitted child Xids*/
@H_301_125@ 0,/* # of subcommitted child Xids*/
@H_301_125@ 0,/* allocated size of childXids[]*/
@H_301_125@ InvalidOid,/* prevIoUs CurrentUserId setting*/
@H_301_125@ 0,/* prevIoUsSecurityRestrictionContext */
@H_301_125@ false,/* entry-time xact r/ostate */
@H_301_125@ false,/* startedInRecovery */
@H_301_125@ NULL /* link to parent state block */
@H_301_125@};
@H_403_20@staticTransactionState@H_301_125@ CurrentTransactionState =&TopTransactionStateData;
3
接着调用VirtualXactLockTableInsert方法给该事务一个VirtualTransactionId(这个类型是把pg服务进程ID和该进程上的事务ID关联起来的结构)类型的虚拟事务ID:VXID,并加锁。VirtualTransactionId的类型定义见下面:
@H_403_20@typedefstruct
@H_301_125@{
@H_301_125@ BackendId@H_301_125@ backendId@H_301_125@; /* determined at backendstartup */
@H_301_125@ LocalTransactionIdlocalTransactionId@H_301_125@; /* backend-localtransaction
* id */
@H_301_125@} VirtualTransactionId@H_301_125@;
在事务开始时调用AtStart_GUC()设置事务嵌套层数,调用AtStart_Inval()方法初始化管理该事务失效信息用的TransInvalidationInfo类型结构,调用AtStart_Cache方法从共享失效消息队列读取并处理失效消息,调用AfterTriggerBeginXact方法初始化@H_301_125@AfterTriggersData类型结构以备后面处理相关AFTER的触发器。@H_301_125@AfterTriggersData@H_301_125@的结构定义见下面:
@H_403_20@typedefstruct@H_301_125@ AfterTriggersData
@H_301_125@{
@H_301_125@ CommandId@H_301_125@ firing_counter@H_301_125@; /* next firing ID to assign */
@H_301_125@ SetConstraintStatestate@H_301_125@; /* the active S C state */
@H_301_125@ AfterTriggerEventListevents@H_301_125@; /* deferred-event list */
@H_301_125@ @H_403_20@int@H_301_125@ query_depth@H_301_125@; /* current query list index */
@H_301_125@ AfterTriggerEventList@H_301_125@ *query_stack@H_301_125@; /* eventspending from each query */
@H_301_125@ @H_403_20@int@H_301_125@ maxquerydepth@H_301_125@; /* allocated len of abovearray */
@H_301_125@ MemoryContextevent_cxt@H_301_125@; /* memory context for events,if any */
@H_301_125@ /* these fields are just for resetting at subtransabort: */
@H_301_125@ SetConstraintState@H_301_125@ *state_stack@H_301_125@; /* stacked S C states */
@H_301_125@ AfterTriggerEventList@H_301_125@ *events_stack@H_301_125@; /* stacked list pointers */
@H_301_125@ @H_403_20@int@H_301_125@ *depth_stack@H_301_125@; /* stacked query_depths */
@H_301_125@ CommandId@H_301_125@ *firing_stack@H_301_125@; /* stacked firing_counters */
@H_301_125@ @H_403_20@int@H_301_125@ maxtransdepth@H_301_125@; /* allocated len of abovearrays */
@H_301_125@} AfterTriggersData@H_301_125@;
在StartTransaction方法里主要干了上面这些事并设置了记录事务状态的结构CurrentTransactionState@H_301_125@的成员,其中有一个成员@H_301_125@TransState state@H_301_125@,@H_301_125@TransState@H_301_125@是枚举类型,表示事务状态,其定义如下:
/*
* transactionstates - transaction state from server perspective
*/
@H_403_20@typedefenum@H_301_125@ TransState
@H_301_125@{
@H_301_125@ TRANS_DEFAULT@H_301_125@,/* idle */
@H_301_125@ TRANS_START@H_301_125@,/* transaction starting */
@H_301_125@ TRANS_INPROGRESS@H_301_125@,/* inside a valid transaction */
@H_301_125@ TRANS_COMMIT@H_301_125@,/* commit in progress */
@H_301_125@ TRANS_ABORT@H_301_125@,/* abort in progress */
@H_301_125@ TRANS_PREPARE@H_301_125@ /* prepare in progress */
@H_301_125@} TransState@H_301_125@;
好了,这节就到这儿。