summaryrefslogtreecommitdiffstats
path: root/wsrep-lib/include/wsrep/provider.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'wsrep-lib/include/wsrep/provider.hpp')
-rw-r--r--wsrep-lib/include/wsrep/provider.hpp506
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