Open2

Google Datastreamの知見をためる場所

kumewatakumewata

DatastreamとPostgreSQLのLSNを比較する方法

背景

streamの転送を一時停止した後に、PostgreSQLのレプリケーションスロットで認識する最後のLSN (=log sequence number)とDatastreamのfetchログが示すLSNが一致することを確かめたかった。
それぞれで出力値の型が異なるため、変換方法を知る必要があった。

LSNの型について

  • PostgreSQL: pg_lsn型
pg_lsn型はWALの位置を示すLSN(Log Sequence Number)データを格納するために使用します。
この型はXLogRecPtrを示すPostgreSQLの内部的なシステムの型です。
内部的にはLSNは64bit整数型で、WALストリームのバイト位置を表現します。
LSNは例えば、16/B374D848のように2つのスラッシュで分けられた8桁の16進数で表示されます。
pg_lsnは例えば、=や>などの標準の比較演算子をサポートしています。
 2つのLSNは-演算子を使い引き算することも可能で、結果はこれらの2つのWALの位置のbytes差分です。
また、バイト数はそれぞれ+(pg_lsn,numeric)や-(pg_lsn,numeric)演算子を使って加算、減算ができます。
計算されたLSNはpg_lsn型の範囲、つまり、0/0とFFFFFFFF/FFFFFFFFの間にあるべきであることに注意してください。

https://www.postgresql.jp/docs/16/datatype-pg-lsn.html

例えばSELECT * FROM pg_replication_slots;で確認すると2つのLSN (restart_lsnとconfirmed_flush_lsn)を確認できる。

  • Datastream: 整数型 (10進数)
    ログの例
    CDC fetch completed. Latest fetched log sequence number: 10460157232, latest fetched event timestamp: 2024-07-23 05:11:27.371656.

結論

レプリケーションスロット情報のconfirmed_flush_lsnの値(pg_lsn型)から/を除いて16進数から10進数に変換する。

Pythonの例

>>> int('2/6F795530'.replace('/', ''), base=16)
10460157232

-> 前述したDatastreamのfetchログと同じタイミングで取得したconfirmed_flush_lsnを変換すると値が一致した。

参考

confirmed_flush_lsnについて

利用者がデータの受信を確認できている論理スロットのアドレス(LSN)。
このLSNより前にコミットされたトランザクションに対応するデータは、もはや有効ではありません。
物理スロットの場合はNULL。

https://www.postgresql.jp/document/16/html/view-pg-replication-slots.html