mirror of
https://github.com/codership/wsrep-lib.git
synced 2025-07-02 05:22:26 +03:00
Implemented client last_written_gtid, sync_wait
This commit is contained in:
@ -38,7 +38,9 @@ namespace wsrep
|
|||||||
e_deadlock_error,
|
e_deadlock_error,
|
||||||
e_interrupted_error,
|
e_interrupted_error,
|
||||||
e_size_exceeded_error,
|
e_size_exceeded_error,
|
||||||
e_append_fragment_error
|
e_append_fragment_error,
|
||||||
|
e_not_supported_error,
|
||||||
|
e_timeout_error
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline const char* to_c_string(enum client_error error)
|
static inline const char* to_c_string(enum client_error error)
|
||||||
@ -46,11 +48,13 @@ namespace wsrep
|
|||||||
switch (error)
|
switch (error)
|
||||||
{
|
{
|
||||||
case e_success: return "success";
|
case e_success: return "success";
|
||||||
case e_error_during_commit: return "error_during_commit";
|
case e_error_during_commit: return "commit_error";
|
||||||
case e_deadlock_error: return "deadlock_error";
|
case e_deadlock_error: return "deadlock_error";
|
||||||
case e_interrupted_error: return "interrupted_error";
|
case e_interrupted_error: return "interrupted_error";
|
||||||
case e_size_exceeded_error: return "size_exceeded";
|
case e_size_exceeded_error: return "size_exceeded_error";
|
||||||
case e_append_fragment_error: return "append_fragment_error";
|
case e_append_fragment_error: return "append_fragment_error";
|
||||||
|
case e_not_supported_error: return "not_supported_error";
|
||||||
|
case e_timeout_error: return "timeout_error";
|
||||||
}
|
}
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
@ -516,6 +520,37 @@ namespace wsrep
|
|||||||
{
|
{
|
||||||
return toi_meta_;
|
return toi_meta_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do sync wait operation. If the method fails, current_error()
|
||||||
|
* can be inspected about the reason of error.
|
||||||
|
*
|
||||||
|
* @param Sync wait timeout in seconds.
|
||||||
|
*
|
||||||
|
* @return Zero on success, non-zero on error.
|
||||||
|
*/
|
||||||
|
int sync_wait(int timeout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current sync wait GTID.
|
||||||
|
*
|
||||||
|
* Sync wait GTID is updated on each sync_wait() call and
|
||||||
|
* reset to wsrep::gtid::undefined() in after_command_after_result()
|
||||||
|
* method. The variable can thus be used to check if a sync wait
|
||||||
|
* has been performend for the current client command.
|
||||||
|
*/
|
||||||
|
const wsrep::gtid& sync_wait_gtid() const
|
||||||
|
{
|
||||||
|
return sync_wait_gtid_;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Return the last written GTID.
|
||||||
|
*/
|
||||||
|
const wsrep::gtid& last_written_gtid() const
|
||||||
|
{
|
||||||
|
return last_written_gtid_;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set debug logging level.
|
* Set debug logging level.
|
||||||
*
|
*
|
||||||
@ -586,6 +621,8 @@ namespace wsrep
|
|||||||
, transaction_(*this)
|
, transaction_(*this)
|
||||||
, toi_meta_()
|
, toi_meta_()
|
||||||
, allow_dirty_reads_()
|
, allow_dirty_reads_()
|
||||||
|
, sync_wait_gtid_()
|
||||||
|
, last_written_gtid_()
|
||||||
, debug_log_level_(0)
|
, debug_log_level_(0)
|
||||||
, current_error_(wsrep::e_success)
|
, current_error_(wsrep::e_success)
|
||||||
{ }
|
{ }
|
||||||
@ -599,6 +636,7 @@ namespace wsrep
|
|||||||
friend class client_toi_mode;
|
friend class client_toi_mode;
|
||||||
friend class transaction;
|
friend class transaction;
|
||||||
|
|
||||||
|
void update_last_written_gtid(const wsrep::gtid&);
|
||||||
void debug_log_state(const char*) const;
|
void debug_log_state(const char*) const;
|
||||||
void state(wsrep::unique_lock<wsrep::mutex>& lock, enum state state);
|
void state(wsrep::unique_lock<wsrep::mutex>& lock, enum state state);
|
||||||
void mode(wsrep::unique_lock<wsrep::mutex>& lock, enum mode mode);
|
void mode(wsrep::unique_lock<wsrep::mutex>& lock, enum mode mode);
|
||||||
@ -617,6 +655,8 @@ namespace wsrep
|
|||||||
wsrep::transaction transaction_;
|
wsrep::transaction transaction_;
|
||||||
wsrep::ws_meta toi_meta_;
|
wsrep::ws_meta toi_meta_;
|
||||||
bool allow_dirty_reads_;
|
bool allow_dirty_reads_;
|
||||||
|
wsrep::gtid sync_wait_gtid_;
|
||||||
|
wsrep::gtid last_written_gtid_;
|
||||||
int debug_log_level_;
|
int debug_log_level_;
|
||||||
wsrep::client_error current_error_;
|
wsrep::client_error current_error_;
|
||||||
};
|
};
|
||||||
|
@ -40,6 +40,22 @@ namespace wsrep
|
|||||||
wsrep::seqno seqno_;
|
wsrep::seqno seqno_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a GTID into character buffer.
|
||||||
|
* @param buf Pointer to the beginning of the buffer
|
||||||
|
* @param buf_len Buffer length
|
||||||
|
*
|
||||||
|
* @return Number of characters printed or negative value for error
|
||||||
|
*/
|
||||||
|
ssize_t gtid_print_to_c_str(const wsrep::gtid&, char* buf, size_t buf_len);
|
||||||
|
/**
|
||||||
|
* Return minimum number of bytes guaranteed to store GTID string
|
||||||
|
* representation, terminating '\0' not included (36 + 1 + 20)
|
||||||
|
*/
|
||||||
|
static inline size_t gtid_c_str_len()
|
||||||
|
{
|
||||||
|
return 57;
|
||||||
|
}
|
||||||
std::ostream& operator<<(std::ostream&, const wsrep::gtid&);
|
std::ostream& operator<<(std::ostream&, const wsrep::gtid&);
|
||||||
std::istream& operator>>(std::istream&, wsrep::gtid&);
|
std::istream& operator>>(std::istream&, wsrep::gtid&);
|
||||||
}
|
}
|
||||||
|
@ -298,7 +298,8 @@ namespace wsrep
|
|||||||
*
|
*
|
||||||
* @return Provider status indicating the result of the call.
|
* @return Provider status indicating the result of the call.
|
||||||
*/
|
*/
|
||||||
virtual enum status causal_read(int timeout) const = 0;
|
virtual std::pair<wsrep::gtid, enum status>
|
||||||
|
causal_read(int timeout) const = 0;
|
||||||
virtual enum status wait_for_gtid(const wsrep::gtid&, int timeout) const = 0;
|
virtual enum status wait_for_gtid(const wsrep::gtid&, int timeout) const = 0;
|
||||||
/**
|
/**
|
||||||
* Return last committed GTID.
|
* Return last committed GTID.
|
||||||
|
@ -336,8 +336,12 @@ namespace wsrep
|
|||||||
* Method wait_for_gtid() should be used whenever possible.
|
* Method wait_for_gtid() should be used whenever possible.
|
||||||
*
|
*
|
||||||
* @param timeout Timeout in seconds
|
* @param timeout Timeout in seconds
|
||||||
|
*
|
||||||
|
* @return Pair of GTID and result status from provider.
|
||||||
*/
|
*/
|
||||||
enum wsrep::provider::status causal_read(int timeout) const;
|
|
||||||
|
std::pair<wsrep::gtid, enum wsrep::provider::status>
|
||||||
|
causal_read(int timeout) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Desynchronize the server.
|
* Desynchronize the server.
|
||||||
|
@ -158,6 +158,7 @@ void wsrep::client_state::after_command_after_result()
|
|||||||
{
|
{
|
||||||
current_error_ = wsrep::e_success;
|
current_error_ = wsrep::e_success;
|
||||||
}
|
}
|
||||||
|
sync_wait_gtid_ = wsrep::gtid::undefined();
|
||||||
state(lock, s_idle);
|
state(lock, s_idle);
|
||||||
debug_log_state("after_command_after_result: leave");
|
debug_log_state("after_command_after_result: leave");
|
||||||
}
|
}
|
||||||
@ -293,12 +294,46 @@ int wsrep::client_state::leave_toi()
|
|||||||
wsrep::unique_lock<wsrep::mutex> lock(mutex_);
|
wsrep::unique_lock<wsrep::mutex> lock(mutex_);
|
||||||
mode(lock, toi_mode_);
|
mode(lock, toi_mode_);
|
||||||
toi_mode_ = m_local;
|
toi_mode_ = m_local;
|
||||||
|
if (toi_meta_.gtid().is_undefined() == false)
|
||||||
|
{
|
||||||
|
update_last_written_gtid(toi_meta_.gtid());
|
||||||
|
}
|
||||||
toi_meta_ = wsrep::ws_meta();
|
toi_meta_ = wsrep::ws_meta();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int wsrep::client_state::sync_wait(int timeout)
|
||||||
|
{
|
||||||
|
std::pair<wsrep::gtid, enum wsrep::provider::status> result(
|
||||||
|
server_state_.causal_read(timeout));
|
||||||
|
int ret(1);
|
||||||
|
switch (result.second)
|
||||||
|
{
|
||||||
|
case wsrep::provider::success:
|
||||||
|
sync_wait_gtid_ = result.first;
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
case wsrep::provider::error_not_implemented:
|
||||||
|
override_error(wsrep::e_not_supported_error);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
override_error(wsrep::e_timeout_error);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// Private
|
// Private
|
||||||
|
|
||||||
|
void wsrep::client_state::update_last_written_gtid(const wsrep::gtid& gtid)
|
||||||
|
{
|
||||||
|
assert(last_written_gtid_.is_undefined() ||
|
||||||
|
(last_written_gtid_.id() == gtid.id() &&
|
||||||
|
last_written_gtid_.seqno() < gtid.seqno()));
|
||||||
|
last_written_gtid_ = gtid;
|
||||||
|
}
|
||||||
|
|
||||||
void wsrep::client_state::debug_log_state(const char* context) const
|
void wsrep::client_state::debug_log_state(const char* context) const
|
||||||
{
|
{
|
||||||
if (debug_log_level() >= 1)
|
if (debug_log_level() >= 1)
|
||||||
|
15
src/gtid.cpp
15
src/gtid.cpp
@ -4,7 +4,9 @@
|
|||||||
|
|
||||||
#include "wsrep/gtid.hpp"
|
#include "wsrep/gtid.hpp"
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
std::ostream& wsrep::operator<<(std::ostream& os, const wsrep::gtid& gtid)
|
std::ostream& wsrep::operator<<(std::ostream& os, const wsrep::gtid& gtid)
|
||||||
{
|
{
|
||||||
@ -21,3 +23,16 @@ std::istream& wsrep::operator>>(std::istream& is, wsrep::gtid& gtid)
|
|||||||
std::cout << "GTID: " << gtid << "\n";
|
std::cout << "GTID: " << gtid << "\n";
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t wsrep::gtid_print_to_c_str(
|
||||||
|
const wsrep::gtid& gtid, char* buf, size_t buf_len)
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << gtid;
|
||||||
|
if (os.str().size() > buf_len)
|
||||||
|
{
|
||||||
|
return -ENOBUFS;
|
||||||
|
}
|
||||||
|
std::strncpy(buf, os.str().c_str(), os.str().size());
|
||||||
|
return os.str().size();
|
||||||
|
}
|
||||||
|
@ -499,7 +499,7 @@ wsrep::server_state::wait_for_gtid(const wsrep::gtid& gtid, int timeout)
|
|||||||
return provider_->wait_for_gtid(gtid, timeout);
|
return provider_->wait_for_gtid(gtid, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum wsrep::provider::status
|
std::pair<wsrep::gtid, enum wsrep::provider::status>
|
||||||
wsrep::server_state::causal_read(int timeout) const
|
wsrep::server_state::causal_read(int timeout) const
|
||||||
{
|
{
|
||||||
return provider_->causal_read(timeout);
|
return provider_->causal_read(timeout);
|
||||||
|
@ -961,8 +961,13 @@ void wsrep::transaction::cleanup()
|
|||||||
debug_log_state("cleanup_enter");
|
debug_log_state("cleanup_enter");
|
||||||
id_ = wsrep::transaction_id::undefined();
|
id_ = wsrep::transaction_id::undefined();
|
||||||
ws_handle_ = wsrep::ws_handle();
|
ws_handle_ = wsrep::ws_handle();
|
||||||
// Keep the state history for troubleshooting. Reset at start_transaction().
|
// Keep the state history for troubleshooting. Reset
|
||||||
|
// at start_transaction().
|
||||||
// state_hist_.clear();
|
// state_hist_.clear();
|
||||||
|
if (ordered())
|
||||||
|
{
|
||||||
|
client_state_.update_last_written_gtid(ws_meta_.gtid());
|
||||||
|
}
|
||||||
ws_meta_ = wsrep::ws_meta();
|
ws_meta_ = wsrep::ws_meta();
|
||||||
certified_ = false;
|
certified_ = false;
|
||||||
pa_unsafe_ = false;
|
pa_unsafe_ = false;
|
||||||
|
@ -703,10 +703,17 @@ wsrep::wsrep_provider_v26::leave_toi(wsrep::client_id client_id)
|
|||||||
wsrep_, client_id.get(), 0));
|
wsrep_, client_id.get(), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
enum wsrep::provider::status
|
std::pair<wsrep::gtid, enum wsrep::provider::status>
|
||||||
wsrep::wsrep_provider_v26::causal_read(int timeout) const
|
wsrep::wsrep_provider_v26::causal_read(int timeout) const
|
||||||
{
|
{
|
||||||
return map_return_value(wsrep_->sync_wait(wsrep_, 0, timeout, 0));
|
wsrep_gtid_t wsrep_gtid;
|
||||||
|
wsrep_status_t ret(wsrep_->sync_wait(wsrep_, 0, timeout, &wsrep_gtid));
|
||||||
|
wsrep::gtid gtid(ret == WSREP_OK ?
|
||||||
|
wsrep::gtid(wsrep::id(wsrep_gtid.uuid.data,
|
||||||
|
sizeof(wsrep_gtid.uuid.data)),
|
||||||
|
wsrep::seqno(wsrep_gtid.seqno)) :
|
||||||
|
wsrep::gtid::undefined());
|
||||||
|
return std::make_pair(gtid, map_return_value(ret));
|
||||||
}
|
}
|
||||||
|
|
||||||
enum wsrep::provider::status
|
enum wsrep::provider::status
|
||||||
|
@ -56,7 +56,8 @@ namespace wsrep
|
|||||||
wsrep::ws_meta&,
|
wsrep::ws_meta&,
|
||||||
int);
|
int);
|
||||||
enum wsrep::provider::status leave_toi(wsrep::client_id);
|
enum wsrep::provider::status leave_toi(wsrep::client_id);
|
||||||
enum wsrep::provider::status causal_read(int) const;
|
std::pair<wsrep::gtid, enum wsrep::provider::status>
|
||||||
|
causal_read(int) const;
|
||||||
enum wsrep::provider::status wait_for_gtid(const wsrep::gtid&, int) const;
|
enum wsrep::provider::status wait_for_gtid(const wsrep::gtid&, int) const;
|
||||||
wsrep::gtid last_committed_gtid() const;
|
wsrep::gtid last_committed_gtid() const;
|
||||||
int sst_sent(const wsrep::gtid&,int);
|
int sst_sent(const wsrep::gtid&,int);
|
||||||
|
@ -208,9 +208,11 @@ namespace wsrep
|
|||||||
enum wsrep::provider::status leave_toi(wsrep::client_id)
|
enum wsrep::provider::status leave_toi(wsrep::client_id)
|
||||||
{ return wsrep::provider::success; }
|
{ return wsrep::provider::success; }
|
||||||
|
|
||||||
enum wsrep::provider::status causal_read(int) const WSREP_OVERRIDE
|
std::pair<wsrep::gtid, enum wsrep::provider::status>
|
||||||
|
causal_read(int) const WSREP_OVERRIDE
|
||||||
{
|
{
|
||||||
return wsrep::provider::success;
|
return std::make_pair(wsrep::gtid::undefined(),
|
||||||
|
wsrep::provider::error_not_implemented);
|
||||||
}
|
}
|
||||||
enum wsrep::provider::status wait_for_gtid(const wsrep::gtid&,
|
enum wsrep::provider::status wait_for_gtid(const wsrep::gtid&,
|
||||||
int) const WSREP_OVERRIDE
|
int) const WSREP_OVERRIDE
|
||||||
|
Reference in New Issue
Block a user