mirror of
				https://github.com/codership/wsrep-lib.git
				synced 2025-10-31 06:50:26 +03:00 
			
		
		
		
	- Add a set_provider_factory() method to server_state to allow injecting provider factory which will be called when the provider is loaded. Other related changes: - Implement to_string() helper method for id class. - Fix id ostream operator human readable id printing. - Pass victim client_service as an argument to provider::bf_abort() to allow passing victim context to custom provider. - Implement prev() helper method for seqno class. - Make server_state recover_streaming_appliers_if_not_recovered() public. In some recovery scenarios the method must be called outside of server_state internal code paths. - Add storage_service requires_globals() method. The storage service implementation may override this to return false if changing to storage service context does not require store/reset globals. - Change view final() to also require that the view status is not primary for the view to be final. Also change the method name to is_final() to avoid confusion with C++ final identifier. - Fixes to server state handling in disconnecting and disconnected states. - Keep TOI meta data over whole TOI critical section. Co-authored-by: Denis Protivensky <denis.protivensky@galeracluster.com>
		
			
				
	
	
		
			330 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			330 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C) 2018 Codership Oy <info@codership.com>
 | |
|  *
 | |
|  * This file is part of wsrep-lib.
 | |
|  *
 | |
|  * Wsrep-lib is free software: you can redistribute it and/or modify
 | |
|  * it under the terms of the GNU General Public License as published by
 | |
|  * the Free Software Foundation, either version 2 of the License, or
 | |
|  * (at your option) any later version.
 | |
|  *
 | |
|  * Wsrep-lib is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with wsrep-lib.  If not, see <https://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| /** @file transaction.hpp */
 | |
| #ifndef WSREP_TRANSACTION_HPP
 | |
| #define WSREP_TRANSACTION_HPP
 | |
| 
 | |
| #include "provider.hpp"
 | |
| #include "transaction_id.hpp"
 | |
| #include "streaming_context.hpp"
 | |
| #include "lock.hpp"
 | |
| #include "sr_key_set.hpp"
 | |
| #include "buffer.hpp"
 | |
| #include "xid.hpp"
 | |
| 
 | |
| #include <iosfwd>
 | |
| #include <vector>
 | |
| 
 | |
| namespace wsrep
 | |
| {
 | |
|     class client_service;
 | |
|     class client_state;
 | |
|     class key;
 | |
|     class const_buffer;
 | |
|     class server_service;
 | |
| 
 | |
|     class transaction
 | |
|     {
 | |
|     public:
 | |
|         enum state
 | |
|         {
 | |
|             s_executing,
 | |
|             s_preparing,
 | |
|             s_prepared,
 | |
|             s_certifying,
 | |
|             s_committing,
 | |
|             s_ordered_commit,
 | |
|             s_committed,
 | |
|             s_cert_failed,
 | |
|             s_must_abort,
 | |
|             s_aborting,
 | |
|             s_aborted,
 | |
|             s_must_replay,
 | |
|             s_replaying
 | |
|         };
 | |
|         static const int n_states = s_replaying + 1;
 | |
|         enum state state() const
 | |
|         { return state_; }
 | |
| 
 | |
|         transaction(wsrep::client_state& client_state);
 | |
|         ~transaction();
 | |
|         // Accessors
 | |
|         wsrep::transaction_id id() const
 | |
|         { return id_; }
 | |
| 
 | |
|         const wsrep::id& server_id() const
 | |
|         { return server_id_; }
 | |
| 
 | |
|         bool active() const
 | |
|         { return (id_ != wsrep::transaction_id::undefined()); }
 | |
| 
 | |
| 
 | |
|         void state(wsrep::unique_lock<wsrep::mutex>&, enum state);
 | |
| 
 | |
|         // Return true if the certification of the last
 | |
|         // fragment succeeded
 | |
|         bool certified() const { return certified_; }
 | |
| 
 | |
|         wsrep::seqno seqno() const
 | |
|         {
 | |
|             return ws_meta_.seqno();
 | |
|         }
 | |
|         // Return true if the last fragment was ordered by the
 | |
|         // provider
 | |
|         bool ordered() const
 | |
|         { return (ws_meta_.seqno().is_undefined() == false); }
 | |
| 
 | |
|         /**
 | |
|          * Return true if any fragments have been successfully certified
 | |
|          * for the transaction.
 | |
|          */
 | |
|         bool is_streaming() const
 | |
|         {
 | |
|             return (streaming_context_.fragments_certified() > 0);
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Return number of fragments certified for current statement.
 | |
|          *
 | |
|          * This counts fragments which have been successfully certified
 | |
|          * since the construction of object or last after_statement()
 | |
|          * call.
 | |
|          *
 | |
|          * @return Number of fragments certified for current statement.
 | |
|          */
 | |
|         size_t fragments_certified_for_statement() const
 | |
|         {
 | |
|             return fragments_certified_for_statement_;
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Return true if transaction has not generated any changes.
 | |
|          */
 | |
|         bool is_empty() const
 | |
|         {
 | |
|             return sr_keys_.empty();
 | |
|         }
 | |
| 
 | |
|         bool is_xa() const
 | |
|         {
 | |
|             return !xid_.is_null();
 | |
|         }
 | |
| 
 | |
|         void assign_xid(const wsrep::xid& xid);
 | |
| 
 | |
|         const wsrep::xid& xid() const
 | |
|         {
 | |
|             return xid_;
 | |
|         }
 | |
| 
 | |
|         int restore_to_prepared_state(const wsrep::xid& xid);
 | |
| 
 | |
|         int commit_or_rollback_by_xid(const wsrep::xid& xid, bool commit);
 | |
| 
 | |
|         void xa_detach();
 | |
| 
 | |
|         int xa_replay(wsrep::unique_lock<wsrep::mutex>&);
 | |
| 
 | |
|         bool pa_unsafe() const { return (flags() & wsrep::provider::flag::pa_unsafe); }
 | |
|         void pa_unsafe(bool pa_unsafe) {
 | |
|           if (pa_unsafe) {
 | |
|             flags(flags() | wsrep::provider::flag::pa_unsafe);
 | |
|           } else {
 | |
|             flags(flags() & ~wsrep::provider::flag::pa_unsafe);
 | |
|           }
 | |
|         }
 | |
|         bool implicit_deps() const { return implicit_deps_; }
 | |
|         void implicit_deps(bool implicit) { implicit_deps_ = implicit; }
 | |
| 
 | |
|         int start_transaction(const wsrep::transaction_id& id);
 | |
| 
 | |
|         int start_transaction(const wsrep::ws_handle& ws_handle,
 | |
|                               const wsrep::ws_meta& ws_meta);
 | |
| 
 | |
|         int next_fragment(const wsrep::ws_meta& ws_meta);
 | |
| 
 | |
|         void adopt(const transaction& transaction);
 | |
|         void fragment_applied(wsrep::seqno seqno);
 | |
| 
 | |
|         int prepare_for_ordering(const wsrep::ws_handle& ws_handle,
 | |
|                                  const wsrep::ws_meta& ws_meta,
 | |
|                                  bool is_commit);
 | |
| 
 | |
|         int assign_read_view(const wsrep::gtid* gtid);
 | |
| 
 | |
|         int append_key(const wsrep::key&);
 | |
| 
 | |
|         int append_data(const wsrep::const_buffer&);
 | |
| 
 | |
|         int after_row();
 | |
| 
 | |
|         int before_prepare(wsrep::unique_lock<wsrep::mutex>&,
 | |
|                            const wsrep::provider::seq_cb_t*);
 | |
| 
 | |
|         int after_prepare(wsrep::unique_lock<wsrep::mutex>&);
 | |
| 
 | |
|         int before_commit(const wsrep::provider::seq_cb_t*);
 | |
| 
 | |
|         int ordered_commit();
 | |
| 
 | |
|         int after_commit();
 | |
| 
 | |
|         int before_rollback();
 | |
| 
 | |
|         int after_rollback();
 | |
| 
 | |
|         int before_statement();
 | |
| 
 | |
|         int after_statement();
 | |
|         int after_statement(wsrep::unique_lock<wsrep::mutex>&);
 | |
| 
 | |
|         void after_command_must_abort(wsrep::unique_lock<wsrep::mutex>&);
 | |
| 
 | |
|         void after_applying();
 | |
| 
 | |
|         bool bf_abort(wsrep::unique_lock<wsrep::mutex>& lock,
 | |
|                       wsrep::seqno bf_seqno,
 | |
|                       wsrep::client_service&);
 | |
|         bool total_order_bf_abort(wsrep::unique_lock<wsrep::mutex>&,
 | |
|                                   wsrep::seqno bf_seqno,
 | |
|                                   wsrep::client_service&);
 | |
| 
 | |
|         void clone_for_replay(const wsrep::transaction& other);
 | |
| 
 | |
|         bool bf_aborted() const
 | |
|         {
 | |
|             return (bf_abort_client_state_ != 0);
 | |
|         }
 | |
| 
 | |
|         bool bf_aborted_in_total_order() const
 | |
|         {
 | |
|             return bf_aborted_in_total_order_;
 | |
|         }
 | |
| 
 | |
|         int flags() const
 | |
|         {
 | |
|             return flags_;
 | |
|         }
 | |
| 
 | |
|         // wsrep::mutex& mutex();
 | |
|         wsrep::ws_handle& ws_handle() { return ws_handle_; }
 | |
|         const wsrep::ws_handle& ws_handle() const { return ws_handle_; }
 | |
|         const wsrep::ws_meta& ws_meta() const { return ws_meta_; }
 | |
|         const wsrep::streaming_context& streaming_context() const
 | |
|         { return streaming_context_; }
 | |
|         wsrep::streaming_context& streaming_context()
 | |
|         { return streaming_context_; }
 | |
|         void adopt_apply_error(wsrep::mutable_buffer& buf)
 | |
|         {
 | |
|             apply_error_buf_ = std::move(buf);
 | |
|         }
 | |
|         const wsrep::mutable_buffer& apply_error() const
 | |
|         { return apply_error_buf_; }
 | |
|     private:
 | |
|         transaction(const transaction&);
 | |
|         transaction operator=(const transaction&);
 | |
| 
 | |
|         wsrep::provider& provider();
 | |
|         void flags(int flags) { flags_ = flags; }
 | |
|         // Return true if the transaction must abort, is aborting,
 | |
|         // or has been aborted, or has been interrupted by DBMS
 | |
|         // as indicated by client_service::interrupted() call.
 | |
|         // The call will adjust transaction state and set client_state
 | |
|         // error status accordingly.
 | |
|         bool abort_or_interrupt(wsrep::unique_lock<wsrep::mutex>&);
 | |
|         int streaming_step(wsrep::unique_lock<wsrep::mutex>&, bool force = false);
 | |
|         int certify_fragment(wsrep::unique_lock<wsrep::mutex>&);
 | |
|         int certify_commit(wsrep::unique_lock<wsrep::mutex>&,
 | |
|                            const wsrep::provider::seq_cb_t*);
 | |
|         int append_sr_keys_for_commit();
 | |
|         int release_commit_order(wsrep::unique_lock<wsrep::mutex>&);
 | |
|         void remove_fragments_in_storage_service_scope(
 | |
|             wsrep::unique_lock<wsrep::mutex>&);
 | |
|         void streaming_rollback(wsrep::unique_lock<wsrep::mutex>&);
 | |
|         int replay(wsrep::unique_lock<wsrep::mutex>&);
 | |
|         void xa_replay_common(wsrep::unique_lock<wsrep::mutex>&);
 | |
|         int xa_replay_commit(wsrep::unique_lock<wsrep::mutex>&);
 | |
|         void cleanup();
 | |
|         void debug_log_state(const char*) const;
 | |
|         void debug_log_key_append(const wsrep::key& key) const;
 | |
| 
 | |
|         wsrep::server_service& server_service_;
 | |
|         wsrep::client_service& client_service_;
 | |
|         wsrep::client_state& client_state_;
 | |
|         wsrep::id server_id_;
 | |
|         wsrep::transaction_id id_;
 | |
|         enum state state_;
 | |
|         std::vector<enum state> state_hist_;
 | |
|         enum state bf_abort_state_;
 | |
|         enum wsrep::provider::status bf_abort_provider_status_;
 | |
|         int bf_abort_client_state_;
 | |
|         bool bf_aborted_in_total_order_;
 | |
|         wsrep::ws_handle ws_handle_;
 | |
|         wsrep::ws_meta ws_meta_;
 | |
|         int flags_;
 | |
|         bool implicit_deps_;
 | |
|         bool certified_;
 | |
|         size_t fragments_certified_for_statement_;
 | |
|         wsrep::streaming_context streaming_context_;
 | |
|         wsrep::sr_key_set sr_keys_;
 | |
|         wsrep::mutable_buffer apply_error_buf_;
 | |
|         wsrep::xid xid_;
 | |
|         bool streaming_rollback_in_progress_;
 | |
|         /* This flag tells that the transaction has become immutable
 | |
|            against BF aborts. Ideally this would be deduced from transaction
 | |
|            state, i.e. s_ordered_commit or s_committed, but the current
 | |
|            version of wsrep-lib changes the transaction state to
 | |
|            s_ordered_commit too late. Fixing this appears to require
 | |
|            too many changes to application using the lib, so boolean flag
 | |
|            must do. */
 | |
|         bool is_bf_immutable_;
 | |
|     };
 | |
| 
 | |
|     static inline const char* to_c_string(enum wsrep::transaction::state state)
 | |
|     {
 | |
|         switch (state)
 | |
|         {
 | |
|         case wsrep::transaction::s_executing: return "executing";
 | |
|         case wsrep::transaction::s_preparing: return "preparing";
 | |
|         case wsrep::transaction::s_prepared: return "prepared";
 | |
|         case wsrep::transaction::s_certifying: return "certifying";
 | |
|         case wsrep::transaction::s_committing: return "committing";
 | |
|         case wsrep::transaction::s_ordered_commit: return "ordered_commit";
 | |
|         case wsrep::transaction::s_committed: return "committed";
 | |
|         case wsrep::transaction::s_cert_failed: return "cert_failed";
 | |
|         case wsrep::transaction::s_must_abort: return "must_abort";
 | |
|         case wsrep::transaction::s_aborting: return "aborting";
 | |
|         case wsrep::transaction::s_aborted: return "aborted";
 | |
|         case wsrep::transaction::s_must_replay: return "must_replay";
 | |
|         case wsrep::transaction::s_replaying: return "replaying";
 | |
|         }
 | |
|         return "unknown";
 | |
|     }
 | |
|     static inline std::string to_string(enum wsrep::transaction::state state)
 | |
|     {
 | |
|         return to_c_string(state);
 | |
|     }
 | |
| 
 | |
|     std::ostream& operator<<(std::ostream& os, enum wsrep::transaction::state);
 | |
| 
 | |
| }
 | |
| 
 | |
| #endif // WSREP_TRANSACTION_HPP
 |