[pgpool-general-jp: 422] pgpool 3.4.1のdo_error_commandについて

Kenichi Sawada k @ sawada.cc
2008年 3月 19日 (水) 10:54:56 JST


お世話になります。
澤田と申します。

pgpool-3.4.1を以下の条件にて使用していた際、
エラーとなるようなクエリを投げた際にプロセスがハングアップすることがあり、
現象を確認してみたところ、

1. replicate_select = false
2. トランザクション内にて、extended modeでMASTERにselectを投げ、errorが返る
3. pgpoolのdo_error_commandにて、SECONDARY側にエラーとなるquery
   "send invalid query from pgpool to abort transaction": 通常モード)が
   投げられる
4. そのあとMASTERとSECONDARYにSyncが投げられる
5. このとき、SECONDARY側から返答が発生するものの、MASTERから返答がない
6. pool_process_query.cのsynchronous pointにおけるpool_readにて
   MASTERからの返答待ちで永久にブロックされる

という状況のようです。そこで、拡張問い合わせの際にはSECONDARYにSyncを
投げないようにするパッチを適用してみたところ、手元ではうまく動作している
ようですが、いかがなものでしょうか。ご意見頂ければ幸いです。

どうぞ宜しくお願い致します。

--澤田 研一
--k @ sawada.cc
-------------- next part --------------
*** pool_process_query.c	2007-08-29 14:44:50.000000000 +0900
--- pool_process_query.c.new	2008-03-19 10:47:14.000000000 +0900
***************
*** 159,164 ****
--- 159,165 ----
  static int internal_transaction_started;		/* to issue table lock command a transaction
  												   has been started internally */
  static int select_in_transaction = 0; /* non 0 if select query is in transaction */
+ static int extended_select = 0; /* non 0 if extended mode */
  static void (*pending_function)(PreparedStatementList *p, PreparedStatement *statement) = NULL;
  static PreparedStatement *pending_prepared_stmt = NULL;
  
***************
*** 725,730 ****
--- 726,732 ----
  		REPLICATION = 0;
  		in_load_balance = 1;
  		select_in_transaction = 1;
+ 		extended_select = 0;
  	}
  
  	/*
***************
*** 879,884 ****
--- 881,887 ----
  			REPLICATION = 0;
  			in_load_balance = 1;
  			select_in_transaction = 1;
+ 			extended_select = 1;
  		}
  	}
  
***************
*** 2731,2738 ****
  		pending_function(&prepared_list, pending_prepared_stmt);
  	}
  	else if (kind == 'C' && select_in_transaction)
  		select_in_transaction = 0;
! 
  	/* 
  	 * Remove a pending function if a received message is not
  	 * NoticeResponse.
--- 2734,2743 ----
  		pending_function(&prepared_list, pending_prepared_stmt);
  	}
  	else if (kind == 'C' && select_in_transaction)
+ 	{
  		select_in_transaction = 0;
! 		extended_select = 0;
! 	}
  	/* 
  	 * Remove a pending function if a received message is not
  	 * NoticeResponse.
***************
*** 2798,2803 ****
--- 2803,2809 ----
  	{
  		int i, k;
  		int res1, res2;
+ 		int sync_secondary = 1;
  		char *p1;
  
  		/*
***************
*** 2835,2840 ****
--- 2841,2851 ----
  				do_error_command(SECONDARY(backend), PROTO_MAJOR_V3);
  			}
  			select_in_transaction = 0;
+ 			if (extended_select)
+ 			{
+ 				sync_secondary = 0;
+ 				extended_select = 0;
+ 			}
  		}
  
  		for (i = 0;i < backend->num;i++)
***************
*** 2847,2852 ****
--- 2858,2877 ----
  			 * it by itself. Moreover we do not need it in non-extend mode.
  			 * At this point we regard it is not harmfull since error resonse
  			 * will not be sent too frequently.
+ 			  
+ 			 * We observed a process stall at the synchronous 
+ 			 * point (Line 370 of this code) in this situation:
+ 			 * 1. replicate_select = false
+ 			 * 2. do extended select for MASTER, and get some error
+ 			 * 3. do_error_command for SECONDARY,
+ 			 * 4. send Sync to both MASTER and SECONDARY
+ 			 * 5. SECONDARY returns something but MASTER doesn't.
+ 			 * 6. then pgpool stalls at pool_read on #370 to wait
+ 			 *    for a response from MASTER.
+ 			 *
+ 			 * To avoid this situation, we introduced a variable
+ 			 * 'extended_select' so that pgpool sends Sync only to 
+ 			 * MASTER when the query is in extended mode.
  			 */
  			pool_write(cp, "S", 1);
  			res1 = htonl(4);
***************
*** 2855,2861 ****
  				return POOL_END;
  			}
  
! 			if (!REPLICATION)
  				break;
  		}
  
--- 2880,2886 ----
  				return POOL_END;
  			}
  
! 			if (!REPLICATION || sync_secondary == 0)
  				break;
  		}
  


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