[pgsql-jp: 32120] Rule と Lock

Tsunehisa Kazawa kazawa @ ca2.so-net.ne.jp
2004年 1月 26日 (月) 23:19:58 JST


皆さんこんばんは。加澤と申します。

Rule を利用した際の Lock の挙動について、よく分からない挙動に悩まされて
います。

ちょっと長くなってしまいますが順を追って説明します。

■環境
Debian 3.0 (woody)
PostgreSQL 7.4.1 (ソースからインストールしたもの)

1. テーブルを作成

まず、次のような同じ構造を持つ3つのテーブルを作成します。

create table daily_log (
    log_date timestamp default current_timestamp,
    log_memo varchar
);
create table daily_log01 (
    log_date timestamp default current_timestamp,
    log_memo varchar
);
create table daily_log02 (
    log_date timestamp default current_timestamp,
    log_memo varchar
);

上記はそれぞれ、insert 用代表テーブルと、実際のデータが格納される実テー
ブル2つ、という位置づけとなります。

2. ルールを設定

次に、一番上の daily_log テーブルに次のようなルールをセットします。

create rule insert_daily_log01 as on insert to daily_log
    where 1=0
    do instead insert into daily_log01 select NEW.*;
create rule insert_daily_log02 as on insert to daily_log
    where 1=1
    do instead insert into daily_log02 select NEW.*;

※上記例ではあまり意味のない条件 (where 句) を指定していますが、実際には
例えば origin からの日数 mod 2 が 0 か 1 か、というような条件になるわけ
です。

# 勘の良い方はピンと来たかもしれませんが、つまり、Oracle にある
# パーティション表のようなことを rule を使ってやろうとしているの
# です。

3. テスト

さて、この段階で daily_log テーブルに何か値を insert すると、ルールによ
り実際には daily_log02 テーブルへの insert へ置き換えられます。

testdb=# insert into daily_log (log_memo) values ('hoge');
INSERT 0 0
testdb=# select * from daily_log;
 log_date | log_memo
----------+----------
(0 rows)

testdb=# select * from daily_log01;
 log_date | log_memo
----------+----------
(0 rows)

testdb=# select * from daily_log02;
          log_date          | log_memo
----------------------------+----------
 2004-01-26 22:32:58.438084 | hoge
(1 row)

4. 別セッションからロック

ここで、異なるセッションから daily_log01 テーブル (データが入らない方の
実テーブル) を share mode でロックします。

testdb=# begin;
BEGIN
testdb=# lock table daily_log01 in share mode;
LOCK TABLE

これは copy コマンド等によるデータ抜き&truncate による表の切り捨てを行
うことを想定しています (データ抜き&切り捨て中に書込みが発生し、データ消
失してしまうことを防ぐ)。

5. なぜか元のセッションからの insert がブロック!

問題はここです。この時、元のセッションで再びログを insert しようとする
と、(ルールにより実際に書込まれるのはロックされていない daily_log02 側で
あることは明らかなのに) insert がブロックされてしまうのです!

testdb=# insert into daily_log (log_memo) values ('hoge');
←ここでブロック!

***

もちろん、lock していた transaction が終了すれば、ブロックされていた
insert 分も正常に実行され、ごく普通に daily_log02 テーブルにデータが書込
まれます。

分からないのは、どうして実際にはデータが書込まれない daily_log01 テーブ
ルの lock によって、ルールにより変換される daily_log への insert 自体が
ブロックされてしまうのか、です。ルールで更新される可能性のあるテーブル
は、条件に合致しようとしなかろうと、share mode の lock と競合するなんら
かのロックを取得してしまうのでしょうか?

下記 SQL リファレンスに、「条件に合致するしないに関らず、NOTIFY は無条件
に実行されてしまう」という怪しげな文がありますが、何らかのロックもこれと
同様の動きとなってしまうのでしょうか?

http://www.postgresql.jp/document/pg74doc/html/sql-createrule.html

Rule と Lock に関するこの挙動に関して、何かご存じの方はいらっしゃいますか?

-- 
  ◇   加澤恒央 Tsunehisa KAZAWA
◇  ◇ mailto:kazawa @ ca2.so-net.ne.jphttp://www.digitune.org/




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