Skip to content

Commit b4672e3

Browse files
committed
PGPRO-2180: In pg_stop_backup for replica wait for LSN of prior record
1 parent 6ea7c61 commit b4672e3

File tree

4 files changed

+72
-37
lines changed

4 files changed

+72
-37
lines changed

src/backup.c

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ static int checkpoint_timeout(void);
109109
//static void backup_list_file(parray *files, const char *root, )
110110
static void parse_backup_filelist_filenames(parray *files, const char *root);
111111
static void wait_wal_lsn(XLogRecPtr lsn, bool is_start_lsn,
112-
bool wait_prev_segment);
112+
bool wait_prev_lsn, bool wait_prev_segment);
113113
static void wait_replica_wal_lsn(XLogRecPtr lsn, bool is_start_backup);
114114
static void make_pagemap_from_ptrack(parray *files);
115115
static void *StreamLog(void *arg);
@@ -1166,15 +1166,15 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup)
11661166

11671167
if (current.backup_mode == BACKUP_MODE_DIFF_PAGE)
11681168
/* In PAGE mode wait for current segment... */
1169-
wait_wal_lsn(backup->start_lsn, true, false);
1169+
wait_wal_lsn(backup->start_lsn, true, false, false);
11701170
/*
11711171
* Do not wait start_lsn for stream backup.
11721172
* Because WAL streaming will start after pg_start_backup() in stream
11731173
* mode.
11741174
*/
11751175
else if (!stream_wal)
11761176
/* ...for others wait for previous segment */
1177-
wait_wal_lsn(backup->start_lsn, true, true);
1177+
wait_wal_lsn(backup->start_lsn, true, false, true);
11781178

11791179
/* In case of backup from replica for PostgreSQL 9.5
11801180
* wait for start_lsn to be replayed by replica
@@ -1504,7 +1504,8 @@ pg_ptrack_get_and_clear(Oid tablespace_oid, Oid db_oid, Oid rel_filenode,
15041504
* If 'wait_prev_segment' wait for previous segment.
15051505
*/
15061506
static void
1507-
wait_wal_lsn(XLogRecPtr lsn, bool is_start_lsn, bool wait_prev_segment)
1507+
wait_wal_lsn(XLogRecPtr lsn, bool is_start_lsn, bool wait_prev_lsn,
1508+
bool wait_prev_segment)
15081509
{
15091510
TimeLineID tli;
15101511
XLogSegNo targetSegNo;
@@ -1515,6 +1516,7 @@ wait_wal_lsn(XLogRecPtr lsn, bool is_start_lsn, bool wait_prev_segment)
15151516
bool file_exists = false;
15161517
uint32 try_count = 0,
15171518
timeout;
1519+
char *prior_to = (wait_prev_lsn) ? " prior to " : "";
15181520

15191521
#ifdef HAVE_LIBZ
15201522
char gz_wal_segment_path[MAXPGPATH];
@@ -1555,14 +1557,13 @@ wait_wal_lsn(XLogRecPtr lsn, bool is_start_lsn, bool wait_prev_segment)
15551557
timeout = archive_timeout;
15561558
else
15571559
timeout = ARCHIVE_TIMEOUT_DEFAULT;
1558-
15591560
}
15601561

15611562
if (wait_prev_segment)
15621563
elog(LOG, "Looking for segment: %s", wal_segment);
15631564
else
1564-
elog(LOG, "Looking for LSN: %X/%X in segment: %s",
1565-
(uint32) (lsn >> 32), (uint32) lsn, wal_segment);
1565+
elog(LOG, "Looking for LSN %s%X/%X in segment: %s",
1566+
prior_to, (uint32) (lsn >> 32), (uint32) lsn, wal_segment);
15661567

15671568
#ifdef HAVE_LIBZ
15681569
snprintf(gz_wal_segment_path, sizeof(gz_wal_segment_path), "%s.gz",
@@ -1598,11 +1599,27 @@ wait_wal_lsn(XLogRecPtr lsn, bool is_start_lsn, bool wait_prev_segment)
15981599
/*
15991600
* A WAL segment found. Check LSN on it.
16001601
*/
1601-
if (wal_contains_lsn(wal_segment_dir, lsn, tli, xlog_seg_size))
1602-
/* Target LSN was found */
1602+
if (!wait_prev_lsn)
16031603
{
1604-
elog(LOG, "Found LSN: %X/%X", (uint32) (lsn >> 32), (uint32) lsn);
1605-
return;
1604+
if (wal_contains_lsn(wal_segment_dir, lsn, tli, xlog_seg_size))
1605+
/* Target LSN was found */
1606+
{
1607+
elog(LOG, "Found LSN: %X/%X", (uint32) (lsn >> 32), (uint32) lsn);
1608+
return;
1609+
}
1610+
}
1611+
else
1612+
{
1613+
XLogRecPtr res;
1614+
1615+
res = get_last_wal_lsn(wal_segment_dir, current.start_lsn,
1616+
lsn, tli, false, xlog_seg_size);
1617+
if (!XLogRecPtrIsInvalid(res))
1618+
{
1619+
/* LSN of the prior record was found */
1620+
elog(LOG, "Found LSN: %X/%X", (uint32) (res >> 32), (uint32) res);
1621+
return;
1622+
}
16061623
}
16071624
}
16081625

@@ -1618,16 +1635,18 @@ wait_wal_lsn(XLogRecPtr lsn, bool is_start_lsn, bool wait_prev_segment)
16181635
elog(INFO, "Wait for WAL segment %s to be archived",
16191636
wal_segment_path);
16201637
else
1621-
elog(INFO, "Wait for LSN %X/%X in archived WAL segment %s",
1622-
(uint32) (lsn >> 32), (uint32) lsn, wal_segment_path);
1638+
elog(INFO, "Wait for LSN %s%X/%X in archived WAL segment %s",
1639+
prior_to, (uint32) (lsn >> 32), (uint32) lsn,
1640+
wal_segment_path);
16231641
}
16241642

16251643
if (timeout > 0 && try_count > timeout)
16261644
{
16271645
if (file_exists)
16281646
elog(ERROR, "WAL segment %s was archived, "
1629-
"but target LSN %X/%X could not be archived in %d seconds",
1630-
wal_segment, (uint32) (lsn >> 32), (uint32) lsn, timeout);
1647+
"but target LSN %s%X/%X could not be archived in %d seconds",
1648+
wal_segment, prior_to, (uint32) (lsn >> 32), (uint32) lsn,
1649+
timeout);
16311650
/* If WAL segment doesn't exist or we wait for previous segment */
16321651
else
16331652
elog(ERROR,
@@ -1724,6 +1743,7 @@ pg_stop_backup(pgBackup *backup)
17241743
size_t len;
17251744
char *val = NULL;
17261745
char *stop_backup_query = NULL;
1746+
bool stop_lsn_exists = false;
17271747

17281748
/*
17291749
* We will use this values if there are no transactions between start_lsn
@@ -1910,7 +1930,6 @@ pg_stop_backup(pgBackup *backup)
19101930
{
19111931
char *xlog_path,
19121932
stream_xlog_path[MAXPGPATH];
1913-
XLogSegNo segno;
19141933

19151934
if (stream_wal)
19161935
{
@@ -1922,12 +1941,14 @@ pg_stop_backup(pgBackup *backup)
19221941
else
19231942
xlog_path = arclog_path;
19241943

1925-
GetXLogSegNo(stop_backup_lsn, segno, xlog_seg_size);
1926-
/* Retreive stop_lsn from previous segment */
1927-
segno = segno - 1;
19281944
stop_backup_lsn = get_last_wal_lsn(xlog_path, backup->start_lsn,
1929-
segno, backup->tli,
1930-
xlog_seg_size);
1945+
stop_backup_lsn, backup->tli,
1946+
true, xlog_seg_size);
1947+
/*
1948+
* Do not check existance of LSN again below using
1949+
* wait_wal_lsn().
1950+
*/
1951+
stop_lsn_exists = true;
19311952
}
19321953
else
19331954
elog(ERROR, "Invalid stop_backup_lsn value %X/%X",
@@ -2040,7 +2061,9 @@ pg_stop_backup(pgBackup *backup)
20402061
* Wait for stop_lsn to be archived or streamed.
20412062
* We wait for stop_lsn in stream mode just in case.
20422063
*/
2043-
wait_wal_lsn(stop_backup_lsn, false, false);
2064+
if (!stop_lsn_exists)
2065+
wait_wal_lsn(stop_backup_lsn, false,
2066+
!exclusive_backup && current.from_replica, false);
20442067

20452068
if (stream_wal)
20462069
{

src/parsexlog.c

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -772,25 +772,33 @@ wal_contains_lsn(const char *archivedir, XLogRecPtr target_lsn,
772772
}
773773

774774
/*
775-
* Get last valid LSN within the WAL segment with number 'segno'. If 'start_lsn'
775+
* Get LSN of last or prior record within the WAL segment with number 'segno'.
776+
* If 'start_lsn'
776777
* is in the segment with number 'segno' then start from 'start_lsn', otherwise
777778
* start from offset 0 within the segment.
779+
*
780+
* Returns LSN which points to end+1 of the last WAL record if seek_prev_segment
781+
* is true. Otherwise returns LSN of the record prior to stop_lsn.
778782
*/
779783
XLogRecPtr
780784
get_last_wal_lsn(const char *archivedir, XLogRecPtr start_lsn,
781-
XLogSegNo segno, TimeLineID tli, uint32 seg_size)
785+
XLogRecPtr stop_lsn, TimeLineID tli, bool seek_prev_segment,
786+
uint32 seg_size)
782787
{
783788
XLogReaderState *xlogreader;
784789
XLogPageReadPrivate private;
785790
XLogRecPtr startpoint;
786791
XLogSegNo start_segno;
792+
XLogSegNo segno;
787793
XLogRecPtr res = InvalidXLogRecPtr;
788794

789-
if (segno == 0)
795+
GetXLogSegNo(stop_lsn, segno, seg_size);
796+
797+
if (segno <= 1)
790798
elog(ERROR, "Invalid WAL segment number " UINT64_FORMAT, segno);
791799

792-
elog(LOG, "Retreiving last LSN of the segment with number " UINT64_FORMAT,
793-
segno);
800+
if (seek_prev_segment)
801+
segno = segno - 1;
794802

795803
xlogreader = InitXLogPageRead(&private, archivedir, tli, seg_size, true);
796804

@@ -821,9 +829,6 @@ get_last_wal_lsn(const char *archivedir, XLogRecPtr start_lsn,
821829
startpoint = found;
822830
}
823831

824-
elog(VERBOSE, "Starting LSN is %X/%X",
825-
(uint32) (startpoint >> 32), (uint32) (startpoint));
826-
827832
while (true)
828833
{
829834
XLogRecord *record;
@@ -851,21 +856,28 @@ get_last_wal_lsn(const char *archivedir, XLogRecPtr start_lsn,
851856
PrintXLogCorruptionMsg(&private, ERROR);
852857
}
853858

854-
res = xlogreader->ReadRecPtr;
855-
856859
/* continue reading at next record */
857860
startpoint = InvalidXLogRecPtr;
858861

859862
GetXLogSegNo(xlogreader->EndRecPtr, next_segno, seg_size);
860863
if (next_segno > segno)
861864
break;
865+
866+
if (seek_prev_segment)
867+
{
868+
/* end+1 of last record read */
869+
res = xlogreader->EndRecPtr;
870+
}
871+
else
872+
res = xlogreader->ReadRecPtr;
873+
874+
if (xlogreader->EndRecPtr >= stop_lsn)
875+
break;
862876
}
863877

864878
CleanupXLogPageRead(xlogreader);
865879
XLogReaderFree(xlogreader);
866880

867-
elog(VERBOSE, "Last LSN is %X/%X", (uint32) (res >> 32), (uint32) (res));
868-
869881
return res;
870882
}
871883

src/pg_probackup.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -577,8 +577,8 @@ extern bool read_recovery_info(const char *archivedir, TimeLineID tli,
577577
extern bool wal_contains_lsn(const char *archivedir, XLogRecPtr target_lsn,
578578
TimeLineID target_tli, uint32 seg_size);
579579
extern XLogRecPtr get_last_wal_lsn(const char *archivedir, XLogRecPtr start_lsn,
580-
XLogSegNo segno, TimeLineID tli,
581-
uint32 seg_size);
580+
XLogRecPtr stop_lsn, TimeLineID tli,
581+
bool seek_prev_segment, uint32 seg_size);
582582

583583
/* in util.c */
584584
extern TimeLineID get_current_timeline(bool safe);

tests/replica.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,4 +551,4 @@ def test_make_block_from_future(self):
551551
exit(1)
552552

553553
# Clean after yourself
554-
self.del_test_dir(module_name, fname)
554+
self.del_test_dir(module_name, fname)

0 commit comments

Comments
 (0)