1
0
mirror of https://github.com/codership/wsrep-lib.git synced 2025-07-28 20:02:00 +03:00

Started documenting client context.

This commit is contained in:
Teemu Ollakka
2018-04-27 12:51:05 +03:00
parent f3afb6306d
commit 28026ea4fc
7 changed files with 384 additions and 49 deletions

View File

@ -229,6 +229,8 @@ TAB_SIZE = 4
# newlines. # newlines.
ALIASES = ALIASES =
ALIASES = "startuml=\if DontIgnorePlantUMLCode"
ALIASES += "enduml=\endif"
# This tag can be used to specify a number of word-keyword mappings (TCL only). # This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class" # A mapping has the form "name=value". For example adding "class=itcl::class"

View File

@ -10,6 +10,71 @@ trrep::provider& trrep::client_context::provider() const
return server_context_.provider(); return server_context_.provider();
} }
int trrep::client_context::before_command()
{
assert(state_ == s_idle);
if (server_context_.rollback_mode() == trrep::server_context::rm_sync)
{
/*!
* \todo Wait until the possible synchronous rollback
* has been finished.
*/
trrep::unique_lock<trrep::mutex> lock(mutex_);
while (transaction_.state() == trrep::transaction_context::s_aborting)
{
// cond_.wait(lock);
}
}
state_ = s_exec;
if (transaction_.state() == trrep::transaction_context::s_must_abort)
{
return 1;
}
return 0;
}
int trrep::client_context::after_command()
{
int ret(0);
trrep::unique_lock<trrep::mutex> lock(mutex_);
if (transaction_.state() == trrep::transaction_context::s_must_abort)
{
lock.unlock();
rollback(transaction_);
lock.lock();
ret = 1;
}
state_ = s_idle;
return ret;
}
int trrep::client_context::before_statement()
{
#if 0
/*!
* \todo It might be beneficial to implement timed wait for
* server synced state.
*/
if (allow_dirty_reads_ == false &&
server_context_.state() != trrep::server_context::s_synced)
{
return 1;
}
#endif // 0
return 0;
}
int trrep::client_context::after_statement()
{
#if 0
/*!
* \todo Check for replay state, do rollback if requested.
*/
#endif // 0
return 0;
}
// TODO: This should be pure virtual method, implemented by // TODO: This should be pure virtual method, implemented by
// DBMS integration or mock classes only. // DBMS integration or mock classes only.
int trrep::client_context::replay( int trrep::client_context::replay(

View File

@ -2,10 +2,44 @@
// Copyright (C) 2018 Codership Oy <info@codership.com> // Copyright (C) 2018 Codership Oy <info@codership.com>
// //
/*! \file client_context.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 TRREP_CLIENT_CONTEXT_HPP #ifndef TRREP_CLIENT_CONTEXT_HPP
#define TRREP_CLIENT_CONTEXT_HPP #define TRREP_CLIENT_CONTEXT_HPP
#include "server_context.hpp" #include "server_context.hpp"
#include "transaction_context.hpp"
#include "mutex.hpp" #include "mutex.hpp"
#include "lock.hpp" #include "lock.hpp"
#include "data.hpp" #include "data.hpp"
@ -36,51 +70,179 @@ namespace trrep
wsrep_conn_id_t id_; wsrep_conn_id_t id_;
}; };
/*! \class Client Context
*
* Client Contex abstract interface.
*/
class client_context class client_context
{ {
public: public:
/*!
* Client mode enumeration.
* \todo m_toi total order isolation mode
*/
enum mode enum mode
{ {
m_local, // Operates in local only mode, no replication /*! Operates in local only mode, no replication. */
m_replicating, // Generates write sets for replication m_local,
m_applier // Applying write sets from provider /*! Generates write sets for replication by the provider. */
m_replicating,
/*! Applies write sets from the provider. */
m_applier
}; };
/*!
* Client state enumeration.
*
*/
enum state enum state
{ {
/*!
* Client is idle, the control is in the application which
* uses the DBMS system.
*/
s_idle, s_idle,
/*!
* The control of the client processing is inside the DBMS
* system.
*/
s_exec, s_exec,
/*!
* The client session is terminating.
*/
s_quitting s_quitting
}; };
virtual ~client_context() { } virtual ~client_context() { }
// Accessors
/*!
* Get reference to the client mutex.
*
* \return Reference to the client mutex.
*/
trrep::mutex& mutex() { return mutex_; } trrep::mutex& mutex() { return mutex_; }
/*!
* Get server context associated the the client session.
*
* \return Reference to server context.
*/
trrep::server_context& server_context() const trrep::server_context& server_context() const
{ return server_context_; } { return server_context_; }
/*!
* Get reference to the Provider which is associated
* with the client context.
*
* \return Reference to the provider.
* \throw trrep::runtime_error if no providers are associated
* with the client context.
*/
trrep::provider& provider() const; trrep::provider& provider() const;
/*!
* Get Client identifier.
*
* \return Client Identifier
*/
client_id id() const { return id_; } client_id id() const { return id_; }
/*!
* Get Client mode.
*
* \todo Enforce mutex protection if called from other threads.
*
* \return Client mode.
*/
enum mode mode() const { return mode_; } enum mode mode() const { return mode_; }
/*!
* Get Client state.
*
* \todo Enforce mutex protection if called from other threads.
*
* \return Client state
*/
enum state state() const { return state_; } enum state state() const { return state_; }
/*!
* Virtual method to return true if the client operates
* in two phase commit mode.
*
* \return True if two phase commit is required, false otherwise.
*/
virtual bool do_2pc() const = 0; virtual bool do_2pc() const = 0;
//
//
//
virtual void before_command() { }
virtual void after_command() { } /*!
* Virtual method which should be called before the client
* starts processing the command received from the application.
* This method will wait until the possible synchronous
* rollback for associated transaction has finished.
* The method has a side effect of changing the client
* 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
* associated transaction was BF aborted.
*/
virtual int before_command();
virtual int before_statement() { return 0; } /*!
* Virtual method which should be called before returning
* the control back to application which uses the DBMS system.
* This method will check if the transaction associated to
* the connection has been aborted. This method has a side effect
* of changing the client state to idle.
*
* If overridden, the implementation should call base
* class metods after any implementation specifict operations.
*/
virtual int after_command();
virtual int after_statement() { return 0; } /*!
* Before statement execution operations.
*
* 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
* is not allowed to be executed due to read or write
* isolation requirements.
*/
virtual int before_statement();
/*!
* After statement execution operations.
*
* * Check for must_replay state
* * Do rollback if requested
*
* If overridden by the implementation, base class method
* should be called after any implementation specific operations.
*/
virtual int after_statement();
/*!
* Append SR fragment to the transaction.
*/
virtual int append_fragment(trrep::transaction_context&, virtual int append_fragment(trrep::transaction_context&,
uint32_t, const trrep::data&) uint32_t, const trrep::data&)
{ return 0; } { return 0; }
/*!
* Commit the transaction.
*/
virtual int commit(trrep::transaction_context&) = 0; virtual int commit(trrep::transaction_context&) = 0;
/*!
* Rollback the transaction.
*/
virtual int rollback(trrep::transaction_context&) = 0; virtual int rollback(trrep::transaction_context&) = 0;
virtual void will_replay(trrep::transaction_context&) { } virtual void will_replay(trrep::transaction_context&) { }
@ -114,9 +276,9 @@ namespace trrep
abort(); abort();
} }
protected: protected:
// /*!
// Client context constuctor * Client context constuctor
// */
client_context(trrep::mutex& mutex, client_context(trrep::mutex& mutex,
trrep::server_context& server_context, trrep::server_context& server_context,
const client_id& id, const client_id& id,
@ -126,6 +288,8 @@ namespace trrep
, id_(id) , id_(id)
, mode_(mode) , mode_(mode)
, state_(s_idle) , state_(s_idle)
, transaction_(*this)
, allow_dirty_reads_()
{ } { }
private: private:
@ -136,6 +300,12 @@ namespace trrep
client_id id_; client_id id_;
enum mode mode_; enum mode mode_;
enum state state_; enum state state_;
trrep::transaction_context transaction_;
/*!
* \todo This boolean should be converted to better read isolation
* semantics.
*/
bool allow_dirty_reads_;
}; };

16
src/compiler.hpp Normal file
View File

@ -0,0 +1,16 @@
//
// Copyright (C) 2018 Codership Oy <info@codership.com>
//
/*! \file compiler.hpp
*
* Compiler specific options.
*/
#define TRREP_UNUSED __attribute__((unused))
#if __cplusplus >= 201103L
#define TRREP_OVERRIDE override
#else
#define TRREP_OVERRIDE
#endif // __cplusplus >= 201103L

View File

@ -109,7 +109,8 @@ public:
const std::string& name, const std::string& name,
const std::string& id, const std::string& id,
const std::string& address) const std::string& address)
: trrep::server_context(name, id, address, name + "_data", : trrep::server_context(mutex_,
name, id, address, name + "_data",
trrep::server_context::rm_async) trrep::server_context::rm_async)
, simulator_(simulator) , simulator_(simulator)
, mutex_() , mutex_()
@ -179,6 +180,7 @@ public:
cond_.notify_all(); cond_.notify_all();
} }
bool sst_before_init() const override { return false; }
std::string on_sst_request() std::string on_sst_request()
{ {
return id(); return id();

View File

@ -9,6 +9,7 @@
#include "mock_client_context.hpp" #include "mock_client_context.hpp"
#include "mock_provider.hpp" #include "mock_provider.hpp"
#include "compiler.hpp"
namespace trrep namespace trrep
{ {
@ -18,7 +19,8 @@ namespace trrep
mock_server_context(const std::string& name, mock_server_context(const std::string& name,
const std::string& id, const std::string& id,
enum trrep::server_context::rollback_mode rollback_mode) enum trrep::server_context::rollback_mode rollback_mode)
: trrep::server_context(name, id, "", "./", rollback_mode) : trrep::server_context(mutex_, name, id, "", "./", rollback_mode)
, mutex_()
, provider_() , provider_()
, last_client_id_(0) , last_client_id_(0)
{ } { }
@ -30,19 +32,21 @@ namespace trrep
trrep::client_context::m_local); trrep::client_context::m_local);
} }
void on_connect() { } void on_connect() TRREP_OVERRIDE { }
void wait_until_connected() { } void wait_until_connected() TRREP_OVERRIDE { }
void on_view(const trrep::view&) { } void on_view(const trrep::view&) TRREP_OVERRIDE { }
void on_sync() { } void on_sync() TRREP_OVERRIDE { }
std::string on_sst_request() { return ""; } bool sst_before_init() const TRREP_OVERRIDE { return false; }
std::string on_sst_request() TRREP_OVERRIDE { return ""; }
void on_sst_donate_request(const std::string&, void on_sst_donate_request(const std::string&,
const wsrep_gtid_t&, const wsrep_gtid_t&,
bool) { } bool) TRREP_OVERRIDE { }
void sst_received(const wsrep_gtid_t&) { } void sst_received(const wsrep_gtid_t&) TRREP_OVERRIDE { }
// void on_apply(trrep::transaction_context&) { } // void on_apply(trrep::transaction_context&) { }
// void on_commit(trrep::transaction_context&) { } // void on_commit(trrep::transaction_context&) { }
private: private:
trrep::default_mutex mutex_;
mutable trrep::mock_provider provider_; mutable trrep::mock_provider provider_;
unsigned long long last_client_id_; unsigned long long last_client_id_;
}; };

View File

@ -51,13 +51,22 @@
* In asynchronous mode the BFA victim transaction is just marked * In asynchronous mode the BFA victim transaction is just marked
* to be aborted or in case of fully optimistic concurrency control, * to be aborted or in case of fully optimistic concurrency control,
* the conflict is detected at commit. * the conflict is detected at commit.
*
* SST
* ===
*
* Depending on SST type (physical or logical), the server storage
* engine initialization must be done before or after SST happens.
* In case of physical SST method (typically rsync, filesystem snapshot)
* the SST happens before the storage engine is initialized, in case
* of logical backup typically after the storage engine initialization.
*/ */
#ifndef TRREP_SERVER_CONTEXT_HPP #ifndef TRREP_SERVER_CONTEXT_HPP
#define TRREP_SERVER_CONTEXT_HPP #define TRREP_SERVER_CONTEXT_HPP
#include "exception.hpp" #include "exception.hpp"
#include "mutex.hpp"
#include "wsrep_api.h" #include "wsrep_api.h"
#include <string> #include <string>
@ -78,9 +87,57 @@ namespace trrep
class server_context class server_context
{ {
public: public:
/*!
/*! Rollback Mode enumeration * Server state enumeration.
* *
* \todo Fix UML generation
*
* Server state diagram if the sst_before_init() returns false.
*
* [*] --> disconnected
* disconnected --> initializing
* initializing --> initialized
* initialized --> connected
* connected --> joiner
* joiner --> joined
* joined --> synced
* synced --> donor
* donor --> joined
*
* Server state diagram if the sst_before_init() returns true.
*
* [*] --> disconnected
* disconnected --> connected
* connected --> joiner
* joiner --> initializing
* initializing --> initialized
* initialized --> joined
* joined --> synced
* synced --> donor
* donor --> joined
*/
enum state
{
/*! Server is in disconnected state. */
s_disconnected,
/*! Server is initializing */
s_initializing,
/*! Server has been initialized */
s_initialized,
/*! Server is connected to the cluster */
s_connected,
/*! Server is receiving SST */
s_joiner,
/*! Server has received SST succesfully but has not synced
with rest of the cluster yet. */
s_joined,
/*! Server is donating state snapshot transfer */
s_donor,
/*! Server has synced with the cluster */
s_synced
};
/*!
* Rollback Mode enumeration
*/ */
enum rollback_mode enum rollback_mode
{ {
@ -90,29 +147,6 @@ namespace trrep
rm_sync rm_sync
}; };
/*! Server Context constructor
*
* \param name Human Readable Server Name.
* \param id Server Identifier String, UUID or some unique
* identifier.
* \param address Server address in form of IPv4 address, IPv6 address
* or hostname.
* \param working_dir Working directory for replication specific
* data files.
* \param rollback_mode Rollback mode which server operates on.
*/
server_context(const std::string& name,
const std::string& id,
const std::string& address,
const std::string& working_dir,
enum rollback_mode rollback_mode)
: provider_()
, name_(name)
, id_(id)
, address_(address)
, working_dir_(working_dir)
, rollback_mode_(rollback_mode)
{ }
virtual ~server_context(); virtual ~server_context();
/*! /*!
@ -136,6 +170,13 @@ namespace trrep
*/ */
const std::string& address() const { return address_; } const std::string& address() const { return address_; }
/*!
* Get the rollback mode which server is operating in.
*
* \return Rollback mode.
*/
enum rollback_mode rollback_mode() const { return rollback_mode_; }
/*! /*!
* Create client context which acts only locally, i.e. does * Create client context which acts only locally, i.e. does
* not participate in replication. However, local client * not participate in replication. However, local client
@ -207,6 +248,12 @@ namespace trrep
*/ */
virtual void on_sync() = 0; virtual void on_sync() = 0;
/*!
* Virtual method to return true if the configured SST
* method requires SST to be performed before DBMS storage
* engine initialization, false otherwise.
*/
virtual bool sst_before_init() const = 0;
/*! /*!
* Virtual method which will be called on *joiner* when the provider * Virtual method which will be called on *joiner* when the provider
* requests the SST request information. This method should * requests the SST request information. This method should
@ -275,11 +322,40 @@ namespace trrep
virtual bool statement_allowed_for_streaming( virtual bool statement_allowed_for_streaming(
const trrep::client_context& client_context, const trrep::client_context& client_context,
const trrep::transaction_context& transaction_context) const; const trrep::transaction_context& transaction_context) const;
protected:
/*! Server Context constructor
*
* \param mutex Mutex provided by the DBMS implementation.
* \param name Human Readable Server Name.
* \param id Server Identifier String, UUID or some unique
* identifier.
* \param address Server address in form of IPv4 address, IPv6 address
* or hostname.
* \param working_dir Working directory for replication specific
* data files.
* \param rollback_mode Rollback mode which server operates on.
*/
server_context(trrep::mutex& mutex,
const std::string& name,
const std::string& id,
const std::string& address,
const std::string& working_dir,
enum rollback_mode rollback_mode)
: mutex_(mutex)
, provider_()
, name_(name)
, id_(id)
, address_(address)
, working_dir_(working_dir)
, rollback_mode_(rollback_mode)
{ }
private: private:
server_context(const server_context&); server_context(const server_context&);
server_context& operator=(const server_context&); server_context& operator=(const server_context&);
trrep::mutex& mutex_;
trrep::provider* provider_; trrep::provider* provider_;
std::string name_; std::string name_;
std::string id_; std::string id_;