+2005-06-25 <t-ishii@sra.co.jp>
+ * version 2.6
+ * fix memory leak in pool_error()
+ * allow replication between servers which have different time zone
+ etc.
+ * fix bug in pgpool -m f stop if pgpool stop has already issued
+ but pgpool cannot stop.
+ * add new "insert_lock" directive which automatically insert table
+ locks to allow SERIAL data type replication
+ * allow new "/*NO STRICT*/ comment to turn off the strict mode
+ temporary
+ * add a row to pool_staus to display server status
+
2005-03-12 <t-ishii@sra.co.jp>
* version 2.5.2
* fix bug in health checking
+2.6(kala) 2005/06/25
+
+ o pool_error etc.¤Ç¡¤asprintf¤Î¸å¤Çfree¤·¤Æ¤¤¤Ê¤«¤Ã¤¿¤Î¤ò½¤Àµ¡¥
+
+ o main.c¤Ç¡¤malloc¤Î¥µ¥¤¥º¤¬¸í¤Ã¤Æpool_config.num_init_children
+ * sizeof(pool_config.num_init_children)¤Ë¤Ê¤Ã¤Æ¤¤¤¿¤Î¤ò
+ pool_config.num_init_children * sizeof(pid_t)¤Ë½¤Àµ¡¥
+
+ o parameter status¤ÎÃͤ¬°ìÃפ·¤Æ¤¤¤Ê¤¯¤Æ¤â¥¨¥é¡¼¤Ë¤Ê¤é¤Ê¤¤¤è¤¦¤Ë
+ ¤·¤¿(US¤ÈNZ¤Ç¥ì¥×¥ê¥±¡¼¥·¥ç¥ó¤·¤Æ¤¤¤ëÎ㤬¤¢¤Ã¤¿¡ª)¡¥
+
+ o pgpool stop¤Ç½ªÎ»¤»¤º¡¤°ìökill¤µ¤ì¤¿¸å¡¤pgpool -m f stop¤ò¼õ
+ ¤±ÉÕ¤±¤Ê¤¯¤Ê¤ë¥Ð¥°¤ò½¤Àµ¡¥
+
+ o ¿·¤·¤¤¥Ç¥£¥ì¥¯¥Æ¥£¥Öinsert_lock¤òÄɲá¥true¤Î¾ì¹ç¡¤INSERT¼Â¹Ô
+ »þ¤Ë¼«Æ°Åª¤Ë¥Æ¡¼¥Ö¥ë¥í¥Ã¥¯¤ò¹Ô¤¦¡¥¤³¤ì¤Ë¤è¤ê¡¤SERIAL·¿¤ò´Þ¤à¥Æ¡¼
+ ¥Ö¥ë¤ÎƱ´ü¤ò¼è¤ë¤³¤È¤¬¤Ç¤¤ë¡¥
+ ¤Ê¤ª¡¤/*NO INSERT LOCK*/¥³¥á¥ó¥È¤òÉÕ¤±¤ë¤È¡¤¤½¤ÎINSERTʸ¤Î¤ß
+ ¥Æ¡¼¥Ö¥ë¥í¥Ã¥¯¤ò¹Ô¤ï¤Ê¤¤¡¥
+ ¤¢¤ë¤¤¤Ïinsert_lock¤¬false¤Ç¤â/*INSERT LOCK*/¥³¥á¥ó¥È¤òÉÕ¤±¤ë
+ ¤È¥Æ¡¼¥Ö¥ë¥í¥Ã¥¯¤ò¹Ô¤¦¡¥
+
+ o 2.5.2¤ÇÄɲ䵤줿¡Östrict¥â¡¼¥É¤Ç¤¢¤Ã¤Æ¤â¡¤SELECT¤À¤Ã¤¿¤ésecondary¤Î´°Î»¤òÂÔ¤¿¤Ê
+ ¤¤¡×»ÅÍͤò¼è¤ê¤ä¤á¡¥Âå¤ê¤Ë¡¤/*NO STRICT*/¥³¥á¥ó¥È¤òÄɲá¥
+
+ o show pool_status¤Ë¿·¤·¤¤¾ðÊó¤òÄɲ᥽ÌÂà¤ä¥Õ¥§¥¤¥ë¥ª¡¼¥Ð¾õ¶·¤ò
+ ʬ¤«¤ê¤ä¤¹¤¯É½¼¨¤¹¤ë¤è¤¦¤Ë¤·¤¿¡¥
+ server_status| master( on 5432) up secondary( on 5433) down| server status
+
2.5.2(kaku) 2005/3/12(Sat)
- o 2.5.1¤Ëenbug¤ò½¤Àµ¡¥health check¤¬¼ÂºÝ¤Ë¤Ï¤µ¤ì¤Æ¤¤¤Ê¤¤¥±¡¼¥¹¤¬
+ o 2.5.1¤Ç¤Îenbug¤ò½¤Àµ¡¥health check¤¬¼ÂºÝ¤Ë¤Ï¤µ¤ì¤Æ¤¤¤Ê¤¤¥±¡¼¥¹¤¬
¤¢¤Ã¤¿¤Î¤ò½¤Àµ¡¥¥±¡¼¥Ö¥ëÈ´¤±¤Ê¤É¤ò¥¿¥¤¥à¥¢¥¦¥È¤Ç¸¡½Ð¤¹¤ë¤Î¤ÏOK
¤À¤¬¡¤Ä¾¤Á¤Ë¥¨¥é¡¼¤Ë¤Ê¤ë¥±¡¼¥¹¤ò¸¡½Ð¤Ç¤¤Æ¤¤¤Ê¤«¤Ã¤¿¡¥
2.0(heemauli) 2004/06/22(Tue)
V3¥×¥í¥È¥³¥ë¤ËnativeÂбþ¤·¤¿¡¥
- Éé²Ùʬ»¶¤Ç¤¤ë¤è¤¦¤Ë¤Ê¤Ã¤¿
+ Éé²Ùʬ»¶(load balance)¤Ç¤¤ë¤è¤¦¤Ë¤Ê¤Ã¤¿
¥Ç¡¼¥¿¤ÎÉÔ°ìÃ×»þ¤Ë¶¯À©½ÌÂ౿ž¤¹¤ë¤«¤É¤¦¤«ÁªÂò¤Ç¤¤ë¤è¤¦¤Ë¤Ê¤Ã¤¿
1.2.3((hapuupuu) 2004/05/16(Sun)
$Header$
-pgpool version 2.5(kaku) README
+pgpool version 2.6(kala) README
1. What is pgpool
two servers. This is because qury results for these are local to
each PostgreSQL server.
+ If you want to use SERIAL data type, "insert_lock" might help
+ you. See "insert_lock" in "6. Setting up pgpool.conf" for more
+ details.
+
When one of PostgreSQL server goes down, pgpool tries to continue
serverce with live server. This is called "degeneration mode".
When you want to come back to the replication mode, please make
currently following protocols are not supported:
o any authentication methods except "trust", "clear text password"
- (replication mode)
+ (replication or master/slave mode)
o any authentication methods except "trust", "clear text password",
"crypt", "md5" (non replication mode)
PostgreSQL user name for the health checking.
+ insert_lock
+
+ If you replicate a table having SERIAL data type column, sometimes
+ the serial value does not match between servers. You can avoid the
+ problem by using a table lock (with a performance penalty due to
+ less currency in transactions). For this you need to rewrite you
+ query:
+
+ INSERT INTO ....
+
+ to:
+
+ BEGIN;
+ LOCK TABLE ...
+ INSERT INTO ...
+ COMMIT;
+
+ This is painfull. If you turn on insert_lock, pgpool will
+ automatically do the rewriting for you.
+
+ Beaware that pgpool is not smart enough that to do the rewriting
+ only for tables having SERIAL column. To avoid the problem try one
+ of these:
+
+ 1) set insert_lock to true and add a /*NO INSERT LOCK*/ comment at
+ the beginning of the query. This will prevent the rewriting.
+
+ 2) set insert_lock to false and add a /*INSERT LOCK*/ comment at
+ the beginning of the query. This will do the rewriting for the
+ query only.
+
+ The default value for insert_lock is false.
+
+ Note that turning on insert_lock will make some of the regression
+ test fail. As of PostgreSQL 8.0, transactions, privileges, rules,
+ alter_table fail. The reason of the failure is table locking for
+ views in rule test, and for others erroneous queries abort the
+ transaction *before* pgpool issues the table lock statement.
+
7. Starting pgpool
The simplist way to start pgpool is:
item | value | description
------------------------------+------------------------------------------------------+------------------------------------------------------------------------
listen_addresses | * | host name(s) or IP address(es) to listen to
- port | 9999 | pgpool accepting port number
+ port | 9998 | pgpool accepting port number
socket_dir | /tmp | pgpool socket directory
backend_host_name | | master backend host name
backend_port | 5432 | master backend port number
secondary_backend_host_name | | secondary backend host name
- secondary_backend_port | 0 | secondary backend port number
- num_init_children | 1 | # of children initially pre-forked
- child_life_time | 300 | if idle for this seconds, child exits
+ secondary_backend_port | 5433 | secondary backend port number
+ num_init_children | 32 | # of children initially pre-forked
+ child_life_time | 0 | if idle for this seconds, child exits
connection_life_time | 0 | if idle for this seconds, connection closes
- max_pool | 4 | max # of connection pool per child
+ max_pool | 2 | max # of connection pool per child
logdir | /tmp | logging directory
backend_socket_dir | /tmp | Unix domain socket directory for the PostgreSQL server
- replication_mode | 0 | non 0 if operating in replication mode
+ replication_mode | 1 | non 0 if operating in replication mode
replication_strict | 1 | non 0 if operating in strict mode
replication_timeout | 5000 | if secondary does not respond in this milli seconds, abort the session
load_balance_mode | 0 | non 0 if operating in load balancing mode
print_timestamp | 1 | if true print time stamp to each log line
master_slave_mode | 0 | if true, operate in master/slave mode
connection_cache | 1 | if true, cache connection pool
- health_check_timeout | 20 | health check timeout
+ health_check_timeout | 5 | health check timeout
health_check_period | 0 | health check period
+ health_check_user | t-ishii | health check user
+ insert_lock | 1 | insert lock
current_backend_host_name | | current master host name
current_backend_port | 5432 | current master port #
- replication_enabled | 0 | non 0 if actually operating in replication mode
+ replication_enabled | 1 | non 0 if actually operating in replication mode
master_slave_enabled | 0 | non 0 if actually operating in master/slave
num_reset_queries | 3 | number of queries in reset_query_list
-(31 rows)
+ server_status | master( on 5432) up secondary( on 5433) up | server status
+(34 rows)
12. Playing with regression test
- not in a transaction block
2) in all other case, quries are sent to only master
-
$Header$
-pgpool version 2.5(kaku) README
+pgpool version 2.6(kala) README
1. pgpool¤È¤Ï
¥ó¤Ï¤·¤Þ¤¹¤¬¡¤2Âæ¤Î¥Û¥¹¥È¤Ç¤Þ¤Ã¤¿¤¯Æ±¤¸Ãͤ¬¥³¥Ô¡¼¤µ¤ì¤ëÊݾڤϤ¢¤ê¤Þ
¤»¤ó¡¥
+ ¤¿¤À¤·¡¤SERIAL·¿¤Ë¤Ä¤¤¤Æ¤Ï¡¤¸å½Ò¤Î"insert_lock"¤ò»È¤¦¤³¤È¤Ë¤è¤Ã¤ÆÂÐ
+ ±þ²Äǽ¤Ç¤¹¡¥¾ÜºÙ¤Ï¡Ö6. pgpool¤ÎÀßÄêÊýË¡¡×¤Îinsert_lock¤Î¹à¤ò»²¾È¤·
+ ¤Æ¤¯¤À¤µ¤¤¡¥
+
¥ì¥×¥ê¥±¡¼¥·¥ç¥óÃæ¤Ë¾ã³²¤¬È¯À¸¤¹¤ë¤È¡¤¼«Æ°Åª¤Ë½ÌÂ౿ž¤ò¹Ô¤¤¤Þ¤¹¡¥
Îã¤ò¼¨¤·¤Þ¤¹¡¥º£¡¤
¥Ñ¥Õ¥©¡¼¥Þ¥ó¥¹¤¬Íî¤Á¤ë²ÄǽÀ¤¬¤¢¤ê¤Þ¤¹¤¬¡¤¤â¤Ã¤È¤â°ÂÁ´¤ÊÊýË¡¤Ç¤¹¡¥
pgpool¤Ï¥Ç¥Õ¥©¥ë¥È¤Ç¤³¤Î¥â¡¼¥É¤Çưºî¤·¤Þ¤¹¡¥
+ ¤Ê¤ª¡¤¤¢¤ëÌä¹ç¤ï¤»¤Î¤ßstrict¥â¡¼¥É¤Ë¤·¤¿¤¯¤Ê¤¤¾ì¹ç¤Ï¡¤
+ /*NO STRICT*/¥³¥á¥ó¥È¤òÌä¹ç¤ï¤»¤ÎÀèÆ¬¤Ë¤¤¤ì¤Æ¤¯¤À¤µ¤¤¡¥
+
2) ¥Ç¥Ã¥É¥í¥Ã¥¯¤¬È¯À¸¤¹¤ë²ÄǽÀ¤Î¤¢¤ëÌ䤤¹ç¤ï¤»¤ÎÀèÆ¬¤ËÆÃÊ̤ʥ¡¼¥ï¡¼
¥É¡Ö/*STRICT*/¡×¤òÆþ¤ì¤ë
3) SELECTʸ¤¬ÌÀ¼¨Åª¤Ê¥È¥é¥ó¥¶¥¯¥·¥ç¥ó¥Ö¥í¥Ã¥¯Æâ¤Ç¼Â¹Ô¤µ¤ì¤Æ¤¤¤Ê¤¤¤³
¤È
- ¤Ê¤ª¡¤ÅöÁ³¤Î¤³¤È¤Ê¤¬¤é¹¹¿·¤òȼ¤¦´Ø¿ô¤ò¸Æ¤Ó½Ð¤¹¤è¤¦¤ÊÉûºîÍѤΤ¢¤ë
- SELECTʸ¤ò»ÈÍѤ·¤Æ¤¤¤ë¾ì¹ç¤ÏÌäÂ꤬µ¯¤¤Þ¤¹¡¥¤³¤Î¤è¤¦¤Ê¾ì¹ç¤Ï
- load_balance_mode"¤òfalse¤Ë¤¹¤ë¤«¡¤SELECTʸ¤Î¹ÔƬ¤Ë¥¹¥Ú¡¼¥¹¤ä
- /*NO LOAD BALANCE*/¤Î¤è¤¦¤Ê¥³¥á¥ó¥È¤òÁÞÆþ¤·¤ÆÉé²Ùʬ»¶¤µ¤ì¤Ê¤¤¤è¤¦¤Ë
- ¤·¤Æ¤¯¤À¤µ¤¤¡¥
+ ¤Ê¤ª¡¤ÅöÁ³¤Î¤³¤È¤Ê¤¬¤éSELECT FOR UPDATE¤ä¡¤¹¹¿·¤òȼ¤¦´Ø¿ô¤ò¸Æ¤Ó½Ð¤¹
+ ¤è¤¦¤ÊÉûºîÍѤΤ¢¤ëSELECTʸ¤ò»ÈÍѤ·¤Æ¤¤¤ë¾ì¹ç¤ÏÌäÂ꤬µ¯¤¤Þ¤¹¡¥¤³¤Î
+ ¤è¤¦¤Ê¾ì¹ç¤Ïload_balance_mode"¤òfalse¤Ë¤¹¤ë¤«¡¤SELECTʸ¤Î¹ÔƬ¤Ë¥¹¥Ú¡¼
+ ¥¹¤ä/*NO LOAD BALANCE*/¤Î¤è¤¦¤Ê¥³¥á¥ó¥È¤òÁÞÆþ¤·¤ÆÉé²Ùʬ»¶¤µ¤ì¤Ê¤¤¤è
+ ¤¦¤Ë¤·¤Æ¤¯¤À¤µ¤¤¡¥
¤Á¤Ê¤ß¤Ë¡¤regression test¤Ë¤Ï¤½¤Î¤è¤¦¤ÊSELECTʸ¤¬´Þ¤Þ¤ì¤Æ¤¤¤ë¤¿¤á
(¤¿¤È¤¨¤Ðconstraints¥Æ¥¹¥È¤Î¡ÖSELECT 'one' AS one,
¸½»þÅÀ¤Ç¤Ï¡¤°Ê²¼¤Îµ¡Ç½¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡¥
o trust, clear text password°Ê³°¤Îǧ¾ÚÊý¼°(¥ì¥×¥ê¥±¡¼¥·¥ç¥ó¥â¡¼
- ¥É»þ)
+ ¥É¤Þ¤¿¤Ï¥Þ¥¹¥¿/¥¹¥ì¡¼¥Ö¥â¡¼¥É»þ)
o trust, clear text password, crypt, md5°Ê³°¤Îǧ¾ÚÊý¼°(Èó¥ì¥×¥ê
¥±¡¼¥·¥ç¥ó¥â¡¼¥É»þ)
¥Ø¥ë¥¹¥Á¥§¥Ã¥¯¤ò¹Ô¤¦¤¿¤á¤ÎPostgreSQL¥æ¡¼¥¶Ì¾¤Ç¤¹¡¥
+ insert_lock
+
+ SERIAL·¿¤ò»È¤Ã¤Æ¤¤¤ë¥Æ¡¼¥Ö¥ë¤ò¥ì¥×¥ê¥±¡¼¥·¥ç¥ó¤¹¤ë¤È¡¤SERIAL·¿¤ÎÎó
+ ¤ÎÃͤ¬¥Þ¥¹¥¿¤È¥»¥«¥ó¥À¥ê¤Ç°ìÃפ·¤Ê¤¯¤Ê¤ë¤³¤È¤¬¤¢¤ê¤Þ¤¹¡¥¤³¤ÎÌäÂê¤Ï¡¤
+ ³ºÅö¥Æ¡¼¥Ö¥ë¤òÌÀ¼¨Åª¤Ë¥í¥Ã¥¯¤¹¤ë¤³¤È¤Ç²óÈò¤Ç¤¤Þ¤¹(¤â¤Á¤í¤ó¥È¥é¥ó¥¶
+ ¥¯¥·¥ç¥ó¤ÎÊÂÎó¼Â¹ÔÀ¤Ïµ¾À·¤Ë¤Ê¤ê¤Þ¤¹¤¬)¡¥¤·¤«¤·¡¤¤½¤Î¤¿¤á¤Ë¤Ï¡¤
+
+ INSERT INTO ...
+
+ ¤ò
+
+ BEGIN;
+ LOCK TABLE ...
+ INSERT INTO ...
+ COMMIT;
+
+ ¤Ë½ñ¤´¹¤¨¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó¡¥insert_lock¤òtrue¤Ë¤¹¤ë¤È¼«Æ°Åª¤Ë¥È¥é
+ ¥ó¥¶¥¯¥·¥ç¥ó¤Î³«»Ï¡¤¥Æ¡¼¥Ö¥ë¥í¥Ã¥¯¡¤¥È¥é¥ó¥¶¥¯¥·¥ç¥ó¤Î½ªÎ»¤ò¹Ô¤Ã¤Æ
+ ¤¯¤ì¤ë¤Î¤Ç¡¤¤³¤¦¤·¤¿¼ê´Ö¤ò¾Ê¤¯¤³¤È¤¬¤Ç¤¤Þ¤¹¡Ê¤¹¤Ç¤Ë¥È¥é¥ó¥¶¥¯¥·¥ç
+ ¥ó¤¬³«»Ï¤µ¤ì¤Æ¤¤¤ë¾ì¹ç¤ÏLOCK TABLE...¤À¤±¤¬¼Â¹Ô¤µ¤ì¤Þ¤¹¡Ë¡¥
+
+ ¤¿¤À¡¤¤Î¥Æ¡¼¥Ö¥ë¤ÇËÜÅö¤ËSERIAL·¿¤¬»È¤ï¤ì¤Æ¤¤¤ë¤«¤É¤¦¤«¤¬È½Äꤵ¤ì¤ë
+ ¤ï¤±¤Ç¤Ï¤Ê¤¤¤Î¤Ç¡¤SERIAL·¿¤ò»È¤Ã¤Æ¤¤¤Ê¤¤¥Æ¡¼¥Ö¥ë¤Ç¤â¤³¤¦¤·¤¿½èÍý¤¬
+ ¹Ô¤ï¤ì¤Æ¤·¤Þ¤¤¤Þ¤¹¡Êµ¡Ç½¾å»Ù¾ã¤¬¤¢¤ë¤ï¤±¤Ç¤Ï¤Ê¤¤¤Î¤Ç¤¹¤¬¡¤½èÍý®ÅÙ
+ ¤¬ÃÙ¤¯¤Ê¤Ã¤Æ¤·¤Þ¤¤¤Þ¤¹¡Ë¡¥
+
+ ¤³¤ÎÌäÂê¤ò²óÈò¤¹¤ë¤Ë¤Ï2¤Ä¤ÎÊýË¡¤¬¤¢¤ê¤Þ¤¹¡¥
+
+ 1) insert_lock¤òtrue¤Ë¤·¤Æ¡¤INSERTʸ¤ÎÀèÆ¬¤Ë/*NO INSERT LOCK*/¥³¥á
+ ¥ó¥È¤òÄɲ乤롥¤³¤Î¥³¥á¥ó¥È¤¬¤¢¤ë¤È¡¤¥Æ¡¼¥Ö¥ë¥í¥Ã¥¯¤Ï¹Ô¤ï¤ì¤Þ¤»
+ ¤ó¡¥
+
+ 2) insert_lock¤òfalse¤Ë¤·¤Æ¡¤INSERTʸ¤ÎÀèÆ¬¤Ë/*INSERT LOCK*/¥³¥á¥ó
+ ¥È¤òÄɲ乤롥¤³¤Î¥³¥á¥ó¥È¤¬¤¢¤ë¤È¡¤¤³¤ÎINSERTʸ¤ËÂФ·¤Æ¤Î¤ß¥Æ¡¼
+ ¥Ö¥ë¥í¥Ã¥¯¤¬¹Ô¤ï¤ì¤Þ¤¹¡¥
+
+ SERIAL·¿¤ò»È¤Ã¤Æ¤¤¤ë¥Æ¡¼¥Ö¥ë¤¬Â¿¤¤¾ì¹ç¤Ï1)¤ò¡¤¾¯¤Ê¤¤¾ì¹ç¤Ï2)¤òºÎÍÑ
+ ¤¹¤ë¤ÈÎɤ¤¤Ç¤·¤ç¤¦¡¥
+
+ insert_lock¤Î¥Ç¥Õ¥©¥ë¥ÈÃͤÏfalse¤Ç¤¹¡¥
+
+ ¤Ê¤ª¡¤insert_lock¤ò͸ú¤Ë¤·¤Æregression test¤ò¼Â¹Ô¤¹¤ë¤È¡¤¾¯¤¯¤È¤â
+ PostgreSQL 8.0¤Ç¤Ïtransactions, privileges, rules, alter_table¤¬
+ fail¤·¤Þ¤¹¡¥rule¤Ç¤Ï¡¤view¤ËÂФ·¤ÆLOCK¤ò¤·¤è¤¦¤È¤·¤Æ¤·¤Þ¤¦¤³¤È¡¤
+ ¤Û¤«¤Î¤â¤Î¤Ï
+
+ ! ERROR: current transaction is aborted, commands ignored until end of transaction block
+
+ ¤È¤¤¤¦¤è¤¦¤Ê¥á¥Ã¥»¡¼¥¸¤¬½Ð¤Æ¤·¤Þ¤¦¤¿¤á¤Ç¤¹¡¥¤¿¤È¤¨¤Ð¡¤transactions
+ ¤Ç¤Ï¡¤Â¸ºß¤·¤Ê¤¤¥Æ¡¼¥Ö¥ë¤ËÂФ·¤ÆINSERT¤ò¹Ô¤¦¥Æ¥¹¥È¤¬´Þ¤Þ¤ì¤Æ¤ª¤ê¡¤
+ pgpool¤¬ºÇ½é¤Ë¸ºß¤·¤Ê¤¤¥Æ¡¼¥Ö¥ë¤ËÂФ·¤ÆLOCK¤ò¹Ô¤¦·ë²Ì¡¤¥¨¥é¡¼¤Ë¤Ê¤Ã
+ ¤Æ¥È¥é¥ó¥¶¥¯¥·¥ç¥ó¤¬¥¢¥Ü¡¼¥È¾õÂ֤ˤʤꡤ³¤¯INSERT¤Ç¾åµ¥¨¥é¡¼¤¬½Ð
+ ¤Æ¤·¤Þ¤¤¤Þ¤¹¡¥
+
7. pgpool¤Îµ¯Æ°
pgpool¤òµ¯Æ°¤¹¤ë¤â¤Ã¤È¤â´Êñ¤ÊÊýË¡¤Ï¡¤
item | value | description
------------------------------+------------------------------------------------------+------------------------------------------------------------------------
listen_addresses | * | host name(s) or IP address(es) to listen to
- port | 9999 | pgpool accepting port number
+ port | 9998 | pgpool accepting port number
socket_dir | /tmp | pgpool socket directory
backend_host_name | | master backend host name
backend_port | 5432 | master backend port number
secondary_backend_host_name | | secondary backend host name
- secondary_backend_port | 0 | secondary backend port number
- num_init_children | 1 | # of children initially pre-forked
- child_life_time | 300 | if idle for this seconds, child exits
+ secondary_backend_port | 5433 | secondary backend port number
+ num_init_children | 32 | # of children initially pre-forked
+ child_life_time | 0 | if idle for this seconds, child exits
connection_life_time | 0 | if idle for this seconds, connection closes
- max_pool | 4 | max # of connection pool per child
+ max_pool | 2 | max # of connection pool per child
logdir | /tmp | logging directory
backend_socket_dir | /tmp | Unix domain socket directory for the PostgreSQL server
- replication_mode | 0 | non 0 if operating in replication mode
+ replication_mode | 1 | non 0 if operating in replication mode
replication_strict | 1 | non 0 if operating in strict mode
replication_timeout | 5000 | if secondary does not respond in this milli seconds, abort the session
load_balance_mode | 0 | non 0 if operating in load balancing mode
print_timestamp | 1 | if true print time stamp to each log line
master_slave_mode | 0 | if true, operate in master/slave mode
connection_cache | 1 | if true, cache connection pool
- health_check_timeout | 20 | health check timeout
+ health_check_timeout | 5 | health check timeout
health_check_period | 0 | health check period
+ health_check_user | t-ishii | health check user
+ insert_lock | 1 | insert lock
current_backend_host_name | | current master host name
current_backend_port | 5432 | current master port #
- replication_enabled | 0 | non 0 if actually operating in replication mode
+ replication_enabled | 1 | non 0 if actually operating in replication mode
master_slave_enabled | 0 | non 0 if actually operating in master/slave
num_reset_queries | 3 | number of queries in reset_query_list
-(31 rows)
+ server_status | master( on 5432) up secondary( on 5433) up | server status
+(34 rows)
12. regression test¤Î¼Â»Ü
TODO¹àÌÜ
-o STRICT¥â¡¼¥É¤Ç¤¢¤Ã¤Æ¤â¡¤SELECT¤Ê¤é¤Ðnon strict¤Ë¤·¤Æ¤¤¤¤¤Ï¤º¡¥
+-o ¼«Æ°¥Æ¡¼¥Ö¥ë¥í¥Ã¥¯¤·¤ÆSERIAL·¿¤ÎƱ´ü¤òÊݾڤ¹¤ë(2.6)¡¥
+
+o SSL¤Î¥µ¥Ý¡¼¥È
+
+o ¤â¤·SQL¤ò¥Ñ¡¼¥¹¤Ç¤¤ì¤Ð¡¤¥Æ¡¼¥Ö¥ëñ°Ì¤Î¥ì¥×¥ê¥±¡¼¥·¥ç¥ó¤â²Äǽ¡©
+
+o ¥»¥Ã¥·¥ç¥ó¥ì¥Ù¥ë¤Î¥í¡¼¥É¥Ð¥é¥ó¥¹¤ò»Ø¼¨¤Ç¤¤ëµ¡Ç½¤òÄɲÃ
+ /* BEGIN SESSION LEVEL LOAD BALANCE */¤È¤«¡¥
+
+-o /*NO STRICT*/ ¤È¤« /*PARALLEL*/ ¤È¤¤¤Ã¤¿»Ø¼¨»Ò¤¬¤¢¤Ã¤Æ¤â¤è¤¤¤Î¤«¤â
+ (pgsql-jp 35304)->2.6¤Ç/*NO STRICT*/¤ò¼ÂÁõ
+
+-o parameter status¤ÎÃͤ¬°ìÃפ·¤Æ¤¤¤Ê¤¯¤Æ¤â¥¨¥é¡¼¤Ë¤Ê¤é¤Ê¤¤¤è¤¦¤Ë¤·¤¿
+ (US¤ÈNZ¤Ç¥ì¥×¥ê¥±¡¼¥·¥ç¥ó¤·¤Æ¤¤¤ëÎ㤬¤¢¤Ã¤¿¡ª)¡¥(v2.5.4)
+
+o load balance¤ÎÈæÎ¨¤òSQLʸñ°Ì¤Ç¥³¥á¥ó¥È¤Ç»ØÄê¤Ç¤¤ë¤è¤¦¤Ë¤¹¤ë¡¥
+
+- o STRICT¥â¡¼¥É¤Ç¤¢¤Ã¤Æ¤â¡¤SELECT¤Ê¤é¤Ðnon strict¤Ë¤·¤Æ¤¤¤¤¤Ï¤º¡¥
+ 2.5.2¤Ç¼ÂÁõ¡¥¤Ç¤âÌäÂêȯÀ¸¡¥[pgsql-jp: 35294]»²¾È¡¥
o ¥Ð¥°¡¥master/slave mode&load balance mode¤Î¤È¤¤Ë¡¤reset query¤¬¥Þ¥¹
¥¿Â¦¤Ë¤·¤«½Ð¤Ê¤¤¡¥master_slave mode¤Ç¤Ê¤±¤ì¤Ð¤³¤ÎÌäÂê¤Ïµ¯¤¤Ê¤¤->¤·¤ç
-o schedule failover/½ÌÂà(v2.5b1)
- ñ¤Ë¥·¥°¥Ê¥ë¤òÁ÷¤ë¤À¤±
+o fail back/switch back¤Î¼ÂÁõ
+
o 3Âæ°Ê¾å¤Î¥µ¡¼¥Ð¤ËÂбþ
-o ¥¿¥¤¥à¥¹¥¿¥ó¥×¤Î°õ»úµ¡Ç½(v2.5b2)
³Æpgpool¤Ëshow status¤òÁ÷¿®¤·¡¤¾õÂÖ¤òÄê´üŪ¤ËÇİ®¤¹¤ëÄøÅ٤Ǥ⽼ʬ
ÊØÍø¡¥
+o ̵Ää»ß¥ê¥«¥Ð¥ê V2
+ 1) rsync
+
+ 2) ¥ª¡¼¥×¥ó¥È¥é¥ó¥¶¥¯¥·¥ç¥ó¤¬¤¢¤Ã¤¿¤éÂԤġ¥
+
+ 3) ¥ª¡¼¥×¥ó¥È¥é¥ó¥¶¥¯¥·¥ç¥ó¤¬¤¤¤Ê¤¯¤Ê¤Ã¤¿¤éReadyForQuery¤Î»þÅÀ¤ÇÂÔ¤Á
+ ¾õÂÖ¤ËÆþ¤ë
+
+ 4) CHECKPOINTȯ¹Ô
+ 5) rsync
+ 6) Ää»ß¦postmaster restart
+ 7) Ä̾ï¥â¡¼¥É¤Ë°Ü¹Ô
+ - ¥Þ¥¹¥¿¤È¥»¥«¥ó¥À¥ê¤¬Æþ¤ìÂØ¤ï¤ë¥±¡¼¥¹¤Ç¤Ï´°Á´restart¤¬É¬Íס©->¤½
+ ¤ó¤Ê¤³¤È¤â¤Ê¤¤¤À¤í¤¦¡¥
+
+ 8) Ê£¿ô¤ÎWeb¥µ¡¼¥Ð¤Çư¤¤¤Æ¤¤¤ëpgpool¤ò°ìÀƤ˺Ƶ¯Æ°¤¹¤ë¤Ë¤Ï¤É¤¦¤·¤¿¤é
+ ¤è¤¤¤«¡©¤Þ¤¿¡¤¤É¤Îpgpool¤¬ÌµÄä»ß¥ê¥«¥Ð¥ê¤ò´ÉÍý¤¹¤ë¤«¡©Ê̤Υꥫ¥Ð
+ ¥êÍÑ´ÉÍý¥µ¡¼¥Ð¤òΩ¤Æ¤¿Êý¤¬¤è¤¤¤«¡©->ñ¤Ê¤ë´ÉÍý¥Ä¡¼¥ë¤ÇÎɤ¤¤Î¤Ç¤Ï¡©
+ ³Æpgpool¤Ëshow status¤òÁ÷¿®¤·¡¤¾õÂÖ¤òÄê´üŪ¤ËÇİ®¤¹¤ëÄøÅ٤Ǥ⽼ʬ
+ ÊØÍø¡¥
+
»²¹Í:
PGCluster¤Îưºî
# Define the identity of the package.
PACKAGE=pgpool
- VERSION=2.5.2
+ VERSION=2.6
cat >>confdefs.h <<_ACEOF
dnl Checks for programs.
AC_PROG_CC
-AM_INIT_AUTOMAKE(pgpool, 2.5.2)
+AM_INIT_AUTOMAKE(pgpool, 2.6)
AM_PROG_LEX
pool_log("starting degeneration. shutdown secondary host %s(%d)",
pool_config.secondary_backend_host_name,
pool_config.secondary_backend_port);
+ pool_config.server_status[1] = 2; /* mark this down */
}
else
{
pool_log("starting degeneration. shutdown master host %s(%d)",
pool_config.backend_host_name,
pool_config.backend_port);
+ pool_config.server_status[0] = 2; /* mark this down */
}
}
else if (!degenerated && pool_config.secondary_backend_port != 0)
pool_config.current_backend_port,
pool_config.secondary_backend_host_name,
pool_config.secondary_backend_port);
+ pool_config.server_status[0] = 2; /* mark this down */
}
else
{
# when replication_strict is set to false, there will be a chance for
# deadlocks. set this to non 0 (in milli seconds) to detect this
-# situation and resolve the deadlock aborting current session.
+# situation and resolve the deadlock by aborting current session.
replication_timeout = 5000
# load balancing mode. i.e. all SELECT except in a transaction block
# health check user
health_check_user = 'nobody'
+# if true, automatically lock table with INSERT statement to keep SERIAL
+# data consistency. /*INSERT LOCK*/ comment has the same effect.
+# /NO INSERT LOCK*/ comment disables the effect.
+insert_lock = false
/* strict mode comment in SQL */
#define STRICT_MODE_STR "/*STRICT*/"
#define STRICT_MODE(s) (strncasecmp((s), STRICT_MODE_STR, strlen(STRICT_MODE_STR)) == 0)
+#define NO_STRICT_MODE_STR "/*NO STRICT*/"
+#define NO_STRICT_MODE(s) (strncasecmp((s), NO_STRICT_MODE_STR, strlen(NO_STRICT_MODE_STR)) == 0)
typedef enum {
POOL_CONTINUE = 0,
int key; /* cancel key */
} CancelPacket;
+#define MAX_CONNECTION_SLOTS 2
+
/*
* configuration paramters
*/
*/
char **reset_query_list; /* comma separated list of quries to be issued at the end of session */
- int print_timestamp; /* if non 0 print time stamp to each log line */
+ int print_timestamp; /* if non 0, print time stamp to each log line */
int master_slave_mode; /* if non 0, operate in master/slave mode */
int connection_cache; /* if non 0, cache connection pool */
int health_check_timeout; /* health check timeout */
int health_check_period; /* health check period */
char *health_check_user; /* PostgreSQL user name for health check */
-
+ int insert_lock; /* if non 0, automatically lock table with INSERT to keep SERIAL
+ data consistency */
/* followings do not exist in the configuration file */
char *current_backend_host_name; /* current backend host name */
int current_backend_port; /* current backend port # */
int replication_enabled; /* replication mode enabled */
int master_slave_enabled; /* master/slave mode enabled */
int num_reset_queries; /* number of queries in reset_query_list */
+ int num_servers; /* number of PostgreSQL servers */
+ int server_status[MAX_CONNECTION_SLOTS]; /* server status 0:unused, 1:up, 2:down */
} POOL_CONFIG;
#define MAX_PASSWORD_SIZE 1024
*/
} POOL_CONNECTION_POOL_SLOT;
-#define MAX_CONNECTION_SLOTS 2
-
typedef struct {
int num; /* number of slots */
POOL_CONNECTION_POOL_SLOT *slots[MAX_CONNECTION_SLOTS];
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
+#define LOCK_COMMENT "/*INSERT LOCK*/"
+#define LOCK_COMMENT_SZ (sizeof(LOCK_COMMENT)-1)
+#define NO_LOCK_COMMENT "/*NO INSERT LOCK*/"
+#define NO_LOCK_COMMENT_SZ (sizeof(NO_LOCK_COMMENT)-1)
+
/*
* global variables
*/
length, length1);
}
}
+ else
+ {
+ length1 = 0;
+ }
if (length < 0 || length1 < 0)
{
pool_config.health_check_timeout = 20;
pool_config.health_check_period = 0;
pool_config.health_check_user = "nobody";
-
+ pool_config.insert_lock = 0;
+ pool_config.num_servers = 0;
#define PARSE_ERROR() pool_error("pool_config: parse error at line %d '%s'", Lineno, yytext)
/* open config file */
return(-1);
}
pool_config.backend_port = v;
+ pool_config.server_status[pool_config.num_servers++] = 1;
}
else if (!strcmp(key, "secondary_backend_host_name"))
{
return(-1);
}
pool_config.secondary_backend_port = v;
+ pool_config.server_status[pool_config.num_servers++] = 1;
}
else if (!strcmp(key, "num_init_children"))
{
}
pool_config.health_check_user = str;
}
+
+ else if (!strcmp(key, "insert_lock"))
+ {
+ int v = eval_logical(yytext);
+
+ if (v < 0)
+ {
+ pool_error("pool_config: invalid value %s for %s", yytext, key);
+ return(-1);
+ }
+ pool_config.insert_lock = v;
+ }
}
return 0;
pool_config.health_check_timeout = 20;
pool_config.health_check_period = 0;
pool_config.health_check_user = "nobody";
-
+ pool_config.insert_lock = 0;
+ pool_config.num_servers = 0;
#define PARSE_ERROR() pool_error("pool_config: parse error at line %d '%s'", Lineno, yytext)
/* open config file */
return(-1);
}
pool_config.backend_port = v;
+ pool_config.server_status[pool_config.num_servers++] = 1;
}
else if (!strcmp(key, "secondary_backend_host_name"))
{
return(-1);
}
pool_config.secondary_backend_port = v;
+ pool_config.server_status[pool_config.num_servers++] = 1;
}
else if (!strcmp(key, "num_init_children"))
{
}
pool_config.health_check_user = str;
}
+
+ else if (!strcmp(key, "insert_lock"))
+ {
+ int v = eval_logical(yytext);
+
+ if (v < 0)
+ {
+ pool_error("pool_config: invalid value %s for %s", yytext, key);
+ return(-1);
+ }
+ pool_config.insert_lock = v;
+ }
}
return 0;
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
+#include <ctype.h>
#include "pool.h"
static int load_balance_enabled(POOL_CONNECTION_POOL *backend, char *sql);
static void start_load_balance(POOL_CONNECTION_POOL *backend);
static void end_load_balance(POOL_CONNECTION_POOL *backend);
+static POOL_STATUS do_command(POOL_CONNECTION *backend, char *query, int protoMajor, int no_ready_for_query);
+static int need_insert_lock(POOL_CONNECTION_POOL *backend, char *query);
+static POOL_STATUS insert_lock(POOL_CONNECTION_POOL *backend, char *query);
+static char *get_insert_command_table_name(char *query);
+static char *skip_comment(char *query);
static POOL_CONNECTION_POOL_SLOT *slots[MAX_CONNECTION_SLOTS];
-static int in_load_balance;
-static int master_slave_dml;
-static int replication_was_enabled;
-static int master_slave_was_enabled;
+
+static int in_load_balance; /* non 0 if in load balance mode */
+static int master_slave_dml; /* non 0 if master/slave mode is specified in config file */
+static int replication_was_enabled; /* replication mode was enabled */
+static int master_slave_was_enabled; /* master/slave mode was enabled */
+static int internal_transaction_started; /* to issue table lock command a transaction
+ has been started internally */
POOL_STATUS pool_process_query(POOL_CONNECTION *frontend,
POOL_CONNECTION_POOL *backend,
* Prrocess backend Response
*/
+ if (kind == 0)
+ {
+ pool_error("kind is 0!");
+ return POOL_ERROR;
+ }
+
+ pool_debug("pool_process_query: kind from backend: %c", kind);
+
if (MAJOR(backend) == PROTO_MAJOR_V3)
{
switch (kind)
master_slave_dml = 1;
}
+ /*
+ * judge if we need to lock the table
+ * to keep SERIAL data consistency among servers
+ * conditions:
+ * - protocol is V3
+ * - statement is INSERT
+ * - either "INSERT LOCK" comment exists or insert_lock directive specified
+ */
+ if (REPLICATION && need_insert_lock(backend, string))
+ {
+ /* start a transaction if needed and lock the table */
+ if (insert_lock(backend, string) != POOL_CONTINUE)
+ return POOL_END;
+ }
+
/* forward the query to the backend */
pool_write(MASTER(backend), "Q", 1);
{
/*
* in "strict mode" we need to wait for master completing the query.
- * note that this is applied to non SELECT queries only.
+ * note that this is not applied if "NO STRICT" is specified as a comment.
*/
- if (strncasecmp("SELECT", string, 6) &&
- (pool_config.replication_strict || STRICT_MODE(string)))
+ if ((pool_config.replication_strict && !NO_STRICT_MODE(string)) ||
+ STRICT_MODE(string))
{
+ pool_debug("waiting for master completing the query");
if (synchronize(MASTER(backend)))
return POOL_END;
}
static POOL_STATUS ReadyForQuery(POOL_CONNECTION *frontend,
POOL_CONNECTION_POOL *backend, int send_ready)
{
+ /* if a transaction is started for insert lock, we need to close it. */
+ if (internal_transaction_started)
+ {
+ int i;
+ int len;
+ signed char state;
+
+ if ((len = pool_read_message_length(backend)) < 0)
+ return POOL_END;
+
+ pool_debug("ReadyForQuery: message length: %d", len);
+
+ len = htonl(len);
+
+ state = pool_read_kind(backend);
+ if (state < 0)
+ return POOL_END;
+
+ /* set transaction state */
+ pool_debug("ReadyForQuery: transaction state: %c", state);
+ MASTER(backend)->tstate = state;
+ if (REPLICATION)
+ SECONDARY(backend)->tstate = state;
+
+ for (i = 0;i < backend->num;i++)
+ {
+ if (do_command(backend->slots[i]->con, "COMMIT", PROTO_MAJOR_V3, 1) != POOL_CONTINUE)
+ return POOL_ERROR;
+ }
+ internal_transaction_started = 0;
+ }
+
pool_flush(frontend);
if (send_ready)
short nrows;
int size;
int hsize;
+ int slen;
i = 0;
status[i].desc = "health check user";
i++;
+ status[i].name = "insert_lock";
+ snprintf(status[i].value, MAXVALLEN, "%d", pool_config.insert_lock);
+ status[i].desc = "insert lock";
+ i++;
+
status[i].name = "current_backend_host_name";
snprintf(status[i].value, MAXVALLEN, "%s", pool_config.current_backend_host_name);
status[i].desc = "current master host name";
status[i].desc = "number of queries in reset_query_list";
i++;
+ status[i].name = "server_status";
+
+ if (pool_config.server_status[0] == 0)
+ {
+ snprintf(status[i].value, MAXVALLEN, "master(%s on %d) unused ",
+ pool_config.backend_host_name, pool_config.backend_port);
+ }
+ else if (pool_config.server_status[0] == 1)
+ {
+ snprintf(status[i].value, MAXVALLEN, "master(%s on %d) up ",
+ pool_config.backend_host_name, pool_config.backend_port);
+ }
+ else if (pool_config.server_status[0] == 2)
+ {
+ snprintf(status[i].value, MAXVALLEN, "master(%s on %d) down ",
+ pool_config.backend_host_name, pool_config.backend_port);
+ }
+
+ slen = strlen(status[i].value);
+
+ if (pool_config.server_status[1] == 0)
+ {
+ snprintf(status[i].value+slen, MAXVALLEN-slen, "secondary(%s on %d) unused",
+ pool_config.secondary_backend_host_name, pool_config.secondary_backend_port);
+ }
+ else if (pool_config.server_status[1] == 1)
+ {
+ snprintf(status[i].value+slen, MAXVALLEN-slen, "secondary(%s on %d) up",
+ pool_config.secondary_backend_host_name, pool_config.secondary_backend_port);
+ }
+ else if (pool_config.server_status[1] == 2)
+ {
+ snprintf(status[i].value+slen, MAXVALLEN-slen, "secondary(%s on %d) down",
+ pool_config.secondary_backend_host_name, pool_config.secondary_backend_port);
+ }
+ status[i].desc = "server status";
+ i++;
+
nrows = i;
if (MAJOR(backend) == PROTO_MAJOR_V2)
#endif
if (DUAL_MODE)
- if (pool_read2(SECONDARY(backend), len_array[1]-4) == NULL)
+ {
+ char *sp;
+
+ if ((sp = pool_read2(SECONDARY(backend), len_array[1]-4)) == NULL)
return POOL_END;
+ name = sp;
+ value = sp + strlen(name) + 1;
+
+ pool_debug("secondary name: %s value: %s", name, value);
+ }
+
return pool_write(frontend, p, len);
}
else
pool_error("send_error_message: unknown protocol major %d", protoMajor);
}
+
+/*
+ * sends q query in sync manner.
+ * this function sends a query and wait for CommandComplete/ReadyForQuery.
+ * if an error occured, it returns with POOL_ERROR.
+ * this function does NOT handle SELECT/SHOW quries.
+ * if no_ready_for_query is non 0, returns without reading the packet
+ * length for ReadyForQuery. This mode is necessary when called from ReadyForQuery().
+ */
+static POOL_STATUS do_command(POOL_CONNECTION *backend, char *query, int protoMajor,
+ int no_ready_for_query)
+{
+ int len;
+ int status;
+ char kind;
+ char *string;
+
+ pool_debug("do_command: Query: %s", query);
+
+ /* send the query to the backend */
+ pool_write(backend, "Q", 1);
+ len = strlen(query)+1;
+
+ if (protoMajor == PROTO_MAJOR_V3)
+ {
+ int sendlen = htonl(len + 4);
+ pool_write(backend, &sendlen, sizeof(sendlen));
+ }
+
+ if (pool_write_and_flush(backend, query, len) < 0)
+ {
+ return POOL_END;
+ }
+
+ /*
+ * Expecting CompleteCommand
+ */
+ status = pool_read(backend, &kind, sizeof(kind));
+ if (status < 0)
+ {
+ pool_error("do_command: error while reading message kind");
+ return POOL_END;
+ }
+
+#ifdef NOT_USED
+ if (kind != 'C')
+ {
+ pool_error("do_command: backend does not successfully complete command %s status %c", query, kind);
+
+ /* the response must be an ERROR. handle it */
+
+ return POOL_END;
+ }
+#endif
+ /*
+ * read command tag of CommandComplete response
+ */
+ if (protoMajor == PROTO_MAJOR_V3)
+ {
+ if (pool_read(backend, &len, sizeof(len)) < 0)
+ return POOL_END;
+ len = ntohl(len) - 4;
+ string = pool_read2(backend, len);
+ if (string == NULL)
+ return POOL_END;
+ pool_debug("command tag: %s", string);
+ }
+ else
+ {
+ string = pool_read_string(backend, &len, 0);
+ if (string == NULL)
+ return POOL_END;
+ }
+
+ /*
+ * Expecting ReadyForQuery
+ */
+ status = pool_read(backend, &kind, sizeof(kind));
+ if (status < 0)
+ {
+ pool_error("do_command: error while reading message kind");
+ return POOL_END;
+ }
+
+ if (kind != 'Z')
+ {
+ pool_error("do_command: backend does not return ReadyForQuery");
+ return POOL_END;
+ }
+
+ if (no_ready_for_query)
+ return POOL_CONTINUE;
+
+ if (protoMajor == PROTO_MAJOR_V3)
+ {
+ if (pool_read(backend, &len, sizeof(len)) < 0)
+ return POOL_END;
+
+ status = pool_read(backend, &kind, sizeof(kind));
+ if (status < 0)
+ {
+ pool_error("do_command: error while reading transaction status");
+ return POOL_END;
+ }
+
+ /* set transaction state */
+ pool_debug("ReadyForQuery: transaction state: %c", kind);
+ backend->tstate = kind;
+ }
+
+ return POOL_CONTINUE;
+}
+
+/*
+ * judge if we need to lock the table
+ * to keep SERIAL consistency among servers
+ */
+static int need_insert_lock(POOL_CONNECTION_POOL *backend, char *query)
+{
+ if (MAJOR(backend) != PROTO_MAJOR_V3)
+ return 0;
+
+ /*
+ * either insert_lock directive specified and without "NO INSERT LOCK" comment
+ * or "INSERT LOCK" comment exists?
+ */
+ if ((pool_config.insert_lock && strncasecmp(query, NO_LOCK_COMMENT, NO_LOCK_COMMENT_SZ)) ||
+ strncasecmp(query, LOCK_COMMENT, LOCK_COMMENT_SZ) == 0)
+ {
+ /* INSERT STATEMENT? */
+ query = skip_comment(query);
+ if (strncasecmp(query, "INSERT", 6) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * if a transaction has not already started, start a new one.
+ * issue LOCK TABLE IN SHARE ROW EXCLUSIVE MODE
+ */
+static POOL_STATUS insert_lock(POOL_CONNECTION_POOL *backend, char *query)
+{
+ char *table;
+ char qbuf[1024];
+ int i;
+
+ if (MAJOR(backend) != PROTO_MAJOR_V3)
+ return 0;
+
+ /* if we are not in a transaction block,
+ * start a new transaction
+ */
+ if (TSTATE(backend) == 'I')
+ {
+ for (i = 0;i < backend->num;i++)
+ {
+ if (do_command(backend->slots[i]->con, "BEGIN", PROTO_MAJOR_V3, 0) != POOL_CONTINUE)
+ return POOL_END;
+ }
+
+ /* mark that we started new transaction */
+ internal_transaction_started = 1;
+ }
+
+ /* issue lock table command */
+ table = get_insert_command_table_name(query);
+ snprintf(qbuf, sizeof(qbuf), "LOCK TABLE %s IN SHARE ROW EXCLUSIVE MODE", table);
+
+ for (i = 0;i < backend->num;i++)
+ {
+ if (do_command(backend->slots[i]->con, qbuf, PROTO_MAJOR_V3, 0) != POOL_CONTINUE)
+ {
+ internal_transaction_started = 0;
+ return POOL_END;
+ }
+ }
+
+ return POOL_CONTINUE;
+}
+
+/*
+ * obtain table name in INSERT statement
+ */
+static char *get_insert_command_table_name(char *query)
+{
+ static char table[1024];
+ char *qbuf;
+ char *token;
+
+ table[0] = '\0';
+
+ /* skip comment */
+ query = skip_comment(query);
+
+ if (*query == '\0')
+ return table;
+
+ /* skip spaces */
+ while (*query && isspace(*query))
+ query++;
+
+ /* skip non spaces(INSERT) */
+ while (*query && !isspace(*query))
+ query++;
+
+ /* skip spaces */
+ while (*query && isspace(*query))
+ query++;
+
+ /* skip non spaces(INTO) */
+ while (*query && !isspace(*query))
+ query++;
+
+ /* skip spaces */
+ while (*query && isspace(*query))
+ query++;
+
+ /* get table */
+ qbuf = strdup(query);
+ token = strtok(qbuf, " (");
+ strncpy(table, token, sizeof(table));
+ free(qbuf);
+
+ pool_debug("get_insert_command_table_name: extracted table name: %s", table);
+
+ return table;
+}
+
+/* skip SQL comments */
+static char *skip_comment(char *query)
+{
+ if (strncmp(query, "/*", 2) == 0)
+ {
+ query += 2;
+ while (query)
+ {
+ if (strncmp(query, "*/", 2) == 0)
+ {
+ query += 2;
+ break;
+ }
+ query++;
+ }
+ }
+ return query;
+}
-#define PGPOOLVERSION "kaku"
+#define PGPOOLVERSION "kala"