Version 2.6 V2_6
authorTatsuo Ishii <ishii at sraoss.co.jp>
Sat, 25 Jun 2005 00:58:46 +0000 (00:58 +0000)
committerTatsuo Ishii <ishii at sraoss.co.jp>
Sat, 25 Jun 2005 00:58:46 +0000 (00:58 +0000)
15 files changed:
ChangeLog
NEWS
README
README.euc_jp
TODO
configure
configure.in
main.c
pgpool.conf.sample
pool.h
pool_auth.c
pool_config.c
pool_config.l
pool_process_query.c
version.h

index 2dab934142b94f30eb07a64faf004a6f5bad8b00..4905d35b1bd81d7db89e5b70351331def285b5bd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+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
diff --git a/NEWS b/NEWS
index 2d5144ec381fd678599fbeae6dff8a51f3ae0aed..63590bbbc871ebbb706d018ce03d490773e0f279 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,35 @@
+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)
diff --git a/README b/README
index a82ec8a8c7bb3d3b827beb432559dd84b0e2cac8..4f6f68e2dea1347954664ebcc481574c0e71d4c4 100644 (file)
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
 $Header$
 
-pgpool version 2.5(kaku) README
+pgpool version 2.6(kala) README
 
 1. What is pgpool
 
@@ -33,6 +33,10 @@ pgpool version 2.5(kaku) README
    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
@@ -156,7 +160,7 @@ pgpool version 2.5(kaku) README
    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)
@@ -415,6 +419,45 @@ pgpool version 2.5(kaku) README
 
    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:
@@ -498,19 +541,19 @@ pgpool version 2.5(kaku) README
              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            |                                                    | # 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
@@ -521,14 +564,17 @@ pgpool version 2.5(kaku) README
  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         |                                                    | 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
 
@@ -581,4 +627,3 @@ pgpool version 2.5(kaku) README
      - not in a transaction block
 
   2) in all other case, quries are sent to only master
-
index 1cfc1f6f66e3399ad3b5ce7d117137ce29617686..48b83aa48740043e5a85a458841e406d52071e09 100644 (file)
@@ -1,6 +1,6 @@
 $Header$
 
-pgpool version 2.5(kaku) README
+pgpool version 2.6(kala) README
 
 1. pgpool¤È¤Ï
 
@@ -40,6 +40,10 @@ pgpool version 2.5(kaku) README
    ¥ó¤Ï¤·¤Þ¤¹¤¬¡¤2Âæ¤Î¥Û¥¹¥È¤Ç¤Þ¤Ã¤¿¤¯Æ±¤¸Ãͤ¬¥³¥Ô¡¼¤µ¤ì¤ëÊݾڤϤ¢¤ê¤Þ
    ¤»¤ó¡¥
 
+   ¤¿¤À¤·¡¤SERIAL·¿¤Ë¤Ä¤¤¤Æ¤Ï¡¤¸å½Ò¤Î"insert_lock"¤ò»È¤¦¤³¤È¤Ë¤è¤Ã¤ÆÂÐ
+   ±þ²Äǽ¤Ç¤¹¡¥¾ÜºÙ¤Ï¡Ö6. pgpool¤ÎÀßÄêÊýË¡¡×¤Îinsert_lock¤Î¹à¤ò»²¾È¤·
+   ¤Æ¤¯¤À¤µ¤¤¡¥
+
    ¥ì¥×¥ê¥±¡¼¥·¥ç¥óÃæ¤Ë¾ã³²¤¬È¯À¸¤¹¤ë¤È¡¤¼«Æ°Åª¤Ë½ÌÂ౿ž¤ò¹Ô¤¤¤Þ¤¹¡¥
    Îã¤ò¼¨¤·¤Þ¤¹¡¥º£¡¤
 
@@ -119,6 +123,9 @@ pgpool version 2.5(kaku) README
       ¥Ñ¥Õ¥©¡¼¥Þ¥ó¥¹¤¬Íî¤Á¤ë²ÄǽÀ­¤¬¤¢¤ê¤Þ¤¹¤¬¡¤¤â¤Ã¤È¤â°ÂÁ´¤ÊÊýË¡¤Ç¤¹¡¥
       pgpool¤Ï¥Ç¥Õ¥©¥ë¥È¤Ç¤³¤Î¥â¡¼¥É¤Çưºî¤·¤Þ¤¹¡¥
 
+      ¤Ê¤ª¡¤¤¢¤ëÌä¹ç¤ï¤»¤Î¤ßstrict¥â¡¼¥É¤Ë¤·¤¿¤¯¤Ê¤¤¾ì¹ç¤Ï¡¤
+      /*NO STRICT*/¥³¥á¥ó¥È¤òÌä¹ç¤ï¤»¤ÎÀèÆ¬¤Ë¤¤¤ì¤Æ¤¯¤À¤µ¤¤¡¥
+
    2) ¥Ç¥Ã¥É¥í¥Ã¥¯¤¬È¯À¸¤¹¤ë²ÄǽÀ­¤Î¤¢¤ëÌ䤤¹ç¤ï¤»¤ÎÀèÆ¬¤ËÆÃÊ̤ʥ­¡¼¥ï¡¼
       ¥É¡Ö/*STRICT*/¡×¤òÆþ¤ì¤ë
 
@@ -165,11 +172,11 @@ pgpool version 2.5(kaku) README
    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,
@@ -244,7 +251,7 @@ pgpool version 2.5(kaku) README
        ¸½»þÅÀ¤Ç¤Ï¡¤°Ê²¼¤Îµ¡Ç½¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡¥
 
        o trust, clear text password°Ê³°¤Îǧ¾ÚÊý¼°(¥ì¥×¥ê¥±¡¼¥·¥ç¥ó¥â¡¼
-        ¥É»þ)
+        ¥É¤Þ¤¿¤Ï¥Þ¥¹¥¿/¥¹¥ì¡¼¥Ö¥â¡¼¥É»þ)
 
        o trust, clear text password, crypt, md5°Ê³°¤Îǧ¾ÚÊý¼°(Èó¥ì¥×¥ê
          ¥±¡¼¥·¥ç¥ó¥â¡¼¥É»þ)
@@ -584,6 +591,60 @@ pgpool version 2.5(kaku) README
 
    ¥Ø¥ë¥¹¥Á¥§¥Ã¥¯¤ò¹Ô¤¦¤¿¤á¤Î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¤òµ¯Æ°¤¹¤ë¤â¤Ã¤È¤â´Êñ¤ÊÊýË¡¤Ï¡¤
@@ -706,19 +767,19 @@ pgpool version 2.5(kaku) README
              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            |                                                    | # 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
@@ -729,14 +790,17 @@ pgpool version 2.5(kaku) README
  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         |                                                    | 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¤Î¼Â»Ü
 
diff --git a/TODO b/TODO
index 948d0fa6c16188694033314c9b7cb4ffdea15aee..7244504ad57c0d22d55259081f6f60d67defa4f5 100644 (file)
--- a/TODO
+++ b/TODO
@@ -2,7 +2,25 @@ $Header$
 
 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¤Ç¤Ê¤±¤ì¤Ð¤³¤ÎÌäÂê¤Ïµ¯¤­¤Ê¤¤->¤·¤ç
@@ -24,6 +42,8 @@ o 
 -o schedule failover/½ÌÂà(v2.5b1)
   - Ã±¤Ë¥·¥°¥Ê¥ë¤òÁ÷¤ë¤À¤±
 
+o fail back/switch back¤Î¼ÂÁõ
+
 o 3Âæ°Ê¾å¤Î¥µ¡¼¥Ð¤ËÂбþ
 
 -o ¥¿¥¤¥à¥¹¥¿¥ó¥×¤Î°õ»úµ¡Ç½(v2.5b2)
@@ -71,6 +91,27 @@ o ̵
      ³Æ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¤Îưºî
 
index f2c873ad227e7a825ddaa4a51e93176ea9cbe920..72e7eb8127cdc60cb3e28ee5de9cdf9556431c48 100755 (executable)
--- a/configure
+++ b/configure
@@ -2603,7 +2603,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE=pgpool
- VERSION=2.5.2
+ VERSION=2.6
 
 
 cat >>confdefs.h <<_ACEOF
index 6720d33b4b45ef1f52f3fb375fd18feca142636b..bc6479073ed61de08702af88bd97e5a4933cf7ce 100644 (file)
@@ -4,7 +4,7 @@ AC_INIT
 dnl Checks for programs.
 AC_PROG_CC
 
-AM_INIT_AUTOMAKE(pgpool, 2.5.2)
+AM_INIT_AUTOMAKE(pgpool, 2.6)
 
 AM_PROG_LEX
 
diff --git a/main.c b/main.c
index 0d9ce337bbfe93c217e86d401659b6dab31b7356..510fbf5d2908ef8b41cb79116a4913e7c63b27df 100644 (file)
--- a/main.c
+++ b/main.c
@@ -774,12 +774,14 @@ static RETSIGTYPE failover_handler(int sig)
                                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)
@@ -789,6 +791,7 @@ static RETSIGTYPE failover_handler(int sig)
                                           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
                {
index 76bb77f107fbcb9bd4fe41f597193dacdd51608f..09798b81f7cf803c15ccac6ceae22e74adf1fc8c 100644 (file)
@@ -57,7 +57,7 @@ replication_strict = true
 
 # 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
@@ -100,3 +100,7 @@ health_check_period = 0
 # 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
diff --git a/pool.h b/pool.h
index 027f2a53b125b044365ecd9a2387c1b2abba3929..dbb46efcc6fd3681fcfac7d9f8047325aa12ef5e 100644 (file)
--- a/pool.h
+++ b/pool.h
@@ -51,6 +51,8 @@
 /* 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,
@@ -101,6 +103,8 @@ typedef struct CancelPacket
        int                     key;    /* cancel key */
 } CancelPacket;
 
+#define MAX_CONNECTION_SLOTS 2
+
 /*
  * configuration paramters
  */
@@ -136,19 +140,22 @@ typedef struct {
                                                                                         */
        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
@@ -213,8 +220,6 @@ typedef struct {
                                                 */
 } POOL_CONNECTION_POOL_SLOT;
 
-#define MAX_CONNECTION_SLOTS 2
-
 typedef struct {
     int num;   /* number of slots */
     POOL_CONNECTION_POOL_SLOT  *slots[MAX_CONNECTION_SLOTS];
@@ -233,6 +238,11 @@ typedef struct {
 #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
  */
index d4a1157ef1df9466b46f08d1f89954f9c59976e7..d5460ccb81fa656a76336c8491a825b49de7cfa2 100644 (file)
@@ -932,6 +932,10 @@ int *pool_read_message_length2(POOL_CONNECTION_POOL *cp)
                                           length, length1);
                }
        }
+       else
+       {
+               length1 = 0;
+       }
 
        if (length < 0 || length1 < 0)
        {
index 4eb40ff2913a8a5433f2762bf2c567a8f8460f92..a24149c374a9769d5407c16af48c09f98e24c215 100644 (file)
@@ -1671,7 +1671,8 @@ int pool_get_config(char *confpath)
        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 */
@@ -1800,6 +1801,7 @@ int pool_get_config(char *confpath)
                                return(-1);
                        }
                        pool_config.backend_port = v;
+                       pool_config.server_status[pool_config.num_servers++] = 1;
                }
                else if (!strcmp(key, "secondary_backend_host_name"))
                {
@@ -1828,6 +1830,7 @@ int pool_get_config(char *confpath)
                                return(-1);
                        }
                        pool_config.secondary_backend_port = v;
+                       pool_config.server_status[pool_config.num_servers++] = 1;
                }
                else if (!strcmp(key, "num_init_children"))
                {
@@ -2104,6 +2107,18 @@ int pool_get_config(char *confpath)
                        }
                        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;
index 453079c21f90bff5ac8c6221f7dcd64b77dd01f1..46119eab494ea1ec13d41b762dd570c1237ba085 100644 (file)
@@ -134,7 +134,8 @@ int pool_get_config(char *confpath)
        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 */
@@ -263,6 +264,7 @@ int pool_get_config(char *confpath)
                                return(-1);
                        }
                        pool_config.backend_port = v;
+                       pool_config.server_status[pool_config.num_servers++] = 1;
                }
                else if (!strcmp(key, "secondary_backend_host_name"))
                {
@@ -291,6 +293,7 @@ int pool_get_config(char *confpath)
                                return(-1);
                        }
                        pool_config.secondary_backend_port = v;
+                       pool_config.server_status[pool_config.num_servers++] = 1;
                }
                else if (!strcmp(key, "num_init_children"))
                {
@@ -567,6 +570,18 @@ int pool_get_config(char *confpath)
                        }
                        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;
index 58dd37ee9d668e8d0d7c4aa0135fe1da10401aed..a9b2078bad80d0b614751feabd96c5df22f25e5c 100644 (file)
@@ -35,6 +35,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <netinet/in.h>
+#include <ctype.h>
 
 #include "pool.h"
 
@@ -95,12 +96,20 @@ static int reset_backend(POOL_CONNECTION_POOL *backend, int qcnt);
 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,
@@ -368,6 +377,14 @@ POOL_STATUS pool_process_query(POOL_CONNECTION *frontend,
                 * 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)
@@ -530,6 +547,21 @@ static POOL_STATUS Query(POOL_CONNECTION *frontend,
                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);
 
@@ -557,11 +589,12 @@ static POOL_STATUS Query(POOL_CONNECTION *frontend,
        {
                /*
                 * 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;
                }
@@ -599,6 +632,38 @@ static POOL_STATUS Query(POOL_CONNECTION *frontend,
 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)
@@ -1568,6 +1633,7 @@ static void process_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *b
        short nrows;
        int size;
        int hsize;
+       int slen;
 
        i = 0;
 
@@ -1714,6 +1780,11 @@ static void process_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *b
        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";
@@ -1739,6 +1810,44 @@ static void process_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *b
        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)
@@ -2042,9 +2151,18 @@ POOL_STATUS ParameterStatus(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *bac
 #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);
 
 }
@@ -2228,3 +2346,251 @@ void pool_send_error_message(POOL_CONNECTION *frontend, int protoMajor,
        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;
+}
index 812dce5f52906ea612a59eac0716086a1e248bbb..a24302a7c21b9cd9bc216790fcae2311a76e931f 100644 (file)
--- a/version.h
+++ b/version.h
@@ -1 +1 @@
-#define PGPOOLVERSION "kaku"
+#define PGPOOLVERSION "kala"