• pgpoolII3.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 语句的识别部分的代码!诡异!

  • 相关阅读:
    循环语句
    流程控制
    特殊的赋值运算符
    位运算符
    运算符
    八种基本类型
    cmd基础命令
    springboot项目部署到tomcat步骤以及常见问题
    【算法问题】如何实现大整数相加
    【算法问题】删除k个数字后的最小值
  • 原文地址:https://www.cnblogs.com/gaojian/p/2661439.html
Copyright © 2020-2023  润新知