mirror of
https://github.com/codership/wsrep-lib.git
synced 2025-04-19 21:02:17 +03:00
This change is needed for custom provider implementations to have a way to access the victim in the application context. Helper interface operation_context to pass caller context for service/provider callbacks in more type safe way.
521 lines
16 KiB
C++
521 lines
16 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/>.
|
|
*/
|
|
|
|
#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 "operation_context.hpp"
|
|
|
|
#include <cassert>
|
|
#include <cstring>
|
|
|
|
#include <memory>
|
|
#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_()
|
|
, provider_position_()
|
|
{ }
|
|
ws_meta(const wsrep::gtid& gtid,
|
|
const wsrep::stid& stid,
|
|
wsrep::seqno depends_on,
|
|
int flags,
|
|
int64_t provider_position)
|
|
: gtid_(gtid)
|
|
, stid_(stid)
|
|
, depends_on_(depends_on)
|
|
, flags_(flags)
|
|
, provider_position_(provider_position)
|
|
{ }
|
|
ws_meta(const wsrep::stid& stid)
|
|
: gtid_()
|
|
, stid_(stid)
|
|
, depends_on_()
|
|
, flags_()
|
|
, provider_position_()
|
|
{ }
|
|
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_; }
|
|
|
|
int64_t provider_position() const { return provider_position_; }
|
|
|
|
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_;
|
|
/** Field reserved for provider to report its internal position. */
|
|
int64_t provider_position_;
|
|
};
|
|
|
|
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::operation_context& victim_ctx,
|
|
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::ws_meta& ws_meta,
|
|
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 std::unique_ptr<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
|