====================================================== 1.An XLOG_SWITCH record can be written within a WAL page with plenty of free space remaining afterward: backend> insert into tt1 values(1); backend> select 'pg_current_wal_flush_lsn' as lsn_name, pg_current_wal_flush_lsn(), pg_walfile_name_offset(pg_current_wal_flush_lsn()) union all select 'pg_current_wal_insert_lsn', pg_current_wal_insert_lsn(), pg_walfile_name_offset(pg_current_wal_insert_lsn()) union all select 'pg_current_wal_lsn', pg_current_wal_lsn(), pg_walfile_name_offset(pg_current_wal_lsn()); 1: lsn_name (typeid = 25, len = -1, typmod = -1, byval = f) 2: pg_current_wal_flush_lsn (typeid = 3220, len = 8, typmod = -1, byval = t) 3: pg_walfile_name_offset (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_flush_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/060003B8" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000006,952)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_insert_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/060003B8" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000006,952)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/060003B8" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000006,952)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- backend> SELECT pg_switch_wal(); 1: pg_switch_wal (typeid = 3220, len = 8, typmod = -1, byval = t) ---- 1: pg_switch_wal = "0/060003D0" (typeid = 3220, len = 8, typmod = -1, byval = t) ---- Works fine: "0/060003B8" + 24(MAXALIGN(SizeOfXLogRecord)) == "0/060003D0" ====================================================== 2.An XLOG_SWITCH record may exactly fill a WAL page, leaving no free space afterward. backend> SELECT pg_switch_wal(); 1: pg_switch_wal (typeid = 3220, len = 8, typmod = -1, byval = t) ---- 1: pg_switch_wal = "0/07000000" (typeid = 3220, len = 8, typmod = -1, byval = t) ---- backend> insert into tt1 values(1); backend> select 'pg_current_wal_flush_lsn' as lsn_name, pg_current_wal_flush_lsn(), pg_walfile_name_offset(pg_current_wal_flush_lsn()) union all select 'pg_current_wal_insert_lsn', pg_current_wal_insert_lsn(), pg_walfile_name_offset(pg_current_wal_insert_lsn()) union all select 'pg_current_wal_lsn', pg_current_wal_lsn(), pg_walfile_name_offset(pg_current_wal_lsn()); 1: lsn_name (typeid = 25, len = -1, typmod = -1, byval = f) 2: pg_current_wal_flush_lsn (typeid = 3220, len = 8, typmod = -1, byval = t) 3: pg_walfile_name_offset (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_flush_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/07000090" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000007,144)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_insert_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/07000090" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000007,144)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/07000090" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000007,144)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- backend> SELECT pg_switch_wal(); 1: pg_switch_wal (typeid = 3220, len = 8, typmod = -1, byval = t) ---- Let¡¯s set a breakpoint at startbytepos = Insert->CurrBytePos; inside ReserveXLogSwitch(). This line advances Insert->CurrBytePos to a position MAXALIGN(SizeOfXLogRecord) bytes ahead within the current WAL page. GDB:set Insert->CurrBytePos = XLogRecPtrToBytePos(XLogBytePosToRecPtr(Insert->CurrBytePos) + (XLOG_BLCKSZ - XLogBytePosToRecPtr(Insert->CurrBytePos) % XLOG_BLCKSZ) - size) backend> SELECT pg_switch_wal(); 1: pg_switch_wal (typeid = 3220, len = 8, typmod = -1, byval = t) ---- 1: pg_switch_wal = "0/07002000" (typeid = 3220, len = 8, typmod = -1, byval = t) ---- backend> The LSN pair (000000010000000000000007,144) corresponds to the first block of WAL segment file 7. After writing the WAL record, the resulting EndPos value equals 8192, which maps to LSN 0/07002000. ====================================================== 3.Calling pg_switch_wal() twice consecutively does not trigger an actual WAL segment switch. backend> SELECT pg_switch_wal(); 1: pg_switch_wal (typeid = 3220, len = 8, typmod = -1, byval = t) ---- 1: pg_switch_wal = "0/08000000" (typeid = 3220, len = 8, typmod = -1, byval = t) ---- backend> SELECT pg_switch_wal(); 1: pg_switch_wal (typeid = 3220, len = 8, typmod = -1, byval = t) ---- select 'pg_current_wal_flush_lsn' as lsn_name, pg_current_wal_flush_lsn(), pg_walfile_name_offset(pg_current_wal_flush_lsn()) union all select 'pg_current_wal_insert_lsn', pg_current_wal_insert_lsn(), pg_walfile_name_offset(pg_current_wal_insert_lsn()) union all select 'pg_current_wal_lsn', pg_current_wal_lsn(), pg_walfile_name_offset(pg_current_wal_lsn()); 1: pg_switch_wal = "0/08000000" (typeid = 3220, len = 8, typmod = -1, byval = t) ---- backend> 1: lsn_name (typeid = 25, len = -1, typmod = -1, byval = f) 2: pg_current_wal_flush_lsn (typeid = 3220, len = 8, typmod = -1, byval = t) 3: pg_walfile_name_offset (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_flush_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/08000000" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000008,0)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_insert_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/08000028" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000008,40)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/08000000" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000008,0)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- backend> ====================================================== 4.Cross page boundaries within a single WAL segment file: backend> backend> insert into tt1 values(1); backend> select 'pg_current_wal_flush_lsn' as lsn_name, pg_current_wal_flush_lsn(), pg_walfile_name_offset(pg_current_wal_flush_lsn()) union all select 'pg_current_wal_insert_lsn', pg_current_wal_insert_lsn(), pg_walfile_name_offset(pg_current_wal_insert_lsn()) union all select 'pg_current_wal_lsn', pg_current_wal_lsn(), pg_walfile_name_offset(pg_current_wal_lsn()); 1: lsn_name (typeid = 25, len = -1, typmod = -1, byval = f) 2: pg_current_wal_flush_lsn (typeid = 3220, len = 8, typmod = -1, byval = t) 3: pg_walfile_name_offset (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_flush_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/08000090" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000008,144)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_insert_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/08000090" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000008,144)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/08000090" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000008,144)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- (000000010000000000000008,144) is the first segment file 8 backend> SELECT pg_switch_wal(); 1: pg_switch_wal (typeid = 3220, len = 8, typmod = -1, byval = t) ---- Let us do:4 bytes left on the first block, with the remaining 20 bytes on the subsequent block of the current WAL segment. GDB: set Insert->CurrBytePos = XLogRecPtrToBytePos(XLogBytePosToRecPtr(Insert->CurrBytePos) + (XLOG_BLCKSZ - XLogBytePosToRecPtr(Insert->CurrBytePos) % XLOG_BLCKSZ) - sizeof(uint32)) backend> SELECT pg_switch_wal(); 1: pg_switch_wal (typeid = 3220, len = 8, typmod = -1, byval = t) ---- 1: pg_switch_wal = "0/0800202C" (typeid = 3220, len = 8, typmod = -1, byval = t) ---- backend> select 'pg_current_wal_flush_lsn' as lsn_name, pg_current_wal_flush_lsn(), pg_walfile_name_offset(pg_current_wal_flush_lsn()) union all select 'pg_current_wal_insert_lsn', pg_current_wal_insert_lsn(), pg_walfile_name_offset(pg_current_wal_insert_lsn()) union all select 'pg_current_wal_lsn', pg_current_wal_lsn(), pg_walfile_name_offset(pg_current_wal_lsn()); 1: lsn_name (typeid = 25, len = -1, typmod = -1, byval = f) 2: pg_current_wal_flush_lsn (typeid = 3220, len = 8, typmod = -1, byval = t) 3: pg_walfile_name_offset (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_flush_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/09000000" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000009,0)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_insert_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/09000028" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000009,40)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/09000000" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000009,0)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- backend> #result: pg_switch_wal = "0/0800202C"£ºthe same segment file£¬ 202C==8236 , page no. is 8236/XLOG_BLCKSZ==1, position==8236%XLOG_BLCKSZ=44(last 20 bytes of switch wal + 24(MAXALIGN(SizeOfXLogRecord))) The LSN returned by pg_switch_wal() is 0/0800202C, which belongs to the same WAL segment file. Here, 0x202C equals decimal 8236. Block number: 8236 / XLOG_BLCKSZ = 1 Intra-block offset: 8236 % XLOG_BLCKSZ = 44 This offset of 44 corresponds to the trailing 20 bytes of the switch WAL record plus 24 bytes from SizeOfXLogShortPHD. ====================================================== 5.This WAL record will cross both page boundaries and WAL segment files. backend> insert into tt1 values(1); backend> select 'pg_current_wal_flush_lsn' as lsn_name, pg_current_wal_flush_lsn(), pg_walfile_name_offset(pg_current_wal_flush_lsn()) union all select 'pg_current_wal_insert_lsn', pg_current_wal_insert_lsn(), pg_walfile_name_offset(pg_current_wal_insert_lsn()) union all select 'pg_current_wal_lsn', pg_current_wal_lsn(), pg_walfile_name_offset(pg_current_wal_lsn()); 1: lsn_name (typeid = 25, len = -1, typmod = -1, byval = f) 2: pg_current_wal_flush_lsn (typeid = 3220, len = 8, typmod = -1, byval = t) 3: pg_walfile_name_offset (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_flush_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/090000F8" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000009,248)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_insert_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/090000F8" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000009,248)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/090000F8" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(000000010000000000000009,248)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- backend> SELECT pg_switch_wal(); 1: pg_switch_wal (typeid = 3220, len = 8, typmod = -1, byval = t) ---- Current WAL segment file number is 9. Let¡¯s set a breakpoint at the line StartBytePos = Insert->CurrBytePos; inside ReserveXLogSwitch(). We adjust Insert->CurrBytePos to a position sizeof(uint32) bytes before the final page boundary of the current WAL segment file with this assignment: GDB:Insert->CurrBytePos = XLogRecPtrToBytePos( XLogBytePosToRecPtr(Insert->CurrBytePos) + (wal_segment_size - XLogBytePosToRecPtr(Insert->CurrBytePos) % wal_segment_size) - sizeof(uint32) ) backend> SELECT pg_switch_wal(); 1: pg_switch_wal (typeid = 3220, len = 8, typmod = -1, byval = t) ---- 1: pg_switch_wal = "0/0A00003C" (typeid = 3220, len = 8, typmod = -1, byval = t) ---- LSN 0/0A00003C maps to WAL segment 10, the first block, with an intra-block offset of 60. The offset value 60 equals the trailing 20 bytes of the switch WAL record plus 40 bytes from MAXALIGN(sizeof(XLogLongPageHeaderData)). This segment file contains nothing other than this single switch WAL record. And the current WAL segment file number is 11: backend> select 'pg_current_wal_flush_lsn' as lsn_name, pg_current_wal_flush_lsn(), pg_walfile_name_offset(pg_current_wal_flush_lsn()) union all select 'pg_current_wal_insert_lsn', pg_current_wal_insert_lsn(), pg_walfile_name_offset(pg_current_wal_insert_lsn()) union all select 'pg_current_wal_lsn', pg_current_wal_lsn(), pg_walfile_name_offset(pg_current_wal_lsn()); 1: lsn_name (typeid = 25, len = -1, typmod = -1, byval = f) 2: pg_current_wal_flush_lsn (typeid = 3220, len = 8, typmod = -1, byval = t) 3: pg_walfile_name_offset (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_flush_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/0B000000" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(00000001000000000000000B,0)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_insert_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/0B000028" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(00000001000000000000000B,40)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- 1: = "pg_current_wal_lsn" (typeid = 25, len = -1, typmod = -1, byval = f) 2: = "0/0B000000" (typeid = 3220, len = 8, typmod = -1, byval = t) 3: = "(00000001000000000000000B,0)" (typeid = 2249, len = -1, typmod = -1, byval = f) ---- backend>