2003年12月,PostgreSQL 7.3系と7.4系に,バグ修正などが行われたマイナー・バージョンアップ版が相次いでリリースされた。

PostgreSQL 7.3.5で,ルールの書き方によって参照整合性制約がチェックされないバグを修正

 PostgreSQL 7.3系列の最新版7.3.5が2003年12月3日にリリースされた。PostgreSQL開発チームによれば,7.3.5は7.3系列としては最後のリリースになるとのことである。7.3.5での修正にはセキュリティ・ホールの修正やデータベース・エンジンの深刻な致命的な問題に対する修正は含まれていないので,今すぐ7.3.5にアップグレードする必要性は低い。ただし,これから7.3系を新たに使い始めるのであれば,7.3.5を使うことをお勧めする。

 7.3.4から7.3.5で修正された分野は以下のものである。

  • データベース・エンジン本体
  • statistics collector(統計情報の収集デーモン)
  • libpq
  • pg_dump
  • clusterdb
  • plpython
  • SSL
  • JDBCドライバ
  • contrib/dblink

     主な修正内容としては,以下のものがある。

    (1) インデックスの更新と検索が同時に行われている場合,ごくまれに検索結果が正しくないことがあったバグの修正

    (2) ルールの影響で参照整合性制約チェックがすり抜けられてしまうことがあるバグの修正

     詳しくはSRAが公開しているPostgreSQL 7.3.5に関する技術情報のページを参照していただきたい。ここでは再現性が高く,またデータの一貫性が失われる可能性のあるルールに関するバグ修正の情報をお届けする。

     ルール(rule)とは,PostgreSQL独自の機能で,INSERT/UPDATE/DELETEを実行する際に指定したアクションを実施するものである。PostgreSQLではルールはビューの実装に用いられているほか,アクションにログ用のテーブルへの記録を指定しておき,テーブルへの更新を監視するなどの用途がある。

     ルールは機能的にはトリガ(trigger)と似ているが,トリガでは監視対象のテーブルの行が更新されるごとにトリガ起動されるのに対し,ルールは基本的に問い合わせの書き換えであり,更新対象の行が多い場合にはトリガは負荷が高い。ただし,ルールとトリガの機能は完全に一致しているわけではなく,ルールでできてトリガではできないこともあるし,その逆もある。そこでPostgreSQLではルールとトリガを使い分けている。

     今回発見・修正されたバグは,ある条件のもとでルールのアクションの中で挿入されたデータが参照整合性制約をすり抜けてしまう,というものである。

     リスト1は,そのバグを再現するスクリプトである(このスクリプトは,PostgreSQL 開発者の Jan Wieck氏がバグの再現例としてメーリングリストに報告したものを簡略化したものである)。テーブルt2に対してINSERTが実行されると,ルールt2_insが起動される。t2_insは以下の処理を行う。

    (1) もし同じiを持つ行が存在しなければ,行を挿入する。
    (2) 同じiを持つ行jの値を+1する。

     このとき,iはテーブルt1のi列への外部キーであるため,本来ならばt1に登録されていないi=3を挿入できないはずであるが,7.3.4では挿入できてしまっている。

     このバグは,INSERTで起動されたルールの中で,DO INSTEADルールによって同じ行が更新されるときに限って発生する。このようなルールの使い方をしている方は7.3.5へのアップグレードで問題を解決できるはずだ。

    リスト1●7.3.4で参照整合性制約がチェックされないルールの例

    CREATE TABLE t1 (
        i INTEGER PRIMARY KEY
    );
    psql:/tmp/rule.sql:4: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 't1_pkey' for table 't1'
    CREATE TABLE
    INSERT INTO t1 VALUES (1);
    INSERT 1690721 1
    INSERT INTO t1 VALUES (2);
    INSERT 1690722 1

    CREATE TABLE t2 (
      i INTEGER PRIMARY KEY,
      j INTEGER DEFAULT 0,
      CONSTRAINT myconstraint FOREIGN KEY(i)
      REFERENCES t1(i)
    );
    psql:/tmp/rule.sql:15: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 't2_pkey' for table 't2'
    psql:/tmp/rule.sql:15: NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
    CREATE TABLE
    CREATE rule t2_ins AS ON INSERT TO t2
      WHERE (EXISTS (SELECT 1 FROM t2
          WHERE i = new.i))
      DO INSTEAD UPDATE t2 SET j = j + 1
      WHERE i = new.i;
    CREATE RULE
    INSERT INTO t2 VALUES (1);
    INSERT 1690733 1
    SELECT * FROM t2;
    i | j
    ---+---
    1 | 1
    (1 row)

    INSERT INTO t2 VALUES (2);
    INSERT 1690734 1
    SELECT * FROM t2;
    i | j
    ---+---
    1 | 1
    2 | 1
    (2 rows)

    INSERT INTO t2 VALUES (1);
    INSERT 0 0
    SELECT * FROM t2;
    i | j
    ---+---
    2 | 1
    1 | 2
    (2 rows)

    INSERT INTO t2 VALUES (3); <--- 本来参照整合性制約違反でエラーになるはず
    INSERT 1690735 1
    SELECT * FROM t2;
    i | j
    ---+---
    2 | 1
    1 | 2
    3 | 1
    (3 rows)

    PostgreSQL 7.4.1リリースではFSMやインフォメーション・スキーマのバグを修正

     昨年11月にリリースされた7.4のバグ修正版である7.4.1が,2003年12月22日に早くもリリースされた。日本PostgreSQLユーザ会(JPUG)では,早くもPostgreSQL7.4.1のマニュアルの日本語版をリリースした。http://www.postgresql.jp/document/pg74doc/index.htmlからダウンロードできるので利用されたい。

    7.4から7.4.1で修正された分野は以下のものである。

  • データベースエンジン本体
  • インフォメーション・スキーマ
  • configure
  • ecpg
  • SSL
  • JDBCドライバ
  • contrib/pg_autovacuum
  • contrib/cube
  • contrib/dblink

     主な修正内容としては,以下のものがある。

    (1)FSMの扱いに関するバグ修正

    (2)副問い合わせを使うとバックエンドが落ちることがあったバグの修正

     詳しくはこれもSRAが公開しているPostgreSQL 7.4.1に関する技術情報のページを参照していただきたい。

     7.4.1で修正されたバグでクリティカルなものはFSM(Free Space Map)に関するものである。FSMは,VACUUMがテーブルなどの再利用可能領域に関する情報を管理するためのテーブルで,共有メモリー上に確保されている。7.4ではこの管理ルーチンにバグがあり,VACUUMの最中に,

    PANIC: insufficient room in FSM
    というエラーが出てバックエンドが再起動を余儀なくされることがあった。FSMに問題があるとデータベースの更新や削除の処理で重大な支障を来たすため,7.4のユーザーはすみやかに7.4.1に移行することをお勧めする。

     インフォメーション・スキーマ(INFORMATION SCHEMA)は,7.4から導入された新機能である。インフォメーション・スキーマはシステム・カタログをアクセスするためのビューの集合体であり,ビューをアクセスすることによってテーブルのリストやテーブルに関するシステムの情報を取得できる(インフォメーション・スキーマについてはPostgreSQLウォッチ第3回を参照されたい)。

     7.4.1ではインフォメーション・スキーマの修正が行われたが,インフォメーション・スキーマはデータベースクラスタの構築時にインストールされるため,インフォメーション・スキーマを修正するためには本来はデータベースクラスタをバックアップの上,再度initdbする必要がある。しかし,それではあまりに不便なので,インフォメーション・スキーマのみを更新することもできる。その方法についてはPostgreSQLに付属のHISTORYか,上記URLを参照されたい。

    開発中の7.5ではチェックポイント処理のジレンマを解決へ

     開発が始まったばかりの7.5だが,久々にバッファ管理やトランザクション・システムなどに手が入れられ,性能面での向上努力がなされている.特に目を引くのは,トランザクションの管理のために新しいプロセスが導入されたことである。管理プロセスが追加されたのは統計情報収集用にプロセスが導入されて以来のことであり,PostgreSQLの歴史の中でも画期的な出来事であると言える。

     PostgreSQLは,ディスク・アクセスを軽減するために共有メモリー上にバッファを持っている。このバッファはディスク上の固定長(デフォルトでは8192バイト) の「ページ」に対応している。データベースがアクセスされると,いったんページはバッファに読み込まれる。データベースを更新する際はこのバッファを修正する。修正され,かつまだディスクに書き込まれていないバッファは「ダーティ・バッファ」と呼ばれる。

     利用が終わったバッファは再利用可能なバッファとして登録されるが,この時点ではディスクへの書き込みは行われず,次にそのバッファを再利用するまではディスクへの書き込みは遅延される。

     ただ,ここでも「書き込み」は実際にはディスクにすぐには書かれないことが多い。OSが持つキャッシュのためである。もちろんデータベースへの変更はトラザンクション・ログに書かれているので,バッファの内容が確実にディスクに書かれなくても問題ないのであるが,次にデータベースを立ち上げたときに長時間にわたってトランザクション・ログから復旧を行う「リカバリ処理」が走ってしまう。

     そこでPostgreSQLでは定期的にバッファの内容を確実にディスクに書き込む「チェックポイント」と呼ばれる処理を行う。問題は,このときに大量のディスク・アクセスが発生することである。チェックポイントでのディスク・アクセスは,物理メモリーが多いほど,またバッファが多いほど多くなる。性能を改善するためにメモリーを増やすほどチェック・ポイント処理が重くなってしまうとい ジレンマがあったわけだ。

    バックグラウンド・ライター・プロセスの導入で商用DBMSに近づく

     そこで7.5で導入されたのがバックグラウンド・ライター・プロセス(background writer process)である。バックグラウンド・ライター・プロセスはpostmasterから起動され,以後postmasterが終了するまで常駐する。バックグラウンド・ライター・プロセスは定期的にダーティ・バッファがないかどうか調べ,あればそれをディスクに書き込む。この結果,チェックポイント時のディスク・アクセスが減少する他,バッファを再利用する際に書き込みを行う必要性が減る。

     また,バックグラウンド・ライター・プロセスのために新しい設定項目(GUCパラメータ)が増えている。

    bgwriter_delay
    バックグラウンド・ライター・プロセスが処理を行う際のインターバル(デフォルトは200ミリ秒ごとに処理を行う)
    bgwriter_percent
    1回の処理ごとに書き込みを行うバッファの割合(%)。デフォルトは1%
    bgwriter_maxpages
    1回の処理ごとに書き込みを行うバッファ数。デフォルトは100。
     なお,これらの情報は本稿執筆時点(2004年1月上旬)のものであり,今後開発と共に大幅に変る可能性があることをお断りしておく。また,現時点ではバックグラウンド・ライター・プロセスはディスクへの強制書き込み(fsyncなど) をまだ行っておらず,実装としては完成していない。そのため今回は特に性能測定などは行っていないが,今後完成度が上がった時点で測定を行って報告したいと考えている。

     バックグラウンド・ライター・プロセスは多くの商用DBMSにも実装されており,PostgreSQLはこの分野でも商用DBMSにますます近づいていると言えよう。

    石井達夫(Tasuo Ishii)

    ■著者紹介
    石井達夫(いしい・たつお)氏
    1984年,SRA入社。主にUNIX関連の開発に従事するかたわら,95年からPostgreSQLのメーリング・リストを主宰。現在はオープンソースソリューション部でPostgreSQL関連のビジネス活動を技術支援。著書に『PostgreSQL完全攻略ガイド』(技術評論社),『PHPxPostgreSQLで作る最強Webシステム』(技術評論社),『PostgreSQL構築・運用ガイド』(日経BP,共著)などがある。日本PostgreSQLユーザ会理事長。