[pgpool-general-jp: 116] SELECT をマスタにだけ送信するパッチ
Yoshiyuki Asaba
y-asaba @ sraoss.co.jp
2007年 4月 17日 (火) 16:00:11 JST
浅羽です。
pgpool をレプリケーションモードで動かしていると、たまにデータ不一致を
誤検知することがあり、縮退することがあります。SELECT の件数がタイミン
グによって異なるためです。そこで負荷分散ができない条件下では、SELECT
をマスタだけに送るようにパッチを作りました。添付します。
ただし、これだと select nextval() と select setval() が困るかと思いま
すので、クエリの文字列が先頭から "SELECT nextval" もしくは "SELECT
setval" の場合(大文字、小文字は区別しない、スペースの数は問題なし)は強
制的にレプリケーションさせるようにしています。それ以外にどうしても
SELECT をレプリケーションさせたい場合は、クエリの先頭に
/*REPLICATION*/ のように適当なコメントを追加してください。
結構大きな仕様変更なのでまだコミットしていません。
設定で挙動を選択できるようにしてほしい、等のコメントがありましたらお知
らせください。
--
Yoshiyuki Asaba
y-asaba @ sraoss.co.jp
-------------- next part --------------
Index: pool_process_query.c
===================================================================
RCS file: /cvsroot/pgpool/pgpool/pool_process_query.c,v
retrieving revision 1.42
diff -c -r1.42 pool_process_query.c
*** pool_process_query.c 12 Feb 2007 06:19:37 -0000 1.42
--- pool_process_query.c 17 Apr 2007 06:27:32 -0000
***************
*** 115,120 ****
--- 115,122 ----
static void process_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend);
static int reset_backend(POOL_CONNECTION_POOL *backend, int qcnt);
+ static int is_select_query(char *sql);
+ static int is_sequence_query(char *sql);
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);
***************
*** 143,148 ****
--- 145,151 ----
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 */
+ static int select_in_transaction = 0; /* non 0 if select query is in transaction */
static void (*pending_function)(PreparedStatementList *p, PreparedStatement *statement) = NULL;
static PreparedStatement *pending_prepared_stmt = NULL;
***************
*** 723,728 ****
--- 726,746 ----
MASTER_SLAVE = 0;
master_slave_dml = 1;
}
+ else if (REPLICATION && is_select_query(string1) && !is_sequence_query(string1))
+ {
+ int i;
+ /* save backend connection slots */
+ for (i=0;i<backend->num;i++)
+ {
+ slots[i] = backend->slots[i];
+ }
+
+ /* send query to master only. */
+ replication_was_enabled = 1;
+ REPLICATION = 0;
+ in_load_balance = 1;
+ select_in_transaction = 1;
+ }
/*
* judge if we need to lock the table
***************
*** 842,847 ****
--- 860,881 ----
MASTER_SLAVE = 0;
master_slave_dml = 1;
}
+ else if (REPLICATION && is_select_query(stmt->prepared_string) && !is_sequence_query(stmt->prepared_string))
+ {
+ int i;
+
+ /* save backend connection slots */
+ for (i=0;i<backend->num;i++)
+ {
+ slots[i] = backend->slots[i];
+ }
+
+ /* send query to master only. */
+ replication_was_enabled = 1;
+ REPLICATION = 0;
+ in_load_balance = 1;
+ select_in_transaction = 1;
+ }
for (i = 0;i < backend->num;i++)
{
***************
*** 2501,2506 ****
--- 2535,2542 ----
{
pending_function(&prepared_list, pending_prepared_stmt);
}
+ else if (kind == 'C' && select_in_transaction)
+ select_in_transaction = 0;
pending_function = NULL;
pending_prepared_stmt = NULL;
***************
*** 2588,2593 ****
--- 2624,2636 ----
}
}
+ if (select_in_transaction)
+ {
+ do_command(SECONDARY(backend), "send invalid query from pgpool to abort transaction.",
+ PROTO_MAJOR_V3, 0);
+ select_in_transaction = 0;
+ }
+
for (i = 0;i < backend->num;i++)
{
POOL_CONNECTION *cp = backend->slots[i]->con;
***************
*** 2942,2970 ****
}
/*
! * return non 0 if load balance is possible
*/
! static int load_balance_enabled(POOL_CONNECTION_POOL *backend, char *sql)
{
! if (pool_config.load_balance_mode &&
! DUAL_MODE &&
! MAJOR(backend) == PROTO_MAJOR_V3 &&
! TSTATE(backend) == 'I')
{
! if (pool_config.ignore_leading_white_space)
! {
! /* ignore leading white spaces */
! while (*sql && isspace(*sql))
! sql++;
! }
! if (!strncasecmp(sql, "SELECT", 6))
! return 1;
}
return 0;
}
/*
* start load balance mode
*/
static void start_load_balance(POOL_CONNECTION_POOL *backend)
--- 2985,3049 ----
}
/*
! * return non 0 if SQL is SELECT statement.
*/
! static int is_select_query(char *sql)
{
! if (pool_config.ignore_leading_white_space)
{
! /* ignore leading white spaces */
! while (*sql && isspace(*sql))
! sql++;
! }
! return (!strncasecmp(sql, "SELECT", 6));
!
! }
!
! /*
! * return non 0 if SQL is SELECT statement.
! */
! static int is_sequence_query(char *sql)
! {
! if (pool_config.ignore_leading_white_space)
! {
! /* ignore leading white spaces */
! while (*sql && isspace(*sql))
! sql++;
}
+
+ if (strncasecmp(sql, "SELECT", 6))
+ return 0;
+
+ sql += 6;
+ while (*sql && isspace(*sql))
+ sql++;
+
+ /* SELECT NEXTVAL('xxx') */
+ if (*sql && !strncasecmp(sql, "NEXTVAL", 7))
+ return 1;
+
+ /* SELECT SETVAL('xxx') */
+ if (*sql && !strncasecmp(sql, "SETVAL", 6))
+ return 1;
+
return 0;
}
/*
+ * return non 0 if load balance is possible
+ */
+ static int load_balance_enabled(POOL_CONNECTION_POOL *backend, char *sql)
+ {
+ return (pool_config.load_balance_mode &&
+ DUAL_MODE &&
+ MAJOR(backend) == PROTO_MAJOR_V3 &&
+ TSTATE(backend) == 'I' &&
+ is_select_query(sql) &&
+ !is_sequence_query(sql));
+ }
+
+ /*
* start load balance mode
*/
static void start_load_balance(POOL_CONNECTION_POOL *backend)
pgpool-general-jp メーリングリストの案内