[pgpool-general-jp: 158] Re: pgpoolでのupdateについて

Yoshiyuki Asaba y-asaba @ sraoss.co.jp
2007年 6月 4日 (月) 15:28:46 JST


浅羽です。

From: "Mizuno Shinya" <098.mizuno.shinya @ gmail.com>
Subject: [pgpool-general-jp: 157] Re: pgpoolでのupdateについて
Date: Mon, 4 Jun 2007 12:36:33 +0900

> replication_strict=true にすれば、「常にsecondaryはmasterの
> 問い合わせ処理が終わってから、問い合わせを処理する」とのこと
> ですが、以下のようにはならないのでしょうか。
> 
>   ----MASTER----  ---SECONDARY---
>   transA  transB  transA  transB
> 
>   update
>           update
>                           update
>                   update

水野さんのおっしゃる通り、可能性としては起こり得ます。
ということで、以下の方法で pgpool を修正する予定です。

  1. SELECT や内部で発行する RESET 等以外は BEGIN で囲む
  2. マスタ以外からコミットし、最後にマスタをコミットさせる
    - マスタ以外からコミットさせないと、同じことが起こる

ただ、1. については CREATE DATABASE など、トランザクション中では実行で
きないクエリがあるので、SQL パーサを持たない pgpool-I ではちょっとメン
ドウなところではあります。pgpool-II 用のパッチを添付します。

なお、上記修正を発展させると、pgpool-II のレプリケーションが高速化でき
るのでは、と考えております。現在の pgpool-II の仕組みではノード数 N に
対して、更新系のクエリが N 倍かかってしまいます。上記を実装することで
マスタ以外は並列にクエリを投げることができるのではないかと推測していま
す。

これによりノード数が増えても 2 倍程度の時間に縮めることができます(たぶ
ん)。

--
Yoshiyuki Asaba
y-asaba @ sraoss.co.jp
-------------- next part --------------
Index: pool_process_query.c
===================================================================
RCS file: /cvsroot/pgpool/pgpool-II/pool_process_query.c,v
retrieving revision 1.19
diff -c -r1.19 pool_process_query.c
*** pool_process_query.c	2 Jun 2007 00:54:40 -0000	1.19
--- pool_process_query.c	4 Jun 2007 06:20:42 -0000
***************
*** 179,184 ****
--- 179,187 ----
  static POOL_MEMORY_POOL *prepare_memory_context = NULL;
  
  static void query_cache_register(char kind, POOL_CONNECTION *frontend, char *database, char *data, int data_len);
+ static POOL_STATUS start_internal_transaction(POOL_CONNECTION_POOL *backend, Node *node);
+ static POOL_STATUS end_internal_transaction(POOL_CONNECTION_POOL *backend);
+ 
  
  POOL_STATUS pool_process_query(POOL_CONNECTION *frontend, 
  							   POOL_CONNECTION_POOL *backend,
***************
*** 1003,1008 ****
--- 1006,1016 ----
  				return status;
  			}
  		}
+ 		else if (REPLICATION && query == NULL && start_internal_transaction(backend, node))
+ 		{
+ 			free_parser();
+ 			return POOL_ERROR;
+ 		}
  	}
  
  	free_parser();
***************
*** 1253,1270 ****
  		/* set transaction state */
  		pool_debug("ReadyForQuery: transaction state: %c", state);
  
! 		for (i=0;i<NUM_BACKENDS;i++)
! 		{
! 			if (!VALID_BACKEND(i))
! 				continue;
! 
! 			CONNECTION(backend, i)->tstate = state;
! 
! 			if (do_command(CONNECTION(backend, i), "COMMIT", PROTO_MAJOR_V3, 1) != POOL_CONTINUE)
! 				return POOL_ERROR;
! 		}
! 
! 		internal_transaction_started = 0;
  	}
  
  	pool_flush(frontend);
--- 1261,1268 ----
  		/* set transaction state */
  		pool_debug("ReadyForQuery: transaction state: %c", state);
  
! 		if (end_internal_transaction(backend) != POOL_CONTINUE)
! 			return POOL_ERROR;
  	}
  
  	pool_flush(frontend);
***************
*** 4020,4042 ****
  
  	snprintf(qbuf, sizeof(qbuf), "LOCK TABLE %s IN SHARE ROW EXCLUSIVE MODE", table);
  
! 	/* if we are not in a transaction block,
! 	 * start a new transaction
! 	 */
! 	if (TSTATE(backend) == 'I')
! 	{
! 		for (i=0;i<NUM_BACKENDS;i++)
! 		{
! 			if (VALID_BACKEND(i))
! 			{
! 				if (do_command(CONNECTION(backend, i), "BEGIN", PROTO_MAJOR_V3, 0) != POOL_CONTINUE)
! 					return POOL_END;
! 			}
! 		}
! 
! 		/* mark that we started new transaction */
! 		internal_transaction_started = 1;
! 	}
  
  	status = POOL_CONTINUE;
  
--- 4018,4025 ----
  
  	snprintf(qbuf, sizeof(qbuf), "LOCK TABLE %s IN SHARE ROW EXCLUSIVE MODE", table);
  
! 	if (start_internal_transaction(backend, (Node *)node) != POOL_CONTINUE)
! 		return POOL_END;
  
  	status = POOL_CONTINUE;
  
***************
*** 4530,4532 ****
--- 4513,4576 ----
  
  	set_ps_display(psbuf, false);
  }
+ 
+ static POOL_STATUS start_internal_transaction(POOL_CONNECTION_POOL *backend, Node *node)
+ {
+ 	int i;
+ 
+ 	/* if we are not in a transaction block,
+ 	 * start a new transaction
+ 	 */
+ 	if (TSTATE(backend) == 'I' &&
+ 		!IsA(node, CreatedbStmt) && !IsA(node, VacuumStmt) && !IsA(node, DropdbStmt))
+ 	{
+ 		for (i=0;i<NUM_BACKENDS;i++)
+ 		{
+ 			if (VALID_BACKEND(i))
+ 			{
+ 				if (do_command(CONNECTION(backend, i), "BEGIN", PROTO_MAJOR_V3, 0) != POOL_CONTINUE)
+ 					return POOL_END;
+ 			}
+ 		}
+ 
+ 		/* mark that we started new transaction */
+ 		internal_transaction_started = 1;
+ 	}
+ 	return POOL_CONTINUE;
+ }
+ 
+ 
+ static POOL_STATUS end_internal_transaction(POOL_CONNECTION_POOL *backend)
+ {
+ 	int i;
+ 
+ 	/* We need to commit from secondary to master. */
+ 	for (i=0;i<NUM_BACKENDS;i++)
+ 	{
+ 		if (VALID_BACKEND(i) && !IS_MASTER_NODE_ID(i))
+ 		{
+ 			if (do_command(CONNECTION(backend, i), "COMMIT", PROTO_MAJOR_V3, 1) != POOL_CONTINUE)
+ 			{
+ 				internal_transaction_started = 0;
+ 				return POOL_END;
+ 			}
+ 		}
+ 	}
+ 
+ 	/* commit on master */
+ 	for (i=0;i<NUM_BACKENDS;i++)
+ 	{
+ 		if (VALID_BACKEND(i) && IS_MASTER_NODE_ID(i))
+ 		{
+ 			if (do_command(CONNECTION(backend, i), "COMMIT", PROTO_MAJOR_V3, 1) != POOL_CONTINUE)
+ 			{
+ 				internal_transaction_started = 0;
+ 				return POOL_END;
+ 			}
+ 			break;
+ 		}
+ 	}
+ 
+ 	internal_transaction_started = 0;
+ 	return POOL_CONTINUE;	
+ }


pgpool-general-jp メーリングリストの案内