Merge branch '2.3' into 2.4
This commit is contained in:
		
							
								
								
									
										106
									
								
								BUILD/mdbci/create_full_repo.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										106
									
								
								BUILD/mdbci/create_full_repo.sh
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,106 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# $box - Vagrant box to be used for build
 | 
			
		||||
 | 
			
		||||
# $target - name of repository to put results
 | 
			
		||||
 | 
			
		||||
# $cmake_flags - cmake flags to be used in the build
 | 
			
		||||
 | 
			
		||||
# $MDBCI_VM_PATH - path to the MDBCI virtual machies directory
 | 
			
		||||
 | 
			
		||||
# $source - reference to the point in the source code repository
 | 
			
		||||
 | 
			
		||||
# $do_not_destroy_vm - if "yes" VM stays alive after the build
 | 
			
		||||
 | 
			
		||||
# $try_already_running - if "yes" already running VM will be used for build
 | 
			
		||||
 | 
			
		||||
# $gpg_keys_path - path to the directory containing GPG keys for repo signing
 | 
			
		||||
# directory have to contain only one file *.public and only one *.private
 | 
			
		||||
 | 
			
		||||
set -x
 | 
			
		||||
 | 
			
		||||
# read the name of build scripts directory
 | 
			
		||||
export script_dir="$(dirname $(readlink -f $0))"
 | 
			
		||||
 | 
			
		||||
# load all needed variables
 | 
			
		||||
. ${script_dir}/set_build_variables.sh
 | 
			
		||||
 | 
			
		||||
export platform=`${mdbci_dir}/mdbci show boxinfo --box-name=$box --field='platform' --silent`
 | 
			
		||||
export platform_version=`${mdbci_dir}/mdbci show boxinfo --box-name=$box --field='platform_version' --silent`
 | 
			
		||||
export dist_sfx="$platform"."$platform_version"
 | 
			
		||||
 | 
			
		||||
# prerare VM
 | 
			
		||||
export provider=`${mdbci_dir}/mdbci show provider $box --silent 2> /dev/null`
 | 
			
		||||
export name="$box-${JOB_NAME}-${BUILD_NUMBER}"
 | 
			
		||||
export name=`echo $name | sed "s|/|-|g"`
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# destroying existing box
 | 
			
		||||
if [ -d "$MDBCI_VM_PATH/${name}" ]; then
 | 
			
		||||
	${mdbci_dir}/mdbci destroy $name
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
  eval "cat <<EOF
 | 
			
		||||
$(<${script_dir}/templates/build.json.template)
 | 
			
		||||
" 2> /dev/null > $MDBCI_VM_PATH/${name}.json
 | 
			
		||||
 | 
			
		||||
# starting VM for build
 | 
			
		||||
echo "Generating build VM template"
 | 
			
		||||
${mdbci_dir}/mdbci --override --template $MDBCI_VM_PATH/$name.json generate $name
 | 
			
		||||
echo "starting VM for build"
 | 
			
		||||
${mdbci_dir}/mdbci up --attempts=1 $name
 | 
			
		||||
if [ $? != 0 ] ; then
 | 
			
		||||
	echo "Error starting VM"
 | 
			
		||||
	exit 1
 | 
			
		||||
fi
 | 
			
		||||
echo "copying public keys to VM"
 | 
			
		||||
cp  ~/build-scripts/team_keys .
 | 
			
		||||
${mdbci_dir}/mdbci public_keys --key team_keys --silent $name
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
echo "Get VM info"
 | 
			
		||||
export sshuser=`${mdbci_dir}/mdbci ssh --command 'whoami' --silent $name/build 2> /dev/null | tr -d '\r'`
 | 
			
		||||
export IP=`${mdbci_dir}/mdbci show network $name/build --silent 2> /dev/null`
 | 
			
		||||
export sshkey=`${mdbci_dir}/mdbci show keyfile $name/build --silent 2> /dev/null | sed 's/"//g'`
 | 
			
		||||
export scpopt="-i $sshkey -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o ConnectTimeout=120 "
 | 
			
		||||
export sshopt="$scpopt $sshuser@$IP"
 | 
			
		||||
 | 
			
		||||
rm -rf $pre_repo_dir/$target/$box
 | 
			
		||||
mkdir -p $pre_repo_dir/$target/SRC
 | 
			
		||||
mkdir -p $pre_repo_dir/$target/$box
 | 
			
		||||
 | 
			
		||||
export work_dir="MaxScale"
 | 
			
		||||
export orig_image=$box
 | 
			
		||||
 | 
			
		||||
ssh $sshopt "sudo rm -rf $work_dir"
 | 
			
		||||
echo "copying stuff to $image machine"
 | 
			
		||||
ssh $sshopt "mkdir -p $work_dir"
 | 
			
		||||
 | 
			
		||||
rsync -avz --delete -e "ssh $scpopt" ${script_dir}/../../ $sshuser@$IP:./$work_dir/
 | 
			
		||||
if [ $? -ne 0 ] ; then
 | 
			
		||||
  echo "Error copying stuff to $box machine"
 | 
			
		||||
  exit 2
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
ssh $sshopt ./MaxScale/BUILD/install_build_deps.sh
 | 
			
		||||
${script_dir}/create_remote_repo.sh full_repo
 | 
			
		||||
export build_result=$?
 | 
			
		||||
 | 
			
		||||
if [ ${build_result} -eq 0 ]; then
 | 
			
		||||
        ${script_dir}/copy_repos.sh
 | 
			
		||||
        export build_result=$?
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo "Removing locks and destroying VM"
 | 
			
		||||
 | 
			
		||||
if [[ "$do_not_destroy_vm" != "yes" && "$try_already_running" != "yes" ]] ; then
 | 
			
		||||
  echo "Destroying VM"
 | 
			
		||||
  ${mdbci_dir}/mdbci destroy $name
 | 
			
		||||
fi
 | 
			
		||||
cd $dir
 | 
			
		||||
 | 
			
		||||
if [ $build_result -ne 0 ] ; then
 | 
			
		||||
        echo "Build FAILED!"
 | 
			
		||||
        exit $build_result
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,12 @@ echo " creating dirs on VM"
 | 
			
		||||
ssh $sshopt "mkdir -p dest ; mkdir -p src; mkdir gpg_keys"
 | 
			
		||||
 | 
			
		||||
echo "copying stuff to VM"
 | 
			
		||||
scp $scpopt $pre_repo_dir/$target/$box/* $sshuser@$IP:src/
 | 
			
		||||
if [ $1 == "full_repo" ] ; then
 | 
			
		||||
         find  ${repo_path}/maxscale-${major_ver}.*-release/mariadb-maxscale/${platform}/${platform_version}/* -name "*.rpm" -exec scp $scpopt {} $sshuser@$IP:src/ \;
 | 
			
		||||
         find  ${repo_path}/maxscale-${major_ver}.*-release/mariadb-maxscale/${platform}/dists/${platform_version}/* -name "*.deb" -exec scp $scpopt {} $sshuser@$IP:src/ \;
 | 
			
		||||
else
 | 
			
		||||
         scp $scpopt $pre_repo_dir/$target/$box/* $sshuser@$IP:src/
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
scp $scpopt -r ${gpg_keys_path}/* $sshuser@$IP:./gpg_keys/
 | 
			
		||||
ssh $sshopt "key=\`ls ~/gpg_keys/*.public -1\` ; gpg --import \$key"
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,11 @@
 | 
			
		||||
  {
 | 
			
		||||
        "hostname" : "default",
 | 
			
		||||
        "memory_size" : "4096",
 | 
			
		||||
        "box" : "$box"
 | 
			
		||||
        "box" : "$box",
 | 
			
		||||
        "product" : {
 | 
			
		||||
                "name": "docker"
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -303,6 +303,16 @@ public:
 | 
			
		||||
        return m_state & FATAL_FAILURE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Is the backend replaying session command history
 | 
			
		||||
     *
 | 
			
		||||
     * @return If a list of session commands was provided at connect time, the function returns true as long
 | 
			
		||||
     *         as the backend has not completed those session commands.
 | 
			
		||||
     */
 | 
			
		||||
    inline bool is_replaying_history() const
 | 
			
		||||
    {
 | 
			
		||||
        return m_history_size > 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Get the object name of this server
 | 
			
		||||
@ -389,7 +399,8 @@ private:
 | 
			
		||||
 | 
			
		||||
    maxbase::StopWatch     m_session_timer;
 | 
			
		||||
    maxbase::IntervalTimer m_select_timer;
 | 
			
		||||
    int64_t                m_num_selects = 0;
 | 
			
		||||
    int64_t                m_num_selects {0};
 | 
			
		||||
    int64_t                m_history_size {0};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef std::shared_ptr<Backend> SBackend;
 | 
			
		||||
 | 
			
		||||
@ -1001,6 +1001,9 @@ add_test_executable(sr_basics.cpp sr_basics sr_basics LABELS REPL_BACKEND)
 | 
			
		||||
# MXS-2490: Direct execution doesn't work with MaxScale
 | 
			
		||||
add_test_executable(mxs2490_ps_execute_direct.cpp mxs2490_ps_execute_direct replication LABELS REPL_BACKEND readwritesplit)
 | 
			
		||||
 | 
			
		||||
# MXS-2609: Maxscale crash in RWSplitSession::retry_master_query()
 | 
			
		||||
add_test_executable(mxs2609_history_replay.cpp mxs2609_history_replay mxs2609_history_replay LABELS readwritesplit REPL_BACKEND)
 | 
			
		||||
 | 
			
		||||
# MXS-2621: Incorrect SQL if lower_case_table_names is used.
 | 
			
		||||
add_test_executable(mxs2621_lower_case_tables.cpp mxs2621_lower_case_tables mxs2621_lower_case_tables LABELS REPL_BACKEND)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										27
									
								
								maxscale-system-test/cnf/maxscale.cnf.template.mxs2609_history_replay
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										27
									
								
								maxscale-system-test/cnf/maxscale.cnf.template.mxs2609_history_replay
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
[maxscale]
 | 
			
		||||
threads=###threads###
 | 
			
		||||
 | 
			
		||||
###server###
 | 
			
		||||
 | 
			
		||||
[MySQL-Monitor]
 | 
			
		||||
type=monitor
 | 
			
		||||
module=mariadbmon
 | 
			
		||||
servers=###server_line###
 | 
			
		||||
user=maxskysql
 | 
			
		||||
password=skysql
 | 
			
		||||
monitor_interval=1000
 | 
			
		||||
 | 
			
		||||
[RW-Split-Router]
 | 
			
		||||
type=service
 | 
			
		||||
router=readwritesplit
 | 
			
		||||
servers=###server_line###
 | 
			
		||||
user=maxskysql
 | 
			
		||||
password=skysql
 | 
			
		||||
transaction_replay=true
 | 
			
		||||
master_accept_reads=true
 | 
			
		||||
 | 
			
		||||
[RW-Split-Listener]
 | 
			
		||||
type=listener
 | 
			
		||||
service=RW-Split-Router
 | 
			
		||||
protocol=MySQLClient
 | 
			
		||||
port=4006
 | 
			
		||||
							
								
								
									
										69
									
								
								maxscale-system-test/mxs2609_history_replay.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								maxscale-system-test/mxs2609_history_replay.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,69 @@
 | 
			
		||||
/**
 | 
			
		||||
 * MXS-2609: Maxscale crash in RWSplitSession::retry_master_query()
 | 
			
		||||
 *
 | 
			
		||||
 * https://jira.mariadb.org/browse/MXS-2609
 | 
			
		||||
 *
 | 
			
		||||
 * This test attempts to reproduce the crash described in MXS-2609 which
 | 
			
		||||
 * occurred during a retrying attempt of a session command that failed on
 | 
			
		||||
 * the master.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "testconnections.h"
 | 
			
		||||
 | 
			
		||||
int main(int argc, char** argv)
 | 
			
		||||
{
 | 
			
		||||
    TestConnections test(argc, argv);
 | 
			
		||||
 | 
			
		||||
    auto block = [&test](int n){
 | 
			
		||||
                     test.repl->block_node(n);
 | 
			
		||||
                     test.maxscales->wait_for_monitor();
 | 
			
		||||
                     test.repl->unblock_node(n);
 | 
			
		||||
                     test.maxscales->wait_for_monitor();
 | 
			
		||||
                 };
 | 
			
		||||
    auto conn = test.maxscales->rwsplit();
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // Test 1: Master failure mid-reconnect should trigger query replay
 | 
			
		||||
    //
 | 
			
		||||
 | 
			
		||||
    test.expect(conn.connect(), "First connect should work: %s", conn.error());
 | 
			
		||||
 | 
			
		||||
    // Queue up session commands so that the history replay takes some time
 | 
			
		||||
    for (int i = 0; i < 10; i++)
 | 
			
		||||
    {
 | 
			
		||||
        conn.query("SET @a = (SLEEP 1)");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    block(0);
 | 
			
		||||
 | 
			
		||||
    test.set_timeout(90);
 | 
			
		||||
 | 
			
		||||
    std::thread([&](){
 | 
			
		||||
                    sleep(5);
 | 
			
		||||
                    block(0);
 | 
			
		||||
                }).detach();
 | 
			
		||||
 | 
			
		||||
    test.expect(conn.query("SELECT @@last_insert_id"), "Query should work: %s", conn.error());
 | 
			
		||||
 | 
			
		||||
    test.stop_timeout();
 | 
			
		||||
    conn.disconnect();
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
    // Test 2: Exceed history limit and trigger a master reconnection
 | 
			
		||||
    //
 | 
			
		||||
 | 
			
		||||
    test.maxctrl("alter service RW-Split-Router max_sescmd_history 2");
 | 
			
		||||
    test.expect(conn.connect(), "Second should work: %s", conn.error());
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < 5; i++)
 | 
			
		||||
    {
 | 
			
		||||
        conn.query("SET @a = (SLEEP 1)");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    block(0);
 | 
			
		||||
 | 
			
		||||
    test.expect(!conn.query("SELECT @@last_insert_id"), "Query should fail");
 | 
			
		||||
 | 
			
		||||
    return test.global_result;
 | 
			
		||||
}
 | 
			
		||||
@ -54,6 +54,7 @@ void Backend::close(close_type type)
 | 
			
		||||
        m_closed = true;
 | 
			
		||||
        m_closed_at = time(NULL);
 | 
			
		||||
        m_session_commands.clear();
 | 
			
		||||
        m_history_size = 0;
 | 
			
		||||
 | 
			
		||||
        if (in_use())
 | 
			
		||||
        {
 | 
			
		||||
@ -139,6 +140,12 @@ uint64_t Backend::complete_session_command()
 | 
			
		||||
{
 | 
			
		||||
    uint64_t rval = m_session_commands.front()->get_position();
 | 
			
		||||
    m_session_commands.pop_front();
 | 
			
		||||
 | 
			
		||||
    if (m_history_size > 0)
 | 
			
		||||
    {
 | 
			
		||||
        --m_history_size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return rval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -192,10 +199,12 @@ bool Backend::connect(MXS_SESSION* session, SessionCommandList* sescmd)
 | 
			
		||||
        m_state = IN_USE;
 | 
			
		||||
        mxb::atomic::add(&m_backend->connections, 1, mxb::atomic::RELAXED);
 | 
			
		||||
        rval = true;
 | 
			
		||||
        m_history_size = 0;
 | 
			
		||||
 | 
			
		||||
        if (sescmd && sescmd->size())
 | 
			
		||||
        if (sescmd && !sescmd->empty())
 | 
			
		||||
        {
 | 
			
		||||
            append_session_command(*sescmd);
 | 
			
		||||
            m_history_size = sescmd->size();
 | 
			
		||||
 | 
			
		||||
            if (!execute_session_command())
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
@ -58,7 +58,7 @@ static std::string do_query(MonitorServer* srv, const char* query)
 | 
			
		||||
// Returns a numeric version similar to mysql_get_server_version
 | 
			
		||||
int get_cs_version(MonitorServer* srv)
 | 
			
		||||
{
 | 
			
		||||
    int rval = 0;
 | 
			
		||||
    int rval = -1;
 | 
			
		||||
    std::string prefix = "Columnstore ";
 | 
			
		||||
    std::string result = do_query(srv, "SELECT @@version_comment");
 | 
			
		||||
    auto pos = result.find(prefix);
 | 
			
		||||
@ -107,16 +107,21 @@ void CsMonitor::update_server_status(MonitorServer* srv)
 | 
			
		||||
 | 
			
		||||
    if (do_query(srv, alive_query) == "1")
 | 
			
		||||
    {
 | 
			
		||||
        status |= SERVER_RUNNING;
 | 
			
		||||
        auto version = get_cs_version(srv);
 | 
			
		||||
 | 
			
		||||
        if (get_cs_version(srv) >= 10200)
 | 
			
		||||
        if (version >= 0)
 | 
			
		||||
        {
 | 
			
		||||
            // 1.2 supports the mcsSystemPrimary function
 | 
			
		||||
            status |= do_query(srv, role_query) == "1" ? SERVER_MASTER : SERVER_SLAVE;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            status |= srv->server == m_primary ? SERVER_MASTER : SERVER_SLAVE;
 | 
			
		||||
            status |= SERVER_RUNNING;
 | 
			
		||||
 | 
			
		||||
            if (version >= 10200)
 | 
			
		||||
            {
 | 
			
		||||
                // 1.2 supports the mcsSystemPrimary function
 | 
			
		||||
                status |= do_query(srv, role_query) == "1" ? SERVER_MASTER : SERVER_SLAVE;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                status |= srv->server == m_primary ? SERVER_MASTER : SERVER_SLAVE;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -355,7 +355,7 @@ bool RWSplitSession::route_single_stmt(GWBUF* querybuf)
 | 
			
		||||
            else if (target->has_session_commands())
 | 
			
		||||
            {
 | 
			
		||||
                // We need to wait until the session commands are executed
 | 
			
		||||
                m_query_queue.emplace_back(gwbuf_clone(querybuf));
 | 
			
		||||
                m_query_queue.emplace_front(gwbuf_clone(querybuf));
 | 
			
		||||
                MXS_INFO("Queuing query until '%s' completes session command", target->name());
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
@ -652,7 +652,8 @@ RWBackend* RWSplitSession::get_master_backend()
 | 
			
		||||
 | 
			
		||||
    if (master)
 | 
			
		||||
    {
 | 
			
		||||
        if (master->in_use() || (m_config.master_reconnection && master->can_connect()))
 | 
			
		||||
        if (master->in_use()
 | 
			
		||||
            || (m_config.master_reconnection && master->can_connect() && can_recover_servers()))
 | 
			
		||||
        {
 | 
			
		||||
            if (can_continue_using_master(master))
 | 
			
		||||
            {
 | 
			
		||||
@ -667,7 +668,8 @@ RWBackend* RWSplitSession::get_master_backend()
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            MXS_ERROR("Server '%s' is not in use and can't be chosen as the master.",
 | 
			
		||||
            MXS_ERROR("Cannot choose server '%s' as the master because it is not "
 | 
			
		||||
                      "in use and a new connection to it cannot be created.",
 | 
			
		||||
                      master->name());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -957,17 +957,40 @@ bool RWSplitSession::retry_master_query(RWBackend* backend)
 | 
			
		||||
{
 | 
			
		||||
    bool can_continue = false;
 | 
			
		||||
 | 
			
		||||
    if (backend->has_session_commands())
 | 
			
		||||
    if (backend->is_replaying_history())
 | 
			
		||||
    {
 | 
			
		||||
        // Try to route the session command again. If the master is not available, the response will be
 | 
			
		||||
        // returned from one of the slaves.
 | 
			
		||||
        // Master failed while it was replaying the session command history
 | 
			
		||||
        mxb_assert(m_config.master_reconnection);
 | 
			
		||||
        mxb_assert(!m_query_queue.empty());
 | 
			
		||||
 | 
			
		||||
        retry_query(m_query_queue.front().release());
 | 
			
		||||
        m_query_queue.pop_front();
 | 
			
		||||
        can_continue = true;
 | 
			
		||||
    }
 | 
			
		||||
    else if (backend->has_session_commands())
 | 
			
		||||
    {
 | 
			
		||||
        // We were routing a session command to all servers but the master server from which the response
 | 
			
		||||
        // was expected failed: try to route the session command again. If the master is not available,
 | 
			
		||||
        // the response will be returned from one of the slaves if the configuration allows it.
 | 
			
		||||
 | 
			
		||||
        mxb_assert(backend->next_session_command()->get_position() == m_recv_sescmd + 1);
 | 
			
		||||
        mxb_assert(m_qc.current_route_info().target() == TARGET_ALL);
 | 
			
		||||
        mxb_assert(!m_current_query.get());
 | 
			
		||||
        mxb_assert(!m_sescmd_list.empty());
 | 
			
		||||
        mxb_assert(m_sescmd_count >= 2);
 | 
			
		||||
        MXS_INFO("Retrying session command due to master failure: %s",
 | 
			
		||||
                 backend->next_session_command()->to_string().c_str());
 | 
			
		||||
 | 
			
		||||
        // MXS-2609: Maxscale crash in RWSplitSession::retry_master_query()
 | 
			
		||||
        // To prevent a crash from happening, we make sure the session command list is not empty before
 | 
			
		||||
        // we touch it. This should be converted into a debug assertion once the true root cause of the
 | 
			
		||||
        // problem is found.
 | 
			
		||||
        if (m_sescmd_count < 2 || m_sescmd_list.empty())
 | 
			
		||||
        {
 | 
			
		||||
            MXS_WARNING("Session command list was empty when it should not be");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Before routing it, pop the failed session command off the list and decrement the number of
 | 
			
		||||
        // executed session commands. This "overwrites" the existing command and prevents history duplication.
 | 
			
		||||
        m_sescmd_list.pop_back();
 | 
			
		||||
@ -978,6 +1001,8 @@ bool RWSplitSession::retry_master_query(RWBackend* backend)
 | 
			
		||||
    }
 | 
			
		||||
    else if (m_current_query.get())
 | 
			
		||||
    {
 | 
			
		||||
        // A query was in progress, try to route it again
 | 
			
		||||
        mxb_assert(m_prev_target == backend);
 | 
			
		||||
        retry_query(m_current_query.release());
 | 
			
		||||
        can_continue = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user