PostgreSQL付属のリグレッションテストでトランザクションを学んでみる

  • 2
    いいね
  • 0
    コメント

これは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さんの二人が共有ロックを掛けた状態で、交互に専有ロックを掛けようとしデッドロックが起きるいうシナリオです。

ファイルの中身を見ます。

deadlock-simple.spec
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を参考に自分でデッドロックを起こしてみる

上記のファイルに基づいて自分でデッドロックを起こしてみます。

  1. ターミナルを二つ立ち上げpsqlコマンドを打ちます
  2. create table a1 ();
  3. 後は、二つのターミナルで交互にpermutationに書かれた順番でSQLを書いていきます。
  4. デッドロックが起きるのを確認する
    実際の実行結果は下記のようになりデッドロックが起きたことが確認できます。
test=# lock table a1 in exclusive mode;
ERROR:  デッドロックを検出しました
DETAIL:  プロセス 13154 は ExclusiveLock を データベース16385のリレーション26561 で待機していましたが、プロセス 13077 でブロックされました
プロセス 13077 は ExclusiveLock を データベース16385のリレーション26561 で待機していましたが、プロセス 13154 でブロックされました
HINT:  クエリーの詳細はサーバログを参照してください

まとめ

この様にisolation testをお手本にすることでデッドロックを学ぶことができました。
他にも複数のテストがあるので、それを自分の手で実行することでデータベースの理解が深まるのではと思います。


  1. 通常このspec/配下のテストhoge.specmake install-check./pg_isolation_regress hogeをターミナルに打ち込み自動実行します。実行結果は、results/に保存されexpected/にある正解ファイルと比べられ正誤の判定が行われます。 

この投稿は PostgreSQL Advent Calendar 201614日目の記事です。