diff options
Diffstat (limited to '')
-rw-r--r-- | wsrep-lib/include/wsrep/provider.hpp | 506 |
1 files changed, 506 insertions, 0 deletions
diff --git a/wsrep-lib/include/wsrep/provider.hpp b/wsrep-lib/include/wsrep/provider.hpp new file mode 100644 index 00000000..c00e9ed5 --- /dev/null +++ b/wsrep-lib/include/wsrep/provider.hpp @@ -0,0 +1,506 @@ +/* + * 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/>. + */ + +#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 <cstring> + +#include <string> +#include <vector> +#include <ostream> + +/** + * 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<wsrep::gtid, enum status> + 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_variable> 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 |