1
0
mirror of https://github.com/codership/wsrep-lib.git synced 2025-07-30 07:23:07 +03:00

Added open(), close(), cleanup() methods to client_state.

Depending on the DBMS client session allocation strategy the
client id may or may not be available when the client_session
is constructed, therefore there should be a method to assign
an id after construction. Close/cleanup methods were added to
clean up open transactions appropriately.
This commit is contained in:
Teemu Ollakka
2018-06-20 10:07:55 +03:00
parent 779f84e5df
commit bf7dad6815
9 changed files with 120 additions and 21 deletions

View File

@ -8,7 +8,7 @@ include(CheckIncludeFile)
include(CTest) include(CTest)
# Options # Options
option(WITH_AUTO_TEST "Run unit tests automatically after build" ON) option(WITH_AUTO_TEST "Run unit tests automatically after build" OFF)
option(WITH_ASAN "Enable address sanitizer" OFF) option(WITH_ASAN "Enable address sanitizer" OFF)
option(WITH_TSAN "Enable thread sanitizer" OFF) option(WITH_TSAN "Enable thread sanitizer" OFF)

View File

@ -23,11 +23,14 @@ db::client::client(db::server& server,
void db::client::start() void db::client::start()
{ {
client_state_.open(client_state_.id());
for (size_t i(0); i < params_.n_transactions; ++i) for (size_t i(0); i < params_.n_transactions; ++i)
{ {
run_one_transaction(); run_one_transaction();
report_progress(i + 1); report_progress(i + 1);
} }
client_state_.close();
client_state_.cleanup();
} }
bool db::client::bf_abort(wsrep::seqno seqno) bool db::client::bf_abort(wsrep::seqno seqno)

View File

@ -34,6 +34,7 @@ int db::client_service::rollback()
assert(ret == 0); assert(ret == 0);
return ret; return ret;
} }
enum wsrep::provider::status enum wsrep::provider::status
db::client_service::replay() db::client_service::replay()
{ {

View File

@ -35,6 +35,7 @@ void db::server::applier_thread()
simulator_.params()); simulator_.params());
wsrep::client_state* cc(static_cast<wsrep::client_state*>( wsrep::client_state* cc(static_cast<wsrep::client_state*>(
&applier.client_state())); &applier.client_state()));
cc->open(cc->id());
enum wsrep::provider::status ret( enum wsrep::provider::status ret(
server_state_.provider().run_applier(cc)); server_state_.provider().run_applier(cc));
wsrep::log_info() << "Applier thread exited with error code " << ret; wsrep::log_info() << "Applier thread exited with error code " << ret;

View File

@ -33,7 +33,7 @@ namespace wsrep
e_append_fragment_error e_append_fragment_error
}; };
static inline std::string to_string(enum client_error error) static inline const char* to_string(enum client_error error)
{ {
switch (error) switch (error)
{ {
@ -73,6 +73,10 @@ namespace wsrep
*/ */
enum state enum state
{ {
/**
* Client session has not been initialized yet.
*/
s_none,
/** /**
* Client is idle, the control is in the application which * Client is idle, the control is in the application which
* uses the DBMS system. * uses the DBMS system.
@ -102,7 +106,7 @@ namespace wsrep
*/ */
void store_globals() void store_globals()
{ {
thread_id_ = wsrep::this_thread::get_id(); current_thread_id_ = wsrep::this_thread::get_id();
} }
/** /**
@ -112,6 +116,33 @@ namespace wsrep
{ {
assert(transaction_.active() == false); assert(transaction_.active() == false);
} }
/** @name Client session handling */
/** @{ */
/**
* This method should be called when opening the client session.
*
* Initializes client id and changes the state to s_idle.
*/
void open(wsrep::client_id);
/**
* This method should be called before closing the client session.
*
* The state is changed to s_quitting and any open transactions
* are rolled back.
*/
void close();
/**
* This method should be called after closing the client session
* to clean up.
*
* The state is changed to s_none.
*/
void cleanup();
/** @} */
/** @name Client command handling */ /** @name Client command handling */
/** @{ */ /** @{ */
/** /**
@ -306,13 +337,19 @@ namespace wsrep
/** @} */ /** @} */
int before_rollback() int before_rollback()
{ {
assert(state_ == s_idle || state_ == s_exec || state_ == s_result); assert(state_ == s_idle ||
state_ == s_exec ||
state_ == s_result ||
state_ == s_quitting);
return transaction_.before_rollback(); return transaction_.before_rollback();
} }
int after_rollback() int after_rollback()
{ {
assert(state_ == s_idle || state_ == s_exec || state_ == s_result); assert(state_ == s_idle ||
state_ == s_exec ||
state_ == s_result ||
state_ == s_quitting);
return transaction_.after_rollback(); return transaction_.after_rollback();
} }
/** @} */ /** @} */
@ -513,13 +550,14 @@ namespace wsrep
wsrep::client_service& client_service, wsrep::client_service& client_service,
const client_id& id, const client_id& id,
enum mode mode) enum mode mode)
: thread_id_(wsrep::this_thread::get_id()) : owning_thread_id_(wsrep::this_thread::get_id())
, current_thread_id_(owning_thread_id_)
, mutex_(mutex) , mutex_(mutex)
, server_state_(server_state) , server_state_(server_state)
, client_service_(client_service) , client_service_(client_service)
, id_(id) , id_(id)
, mode_(mode) , mode_(mode)
, state_(s_idle) , state_(s_none)
, transaction_(*this) , transaction_(*this)
, allow_dirty_reads_() , allow_dirty_reads_()
, debug_log_level_(0) , debug_log_level_(0)
@ -539,7 +577,8 @@ namespace wsrep
void state(wsrep::unique_lock<wsrep::mutex>& lock, enum state state); void state(wsrep::unique_lock<wsrep::mutex>& lock, enum state state);
void override_error(enum wsrep::client_error error); void override_error(enum wsrep::client_error error);
wsrep::thread::id thread_id_; wsrep::thread::id owning_thread_id_;
wsrep::thread::id current_thread_id_;
wsrep::mutex& mutex_; wsrep::mutex& mutex_;
wsrep::server_state& server_state_; wsrep::server_state& server_state_;
wsrep::client_service& client_service_; wsrep::client_service& client_service_;
@ -552,6 +591,18 @@ namespace wsrep
wsrep::client_error current_error_; wsrep::client_error current_error_;
}; };
static inline const char* to_string(enum wsrep::client_state::state state)
{
switch (state)
{
case wsrep::client_state::s_none: return "none";
case wsrep::client_state::s_idle: return "idle";
case wsrep::client_state::s_exec: return "exec";
case wsrep::client_state::s_result: return "result";
case wsrep::client_state::s_quitting: return "quit";
}
return "unknown";
}
class client_state_switch class client_state_switch
{ {
public: public:

View File

@ -15,9 +15,35 @@ wsrep::provider& wsrep::client_state::provider() const
return server_state_.provider(); return server_state_.provider();
} }
void wsrep::client_state::open(wsrep::client_id id)
{
wsrep::unique_lock<wsrep::mutex> lock(mutex_);
owning_thread_id_ = wsrep::this_thread::get_id();
current_thread_id_ = owning_thread_id_;
state(lock, s_idle);
id_ = id;
}
void wsrep::client_state::close()
{
wsrep::unique_lock<wsrep::mutex> lock(mutex_);
state(lock, s_quitting);
lock.unlock();
if (transaction_.active())
{
client_service_.rollback();
}
}
void wsrep::client_state::cleanup()
{
wsrep::unique_lock<wsrep::mutex> lock(mutex_);
state(lock, s_none);
}
void wsrep::client_state::override_error(enum wsrep::client_error error) void wsrep::client_state::override_error(enum wsrep::client_error error)
{ {
assert(wsrep::this_thread::get_id() == thread_id_); assert(wsrep::this_thread::get_id() == owning_thread_id_);
if (current_error_ != wsrep::e_success && if (current_error_ != wsrep::e_success &&
error == wsrep::e_success) error == wsrep::e_success)
{ {
@ -222,15 +248,16 @@ void wsrep::client_state::state(
wsrep::unique_lock<wsrep::mutex>& lock WSREP_UNUSED, wsrep::unique_lock<wsrep::mutex>& lock WSREP_UNUSED,
enum wsrep::client_state::state state) enum wsrep::client_state::state state)
{ {
assert(wsrep::this_thread::get_id() == thread_id_); assert(wsrep::this_thread::get_id() == owning_thread_id_);
assert(lock.owns_lock()); assert(lock.owns_lock());
static const char allowed[state_max_][state_max_] = static const char allowed[state_max_][state_max_] =
{ {
/* idle exec result quit */ /* none idle exec result quit */
{ 0, 1, 0, 1}, /* idle */ { 0, 1, 0, 0, 0}, /* none */
{ 0, 0, 1, 0}, /* exec */ { 0, 0, 1, 0, 1}, /* idle */
{ 1, 0, 0, 1}, /* result */ { 0, 0, 0, 1, 0}, /* exec */
{ 0, 0, 0, 0} /* quit */ { 0, 1, 0, 0, 0}, /* result */
{ 1, 0, 0, 0, 0} /* quit */
}; };
if (allowed[state_][state]) if (allowed[state_][state])
{ {

View File

@ -21,6 +21,7 @@ namespace
wsrep::client_state::m_replicating) wsrep::client_state::m_replicating)
, tc(cc.transaction()) , tc(cc.transaction())
{ {
cc.open(cc.id());
BOOST_REQUIRE(cc.before_command() == 0); BOOST_REQUIRE(cc.before_command() == 0);
BOOST_REQUIRE(cc.before_statement() == 0); BOOST_REQUIRE(cc.before_statement() == 0);
// Verify initial state // Verify initial state
@ -40,6 +41,7 @@ namespace
wsrep::client_state::m_replicating) wsrep::client_state::m_replicating)
, tc(cc.transaction()) , tc(cc.transaction())
{ {
cc.open(cc.id());
BOOST_REQUIRE(cc.before_command() == 0); BOOST_REQUIRE(cc.before_command() == 0);
BOOST_REQUIRE(cc.before_statement() == 0); BOOST_REQUIRE(cc.before_statement() == 0);
// Verify initial state // Verify initial state
@ -59,6 +61,7 @@ namespace
wsrep::client_state::m_replicating) wsrep::client_state::m_replicating)
, tc(cc.transaction()) , tc(cc.transaction())
{ {
cc.open(cc.id());
cc.do_2pc_ = true; cc.do_2pc_ = true;
BOOST_REQUIRE(cc.before_command() == 0); BOOST_REQUIRE(cc.before_command() == 0);
BOOST_REQUIRE(cc.before_statement() == 0); BOOST_REQUIRE(cc.before_statement() == 0);
@ -79,6 +82,7 @@ namespace
wsrep::client_state::m_replicating) wsrep::client_state::m_replicating)
, tc(cc.transaction()) , tc(cc.transaction())
{ {
cc.open(cc.id());
cc.is_autocommit_ = true; cc.is_autocommit_ = true;
BOOST_REQUIRE(cc.before_command() == 0); BOOST_REQUIRE(cc.before_command() == 0);
BOOST_REQUIRE(cc.before_statement() == 0); BOOST_REQUIRE(cc.before_statement() == 0);
@ -101,6 +105,7 @@ namespace
wsrep::client_state::m_high_priority) wsrep::client_state::m_high_priority)
, tc(cc.transaction()) , tc(cc.transaction())
{ {
cc.open(cc.id());
BOOST_REQUIRE(cc.before_command() == 0); BOOST_REQUIRE(cc.before_command() == 0);
BOOST_REQUIRE(cc.before_statement() == 0); BOOST_REQUIRE(cc.before_statement() == 0);
wsrep::ws_handle ws_handle(1, (void*)1); wsrep::ws_handle ws_handle(1, (void*)1);
@ -129,6 +134,7 @@ namespace
wsrep::client_state::m_high_priority) wsrep::client_state::m_high_priority)
, tc(cc.transaction()) , tc(cc.transaction())
{ {
cc.open(cc.id());
cc.do_2pc_ = true; cc.do_2pc_ = true;
BOOST_REQUIRE(cc.before_command() == 0); BOOST_REQUIRE(cc.before_command() == 0);
BOOST_REQUIRE(cc.before_statement() == 0); BOOST_REQUIRE(cc.before_statement() == 0);
@ -157,6 +163,7 @@ namespace
wsrep::client_state::m_replicating) wsrep::client_state::m_replicating)
, tc(cc.transaction()) , tc(cc.transaction())
{ {
cc.open(cc.id());
BOOST_REQUIRE(cc.before_command() == 0); BOOST_REQUIRE(cc.before_command() == 0);
BOOST_REQUIRE(cc.before_statement() == 0); BOOST_REQUIRE(cc.before_statement() == 0);
// Verify initial state // Verify initial state
@ -178,6 +185,7 @@ namespace
wsrep::client_state::m_replicating) wsrep::client_state::m_replicating)
, tc(cc.transaction()) , tc(cc.transaction())
{ {
cc.open(cc.id());
BOOST_REQUIRE(cc.before_command() == 0); BOOST_REQUIRE(cc.before_command() == 0);
BOOST_REQUIRE(cc.before_statement() == 0); BOOST_REQUIRE(cc.before_statement() == 0);
// Verify initial state // Verify initial state
@ -199,6 +207,7 @@ namespace
wsrep::client_state::m_replicating) wsrep::client_state::m_replicating)
, tc(cc.transaction()) , tc(cc.transaction())
{ {
cc.open(cc.id());
BOOST_REQUIRE(cc.before_command() == 0); BOOST_REQUIRE(cc.before_command() == 0);
BOOST_REQUIRE(cc.before_statement() == 0); BOOST_REQUIRE(cc.before_statement() == 0);
// Verify initial state // Verify initial state

View File

@ -32,15 +32,20 @@ namespace wsrep
{ return provider_; } { return provider_; }
wsrep::client_state* local_client_state() wsrep::client_state* local_client_state()
{ {
return new wsrep::mock_client( wsrep::client_state* ret(new wsrep::mock_client(
*this, ++last_client_id_, *this, ++last_client_id_,
wsrep::client_state::m_local); wsrep::client_state::m_local));
ret->open(ret->id());
return ret;
} }
wsrep::client_state* streaming_applier_client_state() wsrep::client_state* streaming_applier_client_state()
{ {
return new wsrep::mock_client( wsrep::client_state* ret(
*this, ++last_client_id_, new wsrep::mock_client(
wsrep::client_state::m_high_priority); *this, ++last_client_id_,
wsrep::client_state::m_high_priority));
ret->open(ret->id());
return ret;
} }
void release_client_state(wsrep::client_state* client_state) void release_client_state(wsrep::client_state* client_state)

View File

@ -23,6 +23,7 @@ namespace
wsrep::provider::flag::start_transaction | wsrep::provider::flag::start_transaction |
wsrep::provider::flag::commit) wsrep::provider::flag::commit)
{ {
cc.open(cc.id());
} }
wsrep::mock_server_state sc; wsrep::mock_server_state sc;
wsrep::mock_client cc; wsrep::mock_client cc;
@ -94,6 +95,7 @@ BOOST_AUTO_TEST_CASE(server_state_streaming)
wsrep::stid(wsrep::id("1"), 1, 1), wsrep::stid(wsrep::id("1"), 1, 1),
wsrep::seqno(0), wsrep::seqno(0),
wsrep::provider::flag::start_transaction); wsrep::provider::flag::start_transaction);
cc.open(cc.id());
BOOST_REQUIRE(sc.on_apply(cc, ws_handle, ws_meta, BOOST_REQUIRE(sc.on_apply(cc, ws_handle, ws_meta,
wsrep::const_buffer("1", 1)) == 0); wsrep::const_buffer("1", 1)) == 0);
BOOST_REQUIRE(sc.find_streaming_applier( BOOST_REQUIRE(sc.find_streaming_applier(