Example #1
0
 def test_is_wal_file(self):
     assert xlog.is_wal_file('000000000000000200000001')
     assert xlog.is_wal_file('test/000000000000000200000001')
     assert not xlog.is_wal_file('00000001000000000000000A.00000020.backup')
     assert not xlog.is_wal_file('00000002.history')
     assert not xlog.is_wal_file('00000000000000000000000')
     assert not xlog.is_wal_file('0000000000000000000000000')
     assert not xlog.is_wal_file('000000000000X00000000000')
     assert not xlog.is_wal_file('00000001000000000000000A.backup')
     assert not xlog.is_any_xlog_file(
         'test.00000001000000000000000A.00000020.backup')
     assert not xlog.is_wal_file('00000001000000000000000A.history')
     assert not xlog.is_wal_file('00000001000000000000000A.partial')
Example #2
0
 def test_is_wal_file(self):
     assert xlog.is_wal_file('000000000000000200000001')
     assert xlog.is_wal_file('test/000000000000000200000001')
     assert not xlog.is_wal_file('00000001000000000000000A.00000020.backup')
     assert not xlog.is_wal_file('00000002.history')
     assert not xlog.is_wal_file('00000000000000000000000')
     assert not xlog.is_wal_file('0000000000000000000000000')
     assert not xlog.is_wal_file('000000000000X00000000000')
     assert not xlog.is_wal_file('00000001000000000000000A.backup')
     assert not xlog.is_any_xlog_file(
         'test.00000001000000000000000A.00000020.backup')
     assert not xlog.is_wal_file('00000001000000000000000A.history')
     assert not xlog.is_wal_file('00000001000000000000000A.partial')
Example #3
0
 def test_is_wal_file(self):
     assert xlog.is_wal_file("000000000000000200000001")
     assert xlog.is_wal_file("test/000000000000000200000001")
     assert not xlog.is_wal_file("00000001000000000000000A.00000020.backup")
     assert not xlog.is_wal_file("00000002.history")
     assert not xlog.is_wal_file("00000000000000000000000")
     assert not xlog.is_wal_file("0000000000000000000000000")
     assert not xlog.is_wal_file("000000000000X00000000000")
     assert not xlog.is_wal_file("00000001000000000000000A.backup")
     assert not xlog.is_any_xlog_file(
         "test.00000001000000000000000A.00000020.backup")
     assert not xlog.is_wal_file("00000001000000000000000A.history")
     assert not xlog.is_wal_file("00000001000000000000000A.partial")
Example #4
0
def missing_wals(server, args):
    warn = args.warning
    crit = args.critical

    from barman.xlog import is_wal_file
    from barman.infofile import WalFileInfo

    wals_directory = server.config.wals_directory

    missing_wals = 0
    with server.xlogdb() as fxlogdb:
        for line in fxlogdb:
            #name, size, time, compression = server.xlogdb_parse_line(line)
            wal_info = WalFileInfo.from_xlogdb_line(line)
            name = wal_info.name

            directory = name[0:16]

            if is_wal_file(name):
                file_path = os.path.join(wals_directory, directory, name)
                if not os.path.exists(file_path):
                    missing_wals = missing_wals + 1

    exit_check(missing_wals,
               warn,
               crit,
               "There are %d missing wals for the last backup." % missing_wals,
               perfdata_key="missing",
               perfdata_min=0)
Example #5
0
 def get_remote_status(self):
     '''Get the status of the remote server'''
     pg_settings = ('archive_mode', 'archive_command', 'data_directory')
     pg_query_keys = ('server_txt_version', 'current_xlog')
     result = dict.fromkeys(pg_settings + pg_query_keys, None)
     try:
         with self.pg_connect() as conn:
             for name in pg_settings:
                 result[name] = self.get_pg_setting(name)
             try:
                 cur = conn.cursor()
                 cur.execute("SELECT version()")
                 result['server_txt_version'] = cur.fetchone()[0].split()[1]
             except:
                 result['server_txt_version'] = None
             try:
                 cur = conn.cursor()
                 cur.execute('SELECT pg_xlogfile_name(pg_current_xlog_location())')
                 result['current_xlog'] = cur.fetchone()[0];
             except:
                 result['current_xlog'] = None
     except:
         pass
     cmd = Command(self.ssh_command, self.ssh_options)
     result['last_shipped_wal'] = None
     if result['data_directory'] and result['archive_command']:
         archive_dir = os.path.join(result['data_directory'], 'pg_xlog', 'archive_status')
         out = cmd.getoutput(None, 'ls', '-tr', archive_dir)[0]
         for line in out.splitlines():
             if line.endswith('.done'):
                 name = line[:-5]
                 if xlog.is_wal_file(name):
                     result['last_shipped_wal'] = line[:-5]
     return result
Example #6
0
    def get_wal_until_next_backup(self, backup):
        """Get the xlog files between backup and the next

        :param backup: a backup object, the starting point to retrieve wals
        """
        begin = backup.begin_wal
        next_end = None
        if self.get_next_backup(backup.backup_id):
            next_end = self.get_next_backup(backup.backup_id).end_wal
        backup_tli, _, _ = xlog.decode_segment_name(begin)

        with self.xlogdb() as fxlogdb:
            for line in fxlogdb:
                name, size, _, _ = self.xlogdb_parse_line(line)
                if name < begin:
                    continue
                tli, _, _ = xlog.decode_segment_name(name)
                if tli > backup_tli:
                    continue
                if not xlog.is_wal_file(name):
                    continue
                if next_end and name > next_end:
                    break
                # count
                yield (name, size)
Example #7
0
 def get_remote_status(self):
     """Get the status of the remote server"""
     pg_settings = ("archive_mode", "archive_command", "data_directory")
     pg_query_keys = ("server_txt_version", "current_xlog")
     result = dict.fromkeys(pg_settings + pg_query_keys, None)
     try:
         with self.pg_connect() as conn:
             for name in pg_settings:
                 result[name] = self.get_pg_setting(name)
             try:
                 cur = conn.cursor()
                 cur.execute("SELECT version()")
                 result["server_txt_version"] = cur.fetchone()[0].split()[1]
             except:
                 result["server_txt_version"] = None
             try:
                 cur = conn.cursor()
                 cur.execute("SELECT pg_xlogfile_name(pg_current_xlog_location())")
                 result["current_xlog"] = cur.fetchone()[0]
             except:
                 result["current_xlog"] = None
     except:
         pass
     cmd = Command(self.ssh_command, self.ssh_options)
     result["last_shipped_wal"] = None
     if result["data_directory"] and result["archive_command"]:
         archive_dir = os.path.join(result["data_directory"], "pg_xlog", "archive_status")
         out = cmd.getoutput(None, "ls", "-tr", archive_dir)[0]
         for line in out.splitlines():
             if line.endswith(".done"):
                 name = line[:-5]
                 if xlog.is_wal_file(name):
                     result["last_shipped_wal"] = line[:-5]
     return result
Example #8
0
    def get_wal_until_next_backup(self, backup, include_history=False):
        """
        Get the xlog files between backup and the next

        :param BackupInfo backup: a backup object, the starting point
            to retrieve WALs
        :param bool include_history: option for the inclusion of
            include_history files into the output
        """
        begin = backup.begin_wal
        next_end = None
        if self.get_next_backup(backup.backup_id):
            next_end = self.get_next_backup(backup.backup_id).end_wal
        backup_tli, _, _ = xlog.decode_segment_name(begin)

        with self.xlogdb() as fxlogdb:
            for line in fxlogdb:
                wal_info = WalFileInfo.from_xlogdb_line(line)
                # Handle .history files: add all of them to the output,
                # regardless of their age, if requested (the 'include_history'
                # parameter is True)
                if xlog.is_history_file(wal_info.name):
                    if include_history:
                        yield wal_info
                    continue
                if wal_info.name < begin:
                    continue
                tli, _, _ = xlog.decode_segment_name(wal_info.name)
                if tli > backup_tli:
                    continue
                if not xlog.is_wal_file(wal_info.name):
                    continue
                if next_end and wal_info.name > next_end:
                    break
                yield wal_info
Example #9
0
    def get_latest_archived_wal(self):
        """
        Return the WalFileInfo of the last WAL file in the archive,
        or None if the archive doesn't contain any WAL file.

        :rtype: WalFileInfo|None
        """
        # TODO: consider timeline?
        from os.path import isdir, join

        root = self.config.wals_directory

        # If the WAL archive directory doesn't exists the archive is empty
        if not isdir(root):
            return None

        # Traverse all the directory in the archive in reverse order,
        # returning the first WAL file found
        for name in sorted(os.listdir(root), reverse=True):
            fullname = join(root, name)
            # All relevant files are in subdirectories, so
            # we skip any non-directory entry
            if isdir(fullname):
                hash_dir = fullname
                # Inspect contained files in reverse order
                for wal_name in sorted(os.listdir(hash_dir), reverse=True):
                    fullname = join(hash_dir, wal_name)
                    # Return the first file that has the correct name
                    if not isdir(fullname) and xlog.is_wal_file(fullname):
                        return WalFileInfo.from_file(fullname)

        # If we get here, no WAL files have been found
        return None
Example #10
0
def missing_wals(server, args):
    warn = args.warning
    crit = args.critical

    from barman.xlog import is_wal_file
    from barman.infofile import WalFileInfo

    wals_directory = server.config.wals_directory

    missing_wals = 0
    with server.xlogdb() as fxlogdb:
        for line in fxlogdb:
            #name, size, time, compression = server.xlogdb_parse_line(line)
            wal_info = WalFileInfo.from_xlogdb_line(line)
            name = wal_info.name

            directory = name[0:16]

            if is_wal_file(name):
                file_path = os.path.join(wals_directory, directory, name)
                if not os.path.exists(file_path):
                    missing_wals = missing_wals + 1

    exit_check(missing_wals, warn, crit,
               "There are %d missing wals for the last backup." % missing_wals,
               perfdata_key="missing", perfdata_min=0)
Example #11
0
    def _reset_streaming_status(self, postgres_status, streaming_status):
        """
        Reset the status of receive-wal by removing the .partial file that
        is marking the current position and creating one that is current with
        the PostgreSQL insert location
        """
        current_wal = xlog.location_to_xlogfile_name_offset(
            postgres_status["current_lsn"],
            streaming_status["timeline"],
            postgres_status["xlog_segment_size"],
        )["file_name"]
        restart_wal = current_wal
        if (postgres_status["replication_slot"]
                and postgres_status["replication_slot"].restart_lsn):
            restart_wal = xlog.location_to_xlogfile_name_offset(
                postgres_status["replication_slot"].restart_lsn,
                streaming_status["timeline"],
                postgres_status["xlog_segment_size"],
            )["file_name"]
        restart_path = os.path.join(self.config.streaming_wals_directory,
                                    restart_wal)
        restart_partial_path = restart_path + ".partial"
        wal_files = sorted(glob(
            os.path.join(self.config.streaming_wals_directory, "*")),
                           reverse=True)

        # Pick the newer file
        last = None
        for last in wal_files:
            if xlog.is_wal_file(last) or xlog.is_partial_file(last):
                break

        # Check if the status is already up-to-date
        if not last or last == restart_partial_path or last == restart_path:
            output.info("Nothing to do. Position of receive-wal is aligned.")
            return

        if os.path.basename(last) > current_wal:
            output.error(
                "The receive-wal position is ahead of PostgreSQL "
                "current WAL lsn (%s > %s)",
                os.path.basename(last),
                postgres_status["current_xlog"],
            )
            return

        output.info("Resetting receive-wal directory status")
        if xlog.is_partial_file(last):
            output.info("Removing status file %s" % last)
            os.unlink(last)
        output.info("Creating status file %s" % restart_partial_path)
        open(restart_partial_path, "w").close()
Example #12
0
    def get_latest_archived_wals_info(self):
        """
        Return a dictionary of timelines associated with the
        WalFileInfo of the last WAL file in the archive,
        or None if the archive doesn't contain any WAL file.

        :rtype: dict[str, WalFileInfo]|None
        """
        from os.path import isdir, join

        root = self.config.wals_directory
        comp_manager = self.compression_manager

        # If the WAL archive directory doesn't exists the archive is empty
        if not isdir(root):
            return dict()

        # Traverse all the directory in the archive in reverse order,
        # returning the first WAL file found
        timelines = {}
        for name in sorted(os.listdir(root), reverse=True):
            fullname = join(root, name)
            # All relevant files are in subdirectories, so
            # we skip any non-directory entry
            if isdir(fullname):
                # Extract the timeline. If it is not valid, skip this directory
                try:
                    timeline = name[0:8]
                    int(timeline, 16)
                except ValueError:
                    continue

                # If this timeline already has a file, skip this directory
                if timeline in timelines:
                    continue

                hash_dir = fullname
                # Inspect contained files in reverse order
                for wal_name in sorted(os.listdir(hash_dir), reverse=True):
                    fullname = join(hash_dir, wal_name)
                    # Return the first file that has the correct name
                    if not isdir(fullname) and xlog.is_wal_file(fullname):
                        timelines[timeline] = comp_manager.get_wal_file_info(
                            fullname)
                        break

        # Return the timeline map
        return timelines
Example #13
0
    def get_next_batch(self):
        """
        Returns the next batch of WAL files that have been archived via
        streaming replication (in the 'streaming' directory)

        This method always leaves one file in the "streaming" directory,
        because the 'pg_receivexlog' process needs at least one file to
        detect the current streaming position after a restart.

        :return: WalArchiverBatch: list of WAL files
        """
        # List and sort all files in the incoming directory
        file_names = glob(
            os.path.join(self.config.streaming_wals_directory, '*'))
        file_names.sort()

        # Process anything that looks like a valid WAL file,
        # including partial ones.
        # Anything else is treated like an error/anomaly
        files = []
        skip = []
        errors = []
        for file_name in file_names:
            if xlog.is_wal_file(file_name) and os.path.isfile(file_name):
                files.append(file_name)
            elif xlog.is_partial_file(file_name) and os.path.isfile(file_name):
                skip.append(file_name)
            else:
                errors.append(file_name)
        # In case of more than a partial file, keep the last
        # and treat the rest as errors
        if len(skip) > 1:
            errors.extend(skip[:-1])
            skip = skip[-1:]

        # Keep the last full WAL file in case no partial file is present
        elif len(skip) == 0 and files:
            skip.append(files.pop())

        # Build the list of WalFileInfo
        wal_files = [WalFileInfo.from_file(f, compression=None) for f in files]
        return WalArchiverBatch(wal_files, errors=errors, skip=skip)
Example #14
0
    def get_next_batch(self):
        """
        Returns the next batch of WAL files that have been archived via
        streaming replication (in the 'streaming' directory)

        This method always leaves one file in the "streaming" directory,
        because the 'pg_receivexlog' process needs at least one file to
        detect the current streaming position after a restart.

        :return: WalArchiverBatch: list of WAL files
        """
        # List and sort all files in the incoming directory
        file_names = glob(os.path.join(
            self.config.streaming_wals_directory, '*'))
        file_names.sort()

        # Process anything that looks like a valid WAL file,
        # including partial ones.
        # Anything else is treated like an error/anomaly
        files = []
        skip = []
        errors = []
        for file_name in file_names:
            if xlog.is_wal_file(file_name) and os.path.isfile(file_name):
                files.append(file_name)
            elif xlog.is_partial_file(file_name) and os.path.isfile(file_name):
                skip.append(file_name)
            else:
                errors.append(file_name)
        # In case of more than a partial file, keep the last
        # and treat the rest as errors
        if len(skip) > 1:
            errors.extend(skip[:-1])
            skip = skip[-1:]

        # Keep the last full WAL file in case no partial file is present
        elif len(skip) == 0 and files:
            skip.append(files.pop())

        # Build the list of WalFileInfo
        wal_files = [WalFileInfo.from_file(f, compression=None) for f in files]
        return WalArchiverBatch(wal_files, errors=errors, skip=skip)
Example #15
0
    def get_wal_until_next_backup(self, backup):
        '''Get the xlog files between backup and the next

        :param backup: a backup object, the starting point to retrieve wals
        '''
        begin = backup.begin_wal
        next_end = None
        if self.get_next_backup(backup.backup_id):
            next_end = self.get_next_backup(backup.backup_id).end_wal
        backup_tli, _, _ = xlog.decode_segment_name(begin)

        with self.xlogdb() as fxlogdb:
            for line in fxlogdb:
                name, size, _, _ = self.xlogdb_parse_line(line)
                if name < begin: continue
                tli, _, _ = xlog.decode_segment_name(name)
                if tli > backup_tli: continue
                if not xlog.is_wal_file(name): continue
                if next_end and name > next_end:
                    break
                # count
                yield (name, size)
Example #16
0
 def get_remote_status(self):
     '''Get the status of the remote server'''
     pg_settings = ('archive_mode', 'archive_command', 'data_directory')
     pg_query_keys = ('server_txt_version', 'current_xlog')
     result = dict.fromkeys(pg_settings + pg_query_keys, None)
     try:
         with self.pg_connect() as conn:
             for name in pg_settings:
                 result[name] = self.get_pg_setting(name)
             try:
                 cur = conn.cursor()
                 cur.execute("SELECT version()")
                 result['server_txt_version'] = cur.fetchone()[0].split()[1]
             except:
                 result['server_txt_version'] = None
             try:
                 cur = conn.cursor()
                 cur.execute(
                     'SELECT pg_xlogfile_name(pg_current_xlog_location())')
                 result['current_xlog'] = cur.fetchone()[0]
             except:
                 result['current_xlog'] = None
     except:
         pass
     cmd = Command(self.ssh_command, self.ssh_options)
     result['last_shipped_wal'] = None
     if result['data_directory'] and result['archive_command']:
         archive_dir = os.path.join(result['data_directory'], 'pg_xlog',
                                    'archive_status')
         out = cmd.getoutput(None, 'ls', '-tr', archive_dir)[0]
         for line in out.splitlines():
             if line.endswith('.done'):
                 name = line[:-5]
                 if xlog.is_wal_file(name):
                     result['last_shipped_wal'] = line[:-5]
     return result
Example #17
0
    def rebuild_xlogdb(self):
        """
        Rebuild the whole xlog database guessing it from the archive content.
        """
        from os.path import isdir, join

        output.info("Rebuilding xlogdb for server %s", self.config.name)
        root = self.config.wals_directory
        comp_manager = self.compression_manager
        wal_count = label_count = history_count = 0
        # lock the xlogdb as we are about replacing it completely
        with self.server.xlogdb("w") as fxlogdb:
            xlogdb_dir = os.path.dirname(fxlogdb.name)
            with tempfile.TemporaryFile(mode="w+",
                                        dir=xlogdb_dir) as fxlogdb_new:
                for name in sorted(os.listdir(root)):
                    # ignore the xlogdb and its lockfile
                    if name.startswith(self.server.XLOG_DB):
                        continue
                    fullname = join(root, name)
                    if isdir(fullname):
                        # all relevant files are in subdirectories
                        hash_dir = fullname
                        for wal_name in sorted(os.listdir(hash_dir)):
                            fullname = join(hash_dir, wal_name)
                            if isdir(fullname):
                                _logger.warning(
                                    "unexpected directory "
                                    "rebuilding the wal database: %s",
                                    fullname,
                                )
                            else:
                                if xlog.is_wal_file(fullname):
                                    wal_count += 1
                                elif xlog.is_backup_file(fullname):
                                    label_count += 1
                                elif fullname.endswith(".tmp"):
                                    _logger.warning(
                                        "temporary file found "
                                        "rebuilding the wal database: %s",
                                        fullname,
                                    )
                                    continue
                                else:
                                    _logger.warning(
                                        "unexpected file "
                                        "rebuilding the wal database: %s",
                                        fullname,
                                    )
                                    continue
                                wal_info = comp_manager.get_wal_file_info(
                                    fullname)
                                fxlogdb_new.write(wal_info.to_xlogdb_line())
                    else:
                        # only history files are here
                        if xlog.is_history_file(fullname):
                            history_count += 1
                            wal_info = comp_manager.get_wal_file_info(fullname)
                            fxlogdb_new.write(wal_info.to_xlogdb_line())
                        else:
                            _logger.warning(
                                "unexpected file rebuilding the wal database: %s",
                                fullname,
                            )
                fxlogdb_new.flush()
                fxlogdb_new.seek(0)
                fxlogdb.seek(0)
                shutil.copyfileobj(fxlogdb_new, fxlogdb)
                fxlogdb.truncate()
        output.info(
            "Done rebuilding xlogdb for server %s "
            "(history: %s, backup_labels: %s, wal_file: %s)",
            self.config.name,
            history_count,
            label_count,
            wal_count,
        )
Example #18
0
    def rebuild_xlogdb(self):
        """
        Rebuild the whole xlog database guessing it from the archive content.
        """
        from os.path import isdir, join

        output.info("Rebuilding xlogdb for server %s", self.config.name)
        root = self.config.wals_directory
        default_compression = self.config.compression
        wal_count = label_count = history_count = 0
        # lock the xlogdb as we are about replacing it completely
        with self.server.xlogdb('w') as fxlogdb:
            xlogdb_new = fxlogdb.name + ".new"
            with open(xlogdb_new, 'w') as fxlogdb_new:
                for name in sorted(os.listdir(root)):
                    # ignore the xlogdb and its lockfile
                    if name.startswith(self.server.XLOG_DB):
                        continue
                    fullname = join(root, name)
                    if isdir(fullname):
                        # all relevant files are in subdirectories
                        hash_dir = fullname
                        for wal_name in sorted(os.listdir(hash_dir)):
                            fullname = join(hash_dir, wal_name)
                            if isdir(fullname):
                                _logger.warning(
                                    'unexpected directory '
                                    'rebuilding the wal database: %s',
                                    fullname)
                            else:
                                if xlog.is_wal_file(fullname):
                                    wal_count += 1
                                elif xlog.is_backup_file(fullname):
                                    label_count += 1
                                else:
                                    _logger.warning(
                                        'unexpected file '
                                        'rebuilding the wal database: %s',
                                        fullname)
                                    continue
                                wal_info = WalFileInfo.from_file(
                                    fullname,
                                    default_compression=default_compression)
                                fxlogdb_new.write(wal_info.to_xlogdb_line())
                    else:
                        # only history files are here
                        if xlog.is_history_file(fullname):
                            history_count += 1
                            wal_info = WalFileInfo.from_file(
                                fullname,
                                default_compression=default_compression)
                            fxlogdb_new.write(wal_info.to_xlogdb_line())
                        else:
                            _logger.warning(
                                'unexpected file '
                                'rebuilding the wal database: %s',
                                fullname)
                os.fsync(fxlogdb_new.fileno())
            shutil.move(xlogdb_new, fxlogdb.name)
            fsync_dir(os.path.dirname(fxlogdb.name))
        output.info('Done rebuilding xlogdb for server %s '
                    '(history: %s, backup_labels: %s, wal_file: %s)',
                    self.config.name, history_count, label_count, wal_count)
Example #19
0
    def rebuild_xlogdb(self):
        """
        Rebuild the whole xlog database guessing it from the archive content.
        """
        from os.path import isdir, join

        output.info("Rebuilding xlogdb for server %s", self.config.name)
        root = self.config.wals_directory
        comp_manager = self.compression_manager
        wal_count = label_count = history_count = 0
        # lock the xlogdb as we are about replacing it completely
        with self.server.xlogdb('w') as fxlogdb:
            xlogdb_new = fxlogdb.name + ".new"
            with open(xlogdb_new, 'w') as fxlogdb_new:
                for name in sorted(os.listdir(root)):
                    # ignore the xlogdb and its lockfile
                    if name.startswith(self.server.XLOG_DB):
                        continue
                    fullname = join(root, name)
                    if isdir(fullname):
                        # all relevant files are in subdirectories
                        hash_dir = fullname
                        for wal_name in sorted(os.listdir(hash_dir)):
                            fullname = join(hash_dir, wal_name)
                            if isdir(fullname):
                                _logger.warning(
                                    'unexpected directory '
                                    'rebuilding the wal database: %s',
                                    fullname)
                            else:
                                if xlog.is_wal_file(fullname):
                                    wal_count += 1
                                elif xlog.is_backup_file(fullname):
                                    label_count += 1
                                elif fullname.endswith('.tmp'):
                                    _logger.warning(
                                        'temporary file found '
                                        'rebuilding the wal database: %s',
                                        fullname)
                                    continue
                                else:
                                    _logger.warning(
                                        'unexpected file '
                                        'rebuilding the wal database: %s',
                                        fullname)
                                    continue
                                wal_info = comp_manager.get_wal_file_info(
                                    fullname)
                                fxlogdb_new.write(wal_info.to_xlogdb_line())
                    else:
                        # only history files are here
                        if xlog.is_history_file(fullname):
                            history_count += 1
                            wal_info = comp_manager.get_wal_file_info(fullname)
                            fxlogdb_new.write(wal_info.to_xlogdb_line())
                        else:
                            _logger.warning(
                                'unexpected file '
                                'rebuilding the wal database: %s', fullname)
                os.fsync(fxlogdb_new.fileno())
        shutil.move(xlogdb_new, fxlogdb.name)
        fsync_dir(os.path.dirname(fxlogdb.name))
        output.info(
            'Done rebuilding xlogdb for server %s '
            '(history: %s, backup_labels: %s, wal_file: %s)', self.config.name,
            history_count, label_count, wal_count)