作者:瀚高PG实验室(Highgo PG Lab)-Chrisx
# LSN与段文件的关系
@[toc]
## LSN
LSN 是一个指向WAL中的位置的指针
在内部,一个 LSN 是一个 64 位整数,表示在预写式日志流中的一个字节位置。它被打印成 两个最高 8 位的十六进制数,中间用斜线分隔,例如16/B374D848。 pg_lsn类型支持标准的比较操作符,如=和 >。两个 LSN 可以用-操作符做减法, 结果将是分隔两个预写式日志位置的字节数。
## LSN与段文件
1. 通过内置函数可以知道LSN对应的段文件
```sql
postgres=# SELECT pg_current_wal_lsn(),pg_walfile_name( pg_current_wal_lsn() );
pg_current_wal_lsn | pg_walfile_name
--------------------+--------------------------
0/D015DF8 | 00000001000000000000000D
(1 row)
```
当前使用的wal段文件是00000001000000000000000D
2. lsn与段文件关系
LSN 由3部分组成 'X/YYZZZZZZ'
* X 表示WAL段文件名的中间部分,一个或两个符号;
* YY 表示WAL文件名的最后一部分;一个或两个符号;
* ZZZZZZ 是表示文件名内偏移量的六个符号。
如上,LSN 0/D015DF8,我们可以假设WAL文件名的中间部分将是0,最后一部分将是D,两者都是零填充到8个符号,因此分别是00000000和0000000D。它们串联在一起,为我们提供了一个以0000000 00000000D结尾的文件名。文件名的初始部分未知,初始部分代表服务器运行的时间线,在本例中为1,将零填充为其他部分,因此00000001为我们提供了最终名称00000001000000000000000D。
LSN的最后一部分是WAL文件中的偏移量,使用内置函数pg_walfile_name_offset()得到,也可转换成整数查看,
```sql
postgres=# SELECT pg_walfile_name_offset('0/D015DF8'),( x'015DF8' )::int AS offset;
pg_walfile_name_offset | offset
----------------------------------+--------
(00000001000000000000000D,89592) | 89592
(1 row)
```
可以得到对应关系
| NAME | 时间线 | 中间部分 | 最后部分 | 偏移量 |
| ---- | -------- | -------- | --------- | ------ |
| LSN | | 0 | D | 015DF8 |
| WAL | 00000001 | 00000000 | 00000000D | 89592 |
:warning: 请注意,上面的示例只是展示这个概念,但是最好使用函数pg_walfile_name() 从LSN获取确切的WAL文件名,因为WAL切换可能导致LSN “手动解码” 的错误结果。
总而言之,给定一个特定的LSN,数据库能清楚地知道(而且必须清楚地知道)LSN所指的WAL文件段,以及在该文件中可以找到数据的确切偏移量。