[pgpool-general-jp: 1117] 「escape_string_warning」 が 「on」 で警告があると各ノードでトランザクションの実行順番が変わる事がある

滝口 tak4ml @ yahoo.co.jp
2012年 11月 9日 (金) 16:44:04 JST


お世話になっております。滝口と申します。

既に改善されていたら申し訳ないのですが標題の通り、
PostgreSQLの設定「escape_string_warning」 が 「on」 の時、
各ノード(DB)間で実行されるトランザクションの実行順序が
変わってしまう場合があるようですので報告です。

上記設定が「on」で、文字列に「E」を付けずにエスケープ文字を使うと
PostgreSQLの仕様で下記のようなWARNINGが出ると思います。
WARNING:  nonstandard use of \\ in a string literal

このWARNINGが出る状態で、
PgPoolを使っていたところ、
繰り返し実行される予定の
トランザクションが途中で止まっていました。

その時各DBのログを調べてみると下記のような状態でした。
-------------------------------------------
DB1
トランザクションAがテーブルhogeをロック(成功)
トランザクションBがテーブルhogeを更新(待ち)

DB2
トランザクションBがテーブルhogeを更新(成功)
トランザクションAがテーブルhogeをロック(待ち)
-------------------------------------------

このトランザクションBの更新は、
先程のWARNINGになるSQLになっていました。
原因調査のため再現しようと試みたところ
やはりそのWARNINGが出ている場合にのみ
発生する現象のようでした。


再現は以下の方法で行いました。
まず以下のような適当なテーブルを用意します。
CREATE TABLE hoge ( a text );

次に以下のような2つのSQLを用意します。
【sql1.sql】
BEGIN;
LOCK TABLE hoge IN SHARE ROW EXCLUSIVE MODE;
COMMIT;

【sql2.sql】
BEGIN;
update hoge set a='\n' ;
COMMIT;


これらのSQLをシェルでループさせて同時に実行させました。
【loop.sh】
for i in {0..1000};
do
  psql -U postgres mytest < $1
done;

【同時に実行】
# loop.sh sql1.sql & loop.sh sql2.sql &

すると実行途中で止まってしまいます。
止まるのは100%ではなく、タイミングもあるようです。

ちなみにフェールオーバーして1台の時は問題ありません。
また、下記のようにSQLの文字列に「E」を付けて
WARNINGが出ないように改修すると問題ありません。

【sql2.sql (改)】
BEGIN;
update hoge set a=E'\n' ;
COMMIT;

環境は下記の通りです。
PgPoolII 3.0.5 (umiyameboshi)-レプリケーションモード
CentOS5.5
PostgreSQL9.0.3 (3台)

設定をoffにすれば問題ないので
特に修正希望というわけではありませんが
参考までに情報連携させていただきました。



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