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,如需转载请自行联系原作者
目录
相关文章
|
存储 Linux 数据安全/隐私保护
【CentOS 7】深入指南:使用LVM和扩展文件系统增加root分区存储容量
通过上述步骤,您可以在 CentOS 7 系统中使用 LVM 和扩展文件系统来增加 root 分区的存储容量。这种方法不仅灵活,还能在不中断系统运行的情况下扩展存储空间,非常适合生产环境。请确保在操作前备份重要数据,并仔细执行每一步骤,以确保系统稳定和数据安全。
977 6
|
9月前
|
机器学习/深度学习 人工智能 数据可视化
1.4K star!几分钟搞定AI视频创作,这个开源神器让故事可视化如此简单!
story-flicks 是一个基于AI技术的自动化视频生成工具,能够将文字剧本快速转化为高质量短视频。开发者@alecm20通过深度学习算法,实现了从文本解析到视频合成的全流程自动化处理,支持多平台适配输出,是内容创作者和自媒体运营者的效率神器。
461 0
|
弹性计算 缓存 安全
阿里云服务器ECS收费标准参考,2核4G配置ECS实例规格整理
阿里云提供多种2核4G ECS实例,如计算型c7、经济型e、u1等,价格不等,从68.0元/月到203.0元/月。ECS通用算力型u1实例采用高性能Intel处理器,网络收发包能力达30万PPS。经济型e实例基于Intel Xeon Platinum,适合入门级需求。2核4G服务器支持的并发访问人数依赖于软件效率、带宽、应用架构和用户行为等因素。更多信息请查看阿里云ECS产品页。
597 1
|
负载均衡 安全 API
小红书商品详情API接口获取步骤
获取小红书商品详情API接口需先注册账号并实名认证,阅读API文档后,通过编程语言调用API,构建请求参数,处理返回数据。确保应用支持高并发,遵守安全规范,申请API权限,查阅接口文档,进行开发调试。
|
人工智能 运维 安全
科技云报到:数字化转型,从不确定性到确定性的关键路径
科技云报到:数字化转型,从不确定性到确定性的关键路径
186 6
|
监控 安全 UED
星型拓扑的缺点是什么?
【8月更文挑战第4天】
1192 16
星型拓扑的缺点是什么?
|
机器学习/深度学习 算法 数据处理
label的作用是什么?是怎么用的?
label的作用是什么?是怎么用的?
650 0
|
机器学习/深度学习 编解码 人工智能
视频生成新玩家:Sora 原理探索与效果对比
视频生成新玩家:Sora 原理探索与效果对比
426 0
视频生成新玩家:Sora 原理探索与效果对比
|
应用服务中间件
weblogic配置、修改日志保存目录、配置滚动日志
weblogic配置、修改日志保存目录、配置滚动日志
1156 0
|
测试技术
谷歌DeepMind全新ToT基准:全面评估LLM时间推理能力
【7月更文挑战第10天】DeepMind的ToT基准测试了大型语言模型的时间推理能力,分为ToT-Semantic(合成数据,评估时间逻辑理解)和ToT-Arithmetic(真实数据,检查时间计算)。研究使用Claude-3-Sonnet、GPT-4和Gemini 1.5 Pro进行评估,发现模型在时间逻辑理解上表现各异,而时间计算上均较强。 Gemini 1.5 Pro在复杂问题上表现出色,而GPT-4在数学相关问题上较弱。[[1](https://arxiv.org/pdf/2406.09170)]
302 1