最も単純なケースでは、新しい行をテーブルに挿入すると(そしてトランザクションがコミットすると)、それは後続のすべてのトランザクションから見えるようになります。この例では、xmax
が0であることを確認してください。
_CREATE TABLE vis (
id serial,
is_active boolean
);
INSERT INTO vis (is_active) VALUES (FALSE);
SELECT ctid, xmin, xmax, * FROM vis;
ctid │xmin │ xmax │ id │ is_active
───────┼─────┼──────┼────┼───────────
(0,1) │2699 │ 0 │ 1 │ f
_
これを更新すると(フラグが誤ってFALSE
に設定されていたため)、少し変更されます。
_UPDATE vis SET is_active = TRUE;
SELECT ctid, xmin, xmax, * FROM vis;
ctid │ xmin │ xmax │ id │ is_active
──────┼──────┼──────┼────┼───────────
(0,2) │ 2700 │ 0 │ 1 │ t
_
[〜#〜] mvcc [〜#〜] PostgreSQLが使用するモデルによると、新しい物理行が書き込まれ、古い行が無効化されました(これは ctid
から確認できます) =)。新しいトランザクションは、後続のすべてのトランザクションから見えます。
ここで、UPDATE
をロールバックすると興味深いことが起こります。
_BEGIN;
UPDATE vis SET is_active = TRUE;
ROLLBACK;
SELECT ctid, xmin, xmax, * FROM vis;
ctid │ xmin │ xmax │ id │ is_active
───────┼──────┼──────┼────┼───────────
(0,2) │ 2700 │ 2702 │ 1 │ t
_
行のバージョンは同じままですが、xmax
が何かに設定されています。これにもかかわらず、後続のトランザクションはこの(そうでなければ変更されていない)行を見ることができます。
これについて少し読んだ後、行の可視性についていくつかのことを理解できます。 visibility map はありますが、ページ全体が表示されているかどうかを示すだけで、行(タプル)レベルでは確実に機能しません。次に、コミットログ(別名clog
)がありますが、Postgresは、ログにアクセスする必要があるかどうかをどのように判断しますか?
infomask bits を見て、可視性が実際にどのように機能するかを理解することにしました。それらを表示するには、最も簡単な方法は pageinspect extension を使用することです。設定されているビットを確認するために、それらを格納するテーブルを作成しました。
_CREATE TABLE infomask (
i_flag text,
i_bits bit(16)
);
INSERT INTO infomask
VALUES
('HEAP_HASNULL', x'0001'::bit(16)),
('HEAP_HASVARWIDTH', x'0002'::bit(16)),
('HEAP_HASEXTERNAL', x'0004'::bit(16)),
('HEAP_HASOID', x'0008'::bit(16)),
('HEAP_XMAX_KEYSHR_LOCK', x'0010'::bit(16)),
('HEAP_COMBOCID', x'0020'::bit(16)),
('HEAP_XMAX_EXCL_LOCK', x'0040'::bit(16)),
('HEAP_XMAX_LOCK_ONLY', x'0080'::bit(16)),
('HEAP_XMIN_COMMITTED', x'0100'::bit(16)),
('HEAP_XMIN_INVALID', x'0200'::bit(16)),
('HEAP_XMAX_COMMITTED', x'0400'::bit(16)),
('HEAP_XMAX_INVALID', x'0800'::bit(16)),
('HEAP_XMAX_IS_MULTI', x'1000'::bit(16)),
('HEAP_UPDATED', x'2000'::bit(16)),
('HEAP_MOVED_OFF', x'4000'::bit(16)),
('HEAP_MOVED_IN', x'8000'::bit(16)),
('HEAP_XACT_MASK', x'FFF0'::bit(16));
_
次に、vis
テーブルの内容を確認しました。pageinspect
はヒープの物理的な内容を示しているため、可視の行だけが返されるわけではありません。
_SELECT t_xmin, t_xmax, string_agg(i_flag, ', ') FILTER (WHERE (t_infomask::bit(16) & i_bits)::integer::boolean)
FROM heap_page_items(get_raw_page('vis', 0)),
infomask
GROUP BY t_xmin, t_xmax;
t_xmin │ t_xmax │ string_agg
────────┼────────┼──────────────────────────────────────────────────────
2699 │ 2700 │ HEAP_XMIN_COMMITTED, HEAP_XMAX_COMMITTED
2700 │ 2702 │ HEAP_XMIN_COMMITTED, HEAP_XMAX_INVALID, HEAP_UPDATED
2702 │ 0 │ HEAP_XMIN_INVALID, HEAP_XMAX_INVALID, HEAP_UPDATED
_
上記から私が理解しているのは、最初のバージョンがトランザクション2699で実現し、その後2700で新しいバージョンに正常に置き換えられたことです。
次に、2700年から存続していた次のものは、2702年に_HEAP_XMAX_INVALID
_から見たUPDATE
のロールバック試行がありました。
_HEAP_XMIN_INVALID
_が示すように、最後のものは実際には決して生まれませんでした。
したがって、上記から推測すると、最初と最後のケースは明白です-それらはトランザクション2703以降ではもう見えません。
2つ目はどこかで検索する必要があります-おそらくclog
として知られるコミットログだと思います。
問題をさらに複雑にするために、後続のUPDATE
は次のようになります。
_ t_xmin │ t_xmax │ string_agg
────────┼────────┼────────────────────────────────────────────────────
2699 │ 2700 │ HEAP_XMIN_COMMITTED, HEAP_XMAX_COMMITTED
2702 │ 0 │ HEAP_XMIN_INVALID, HEAP_XMAX_INVALID, HEAP_UPDATED
2703 │ 0 │ HEAP_XMAX_INVALID, HEAP_UPDATED
2700 │ 2703 │ HEAP_XMIN_COMMITTED, HEAP_UPDATED
_
ここでは、すでに表示されている可能性がある2つの候補が表示されています。だから、最後に、ここに私の質問があります:
clog
が可視性を判別するために参照する場所であるという私の想定はありますか?clog
にアクセスするように伝えるフラグ(またはフラグの組み合わせ)はどれですか?clog
の内部を調べる方法はありますか?以前のバージョンのPostgresでのclog
の破損についての言及と、偽のファイルを手動で作成できるというヒントがあります。この情報は、非常に役立ちます。したがって、上記から推測すると、最初と最後のケースは明白です-それらはトランザクション2703以降ではもう見えません。 2つ目は、どこかで検索する必要があります。これは、コミットログ(別名clog)だと思います。
2つ目はHEAP_XMAX_INVALID
です。つまり、誰かがすでにそうしているので、xmax
が中止されていることを確認し、「ヒントビット」を設定して、今後のプロセスが再度clogにアクセスする必要がないように、clogを参照する必要はありません。その行のため。
どのフラグ(またはフラグの組み合わせ)がシステムに詰まりを訪問するように伝えますか?
heap_xmin_committed
またはheap_xmin_invalid
がない場合は、クロッグにアクセスして、xminの性質を確認する必要があります。トランザクションがまだ進行中の場合、行は表示されず、フラグを設定できません。トランザクションがコミットまたはロールバックされた場合は、heap_xmin_committed
またはheap_xmin_invalid
を適宜設定します(これが便利な場合-必須ではありません)。将来の人々はそれを調べる必要がありません。 。
xmin
が有効でコミットされており、xmax
がゼロではなく、heap_max_committed
またはheap_max_invalid
がない場合は、clogにアクセスして何を確認する必要がありますそのトランザクションの性質はそうでした。
下駄の内容を調べる方法はありますか?以前のバージョンのPostgresでのclogの破損についての言及と、偽のファイルを手動で作成できるというヒントがあります。この情報は、非常に役立ちます。
ユーザーフレンドリーな方法を私は知りません。 "od"を使用して、clogファイルを適切な方法でダンプして検査し、src/backend/access/transam/clog.c
で定義されたマクロを使用して検査する場所を特定できます。
PGXNに機能する拡張機能がないことに驚いていますが、見つかりませんでした。しかし、サーバーが実行されていないときに実際にこれを実行できるようにする必要があるので、それほど便利ではないと思います。
HeapTupleSatisfiesMVCC() の実装を見てください。実際のclog
チェックは TransactionIdDidCommit() で行われますが、トランザクションステータスを推測できない場合にのみ呼び出されます情報マスクビット( HeapTupleHeaderXminCommitted()マクロ およびその仲間)。
関数TransactionDidCommit()
およびTransactionDidAbort()
へのpg_clog
へのアクセスをたどって、これらが呼び出された場所を調べたところ、質問に関連するコード内の唯一の場所が表示されましたHeapTupleSatisfiesMVCC()
にあります。この関数のコードから、タプルに関連するinfomaskビットが設定されていない場合にのみ、実際のclogルックアップが発生することがわかります。コードは、HeapTupleHeaderXminCommitted()
などでビットをチェックすることから始まります。また、目詰まりの検索は、ビットが設定されていない場合にのみ発生します。