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

@ -10,6 +10,71 @@ trrep::provider& trrep::client_context::provider() const
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
// DBMS integration or mock classes only.
int trrep::client_context::replay(

View File

@ -2,10 +2,44 @@
// 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
#define TRREP_CLIENT_CONTEXT_HPP
#include "server_context.hpp"
#include "transaction_context.hpp"
#include "mutex.hpp"
#include "lock.hpp"
#include "data.hpp"
@ -36,51 +70,179 @@ namespace trrep
wsrep_conn_id_t id_;
};
/*! \class Client Context
*
* Client Contex abstract interface.
*/
class client_context
{
public:
/*!
* Client mode enumeration.
* \todo m_toi total order isolation mode
*/
enum mode
{
m_local, // Operates in local only mode, no replication
m_replicating, // Generates write sets for replication
m_applier // Applying write sets from provider
/*! Operates in local only mode, no replication. */
m_local,
/*! Generates write sets for replication by the provider. */
m_replicating,
/*! Applies write sets from the provider. */
m_applier
};
/*!
* Client state enumeration.
*
*/
enum state
{
/*!
* Client is idle, the control is in the application which
* uses the DBMS system.
*/
s_idle,
/*!
* The control of the client processing is inside the DBMS
* system.
*/
s_exec,
/*!
* The client session is terminating.
*/
s_quitting
};
virtual ~client_context() { }
// Accessors
/*!
* Get reference to the client mutex.
*
* \return Reference to the client 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
{ 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;
/*!
* Get Client identifier.
*
* \return Client Identifier
*/
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_; }
/*!
* Get Client state.
*
* \todo Enforce mutex protection if called from other threads.
*
* \return Client 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 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&,
uint32_t, const trrep::data&)
{ return 0; }
/*!
* Commit the transaction.
*/
virtual int commit(trrep::transaction_context&) = 0;
/*!
* Rollback the transaction.
*/
virtual int rollback(trrep::transaction_context&) = 0;
virtual void will_replay(trrep::transaction_context&) { }
@ -114,9 +276,9 @@ namespace trrep
abort();
}
protected:
//
// Client context constuctor
//
/*!
* Client context constuctor
*/
client_context(trrep::mutex& mutex,
trrep::server_context& server_context,
const client_id& id,
@ -126,6 +288,8 @@ namespace trrep
, id_(id)
, mode_(mode)
, state_(s_idle)
, transaction_(*this)
, allow_dirty_reads_()
{ }
private:
@ -136,6 +300,12 @@ namespace trrep
client_id id_;
enum mode mode_;
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& id,
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)
, simulator_(simulator)
, mutex_()
@ -179,6 +180,7 @@ public:
cond_.notify_all();
}
bool sst_before_init() const override { return false; }
std::string on_sst_request()
{
return id();

View File

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

View File

@ -51,13 +51,22 @@
* In asynchronous mode the BFA victim transaction is just marked
* to be aborted or in case of fully optimistic concurrency control,
* 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
#define TRREP_SERVER_CONTEXT_HPP
#include "exception.hpp"
#include "mutex.hpp"
#include "wsrep_api.h"
#include <string>
@ -78,9 +87,57 @@ namespace trrep
class server_context
{
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
{
@ -90,29 +147,6 @@ namespace trrep
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();
/*!
@ -136,6 +170,13 @@ namespace trrep
*/
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
* not participate in replication. However, local client
@ -207,6 +248,12 @@ namespace trrep
*/
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
* requests the SST request information. This method should
@ -275,11 +322,40 @@ namespace trrep
virtual bool statement_allowed_for_streaming(
const trrep::client_context& client_context,
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:
server_context(const server_context&);
server_context& operator=(const server_context&);
trrep::mutex& mutex_;
trrep::provider* provider_;
std::string name_;
std::string id_;