20110408pg upgrade fix/ja
Critical Fix for pg_upgrade/pg_migrator Users 2011-04-08: Details
ここでは、2011-04-08にアナウンス用メーリングリストで公開したpg_upgradeと(以前の)pg_migratorの修正について説明します。 この修正は8.4.8と9.0.4リリースに反映されます。
What can you tell me about this bug?
以下はこの不具合に関して全ユーザに通知したものです。
pg_upgradeと(以前の)pg_migratorのすべてのバージョンで不具合が見つかりました。 pg_upgradeまたはpg_migratorを使用していたユーザはすべて、極力早く、以下に示す修正する操作を行わなければなりません。 また、最新のバックアップを持っていない場合は、pg_clogディレクトリのバックアップを取得した方が良いかもしれません。 正しく操作を行うことに失敗した場合、想定外の停止時間が発生する可能性があります。
この不具合により問い合わせに対して以下のようなエラーが返ります。
ERROR: could not access status of transaction ###### DETAIL: could not open file "pg_clog/####": No such file or directory=20
このエラーにより、データベースに格納された非常に広範囲の値へのアクセスが阻害されます。 まず、この説明を読んだ後すぐに、PostgreSQLデータベースのデータディレクトリにあるpg_clogディレクトリのファイルレベルのバックアップを取得してください。 次に、こうしたエラーを防ぐために、ユーザはスーパーユーザとして以下のpsqlスクリプトをできる限り早くすべてのアップグレードしたデータベースに対して実行しなければなりません。
-- このスクリプトは、pg_upgradeとpg_migratorによりアップグレードされた、 -- 8.4.8より前と9.0.4より前のサーバ内のデータを修正します。 -- クラスタ内のすべてのデータベースに対してpsqlを用いてこのスクリプトを実行してください。 -- ただし'template0'は除きます。 -- 例: -- psql -U postgres -a -f pg_upgrade_fix.sql dbname -- これは書き込み可能なディレクトリで実行しなければなりません。 -- -- データベースの容量と設定によりますが、このスクリプトにより大量のI/O -- が発生し、性能が劣化する可能性があります。トラフィックが低い時間底に -- このスクリプトを実行し、データベースの負荷を監視してください。 -- CREATE TEMPORARY TABLE pg_upgrade_fix AS SELECT 'VACUUM FREEZE pg_toast.' || c.relname || ';' FROM pg_class c, pg_namespace n WHERE c.relnamespace = n.oid AND n.nspname = 'pg_toast' AND c.relkind = 't' ORDER by c.oid; \copy pg_upgrade_fix TO 'pg_upgrade_tmp.sql' \i pg_upgrade_tmp.sql
今後リリースされるpostgresql 8.4.8と9.0.4には修正が反映されます。 これらのリリースでは、移行されるデータベース内のTOASTテーブルすべてを正しくリストアしますので、アップグレードの後に上記スクリプトを実行する必要はなくなります。 しかし、過去にアップグレードしたデータベースに対しては、PostgreSQL 9.0.4を使用している場合であっても、このスクリプトを実行しなければなりません。
Who is affected by this bug?
PostgreSQL 8.4.8と9.0.4より前のpg_upgradeとpg_migratorを使用して、PostgreSQLインストレーションをアップグレードした場合、おそらくこの不具合の影響を受けます。
より正確にいうと、アップグレード以前に非常に古いレコードを持つTOASTテーブル(圧縮されたデータ拡張)を持つユーザに影響します。 しかし事後に検証することは困難ですので、PostgreSQLプロジェクトはpg_upgradeを使用したユーザすべてが以下の整理スクリプトを実行することを推奨します。
影響を受けるグループのユーザは、後述の不具合が発生することを防ぐために、できる限り早く整理スクリプトを実行しなければなりません。
How do I know if I am being affected by the bug?
一般的には、アップグレードの後すぐに問題に遭遇することはありません。 そうではなく、アップグレードしてから数ヶ月あるいは数週間後に、以下のようなエラーメッセージがセッションまたはログに出力されることになります。
ERROR: could not access status of transaction ###### DETAIL: could not open file "pg_clog/####": No such file or directory
このエラーのため一部の問い合わせを実行することができなくなります。
Resolving the errors
上のような(clogファイルの欠落に関する)エラーになった場合、可能であれば、PostgreSQLデータディレクトリのバックアップから欠落したclogファイルをリストアしなければなりません。 要求されたclogファイルより小さいclogファイルが存在する場合、"周回"が起きていますので、より深刻な破損が起こることなく、修正を適用するための時間が短くなるかもしれません。 要求されたファイルによりカバーされるところまでclogが進行することを防ぐために、データベースへのアクセスを禁止することを検討してください。 clogが周回してエラーが発生したところまで進行すると、これまではエラーになったレコードは突然可視になるかもしれませんし、(新しいclogがアボートされたものと記録された場合)他のレコードが消失してしまうかもしれません。
clogファイルはトランザクションのコミット/アボート状態を保持するものであり、新しいclogファイルが作成された後めったに変更されません。
clogのリストア処理は以下のようになります。
PostgreSQLシステムを停止してください。(PostgreSQLに部分的なclogファイルを参照させたくありません。) postgresql.confを編集し、autovacuum_freeze_max_ageを500000000 (500m)まで増やしてください。 できる限り多くのclogファイルをリストアしてください。ここでclogファイルはpg_clog内の既存のclogファイルより大きくないものです。また既存のファイルを上書きしてはいけません。*既存のclogファイルを上書きしないように注意してください* リストアが完了した後PostgreSQLシステムを起動してください。 理想をいうと、クラスタ全体に'VACUUM FREEZE;'を(すべてのデータベースで)実行してください。 注意:これは*多くの*I/Oが発生します。また、完了まで時間がかかるかもしれません。 これはコマンドラインからvacuumdb -a -v -Fを行うことで実現できます。 代替案として(すべてのデータベースに対して)上のスクリプトを実行してください。 clogファイルをリストアしなければならなかった場合、テーブルごとにVACUUM FREEZEコマンドを実行する時に、あまりに早 く削除される可能性がありますので、再度clogをリストアする準備を行ってください。 (VACUUM FREEZEの実行は必須です! この処理を忘れないでください。さもないとclogが再び削除され問題が再発するかもしれません!)
pg_clogディレクトリのバックアップがない場合、この段階で問題を解消することは非常に多くのことが関連します。 この段階では、PostgreSQLコミュニティのハッカーの助けが必要になるでしょう。 irc.freenode.netの#postgresqlチャンネルにリクエストする、pgsql-adminまたはpgsql-generalメーリングリストに投稿する、あるいはbruce -at- postgresql.org宛にメールをしてください。
Will I lose any data due to this error?
欠落したclogファイルに関するエラーが発生し、これらのclogファイルのバックアップがない場合はYESです。 まだ欠落したclogファイルによるエラーが発生していない場合、この問題はわずかな停止時間で解消できるはずです。 エラーが発生し、そのclogのバックアップが*ない*場合、できる限り早くこれに対応することが*非常に重要*です。さもないとデータを失うことになります。 すでに(すべてのデータベースで)クラスタ全体の'VACUUM FREEZE;'を実行していた場合(通常ありませんが)、すでに安全です。
What is the underlying cause of this bug?
原因は、pg_upgradeが適切いTOASTテーブルのpg_class.relfrozenxidをリストアしていなかったことです。 TOASTテーブルは、8kのヒープページに収まらない大きな値を格納するために使用されるものです。 TOAST Storage日本語版を参照してください
How can I fix my cluster if I already used pg_upgrade that had this bug?
上記アナウンスには実行しなければならないスクリプトが含まれています。 これは効果的にすべてのTOASTトランザクションIDを凍結状態とし、その状態はpg_clogファイルに依存しないようにします。 TOASTテーブルに対してpg_class.relfrozenxidが適切に設定されていませんので、これが必要です。 タプルの凍結はautovacuumにより実行される一般的な処理です。 ですので、この修正は実際には、通常必要になる前にこの処理を実行しているだけです。
What if I can't run the fix promptly?
できないのであれば、スクリプトを実行できるようになる前に再利用されないように、data/pg_clogディレクトリの内容を安全なバックアップにコピーしてください。
I am running the clean-up script, but it's causing too much I/O and my database is unresponsive. What do I do?
まずスクリプトを止めてください。
そしてvacuum_cost_delayを増やしてください。 これによりスクリプトは時間がかかるようになりますが、激しいI/Oは減少します。 スクリプトを実行するセッションで、スクリプトを始める前にまず以下を行ってください。
SET vacuum_cost_delay = 40; SET vacuum_cost_limit = 200;
その後、スクリプトを再実行してください。
How was this bug fixed in Postgres 8.4.8 and 9.0.4
TOASTテーブルについてのpg_class.relfrozenxidを適切にリストアするようにpg_dumpを修正します。
Who discovered this bug?
この問題はirc.freenode.net #postgresql上で二人のユーザから報告され、Andrew GierthとBruce Momjianにより診断されました。