@@ -250,7 +250,8 @@ def cluster_info_query(self) -> str:
250250
251251 written_lsn = ("pg_catalog.pg_wal_lsn_diff(written_lsn, '0/0')::bigint"
252252 if self ._major_version >= 130000 else "NULL" )
253- extra = (", CASE WHEN latest_end_lsn IS NULL THEN NULL ELSE received_tli END, {0}, slot_name, "
253+ extra = (", CASE WHEN latest_end_lsn IS NULL THEN NULL ELSE received_tli END, {0}, "
254+ "pg_catalog.pg_wal_lsn_diff(latest_end_lsn, '0/0')::bigint, slot_name, "
254255 "conninfo, status, {1} FROM pg_catalog.pg_stat_get_wal_receiver()" ).format (written_lsn , extra )
255256 if self .role == PostgresqlRole .STANDBY_LEADER :
256257 extra = "timeline_id" + extra + ", pg_catalog.pg_control_checkpoint()"
@@ -491,9 +492,10 @@ def _cluster_info_state_get(self, name: str) -> Optional[Any]:
491492 result = self ._is_leader_retry (self ._query , self .cluster_info_query )[0 ]
492493 cluster_info_state = dict (zip (['timeline' , 'wal_position' , 'replay_lsn' ,
493494 'receive_lsn' , 'replay_paused' , 'pg_control_timeline' ,
494- 'received_tli' , 'write_location' , 'slot_name' , 'conninfo' ,
495- 'receiver_state' , 'restore_command' , 'slots' , 'synchronous_commit' ,
496- 'synchronous_standby_names' , 'pg_stat_replication' ], result ))
495+ 'received_tli' , 'write_location' , 'latest_end_lsn' , 'slot_name' ,
496+ 'conninfo' , 'receiver_state' , 'restore_command' , 'slots' ,
497+ 'synchronous_commit' , 'synchronous_standby_names' ,
498+ 'pg_stat_replication' ], result ))
497499 if self ._should_query_slots and self .can_advance_slots :
498500 cluster_info_state ['slots' ] = \
499501 self .slots_handler .process_permanent_slots (cluster_info_state ['slots' ])
@@ -511,6 +513,9 @@ def _cluster_info_state_get(self, name: str) -> Optional[Any]:
511513 def replay_lsn (self ) -> Optional [int ]:
512514 return self ._cluster_info_state_get ('replay_lsn' )
513515
516+ def latest_end_lsn (self ) -> Optional [int ]:
517+ return self ._cluster_info_state_get ('latest_end_lsn' )
518+
514519 def receive_lsn (self ) -> Optional [int ]:
515520 write = self ._cluster_info_state_get ('write_location' )
516521 received = self ._cluster_info_state_get ('receive_lsn' )
@@ -1252,12 +1257,16 @@ def _wal_position(is_primary: bool, wal_position: int,
12521257 receive_lsn : Optional [int ], replay_lsn : Optional [int ]) -> int :
12531258 return wal_position if is_primary else max (receive_lsn or 0 , replay_lsn or 0 )
12541259
1255- def timeline_wal_position (self ) -> Tuple [int , int , Optional [int ], Optional [int ], Optional [int ]]:
1260+ def timeline_wal_position (self ) -> Tuple [int , int , Optional [int ], Optional [int ], Optional [int ], Optional [ int ] ]:
12561261 """Get timeline and various wal positions.
12571262
1258- :returns: a tuple composed of 5 integers representing timeline, ``pg_current_wal_lsn()`` position
1259- on primary/the biggest value among receive and replay LSN on replicas, ``pg_control_checkpoint()``
1260- value on a standby leader, receive and replay LSN on replicas (if available).
1263+ :returns: a tuple composed of 6 integers representing
1264+ * timeline,
1265+ * ``pg_current_wal_lsn()`` position on the primary
1266+ or the biggest value among receive and replay LSN on replicas,
1267+ * ``pg_control_checkpoint()`` value on a standby leader,
1268+ * receive and replay LSN on replicas (if available),
1269+ * latest_end_lsn (the last known LSN on the primary)
12611270 """
12621271 # This method could be called from different threads (simultaneously with some other `_query` calls).
12631272 # If it is called not from main thread we will create a new cursor to execute statement.
@@ -1266,14 +1275,16 @@ def timeline_wal_position(self) -> Tuple[int, int, Optional[int], Optional[int],
12661275 wal_position = self ._cluster_info_state_get ('wal_position' ) or 0
12671276 replay_lsn = self .replay_lsn ()
12681277 receive_lsn = self .receive_lsn ()
1278+ latest_end_lsn = self .latest_end_lsn ()
12691279 pg_control_timeline = self ._cluster_info_state_get ('pg_control_timeline' )
12701280 else :
1271- timeline , wal_position , replay_lsn , receive_lsn , _ , pg_control_timeline , _ , write_location = \
1272- self ._query (self .cluster_info_query )[0 ][:8 ]
1281+ timeline , wal_position , replay_lsn , receive_lsn , _ , \
1282+ pg_control_timeline , _ , write_location , latest_end_lsn = \
1283+ self ._query (self .cluster_info_query )[0 ][:9 ]
12731284 receive_lsn = max (receive_lsn or 0 , write_location or 0 )
12741285
12751286 wal_position = self ._wal_position (bool (timeline ), wal_position , receive_lsn , replay_lsn )
1276- return timeline , wal_position , pg_control_timeline , receive_lsn , replay_lsn
1287+ return timeline , wal_position , pg_control_timeline , receive_lsn , replay_lsn , latest_end_lsn
12771288
12781289 def postmaster_start_time (self ) -> Optional [str ]:
12791290 try :
0 commit comments