def test_gtid_set_itemize(self): gtid_set = ('cfb4dd08-588e-11e4-89aa-606720440b68:7,' 'd4f8eb6e-588e-11e4-89aa-606720440b68:1-4:6:8:10-11,' 'da1f90b1-588e-11e4-89aa-606720440b68:5-8') expected_result = [ ('cfb4dd08-588e-11e4-89aa-606720440b68', [7]), ('d4f8eb6e-588e-11e4-89aa-606720440b68', [1, 2, 3, 4, 6, 8, 10, 11]), ('da1f90b1-588e-11e4-89aa-606720440b68', [5, 6, 7, 8]) ] # Decompose (itemize) a GTID set with different intervals and UUIDs. self.assertEqual(gtid_set_itemize(gtid_set), expected_result)
def skip_slaves_trx(gtid_set, slaves_cnx_val, options): """Skip transactions on slaves. This method skips the given transactions (GTID set) on all the specified slaves. That is, an empty transaction is injected for each GTID in the given set for one of each slaves. In case a slave already has an executed transaction for a given GTID then that GTID is ignored for this slave. gtid_set[in] String representing the set of GTIDs to skip. slaves_cnx_val[in] List of the dictionaries with the connection values for each target slave. options[in] Dictionary of options (dry_run, verbosity). Throws an UtilError exception if an error occurs during the execution. """ verbosity = options.get('verbosity') dryrun = options.get('dry_run') # Connect to slaves. rpl_topology = Topology(None, slaves_cnx_val, options) # Check required privileges. errors = rpl_topology.check_privileges(skip_master=True) if errors: err_details = '' for err in errors: err_msg = ERROR_USER_WITHOUT_PRIVILEGES.format( user=err[0], host=err[1], port=err[2], operation='inject empty transactions', req_privileges=err[3]) err_details = '{0}{1}\n'.format(err_details, err_msg) err_details.strip() raise UtilRplError("Not enough privileges.\n{0}".format(err_details)) # GTID must be enabled on all servers. srv_list = rpl_topology.get_servers_with_gtid_not_on() if srv_list: if verbosity: print("# Slaves with GTID not enabled:") for srv in srv_list: msg = "# - GTID_MODE={0} on {1}:{2}".format(srv[2], srv[0], srv[1]) print(msg) raise UtilRplError(_GTID_ON_REQ.format(action='Transaction skip')) if dryrun: print("#") print("# WARNING: Executing utility in dry run mode (read only).") # Get GTID set that can be skipped, i.e., not in GTID_EXECUTED. gtids_by_slave = rpl_topology.slaves_gtid_subtract_executed(gtid_set) # Output GTID set that will be skipped. print("#") print("# GTID set to be skipped for each server:") has_gtid_to_skip = False for host, port, gtids_to_skip in gtids_by_slave: if not gtids_to_skip: gtids_to_skip = 'None' else: # Set flag to indicate that there is at least one GTID to skip. has_gtid_to_skip = True print("# - {0}@{1}: {2}".format(host, port, gtids_to_skip)) # Create dictionary to directly access the slaves instances. slaves_dict = rpl_topology.get_slaves_dict() # Skip transactions for the given list of slaves. print("#") if has_gtid_to_skip: for host, port, gtids_to_skip in gtids_by_slave: if gtids_to_skip: # Decompose GTID set into a list of single transactions. gtid_items = gtid_set_itemize(gtids_to_skip) dryrun_mark = '(dry run) ' if dryrun else '' print("# {0}Injecting empty transactions for '{1}:{2}'" "...".format(dryrun_mark, host, port)) slave_key = '{0}@{1}'.format(host, port) slave_srv = slaves_dict[slave_key]['instance'] for uuid, trx_list in gtid_items: for trx_num in trx_list: trx_to_skip = '{0}:{1}'.format(uuid, trx_num) if verbosity: print("# - {0}".format(trx_to_skip)) if not dryrun: # Inject empty transaction. slave_srv.inject_empty_trx( trx_to_skip, gtid_next_automatic=False) if not dryrun: slave_srv.set_gtid_next_automatic() else: print("# No transaction to skip.") print("#\n#...done.\n#")