pgpool-II3.1 的begin transaction 和 自动追加 BEGIN/COMMIT问题-阿里云开发者社区

开发者社区> 嗯哼9925> 正文

pgpool-II3.1 的begin transaction 和 自动追加 BEGIN/COMMIT问题

简介:
+关注继续查看
pgpool-II3.1 里面,有一些比较奇怪的做法,至少目前在我看来,是画蛇添足。

如果你没有声明 begin transaction 和 end/commit/rollback 。
当你执行一个SQL文的时候,如果事前没有 begin transaction 之类的,

它会在你所执行的单一的 update/insert/delete SQL 执行前,后,分别追加 BEGIN 和COMMIT。

虽然我认为这个追加是没有必要的,只要交给后台数据库就好了,但是还是先来探讨一下其实现机理。

具体是如何实现的呢。看代码:

复制代码
start_internal_transaction 函数
/* 
* Start an internal transaction if necessary.  
*/ 
POOL_STATUS start_internal_transaction(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, Node *node)
  int i;
 
  /* If we are not in a transaction block, 
   * start a new transaction
   */
  if (is_internal_transaction_needed(node)){
     for (i=0;i<NUM_BACKENDS;i++){
          if (VALID_BACKEND(i) &&
                !INTERNAL_TRANSACTION_STARTED(backend, i) &&
                     TSTATE(backend, i) == 'I'   )
          {
              per_node_statement_log(backend, i, "BEGIN");
 
              if (do_command(frontend, CONNECTION(backend, i), "BEGIN", 
                   MAJOR(backend),
                   MASTER_CONNECTION(backend)->pid,
                   MASTER_CONNECTION(backend)->key, 0) != POOL_CONTINUE)
                        return POOL_END;  
 
              /* Mark that we started new transaction */  
              INTERNAL_TRANSACTION_STARTED(backend, i) = true;   
              pool_unset_writing_transaction();  
           }  
      }  
   }  
   return POOL_CONTINUE;   
 
end_internal_transaction 函数 
/* 
* End internal transaction.  
*/ 
POOL_STATUS end_internal_transaction(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend) 
{     
   ……    
   /* We need to commit from secondary to master. */              
   for (i=0;i<NUM_BACKENDS;i++){   
     if (VALID_BACKEND(i) && !IS_MASTER_NODE_ID(i) &&        
          TSTATE(backend, i) != 'I' &&             
          INTERNAL_TRANSACTION_STARTED(backend, i))  
     {     
         …… 
         per_node_statement_log(backend, i, "COMMIT");
 
         /* COMMIT success? */   
         if (do_command(frontend, CONNECTION(backend, i), "COMMIT", 
               MAJOR(backend),  
               MASTER_CONNECTION(backend)->pid,MASTER_CONNECTION(backend)->key, 1)                 != POOL_CONTINUE)
         {    
            INTERNAL_TRANSACTION_STARTED(backend, i) = false;   
            POOL_SETMASK(&oldmask);      
            return POOL_END;     
         }  
         INTERNAL_TRANSACTION_STARTED(backend, i) = false;    
      }   
   }  
 
   /* Commit on master */   
   if (TSTATE(backend, MASTER_NODE_ID) != 'I' &&   
         INTERNAL_TRANSACTION_STARTED(backend, MASTER_NODE_ID))  
   {   
      ……  
      per_node_statement_log(backend, MASTER_NODE_ID, "COMMIT");  
      if (do_command(frontend, MASTER(backend), "COMMIT", MAJOR(backend),
           MASTER_CONNECTION(backend)->pid,MASTER_CONNECTION(backend)->key, 1) != 
             POOL_CONTINUE)   
      {   
         INTERNAL_TRANSACTION_STARTED(backend, MASTER_NODE_ID) = false;
         POOL_SETMASK(&oldmask);  
         return POOL_END; 
      }
      INTERNAL_TRANSACTION_STARTED(backend, MASTER_NODE_ID) = false; 
    }
    POOL_SETMASK(&oldmask); 
    return POOL_CONTINUE;   
}  
复制代码
其中所使用的 is_internal_transaction_needed 函数,其篇幅比较长,代码省略。
其主要做法,就是把 delete/insert/update 之类的关键字放到一个list中,然后用二分法查找。
如果命中,就认为 internal_transaction_needded。

从更高的层次看,有如下的调用关系:

pool_process_query  →  ProcessFrontEndResponse  和 ProcessBackendResponse

ProcessFrontEndResponse → 
      SimpleQuery → start_internal_transaction  → is_internal_transaction_needed

ProcessBackendResponse → 
      ReadyForQuery →end_internal_transaction

需要注意,在 start_internal_transaction 中追加 BEGIN需要以下几个条件:

       i)  Interal transaction 被认定是必须的 

   ii) INTERNAL_TRANSACTION_STARTED 标志位被置位

       iii) 各DB节点的TSTATE 状态是初始状态 I

而在 end_internal_transaction 中追加 COMMIT需要以下几个条件:

     i) Interal transaction 被认定是必须的

       ii) INTERNAl_TRANSACTION_STARTED标志位被置位

       iii) 各DB节点的TSTATE 状态时初始状态 I

普通的单一SQL文执行的时候,上述的条件均可得到满足。

但是,像begein transaction 这样的语句,一旦执行,会改变DB节点的 TSTATE状态为 T。

这样,即使后面再有 单一SQL文被执行,也没有可能满足上面的条件了。

直到遇到了 begin-transaction--commit/rollback  的 commit/rollback , TSTATE状态恢复为I 。

 

换句话说,其实pgpool-II中,根本就没有对 begin transaction 语句的识别部分的代码!诡异!


本文转自健哥的数据花园博客园博客,原文链接:http://www.cnblogs.com/gaojian/archive/2012/08/29/2661439.html,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
AutoCompleteTextView 自动提示
在输入框中输入我们想要输入的信息就会出现其他与其相关的提示信息,这种效果在Android中是用AutoCompleteTextView实现的。   public class MainActivity extends Activity { private AutoCompleteText...
650 0
**使用 Git Hook 实现网站的自动部署
http://www.tuicool.com/articles/3QRB7jU 自动化能解放人类的双手,而且更重要的是,因为按照规定的流程来走,也减少了很多误操作的产生。不知道大家平时都是怎么样更新自己生产环境的代码的,FTP 覆盖旧文件、服务器定时任务去 build 最新的源码,还是有更高级的做法? 目前我在使用 Git Hook 来部署自己的项目。
1012 0
GitHub Actions 的机器学习推理上线,推进测试部署高度自动化
在看到最近新推出的 GitHub Actions 后,我的第一个想法是创建一个简单的示例项目,在这个项目中,我们“部署”一个使用了这个新特性的机器学习模型。当然,这不是一个“真正的部署”,但是可用此模型在存储库中测试你的模型,而不需要任何额外的编码。
495 0
解决UnicodeEncodeError: &#39;ascii&#39; codec can&#39;t encode characters in position 问题(转)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 8-11: ordinal not in range(128) 解决UnicodeEncodeError: 'ascii' codec can't encode characters in position 转自:http://cooler1217.
1083 0
duilib combo控件,当鼠标滚动时下拉列表自动关闭的bug的修复
转载请说明出处,谢谢~~       群里有朋友提到了使用Combo控件时,当下拉列表出现,此时鼠标滚轮滚动,下拉列表就自动消失了。我看了一下源码,这个bug的修复很简单。
1157 0
关于spoolsv.exe 报错,并打印服务停止的问题
都说是打印机驱动任务啥的,其实应该是控件和PDF打印机导致的,最多算上一个不正常的其他打印机导致的,所以除常规方法外,还需要干掉不用的所有打印机,只保留正常的那几个,虚拟打印机好像常常会搞出一些莫名其妙的问题来。
796 0
+关注
4716
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载