def get_history(self, timeline): history_path = 'pg_{0}/{1:08X}.history'.format(self.wal_name, timeline) try: cursor = self._connection.cursor() cursor.execute('SELECT isdir, modification FROM pg_catalog.pg_stat_file(%s)', (history_path,)) isdir, modification = cursor.fetchone() if not isdir: cursor.execute('SELECT pg_catalog.pg_read_file(%s)', (history_path,)) history = list(parse_history(cursor.fetchone()[0])) if history[-1][0] == timeline - 1: history[-1].append(modification.isoformat()) return history except Exception: logger.exception('Failed to read and parse %s', (history_path,))
def get_history(self, timeline): history_path = os.path.join(self.wal_dir, '{0:08X}.history'.format(timeline)) history_mtime = mtime(history_path) if history_mtime: try: with open(history_path, 'r') as f: history = f.read() history = list(parse_history(history)) if history[-1][0] == timeline - 1: history_mtime = datetime.fromtimestamp(history_mtime).replace(tzinfo=tz.tzlocal()) history[-1].append(history_mtime.isoformat()) return history except Exception: logger.exception('Failed to read and parse %s', (history_path,))
def _check_timeline_and_lsn(self, leader): local_timeline, local_lsn = self._get_local_timeline_lsn() if local_timeline is None or local_lsn is None: return if isinstance(leader, Leader): if leader.member.data.get('role') != 'master': return # standby cluster elif not self.check_leader_is_not_in_recovery( **leader.conn_kwargs(self._postgresql.config.replication)): return history = need_rewind = None try: with self._postgresql.get_replication_connection_cursor( **leader.conn_kwargs()) as cur: cur.execute('IDENTIFY_SYSTEM') master_timeline = cur.fetchone()[1] logger.info('master_timeline=%s', master_timeline) if local_timeline > master_timeline: # Not always supported by pg_rewind need_rewind = True elif master_timeline > 1: cur.execute('TIMELINE_HISTORY %s', (master_timeline, )) history = bytes(cur.fetchone()[1]).decode('utf-8') logger.info('master: history=%s', history) else: # local_timeline == master_timeline == 1 need_rewind = False except Exception: return logger.exception( 'Exception when working with master via replication connection' ) if history is not None: for parent_timeline, switchpoint, _ in parse_history(history): if parent_timeline == local_timeline: try: need_rewind = parse_lsn(local_lsn) >= switchpoint except (IndexError, ValueError): logger.exception('Exception when parsing lsn') break elif parent_timeline > local_timeline: break self._state = need_rewind and REWIND_STATUS.NEED or REWIND_STATUS.NOT_NEED