Esempio n. 1
0
    def checkpoint(self):
        """
        Execute a checkpoint
        """
        try:
            conn = self.connect()

            # Requires superuser privilege
            if not self.is_superuser:
                raise PostgresSuperuserRequired()

            cur = conn.cursor()
            cur.execute("CHECKPOINT")
        except (PostgresConnectionError, psycopg2.Error) as e:
            _logger.debug("Error issuing CHECKPOINT: %s", str(e).strip())
Esempio n. 2
0
    def switch_xlog(self):
        """
        Execute a pg_switch_xlog()

        To be SURE of the switch of a xlog, we collect the xlogfile name
        before and after the switch.
        The method returns the just closed xlog file name if the current xlog
        file has changed, it returns an empty string otherwise.

        The method returns None if something went wrong during the execution
        of the pg_switch_xlog command.

        :rtype: str|None
        """
        try:
            conn = self.connect()
            # Requires superuser privilege
            if not self.is_superuser:
                raise PostgresSuperuserRequired()

            # If this server is in recovery there is nothing to do
            if self.is_in_recovery:
                raise PostgresIsInRecovery()

            cur = conn.cursor()
            # Collect the xlog file name before the switch
            cur.execute(
                'SELECT {pg_walfile_name}('
                '{pg_current_wal_insert_lsn}())'.format(**self.name_map))
            pre_switch = cur.fetchone()[0]
            # Switch
            cur.execute('SELECT {pg_walfile_name}({pg_switch_wal}())'.format(
                **self.name_map))
            # Collect the xlog file name after the switch
            cur.execute(
                'SELECT {pg_walfile_name}('
                '{pg_current_wal_insert_lsn}())'.format(**self.name_map))
            post_switch = cur.fetchone()[0]
            if pre_switch < post_switch:
                return pre_switch
            else:
                return ''
        except (PostgresConnectionError, psycopg2.Error) as e:
            _logger.debug("Error issuing pg_switch_xlog() command: %s",
                          str(e).strip())
            return None
Esempio n. 3
0
    def switch_xlog(self):
        """
        Execute a pg_switch_xlog()

        To be SURE of the switch of a xlog, we collect the xlogfile name
        before and after the switch.
        If the name of the xlog file post switch is greater than the one
        collected before the switch have been executed.
        Returns an empty string otherwise.

        The method returns None if something went wrong during the execution
        of the pg_switch_xlog command.

        :rtype: str|None
        """
        try:
            conn = self.connect()
            # Requires superuser privilege
            if not self.is_superuser:
                raise PostgresSuperuserRequired()

            # If this server is in recovery there is nothing to do
            if self.is_in_recovery:
                raise PostgresIsInRecovery()

            cur = conn.cursor()
            # Collect the xlog file name before the switch
            cur.execute('SELECT pg_xlogfile_name('
                        'pg_current_xlog_insert_location())')
            pre_switch = cur.fetchone()[0]
            # Switch
            cur.execute('SELECT pg_xlogfile_name(pg_switch_xlog())')
            # Collect the xlog file name after the switch
            cur.execute('SELECT pg_xlogfile_name('
                        'pg_current_xlog_insert_location())')
            post_switch = cur.fetchone()[0]
            if pre_switch < post_switch:
                return post_switch
            else:
                return ''
        except (PostgresConnectionError, psycopg2.Error) as e:
            _logger.debug(
                "Error issuing pg_switch_xlog() command: %s",
                str(e).strip())
            return None
Esempio n. 4
0
    def get_replication_stats(self, client_type=STANDBY):
        """
        Returns streaming replication information
        """
        try:
            cur = self._cursor(cursor_factory=NamedTupleCursor)

            # Without superuser rights, this function is useless
            # TODO: provide a simplified version for non-superusers
            if not self.is_superuser:
                raise PostgresSuperuserRequired()

            # pg_stat_replication is a system view that contains one
            # row per WAL sender process with information about the
            # replication status of a standby server. It has been
            # introduced in PostgreSQL 9.1. Current fields are:
            #
            # - pid (procpid in 9.1)
            # - usesysid
            # - usename
            # - application_name
            # - client_addr
            # - client_hostname
            # - client_port
            # - backend_start
            # - backend_xmin (9.4+)
            # - state
            # - sent_location
            # - write_location
            # - flush_location
            # - replay_location
            # - sync_priority
            # - sync_state
            #

            if self.server_version < 90100:
                raise PostgresUnsupportedFeature('9.1')

            from_repslot = ""
            if self.server_version >= 90500:
                # Current implementation (9.5+)
                what = "r.*, rs.slot_name"
                # Look for replication slot name
                from_repslot = "LEFT JOIN pg_replication_slots rs " \
                               "ON (r.pid = rs.active_pid) "
            elif self.server_version >= 90400:
                # PostgreSQL 9.4
                what = "*"
            elif self.server_version >= 90200:
                # PostgreSQL 9.2/9.3
                what = "pid," \
                    "usesysid," \
                    "usename," \
                    "application_name," \
                    "client_addr," \
                    "client_hostname," \
                    "client_port," \
                    "backend_start," \
                    "CAST (NULL AS xid) AS backend_xmin," \
                    "state," \
                    "sent_location," \
                    "write_location," \
                    "flush_location," \
                    "replay_location," \
                    "sync_priority," \
                    "sync_state "
            else:
                # PostgreSQL 9.1
                what = "procpid AS pid," \
                    "usesysid," \
                    "usename," \
                    "application_name," \
                    "client_addr," \
                    "client_hostname," \
                    "client_port," \
                    "backend_start," \
                    "CAST (NULL AS xid) AS backend_xmin," \
                    "state," \
                    "sent_location," \
                    "write_location," \
                    "flush_location," \
                    "replay_location," \
                    "sync_priority," \
                    "sync_state "

            # Streaming client
            if client_type == self.STANDBY:
                # Standby server
                where = 'WHERE replay_location IS NOT NULL '
            elif client_type == self.WALSTREAMER:
                # WAL streamer
                where = 'WHERE replay_location IS NULL '
            else:
                where = ''

            # Execute the query
            cur.execute("SELECT %s, "
                        "pg_is_in_recovery() AS is_in_recovery,"
                        "CASE WHEN pg_is_in_recovery() "
                        "  THEN {pg_last_wal_receive_lsn}() "
                        "  ELSE {pg_current_wal_lsn}() "
                        "END AS current_location "
                        "FROM pg_stat_replication r "
                        "%s"
                        "%s"
                        "ORDER BY sync_state DESC, sync_priority".format(
                            **self.name_map) % (what, from_repslot, where))

            # Generate a list of standby objects
            return cur.fetchall()
        except (PostgresConnectionError, psycopg2.Error) as e:
            _logger.debug("Error retrieving status of standby servers: %s",
                          str(e).strip())
            return None