hillpig的个人博客分享 http://blog.sciencenet.cn/u/hillpig 畅想ing,思考ing,前行ing Email:bluevaley@gmail.com

博文

Postgresql Executor 阶段内存结构

已有 5877 次阅读 2010-5-3 09:15 |个人分类:postgresql|系统分类:科研笔记| Executor, 内存结构, Portal

上次写完了postgresql中plantree内存结构后,接下来就是执行器阶段了,首先我们得重申我们的前提条件:
假定我们数据库中已经有如下表,并填充了数据:
CREATE TABLE pois
(
  uid integer not null,
  catcode VARCHAR(32)  not null,
);
现在我们用psql发送请求:select catcode from pois;
程序已经执行完了stmt = (Node *) pg_plan_query(query, cursorOptions, boundParams);了。
我们来看看接下来需要执行的函数调用:

  1. portal = CreatePortal("", true, true);

  2. PortalDefineQuery(portal,
                             NULL,
                             query_string,
                             commandTag,
                             plantree_list,
                             NULL);

  3. PortalStart(portal, NULL, InvalidSnapshot);

  4. PortalSetResultFormat(portal, 1, &format);

  5. receiver = CreateDestReceiver(dest);

  6. SetRemoteDestReceiverParams(receiver, portal);

  7. (void) PortalRun(portal,
                            FETCH_ALL,
                            isTopLevel,
                            receiver,
                            receiver,
                            completionTag);

  8. PortalDrop(portal, false);

  9. CommandCounterIncrement();

比较重要的阶段我用红色标出。
我们先来看/backend/executor/exeMain.c中的注释,然后分别对上面的调用分析。
The old ExecutorMain() has been replaced by ExecutorStart(),ExecutorRun() and ExecutorEnd()
These three procedures are the external interfaces to the executor.In each case, the query descriptor is required as an argument.
ExecutorStart() must be called at the beginning of execution of any query plan and ExecutorEnd() should always be called at the end of execution of a plan.
看样子ExecutorStart(),ExecutorRun() and ExecutorEnd()贯穿整个executor的全过程。
1.portal = CreatePortal("", true, true);
是创建一个名字为“”的portal,创建之后如下图,并插入到PortalHashTable的hash表中:


2.PortalDefineQuery(portal,
                         NULL,
                         query_string,
                         commandTag,
                         plantree_list,
                         NULL);
该函数只是对上面的portal进行进一步的初始化,比较重要的一个赋值是:portal->stmts=plantree_list.
赋值完之后如下图:


3.PortalStart(portal, NULL, InvalidSnapshot);
其中最主要的调用是 InitPlan() ,调用堆栈是:
postgresql Thread [C/C++ Attach to Application]    
   gdb Debugger (5/1/10 10:16 AM) (Suspended)    
       Thread [1] (Suspended)    
           10 InitPlan() /home/postgres/develop/.../src/backend/executor/execMain.c:649
           9 standard_ExecutorStart() /home/postgres/develop/.../src/backend/executor/execMain.c:219    
           8 PortalStart() /home/postgres/develop/.../src/backend/tcop/pquery.c:539    
           7 exec_simple_query() /home/postgres/develop/.../src/backend/tcop/postgres.c:953
           6 PostgresMain() /home/postgres/develop/.../src/backend/tcop/postgres.c:3617    
           5 BackendRun() /home/postgres/develop/.../src/backend/postmaster/postmaster.c:3449
           4 BackendStartup() /home/postgres/develop/.../src/backend/postmaster/postmaster.c:3063
           3 ServerLoop() /home/postgres/develop/.../src/backend/postmaster/postmaster.c:1387
           2 PostmasterMain() /home/postgres/develop/.../src/backend/postmaster/postmaster.c:1040
           1 main() /home/postgres/develop/.../src/backend/main/main.c:188 0x081e7ee7
到此为止,我们形成的数据结构有些庞大了,如下图(有谁能告诉我哪儿能上传大图的?picasa不行,flickr不行):

更清晰的全图可以从这里下载。
但是有几个重要的可以罗列一下,可以号称3大天王:

  1. QueryDesc

  2. SeqScanState

  3. EState

哎,读postgresql代码真是一个耐心活呀,当你走完了十万里长征的时候,发现前面还有无休止的长征,真叫人抓狂,建议急性子的人别来玩postgresql,否则学不好最后可能会去跳峨眉山。

4.PortalSetResultFormat(portal, 1, &format);
该函数的主要作用是格式化输出字段。共有natt=1,格式化赋为0,0默认为输出为text。如源码中的注释:
format = 0;                /* TEXT is default */

5.receiver = CreateDestReceiver(dest);

6.SetRemoteDestReceiverParams(receiver, portal);
其中dest=DestRemote
这一个阶段比较简单,最终形成的数据结构为(图中做了简化,但不影响理解):


7.(void) PortalRun(portal,
                        FETCH_ALL,
                        isTopLevel,
                        receiver,
                        receiver,
                        completionTag);
千辛万苦终于到了portalrun了。
顺序抽取tuple的主循环是ExecutePlan() ,调用堆栈为:
gdb Debugger (5/2/10 5:14 PM) (Suspended)    
   Thread [1] (Suspended)    
       11 ExecutePlan() /home/postgres/develop/.../src/backend/executor/execMain.c:1696    
       10 standard_ExecutorRun() /home/postgres/develop/.../src/backend/executor/execMain.c:309
       9 PortalRunSelect() /home/postgres/develop/.../src/backend/tcop/pquery.c:953
       8 PortalRun() /home/postgres/develop/.../src/backend/tcop/pquery.c:807
       7 exec_simple_query() /home/postgres/develop/.../src/backend/tcop/postgres.c:992
       6 PostgresMain() /home/postgres/develop/.../src/backend/tcop/postgres.c:3617
       5 BackendRun() /home/postgres/develop/.../src/backend/postmaster/postmaster.c:3449
       4 BackendStartup() /home/postgres/develop/.../src/backend/postmaster/postmaster.c:3063    
       3 ServerLoop() /home/postgres/develop/.../src/backend/postmaster/postmaster.c:1387
       2 PostmasterMain() /home/postgres/develop/.../src/backend/postmaster/postmaster.c:1040    
       1 main() /home/postgres/develop/.../src/backend/main/main.c:188
这里的ExecutePlan()函数就比较简单了,主要就是从硬盘上取出每一个tuple来,放入到des中去。由于执行流程实在简单,只是修改我们原有的数据结构的一些参数,例如当时访问了多少条tuple了等等,所以这里不再绘图。
8.PortalDrop(portal, false);
9.CommandCounterIncrement();
这里就非常简单了。

最后说明一下,当执行完exec_simple_query() 之后,postgresql重新进入循环,再次执行到PostgresMain函数的第3565行的ReadyForQuery(whereToSendOutput);时,才通过库函数进行网络传送给客户端查询的结果数据。

为完整起见,我把全部需要的数据结构绘一张图,上传到这里,供参考。

加我私人微信,交流技术。







http://blog.sciencenet.cn/blog-419883-318721.html

上一篇:postgresql中plantree内存结构
下一篇:配置postgresql服务器以查看日志

0

该博文允许注册用户评论 请点击登录 评论 (1 个评论)

数据加载中...

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2021-4-13 16:52

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部