From 338b222007ebe8610f1c4f029b7d919dd7e05a9d Mon Sep 17 00:00:00 2001 From: Cameron Murdoch Date: Wed, 18 Dec 2024 11:40:51 +0100 Subject: [PATCH] Proof of concept fix for `barman backup --wait` on pg17 pg_walfile_name_offset() has been changed in pg17 to return the current segment if on a segment boundary. Implement previous_segment_name() to calulate the previous segment and use this to restore the pre pg17 behaviour. Tested with pg16 and pg17. --- barman/postgres.py | 10 +++++++++- barman/xlog.py | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/barman/postgres.py b/barman/postgres.py index 9fb1e0049..36a47880e 100644 --- a/barman/postgres.py +++ b/barman/postgres.py @@ -55,6 +55,7 @@ from barman.postgres_plumbing import function_name_map from barman.remote_status import RemoteStatusMixin from barman.utils import force_str, simplify_version, with_metaclass +from barman.xlog import previous_segment_name try: from queue import Empty @@ -739,7 +740,14 @@ def current_xlog_info(self): "CURRENT_TIMESTAMP AS timestamp " "FROM {pg_current_wal_lsn}() AS location".format(**self.name_map) ) - return cur.fetchone() + result = cur.fetchone() + # pg_walfile_name_offset() in Postgres 17 returns the current segment + # if on a segment boundary so return the previous segment name in that case. + if self.server_version >= 170000 and result["file_offset"] == 00000000: + result["file_name"] = previous_segment_name( + result["file_name"], self.xlog_segment_size + ) + return result else: cur.execute( "SELECT location, " diff --git a/barman/xlog.py b/barman/xlog.py index 8415d5ec1..28c7faac8 100644 --- a/barman/xlog.py +++ b/barman/xlog.py @@ -302,6 +302,26 @@ def generate_segment_names(begin, end=None, version=None, xlog_segment_size=None cur_log += 1 +def previous_segment_name(segment, xlog_segment_size): + """ + Get the previous XLOG segment name + + :param str segment: segment name + :param int xlog_segment_size: the size of a XLOG segment + :rtype: str + :raise: BadXlogSegmentName + """ + tli, log, seg = decode_segment_name(segment) + xlog_seg_per_file = xlog_segments_per_file(xlog_segment_size) + prev_log, prev_seg = log, seg + if prev_seg == 0: + prev_seg = xlog_seg_per_file + prev_log -= 1 + else: + prev_seg -= 1 + return encode_segment_name(tli, prev_log, prev_seg) + + def hash_dir(path): """ Get the directory where the xlog segment will be stored