[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 メーリングリストの案内