------------------------------------------------------------------------------
PG_MIGRATOR: 現場でPOSTGRESQLをアップグレード 
------------------------------------------------------------------------------

あるメジャーリリースから他のメジャーリリースにPostgreSQLデータベースをアップグレードすることは
費用の掛かる作業です。マイナリリースでは、単に新規実行形式をインストールするだけで、現在存在する
データの更新を心配する必要がありません。しかし、メジャーアップグレードでは、pg_dumpを使用して
全てのデータをエクスポートし、新規リリースをインストールし、新規クラスタをinitdbの実行で作成し、
そして旧データをインポートしなければなりません。巨大なデータがある場合、この作業は相応の時間を必
要とします。大きすぎるデータに対処するには、従来のデータに加えてエクスポートされたデータを共に格
納するに足り得る余裕が必要になるため、さらにストレージを購入しなければならない場合も考えられます。

多くのアップグレードの際に必要となる作業時間とディスク空間をpg_migratorは削減します。

------------------------------------------------------------------------------
何を行うのか
------------------------------------------------------------------------------

pg_migratorは現場で既存のデータの更新作業を行うツールです。アップグレードの中には、データのディ
スク上における表現形式を変更してしまいます。pg_migratorはこのようなアップグレードの手助けにはな
りません。しかし、多くのアップグレードはユーザ定義のテーブルのディスク上の表現形式を変更しません。
これらの場合、pg_migratorは旧データベースクラスタから新データベースクラスタに既存のユーザ定義の
テーブルを移動させることができます。

現場での移行が現実性を帯びるかどうかを決定する２つの要素が存在します。

第一に、クラスタ内の全てのテーブルは、テーブルヘッダ、テーブルトレイラー、およびタプルヘッダのディ
スク上の表現方式の同一のディスク上表現形式を共有します。もし、これが旧バージョンのPostgreSQLと新
規バージョンのPostgreSQLで変わっているとしたなら、既存のテーブルを新規クラスタに、pg_migrator
は移行することができません。旧データをpg_dumpし、そしてその後そのデータを新規クラスタにインポート
しなければなりません。

第二に、２つのメジャーPostgreSQLバージョン間で、全てのデータ型は同一のバイナリ形式でなければな
りません。

------------------------------------------------------------------------------
どのように動くのか
------------------------------------------------------------------------------

アップグレード間でpg_migratorを使用するには、新規のディレクトリで、最新のバージョンを使用して、
無垢のクラスタをインストールすることから始めます。インストールが終了すると、新規クラスタには、新
実行形式と、通常のtemplate0、template1、およびpostgresが含まれますが、ユーザ定義のテーブル
は含まれません。この時点で、新旧のpostmasterを共に停止し、pg_migratorを起動させます。

pg_migratorが起動された時点で、全ての必須実行形式が揃っていて、予期するバージョン番号が内包さ
れいているかどうかをpg_migratorが確証します。その検証手順は、同時に新旧の$PGDATAディレクトリ
が予期するファイルとディレクトリが正しく配置されているかを確認します。この確認手順が首尾良く完了
すれば、pg_migratorは旧postmasterを起動し、旧クラスタにあるメタデータを確保するため
pg_dumpall --schema-onlyを実行します。pg_dumpallで生成されたこのスクリプトは、新規クラス
タ内の全てのユーザ定義オブジェクトを再作成するため、後の手順で使用されます。

pg_dumpallで作成されたスクリプトはユーザ定義オブジェクトのみを再作成するだけで、システム定義の
オブジェクトは作成しないことに注意が必要です。新クラスタには最新バージョンのPostgreSQLで作成さ
れたシステム定義オブジェクトが存在します。

pg_migratorが旧クラスタからメタデータを一度取り出すと、既存のデータを含んだ新規クラスタを「同
期させる」のに必要な数多くの計算合わせ処理を行います。

最初に、pg_migratorは旧クラスタ内の全てのテーブル空間ディレクトリ名を一時的に変更します。新ク
ラスタは同一のテーブル空間ディレクトリを使用しなければならず、もしも最終段階でメタデータを
pg_migratorがインポートする際にそれらのディレクトリが存在していると、もう先には行きませんと不
満を漏らします。そして、旧サーバ列に格納されている全てのトランザクション情報を凍結します。

次にpg_migratorは、コミット状態情報と、旧クラスタから新クラスタへ「次に与えられるトランザクシ
ョン識別子」を複写します。この手順によって、新クラスタから特定のタプルが可視となることが保証され
ます。pg_migratorはユーザ定義のテーブルをインポート・エクスポートしないこと、従って新クラスタ
におけるトランザクション識別子は旧データでのトランザクション識別子と一致しなければならないことを、
思い出してください。pg_migratorは同時にログ先行書き込み（WAL）の開始アドレスを旧クラスタから
新クラスタに複写します。

ここまで来ると、pg_migratorは旧クラスタで定義されたそれぞれのデータベースに対しcreatedbを実
行し、旧クラスタから取得したメタデータを再構築します。

新クラスタで全てのデータベースが作成された暁には、pg_migratorはTOASTリレーションの名前付けに
挑戦します。TOASTテーブルは大きすぎる行を越えたデータ（つまり、分割れたテーブル）を格納するため
に使用されます。タプルからTOASTテーブルへデータを移動しようとサーバが判断した時点で、タプル内の
元となるスロットにポインタを格納します。そのポインタにはTOASTテーブルのrelfilenode（つまり、
ファイル名）が含まれます。これが示唆するところは、TOASTされたデータを含むどんなテーブルでも、そ
れぞれのTOASTポインタにおけるTOASTテーブルのファイル名を持っていることです。従って、新規クラス
タ内で新しく作成された時に、TOASTテーブルが旧名称を持ち続けることがとても大切です。
CREATE TABLEはTOASTテーブルに名前をつけることに何も関与しません。TOASTテーブル名が旧名を引き
継いでいることを確証するため、pg_migratorは旧クラスタからメタデータをインポートする前に、全て
のTOASTテーブルの名称を保存します。ファイル名反転のため、pg_migratorは単に適切な名前を付けた
空ファイルを作成し、サーバはその名前の衝突を検出すると無効にします。

次に、pg_migratorは以前にpg_dumpallが作成したスクリプトを実行します。このスクリプトは旧クラ
スタから新クラスタに全部揃ったユーザ定義メタデータを効果的に作成します。そのスクリプトが完了する
と、新postmasterを停止した後、pg_migratorはプレースホルダーTOASTテーブルを削除し、新クラス
タ内に適切なTOASTタプル名を設定します。

最後に、pg_migratorはそれぞれのユーザ定義テーブルとそれがサポートするインデックスとTOASTテー
ブルを旧クラスタから新クラスタへ、リンク、または複写します。この最後の手順でpg_migratorは、新
クラスタのpg_class.relfilenodeに一致するよう、それぞれのリレーションに新規名称を割り当てます。
上記で概要を示したように、TOASTファイル名は維持されます。

pg_migrator設計の重要な機能は、元となるクラスタが損傷されないようになっていることです。更新中
に問題が発生しても以前のバージョンを続けて使用することができます。
