mirror of
https://github.com/codership/wsrep-lib.git
synced 2025-07-30 07:23:07 +03:00
Support for detaching prepared XA transactions
Add support for detaching XA transactions. This is useful for handling the case where the DBMS client has a transaction in prepared state and disconnects. Before disconnect, the DBMS calls the newly introduced client_state::xa_detach(), to cleanup the local transaction and convert it to a high priority transaction. The DBMS may later attempt to terminate the transaction through client_state::commit_by_xid() or client_state::rollback_by_xid(). Also in this patch: - Fix client_state::close() so that it does not rollback transactions in prepared state - Changed class wsrep::xid representation to hold enough information so that DBMS can convert to its native representation - Fix potential infinite loop in server_state::find_streaming_applier(wsrep:xid&) - Append SR keys on prepare fragment and make it pa_unsafe - Handle one phase commit (simply fall back to two phase) - Do not rollback prepared streaming clients in server_state::close_orphaned_transactions()
This commit is contained in:
@ -50,7 +50,9 @@ void wsrep::client_state::close()
|
||||
debug_log_state("close: enter");
|
||||
state(lock, s_quitting);
|
||||
lock.unlock();
|
||||
if (transaction_.active())
|
||||
if (transaction_.active() &&
|
||||
(mode_ != m_local ||
|
||||
transaction_.state() != wsrep::transaction::s_prepared))
|
||||
{
|
||||
client_service_.bf_rollback();
|
||||
transaction_.after_statement();
|
||||
|
@ -1297,6 +1297,7 @@ wsrep::high_priority_service* wsrep::server_state::find_streaming_applier(
|
||||
{
|
||||
return sa;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -1425,6 +1426,19 @@ void wsrep::server_state::recover_streaming_appliers_if_not_recovered(
|
||||
streaming_appliers_recovered_ = true;
|
||||
}
|
||||
|
||||
class transaction_state_cmp
|
||||
{
|
||||
public:
|
||||
transaction_state_cmp(const enum wsrep::transaction::state s) : state_(s)
|
||||
{ }
|
||||
bool operator()(std::pair<const wsrep::client_id, wsrep::client_state*>& vt) const
|
||||
{
|
||||
return vt.second->transaction().state() == state_;
|
||||
}
|
||||
private:
|
||||
enum wsrep::transaction::state state_;
|
||||
};
|
||||
|
||||
void wsrep::server_state::close_orphaned_sr_transactions(
|
||||
wsrep::unique_lock<wsrep::mutex>& lock,
|
||||
wsrep::high_priority_service& high_priority_service)
|
||||
@ -1445,9 +1459,13 @@ void wsrep::server_state::close_orphaned_sr_transactions(
|
||||
|
||||
if (current_view_.own_index() == -1 || equal_consecutive_views)
|
||||
{
|
||||
while (streaming_clients_.empty() == false)
|
||||
streaming_clients_map::iterator i;
|
||||
transaction_state_cmp prepared_state_cmp(wsrep::transaction::s_prepared);
|
||||
while ((i = std::find_if_not(streaming_clients_.begin(),
|
||||
streaming_clients_.end(),
|
||||
prepared_state_cmp))
|
||||
!= streaming_clients_.end())
|
||||
{
|
||||
streaming_clients_map::iterator i(streaming_clients_.begin());
|
||||
wsrep::client_id client_id(i->first);
|
||||
wsrep::transaction_id transaction_id(i->second->transaction().id());
|
||||
// It is safe to unlock the server state temporarily here.
|
||||
|
@ -326,6 +326,8 @@ int wsrep::transaction::before_prepare(
|
||||
{
|
||||
// Force fragment replication on XA prepare
|
||||
flags(flags() | wsrep::provider::flag::prepare);
|
||||
flags(flags() | wsrep::provider::flag::pa_unsafe);
|
||||
append_sr_keys_for_commit();
|
||||
const bool force_streaming_step = true;
|
||||
ret = streaming_step(lock, force_streaming_step);
|
||||
if (ret == 0)
|
||||
@ -423,15 +425,27 @@ int wsrep::transaction::before_commit()
|
||||
switch (client_state_.mode())
|
||||
{
|
||||
case wsrep::client_state::m_local:
|
||||
if (state() == s_prepared)
|
||||
if (is_xa() &&
|
||||
(state() == s_prepared || state() == s_executing))
|
||||
{
|
||||
assert(is_xa());
|
||||
ret = certify_commit(lock);
|
||||
assert((ret == 0 && state() == s_committing) ||
|
||||
(state() == s_must_abort ||
|
||||
state() == s_must_replay ||
|
||||
state() == s_cert_failed ||
|
||||
state() == s_prepared));
|
||||
ret = 0;
|
||||
if (state() == s_executing)
|
||||
{
|
||||
// XA COMMIT in one phase
|
||||
// This optimization is not supported...
|
||||
// fall back to prepare + commit
|
||||
ret = before_prepare(lock) || after_prepare(lock);
|
||||
}
|
||||
if (!ret)
|
||||
{
|
||||
assert(state() == s_prepared);
|
||||
ret = certify_commit(lock);
|
||||
assert((ret == 0 && state() == s_committing) ||
|
||||
(state() == s_must_abort ||
|
||||
state() == s_must_replay ||
|
||||
state() == s_cert_failed ||
|
||||
state() == s_prepared));
|
||||
}
|
||||
}
|
||||
else if (state() == s_executing)
|
||||
{
|
||||
@ -1084,6 +1098,20 @@ int wsrep::transaction::commit_or_rollback_by_xid(const wsrep::xid& xid,
|
||||
}
|
||||
}
|
||||
|
||||
void wsrep::transaction::xa_detach()
|
||||
{
|
||||
assert(state() == s_prepared);
|
||||
wsrep::server_state& server_state(client_state_.server_state());
|
||||
server_state.convert_streaming_client_to_applier(&client_state_);
|
||||
client_service_.cleanup_transaction();
|
||||
wsrep::unique_lock<wsrep::mutex> lock(client_state_.mutex_);
|
||||
streaming_context_.cleanup();
|
||||
state(lock, s_aborting);
|
||||
state(lock, s_aborted);
|
||||
provider().release(ws_handle_);
|
||||
cleanup();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Private //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1470,7 +1498,7 @@ int wsrep::transaction::certify_commit(
|
||||
state(lock, s_certifying);
|
||||
lock.unlock();
|
||||
|
||||
if (is_streaming())
|
||||
if (is_streaming() && !is_xa())
|
||||
{
|
||||
append_sr_keys_for_commit();
|
||||
flags(flags() | wsrep::provider::flag::pa_unsafe);
|
||||
|
@ -22,10 +22,10 @@
|
||||
|
||||
std::string wsrep::to_string(const wsrep::xid& xid)
|
||||
{
|
||||
return xid.xid_;
|
||||
return std::string(xid.data_.data(), xid.data_.size());
|
||||
}
|
||||
|
||||
std::ostream& wsrep::operator<<(std::ostream& os, const wsrep::xid& xid)
|
||||
{
|
||||
return os << xid.xid_;
|
||||
return os << to_string(xid);
|
||||
}
|
||||
|
Reference in New Issue
Block a user