mirror of
https://github.com/codership/wsrep-lib.git
synced 2025-07-28 20:02:00 +03:00
Implemented thread service support.
Added a wsrep::thread_service interface to allow application to inject instrumented thread, mutex and condition variable implementation for provider. The interface is defined in include/wsrep/thread_service.hpp. Sample implementation is provided in dbsim/db_threads.[h|c]pp. This patch will also clean up some remaining dependencies to wsrep-API compilation units so that the dependency to wsrep-API is header only. This will extending the provider support to later wsrep-API versions.
This commit is contained in:
@ -14,6 +14,8 @@ add_library(wsrep-lib
|
||||
view.cpp
|
||||
server_state.cpp
|
||||
thread.cpp
|
||||
thread_service_v1.cpp
|
||||
transaction.cpp
|
||||
uuid.cpp
|
||||
wsrep_provider_v26.cpp)
|
||||
target_link_libraries(wsrep-lib wsrep_api_v26 pthread dl)
|
||||
|
40
src/gtid.cpp
40
src/gtid.cpp
@ -36,11 +36,47 @@ std::istream& wsrep::operator>>(std::istream& is, wsrep::gtid& gtid)
|
||||
std::getline(is, id_str, ':');
|
||||
long long seq;
|
||||
is >> seq;
|
||||
gtid = wsrep::gtid(wsrep::id(id_str), wsrep::seqno(seq));
|
||||
if (!is)
|
||||
{
|
||||
is.clear(std::ios_base::failbit);
|
||||
return is;
|
||||
}
|
||||
try
|
||||
{
|
||||
// wsrep::id constructor will throw if it cannot parse the
|
||||
// id_str.
|
||||
gtid = wsrep::gtid(wsrep::id(id_str), wsrep::seqno(seq));
|
||||
}
|
||||
catch (const wsrep::runtime_error& e)
|
||||
{
|
||||
// Formatting or extraction error. Clear the istream state and
|
||||
// set failibit.
|
||||
is.clear(std::ios_base::failbit);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
ssize_t wsrep::gtid_print_to_c_str(
|
||||
ssize_t wsrep::scan_from_c_str(
|
||||
const char* buf, size_t buf_len, wsrep::gtid& gtid)
|
||||
{
|
||||
std::istringstream is(std::string(buf, buf_len));
|
||||
is >> gtid;
|
||||
// Whole string was consumed without failures
|
||||
if (is && is.eof())
|
||||
{
|
||||
return static_cast<ssize_t>(buf_len);
|
||||
}
|
||||
// Some failure occurred
|
||||
if (!is)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
// The string was not consumed completely, return current position
|
||||
// of the istream.
|
||||
return is.tellg();
|
||||
}
|
||||
|
||||
ssize_t wsrep::print_to_c_str(
|
||||
const wsrep::gtid& gtid, char* buf, size_t buf_len)
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
22
src/id.cpp
22
src/id.cpp
@ -18,7 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "wsrep/id.hpp"
|
||||
#include <wsrep_api.h>
|
||||
#include "uuid.hpp"
|
||||
|
||||
#include <cctype>
|
||||
#include <sstream>
|
||||
@ -29,15 +29,17 @@ const wsrep::id wsrep::id::undefined_ = wsrep::id();
|
||||
wsrep::id::id(const std::string& str)
|
||||
: data_()
|
||||
{
|
||||
wsrep_uuid_t wsrep_uuid;
|
||||
if (wsrep_uuid_scan(str.c_str(), str.size(), &wsrep_uuid) ==
|
||||
WSREP_UUID_STR_LEN)
|
||||
wsrep::uuid_t wsrep_uuid;
|
||||
|
||||
if (str.size() == WSREP_LIB_UUID_STR_LEN &&
|
||||
wsrep::uuid_scan(str.c_str(), str.size(), &wsrep_uuid) ==
|
||||
WSREP_LIB_UUID_STR_LEN)
|
||||
{
|
||||
std::memcpy(data_, wsrep_uuid.data, sizeof(data_));
|
||||
std::memcpy(data_.buf, wsrep_uuid.data, sizeof(data_.buf));
|
||||
}
|
||||
else if (str.size() <= 16)
|
||||
{
|
||||
std::memcpy(data_, str.c_str(), str.size());
|
||||
std::memcpy(data_.buf, str.c_str(), str.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -58,14 +60,14 @@ std::ostream& wsrep::operator<<(std::ostream& os, const wsrep::id& id)
|
||||
}
|
||||
else
|
||||
{
|
||||
char uuid_str[WSREP_UUID_STR_LEN + 1];
|
||||
wsrep_uuid_t uuid;
|
||||
char uuid_str[WSREP_LIB_UUID_STR_LEN + 1];
|
||||
wsrep::uuid_t uuid;
|
||||
std::memcpy(uuid.data, ptr, sizeof(uuid.data));
|
||||
if (wsrep_uuid_print(&uuid, uuid_str, sizeof(uuid_str)) < 0)
|
||||
if (wsrep::uuid_print(&uuid, uuid_str, sizeof(uuid_str)) < 0)
|
||||
{
|
||||
throw wsrep::runtime_error("Could not print uuid");
|
||||
}
|
||||
uuid_str[WSREP_UUID_STR_LEN] = '\0';
|
||||
uuid_str[WSREP_LIB_UUID_STR_LEN] = '\0';
|
||||
return (os << uuid_str);
|
||||
}
|
||||
}
|
||||
|
@ -19,18 +19,69 @@
|
||||
|
||||
#include "wsrep/provider.hpp"
|
||||
#include "wsrep/logger.hpp"
|
||||
#include "wsrep/compiler.hpp"
|
||||
|
||||
#include "wsrep_provider_v26.hpp"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <memory>
|
||||
|
||||
struct dlh_deleter
|
||||
{
|
||||
void operator()(void* dlh)
|
||||
{
|
||||
dlclose(dlh);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<void, dlh_deleter>
|
||||
load_library(const std::string& provider_spec)
|
||||
{
|
||||
void* ret(dlopen(provider_spec.c_str(), RTLD_NOW | RTLD_LOCAL));
|
||||
if (ret == 0)
|
||||
{
|
||||
wsrep::log_error() << "Failed to load library " << provider_spec;
|
||||
}
|
||||
return std::unique_ptr<void, dlh_deleter>(ret);
|
||||
}
|
||||
|
||||
static int get_api_version(void* dlh)
|
||||
{
|
||||
const char** version(reinterpret_cast<const char**>(
|
||||
dlsym(dlh, "wsrep_interface_version")));
|
||||
if (version == 0)
|
||||
{
|
||||
wsrep::log_error() << "Failed to read interface version";
|
||||
return 0;
|
||||
}
|
||||
std::istringstream is(*version);
|
||||
int ret;
|
||||
is >> ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
wsrep::provider* wsrep::provider::make_provider(
|
||||
wsrep::server_state& server_state,
|
||||
const std::string& provider_spec,
|
||||
const std::string& provider_options)
|
||||
const std::string& provider_options,
|
||||
const wsrep::provider::services& services)
|
||||
{
|
||||
auto dlh(load_library(provider_spec));
|
||||
if (dlh == 0) return 0;
|
||||
int api_ver(get_api_version(dlh.get()));
|
||||
if (api_ver == 0) return 0;
|
||||
wsrep::log_info() << "Found provider with API version " << api_ver;
|
||||
try
|
||||
{
|
||||
return new wsrep::wsrep_provider_v26(
|
||||
server_state, provider_options, provider_spec);
|
||||
switch (api_ver)
|
||||
{
|
||||
case 26:
|
||||
return new wsrep::wsrep_provider_v26(
|
||||
server_state, provider_options, provider_spec, services);
|
||||
default:
|
||||
wsrep::log_error() << "Unimplemented wsrep-API version "
|
||||
<< api_ver;
|
||||
}
|
||||
}
|
||||
catch (const wsrep::runtime_error& e)
|
||||
{
|
||||
|
@ -471,15 +471,17 @@ static int apply_toi(wsrep::provider& provider,
|
||||
// Server State //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int wsrep::server_state::load_provider(const std::string& provider_spec,
|
||||
const std::string& provider_options)
|
||||
int wsrep::server_state::load_provider(
|
||||
const std::string& provider_spec, const std::string& provider_options,
|
||||
const wsrep::provider::services& services)
|
||||
{
|
||||
wsrep::log_info() << "Loading provider " << provider_spec
|
||||
<< " initial position: " << initial_position_;
|
||||
|
||||
provider_ = wsrep::provider::make_provider(*this,
|
||||
provider_spec,
|
||||
provider_options);
|
||||
provider_options,
|
||||
services);
|
||||
return (provider_ ? 0 : 1);
|
||||
}
|
||||
|
||||
|
284
src/thread_service_v1.cpp
Normal file
284
src/thread_service_v1.cpp
Normal file
@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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/>.
|
||||
*/
|
||||
|
||||
#include "thread_service_v1.hpp"
|
||||
|
||||
#include "wsrep/thread_service.hpp"
|
||||
#include "wsrep/logger.hpp"
|
||||
#include "v26/wsrep_thread_service.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <cerrno>
|
||||
|
||||
namespace wsrep_thread_service_v1
|
||||
{
|
||||
//
|
||||
// Thread service callbacks
|
||||
//
|
||||
|
||||
// Pointer to thread service implementation provided by
|
||||
// the application.
|
||||
static wsrep::thread_service* thread_service_impl{ 0 };
|
||||
|
||||
static const wsrep_thread_key_t* thread_key_create_cb(const char* name)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return reinterpret_cast<const wsrep_thread_key_t*>(
|
||||
thread_service_impl->create_thread_key(name));
|
||||
;
|
||||
}
|
||||
|
||||
static int thread_create_cb(const wsrep_thread_key_t* key,
|
||||
wsrep_thread_t** thread,
|
||||
void* (*fn)(void*), void* args)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return thread_service_impl->create_thread(
|
||||
reinterpret_cast<const wsrep::thread_service::thread_key*>(key),
|
||||
reinterpret_cast<wsrep::thread_service::thread**>(thread), fn,
|
||||
args);
|
||||
}
|
||||
|
||||
int thread_detach_cb(wsrep_thread_t* thread)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return thread_service_impl->detach(
|
||||
reinterpret_cast<wsrep::thread_service::thread*>(thread));
|
||||
}
|
||||
|
||||
int thread_equal_cb(wsrep_thread_t* thread_1, wsrep_thread_t* thread_2)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return thread_service_impl->equal(
|
||||
reinterpret_cast<wsrep::thread_service::thread*>(thread_1),
|
||||
reinterpret_cast<wsrep::thread_service::thread*>(thread_2));
|
||||
}
|
||||
|
||||
__attribute__((noreturn))
|
||||
void thread_exit_cb(wsrep_thread_t* thread, void* retval)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
thread_service_impl->exit(
|
||||
reinterpret_cast<wsrep::thread_service::thread*>(thread), retval);
|
||||
throw; // Implementation broke the contract and returned.
|
||||
}
|
||||
|
||||
int thread_join_cb(wsrep_thread_t* thread, void** retval)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return thread_service_impl->join(
|
||||
reinterpret_cast<wsrep::thread_service::thread*>(thread), retval);
|
||||
}
|
||||
|
||||
wsrep_thread_t* thread_self_cb(void)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return reinterpret_cast<wsrep_thread_t*>(thread_service_impl->self());
|
||||
}
|
||||
|
||||
int thread_setschedparam_cb(wsrep_thread_t* thread, int policy,
|
||||
const struct sched_param* sp)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return thread_service_impl->setschedparam(
|
||||
reinterpret_cast<wsrep::thread_service::thread*>(thread),
|
||||
policy, sp);
|
||||
}
|
||||
|
||||
int thread_getschedparam_cb(wsrep_thread_t* thread, int* policy,
|
||||
struct sched_param* sp)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return thread_service_impl->getschedparam(
|
||||
reinterpret_cast<wsrep::thread_service::thread*>(thread), policy,
|
||||
sp);
|
||||
}
|
||||
|
||||
const wsrep_mutex_key_t* mutex_key_create_cb(const char* name)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return reinterpret_cast<const wsrep_mutex_key_t*>(
|
||||
thread_service_impl->create_mutex_key(name));
|
||||
}
|
||||
|
||||
wsrep_mutex_t* mutex_init_cb(const wsrep_mutex_key_t* key, void* memblock,
|
||||
size_t memblock_size)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return reinterpret_cast<wsrep_mutex_t*>(
|
||||
thread_service_impl->init_mutex(
|
||||
reinterpret_cast<const wsrep::thread_service::mutex_key*>(key),
|
||||
memblock, memblock_size));
|
||||
}
|
||||
|
||||
int mutex_destroy_cb(wsrep_mutex_t* mutex)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return thread_service_impl->destroy(
|
||||
reinterpret_cast<wsrep::thread_service::mutex*>(mutex));
|
||||
}
|
||||
int mutex_lock_cb(wsrep_mutex_t* mutex)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return thread_service_impl->lock(
|
||||
reinterpret_cast<wsrep::thread_service::mutex*>(mutex));
|
||||
}
|
||||
|
||||
int mutex_trylock_cb(wsrep_mutex_t* mutex)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return thread_service_impl->trylock(
|
||||
reinterpret_cast<wsrep::thread_service::mutex*>(mutex));
|
||||
}
|
||||
|
||||
int mutex_unlock_cb(wsrep_mutex_t* mutex)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return thread_service_impl->unlock(
|
||||
reinterpret_cast<wsrep::thread_service::mutex*>(mutex));
|
||||
}
|
||||
|
||||
const wsrep_cond_key_t* cond_key_create_cb(const char* name)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return reinterpret_cast<const wsrep_cond_key_t*>(
|
||||
thread_service_impl->create_cond_key(name));
|
||||
}
|
||||
|
||||
wsrep_cond_t* cond_init_cb(const wsrep_cond_key_t* key, void* memblock,
|
||||
size_t memblock_size)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return reinterpret_cast<wsrep_cond_t*>(thread_service_impl->init_cond(
|
||||
reinterpret_cast<const wsrep::thread_service::cond_key*>(key),
|
||||
memblock, memblock_size));
|
||||
}
|
||||
|
||||
int cond_destroy_cb(wsrep_cond_t* cond)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return thread_service_impl->destroy(
|
||||
reinterpret_cast<wsrep::thread_service::cond*>(cond));
|
||||
}
|
||||
|
||||
int cond_wait_cb(wsrep_cond_t* cond, wsrep_mutex_t* mutex)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return thread_service_impl->wait(
|
||||
reinterpret_cast<wsrep::thread_service::cond*>(cond),
|
||||
reinterpret_cast<wsrep::thread_service::mutex*>(mutex));
|
||||
}
|
||||
|
||||
int cond_timedwait_cb(wsrep_cond_t* cond, wsrep_mutex_t* mutex,
|
||||
const struct timespec* ts)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return thread_service_impl->timedwait(
|
||||
reinterpret_cast<wsrep::thread_service::cond*>(cond),
|
||||
reinterpret_cast<wsrep::thread_service::mutex*>(mutex), ts);
|
||||
}
|
||||
|
||||
int cond_signal_cb(wsrep_cond_t* cond)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return thread_service_impl->signal(
|
||||
reinterpret_cast<wsrep::thread_service::cond*>(cond));
|
||||
}
|
||||
|
||||
int cond_broadcast_cb(wsrep_cond_t* cond)
|
||||
{
|
||||
assert(thread_service_impl);
|
||||
return thread_service_impl->broadcast(
|
||||
reinterpret_cast<wsrep::thread_service::cond*>(cond));
|
||||
}
|
||||
|
||||
static wsrep_thread_service_v1_t thread_service_callbacks
|
||||
= { thread_key_create_cb,
|
||||
thread_create_cb,
|
||||
thread_detach_cb,
|
||||
thread_equal_cb,
|
||||
thread_exit_cb,
|
||||
thread_join_cb,
|
||||
thread_self_cb,
|
||||
thread_setschedparam_cb,
|
||||
thread_getschedparam_cb,
|
||||
mutex_key_create_cb,
|
||||
mutex_init_cb,
|
||||
mutex_destroy_cb,
|
||||
mutex_lock_cb,
|
||||
mutex_trylock_cb,
|
||||
mutex_unlock_cb,
|
||||
cond_key_create_cb,
|
||||
cond_init_cb,
|
||||
cond_destroy_cb,
|
||||
cond_wait_cb,
|
||||
cond_timedwait_cb,
|
||||
cond_signal_cb,
|
||||
cond_broadcast_cb };
|
||||
}
|
||||
|
||||
int wsrep::thread_service_v1_probe(void* dlh)
|
||||
{
|
||||
typedef int (*init_fn)(wsrep_thread_service_v1_t*);
|
||||
union {
|
||||
init_fn dlfun;
|
||||
void* obj;
|
||||
} alias;
|
||||
// Clear previous errors
|
||||
(void)dlerror();
|
||||
alias.obj = dlsym(dlh, WSREP_THREAD_SERVICE_INIT_FUNC);
|
||||
if (alias.obj)
|
||||
{
|
||||
wsrep::log_info()
|
||||
<< "Found support for thread service v1 from provider";
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
wsrep::log_info() << "Thread service v1 not found from provider: "
|
||||
<< dlerror();
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int wsrep::thread_service_v1_init(void* dlh,
|
||||
wsrep::thread_service* thread_service)
|
||||
{
|
||||
if (not (dlh && thread_service)) return EINVAL;
|
||||
|
||||
typedef int (*init_fn)(wsrep_thread_service_v1_t*);
|
||||
union {
|
||||
init_fn dlfun;
|
||||
void* obj;
|
||||
} alias;
|
||||
alias.obj = dlsym(dlh, WSREP_THREAD_SERVICE_INIT_FUNC);
|
||||
if (alias.obj)
|
||||
{
|
||||
wsrep::log_info() << "Initializing process instrumentation";
|
||||
wsrep_thread_service_v1::thread_service_impl = thread_service;
|
||||
return (*alias.dlfun)(&wsrep_thread_service_v1::thread_service_callbacks);
|
||||
}
|
||||
else
|
||||
{
|
||||
wsrep::log_info()
|
||||
<< "Provider does not support process instrumentation";
|
||||
return ENOTSUP;
|
||||
}
|
||||
}
|
47
src/thread_service_v1.hpp
Normal file
47
src/thread_service_v1.hpp
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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_THREAD_SERVICE_V1_HPP
|
||||
#define WSREP_THREAD_SERVICE_V1_HPP
|
||||
|
||||
namespace wsrep
|
||||
{
|
||||
class thread_service;
|
||||
/**
|
||||
* Probe thread_service_v1 support in loaded library.
|
||||
*
|
||||
* @param dlh Handle returned by dlopen().
|
||||
*
|
||||
* @return Zero on success, non-zero system error code on failure.
|
||||
*/
|
||||
int thread_service_v1_probe(void *dlh);
|
||||
|
||||
/**
|
||||
* Initialize the thread service.
|
||||
*
|
||||
* @param dlh Handle returned by dlopen().
|
||||
* @params thread_service Pointer to wsrep::thread_service implementation.
|
||||
*
|
||||
* @return Zero on success, non-zero system error code on failure.
|
||||
*/
|
||||
int thread_service_v1_init(void* dlh,
|
||||
wsrep::thread_service* thread_service);
|
||||
}
|
||||
|
||||
#endif // WSREP_THREAD_SERVICE_V1_HPP
|
74
src/uuid.cpp
Normal file
74
src/uuid.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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/>.
|
||||
*/
|
||||
|
||||
#include "uuid.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cctype>
|
||||
|
||||
int wsrep::uuid_scan (const char* str, size_t str_len, wsrep::uuid_t* uuid)
|
||||
{
|
||||
unsigned int uuid_len = 0;
|
||||
unsigned int uuid_offt = 0;
|
||||
|
||||
while (uuid_len + 1 < str_len) {
|
||||
/* We are skipping potential '-' after uuid_offt == 4, 6, 8, 10
|
||||
* which means
|
||||
* (uuid_offt >> 1) == 2, 3, 4, 5,
|
||||
* which in turn means
|
||||
* (uuid_offt >> 1) - 2 <= 3
|
||||
* since it is always >= 0, because uuid_offt is unsigned */
|
||||
if (((uuid_offt >> 1) - 2) <= 3 && str[uuid_len] == '-') {
|
||||
// skip dashes after 4th, 6th, 8th and 10th positions
|
||||
uuid_len += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isxdigit(str[uuid_len]) && isxdigit(str[uuid_len + 1])) {
|
||||
// got hex digit, scan another byte to uuid, increment uuid_offt
|
||||
sscanf (str + uuid_len, "%2hhx", uuid->data + uuid_offt);
|
||||
uuid_len += 2;
|
||||
uuid_offt += 1;
|
||||
if (sizeof (uuid->data) == uuid_offt)
|
||||
return static_cast<int>(uuid_len);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*uuid = wsrep::uuid_initializer;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int wsrep::uuid_print (const wsrep::uuid_t* uuid, char* str, size_t str_len)
|
||||
{
|
||||
if (str_len > WSREP_LIB_UUID_STR_LEN) {
|
||||
const unsigned char* u = uuid->data;
|
||||
return snprintf(str, str_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
|
||||
"%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
u[ 0], u[ 1], u[ 2], u[ 3], u[ 4], u[ 5], u[ 6], u[ 7],
|
||||
u[ 8], u[ 9], u[10], u[11], u[12], u[13], u[14], u[15]);
|
||||
}
|
||||
else {
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
}
|
79
src/uuid.hpp
Normal file
79
src/uuid.hpp
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 uuid.hpp
|
||||
*
|
||||
* Helper methods to parse and print UUIDs, intended to use
|
||||
* internally in wsrep-lib.
|
||||
*
|
||||
* The implementation is copied from wsrep-API v26.
|
||||
*/
|
||||
|
||||
#ifndef WSREP_UUID_HPP
|
||||
#define WSREP_UUID_HPP
|
||||
|
||||
#include "wsrep/compiler.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
/**
|
||||
* Length of UUID string representation, not including terminating '\0'.
|
||||
*/
|
||||
#define WSREP_LIB_UUID_STR_LEN 36
|
||||
|
||||
namespace wsrep
|
||||
{
|
||||
/**
|
||||
* UUID type.
|
||||
*/
|
||||
typedef union uuid_
|
||||
{
|
||||
unsigned char data[16];
|
||||
size_t alignment;
|
||||
} uuid_t;
|
||||
|
||||
static const wsrep::uuid_t uuid_initializer = {{0, }};
|
||||
|
||||
/**
|
||||
* Read UUID from string.
|
||||
*
|
||||
* @param str String to read from
|
||||
* @param str_len Length of string
|
||||
* @param[out] UUID to read to
|
||||
*
|
||||
* @return Number of bytes read or negative error code in case
|
||||
* of error.
|
||||
*/
|
||||
int uuid_scan(const char* str, size_t str_len, wsrep::uuid_t* uuid);
|
||||
|
||||
/**
|
||||
* Write UUID to string. The caller must allocate at least
|
||||
* WSREP_LIB_UUID_STR_LEN + 1 space for the output str parameter.
|
||||
*
|
||||
* @param uuid UUID to print
|
||||
* @param str[out] Output buffer
|
||||
* @param str_len Size of output buffer
|
||||
*
|
||||
* @return Number of chars printerd, negative error code in case of
|
||||
* error.
|
||||
*/
|
||||
int uuid_print(const wsrep::uuid_t* uuid, char* str, size_t str_len);
|
||||
}
|
||||
|
||||
#endif // WSREP_UUID_HPP
|
@ -25,9 +25,13 @@
|
||||
#include "wsrep/view.hpp"
|
||||
#include "wsrep/exception.hpp"
|
||||
#include "wsrep/logger.hpp"
|
||||
#include "wsrep/thread_service.hpp"
|
||||
|
||||
#include <wsrep_api.h>
|
||||
#include "thread_service_v1.hpp"
|
||||
#include "v26/wsrep_api.h"
|
||||
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
|
||||
@ -562,12 +566,39 @@ namespace
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int init_thread_service(void* dlh,
|
||||
wsrep::thread_service* thread_service)
|
||||
{
|
||||
assert(thread_service);
|
||||
if (wsrep::thread_service_v1_probe(dlh))
|
||||
{
|
||||
// No support in library.
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (thread_service->before_init())
|
||||
{
|
||||
wsrep::log_error() << "Thread service before init failed";
|
||||
return 1;
|
||||
}
|
||||
wsrep::thread_service_v1_init(dlh, thread_service);
|
||||
if (thread_service->after_init())
|
||||
{
|
||||
wsrep::log_error() << "Thread service after init failed";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
wsrep::wsrep_provider_v26::wsrep_provider_v26(
|
||||
wsrep::server_state& server_state,
|
||||
const std::string& provider_options,
|
||||
const std::string& provider_spec)
|
||||
const std::string& provider_spec,
|
||||
const wsrep::provider::services& services)
|
||||
: provider(server_state)
|
||||
, wsrep_()
|
||||
{
|
||||
@ -603,6 +634,13 @@ wsrep::wsrep_provider_v26::wsrep_provider_v26(
|
||||
{
|
||||
throw wsrep::runtime_error("Failed to load wsrep library");
|
||||
}
|
||||
|
||||
if (services.thread_service &&
|
||||
init_thread_service(wsrep_->dlh, services.thread_service))
|
||||
{
|
||||
throw wsrep::runtime_error("Failed to initialize thread service");
|
||||
}
|
||||
|
||||
if (wsrep_->init(wsrep_, &init_args) != WSREP_OK)
|
||||
{
|
||||
throw wsrep::runtime_error("Failed to initialize wsrep provider");
|
||||
|
@ -26,12 +26,14 @@ struct wsrep_st;
|
||||
|
||||
namespace wsrep
|
||||
{
|
||||
class thread_service;
|
||||
class wsrep_provider_v26 : public wsrep::provider
|
||||
{
|
||||
public:
|
||||
|
||||
wsrep_provider_v26(wsrep::server_state&, const std::string&,
|
||||
const std::string&);
|
||||
const std::string&,
|
||||
const wsrep::provider::services& services);
|
||||
~wsrep_provider_v26();
|
||||
enum wsrep::provider::status
|
||||
connect(const std::string&, const std::string&, const std::string&,
|
||||
|
Reference in New Issue
Block a user