diff --git a/include/wsrep/client_context.hpp b/include/wsrep/client_context.hpp index 2b596ad..2887e12 100644 --- a/include/wsrep/client_context.hpp +++ b/include/wsrep/client_context.hpp @@ -190,6 +190,21 @@ namespace wsrep */ int before_statement(); + /*! + * Return values for after_statement() method. + */ + enum after_statement_result + { + /*! Statement was executed succesfully */ + asr_success, + /*! Statement execution encountered an error, the transaction + * was rolled back */ + asr_error, + /*! Statement execution encountered an error, the transaction + was rolled back. However the statement was self contained + (e.g. autocommit statement) so it can be retried. */ + asr_may_retry + }; /*! * After statement execution operations. * @@ -199,7 +214,7 @@ namespace wsrep * If overridden by the implementation, base class method * should be called after any implementation specific operations. */ - void after_statement(); + enum after_statement_result after_statement(); int start_transaction() { @@ -386,6 +401,7 @@ namespace wsrep */ void state(wsrep::unique_lock& lock, enum state state); + virtual bool is_autocommit() const = 0; /*! * Virtual method to return true if the client operates * in two phase commit mode. diff --git a/include/wsrep/client_service.hpp b/include/wsrep/client_service.hpp new file mode 100644 index 0000000..c66b7d2 --- /dev/null +++ b/include/wsrep/client_service.hpp @@ -0,0 +1,137 @@ +// +// Copyright (C) 2018 Codership Oy +// + +/*! \file client_service.hpp + * + * This file will define a `callback` abstract interface for a + * DBMS client session service. The interface will define methods + * which will be called by the wsrep-lib under certain circumstances, + * for example when a transaction rollback is required by internal + * wsrep-lib operation or applier client needs to apply a write set. + * + * \todo Figure out better name for this interface. + */ + +namespace wsrep +{ + class client_service + { + public: + virtual bool is_autocommit() const = 0; + /*! + * Return true if two pahase commit is required for transaction + * to commit. + */ + virtual bool do_2pc() const = 0; + + /*! + * Return true if the current transaction has been interrupted. + */ + virtual bool interrupted() const = 0; + + /*! + * Reset possible global or thread local parameters associated + * to the thread. + */ + virtual void reset_globals() = 0; + + /*! + * Store possible global or thread local parameters associated + * to the thread. + */ + virtual void store_globals() = 0; + + /*! + * Set up a data for replication. + */ + virtual int prepare_data_for_replication(wsrep::data& data) = 0; + + + /*! + * Apply a write set. + */ + virtual int apply() = 0; + + /*! + * Prepare a transaction for commit. + */ + virtual int prepare() = 0; + + /*! + * Commit transaction. + */ + virtual int commit() = 0; + + /*! + * Roll back transaction. + */ + virtual int rollback() = 0; + + /*! + * Forcefully shut down the DBMS process or replication system. + * This may be called in situations where + * the process may encounter a situation where data integrity + * may not be guaranteed or other unrecoverable condition is + * encontered. + */ + virtual void emergency_shutdown() = 0; + + // Replaying + /*! + * Notify that the client will replay. + * + * \todo This should not be visible to DBMS level, should be + * handled internally by wsrep-lib. + */ + virtual void will_replay() = 0; + + /*! + * Replay the current transaction. The implementation must put + * the caller Client Context into applying mode and call + * client_context::replay(). + * + * \todo This should not be visible to DBMS level, should be + * handled internally by wsrep-lib. + */ + virtual int replay() = 0; + + /*! + * Wait until all replaying transactions have been finished + * replaying. + * + * \todo This should not be visible to DBMS level, should be + * handled internally by wsrep-lib. + */ + virtual void wait_for_replayers() = 0; + + // Streaming replication + /*! + * Append a write set fragment into fragment storage. + */ + virtual int append_fragment() = 0; + }; + + /*! + * Debug callback methods. These methods are called only in + * builds that have WITH_DEBUG defined. + */ + class client_debug_callback + { + public: + /*! + * Enter debug sync point. + * + * @params sync_point Name of the debug sync point. + */ + void debug_sync(const char* sync_point) = 0; + + /*! + * Forcefully kill the process if the suicide_point has + * been enabled. + */ + void debug_suicide(const char* suicide_point) = 0; + }; + + +} diff --git a/src/client_context.cpp b/src/client_context.cpp index 3ee1836..da6da91 100644 --- a/src/client_context.cpp +++ b/src/client_context.cpp @@ -105,14 +105,29 @@ int wsrep::client_context::before_statement() return 0; } -void wsrep::client_context::after_statement() +enum wsrep::client_context::after_statement_result +wsrep::client_context::after_statement() { + // wsrep::unique_lock lock(mutex_); + assert(state() == s_exec); #if 0 /*! * \todo Check for replay state, do rollback if requested. */ #endif // 0 - (void)transaction_.after_statement(); + int ret(transaction_.after_statement()); + if (ret) + { + if (is_autocommit()) + { + return asr_may_retry; + } + else + { + return asr_error; + } + } + return asr_success; } // Private diff --git a/src/dbms_simulator.cpp b/src/dbms_simulator.cpp index f32c799..4668edf 100644 --- a/src/dbms_simulator.cpp +++ b/src/dbms_simulator.cpp @@ -336,6 +336,7 @@ public: return stats_; } private: + bool is_autocommit() const override { return false; } bool do_2pc() const override { return false; } int apply(const wsrep::data& data) override { diff --git a/src/mock_client_context.hpp b/src/mock_client_context.hpp index d6a5b61..bc4928a 100644 --- a/src/mock_client_context.hpp +++ b/src/mock_client_context.hpp @@ -22,6 +22,7 @@ namespace wsrep // Note: Mutex is initialized only after passed // to client_context constructor. , mutex_() + , is_autocommit_(false) , do_2pc_(do_2pc) , fail_next_applying_() { } @@ -35,6 +36,7 @@ namespace wsrep int apply(const wsrep::data&); int commit(); int rollback(); + bool is_autocommit() const { return is_autocommit_; } bool do_2pc() const { return do_2pc_; } void will_replay(wsrep::transaction_context&) WSREP_OVERRIDE { } int replay(wsrep::transaction_context& tc) WSREP_OVERRIDE @@ -61,6 +63,7 @@ namespace wsrep { fail_next_applying_ = fail_next_applying; } private: wsrep::default_mutex mutex_; + bool is_autocommit_; bool do_2pc_; bool fail_next_applying_; };