mirror of
https://github.com/codership/wsrep-lib.git
synced 2025-07-30 07:23:07 +03:00
Split client_context::after_command() into two stages, before
sending result to client and after the result was sent. Added s_result state to client_context states.
This commit is contained in:
@ -120,6 +120,10 @@ namespace trrep
|
|||||||
* system.
|
* system.
|
||||||
*/
|
*/
|
||||||
s_exec,
|
s_exec,
|
||||||
|
/*!
|
||||||
|
* Client handler is sending result to client.
|
||||||
|
*/
|
||||||
|
s_result,
|
||||||
/*!
|
/*!
|
||||||
* The client session is terminating.
|
* The client session is terminating.
|
||||||
*/
|
*/
|
||||||
@ -136,32 +140,40 @@ namespace trrep
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Virtual method which should be called before the client
|
* Method which should be called before the client
|
||||||
* starts processing the command received from the application.
|
* starts processing the command received from the application.
|
||||||
* This method will wait until the possible synchronous
|
* This method will wait until the possible synchronous
|
||||||
* rollback for associated transaction has finished.
|
* rollback for associated transaction has finished.
|
||||||
* The method has a side effect of changing the client
|
* The method has a side effect of changing the client
|
||||||
* context state to executing.
|
* context state to executing.
|
||||||
*
|
*
|
||||||
* If overridden, the implementation should call base
|
|
||||||
* class method before any implementation specific operations.
|
|
||||||
*
|
|
||||||
* \return Zero in case of success, non-zero in case of the
|
* \return Zero in case of success, non-zero in case of the
|
||||||
* associated transaction was BF aborted.
|
* associated transaction was BF aborted.
|
||||||
*/
|
*/
|
||||||
virtual int before_command();
|
int before_command();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Virtual method which should be called before returning
|
* Method which should be called before returning
|
||||||
* the control back to application which uses the DBMS system.
|
* the control back to application which uses the DBMS system.
|
||||||
* This method will check if the transaction associated to
|
* This method will check if the transaction associated to
|
||||||
* the connection has been aborted. This method has a side effect
|
* the connection has been aborted. Rollback is performed
|
||||||
* of changing the client state to idle.
|
* if needed.
|
||||||
*
|
|
||||||
* If overridden, the implementation should call base
|
|
||||||
* class metods after any implementation specifict operations.
|
|
||||||
*/
|
*/
|
||||||
virtual void after_command();
|
void after_command_before_result();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Method which should be called after returning the
|
||||||
|
* control back to application which uses the DBMS system.
|
||||||
|
* The method will do the check if the transaction associated
|
||||||
|
* to the connection has been aborted. If so, rollback is
|
||||||
|
* performed and the transaction is left to aborted state
|
||||||
|
* so that the client will get appropriate error on next
|
||||||
|
* command.
|
||||||
|
*
|
||||||
|
* This method has a side effect of changing state to
|
||||||
|
* idle.
|
||||||
|
*/
|
||||||
|
void after_command_after_result();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Before statement execution operations.
|
* Before statement execution operations.
|
||||||
@ -176,7 +188,7 @@ namespace trrep
|
|||||||
* is not allowed to be executed due to read or write
|
* is not allowed to be executed due to read or write
|
||||||
* isolation requirements.
|
* isolation requirements.
|
||||||
*/
|
*/
|
||||||
virtual int before_statement();
|
int before_statement();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* After statement execution operations.
|
* After statement execution operations.
|
||||||
@ -187,7 +199,7 @@ namespace trrep
|
|||||||
* If overridden by the implementation, base class method
|
* If overridden by the implementation, base class method
|
||||||
* should be called after any implementation specific operations.
|
* should be called after any implementation specific operations.
|
||||||
*/
|
*/
|
||||||
virtual void after_statement();
|
void after_statement();
|
||||||
|
|
||||||
int start_transaction()
|
int start_transaction()
|
||||||
{
|
{
|
||||||
|
@ -40,9 +40,10 @@ int trrep::client_context::before_command()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void trrep::client_context::after_command()
|
void trrep::client_context::after_command_before_result()
|
||||||
{
|
{
|
||||||
trrep::unique_lock<trrep::mutex> lock(mutex_);
|
trrep::unique_lock<trrep::mutex> lock(mutex_);
|
||||||
|
assert(state() == s_exec);
|
||||||
if (transaction_.active() &&
|
if (transaction_.active() &&
|
||||||
transaction_.state() == trrep::transaction_context::s_must_abort)
|
transaction_.state() == trrep::transaction_context::s_must_abort)
|
||||||
{
|
{
|
||||||
@ -54,6 +55,26 @@ void trrep::client_context::after_command()
|
|||||||
assert(transaction_.state() == trrep::transaction_context::s_aborted);
|
assert(transaction_.state() == trrep::transaction_context::s_aborted);
|
||||||
assert(current_error() != trrep::e_success);
|
assert(current_error() != trrep::e_success);
|
||||||
}
|
}
|
||||||
|
state(lock, s_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void trrep::client_context::after_command_after_result()
|
||||||
|
{
|
||||||
|
trrep::unique_lock<trrep::mutex> lock(mutex_);
|
||||||
|
assert(state() == s_result);
|
||||||
|
if (transaction_.active() &&
|
||||||
|
transaction_.state() == trrep::transaction_context::s_must_abort)
|
||||||
|
{
|
||||||
|
// Note: Error is not overridden here as the result has already
|
||||||
|
// been sent to client. The error should be set in before_command()
|
||||||
|
// when the client issues next command.
|
||||||
|
lock.unlock();
|
||||||
|
rollback();
|
||||||
|
transaction_.after_statement();
|
||||||
|
lock.lock();
|
||||||
|
assert(transaction_.state() == trrep::transaction_context::s_aborted);
|
||||||
|
assert(current_error() != trrep::e_success);
|
||||||
|
}
|
||||||
state(lock, s_idle);
|
state(lock, s_idle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,10 +124,11 @@ void trrep::client_context::state(
|
|||||||
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 quit */
|
/* idle exec result quit */
|
||||||
{ 0, 1, 1}, /* idle */
|
{ 0, 1, 0, 1}, /* idle */
|
||||||
{ 1, 0, 1}, /* exec */
|
{ 0, 0, 1, 0}, /* exec */
|
||||||
{ 0, 0, 0}
|
{ 1, 0, 0, 1}, /* result */
|
||||||
|
{ 0, 0, 0, 0} /* quit */
|
||||||
};
|
};
|
||||||
if (allowed[state_][state])
|
if (allowed[state_][state])
|
||||||
{
|
{
|
||||||
|
@ -25,5 +25,6 @@ BOOST_AUTO_TEST_CASE(client_context_test_error_codes)
|
|||||||
trrep_mock::bf_abort_unordered(cc);
|
trrep_mock::bf_abort_unordered(cc);
|
||||||
|
|
||||||
cc.after_statement();
|
cc.after_statement();
|
||||||
cc.after_command();
|
cc.after_command_before_result();
|
||||||
|
cc.after_command_after_result();
|
||||||
}
|
}
|
||||||
|
@ -392,7 +392,8 @@ private:
|
|||||||
}
|
}
|
||||||
after_statement();
|
after_statement();
|
||||||
}
|
}
|
||||||
after_command();
|
after_command_before_result();
|
||||||
|
after_command_after_result();
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +323,8 @@ int trrep::server_context::on_apply(
|
|||||||
if (not_replaying)
|
if (not_replaying)
|
||||||
{
|
{
|
||||||
client_context.after_statement();
|
client_context.after_statement();
|
||||||
client_context.after_command();
|
client_context.after_command_before_result();
|
||||||
|
client_context.after_command_after_result();
|
||||||
}
|
}
|
||||||
assert(ret ||
|
assert(ret ||
|
||||||
txc.state() == trrep::transaction_context::s_committed);
|
txc.state() == trrep::transaction_context::s_committed);
|
||||||
|
Reference in New Issue
Block a user