Пример #1
0
def wait_for_slave_gtid(server, gtids, timeout=0):
    """Wait until a slave executes GITDs.

    The function `SELECT WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS` is called until the
    slave catches up. If the timeout period expires prior to achieving
    the condition the :class:`~mysql.fabric.errors.TimeoutError` exception is
    raised. If any thread is stopped, the
    :class:`~mysql.fabric.errors.DatabaseError` exception is raised.

    :param server: MySQL Server.
    :param gtids: Gtid information.
    :param timeout: Timeout for waiting for slave to catch up.
    """
    # Check servers for GTID support
    if not server.gtid_enabled:
        raise _errors.ProgrammingError(
            "Global Transaction IDs are not supported.")

    res = server.exec_stmt(_GTID_WAIT, {"params": (gtids, timeout)})

    if res is None or res[0] is None or res[0][0] is None:
        raise _errors.DatabaseError("Error waiting for slave to catch up. "
                                    "GTID (%s)." % (gtids, ))
    elif res[0][0] == -1:
        raise _errors.TimeoutError("Error waiting for slave to catch up. "
                                   "GTID (%s)." % (gtids, ))

    assert (res[0][0] > -1)
Пример #2
0
def get_num_gtid(gtids, server_uuid=None):
    """Return the number of transactions represented in GTIDs.

    By default this function considers any server in GTIDs. So if one wants
    to count transactions from a specific server, the parameter server_uuid
    must be defined.

    :param gtids: Set of transactions.
    :param server_uuid: Which server one should consider where None means
                        all.
    """
    sid = None
    difference = 0
    for gtid in gtids.split(","):
        # Exctract the server_uuid and the trx_ids.
        trx_ids = None
        if gtid.find(":") != -1:
            sid, trx_ids = gtid.split(":")
        else:
            if not sid:
                raise _errors.ProgrammingError("Malformed GTID (%s)." %
                                               (gtid, ))
            trx_ids = gtid

        # Ignore differences if server_uuid is set and does
        # not match.
        if server_uuid and str(server_uuid).upper() != sid.upper():
            continue

        # Check the difference.
        difference += 1
        if trx_ids.find("-") != -1:
            lgno, rgno = trx_ids.split("-")
            difference += int(rgno) - int(lgno)
    return difference
Пример #3
0
 def _do_enqueue_procedures(self, within_procedure, actions,
                            lockable_objects):
     """Schedule a set of procedures.
     """
     procedures = None
     executor = ExecutorThread.executor_object()
     if not executor:
         if within_procedure:
             raise _errors.ProgrammingError(
                 "One can only create a new job from a job.")
         procedures, jobs = self._create_jobs(actions, lockable_objects)
         assert (len(set(procedures)) == len(set(jobs)))
         # There is no need to catch exceptions at this point. They will
         # be automatically caught by the caller which is usually the
         # XML-RPC session thread.
         _checkpoint.register(jobs, False)
         self.__scheduler.enqueue_procedures(procedures)
     else:
         current_job = executor.current_job
         current_procedure = current_job.procedure
         if within_procedure:
             procedures, jobs = self._create_jobs(actions, lockable_objects,
                                                  current_procedure.uuid)
             assert (set([job.procedure for job in jobs]) == set(procedures)
                     == set([current_procedure]))
             current_job.append_jobs(jobs)
         else:
             procedures, jobs = self._create_jobs(actions, lockable_objects)
             assert (len(set(procedures)) == len(set(jobs)))
             current_job.append_procedures(procedures)
     assert (procedures is not None)
     return procedures
Пример #4
0
    def wait_for_procedure(self, procedure):
        """Wait until the procedure finishes the execution of all
        its jobs.
        """
        if ExecutorThread.executor_object():
            raise _errors.ProgrammingError(
                "One cannot wait for the execution of a procedure from "
                "a job.")

        procedure.wait()
Пример #5
0
    def _do_reschedule_procedure(self, proc_uuid, actions, lockable_objects):
        """Recovers a procedure after a failure by rescheduling it.
        """
        if ExecutorThread.executor_object():
            raise _errors.ProgrammingError(
                "One cannot reschedule a procedure from a job.")

        procedures, jobs = self._create_jobs(actions, lockable_objects,
                                             proc_uuid)
        self.__scheduler.enqueue_procedures(procedures)
        assert (set([job.procedure for job in jobs]) == set(procedures))
        assert (set([job.procedure.uuid for job in jobs
                     ]) == set([procedure.uuid for procedure in procedures]))
        assert (procedures is not None)
        return procedures
Пример #6
0
def sync_slave_with_master(slave, master, timeout=0):
    """Synchronizes a slave with a master.

    See :func:`wait_for_slave_gtid`.

    This function can block if the master fails and all
    transactions are not fetched.

    :param slave: Reference to a slave (MySQL Server).
    :param master: Reference to the master (MySQL Server).
    :param timeout: Timeout for waiting for slave to catch up.
    """
    # Check servers for GTID support
    if not slave.gtid_enabled or not master.gtid_enabled:
        raise _errors.ProgrammingError(
            "Global Transaction IDs are not supported.")

    master_gtids = master.get_gtid_status()
    master_gtids = master_gtids[0].GTID_EXECUTED.strip(",")
    wait_for_slave_gtid(slave, master_gtids, timeout)
Пример #7
0
def exec_mysql_stmt(cnx, stmt_str, options=None):
    """Execute a statement for the client and return a result set or a
    cursor.

    This is the singular method to execute queries. If something goes
    wrong while executing a statement, the exception
    :class:`~mysql.fabric.errors.DatabaseError` is raised.

    :param cnx: Database connection.
    :param stmt_str: The statement (e.g. query, updates, etc) to execute.
    :param options: Options to control behavior:

                    - params - Parameters for statement.
                    - columns - If true, return a rows as named tuples
                      (default is False).
                    - raw - If true, do not convert MySQL's types to
                      Python's types (default is True).
                    - fetch - If true, execute the fetch as part of the
                      operation (default is True).

    :return: Either a result set as list of tuples (either named or unnamed)
             or a cursor.
    """
    if cnx is None:
        raise _errors.DatabaseError("Invalid database connection.")

    options = options or {}
    params = options.get('params', ())
    columns = options.get('columns', False)
    fetch = options.get('fetch', True)
    raw = options.get('raw', False)

    if raw and columns:
        raise _errors.ProgrammingError(
            "No raw cursor available returning named tuple")

    _LOGGER.debug("Statement ({statement}, Params({parameters}).".format(
        statement=stmt_str.replace('\n', '').replace('\r', ''),
        parameters=params))

    cur = None
    try:
        cur = cnx.cursor(raw=raw, named_tuple=columns)
        cur.execute(stmt_str, params)
    except Exception as error:
        if cnx.unread_result:
            cnx.get_rows()
        if cur:
            cur.close()

        errno = getattr(error, 'errno', None)
        raise _errors.DatabaseError(
            "Command (%s, %s) failed accessing (%s). %s." %
            (stmt_str, params, mysql_address_from_cnx(cnx), error), errno)

    assert (cur is not None)
    if fetch:
        results = None
        try:
            if cnx.unread_result:
                results = cur.fetchall()
        except mysql.connector.errors.InterfaceError as error:
            raise _errors.DatabaseError(
                "Command (%s, %s) failed fetching data from (%s). %s." %
                (stmt_str, params, mysql_address_from_cnx(cnx), error))
        finally:
            cur.close()
        return results

    return cur