1
0
mirror of https://github.com/codership/wsrep-lib.git synced 2025-04-19 21:02:17 +03:00

Improved client state documentation.

This commit is contained in:
Teemu Ollakka 2018-06-17 11:12:20 +03:00
parent ef4baa9f9d
commit 0dac901b39

View File

@ -4,35 +4,6 @@
/** @file client_state.hpp /** @file client_state.hpp
* *
* Client Context
* ==============
*
* This file provides abstraction for integrating DBMS client
* with replication system.
*
* Client Modes
* ============
*
* Local
* -----
*
* Replicating
* -----------
*
* Applier
* --------
*
* Client State
* ============
*
* Client state is mainly relevant for the operation if the Server
* supports synchronous rollback mode only. In this case the transactions
* of the the idle clients (controls is in application which is using the
* DBMS system) which encounter Brute Force Abort (BFA) must be rolled
* back either by applier or a background process. If the client
* state is executing, the control is inside the DBMS system and
* the rollback process should be performed by the client which
* drives the transaction.
*/ */
#ifndef WSREP_CLIENT_CONTEXT_HPP #ifndef WSREP_CLIENT_CONTEXT_HPP
@ -76,16 +47,14 @@ namespace wsrep
return "unknown"; return "unknown";
} }
/** @class Client Context /**
* * Client State
* Client Contex abstract interface.
*/ */
class client_state class client_state
{ {
public: public:
/** /**
* Client mode enumeration. * Client mode enumeration.
* @todo m_toi total order isolation mode
*/ */
enum mode enum mode
{ {
@ -127,7 +96,11 @@ namespace wsrep
const static int state_max_ = s_quitting + 1; const static int state_max_ = s_quitting + 1;
/**
* Store variables related to global execution context.
* This method should be called every time the thread
* operating the client state changes.
*/
void store_globals() void store_globals()
{ {
thread_id_ = wsrep::this_thread::get_id(); thread_id_ = wsrep::this_thread::get_id();
@ -142,7 +115,8 @@ namespace wsrep
} }
/** /**
* * Return true if the transaction commit requires
* two-phase commit.
*/ */
bool do_2pc() const bool do_2pc() const
{ {
@ -150,8 +124,9 @@ namespace wsrep
} }
/** /**
* Method which should be called before the client * This mehod should be called before the processing of command
* starts processing the command received from the application. * received from DBMS client starts.
*
* 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
@ -163,22 +138,28 @@ namespace wsrep
int before_command(); int before_command();
/** /**
* Method which should be called before returning * This method should be called before returning
* the control back to application which uses the DBMS system. * a result to DBMS client.
* This method will check if the transaction associated to *
* The method will check if the transaction associated to
* the connection has been aborted. Rollback is performed * the connection has been aborted. Rollback is performed
* if needed. * if needed. After the call, current_error() will return an error
* code associated to the client state. If the error code is
* not success, the transaction associated to the client state
* has been aborted and rolled back.
*/ */
void after_command_before_result(); void after_command_before_result();
/** /**
* Method which should be called after returning the * Method which should be called after returning the
* control back to application which uses the DBMS system. * control back to DBMS client..
*
* The method will do the check if the transaction associated * The method will do the check if the transaction associated
* to the connection has been aborted. If so, rollback is * to the connection has been aborted. If so, rollback is
* performed and the transaction is left to aborted state * performed and the transaction is left to aborted state.
* so that the client will get appropriate error on next * The next call to before_command() will return an error and
* command. * the error state can be examined after after_command_before_resul()
* is called.
* *
* This method has a side effect of changing state to * This method has a side effect of changing state to
* idle. * idle.
@ -190,10 +171,6 @@ namespace wsrep
* *
* Check if server is synced and if dirty reads are allowed. * Check if server is synced and if dirty reads are allowed.
* *
* If the method is overridden by the implementation, base class
* method should be called before any implementation specifc
* operations.
*
* @return Zero in case of success, non-zero if the statement * @return Zero in case of success, non-zero if the statement
* 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.
@ -220,21 +197,28 @@ namespace wsrep
* *
* * Check for must_replay state * * Check for must_replay state
* * Do rollback if requested * * Do rollback if requested
*
* If overridden by the implementation, base class method
* should be called after any implementation specific operations.
*/ */
enum after_statement_result after_statement(); enum after_statement_result after_statement();
// //
// Replicating interface // Replicating interface
// //
/**
* Start a new transaction with a transaction id.
*
* @todo This method should
* - Register the transaction on server level for bookkeeping
* - Isolation levels? Or part of the transaction?
*/
int start_transaction(const wsrep::transaction_id& id) int start_transaction(const wsrep::transaction_id& id)
{ {
assert(state_ == s_exec); assert(state_ == s_exec);
return transaction_.start_transaction(id); return transaction_.start_transaction(id);
} }
/**
* Append a key into transaction write set.
*/
int append_key(const wsrep::key& key) int append_key(const wsrep::key& key)
{ {
assert(mode_ == m_replicating); assert(mode_ == m_replicating);
@ -242,6 +226,9 @@ namespace wsrep
return transaction_.append_key(key); return transaction_.append_key(key);
} }
/**
* Append data into transaction write set.
*/
int append_data(const wsrep::const_buffer& data) int append_data(const wsrep::const_buffer& data)
{ {
assert(mode_ == m_replicating); assert(mode_ == m_replicating);
@ -257,13 +244,29 @@ namespace wsrep
// //
// Streaming interface // Streaming interface
// //
/**
* This method should be called after every row operation.
*/
int after_row() int after_row()
{ {
assert(mode_ == m_replicating); assert(mode_ == m_replicating);
assert(state_ == s_exec); assert(state_ == s_exec);
return transaction_.after_row(); return (transaction_.streaming_context_.fragment_size() ?
transaction_.after_row() : 0);
} }
/**
* Enable streaming replication.
*
* Currently it is not possible to change the fragment unit
* for active streaming transaction.
*
* @param fragment_unit Desired fragment unit
* @param fragment_size Desired fragment size
*
* @return Zero on success, non-zero if the streaming cannot be
* enabled.
*/
int enable_streaming( int enable_streaming(
enum wsrep::streaming_context::fragment_unit enum wsrep::streaming_context::fragment_unit
fragment_unit, fragment_unit,
@ -284,12 +287,14 @@ namespace wsrep
return 0; return 0;
} }
/** @todo deprecate */
size_t bytes_generated() const size_t bytes_generated() const
{ {
assert(mode_ == m_replicating); assert(mode_ == m_replicating);
return client_service_.bytes_generated(); return client_service_.bytes_generated();
} }
/** @todo deprecate */
int prepare_fragment_for_replication( int prepare_fragment_for_replication(
const wsrep::transaction& tc, const wsrep::transaction& tc,
wsrep::mutable_buffer& mb) wsrep::mutable_buffer& mb)
@ -298,6 +303,7 @@ namespace wsrep
*this, tc, mb); *this, tc, mb);
} }
/** @todo deprecate */
int append_fragment(const wsrep::transaction& tc, int append_fragment(const wsrep::transaction& tc,
int flags, int flags,
const wsrep::const_buffer& buf) const wsrep::const_buffer& buf)
@ -308,6 +314,8 @@ namespace wsrep
* Remove fragments from the fragment storage. If the * Remove fragments from the fragment storage. If the
* storage is transactional, this should be done within * storage is transactional, this should be done within
* the same transaction which is committing. * the same transaction which is committing.
*
* @todo deprecate
*/ */
void remove_fragments() void remove_fragments()
{ {
@ -338,6 +346,7 @@ namespace wsrep
*this, *this,
transaction_.ws_handle(), transaction_.ws_meta()); transaction_.ws_handle(), transaction_.ws_meta());
} }
// //
// Commit ordering // Commit ordering
// //
@ -407,8 +416,6 @@ namespace wsrep
// //
// Replaying // Replaying
// //
int start_replaying(const wsrep::ws_meta& ws_meta) int start_replaying(const wsrep::ws_meta& ws_meta)
{ {
assert(mode_ == m_high_priority); assert(mode_ == m_high_priority);
@ -431,11 +438,11 @@ namespace wsrep
// //
// //
// //
void will_replay(const wsrep::transaction& tc) void will_replay(const wsrep::transaction& tc)
{ {
client_service_.will_replay(tc); client_service_.will_replay(tc);
} }
void wait_for_replayers(wsrep::unique_lock<wsrep::mutex>& lock) void wait_for_replayers(wsrep::unique_lock<wsrep::mutex>& lock)
{ {
client_service_.wait_for_replayers(*this, lock); client_service_.wait_for_replayers(*this, lock);
@ -451,6 +458,29 @@ namespace wsrep
client_service_.emergency_shutdown(); client_service_.emergency_shutdown();
} }
//
// Causal reads
//
/**
* Perform a causal read in the cluster. After the call returns,
* all the causally preceding write sets have been committed
* or the error is returned.
*
* This operation may require communication with other processes
* in the DBMS cluster, so it may be relatively heavy operation.
* Method wait_for_gtid() should be used whenever possible.
*/
int causal_read() const;
/**
* Wait until all the write sets up to given GTID have been
* committed.
*
* @return Zero on success, non-zero on failure.
*/
int wait_for_gtid(const wsrep::gtid&) const;
// //
// Debug interface // Debug interface
// //
@ -485,6 +515,8 @@ namespace wsrep
* @return Reference to the provider. * @return Reference to the provider.
* @throw wsrep::runtime_error if no providers are associated * @throw wsrep::runtime_error if no providers are associated
* with the client context. * with the client context.
*
* @todo Should be removed.
*/ */
wsrep::provider& provider() const; wsrep::provider& provider() const;
@ -503,6 +535,7 @@ namespace wsrep
* @return Client mode. * @return Client mode.
*/ */
enum mode mode() const { return mode_; } enum mode mode() const { return mode_; }
/** /**
* Get Client state. * Get Client state.
* *
@ -512,27 +545,62 @@ namespace wsrep
*/ */
enum state state() const { return state_; } enum state state() const { return state_; }
/**
* Return a const reference to the transaction associated
* with the client state.
*/
const wsrep::transaction& transaction() const const wsrep::transaction& transaction() const
{ {
return transaction_; return transaction_;
} }
/**
* Set debug logging level.
*
* Levels:
* 0 - Debug logging is disabled
* 1..n - Debug logging with increasing verbosity.
*/
void debug_log_level(int level) { debug_log_level_ = level; } void debug_log_level(int level) { debug_log_level_ = level; }
/**
* Return current debug logging level. The return value
* is a maximum of client state and server state debug log
* levels.
*
* @return Current debug log level.
*/
int debug_log_level() const int debug_log_level() const
{ {
return std::max(debug_log_level_, return std::max(debug_log_level_,
server_state_.debug_log_level()); server_state_.debug_log_level());
} }
//
// Error handling
//
/**
* Reset the current error state.
*
* @todo There should be some protection about when this can
* be done.
*/
void reset_error() void reset_error()
{ {
current_error_ = wsrep::e_success; current_error_ = wsrep::e_success;
} }
/**
* Return current error code.
*
* @return Current error code.
*/
enum wsrep::client_error current_error() const enum wsrep::client_error current_error() const
{ {
return current_error_; return current_error_;
} }
protected: protected:
/** /**
* Client context constuctor. This is protected so that it * Client context constuctor. This is protected so that it
@ -566,33 +634,22 @@ namespace wsrep
friend class transaction; friend class transaction;
void debug_log_state(const char*) const; void debug_log_state(const char*) const;
/**
* Set client state.
*/
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 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_;
client_id id_; wsrep::client_id id_;
enum mode mode_; enum mode mode_;
enum state state_; enum state state_;
protected:
wsrep::transaction transaction_; wsrep::transaction transaction_;
private:
/**
* @todo This boolean should be converted to better read isolation
* semantics.
*/
bool allow_dirty_reads_; bool allow_dirty_reads_;
int debug_log_level_; int debug_log_level_;
wsrep::client_error current_error_; wsrep::client_error current_error_;
}; };
class client_state_switch class client_state_switch
{ {
public: public:
@ -612,6 +669,12 @@ namespace wsrep
client_state& current_context_; client_state& current_context_;
}; };
/**
* Utility class to switch the client state to high priority
* mode. The client is switched back to the original mode
* when the high priority context goes out of scope.
*/
class high_priority_context class high_priority_context
{ {
public: public:
@ -621,7 +684,7 @@ namespace wsrep
{ {
client_.mode_ = wsrep::client_state::m_high_priority; client_.mode_ = wsrep::client_state::m_high_priority;
} }
~high_priority_context() virtual ~high_priority_context()
{ {
client_.mode_ = orig_mode_; client_.mode_ = orig_mode_;
} }
@ -630,6 +693,9 @@ namespace wsrep
enum wsrep::client_state::mode orig_mode_; enum wsrep::client_state::mode orig_mode_;
}; };
/**
*
*/
class client_toi_mode class client_toi_mode
{ {
public: public: