これはPostgreSQL Advent Calendar 2016の14日目の記事です。
これは何?
トランザクションを勉強し始めたけれど、本や記事を読んでいるだけでは分からない。自分の手でSQLを書きながら勉強したいからとりあえずPostgreSQLをインストールしたけれど、何かお手本がないとつらい。。
そんな時はPostgreSQLのソースコードに付属しているテストをお手本になるかもしれないという記事です。今回はデッドロックを起こすテストケースを例に説明します。
PostgreSQLのRegression Test
ソースコードの入手
PostgreSQLのソースコードを落とします
$ wget https://ftp.postgresql.org/pub/source/v9.6.1/postgresql-9.6.1.tar.gz
$ tar xf postgresql-9.6.1.tar.gz
$ cd postgresql-9.6.1/src/test/isolation
src/test/
配下には多くのテストが含まれています。今回はisolation/
配下のテストに注目します。
isolation testを見てみる
README
を見ると一つのデータベースに対して複数のトランザクションが同時に実行された時の動きをテストするものだと分かります。実際、ディレクトリのタイトルもisolation
(分離性:複数のトランザクションが互いに影響を与えないこと)となっています。
This directory contains a set of tests for concurrent behaviors in
PostgreSQL. These tests require running multiple interacting transactions, which requires management of multiple concurrent connections, and therefore can't be tested using the normal pg_regress program. ....
テスト自体はspecs/
配下1にあります。
今回は、デッドロックの勉強をしたいとします。deadlock-hogehoge.spec
ファイルはいくつかありますが、分かりやすそうなdeadlock-simple.spec
をお手本にします。
このファイルはあるテーブルa1
にs1さんとs2さんの二人が共有ロックを掛けた状態で、交互に専有ロックを掛けようとしデッドロックが起きるいうシナリオです。
ファイルの中身を見ます。
setup
{
CREATE TABLE a1 ();
}
teardown
{
DROP TABLE a1;
}
session "s1"
setup { BEGIN; }
step "s1as" { LOCK TABLE a1 IN ACCESS SHARE MODE; }
step "s1ae" { LOCK TABLE a1 IN ACCESS EXCLUSIVE MODE; }
step "s1c" { COMMIT; }
session "s2"
setup { BEGIN; }
step "s2as" { LOCK TABLE a1 IN ACCESS SHARE MODE; }
step "s2ae" { LOCK TABLE a1 IN ACCESS EXCLUSIVE MODE; }
step "s2c" { COMMIT; }
permutation "s1as" "s2as" "s1ae" "s2ae" "s1c" "s2c"
上記ファイルのsetup
などのキーワードはテストの自動実行をする際に利用されるものです。{}
の中にはSQL文が入ります。
構文 | 役割 |
---|---|
setup {} | テスト開始時に実行 |
teardown {} | テスト終了時に実行 |
session "hoge" | "hoge"という名前でデータベースに接続 |
step "stepName" {} | 各SQLに"stepName"という名前を付与 |
permutation "stepName1" "stepName2" | SQLを実行する順番をstep名で指定 |
isolation testを参考に自分でデッドロックを起こしてみる
上記のファイルに基づいて自分でデッドロックを起こしてみます。
- ターミナルを二つ立ち上げ
psql
コマンドを打ちます create table a1 ();
- 後は、二つのターミナルで交互に
permutation
に書かれた順番でSQLを書いていきます。 - デッドロックが起きるのを確認する
実際の実行結果は下記のようになりデッドロックが起きたことが確認できます。
test=# lock table a1 in exclusive mode;
ERROR: デッドロックを検出しました
DETAIL: プロセス 13154 は ExclusiveLock を データベース16385のリレーション26561 で待機していましたが、プロセス 13077 でブロックされました
プロセス 13077 は ExclusiveLock を データベース16385のリレーション26561 で待機していましたが、プロセス 13154 でブロックされました
HINT: クエリーの詳細はサーバログを参照してください
まとめ
この様にisolation testをお手本にすることでデッドロックを学ぶことができました。
他にも複数のテストがあるので、それを自分の手で実行することでデータベースの理解が深まるのではと思います。
-
通常この
spec/
配下のテストhoge.spec
をmake install-check
や./pg_isolation_regress hoge
をターミナルに打ち込み自動実行します。実行結果は、results/
に保存されexpected/
にある正解ファイルと比べられ正誤の判定が行われます。 ↩