1
0
mirror of https://github.com/codership/wsrep-lib.git synced 2025-07-28 20:02:00 +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:
Daniele Sciascia
2020-03-25 15:40:24 +01:00
parent 2da6e4894e
commit 965642eded
9 changed files with 167 additions and 29 deletions

View File

@ -66,6 +66,10 @@ namespace wsrep
: buffer_()
{ }
mutable_buffer(const mutable_buffer& b)
: buffer_(b.buffer_)
{ }
void resize(size_t s) { buffer_.resize(s); }
void clear()
@ -111,6 +115,11 @@ namespace wsrep
buffer_ = other.buffer_;
return *this;
}
bool operator==(const mutable_buffer& other) const
{
return buffer_ == other.buffer_;
}
private:
std::vector<char> buffer_;
};

View File

@ -589,6 +589,21 @@ namespace wsrep
return transaction_.commit_or_rollback_by_xid(xid, false);
}
/**
* Detach a prepared XA transaction
*
* This method cleans up a local XA transaction in prepared state
* and converts it to high priority mode.
* This can be used to handle the case where the client of a XA
* transaction disconnects, and the transaction must not rollback.
* After this call, a different client may later attempt to terminate
* the transaction by calling method commit_by_xid() or rollback_by_xid().
*/
void xa_detach()
{
transaction_.xa_detach();
}
//
// BF aborting
//

View File

@ -125,17 +125,17 @@ namespace wsrep
bool is_xa() const
{
return !xid_.empty();
return !xid_.is_null();
}
void assign_xid(const wsrep::xid& xid)
{
assert(active());
assert(xid_.empty());
assert(!is_xa());
xid_ = xid;
}
const wsrep::xid xid() const
const wsrep::xid& xid() const
{
return xid_;
}
@ -144,6 +144,8 @@ namespace wsrep
int commit_or_rollback_by_xid(const wsrep::xid& xid, bool commit);
void xa_detach();
bool pa_unsafe() const { return pa_unsafe_; }
void pa_unsafe(bool pa_unsafe) { pa_unsafe_ = pa_unsafe; }

View File

@ -21,23 +21,80 @@
#define WSREP_XID_HPP
#include <iosfwd>
#include <string>
#include "buffer.hpp"
namespace wsrep
{
class xid
{
public:
xid() : xid_() { }
xid(const std::string& str) : xid_(str) { }
xid(const char* s) : xid_(s) { }
bool empty() const { return xid_.empty(); }
void clear() { xid_.clear(); }
bool operator==(const xid& other) const { return xid_ == other.xid_; }
xid()
: format_id_(-1)
, gtrid_len_(0)
, bqual_len_(0)
, data_()
{ }
xid(long format_id, long gtrid_len,
long bqual_len, const char* data)
: format_id_(format_id)
, gtrid_len_(gtrid_len)
, bqual_len_(bqual_len)
, data_()
{
const long len = gtrid_len_ + bqual_len_;
if (len > 0)
{
data_.push_back(data, data + len);
}
}
xid(const xid& xid)
: format_id_(xid.format_id_)
, gtrid_len_(xid.gtrid_len_)
, bqual_len_(xid.bqual_len_)
, data_(xid.data_)
{ }
bool is_null() const
{
return format_id_ == -1;
}
void clear()
{
format_id_ = -1;
data_.clear();
}
xid& operator= (const xid& other)
{
format_id_ = other.format_id_;
gtrid_len_ = other.gtrid_len_;
bqual_len_ = other.bqual_len_;
data_ = other.data_;
return *this;
}
bool operator==(const xid& other) const
{
if (format_id_ != other.format_id_ ||
gtrid_len_ != other.gtrid_len_ ||
bqual_len_ != other.bqual_len_ ||
data_.size() != other.data_.size())
{
return false;
}
return data_ == other.data_;
}
friend std::string to_string(const wsrep::xid& xid);
friend std::ostream& operator<<(std::ostream& os, const wsrep::xid& xid);
private:
std::string xid_;
protected:
long format_id_;
long gtrid_len_;
long bqual_len_;
mutable_buffer data_;
};
std::string to_string(const wsrep::xid& xid);