/* * Copyright (C) 2018 Codership Oy * * 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 . */ #ifndef WSREP_PROVIDER_HPP #define WSREP_PROVIDER_HPP #include "gtid.hpp" #include "key.hpp" #include "buffer.hpp" #include "client_id.hpp" #include "transaction_id.hpp" #include "compiler.hpp" #include #include #include #include /** * Empty provider magic. If none provider is passed to make_provider(), * a dummy provider is loaded. */ #define WSREP_LIB_PROVIDER_NONE "none" namespace wsrep { class server_state; class high_priority_service; class thread_service; class tls_service; class allowlist_service; class event_service; class stid { public: stid() : server_id_() , transaction_id_() , client_id_() { } stid(const wsrep::id& server_id, wsrep::transaction_id transaction_id, wsrep::client_id client_id) : server_id_(server_id) , transaction_id_(transaction_id) , client_id_(client_id) { } const wsrep::id& server_id() const { return server_id_; } wsrep::transaction_id transaction_id() const { return transaction_id_; } wsrep::client_id client_id() const { return client_id_; } bool operator==(const stid& other) const { return ( server_id_ == other.server_id_ && transaction_id_ == other.transaction_id_ && client_id_ == other.client_id_ ); } private: wsrep::id server_id_; wsrep::transaction_id transaction_id_; wsrep::client_id client_id_; }; class ws_handle { public: ws_handle() : transaction_id_() , opaque_() { } ws_handle(wsrep::transaction_id id) : transaction_id_(id) , opaque_() { } ws_handle(wsrep::transaction_id id, void* opaque) : transaction_id_(id) , opaque_(opaque) { } wsrep::transaction_id transaction_id() const { return transaction_id_; } void* opaque() const { return opaque_; } bool operator==(const ws_handle& other) const { return ( transaction_id_ == other.transaction_id_ && opaque_ == other.opaque_ ); } private: wsrep::transaction_id transaction_id_; void* opaque_; }; class ws_meta { public: ws_meta() : gtid_() , stid_() , depends_on_() , flags_() { } ws_meta(const wsrep::gtid& gtid, const wsrep::stid& stid, wsrep::seqno depends_on, int flags) : gtid_(gtid) , stid_(stid) , depends_on_(depends_on) , flags_(flags) { } ws_meta(const wsrep::stid& stid) : gtid_() , stid_(stid) , depends_on_() , flags_() { } const wsrep::gtid& gtid() const { return gtid_; } const wsrep::id& group_id() const { return gtid_.id(); } wsrep::seqno seqno() const { return gtid_.seqno(); } const wsrep::id& server_id() const { return stid_.server_id(); } wsrep::client_id client_id() const { return stid_.client_id(); } wsrep::transaction_id transaction_id() const { return stid_.transaction_id(); } bool ordered() const { return !gtid_.is_undefined(); } wsrep::seqno depends_on() const { return depends_on_; } int flags() const { return flags_; } bool operator==(const ws_meta& other) const { return ( gtid_ == other.gtid_ && stid_ == other.stid_ && depends_on_ == other.depends_on_ && flags_ == other.flags_ ); } private: wsrep::gtid gtid_; wsrep::stid stid_; wsrep::seqno depends_on_; int flags_; }; std::string flags_to_string(int flags); std::ostream& operator<<(std::ostream& os, const wsrep::ws_meta& ws_meta); // Abstract interface for provider implementations class provider { public: class status_variable { public: status_variable(const std::string& name, const std::string& value) : name_(name) , value_(value) { } const std::string& name() const { return name_; } const std::string& value() const { return value_; } private: std::string name_; std::string value_; }; /** * Return value enumeration * * @todo Convert this to struct ec, get rid of prefixes. */ enum status { /** Success */ success, /** Warning*/ error_warning, /** Transaction was not found from provider */ error_transaction_missing, /** Certification failed */ error_certification_failed, /** Transaction was BF aborted */ error_bf_abort, /** Transaction size exceeded */ error_size_exceeded, /** Connectivity to cluster lost */ error_connection_failed, /** Internal provider failure or provider was closed, provider must be reinitialized */ error_provider_failed, /** Fatal error, server must abort */ error_fatal, /** Requested functionality is not implemented by the provider */ error_not_implemented, /** Operation is not allowed */ error_not_allowed, /** Unknown error code from the provider */ error_unknown }; static std::string to_string(enum status); struct flag { static const int start_transaction = (1 << 0); static const int commit = (1 << 1); static const int rollback = (1 << 2); static const int isolation = (1 << 3); static const int pa_unsafe = (1 << 4); static const int commutative = (1 << 5); static const int native = (1 << 6); static const int prepare = (1 << 7); static const int snapshot = (1 << 8); static const int implicit_deps = (1 << 9); }; /** * Provider capabilities. */ struct capability { static const int multi_master = (1 << 0); static const int certification = (1 << 1); static const int parallel_applying = (1 << 2); static const int transaction_replay = (1 << 3); static const int isolation = (1 << 4); static const int pause = (1 << 5); static const int causal_reads = (1 << 6); static const int causal_transaction = (1 << 7); static const int incremental_writeset = (1 << 8); static const int session_locks = (1 << 9); static const int distributed_locks = (1 << 10); static const int consistency_check = (1 << 11); static const int unordered = (1 << 12); static const int annotation = (1 << 13); static const int preordered = (1 << 14); static const int streaming = (1 << 15); static const int snapshot = (1 << 16); static const int nbo = (1 << 17); /** decipher capability bitmask */ static std::string str(int); }; provider(wsrep::server_state& server_state) : server_state_(server_state) { } virtual ~provider() { } // Provider state management virtual enum status connect(const std::string& cluster_name, const std::string& cluster_url, const std::string& state_donor, bool bootstrap) = 0; virtual int disconnect() = 0; virtual int capabilities() const = 0; virtual int desync() = 0; virtual int resync() = 0; virtual wsrep::seqno pause() = 0; virtual int resume() = 0; // Applier interface virtual enum status run_applier(wsrep::high_priority_service* applier_ctx) = 0; // Write set replication // TODO: Rename to assing_read_view() virtual int start_transaction(wsrep::ws_handle&) = 0; virtual enum status assign_read_view( wsrep::ws_handle&, const wsrep::gtid*) = 0; virtual int append_key(wsrep::ws_handle&, const wsrep::key&) = 0; virtual enum status append_data( wsrep::ws_handle&, const wsrep::const_buffer&) = 0; virtual enum status certify(wsrep::client_id, wsrep::ws_handle&, int, wsrep::ws_meta&) = 0; /** * BF abort a transaction inside provider. * * @param[in] bf_seqno Seqno of the aborter transaction * @param[in] victim_txt Transaction identifier of the victim * @param[out] victim_seqno Sequence number of the victim transaction * or WSREP_SEQNO_UNDEFINED if the victim was not ordered * * @return wsrep_status_t */ virtual enum status bf_abort(wsrep::seqno bf_seqno, wsrep::transaction_id victim_trx, wsrep::seqno& victim_seqno) = 0; virtual enum status rollback(wsrep::transaction_id) = 0; virtual enum status commit_order_enter(const wsrep::ws_handle&, const wsrep::ws_meta&) = 0; virtual int commit_order_leave(const wsrep::ws_handle&, const wsrep::ws_meta&, const wsrep::mutable_buffer& err) = 0; virtual int release(wsrep::ws_handle&) = 0; /** * Replay a transaction. * * @todo Inspect if the ws_handle could be made const * * @return Zero in case of success, non-zero on failure. */ virtual enum status replay( const wsrep::ws_handle& ws_handle, wsrep::high_priority_service* applier_ctx) = 0; /** * Enter total order isolation critical section */ virtual enum status enter_toi(wsrep::client_id, const wsrep::key_array& keys, const wsrep::const_buffer& buffer, wsrep::ws_meta& ws_meta, int flags) = 0; /** * Leave total order isolation critical section */ virtual enum status leave_toi(wsrep::client_id, const wsrep::mutable_buffer& err) = 0; /** * Perform a causal read on cluster. * * @param timeout Timeout in seconds * * @return Provider status indicating the result of the call. */ virtual std::pair causal_read(int timeout) const = 0; virtual enum status wait_for_gtid(const wsrep::gtid&, int timeout) const = 0; /** * Return last committed GTID. */ virtual wsrep::gtid last_committed_gtid() const = 0; virtual enum status sst_sent(const wsrep::gtid&, int) = 0; virtual enum status sst_received(const wsrep::gtid&, int) = 0; virtual enum status enc_set_key(const wsrep::const_buffer& key) = 0; virtual std::vector status() const = 0; virtual void reset_status() = 0; virtual std::string options() const = 0; virtual enum status options(const std::string&) = 0; /** * Get provider name. * * @return Provider name string. */ virtual std::string name() const = 0; /** * Get provider version. * * @return Provider version string. */ virtual std::string version() const = 0; /** * Get provider vendor. * * @return Provider vendor string. */ virtual std::string vendor() const = 0; /** * Return pointer to native provider handle. */ virtual void* native() const = 0; /** * Services argument passed to make_provider. This struct contains * optional services which are passed to the provider. */ struct services { wsrep::thread_service* thread_service; wsrep::tls_service* tls_service; wsrep::allowlist_service* allowlist_service; wsrep::event_service* event_service; // some GCC and clang versions don't support C++11 default // initializers fully, so we need to use explicit constructors // instead: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165 // https://bugs.llvm.org/show_bug.cgi?id=36684 services() : thread_service() , tls_service() , allowlist_service() , event_service() { } services(wsrep::thread_service* thr, wsrep::tls_service* tls, wsrep::allowlist_service* all, wsrep::event_service* event) : thread_service(thr) , tls_service(tls) , allowlist_service(all) , event_service(event) { } }; /** * Create a new provider. * * @param provider_spec Provider specification * @param provider_options Initial options to provider * @param thread_service Optional thread service implementation. */ static provider* make_provider(wsrep::server_state&, const std::string& provider_spec, const std::string& provider_options, const wsrep::provider::services& services = wsrep::provider::services()); protected: wsrep::server_state& server_state_; }; static inline bool starts_transaction(int flags) { return (flags & wsrep::provider::flag::start_transaction); } static inline bool commits_transaction(int flags) { return (flags & wsrep::provider::flag::commit); } static inline bool rolls_back_transaction(int flags) { return (flags & wsrep::provider::flag::rollback); } static inline bool prepares_transaction(int flags) { return (flags & wsrep::provider::flag::prepare); } static inline bool is_toi(int flags) { return (flags & wsrep::provider::flag::isolation); } static inline bool is_commutative(int flags) { return (flags & wsrep::provider::flag::commutative); } static inline bool is_native(int flags) { return (flags & wsrep::provider::flag::native); } } #endif // WSREP_PROVIDER_HPP