PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么

网友投稿 591 2024-01-03 11:40:16

PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么

这篇文章主要讲解了“PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么”吧!

一、基础信息

ExecProcNode/ExecProcNodeFirst函数使用的数据结构、宏定义以及依赖的函数等。

数据结构/宏定义

1、ExecProcNodeMtd

ExecProcNodeMtd是一个函数指针类型,指向的函数输入参数是PlanState结构体指针,输出参数是TupleTableSlot 结构体指针 /* ----------------   *   ExecProcNodeMtd   *   * This is the method called by ExecProcNode to return the next tuple   * from an executor node.  It returns NULL, or an empty TupleTableSlot,   * if no more tuples are available.   * ----------------   */  typedef TupleTableSlot *(*ExecProcNodeMtd) (struct PlanState *pstate);

依赖的函数1、check_stack_depth

//检查stack的深度,如超出系统限制,则主动报错  /*   * check_stack_depth/stack_is_too_deep: check for excessively deep recursion   *   * This should be called someplace in any recursive routine that might possibly   * recurse deep enough to overflow the stack.  Most Unixen treat stack   * overflow as an unrecoverable SIGSEGV, so we want to error out ourselves   * before hitting the hardware limit.   *   * check_stack_depth() just throws an error summarily.  stack_is_too_deep()   * can be used by code that wants to handle the error condition itself.   */  void  check_stack_depth(void)  {      if(stack_is_too_deep())      {          ereport(ERROR,                  (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),                   errmsg("stack depth limit exceeded"),                   errhint("Increase the configuration parameter \"max_stack_depth\" (currently %dkB), "                           "after ensuring the platforms stack depth limit is adequate.",                           max_stack_depth)));      }  }bool  stack_is_too_deep(void)  {      char        stack_top_loc;      longstack_depth;/*       * Compute distance from reference point to my local variables       */      stack_depth = (long) (stack_base_ptr - &stack_top_loc);        /*       * Take abs value, since stacks grow up on some machines, down on others       */      if (stack_depth < 0)          stack_depth = -stack_depth;/*       * Trouble?       *       * The test on stack_base_ptr prevents us from erroring out if called       * during process setup or in a non-backend process.  Logically it should       * be done first, but putting it here avoids wasting cycles during normal       * cases.       */      if (stack_depth > max_stack_depth_bytes &&          stack_base_ptr != NULL)          return true;        /*       * On IA64 there is a separate "register" stack that requires its own       * independent check.  For this, we have to measure the change in the       * "BSP" pointer from PostgresMain to here.  Logic is just as above,       * except that we know IA64s register stack grows up.       *       * Note we assume that the same max_stack_depth applies to both stacks.       */  #if defined(__ia64__) || defined(__ia64)stack_depth = (long) (ia64_get_bsp() - register_stack_base_ptr);        if(stack_depth > max_stack_depth_bytes &&          register_stack_base_ptr !=NULL)          return true;  #endif                          /* IA64 */        return false;  }

2、ExecProcNodeInstr

 /*   * ExecProcNode wrapper that performs instrumentation calls.  By keeping   * this a separate function, we avoid overhead in the normal case where   * no instrumentation is wanted.   */  staticTupleTableSlot *  ExecProcNodeInstr(PlanState *node)  {      TupleTableSlot *result;        InstrStartNode(node->instrument);        result = node->ExecProcNodeReal(node);        InstrStopNode(node->instrument, TupIsNull(result) ?0.0 : 1.0);        returnresult;  }二、源码解读

1、ExecProcNode

//外部调用者可通过改变node实现遍历  /* ----------------------------------------------------------------   *      ExecProcNode   *   *      Execute the given node to return a(nother) tuple.   * ----------------------------------------------------------------   */  #ifndef FRONTEND  static inline TupleTableSlot *  ExecProcNode(PlanState *node)  {      if(node->chgParam !=NULL/* something changed? */          ExecReScan(node);       /* let ReScan handle this */        returnnode->ExecProcNode(node);  }#endif

2、ExecProcNodeFirst

/*  * ExecProcNode wrapper that performs some one-time checks, before calling  * the relevant node method (possibly via an instrumentation wrapper).  */ /* 输入:     node-PlanState指针 输出:     存储Tuple的Slot */ staticTupleTableSlot * ExecProcNodeFirst(PlanState *node) {/*      * Perform stack depth check during the first execution of the node.  We      * only do so the first time round because it turns out to not be cheap on      * some common architectures (eg. x86).  This relies on the assumption      * that ExecProcNode calls for a given plan node will always be made at      * roughly the same stack depth.      */     //检查Stack是否超深     check_stack_depth();     /*      * If instrumentation is required, change the wrapper to one that just      * does instrumentation.  Otherwise we can dispense with all wrappers and      * have ExecProcNode() directly call the relevant function from now on.      */     //如果instrument(TODO)     if(node->instrument)         node->ExecProcNode = ExecProcNodeInstr;elsenode->ExecProcNode = node->ExecProcNodeReal;//执行该Node的处理过程     return node->ExecProcNode(node); }三、跟踪分析

插入测试数据:

testdb=# -- 获取pid testdb=# select pg_backend_pid();  pg_backend_pid  ----------------            2835 (1row) testdb=#-- 插入1行 testdb=# insert into t_insert values(14,ExecProcNodeFirst,ExecProcNodeFirst,ExecProcNodeFirst); (挂起)

启动gdb分析:

[root@localhost ~]# gdb -p 2835 GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-100.el7 Copyright (C) 2013 Free Software Foundation, Inc. ... (gdb) b ExecProcNodeFirst Breakpoint 1 at 0x69a797: file execProcnode.c, line 433. (gdb) c Continuing. Breakpoint 1, ExecProcNodeFirst (node=0x2cca790) at execProcnode.c:433 433     check_stack_depth(); #查看输入参数 (gdb) p *node $1 = {type = T_ModifyTableState, plan = 0x2c1d028, state = 0x2cca440, ExecProcNode = 0x69a78b <ExecProcNodeFirst>, ExecProcNodeReal = 0x6c2485 <ExecModifyTable>, instrument = 0x0,    worker_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2ccb6a0, ps_ExprContext = 0x0, ps_ProjInfo = 0x0,    scandesc = 0x0} #ExecProcNode 实际对应的函数是ExecProcNodeFirst #ExecProcNodeReal 实际对应的函数是ExecModifyTable(上一章节已粗略解析) (gdb) next 440     if (node->instrument) (gdb)  #实际调用ExecModifyTable函数(这个函数由更高层的调用函数植入) 443         node->ExecProcNode = node->ExecProcNodeReal; (gdb)  445     return node->ExecProcNode(node); (gdb) next #第二次调用(TODO) Breakpoint 1, ExecProcNodeFirst (node=0x2ccac80) at execProcnode.c:433 433     check_stack_depth(); (gdb) next 440     if (node->instrument) (gdb) next 443         node->ExecProcNode = node->ExecProcNodeReal; (gdb) next 445     return node->ExecProcNode(node); (gdb) next 446 } (gdb) next ExecProcNode (node=0x2ccac80) at ../../../src/include/executor/executor.h:238 238 } #第二次调用的参数 (gdb) p *node $2 = {type = T_ResultState, plan = 0x2cd0488, state = 0x2cca440, ExecProcNode = 0x6c5094 <ExecResult>, ExecProcNodeReal = 0x6c5094 <ExecResult>, instrument = 0x0, worker_instrument = 0x0, qual = 0x0,    lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x2ccad90, ps_ExprContext = 0x2ccab30, ps_ProjInfo = 0x2ccabc0, scandesc = 0x0} #ExecProcNode对应的实际函数是ExecResult (gdb)

感谢各位的阅读,以上就是“PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么”的内容了,经过本文的学习后,相信大家对PostgreSQL中ExecProcNode和ExecProcNodeFirst函数的实现逻辑是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:vuejs移动端ui框架(vue移动端ui框架哪个好)
下一篇:Oracle如何实现手工建库
相关文章