Format source code using clformat (#233)

Signed-off-by: Tao He <sighingnow@gmail.com>
This commit is contained in:
Tao He 2023-07-01 20:49:16 +08:00 committed by GitHub
parent fe9f17e61e
commit 1d5128a7e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 4914 additions and 4914 deletions

15
.clang-format Normal file
View File

@ -0,0 +1,15 @@
BasedOnStyle: Google
DerivePointerAlignment: false
PointerAlignment: Left
Cpp11BracedListStyle: true
IndentCaseLabels: false
AllowShortBlocksOnASingleLine: true
AllowShortLoopsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
Standard: 'Cpp11'
SpaceAfterCStyleCast: true
AlignAfterOpenBracket: Align
SortIncludes: true
IncludeBlocks: Preserve
ForEachMacros:
- BOOST_FOREACH

View File

@ -82,6 +82,10 @@ jobs:
wget https://github.com/Kitware/CMake/releases/download/v3.19.3/cmake-3.19.3-Linux-x86_64.sh wget https://github.com/Kitware/CMake/releases/download/v3.19.3/cmake-3.19.3-Linux-x86_64.sh
sudo bash cmake-3.19.3-Linux-x86_64.sh --prefix /usr --skip-license sudo bash cmake-3.19.3-Linux-x86_64.sh --prefix /usr --skip-license
# install clang-format
sudo curl -L https://github.com/muttleyxd/clang-tools-static-binaries/releases/download/master-1d7ec53d/clang-format-11_linux-amd64 --output /usr/bin/clang-format
sudo chmod +x /usr/bin/clang-format
- name: Install grpc v1.27.x for Ubuntu 18.04 - name: Install grpc v1.27.x for Ubuntu 18.04
if: matrix.os == 'ubuntu-18.04' if: matrix.os == 'ubuntu-18.04'
run: | run: |
@ -170,7 +174,7 @@ jobs:
if: false if: false
uses: mxschmitt/action-tmate@v3 uses: mxschmitt/action-tmate@v3
- name: Build - name: CMake
run: | run: |
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib:/usr/local/lib/x86_64-linux-gnu export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib:/usr/local/lib/x86_64-linux-gnu
@ -182,6 +186,42 @@ jobs:
-DBUILD_ETCD_TESTS=ON \ -DBUILD_ETCD_TESTS=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Format
if: runner.os == 'Linux'
run: |
cd build
function prepend() { while read line; do echo "${1}${line}"; done; }
make etcd_cpp_apiv3_clformat
GIT_DIFF=$(git diff --ignore-submodules)
if [[ -n $GIT_DIFF ]]; then
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
echo "| clang-format failures found!"
echo "|"
echo "$GIT_DIFF" | prepend "| "
echo "|"
echo "| Run: "
echo "|"
echo "| make etcd_cpp_apiv3_clformat"
echo "|"
echo "| to fix this error."
echo "|"
echo "| Ensure you are working with clang-format-11, which can be obtained from"
echo "|"
echo "| https://github.com/muttleyxd/clang-tools-static-binaries/releases "
echo "|"
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
exit -1
fi
- name: Build
run: |
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib:/usr/local/lib/x86_64-linux-gnu
cd build
make -j`nproc` make -j`nproc`
sudo make install sudo make install

View File

@ -223,6 +223,17 @@ install(EXPORT etcd-targets
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/etcd-cpp-api DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/etcd-cpp-api
) )
file(GLOB_RECURSE FILES_NEED_FORMAT
"etcd/*.hpp"
"src/*.cpp"
"tst/*.cpp"
)
add_custom_target(etcd_cpp_apiv3_clformat
COMMAND clang-format --style=file -i ${FILES_NEED_FORMAT}
COMMENT "Running clang-format, using clang-format-11 from https://github.com/muttleyxd/clang-tools-static-binaries/releases"
VERBATIM)
# deb/rpc packaging for Linux # deb/rpc packaging for Linux
set(CPACK_PACKAGE_NAME ${CMAKE_PROJECT_NAME}) set(CPACK_PACKAGE_NAME ${CMAKE_PROJECT_NAME})

File diff suppressed because it is too large Load Diff

View File

@ -10,119 +10,114 @@
#include <string> #include <string>
#include <thread> #include <thread>
#include "etcd/SyncClient.hpp"
#include "etcd/Response.hpp" #include "etcd/Response.hpp"
#include "etcd/SyncClient.hpp"
namespace etcd namespace etcd {
{ // forward declaration to avoid header/library dependency
// forward declaration to avoid header/library dependency class Client;
class Client;
/**
* If ID is set to 0, the library will choose an ID, and can be accessed from
* ".Lease()".
*/
class KeepAlive {
public:
KeepAlive(Client const& client, int ttl, int64_t lease_id = 0);
KeepAlive(SyncClient const& client, int ttl, int64_t lease_id = 0);
KeepAlive(std::string const& address, int ttl, int64_t lease_id = 0);
KeepAlive(std::string const& address, std::string const& username,
std::string const& password, int ttl, int64_t lease_id = 0,
int const auth_token_ttl = 300);
KeepAlive(Client const& client,
std::function<void(std::exception_ptr)> const& handler, int ttl,
int64_t lease_id = 0);
KeepAlive(SyncClient const& client,
std::function<void(std::exception_ptr)> const& handler, int ttl,
int64_t lease_id = 0);
KeepAlive(std::string const& address,
std::function<void(std::exception_ptr)> const& handler, int ttl,
int64_t lease_id = 0);
KeepAlive(std::string const& address, std::string const& username,
std::string const& password,
std::function<void(std::exception_ptr)> const& handler, int ttl,
int64_t lease_id = 0, int const auth_token_ttl = 300);
KeepAlive(std::string const& address, std::string const& ca,
std::string const& cert, std::string const& privkey,
std::function<void(std::exception_ptr)> const& handler, int ttl,
int64_t lease_id = 0, std::string const& target_name_override = "");
KeepAlive(KeepAlive const&) = delete;
KeepAlive(KeepAlive&&) = delete;
int64_t Lease() const { return lease_id; }
/** /**
* If ID is set to 0, the library will choose an ID, and can be accessed from ".Lease()". * Stop the keep alive action.
*/ */
class KeepAlive void Cancel();
{
public:
KeepAlive(Client const &client,
int ttl, int64_t lease_id = 0);
KeepAlive(SyncClient const &client,
int ttl, int64_t lease_id = 0);
KeepAlive(std::string const & address,
int ttl, int64_t lease_id = 0);
KeepAlive(std::string const & address,
std::string const & username, std::string const & password,
int ttl, int64_t lease_id = 0,
int const auth_token_ttl = 300);
KeepAlive(Client const &client, /**
std::function<void (std::exception_ptr)> const &handler, * Check if the keep alive is still valid (invalid when there's an async
int ttl, int64_t lease_id = 0); * exception).
KeepAlive(SyncClient const &client, *
std::function<void (std::exception_ptr)> const &handler, * Nothing will happen if valid and an exception will be rethrowed if invalid.
int ttl, int64_t lease_id = 0); */
KeepAlive(std::string const & address, void Check();
std::function<void (std::exception_ptr)> const &handler,
int ttl, int64_t lease_id = 0);
KeepAlive(std::string const & address,
std::string const & username, std::string const & password,
std::function<void (std::exception_ptr)> const &handler,
int ttl, int64_t lease_id = 0,
int const auth_token_ttl = 300);
KeepAlive(std::string const & address,
std::string const & ca,
std::string const & cert,
std::string const & privkey,
std::function<void (std::exception_ptr)> const &handler,
int ttl, int64_t lease_id = 0,
std::string const & target_name_override = "");
KeepAlive(KeepAlive const &) = delete; /**
KeepAlive(KeepAlive &&) = delete; * Set a timeout value for grpc operations.
*/
template <typename Rep = std::micro>
void set_grpc_timeout(std::chrono::duration<Rep> const& timeout) {
this->grpc_timeout =
std::chrono::duration_cast<std::chrono::milliseconds>(timeout);
}
int64_t Lease() const { return lease_id; } /**
* Get the current timeout value for grpc operations.
*/
std::chrono::microseconds get_grpc_timeout() const {
return this->grpc_timeout;
}
/** ~KeepAlive();
* Stop the keep alive action.
*/
void Cancel();
/** protected:
* Check if the keep alive is still valid (invalid when there's an async exception). // automatically refresh loop
* void refresh();
* Nothing will happen if valid and an exception will be rethrowed if invalid. // refresh once immediately
*/ void refresh_once();
void Check();
/** struct EtcdServerStubs;
* Set a timeout value for grpc operations. struct EtcdServerStubsDeleter {
*/ void operator()(EtcdServerStubs* stubs);
template <typename Rep = std::micro>
void set_grpc_timeout(std::chrono::duration<Rep> const &timeout) {
this->grpc_timeout = std::chrono::duration_cast<std::chrono::milliseconds>(timeout);
}
/**
* Get the current timeout value for grpc operations.
*/
std::chrono::microseconds get_grpc_timeout() const {
return this->grpc_timeout;
}
~KeepAlive();
protected:
// automatically refresh loop
void refresh();
// refresh once immediately
void refresh_once();
struct EtcdServerStubs;
struct EtcdServerStubsDeleter {
void operator()(EtcdServerStubs *stubs);
};
std::unique_ptr<EtcdServerStubs, EtcdServerStubsDeleter> stubs;
private:
// error handling
std::exception_ptr eptr_;
std::function<void (std::exception_ptr)> handler_;
// Don't use `pplx::task` to avoid sharing thread pool with other actions on the client
// to avoid any potential blocking, which may block the keepalive loop and evict the lease.
std::thread refresh_task_;
int ttl;
int64_t lease_id;
// protect the initializing status of `timer`.
std::mutex mutex_for_refresh_;
std::condition_variable cv_for_refresh_;
std::atomic_bool continue_next;
// grpc timeout in `refresh()`
mutable std::chrono::microseconds grpc_timeout = std::chrono::microseconds::zero();
}; };
} std::unique_ptr<EtcdServerStubs, EtcdServerStubsDeleter> stubs;
private:
// error handling
std::exception_ptr eptr_;
std::function<void(std::exception_ptr)> handler_;
// Don't use `pplx::task` to avoid sharing thread pool with other actions on
// the client to avoid any potential blocking, which may block the keepalive
// loop and evict the lease.
std::thread refresh_task_;
int ttl;
int64_t lease_id;
// protect the initializing status of `timer`.
std::mutex mutex_for_refresh_;
std::condition_variable cv_for_refresh_;
std::atomic_bool continue_next;
// grpc timeout in `refresh()`
mutable std::chrono::microseconds grpc_timeout =
std::chrono::microseconds::zero();
};
} // namespace etcd
#endif #endif

View File

@ -2,8 +2,8 @@
#define __ETCD_RESPONSE_HPP__ #define __ETCD_RESPONSE_HPP__
#include <chrono> #include <chrono>
#include <iostream>
#include <functional> #include <functional>
#include <iostream>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
@ -11,239 +11,243 @@
#include "etcd/Value.hpp" #include "etcd/Value.hpp"
namespace etcdv3 { namespace etcdv3 {
class AsyncWatchAction; class AsyncWatchAction;
class AsyncLeaseKeepAliveAction; class AsyncLeaseKeepAliveAction;
class AsyncObserveAction; class AsyncObserveAction;
class V3Response; class V3Response;
} // namespace etcdv3
namespace etcd {
typedef std::vector<std::string> Keys;
namespace detail {
// Compute the duration between given start time point and now
inline const std::chrono::microseconds duration_till_now(
std::chrono::high_resolution_clock::time_point const& start_timepoint) {
return std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now() - start_timepoint);
} }
} // namespace detail
namespace etcd // forward declaration
{ class KeepAlive;
typedef std::vector<std::string> Keys; class Watcher;
namespace detail { /**
// Compute the duration between given start time point and now * The Reponse object received for the requests of etcd::Client
inline const std::chrono::microseconds duration_till_now( */
std::chrono::high_resolution_clock::time_point const & start_timepoint) { class Response {
return std::chrono::duration_cast<std::chrono::microseconds>( public:
std::chrono::high_resolution_clock::now() - start_timepoint); template <typename T>
} static etcd::Response create(std::unique_ptr<T> call) {
call->waitForResponse();
auto v3resp = call->ParseResponse();
return etcd::Response(v3resp,
detail::duration_till_now(call->startTimepoint()));
} }
// forward declaration template <typename T>
class KeepAlive; static etcd::Response create(std::shared_ptr<T> call) {
class Watcher; call->waitForResponse();
auto v3resp = call->ParseResponse();
return etcd::Response(v3resp,
detail::duration_till_now(call->startTimepoint()));
}
template <typename T>
static etcd::Response create(std::unique_ptr<T> call,
std::function<void(Response)> callback) {
call->waitForResponse(callback);
auto v3resp = call->ParseResponse();
return etcd::Response(v3resp,
detail::duration_till_now(call->startTimepoint()));
}
template <typename T>
static etcd::Response create(std::function<std::unique_ptr<T>()> fn) {
auto call = fn();
call->waitForResponse();
auto v3resp = call->ParseResponse();
return etcd::Response(v3resp,
detail::duration_till_now(call->startTimepoint()));
}
template <typename T>
static etcd::Response create(std::function<std::shared_ptr<T>()> fn) {
auto call = fn();
call->waitForResponse();
auto v3resp = call->ParseResponse();
return etcd::Response(v3resp,
detail::duration_till_now(call->startTimepoint()));
}
Response();
Response(const Response&);
/** /**
* The Reponse object received for the requests of etcd::Client * Returns the error code received from the etcd server. In case of success
* the error code is 0.
*/ */
class Response int error_code() const;
{
public:
template <typename T> /**
static etcd::Response create(std::unique_ptr<T> call) * Returns the string representation of the error code
{ */
call->waitForResponse(); std::string const& error_message() const;
auto v3resp = call->ParseResponse();
return etcd::Response(v3resp, detail::duration_till_now(call->startTimepoint()));
}
template <typename T> /**
static etcd::Response create(std::shared_ptr<T> call) * Returns true if this is a successful response
{ */
call->waitForResponse(); bool is_ok() const;
auto v3resp = call->ParseResponse();
return etcd::Response(v3resp, detail::duration_till_now(call->startTimepoint()));
}
template <typename T> /**
static etcd::Response create(std::unique_ptr<T> call, * Returns true if the error is a network unavailable error.
std::function<void(Response)> callback) */
{ bool is_network_unavailable() const;
call->waitForResponse(callback);
auto v3resp = call->ParseResponse();
return etcd::Response(v3resp, detail::duration_till_now(call->startTimepoint()));
}
template <typename T> /**
static etcd::Response create(std::function<std::unique_ptr<T>()> fn) * Check whether the response contains a grpc TIMEOUT error.
{ */
auto call = fn(); bool is_grpc_timeout() const;
call->waitForResponse(); /**
auto v3resp = call->ParseResponse(); * Returns the action type of the operation that this response belongs to.
return etcd::Response(v3resp, detail::duration_till_now(call->startTimepoint())); */
} std::string const& action() const;
template <typename T> /**
static etcd::Response create(std::function<std::shared_ptr<T>()> fn) * Returns the current index value of etcd
{ */
auto call = fn(); int64_t index() const;
call->waitForResponse(); /**
auto v3resp = call->ParseResponse(); * Returns the value object of the response to a get/set/modify operation.
return etcd::Response(v3resp, detail::duration_till_now(call->startTimepoint())); */
} Value const& value() const;
Response(); /**
* Returns the previous value object of the response to a set/modify/rm
* operation.
*/
Value const& prev_value() const;
Response(const Response &); /**
* Returns the index-th value of the response to an 'ls' operation. Equivalent
* to values()[index]
*/
Value const& value(int index) const;
/** /**
* Returns the error code received from the etcd server. In case of success the error code is 0. * Returns the vector of values in a directory in response to an 'ls'
*/ * operation.
int error_code() const; */
Values const& values() const;
/** /**
* Returns the string representation of the error code * Returns the vector of keys in a directory in response to an 'ls' operation.
*/ */
std::string const & error_message() const; Keys const& keys() const;
/** /**
* Returns true if this is a successful response * Returns the index-th key in a directory listing. Same as keys()[index]
*/ */
bool is_ok() const; std::string const& key(int index) const;
/** /**
* Returns true if the error is a network unavailable error. * Returns the compact_revision if the response is a watch-cancelled revision.
*/ * `-1` means uninitialized (the response is not watch-cancelled)
bool is_network_unavailable() const; */
int64_t compact_revision() const;
/** /**
* Check whether the response contains a grpc TIMEOUT error. * Returns the watcher id for client.watch() requests. `-1` means
*/ * uninitialized (the response is not for watch).
bool is_grpc_timeout() const; */
int64_t watch_id() const;
/** /**
* Returns the action type of the operation that this response belongs to. * Returns the lock key.
*/ */
std::string const & action() const; std::string const& lock_key() const;
/** /**
* Returns the current index value of etcd * Return the "name" in response.
*/ */
int64_t index() const; std::string const& name() const;
/** /**
* Returns the value object of the response to a get/set/modify operation. * Returns the watched events.
*/ */
Value const & value() const; std::vector<Event> const& events() const;
/** /**
* Returns the previous value object of the response to a set/modify/rm operation. * Returns the duration of request execution in microseconds.
*/ */
Value const & prev_value() const; std::chrono::microseconds const& duration() const;
/** /**
* Returns the index-th value of the response to an 'ls' operation. Equivalent to values()[index] * Returns the current cluster id.
*/ */
Value const & value(int index) const; uint64_t cluster_id() const;
/** /**
* Returns the vector of values in a directory in response to an 'ls' operation. * Returns the current member id.
*/ */
Values const & values() const; uint64_t member_id() const;
/** /**
* Returns the vector of keys in a directory in response to an 'ls' operation. * Returns ther current raft term.
*/ */
Keys const & keys() const; uint64_t raft_term() const;
/** /**
* Returns the index-th key in a directory listing. Same as keys()[index] * Returns ther current raft term.
*/ */
std::string const & key(int index) const; std::vector<int64_t> const& leases() const;
/** protected:
* Returns the compact_revision if the response is a watch-cancelled revision. Response(const etcdv3::V3Response& response,
* `-1` means uninitialized (the response is not watch-cancelled) std::chrono::microseconds const& duration);
*/ Response(int error_code, std::string const& error_message);
int64_t compact_revision() const; Response(int error_code, char const* error_message);
/** int _error_code;
* Returns the watcher id for client.watch() requests. `-1` means uninitialized (the response is not for watch). std::string _error_message;
*/ int64_t _index;
int64_t watch_id() const; std::string _action;
Value _value;
Value _prev_value;
Values _values;
Keys _keys;
int64_t _compact_revision = -1; // for watch
int64_t _watch_id = -1; // for watch
std::string _lock_key; // for lock
std::string _name; // for campaign (in v3election)
std::vector<Event> _events; // for watch
// execute duration (in microseconds), during the action created and response
// parsed
std::chrono::microseconds _duration;
/** // cluster metadata
* Returns the lock key. uint64_t _cluster_id;
*/ uint64_t _member_id;
std::string const & lock_key() const; uint64_t _raft_term;
/** // for lease list
* Return the "name" in response. std::vector<int64_t> _leases;
*/
std::string const & name() const;
/** friend class Client;
* Returns the watched events. friend class SyncClient;
*/ friend class KeepAlive;
std::vector<Event> const & events() const; friend class Watcher;
/** friend class etcdv3::AsyncWatchAction;
* Returns the duration of request execution in microseconds. friend class etcdv3::AsyncLeaseKeepAliveAction;
*/ friend class etcdv3::AsyncObserveAction;
std::chrono::microseconds const & duration() const; };
} // namespace etcd
/**
* Returns the current cluster id.
*/
uint64_t cluster_id() const;
/**
* Returns the current member id.
*/
uint64_t member_id() const;
/**
* Returns ther current raft term.
*/
uint64_t raft_term() const;
/**
* Returns ther current raft term.
*/
std::vector<int64_t> const & leases() const;
protected:
Response(const etcdv3::V3Response& response, std::chrono::microseconds const& duration);
Response(int error_code, std::string const& error_message);
Response(int error_code, char const * error_message);
int _error_code;
std::string _error_message;
int64_t _index;
std::string _action;
Value _value;
Value _prev_value;
Values _values;
Keys _keys;
int64_t _compact_revision = -1; // for watch
int64_t _watch_id = -1; // for watch
std::string _lock_key; // for lock
std::string _name; // for campaign (in v3election)
std::vector<Event> _events; // for watch
// execute duration (in microseconds), during the action created and response parsed
std::chrono::microseconds _duration;
// cluster metadata
uint64_t _cluster_id;
uint64_t _member_id;
uint64_t _raft_term;
// for lease list
std::vector<int64_t> _leases;
friend class Client;
friend class SyncClient;
friend class KeepAlive;
friend class Watcher;
friend class etcdv3::AsyncWatchAction;
friend class etcdv3::AsyncLeaseKeepAliveAction;
friend class etcdv3::AsyncObserveAction;
};
}
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -5,126 +5,124 @@
#include <vector> #include <vector>
namespace etcdv3 { namespace etcdv3 {
class KeyValue; class KeyValue;
} }
namespace mvccpb { namespace mvccpb {
class KeyValue; class KeyValue;
class Event; class Event;
} } // namespace mvccpb
namespace electionpb { namespace electionpb {
class LeaderKey; class LeaderKey;
} }
namespace etcd namespace etcd {
{ class Value;
class Value; class Event;
class Event; class Response;
class Response; class Client;
class Client; class SyncClient;
class SyncClient;
/**
* Represents a value object received from the etcd server
*/
class Value {
public:
/**
* Returns true if this value represents a directory on the server. If true
* the as_string() method is meaningless.
*/
bool is_dir() const;
/** /**
* Represents a value object received from the etcd server * Returns the key of this value as an "absolute path".
*/ */
class Value std::string const& key() const;
{
public:
/**
* Returns true if this value represents a directory on the server. If true the as_string()
* method is meaningless.
*/
bool is_dir() const;
/** /**
* Returns the key of this value as an "absolute path". * Returns the string representation of the value
*/ */
std::string const & key() const; std::string const& as_string() const;
/** /**
* Returns the string representation of the value * Returns the creation index of this value.
*/ */
std::string const & as_string() const; int64_t created_index() const;
/** /**
* Returns the creation index of this value. * Returns the last modification's index of this value.
*/ */
int64_t created_index() const; int64_t modified_index() const;
/** /**
* Returns the last modification's index of this value. * Returns the version of this value.
*/ */
int64_t modified_index() const; int64_t version() const;
/** /**
* Returns the version of this value. * Returns the ttl of this value or 0 if ttl is not set
*/ */
int64_t version() const; int ttl() const;
/** int64_t lease() const;
* Returns the ttl of this value or 0 if ttl is not set
*/
int ttl() const;
int64_t lease() const;
protected: protected:
friend class Client; friend class Client;
friend class SyncClient; friend class SyncClient;
friend class Response; friend class Response;
friend class BaseResponse; //deliberately done since Value class will be removed during full V3 friend class BaseResponse; // deliberately done since Value class will be
friend class DeleteRpcResponse; // removed during full V3
friend class AsyncDeleteResponse; friend class DeleteRpcResponse;
friend class AsyncDeleteResponse;
friend class Event; friend class Event;
Value(); Value();
Value(etcdv3::KeyValue const & kvs); Value(etcdv3::KeyValue const& kvs);
Value(mvccpb::KeyValue const & kvs); Value(mvccpb::KeyValue const& kvs);
std::string _key; std::string _key;
bool dir; bool dir;
std::string value; std::string value;
int64_t created; int64_t created;
int64_t modified; int64_t modified;
int64_t _version; int64_t _version;
int _ttl; int _ttl;
int64_t leaseId; int64_t leaseId;
};
typedef std::vector<Value> Values;
class Event {
public:
enum class EventType {
PUT,
DELETE_,
INVALID,
}; };
typedef std::vector<Value> Values; enum EventType event_type() const;
class Event bool has_kv() const;
{
public:
enum class EventType {
PUT,
DELETE_,
INVALID,
};
enum EventType event_type() const; bool has_prev_kv() const;
bool has_kv() const; const Value& kv() const;
bool has_prev_kv() const; const Value& prev_kv() const;
const Value &kv() const; protected:
friend class Response;
const Value &prev_kv() const; Event(mvccpb::Event const& event);
protected: private:
friend class Response; enum EventType event_type_;
Value _kv, _prev_kv;
bool _has_kv, _has_prev_kv;
};
Event(mvccpb::Event const & event); typedef std::vector<Event> Events;
} // namespace etcd
private:
enum EventType event_type_;
Value _kv, _prev_kv;
bool _has_kv, _has_prev_kv;
};
typedef std::vector<Event> Events;
}
#endif #endif

View File

@ -8,237 +8,199 @@
#include "etcd/Response.hpp" #include "etcd/Response.hpp"
namespace etcd namespace etcd {
{ // forward declaration to avoid header/library dependency
// forward declaration to avoid header/library dependency class Client;
class Client;
class Watcher class Watcher {
{ public:
public: Watcher(Client const& client, std::string const& key,
Watcher(Client const &client, std::string const & key, std::function<void(Response)> callback, bool recursive = false);
std::function<void(Response)> callback, Watcher(SyncClient const& client, std::string const& key,
bool recursive=false); std::function<void(Response)> callback, bool recursive = false);
Watcher(SyncClient const &client, std::string const & key, Watcher(Client const& client, std::string const& key,
std::function<void(Response)> callback, std::string const& range_end, std::function<void(Response)> callback);
bool recursive=false); Watcher(SyncClient const& client, std::string const& key,
Watcher(Client const &client, std::string const & key, std::string const& range_end, std::function<void(Response)> callback);
std::string const &range_end, Watcher(Client const& client, std::string const& key, int64_t fromIndex,
std::function<void(Response)> callback); std::function<void(Response)> callback, bool recursive = false);
Watcher(SyncClient const &client, std::string const & key, Watcher(SyncClient const& client, std::string const& key, int64_t fromIndex,
std::string const &range_end, std::function<void(Response)> callback, bool recursive = false);
std::function<void(Response)> callback); Watcher(Client const& client, std::string const& key,
Watcher(Client const &client, std::string const & key, int64_t fromIndex, std::string const& range_end, int64_t fromIndex,
std::function<void(Response)> callback, std::function<void(Response)> callback);
bool recursive=false); Watcher(SyncClient const& client, std::string const& key,
Watcher(SyncClient const &client, std::string const & key, int64_t fromIndex, std::string const& range_end, int64_t fromIndex,
std::function<void(Response)> callback, std::function<void(Response)> callback);
bool recursive=false); Watcher(std::string const& address, std::string const& key,
Watcher(Client const &client, std::string const & key, std::function<void(Response)> callback, bool recursive = false);
std::string const &range_end, int64_t fromIndex, Watcher(std::string const& address, std::string const& key,
std::function<void(Response)> callback); std::string const& range_end, std::function<void(Response)> callback);
Watcher(SyncClient const &client, std::string const & key, Watcher(std::string const& address, std::string const& key, int64_t fromIndex,
std::string const &range_end, int64_t fromIndex, std::function<void(Response)> callback, bool recursive = false);
std::function<void(Response)> callback); Watcher(std::string const& address, std::string const& key,
Watcher(std::string const & address, std::string const & key, std::string const& range_end, int64_t fromIndex,
std::function<void(Response)> callback, std::function<void(Response)> callback);
bool recursive=false); Watcher(std::string const& address, std::string const& username,
Watcher(std::string const & address, std::string const & key, std::string const& password, std::string const& key,
std::string const &range_end, std::function<void(Response)> callback, bool recursive = false,
std::function<void(Response)> callback); int const auth_token_ttl = 300);
Watcher(std::string const & address, std::string const & key, int64_t fromIndex, Watcher(std::string const& address, std::string const& username,
std::function<void(Response)> callback, std::string const& password, std::string const& key,
bool recursive=false); std::string const& range_end, std::function<void(Response)> callback,
Watcher(std::string const & address, std::string const & key, int const auth_token_ttl = 300);
std::string const &range_end, int64_t fromIndex, Watcher(std::string const& address, std::string const& username,
std::function<void(Response)> callback); std::string const& password, std::string const& key,
Watcher(std::string const & address, int64_t fromIndex, std::function<void(Response)> callback,
std::string const & username, std::string const & password, bool recursive = false, int const auth_token_ttl = 300);
std::string const & key, Watcher(std::string const& address, std::string const& username,
std::function<void(Response)> callback, std::string const& password, std::string const& key,
bool recursive=false, std::string const& range_end, int64_t fromIndex,
int const auth_token_ttl = 300); std::function<void(Response)> callback,
Watcher(std::string const & address, int const auth_token_ttl = 300);
std::string const & username, std::string const & password, Watcher(std::string const& address, std::string const& ca,
std::string const & key, std::string const &range_end, std::string const& cert, std::string const& privkey,
std::function<void(Response)> callback, std::string const& key, int64_t fromIndex,
int const auth_token_ttl = 300); std::function<void(Response)> callback, bool recursive = false,
Watcher(std::string const & address, std::string const& target_name_override = "");
std::string const & username, std::string const & password, Watcher(std::string const& address, std::string const& ca,
std::string const & key, int64_t fromIndex, std::string const& cert, std::string const& privkey,
std::function<void(Response)> callback, std::string const& key, std::string const& range_end,
bool recursive=false, int64_t fromIndex, std::function<void(Response)> callback,
int const auth_token_ttl = 300); std::string const& target_name_override = "");
Watcher(std::string const & address,
std::string const & username, std::string const & password,
std::string const & key, std::string const &range_end, int64_t fromIndex,
std::function<void(Response)> callback,
int const auth_token_ttl = 300);
Watcher(std::string const & address,
std::string const & ca,
std::string const & cert,
std::string const & privkey,
std::string const & key, int64_t fromIndex,
std::function<void(Response)> callback, bool recursive=false,
std::string const & target_name_override = "");
Watcher(std::string const & address,
std::string const & ca,
std::string const & cert,
std::string const & privkey,
std::string const & key, std::string const &range_end, int64_t fromIndex,
std::function<void(Response)> callback,
std::string const & target_name_override = "");
Watcher(Client const &client, std::string const & key, Watcher(Client const& client, std::string const& key,
std::function<void(Response)> callback, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback, std::function<void(bool)> wait_callback, bool recursive = false);
bool recursive=false); Watcher(SyncClient const& client, std::string const& key,
Watcher(SyncClient const &client, std::string const & key, std::function<void(Response)> callback,
std::function<void(Response)> callback, std::function<void(bool)> wait_callback, bool recursive = false);
std::function<void(bool)> wait_callback, Watcher(Client const& client, std::string const& key,
bool recursive=false); std::string const& range_end, std::function<void(Response)> callback,
Watcher(Client const &client, std::string const & key, std::function<void(bool)> wait_callback);
std::string const &range_end, Watcher(SyncClient const& client, std::string const& key,
std::function<void(Response)> callback, std::string const& range_end, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback); std::function<void(bool)> wait_callback);
Watcher(SyncClient const &client, std::string const & key, Watcher(Client const& client, std::string const& key, int64_t fromIndex,
std::string const &range_end, std::function<void(Response)> callback,
std::function<void(Response)> callback, std::function<void(bool)> wait_callback, bool recursive = false);
std::function<void(bool)> wait_callback); Watcher(SyncClient const& client, std::string const& key, int64_t fromIndex,
Watcher(Client const &client, std::string const & key, int64_t fromIndex, std::function<void(Response)> callback,
std::function<void(Response)> callback, std::function<void(bool)> wait_callback, bool recursive = false);
std::function<void(bool)> wait_callback, Watcher(Client const& client, std::string const& key,
bool recursive=false); std::string const& range_end, int64_t fromIndex,
Watcher(SyncClient const &client, std::string const & key, int64_t fromIndex, std::function<void(Response)> callback,
std::function<void(Response)> callback, std::function<void(bool)> wait_callback);
std::function<void(bool)> wait_callback, Watcher(SyncClient const& client, std::string const& key,
bool recursive=false); std::string const& range_end, int64_t fromIndex,
Watcher(Client const &client, std::string const & key, std::function<void(Response)> callback,
std::string const &range_end, int64_t fromIndex, std::function<void(bool)> wait_callback);
std::function<void(Response)> callback, Watcher(std::string const& address, std::string const& key,
std::function<void(bool)> wait_callback); std::function<void(Response)> callback,
Watcher(SyncClient const &client, std::string const & key, std::function<void(bool)> wait_callback, bool recursive = false);
std::string const &range_end, int64_t fromIndex, Watcher(std::string const& address, std::string const& key,
std::function<void(Response)> callback, std::string const& range_end, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback); std::function<void(bool)> wait_callback);
Watcher(std::string const & address, std::string const & key, Watcher(std::string const& address, std::string const& key, int64_t fromIndex,
std::function<void(Response)> callback, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback, std::function<void(bool)> wait_callback, bool recursive = false);
bool recursive=false); Watcher(std::string const& address, std::string const& key,
Watcher(std::string const & address, std::string const & key, std::string const& range_end, int64_t fromIndex,
std::string const &range_end, std::function<void(Response)> callback,
std::function<void(Response)> callback, std::function<void(bool)> wait_callback);
std::function<void(bool)> wait_callback); Watcher(std::string const& address, std::string const& username,
Watcher(std::string const & address, std::string const & key, int64_t fromIndex, std::string const& password, std::string const& key,
std::function<void(Response)> callback, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback, std::function<void(bool)> wait_callback, bool recursive = false,
bool recursive=false); int const auth_token_ttl = 300);
Watcher(std::string const & address, std::string const & key, Watcher(std::string const& address, std::string const& username,
std::string const &range_end, int64_t fromIndex, std::string const& password, std::string const& key,
std::function<void(Response)> callback, std::string const& range_end, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback); std::function<void(bool)> wait_callback,
Watcher(std::string const & address, int const auth_token_ttl = 300);
std::string const & username, std::string const & password, Watcher(std::string const& address, std::string const& username,
std::string const & key, std::string const& password, std::string const& key,
std::function<void(Response)> callback, int64_t fromIndex, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback, std::function<void(bool)> wait_callback, bool recursive = false,
bool recursive=false, int const auth_token_ttl = 300);
int const auth_token_ttl = 300); Watcher(std::string const& address, std::string const& username,
Watcher(std::string const & address, std::string const& password, std::string const& key,
std::string const & username, std::string const & password, std::string const& range_end, int64_t fromIndex,
std::string const & key, std::string const &range_end, std::function<void(Response)> callback,
std::function<void(Response)> callback, std::function<void(bool)> wait_callback,
std::function<void(bool)> wait_callback, int const auth_token_ttl = 300);
int const auth_token_ttl = 300); Watcher(std::string const& address, std::string const& ca,
Watcher(std::string const & address, std::string const& cert, std::string const& privkey,
std::string const & username, std::string const & password, std::string const& key, int64_t fromIndex,
std::string const & key, int64_t fromIndex, std::function<void(Response)> callback,
std::function<void(Response)> callback, std::function<void(bool)> wait_callback, bool recursive = false,
std::function<void(bool)> wait_callback, std::string const& target_name_override = "");
bool recursive=false, Watcher(std::string const& address, std::string const& ca,
int const auth_token_ttl = 300); std::string const& cert, std::string const& privkey,
Watcher(std::string const & address, std::string const& key, std::string const& range_end,
std::string const & username, std::string const & password, int64_t fromIndex, std::function<void(Response)> callback,
std::string const & key, std::string const &range_end, int64_t fromIndex, std::function<void(bool)> wait_callback,
std::function<void(Response)> callback, std::string const& target_name_override = "");
std::function<void(bool)> wait_callback,
int const auth_token_ttl = 300);
Watcher(std::string const & address,
std::string const & ca,
std::string const & cert,
std::string const & privkey,
std::string const & key, int64_t fromIndex,
std::function<void(Response)> callback,
std::function<void(bool)> wait_callback,
bool recursive=false,
std::string const & target_name_override = "");
Watcher(std::string const & address,
std::string const & ca,
std::string const & cert,
std::string const & privkey,
std::string const & key, std::string const &range_end, int64_t fromIndex,
std::function<void(Response)> callback,
std::function<void(bool)> wait_callback,
std::string const & target_name_override = "");
Watcher(Watcher const &) = delete; Watcher(Watcher const&) = delete;
Watcher(Watcher &&) = delete; Watcher(Watcher&&) = delete;
/** /**
* Wait util the task has been stopped, actively or passively, e.g., the watcher * Wait util the task has been stopped, actively or passively, e.g., the
* get cancelled or the server closes the connection. * watcher get cancelled or the server closes the connection.
* *
* Returns true if the watcher is been normally cancelled, otherwise false. * Returns true if the watcher is been normally cancelled, otherwise false.
*/ */
bool Wait(); bool Wait();
/** /**
* An async wait, the callback will be called when the task has been stopped. * An async wait, the callback will be called when the task has been stopped.
* *
* The callback parameter would be true if the watch is been normally cancelled. * The callback parameter would be true if the watch is been normally
* * cancelled.
* Note that you shouldn't use the watcher itself inside the `Wait()` callback *
* as the callback will be invoked in a separate **detached** thread where the * Note that you shouldn't use the watcher itself inside the `Wait()` callback
* watcher may have been destroyed. * as the callback will be invoked in a separate **detached** thread where the
*/ * watcher may have been destroyed.
void Wait(std::function<void(bool)> callback); */
void Wait(std::function<void(bool)> callback);
/** /**
* Stop the watching action. * Stop the watching action.
*/ */
bool Cancel(); bool Cancel();
/** /**
* Whether the watcher has been cancelled. * Whether the watcher has been cancelled.
*/ */
bool Cancelled() const; bool Cancelled() const;
~Watcher(); ~Watcher();
protected: protected:
void doWatch(std::string const & key, void doWatch(std::string const& key, std::string const& range_end,
std::string const & range_end, std::string const& auth_token,
std::string const & auth_token, std::function<void(Response)> callback);
std::function<void(Response)> callback);
std::function<void(Response)> callback; std::function<void(Response)> callback;
std::function<void(bool)> wait_callback; std::function<void(bool)> wait_callback;
// Don't use `pplx::task` to avoid sharing thread pool with other actions on the client // Don't use `pplx::task` to avoid sharing thread pool with other actions on
// to avoid any potential blocking, which may block the keepalive loop and evict the lease. // the client to avoid any potential blocking, which may block the keepalive
std::thread task_; // loop and evict the lease.
std::thread task_;
struct EtcdServerStubs; struct EtcdServerStubs;
struct EtcdServerStubsDeleter { struct EtcdServerStubsDeleter {
void operator()(etcd::Watcher::EtcdServerStubs *stubs); void operator()(etcd::Watcher::EtcdServerStubs* stubs);
};
std::unique_ptr<EtcdServerStubs, EtcdServerStubsDeleter> stubs;
private:
int64_t fromIndex;
bool recursive;
std::atomic_bool cancelled;
}; };
} std::unique_ptr<EtcdServerStubs, EtcdServerStubsDeleter> stubs;
private:
int64_t fromIndex;
bool recursive;
std::atomic_bool cancelled;
};
} // namespace etcd
#endif #endif

View File

@ -6,86 +6,81 @@
#include <grpc++/grpc++.h> #include <grpc++/grpc++.h>
#include "proto/rpc.grpc.pb.h" #include "proto/rpc.grpc.pb.h"
#include "proto/v3lock.grpc.pb.h"
#include "proto/v3election.grpc.pb.h" #include "proto/v3election.grpc.pb.h"
#include "proto/v3lock.grpc.pb.h"
using grpc::ClientContext; using grpc::ClientContext;
using grpc::CompletionQueue; using grpc::CompletionQueue;
using grpc::Status; using grpc::Status;
using etcdserverpb::KV; using etcdserverpb::KV;
using etcdserverpb::Watch;
using etcdserverpb::Lease; using etcdserverpb::Lease;
using v3lockpb::Lock; using etcdserverpb::Watch;
using v3electionpb::Election; using v3electionpb::Election;
using v3lockpb::Lock;
namespace etcd { namespace etcd {
class Response; class Response;
} }
namespace etcdv3 namespace etcdv3 {
{ enum class AtomicityType { PREV_INDEX = 0, PREV_VALUE = 1 };
enum class AtomicityType
{
PREV_INDEX = 0,
PREV_VALUE = 1
};
struct ActionParameters struct ActionParameters {
{ ActionParameters();
ActionParameters(); bool withPrefix;
bool withPrefix; int64_t revision = 0;
int64_t revision = 0; int64_t old_revision = 0;
int64_t old_revision = 0; int64_t lease_id = 0; // no lease
int64_t lease_id = 0; // no lease int ttl;
int ttl; int limit;
int limit; std::string name; // for campaign (in v3election)
std::string name; // for campaign (in v3election) std::string key;
std::string key; std::string range_end;
std::string range_end; bool keys_only;
bool keys_only; bool count_only;
bool count_only; std::string value;
std::string value; std::string old_value;
std::string old_value; std::string auth_token;
std::string auth_token; std::chrono::microseconds grpc_timeout = std::chrono::microseconds::zero();
std::chrono::microseconds grpc_timeout = std::chrono::microseconds::zero(); KV::Stub* kv_stub;
KV::Stub* kv_stub; Watch::Stub* watch_stub;
Watch::Stub* watch_stub; Lease::Stub* lease_stub;
Lease::Stub* lease_stub; Lock::Stub* lock_stub;
Lock::Stub* lock_stub; Election::Stub* election_stub;
Election::Stub* election_stub;
bool has_grpc_timeout() const; bool has_grpc_timeout() const;
std::chrono::system_clock::time_point grpc_deadline() const; std::chrono::system_clock::time_point grpc_deadline() const;
void dump(std::ostream &os) const; void dump(std::ostream& os) const;
}; };
class Action class Action {
{ public:
public: Action(etcdv3::ActionParameters const& params);
Action(etcdv3::ActionParameters const &params); Action(etcdv3::ActionParameters&& params);
Action(etcdv3::ActionParameters && params); virtual ~Action();
virtual ~Action();
void waitForResponse(); void waitForResponse();
const std::chrono::high_resolution_clock::time_point startTimepoint(); const std::chrono::high_resolution_clock::time_point startTimepoint();
protected:
Status status;
ClientContext context;
CompletionQueue cq_;
etcdv3::ActionParameters parameters;
std::chrono::high_resolution_clock::time_point start_timepoint;
private:
// Init things like auth token, etc.
void InitAction();
friend class etcd::Response; protected:
}; Status status;
ClientContext context;
CompletionQueue cq_;
etcdv3::ActionParameters parameters;
std::chrono::high_resolution_clock::time_point start_timepoint;
namespace detail { private:
std::string string_plus_one(std::string const &value); // Init things like auth token, etc.
std::string resolve_etcd_endpoints(std::string const &default_endpoints); void InitAction();
}
} friend class etcd::Response;
};
namespace detail {
std::string string_plus_one(std::string const& value);
std::string resolve_etcd_endpoints(std::string const& default_endpoints);
} // namespace detail
} // namespace etcdv3
#endif #endif

View File

@ -6,16 +6,16 @@
#include <grpc++/grpc++.h> #include <grpc++/grpc++.h>
#include "proto/rpc.pb.h"
#include "proto/rpc.grpc.pb.h" #include "proto/rpc.grpc.pb.h"
#include "proto/v3election.pb.h" #include "proto/rpc.pb.h"
#include "proto/v3election.grpc.pb.h" #include "proto/v3election.grpc.pb.h"
#include "proto/v3lock.pb.h" #include "proto/v3election.pb.h"
#include "proto/v3lock.grpc.pb.h" #include "proto/v3lock.grpc.pb.h"
#include "proto/v3lock.pb.h"
#include "etcd/Response.hpp"
#include "etcd/v3/Action.hpp" #include "etcd/v3/Action.hpp"
#include "etcd/v3/V3Response.hpp" #include "etcd/v3/V3Response.hpp"
#include "etcd/Response.hpp"
using grpc::ClientAsyncReader; using grpc::ClientAsyncReader;
using grpc::ClientAsyncReaderWriter; using grpc::ClientAsyncReaderWriter;
@ -23,28 +23,20 @@ using grpc::ClientAsyncResponseReader;
using etcdserverpb::KV; using etcdserverpb::KV;
using v3electionpb::CampaignRequest;
using v3electionpb::CampaignResponse;
using etcdserverpb::DeleteRangeRequest; using etcdserverpb::DeleteRangeRequest;
using etcdserverpb::DeleteRangeResponse; using etcdserverpb::DeleteRangeResponse;
using etcdserverpb::LeaseCheckpointRequest; using etcdserverpb::LeaseCheckpointRequest;
using etcdserverpb::LeaseCheckpointResponse; using etcdserverpb::LeaseCheckpointResponse;
using etcdserverpb::LeaseGrantRequest; using etcdserverpb::LeaseGrantRequest;
using etcdserverpb::LeaseGrantResponse; using etcdserverpb::LeaseGrantResponse;
using etcdserverpb::LeaseRevokeRequest;
using etcdserverpb::LeaseRevokeResponse;
using etcdserverpb::LeaseKeepAliveRequest; using etcdserverpb::LeaseKeepAliveRequest;
using etcdserverpb::LeaseKeepAliveResponse; using etcdserverpb::LeaseKeepAliveResponse;
using etcdserverpb::LeaseLeasesRequest; using etcdserverpb::LeaseLeasesRequest;
using etcdserverpb::LeaseLeasesResponse; using etcdserverpb::LeaseLeasesResponse;
using etcdserverpb::LeaseRevokeRequest;
using etcdserverpb::LeaseRevokeResponse;
using etcdserverpb::LeaseTimeToLiveRequest; using etcdserverpb::LeaseTimeToLiveRequest;
using etcdserverpb::LeaseTimeToLiveResponse; using etcdserverpb::LeaseTimeToLiveResponse;
using etcdserverpb::TxnRequest;
using etcdserverpb::TxnResponse;
using etcdserverpb::RangeRequest;
using etcdserverpb::RangeResponse;
using v3electionpb::ResignRequest;
using v3electionpb::ResignResponse;
using etcdserverpb::PutRequest; using etcdserverpb::PutRequest;
using etcdserverpb::PutResponse; using etcdserverpb::PutResponse;
using etcdserverpb::RangeRequest; using etcdserverpb::RangeRequest;
@ -53,393 +45,393 @@ using etcdserverpb::TxnRequest;
using etcdserverpb::TxnResponse; using etcdserverpb::TxnResponse;
using etcdserverpb::WatchRequest; using etcdserverpb::WatchRequest;
using etcdserverpb::WatchResponse; using etcdserverpb::WatchResponse;
using v3electionpb::CampaignRequest;
using v3electionpb::CampaignResponse;
using v3electionpb::LeaderRequest; using v3electionpb::LeaderRequest;
using v3electionpb::LeaderResponse; using v3electionpb::LeaderResponse;
using v3electionpb::ProclaimRequest; using v3electionpb::ProclaimRequest;
using v3electionpb::ProclaimResponse; using v3electionpb::ProclaimResponse;
using v3electionpb::ResignRequest;
using v3electionpb::ResignResponse;
using v3lockpb::LockRequest; using v3lockpb::LockRequest;
using v3lockpb::LockResponse; using v3lockpb::LockResponse;
using v3lockpb::UnlockRequest; using v3lockpb::UnlockRequest;
using v3lockpb::UnlockResponse; using v3lockpb::UnlockResponse;
namespace etcd { namespace etcd {
class KeepAlive; class KeepAlive;
} }
namespace etcdv3 { namespace etcdv3 {
class Transaction; class Transaction;
} }
namespace etcdv3 { namespace etcdv3 {
class AsyncCampaignResponse : public etcdv3::V3Response class AsyncCampaignResponse : public etcdv3::V3Response {
{ public:
public: AsyncCampaignResponse(){};
AsyncCampaignResponse(){}; void ParseResponse(CampaignResponse& resp);
void ParseResponse(CampaignResponse& resp); };
};
class AsyncDeleteResponse : public etcdv3::V3Response class AsyncDeleteResponse : public etcdv3::V3Response {
{ public:
public: AsyncDeleteResponse(){};
AsyncDeleteResponse(){}; void ParseResponse(std::string const& key, bool prefix,
void ParseResponse(std::string const& key, bool prefix, DeleteRangeResponse& resp); DeleteRangeResponse& resp);
}; };
class AsyncHeadResponse : public etcdv3::V3Response class AsyncHeadResponse : public etcdv3::V3Response {
{ public:
public: AsyncHeadResponse(){};
AsyncHeadResponse(){}; void ParseResponse(RangeResponse& resp);
void ParseResponse(RangeResponse& resp); };
};
class AsyncLeaderResponse : public etcdv3::V3Response class AsyncLeaderResponse : public etcdv3::V3Response {
{ public:
public: AsyncLeaderResponse(){};
AsyncLeaderResponse(){}; void ParseResponse(LeaderResponse& resp);
void ParseResponse(LeaderResponse& resp); };
};
class AsyncLeaseGrantResponse : public etcdv3::V3Response class AsyncLeaseGrantResponse : public etcdv3::V3Response {
{ public:
public: AsyncLeaseGrantResponse(){};
AsyncLeaseGrantResponse(){}; void ParseResponse(LeaseGrantResponse& resp);
void ParseResponse(LeaseGrantResponse& resp); };
};
class AsyncLeaseKeepAliveResponse : public etcdv3::V3Response class AsyncLeaseKeepAliveResponse : public etcdv3::V3Response {
{ public:
public: AsyncLeaseKeepAliveResponse(){};
AsyncLeaseKeepAliveResponse(){}; void ParseResponse(LeaseKeepAliveResponse& resp);
void ParseResponse(LeaseKeepAliveResponse& resp); };
};
class AsyncLeaseLeasesResponse : public etcdv3::V3Response class AsyncLeaseLeasesResponse : public etcdv3::V3Response {
{ public:
public: AsyncLeaseLeasesResponse(){};
AsyncLeaseLeasesResponse(){}; void ParseResponse(LeaseLeasesResponse& resp);
void ParseResponse(LeaseLeasesResponse& resp); };
};
class AsyncLeaseRevokeResponse : public etcdv3::V3Response class AsyncLeaseRevokeResponse : public etcdv3::V3Response {
{ public:
public: AsyncLeaseRevokeResponse(){};
AsyncLeaseRevokeResponse(){}; void ParseResponse(LeaseRevokeResponse& resp);
void ParseResponse(LeaseRevokeResponse& resp); };
};
class AsyncLeaseTimeToLiveResponse : public etcdv3::V3Response class AsyncLeaseTimeToLiveResponse : public etcdv3::V3Response {
{ public:
public: AsyncLeaseTimeToLiveResponse(){};
AsyncLeaseTimeToLiveResponse(){}; void ParseResponse(LeaseTimeToLiveResponse& resp);
void ParseResponse(LeaseTimeToLiveResponse& resp); };
};
class AsyncLockResponse : public etcdv3::V3Response class AsyncLockResponse : public etcdv3::V3Response {
{ public:
public: AsyncLockResponse(){};
AsyncLockResponse(){}; void ParseResponse(LockResponse& resp);
void ParseResponse(LockResponse& resp); };
};
class AsyncObserveResponse : public etcdv3::V3Response class AsyncObserveResponse : public etcdv3::V3Response {
{ public:
public: AsyncObserveResponse(){};
AsyncObserveResponse(){}; void ParseResponse(LeaderResponse& resp);
void ParseResponse(LeaderResponse& resp); };
};
class AsyncProclaimResponse : public etcdv3::V3Response class AsyncProclaimResponse : public etcdv3::V3Response {
{ public:
public: AsyncProclaimResponse(){};
AsyncProclaimResponse(){}; void ParseResponse(ProclaimResponse& resp);
void ParseResponse(ProclaimResponse& resp); };
};
class AsyncPutResponse : public etcdv3::V3Response class AsyncPutResponse : public etcdv3::V3Response {
{ public:
public: AsyncPutResponse(){};
AsyncPutResponse(){}; void ParseResponse(PutResponse& resp);
void ParseResponse(PutResponse& resp); };
};
class AsyncRangeResponse : public etcdv3::V3Response class AsyncRangeResponse : public etcdv3::V3Response {
{ public:
public: AsyncRangeResponse(){};
AsyncRangeResponse(){}; void ParseResponse(RangeResponse& resp, bool prefix = false);
void ParseResponse(RangeResponse& resp, bool prefix=false); };
};
class AsyncResignResponse : public etcdv3::V3Response class AsyncResignResponse : public etcdv3::V3Response {
{ public:
public: AsyncResignResponse(){};
AsyncResignResponse(){}; void ParseResponse(ResignResponse& resp);
void ParseResponse(ResignResponse& resp); };
};
class AsyncTxnResponse : public etcdv3::V3Response class AsyncTxnResponse : public etcdv3::V3Response {
{ public:
public: AsyncTxnResponse(){};
AsyncTxnResponse(){}; void ParseResponse(TxnResponse& resp);
void ParseResponse(TxnResponse& resp); void ParseResponse(std::string const& key, bool prefix, TxnResponse& resp);
void ParseResponse(std::string const& key, bool prefix, TxnResponse& resp); };
};
class AsyncUnlockResponse : public etcdv3::V3Response class AsyncUnlockResponse : public etcdv3::V3Response {
{ public:
public: AsyncUnlockResponse(){};
AsyncUnlockResponse(){}; void ParseResponse(UnlockResponse& resp);
void ParseResponse(UnlockResponse& resp); };
};
class AsyncWatchResponse : public etcdv3::V3Response class AsyncWatchResponse : public etcdv3::V3Response {
{ public:
public: AsyncWatchResponse(){};
AsyncWatchResponse(){}; void ParseResponse(WatchResponse& resp);
void ParseResponse(WatchResponse& resp); };
}; } // namespace etcdv3
}
namespace etcdv3 namespace etcdv3 {
{ class AsyncCampaignAction : public etcdv3::Action {
class AsyncCampaignAction : public etcdv3::Action public:
{ AsyncCampaignAction(etcdv3::ActionParameters&& params);
public: AsyncCampaignResponse ParseResponse();
AsyncCampaignAction(etcdv3::ActionParameters && params);
AsyncCampaignResponse ParseResponse();
private:
CampaignResponse reply;
std::unique_ptr<ClientAsyncResponseReader<CampaignResponse>> response_reader;
};
class AsyncCompareAndDeleteAction : public etcdv3::Action private:
{ CampaignResponse reply;
public: std::unique_ptr<ClientAsyncResponseReader<CampaignResponse>> response_reader;
AsyncCompareAndDeleteAction(etcdv3::ActionParameters && params, etcdv3::AtomicityType type); };
AsyncTxnResponse ParseResponse();
private:
TxnResponse reply;
std::unique_ptr<ClientAsyncResponseReader<TxnResponse>> response_reader;
};
class AsyncCompareAndSwapAction : public etcdv3::Action class AsyncCompareAndDeleteAction : public etcdv3::Action {
{ public:
public: AsyncCompareAndDeleteAction(etcdv3::ActionParameters&& params,
AsyncCompareAndSwapAction(etcdv3::ActionParameters && params, etcdv3::AtomicityType type); etcdv3::AtomicityType type);
AsyncTxnResponse ParseResponse(); AsyncTxnResponse ParseResponse();
private:
TxnResponse reply;
std::unique_ptr<ClientAsyncResponseReader<TxnResponse>> response_reader;
};
class AsyncDeleteAction : public etcdv3::Action private:
{ TxnResponse reply;
public: std::unique_ptr<ClientAsyncResponseReader<TxnResponse>> response_reader;
AsyncDeleteAction(etcdv3::ActionParameters && params); };
AsyncDeleteResponse ParseResponse();
private:
DeleteRangeResponse reply;
std::unique_ptr<ClientAsyncResponseReader<DeleteRangeResponse>> response_reader;
};
class AsyncHeadAction : public etcdv3::Action class AsyncCompareAndSwapAction : public etcdv3::Action {
{ public:
public: AsyncCompareAndSwapAction(etcdv3::ActionParameters&& params,
AsyncHeadAction(etcdv3::ActionParameters && params); etcdv3::AtomicityType type);
AsyncHeadResponse ParseResponse(); AsyncTxnResponse ParseResponse();
private:
RangeResponse reply;
std::unique_ptr<ClientAsyncResponseReader<RangeResponse>> response_reader;
};
class AsyncLeaderAction : public etcdv3::Action private:
{ TxnResponse reply;
public: std::unique_ptr<ClientAsyncResponseReader<TxnResponse>> response_reader;
AsyncLeaderAction(etcdv3::ActionParameters && params); };
AsyncLeaderResponse ParseResponse();
private:
LeaderResponse reply;
std::unique_ptr<ClientAsyncResponseReader<LeaderResponse>> response_reader;
};
class AsyncLeaseGrantAction : public etcdv3::Action { class AsyncDeleteAction : public etcdv3::Action {
public: public:
AsyncLeaseGrantAction(etcdv3::ActionParameters && params); AsyncDeleteAction(etcdv3::ActionParameters&& params);
AsyncLeaseGrantResponse ParseResponse(); AsyncDeleteResponse ParseResponse();
private:
LeaseGrantResponse reply;
std::unique_ptr<ClientAsyncResponseReader<LeaseGrantResponse>> response_reader;
};
class AsyncLeaseKeepAliveAction: public etcdv3::Action { private:
public: DeleteRangeResponse reply;
AsyncLeaseKeepAliveAction(etcdv3::ActionParameters && params); std::unique_ptr<ClientAsyncResponseReader<DeleteRangeResponse>>
AsyncLeaseKeepAliveResponse ParseResponse(); response_reader;
};
etcd::Response Refresh(); class AsyncHeadAction : public etcdv3::Action {
void CancelKeepAlive(); public:
bool Cancelled() const; AsyncHeadAction(etcdv3::ActionParameters&& params);
AsyncHeadResponse ParseResponse();
private: private:
etcdv3::ActionParameters& mutable_parameters(); RangeResponse reply;
std::unique_ptr<ClientAsyncResponseReader<RangeResponse>> response_reader;
};
LeaseKeepAliveResponse reply; class AsyncLeaderAction : public etcdv3::Action {
std::unique_ptr<ClientAsyncReaderWriter<LeaseKeepAliveRequest, LeaseKeepAliveResponse>> stream; public:
AsyncLeaderAction(etcdv3::ActionParameters&& params);
AsyncLeaderResponse ParseResponse();
LeaseKeepAliveRequest req; private:
bool isCancelled; LeaderResponse reply;
std::recursive_mutex protect_is_cancelled; std::unique_ptr<ClientAsyncResponseReader<LeaderResponse>> response_reader;
};
friend class etcd::KeepAlive; class AsyncLeaseGrantAction : public etcdv3::Action {
}; public:
AsyncLeaseGrantAction(etcdv3::ActionParameters&& params);
AsyncLeaseGrantResponse ParseResponse();
class AsyncLeaseLeasesAction: public etcdv3::Action { private:
public: LeaseGrantResponse reply;
AsyncLeaseLeasesAction(etcdv3::ActionParameters && params); std::unique_ptr<ClientAsyncResponseReader<LeaseGrantResponse>>
AsyncLeaseLeasesResponse ParseResponse(); response_reader;
private: };
LeaseLeasesResponse reply;
std::unique_ptr<ClientAsyncResponseReader<LeaseLeasesResponse>> response_reader;
};
class AsyncLeaseRevokeAction: public etcdv3::Action { class AsyncLeaseKeepAliveAction : public etcdv3::Action {
public: public:
AsyncLeaseRevokeAction(etcdv3::ActionParameters && params); AsyncLeaseKeepAliveAction(etcdv3::ActionParameters&& params);
AsyncLeaseRevokeResponse ParseResponse(); AsyncLeaseKeepAliveResponse ParseResponse();
private:
LeaseRevokeResponse reply;
std::unique_ptr<ClientAsyncResponseReader<LeaseRevokeResponse>> response_reader;
};
class AsyncLeaseTimeToLiveAction: public etcdv3::Action { etcd::Response Refresh();
public: void CancelKeepAlive();
AsyncLeaseTimeToLiveAction(etcdv3::ActionParameters && params); bool Cancelled() const;
AsyncLeaseTimeToLiveResponse ParseResponse();
private:
LeaseTimeToLiveResponse reply;
std::unique_ptr<ClientAsyncResponseReader<LeaseTimeToLiveResponse>> response_reader;
};
class AsyncLockAction : public etcdv3::Action private:
{ etcdv3::ActionParameters& mutable_parameters();
public:
AsyncLockAction(etcdv3::ActionParameters && params);
AsyncLockResponse ParseResponse();
private:
LockResponse reply;
std::unique_ptr<ClientAsyncResponseReader<LockResponse>> response_reader;
};
class AsyncObserveAction : public etcdv3::Action LeaseKeepAliveResponse reply;
{ std::unique_ptr<
public: ClientAsyncReaderWriter<LeaseKeepAliveRequest, LeaseKeepAliveResponse>>
AsyncObserveAction(etcdv3::ActionParameters && params); stream;
AsyncObserveResponse ParseResponse();
void waitForResponse();
void CancelObserve();
bool Cancelled() const;
private:
LeaderResponse reply;
std::unique_ptr<ClientAsyncReader<LeaderResponse>> response_reader;
std::atomic_bool isCancelled;
std::mutex protect_is_cancalled;
};
class AsyncProclaimAction : public etcdv3::Action LeaseKeepAliveRequest req;
{ bool isCancelled;
public: std::recursive_mutex protect_is_cancelled;
AsyncProclaimAction(etcdv3::ActionParameters && params);
AsyncProclaimResponse ParseResponse();
private:
ProclaimResponse reply;
std::unique_ptr<ClientAsyncResponseReader<ProclaimResponse>> response_reader;
};
class AsyncPutAction : public etcdv3::Action friend class etcd::KeepAlive;
{ };
public:
AsyncPutAction(etcdv3::ActionParameters && params);
AsyncPutResponse ParseResponse();
private:
PutResponse reply;
std::unique_ptr<ClientAsyncResponseReader<PutResponse>> response_reader;
};
class AsyncRangeAction : public etcdv3::Action class AsyncLeaseLeasesAction : public etcdv3::Action {
{ public:
public: AsyncLeaseLeasesAction(etcdv3::ActionParameters&& params);
AsyncRangeAction(etcdv3::ActionParameters && params); AsyncLeaseLeasesResponse ParseResponse();
AsyncRangeResponse ParseResponse();
private:
RangeResponse reply;
std::unique_ptr<ClientAsyncResponseReader<RangeResponse>> response_reader;
};
class AsyncResignAction : public etcdv3::Action private:
{ LeaseLeasesResponse reply;
public: std::unique_ptr<ClientAsyncResponseReader<LeaseLeasesResponse>>
AsyncResignAction(etcdv3::ActionParameters && params); response_reader;
AsyncResignResponse ParseResponse(); };
private:
ResignResponse reply;
std::unique_ptr<ClientAsyncResponseReader<ResignResponse>> response_reader;
};
class AsyncSetAction : public etcdv3::Action class AsyncLeaseRevokeAction : public etcdv3::Action {
{ public:
public: AsyncLeaseRevokeAction(etcdv3::ActionParameters&& params);
AsyncSetAction(etcdv3::ActionParameters && params, bool create=false); AsyncLeaseRevokeResponse ParseResponse();
AsyncTxnResponse ParseResponse();
private:
TxnResponse reply;
std::unique_ptr<ClientAsyncResponseReader<TxnResponse>> response_reader;
bool isCreate;
};
class AsyncTxnAction : public etcdv3::Action private:
{ LeaseRevokeResponse reply;
public: std::unique_ptr<ClientAsyncResponseReader<LeaseRevokeResponse>>
AsyncTxnAction(etcdv3::ActionParameters && params, etcdv3::Transaction const &tx); response_reader;
AsyncTxnResponse ParseResponse(); };
private:
TxnResponse reply;
std::unique_ptr<ClientAsyncResponseReader<TxnResponse>> response_reader;
};
class AsyncUnlockAction : public etcdv3::Action class AsyncLeaseTimeToLiveAction : public etcdv3::Action {
{ public:
public: AsyncLeaseTimeToLiveAction(etcdv3::ActionParameters&& params);
AsyncUnlockAction(etcdv3::ActionParameters && params); AsyncLeaseTimeToLiveResponse ParseResponse();
AsyncUnlockResponse ParseResponse();
private:
UnlockResponse reply;
std::unique_ptr<ClientAsyncResponseReader<UnlockResponse>> response_reader;
};
class AsyncUpdateAction : public etcdv3::Action private:
{ LeaseTimeToLiveResponse reply;
public: std::unique_ptr<ClientAsyncResponseReader<LeaseTimeToLiveResponse>>
AsyncUpdateAction(etcdv3::ActionParameters && params); response_reader;
AsyncTxnResponse ParseResponse(); };
private:
TxnResponse reply;
std::unique_ptr<ClientAsyncResponseReader<TxnResponse>> response_reader;
};
class AsyncWatchAction : public etcdv3::Action class AsyncLockAction : public etcdv3::Action {
{ public:
public: AsyncLockAction(etcdv3::ActionParameters&& params);
AsyncWatchAction(etcdv3::ActionParameters && params); AsyncLockResponse ParseResponse();
AsyncWatchResponse ParseResponse();
void waitForResponse(); private:
void waitForResponse(std::function<void(etcd::Response)> callback); LockResponse reply;
void CancelWatch(); std::unique_ptr<ClientAsyncResponseReader<LockResponse>> response_reader;
bool Cancelled() const; };
private:
int64_t watch_id = -1; class AsyncObserveAction : public etcdv3::Action {
WatchResponse reply; public:
std::unique_ptr<ClientAsyncReaderWriter<WatchRequest,WatchResponse>> stream; AsyncObserveAction(etcdv3::ActionParameters&& params);
std::atomic_bool isCancelled; AsyncObserveResponse ParseResponse();
}; void waitForResponse();
} void CancelObserve();
bool Cancelled() const;
private:
LeaderResponse reply;
std::unique_ptr<ClientAsyncReader<LeaderResponse>> response_reader;
std::atomic_bool isCancelled;
std::mutex protect_is_cancalled;
};
class AsyncProclaimAction : public etcdv3::Action {
public:
AsyncProclaimAction(etcdv3::ActionParameters&& params);
AsyncProclaimResponse ParseResponse();
private:
ProclaimResponse reply;
std::unique_ptr<ClientAsyncResponseReader<ProclaimResponse>> response_reader;
};
class AsyncPutAction : public etcdv3::Action {
public:
AsyncPutAction(etcdv3::ActionParameters&& params);
AsyncPutResponse ParseResponse();
private:
PutResponse reply;
std::unique_ptr<ClientAsyncResponseReader<PutResponse>> response_reader;
};
class AsyncRangeAction : public etcdv3::Action {
public:
AsyncRangeAction(etcdv3::ActionParameters&& params);
AsyncRangeResponse ParseResponse();
private:
RangeResponse reply;
std::unique_ptr<ClientAsyncResponseReader<RangeResponse>> response_reader;
};
class AsyncResignAction : public etcdv3::Action {
public:
AsyncResignAction(etcdv3::ActionParameters&& params);
AsyncResignResponse ParseResponse();
private:
ResignResponse reply;
std::unique_ptr<ClientAsyncResponseReader<ResignResponse>> response_reader;
};
class AsyncSetAction : public etcdv3::Action {
public:
AsyncSetAction(etcdv3::ActionParameters&& params, bool create = false);
AsyncTxnResponse ParseResponse();
private:
TxnResponse reply;
std::unique_ptr<ClientAsyncResponseReader<TxnResponse>> response_reader;
bool isCreate;
};
class AsyncTxnAction : public etcdv3::Action {
public:
AsyncTxnAction(etcdv3::ActionParameters&& params,
etcdv3::Transaction const& tx);
AsyncTxnResponse ParseResponse();
private:
TxnResponse reply;
std::unique_ptr<ClientAsyncResponseReader<TxnResponse>> response_reader;
};
class AsyncUnlockAction : public etcdv3::Action {
public:
AsyncUnlockAction(etcdv3::ActionParameters&& params);
AsyncUnlockResponse ParseResponse();
private:
UnlockResponse reply;
std::unique_ptr<ClientAsyncResponseReader<UnlockResponse>> response_reader;
};
class AsyncUpdateAction : public etcdv3::Action {
public:
AsyncUpdateAction(etcdv3::ActionParameters&& params);
AsyncTxnResponse ParseResponse();
private:
TxnResponse reply;
std::unique_ptr<ClientAsyncResponseReader<TxnResponse>> response_reader;
};
class AsyncWatchAction : public etcdv3::Action {
public:
AsyncWatchAction(etcdv3::ActionParameters&& params);
AsyncWatchResponse ParseResponse();
void waitForResponse();
void waitForResponse(std::function<void(etcd::Response)> callback);
void CancelWatch();
bool Cancelled() const;
private:
int64_t watch_id = -1;
WatchResponse reply;
std::unique_ptr<ClientAsyncReaderWriter<WatchRequest, WatchResponse>> stream;
std::atomic_bool isCancelled;
};
} // namespace etcdv3
#endif #endif

View File

@ -3,18 +3,16 @@
#include "proto/kv.pb.h" #include "proto/kv.pb.h"
namespace etcdv3 {
class KeyValue {
public:
KeyValue();
mvccpb::KeyValue kvs;
void set_ttl(int ttl);
int get_ttl() const;
namespace etcdv3 private:
{ int ttl;
class KeyValue };
{ } // namespace etcdv3
public:
KeyValue();
mvccpb::KeyValue kvs;
void set_ttl(int ttl);
int get_ttl() const;
private:
int ttl;
};
}
#endif #endif

View File

@ -1,60 +1,67 @@
#ifndef V3_SRC_TRANSACTION_HPP_ #ifndef V3_SRC_TRANSACTION_HPP_
#define V3_SRC_TRANSACTION_HPP_ #define V3_SRC_TRANSACTION_HPP_
#include <string>
#include <memory> #include <memory>
#include <string>
namespace etcdserverpb { namespace etcdserverpb {
class TxnRequest; class TxnRequest;
} }
namespace etcdv3 { namespace etcdv3 {
enum class CompareResult { enum class CompareResult {
EQUAL = 0, EQUAL = 0,
GREATER = 1, GREATER = 1,
LESS = 2, LESS = 2,
NOT_EQUAL = 3, NOT_EQUAL = 3,
}; };
enum class CompareTarget { enum class CompareTarget {
VERSION = 0, VERSION = 0,
CREATE = 1, CREATE = 1,
MOD = 2, MOD = 2,
VALUE = 3, VALUE = 3,
LEASE = 4, LEASE = 4,
}; };
class Transaction { class Transaction {
public: public:
Transaction(); Transaction();
Transaction(std::string const&); Transaction(std::string const&);
virtual ~Transaction(); virtual ~Transaction();
// Set a new key for different comparisons and /put/get/delete requests. // Set a new key for different comparisons and /put/get/delete requests.
void reset_key(std::string const& newkey); void reset_key(std::string const& newkey);
void init_compare(CompareResult, CompareTarget); void init_compare(CompareResult, CompareTarget);
void init_compare(std::string const &old_value, CompareResult, CompareTarget); void init_compare(std::string const& old_value, CompareResult, CompareTarget);
void init_compare(int64_t old_value, CompareResult, CompareTarget); void init_compare(int64_t old_value, CompareResult, CompareTarget);
void setup_basic_failure_operation(std::string const &key); void setup_basic_failure_operation(std::string const& key);
void setup_set_failure_operation(std::string const &key, std::string const &value, int64_t leaseid); void setup_set_failure_operation(std::string const& key,
void setup_basic_create_sequence(std::string const &key, std::string const &value, int64_t leaseid); std::string const& value, int64_t leaseid);
void setup_compare_and_swap_sequence(std::string const &valueToSwap, int64_t leaseid); void setup_basic_create_sequence(std::string const& key,
void setup_delete_sequence(std::string const &key, std::string const &range_end, bool recursive); std::string const& value, int64_t leaseid);
void setup_delete_failure_operation(std::string const &key, std::string const &range_end, bool recursive); void setup_compare_and_swap_sequence(std::string const& valueToSwap,
void setup_compare_and_delete_operation(std::string const& key); int64_t leaseid);
void setup_delete_sequence(std::string const& key,
std::string const& range_end, bool recursive);
void setup_delete_failure_operation(std::string const& key,
std::string const& range_end,
bool recursive);
void setup_compare_and_delete_operation(std::string const& key);
// update without `get` and no `prev_kv` returned // update without `get` and no `prev_kv` returned
void setup_put(std::string const &key, std::string const &value); void setup_put(std::string const& key, std::string const& value);
void setup_delete(std::string const &key); void setup_delete(std::string const& key);
std::shared_ptr<etcdserverpb::TxnRequest> txn_request; std::shared_ptr<etcdserverpb::TxnRequest> txn_request;
private:
std::string key; private:
std::string key;
}; };
} } // namespace etcdv3
#endif #endif

View File

@ -7,59 +7,58 @@
#include "etcd/v3/KeyValue.hpp" #include "etcd/v3/KeyValue.hpp"
namespace etcdv3 namespace etcdv3 {
{ class V3Response {
class V3Response public:
{ V3Response() : error_code(0), index(0){};
public: void set_error_code(int code);
V3Response(): error_code(0), index(0){}; int get_error_code() const;
void set_error_code(int code); std::string const& get_error_message() const;
int get_error_code() const; void set_error_message(std::string msg);
std::string const & get_error_message() const; void set_action(std::string action);
void set_error_message(std::string msg); int64_t get_index() const;
void set_action(std::string action); std::string const& get_action() const;
int64_t get_index() const; std::vector<etcdv3::KeyValue> const& get_values() const;
std::string const & get_action() const; std::vector<etcdv3::KeyValue> const& get_prev_values() const;
std::vector<etcdv3::KeyValue> const & get_values() const; etcdv3::KeyValue const& get_value() const;
std::vector<etcdv3::KeyValue> const & get_prev_values() const; etcdv3::KeyValue const& get_prev_value() const;
etcdv3::KeyValue const & get_value() const; bool has_values() const;
etcdv3::KeyValue const & get_prev_value() const; int64_t get_compact_revision() const;
bool has_values() const; void set_compact_revision(const int64_t compact_revision);
int64_t get_compact_revision() const; int64_t get_watch_id() const;
void set_compact_revision(const int64_t compact_revision); void set_watch_id(const int64_t watch_id);
int64_t get_watch_id() const; void set_lock_key(std::string const& key);
void set_watch_id(const int64_t watch_id); std::string const& get_lock_key() const;
void set_lock_key(std::string const &key); void set_name(std::string const& name);
std::string const &get_lock_key() const; std::string const& get_name() const;
void set_name(std::string const &name); std::vector<mvccpb::Event> const& get_events() const;
std::string const &get_name() const; uint64_t get_cluster_id() const;
std::vector<mvccpb::Event> const & get_events() const; uint64_t get_member_id() const;
uint64_t get_cluster_id() const; uint64_t get_raft_term() const;
uint64_t get_member_id() const; std::vector<int64_t> const& get_leases() const;
uint64_t get_raft_term() const;
std::vector<int64_t> const &get_leases() const;
protected:
int error_code;
int64_t index;
std::string error_message;
std::string action;
etcdv3::KeyValue value;
etcdv3::KeyValue prev_value;
std::vector<etcdv3::KeyValue> values;
std::vector<etcdv3::KeyValue> prev_values;
int64_t compact_revision = -1;
int64_t watch_id = -1;
std::string lock_key; // for lock
std::string name; // for campaign (in v3election)
std::vector<mvccpb::Event> events; // for watch
// cluster metadata protected:
uint64_t cluster_id; int error_code;
uint64_t member_id; int64_t index;
uint64_t raft_term; std::string error_message;
std::string action;
etcdv3::KeyValue value;
etcdv3::KeyValue prev_value;
std::vector<etcdv3::KeyValue> values;
std::vector<etcdv3::KeyValue> prev_values;
int64_t compact_revision = -1;
int64_t watch_id = -1;
std::string lock_key; // for lock
std::string name; // for campaign (in v3election)
std::vector<mvccpb::Event> events; // for watch
// for lease list // cluster metadata
std::vector<int64_t> leases; uint64_t cluster_id;
}; uint64_t member_id;
} uint64_t raft_term;
// for lease list
std::vector<int64_t> leases;
};
} // namespace etcdv3
#endif #endif

View File

@ -3,72 +3,71 @@
#include <string> #include <string>
namespace etcdv3 namespace etcdv3 {
{ extern char const* CREATE_ACTION;
extern char const * CREATE_ACTION; extern char const* UPDATE_ACTION;
extern char const * UPDATE_ACTION; extern char const* SET_ACTION;
extern char const * SET_ACTION; extern char const* GET_ACTION;
extern char const * GET_ACTION; extern char const* PUT_ACTION;
extern char const * PUT_ACTION; extern char const* DELETE_ACTION;
extern char const * DELETE_ACTION; extern char const* COMPARESWAP_ACTION;
extern char const * COMPARESWAP_ACTION; extern char const* COMPAREDELETE_ACTION;
extern char const * COMPAREDELETE_ACTION; extern char const* LOCK_ACTION;
extern char const * LOCK_ACTION; extern char const* UNLOCK_ACTION;
extern char const * UNLOCK_ACTION; extern char const* TXN_ACTION;
extern char const * TXN_ACTION; extern char const* WATCH_ACTION;
extern char const * WATCH_ACTION;
extern char const * LEASEGRANT; extern char const* LEASEGRANT;
extern char const * LEASEREVOKE; extern char const* LEASEREVOKE;
extern char const * LEASEKEEPALIVE; extern char const* LEASEKEEPALIVE;
extern char const * LEASETIMETOLIVE; extern char const* LEASETIMETOLIVE;
extern char const * LEASELEASES; extern char const* LEASELEASES;
extern char const * CAMPAIGN_ACTION; extern char const* CAMPAIGN_ACTION;
extern char const * PROCLAIM_ACTION; extern char const* PROCLAIM_ACTION;
extern char const * LEADER_ACTION; extern char const* LEADER_ACTION;
extern char const * OBSERVE_ACTION; extern char const* OBSERVE_ACTION;
extern char const * RESIGN_ACTION; extern char const* RESIGN_ACTION;
extern std::string const NUL; extern std::string const NUL;
extern char const * KEEPALIVE_CREATE; extern char const* KEEPALIVE_CREATE;
extern char const * KEEPALIVE_WRITE; extern char const* KEEPALIVE_WRITE;
extern char const * KEEPALIVE_READ; extern char const* KEEPALIVE_READ;
extern char const * KEEPALIVE_DONE; extern char const* KEEPALIVE_DONE;
extern char const * KEEPALIVE_FINISH; extern char const* KEEPALIVE_FINISH;
extern char const * WATCH_CREATE; extern char const* WATCH_CREATE;
extern char const * WATCH_WRITE; extern char const* WATCH_WRITE;
extern char const * WATCH_WRITE_CANCEL; extern char const* WATCH_WRITE_CANCEL;
extern char const * WATCH_WRITES_DONE; extern char const* WATCH_WRITES_DONE;
extern char const * WATCH_FINISH; extern char const* WATCH_FINISH;
extern char const * ELECTION_OBSERVE_CREATE; extern char const* ELECTION_OBSERVE_CREATE;
extern char const * ELECTION_OBSERVE_FINISH; extern char const* ELECTION_OBSERVE_FINISH;
extern const int ERROR_GRPC_OK; extern const int ERROR_GRPC_OK;
extern const int ERROR_GRPC_CANCELLED; extern const int ERROR_GRPC_CANCELLED;
extern const int ERROR_GRPC_UNKNOWN; extern const int ERROR_GRPC_UNKNOWN;
extern const int ERROR_GRPC_INVALID_ARGUMENT; extern const int ERROR_GRPC_INVALID_ARGUMENT;
extern const int ERROR_GRPC_DEADLINE_EXCEEDED; extern const int ERROR_GRPC_DEADLINE_EXCEEDED;
extern const int ERROR_GRPC_NOT_FOUND; extern const int ERROR_GRPC_NOT_FOUND;
extern const int ERROR_GRPC_ALREADY_EXISTS; extern const int ERROR_GRPC_ALREADY_EXISTS;
extern const int ERROR_GRPC_PERMISSION_DENIED; extern const int ERROR_GRPC_PERMISSION_DENIED;
extern const int ERROR_GRPC_UNAUTHENTICATED; extern const int ERROR_GRPC_UNAUTHENTICATED;
extern const int ERROR_GRPC_RESOURCE_EXHAUSTED; extern const int ERROR_GRPC_RESOURCE_EXHAUSTED;
extern const int ERROR_GRPC_FAILED_PRECONDITION; extern const int ERROR_GRPC_FAILED_PRECONDITION;
extern const int ERROR_GRPC_ABORTED; extern const int ERROR_GRPC_ABORTED;
extern const int ERROR_GRPC_OUT_OF_RANGE; extern const int ERROR_GRPC_OUT_OF_RANGE;
extern const int ERROR_GRPC_UNIMPLEMENTED; extern const int ERROR_GRPC_UNIMPLEMENTED;
extern const int ERROR_GRPC_INTERNAL; extern const int ERROR_GRPC_INTERNAL;
extern const int ERROR_GRPC_UNAVAILABLE; extern const int ERROR_GRPC_UNAVAILABLE;
extern const int ERROR_GRPC_DATA_LOSS; extern const int ERROR_GRPC_DATA_LOSS;
extern const int ERROR_KEY_NOT_FOUND; extern const int ERROR_KEY_NOT_FOUND;
extern const int ERROR_COMPARE_FAILED; extern const int ERROR_COMPARE_FAILED;
extern const int ERROR_KEY_ALREADY_EXISTS; extern const int ERROR_KEY_ALREADY_EXISTS;
extern const int ERROR_ACTION_CANCELLED; extern const int ERROR_ACTION_CANCELLED;
} } // namespace etcdv3
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
#include "proto/rpc.grpc.pb.h" #include "proto/rpc.grpc.pb.h"
namespace etcdv3 { namespace etcdv3 {
class AsyncLeaseKeepAliveAction; class AsyncLeaseKeepAliveAction;
} }
struct etcd::KeepAlive::EtcdServerStubs { struct etcd::KeepAlive::EtcdServerStubs {
@ -16,15 +16,18 @@ struct etcd::KeepAlive::EtcdServerStubs {
std::unique_ptr<etcdv3::AsyncLeaseKeepAliveAction> call; std::unique_ptr<etcdv3::AsyncLeaseKeepAliveAction> call;
}; };
void etcd::KeepAlive::EtcdServerStubsDeleter::operator()(etcd::KeepAlive::EtcdServerStubs *stubs) { void etcd::KeepAlive::EtcdServerStubsDeleter::operator()(
etcd::KeepAlive::EtcdServerStubs* stubs) {
if (stubs) { if (stubs) {
delete stubs; delete stubs;
} }
} }
etcd::KeepAlive::KeepAlive(SyncClient const &client, int ttl, int64_t lease_id): etcd::KeepAlive::KeepAlive(SyncClient const& client, int ttl, int64_t lease_id)
ttl(ttl), lease_id(lease_id), continue_next(true), : ttl(ttl),
grpc_timeout(client.get_grpc_timeout()) { lease_id(lease_id),
continue_next(true),
grpc_timeout(client.get_grpc_timeout()) {
stubs.reset(new EtcdServerStubs{}); stubs.reset(new EtcdServerStubs{});
stubs->leaseServiceStub = Lease::NewStub(client.grpc_channel()); stubs->leaseServiceStub = Lease::NewStub(client.grpc_channel());
@ -41,38 +44,41 @@ etcd::KeepAlive::KeepAlive(SyncClient const &client, int ttl, int64_t lease_id):
try { try {
// start refresh // start refresh
this->refresh(); this->refresh();
} catch (const std::exception &e) { } catch (const std::exception& e) {
// propagate the exception // propagate the exception
eptr_ = std::current_exception(); eptr_ = std::current_exception();
} }
}); });
} }
etcd::KeepAlive::KeepAlive(std::string const & address, int ttl, int64_t lease_id): etcd::KeepAlive::KeepAlive(std::string const& address, int ttl,
KeepAlive(SyncClient(address), ttl, lease_id) { int64_t lease_id)
} : KeepAlive(SyncClient(address), ttl, lease_id) {}
etcd::KeepAlive::KeepAlive(std::string const & address, etcd::KeepAlive::KeepAlive(std::string const& address,
std::string const & username, std::string const & password, std::string const& username,
int ttl, int64_t lease_id, int const auth_token_ttl): std::string const& password, int ttl,
KeepAlive(SyncClient(address, username, password, auth_token_ttl), ttl, lease_id) { int64_t lease_id, int const auth_token_ttl)
} : KeepAlive(SyncClient(address, username, password, auth_token_ttl), ttl,
lease_id) {}
etcd::KeepAlive::KeepAlive(std::string const & address, etcd::KeepAlive::KeepAlive(
std::string const & ca, std::string const& address, std::string const& ca, std::string const& cert,
std::string const & cert, std::string const& privkey,
std::string const & privkey, std::function<void(std::exception_ptr)> const& handler, int ttl,
std::function<void (std::exception_ptr)> const &handler, int64_t lease_id, std::string const& target_name_override)
int ttl, int64_t lease_id, : KeepAlive(SyncClient(address, ca, cert, privkey, target_name_override),
std::string const & target_name_override): ttl, lease_id) {}
KeepAlive(SyncClient(address, ca, cert, privkey, target_name_override), ttl, lease_id) {
}
etcd::KeepAlive::KeepAlive(SyncClient const &client, etcd::KeepAlive::KeepAlive(
std::function<void (std::exception_ptr)> const &handler, SyncClient const& client,
int ttl, int64_t lease_id): std::function<void(std::exception_ptr)> const& handler, int ttl,
handler_(handler), ttl(ttl), lease_id(lease_id), continue_next(true), int64_t lease_id)
grpc_timeout(client.get_grpc_timeout()) { : handler_(handler),
ttl(ttl),
lease_id(lease_id),
continue_next(true),
grpc_timeout(client.get_grpc_timeout()) {
stubs.reset(new EtcdServerStubs{}); stubs.reset(new EtcdServerStubs{});
stubs->leaseServiceStub = Lease::NewStub(client.grpc_channel()); stubs->leaseServiceStub = Lease::NewStub(client.grpc_channel());
@ -97,26 +103,23 @@ etcd::KeepAlive::KeepAlive(SyncClient const &client,
}); });
} }
etcd::KeepAlive::KeepAlive(std::string const & address, etcd::KeepAlive::KeepAlive(
std::function<void (std::exception_ptr)> const &handler, std::string const& address,
int ttl, int64_t lease_id): std::function<void(std::exception_ptr)> const& handler, int ttl,
KeepAlive(SyncClient(address), handler, ttl, lease_id) { int64_t lease_id)
} : KeepAlive(SyncClient(address), handler, ttl, lease_id) {}
etcd::KeepAlive::KeepAlive(std::string const & address, etcd::KeepAlive::KeepAlive(
std::string const & username, std::string const & password, std::string const& address, std::string const& username,
std::function<void (std::exception_ptr)> const &handler, std::string const& password,
int ttl, int64_t lease_id, const int auth_token_ttl): std::function<void(std::exception_ptr)> const& handler, int ttl,
KeepAlive(SyncClient(address, username, password, auth_token_ttl), handler, ttl, lease_id) { int64_t lease_id, const int auth_token_ttl)
} : KeepAlive(SyncClient(address, username, password, auth_token_ttl),
handler, ttl, lease_id) {}
etcd::KeepAlive::~KeepAlive() etcd::KeepAlive::~KeepAlive() { this->Cancel(); }
{
this->Cancel();
}
void etcd::KeepAlive::Cancel() void etcd::KeepAlive::Cancel() {
{
if (!continue_next.exchange(false)) { if (!continue_next.exchange(false)) {
return; return;
} }
@ -143,7 +146,8 @@ void etcd::KeepAlive::Check() {
// run canceller first // run canceller first
this->Cancel(); this->Cancel();
// propagate the exception, as we throw in `Check()`, the `handler` won't be touched // propagate the exception, as we throw in `Check()`, the `handler` won't be
// touched
eptr_ = std::current_exception(); eptr_ = std::current_exception();
if (handler_) { if (handler_) {
handler_(eptr_); handler_(eptr_);
@ -154,8 +158,7 @@ void etcd::KeepAlive::Check() {
} }
} }
void etcd::KeepAlive::refresh() void etcd::KeepAlive::refresh() {
{
while (true) { while (true) {
if (!continue_next.load()) { if (!continue_next.load()) {
return; return;
@ -164,7 +167,8 @@ void etcd::KeepAlive::refresh()
int keepalive_ttl = std::max(ttl - 1, 1); int keepalive_ttl = std::max(ttl - 1, 1);
{ {
std::unique_lock<std::mutex> lock(mutex_for_refresh_); std::unique_lock<std::mutex> lock(mutex_for_refresh_);
if (cv_for_refresh_.wait_for(lock, std::chrono::seconds(keepalive_ttl)) == std::cv_status::no_timeout) { if (cv_for_refresh_.wait_for(lock, std::chrono::seconds(keepalive_ttl)) ==
std::cv_status::no_timeout) {
return; return;
} }
} }
@ -174,8 +178,7 @@ void etcd::KeepAlive::refresh()
} }
} }
void etcd::KeepAlive::refresh_once() void etcd::KeepAlive::refresh_once() {
{
std::lock_guard<std::mutex> scope_lock(mutex_for_refresh_); std::lock_guard<std::mutex> scope_lock(mutex_for_refresh_);
if (!continue_next.load()) { if (!continue_next.load()) {
return; return;
@ -183,10 +186,12 @@ void etcd::KeepAlive::refresh_once()
this->stubs->call->mutable_parameters().grpc_timeout = this->grpc_timeout; this->stubs->call->mutable_parameters().grpc_timeout = this->grpc_timeout;
auto resp = this->stubs->call->Refresh(); auto resp = this->stubs->call->Refresh();
if (!resp.is_ok()) { if (!resp.is_ok()) {
throw std::runtime_error("Failed to refresh lease: error code: " + std::to_string(resp.error_code()) + throw std::runtime_error("Failed to refresh lease: error code: " +
", message: " + resp.error_message()); std::to_string(resp.error_code()) +
", message: " + resp.error_message());
} }
if (resp.value().ttl() == 0) { if (resp.value().ttl() == 0) {
throw std::out_of_range("Failed to refresh lease due to expiration: the new TTL is 0."); throw std::out_of_range(
"Failed to refresh lease due to expiration: the new TTL is 0.");
} }
} }

View File

@ -3,13 +3,9 @@
#include <iostream> #include <iostream>
etcd::Response::Response() etcd::Response::Response() : _error_code(0), _index(0) {}
: _error_code(0),
_index(0)
{
}
etcd::Response::Response(const etcd::Response & response) { etcd::Response::Response(const etcd::Response& response) {
this->_error_code = response._error_code; this->_error_code = response._error_code;
this->_error_message = response._error_message; this->_error_message = response._error_message;
this->_index = response._index; this->_index = response._index;
@ -20,7 +16,7 @@ etcd::Response::Response(const etcd::Response & response) {
this->_keys = response._keys; this->_keys = response._keys;
this->_compact_revision = response._compact_revision; this->_compact_revision = response._compact_revision;
this->_lock_key = response._lock_key; this->_lock_key = response._lock_key;
this->_name = response._name; this->_name = response._name;
this->_events = response._events; this->_events = response._events;
this->_duration = response._duration; this->_duration = response._duration;
@ -31,23 +27,19 @@ etcd::Response::Response(const etcd::Response & response) {
this->_leases = response._leases; this->_leases = response._leases;
} }
etcd::Response::Response(const etcdv3::V3Response& reply, std::chrono::microseconds const& duration) etcd::Response::Response(const etcdv3::V3Response& reply,
{ std::chrono::microseconds const& duration) {
_index = reply.get_index(); _index = reply.get_index();
_action = reply.get_action(); _action = reply.get_action();
_error_code = reply.get_error_code(); _error_code = reply.get_error_code();
_error_message = reply.get_error_message(); _error_message = reply.get_error_message();
if(reply.has_values()) if (reply.has_values()) {
{
auto val = reply.get_values(); auto val = reply.get_values();
for(unsigned int index = 0; index < val.size(); index++) for (unsigned int index = 0; index < val.size(); index++) {
{
_values.push_back(Value(val[index])); _values.push_back(Value(val[index]));
_keys.push_back(val[index].kvs.key()); _keys.push_back(val[index].kvs.key());
} }
} } else {
else
{
_value = Value(reply.get_value()); _value = Value(reply.get_value());
} }
_prev_value = Value(reply.get_prev_value()); _prev_value = Value(reply.get_prev_value());
@ -57,7 +49,7 @@ etcd::Response::Response(const etcdv3::V3Response& reply, std::chrono::microseco
_lock_key = reply.get_lock_key(); _lock_key = reply.get_lock_key();
_name = reply.get_name(); _name = reply.get_name();
for (auto const &ev: reply.get_events()) { for (auto const& ev : reply.get_events()) {
_events.emplace_back(etcd::Event(ev)); _events.emplace_back(etcd::Event(ev));
} }
@ -74,103 +66,54 @@ etcd::Response::Response(const etcdv3::V3Response& reply, std::chrono::microseco
} }
etcd::Response::Response(int error_code, std::string const& error_message) etcd::Response::Response(int error_code, std::string const& error_message)
: _error_code(error_code), : _error_code(error_code), _error_message(error_message), _index(0) {}
_error_message(error_message),
_index(0)
{
}
etcd::Response::Response(int error_code, char const * error_message) etcd::Response::Response(int error_code, char const* error_message)
: _error_code(error_code), : _error_code(error_code), _error_message(error_message), _index(0) {}
_error_message(error_message),
_index(0)
{
}
int etcd::Response::error_code() const int etcd::Response::error_code() const { return _error_code; }
{
return _error_code;
}
std::string const & etcd::Response::error_message() const std::string const& etcd::Response::error_message() const {
{
return _error_message; return _error_message;
} }
bool etcd::Response::is_ok() const bool etcd::Response::is_ok() const { return error_code() == 0; }
{
return error_code() == 0;
}
bool etcd::Response::is_network_unavailable() const bool etcd::Response::is_network_unavailable() const {
{
return error_code() == ::grpc::StatusCode::UNAVAILABLE; return error_code() == ::grpc::StatusCode::UNAVAILABLE;
} }
bool etcd::Response::is_grpc_timeout() const bool etcd::Response::is_grpc_timeout() const {
{
return _error_code == grpc::StatusCode::DEADLINE_EXCEEDED; return _error_code == grpc::StatusCode::DEADLINE_EXCEEDED;
} }
std::string const & etcd::Response::action() const std::string const& etcd::Response::action() const { return _action; }
{
return _action;
}
int64_t etcd::Response::index() const int64_t etcd::Response::index() const { return _index; }
{
return _index;
}
etcd::Value const & etcd::Response::value() const etcd::Value const& etcd::Response::value() const { return _value; }
{
return _value;
}
etcd::Value const & etcd::Response::prev_value() const etcd::Value const& etcd::Response::prev_value() const { return _prev_value; }
{
return _prev_value;
}
etcd::Values const & etcd::Response::values() const etcd::Values const& etcd::Response::values() const { return _values; }
{
return _values;
}
etcd::Value const & etcd::Response::value(int index) const etcd::Value const& etcd::Response::value(int index) const {
{
return _values[index]; return _values[index];
} }
etcd::Keys const & etcd::Response::keys() const etcd::Keys const& etcd::Response::keys() const { return _keys; }
{
return _keys;
}
std::string const & etcd::Response::key(int index) const std::string const& etcd::Response::key(int index) const { return _keys[index]; }
{
return _keys[index];
}
int64_t etcd::Response::compact_revision() const int64_t etcd::Response::compact_revision() const { return _compact_revision; }
{
return _compact_revision;
}
int64_t etcd::Response::watch_id() const int64_t etcd::Response::watch_id() const { return _watch_id; }
{
return _watch_id;
}
std::string const & etcd::Response::lock_key() const { std::string const& etcd::Response::lock_key() const { return _lock_key; }
return _lock_key;
}
std::string const & etcd::Response::name() const { std::string const& etcd::Response::name() const { return _name; }
return _name;
}
std::vector<etcd::Event> const & etcd::Response::events() const { std::vector<etcd::Event> const& etcd::Response::events() const {
return this->_events; return this->_events;
} }
@ -178,18 +121,12 @@ std::chrono::microseconds const& etcd::Response::duration() const {
return this->_duration; return this->_duration;
} }
uint64_t etcd::Response::cluster_id() const { uint64_t etcd::Response::cluster_id() const { return this->_cluster_id; }
return this->_cluster_id;
}
uint64_t etcd::Response::member_id() const { uint64_t etcd::Response::member_id() const { return this->_member_id; }
return this->_member_id;
}
uint64_t etcd::Response::raft_term() const { uint64_t etcd::Response::raft_term() const { return this->_raft_term; }
return this->_raft_term;
}
std::vector<int64_t> const & etcd::Response::leases() const { std::vector<int64_t> const& etcd::Response::leases() const {
return this->_leases; return this->_leases;
} }

File diff suppressed because it is too large Load Diff

View File

@ -4,18 +4,9 @@
#include "etcd/v3/KeyValue.hpp" #include "etcd/v3/KeyValue.hpp"
etcd::Value::Value() etcd::Value::Value()
: dir(false), : dir(false), created(0), modified(0), _version(0), _ttl(0), leaseId(0) {}
created(0),
modified(0),
_version(0),
_ttl(0),
leaseId(0)
{
}
etcd::Value::Value(etcdv3::KeyValue const& kv) {
etcd::Value::Value(etcdv3::KeyValue const & kv)
{
dir = false; dir = false;
_key = kv.kvs.key(); _key = kv.kvs.key();
value = kv.kvs.value(); value = kv.kvs.value();
@ -26,8 +17,7 @@ etcd::Value::Value(etcdv3::KeyValue const & kv)
_ttl = kv.get_ttl(); _ttl = kv.get_ttl();
} }
etcd::Value::Value(mvccpb::KeyValue const & kv) etcd::Value::Value(mvccpb::KeyValue const& kv) {
{
dir = false; dir = false;
_key = kv.key(); _key = kv.key();
value = kv.value(); value = kv.value();
@ -38,47 +28,23 @@ etcd::Value::Value(mvccpb::KeyValue const & kv)
_ttl = -1; _ttl = -1;
} }
std::string const & etcd::Value::key() const std::string const& etcd::Value::key() const { return _key; }
{
return _key;
}
bool etcd::Value::is_dir() const bool etcd::Value::is_dir() const { return dir; }
{
return dir;
}
std::string const & etcd::Value::as_string() const std::string const& etcd::Value::as_string() const { return value; }
{
return value;
}
int64_t etcd::Value::created_index() const int64_t etcd::Value::created_index() const { return created; }
{
return created;
}
int64_t etcd::Value::modified_index() const int64_t etcd::Value::modified_index() const { return modified; }
{
return modified;
}
int64_t etcd::Value::version() const int64_t etcd::Value::version() const { return _version; }
{
return _version;
}
int etcd::Value::ttl() const int etcd::Value::ttl() const { return _ttl; }
{
return _ttl;
}
int64_t etcd::Value::lease() const int64_t etcd::Value::lease() const { return leaseId; }
{
return leaseId;
}
etcd::Event::Event(mvccpb::Event const & event) { etcd::Event::Event(mvccpb::Event const& event) {
_has_kv = event.has_kv(); _has_kv = event.has_kv();
_has_prev_kv = event.has_prev_kv(); _has_prev_kv = event.has_prev_kv();
if (_has_kv) { if (_has_kv) {
@ -100,18 +66,10 @@ enum etcd::Event::EventType etcd::Event::event_type() const {
return event_type_; return event_type_;
} }
bool etcd::Event::has_kv() const { bool etcd::Event::has_kv() const { return _has_kv; }
return _has_kv;
}
bool etcd::Event::has_prev_kv() const { bool etcd::Event::has_prev_kv() const { return _has_prev_kv; }
return _has_prev_kv;
}
const etcd::Value &etcd::Event::kv() const { const etcd::Value& etcd::Event::kv() const { return _kv; }
return _kv;
}
const etcd::Value &etcd::Event::prev_kv() const { const etcd::Value& etcd::Event::prev_kv() const { return _prev_kv; }
return _prev_kv;
}

View File

@ -9,7 +9,8 @@ struct etcd::Watcher::EtcdServerStubs {
std::unique_ptr<etcdv3::AsyncWatchAction> call; std::unique_ptr<etcdv3::AsyncWatchAction> call;
}; };
void etcd::Watcher::EtcdServerStubsDeleter::operator()(etcd::Watcher::EtcdServerStubs *stubs) { void etcd::Watcher::EtcdServerStubsDeleter::operator()(
etcd::Watcher::EtcdServerStubs* stubs) {
if (stubs) { if (stubs) {
if (stubs->watchServiceStub) { if (stubs->watchServiceStub) {
stubs->watchServiceStub.reset(); stubs->watchServiceStub.reset();
@ -21,239 +22,205 @@ void etcd::Watcher::EtcdServerStubsDeleter::operator()(etcd::Watcher::EtcdServer
} }
} }
etcd::Watcher::Watcher(SyncClient const &client, std::string const & key, etcd::Watcher::Watcher(SyncClient const& client, std::string const& key,
std::function<void(Response)> callback, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback, std::function<void(bool)> wait_callback, bool recursive)
bool recursive): : Watcher(client, key, -1, callback, wait_callback, recursive) {}
Watcher(client, key, -1, callback, wait_callback, recursive) {
}
etcd::Watcher::Watcher(SyncClient const &client, std::string const & key, etcd::Watcher::Watcher(SyncClient const& client, std::string const& key,
std::string const &range_end, std::string const& range_end,
std::function<void(Response)> callback, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback): std::function<void(bool)> wait_callback)
Watcher(client, key, range_end, -1, callback, wait_callback) { : Watcher(client, key, range_end, -1, callback, wait_callback) {}
}
etcd::Watcher::Watcher(SyncClient const &client, std::string const & key, int64_t fromIndex, etcd::Watcher::Watcher(SyncClient const& client, std::string const& key,
int64_t fromIndex,
std::function<void(Response)> callback, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback, std::function<void(bool)> wait_callback, bool recursive)
bool recursive): : wait_callback(wait_callback), fromIndex(fromIndex), recursive(recursive) {
wait_callback(wait_callback), fromIndex(fromIndex), recursive(recursive) {
stubs.reset(new EtcdServerStubs{}); stubs.reset(new EtcdServerStubs{});
stubs->watchServiceStub = Watch::NewStub(client.channel); stubs->watchServiceStub = Watch::NewStub(client.channel);
doWatch(key, "", client.current_auth_token(), callback); doWatch(key, "", client.current_auth_token(), callback);
} }
etcd::Watcher::Watcher(SyncClient const &client, std::string const & key, etcd::Watcher::Watcher(SyncClient const& client, std::string const& key,
std::string const &range_end, int64_t fromIndex, std::string const& range_end, int64_t fromIndex,
std::function<void(Response)> callback, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback): std::function<void(bool)> wait_callback)
wait_callback(wait_callback), fromIndex(fromIndex), recursive(false) { : wait_callback(wait_callback), fromIndex(fromIndex), recursive(false) {
stubs.reset(new EtcdServerStubs{}); stubs.reset(new EtcdServerStubs{});
stubs->watchServiceStub = Watch::NewStub(client.channel); stubs->watchServiceStub = Watch::NewStub(client.channel);
doWatch(key, range_end, client.current_auth_token(), callback); doWatch(key, range_end, client.current_auth_token(), callback);
} }
etcd::Watcher::Watcher(std::string const & address, std::string const & key, etcd::Watcher::Watcher(std::string const& address, std::string const& key,
std::function<void(Response)> callback,
std::function<void(bool)> wait_callback, bool recursive)
: Watcher(address, key, -1, callback, wait_callback, recursive) {}
etcd::Watcher::Watcher(std::string const& address, std::string const& key,
std::string const& range_end,
std::function<void(Response)> callback,
std::function<void(bool)> wait_callback)
: Watcher(address, key, range_end, -1, callback, wait_callback) {}
etcd::Watcher::Watcher(std::string const& address, std::string const& key,
int64_t fromIndex,
std::function<void(Response)> callback,
std::function<void(bool)> wait_callback, bool recursive)
: Watcher(SyncClient(address), key, fromIndex, callback, wait_callback,
recursive) {}
etcd::Watcher::Watcher(std::string const& address, std::string const& key,
std::string const& range_end, int64_t fromIndex,
std::function<void(Response)> callback,
std::function<void(bool)> wait_callback)
: Watcher(SyncClient(address), key, range_end, fromIndex, callback,
wait_callback) {}
etcd::Watcher::Watcher(std::string const& address, std::string const& username,
std::string const& password, std::string const& key,
std::function<void(Response)> callback,
std::function<void(bool)> wait_callback, bool recursive,
int const auth_token_ttl)
: Watcher(address, username, password, key, -1, callback, wait_callback,
recursive, auth_token_ttl) {}
etcd::Watcher::Watcher(std::string const& address, std::string const& username,
std::string const& password, std::string const& key,
std::string const& range_end,
std::function<void(Response)> callback, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback, std::function<void(bool)> wait_callback,
bool recursive): int const auth_token_ttl)
Watcher(address, key, -1, callback, wait_callback, recursive) { : Watcher(address, username, password, key, range_end, -1, callback,
} wait_callback, auth_token_ttl) {}
etcd::Watcher::Watcher(std::string const & address, std::string const & key, etcd::Watcher::Watcher(std::string const& address, std::string const& username,
std::string const & range_end, std::string const& password, std::string const& key,
int64_t fromIndex,
std::function<void(Response)> callback, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback): std::function<void(bool)> wait_callback, bool recursive,
Watcher(address, key, range_end, -1, callback, wait_callback) { int const auth_token_ttl)
} : Watcher(SyncClient(address, username, password, auth_token_ttl), key,
fromIndex, callback, wait_callback, recursive) {}
etcd::Watcher::Watcher(std::string const & address, std::string const & key, int64_t fromIndex, etcd::Watcher::Watcher(std::string const& address, std::string const& username,
std::string const& password, std::string const& key,
std::string const& range_end, int64_t fromIndex,
std::function<void(Response)> callback, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback, std::function<void(bool)> wait_callback,
bool recursive): int const auth_token_ttl)
Watcher(SyncClient(address), key, fromIndex, callback, wait_callback, recursive) { : Watcher(SyncClient(address, username, password, auth_token_ttl), key,
} range_end, fromIndex, callback, wait_callback) {}
etcd::Watcher::Watcher(std::string const & address, std::string const & key, etcd::Watcher::Watcher(std::string const& address, std::string const& ca,
std::string const & range_end, int64_t fromIndex, std::string const& cert, std::string const& privkey,
std::string const& key, int64_t fromIndex,
std::function<void(Response)> callback, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback): std::function<void(bool)> wait_callback, bool recursive,
Watcher(SyncClient(address), key, range_end, fromIndex, callback, wait_callback) { std::string const& target_name_override)
} : Watcher(SyncClient(address, ca, cert, privkey, target_name_override), key,
fromIndex, callback, wait_callback, recursive) {}
etcd::Watcher::Watcher(std::string const & address, etcd::Watcher::Watcher(std::string const& address, std::string const& ca,
std::string const & username, std::string const & password, std::string const& cert, std::string const& privkey,
std::string const & key, std::string const& key, std::string const& range_end,
int64_t fromIndex,
std::function<void(Response)> callback, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback, std::function<void(bool)> wait_callback,
bool recursive, std::string const& target_name_override)
int const auth_token_ttl): : Watcher(SyncClient(address, ca, cert, privkey, target_name_override), key,
Watcher(address, username, password, key, -1, callback, wait_callback, recursive, auth_token_ttl) { range_end, fromIndex, callback, wait_callback) {}
}
etcd::Watcher::Watcher(std::string const & address, etcd::Watcher::Watcher(SyncClient const& client, std::string const& key,
std::string const & username, std::string const & password, std::function<void(Response)> callback, bool recursive)
std::string const & key, std::string const & range_end, : Watcher(client, key, callback, nullptr, recursive) {}
etcd::Watcher::Watcher(SyncClient const& client, std::string const& key,
std::string const& range_end,
std::function<void(Response)> callback)
: Watcher(client, key, range_end, callback, nullptr) {}
etcd::Watcher::Watcher(SyncClient const& client, std::string const& key,
int64_t fromIndex,
std::function<void(Response)> callback, bool recursive)
: Watcher(client, key, fromIndex, callback, nullptr, recursive) {}
etcd::Watcher::Watcher(SyncClient const& client, std::string const& key,
std::string const& range_end, int64_t fromIndex,
std::function<void(Response)> callback)
: Watcher(client, key, range_end, fromIndex, callback, nullptr) {}
etcd::Watcher::Watcher(std::string const& address, std::string const& key,
std::function<void(Response)> callback, bool recursive)
: Watcher(address, key, callback, nullptr, recursive) {}
etcd::Watcher::Watcher(std::string const& address, std::string const& key,
std::string const& range_end,
std::function<void(Response)> callback)
: Watcher(address, key, range_end, callback, nullptr) {}
etcd::Watcher::Watcher(std::string const& address, std::string const& key,
int64_t fromIndex,
std::function<void(Response)> callback, bool recursive)
: Watcher(address, key, fromIndex, callback, nullptr, recursive) {}
etcd::Watcher::Watcher(std::string const& address, std::string const& key,
std::string const& range_end, int64_t fromIndex,
std::function<void(Response)> callback)
: Watcher(address, key, range_end, fromIndex, callback, nullptr) {}
etcd::Watcher::Watcher(std::string const& address, std::string const& username,
std::string const& password, std::string const& key,
std::function<void(Response)> callback, bool recursive,
int const auth_token_ttl)
: Watcher(address, username, password, key, callback, nullptr, recursive,
auth_token_ttl) {}
etcd::Watcher::Watcher(std::string const& address, std::string const& username,
std::string const& password, std::string const& key,
std::string const& range_end,
std::function<void(Response)> callback, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback, int const auth_token_ttl)
int const auth_token_ttl): : Watcher(address, username, password, key, range_end, callback, nullptr,
Watcher(address, username, password, key, range_end, -1, callback, wait_callback, auth_token_ttl) { auth_token_ttl) {}
}
etcd::Watcher::Watcher(std::string const & address, etcd::Watcher::Watcher(std::string const& address, std::string const& username,
std::string const & username, std::string const & password, std::string const& password, std::string const& key,
std::string const & key, int64_t fromIndex, int64_t fromIndex,
std::function<void(Response)> callback, bool recursive,
int const auth_token_ttl)
: Watcher(address, username, password, key, fromIndex, callback, nullptr,
recursive, auth_token_ttl) {}
etcd::Watcher::Watcher(std::string const& address, std::string const& username,
std::string const& password, std::string const& key,
std::string const& range_end, int64_t fromIndex,
std::function<void(Response)> callback, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback, int const auth_token_ttl)
bool recursive, : Watcher(address, username, password, key, range_end, fromIndex, callback,
int const auth_token_ttl): nullptr, auth_token_ttl) {}
Watcher(SyncClient(address, username, password, auth_token_ttl), key, fromIndex, callback, wait_callback, recursive) {
}
etcd::Watcher::Watcher(std::string const & address, etcd::Watcher::Watcher(std::string const& address, std::string const& ca,
std::string const & username, std::string const & password, std::string const& cert, std::string const& privkey,
std::string const & key, std::string const & range_end, int64_t fromIndex, std::string const& key, int64_t fromIndex,
std::function<void(Response)> callback, bool recursive,
std::string const& target_name_override)
: Watcher(address, ca, cert, privkey, key, fromIndex, callback, nullptr,
recursive, target_name_override) {}
etcd::Watcher::Watcher(std::string const& address, std::string const& ca,
std::string const& cert, std::string const& privkey,
std::string const& key, std::string const& range_end,
int64_t fromIndex,
std::function<void(Response)> callback, std::function<void(Response)> callback,
std::function<void(bool)> wait_callback, std::string const& target_name_override)
int const auth_token_ttl): : Watcher(address, ca, cert, privkey, key, range_end, fromIndex, callback,
Watcher(SyncClient(address, username, password, auth_token_ttl), key, range_end, fromIndex, callback, wait_callback) { nullptr, target_name_override) {}
}
etcd::Watcher::Watcher(std::string const & address, etcd::Watcher::~Watcher() { this->Cancel(); }
std::string const & ca,
std::string const & cert,
std::string const & privkey,
std::string const & key, int64_t fromIndex,
std::function<void(Response)> callback,
std::function<void(bool)> wait_callback,
bool recursive,
std::string const & target_name_override):
Watcher(SyncClient(address, ca, cert, privkey, target_name_override), key, fromIndex, callback, wait_callback, recursive) {
}
etcd::Watcher::Watcher(std::string const & address, bool etcd::Watcher::Wait() {
std::string const & ca,
std::string const & cert,
std::string const & privkey,
std::string const & key, std::string const & range_end, int64_t fromIndex,
std::function<void(Response)> callback,
std::function<void(bool)> wait_callback,
std::string const & target_name_override):
Watcher(SyncClient(address, ca, cert, privkey, target_name_override), key, range_end, fromIndex, callback, wait_callback) {
}
etcd::Watcher::Watcher(SyncClient const &client, std::string const & key,
std::function<void(Response)> callback,
bool recursive):
Watcher(client, key, callback, nullptr, recursive) {
}
etcd::Watcher::Watcher(SyncClient const &client, std::string const & key,
std::string const &range_end,
std::function<void(Response)> callback):
Watcher(client, key, range_end, callback, nullptr) {
}
etcd::Watcher::Watcher(SyncClient const &client, std::string const & key, int64_t fromIndex,
std::function<void(Response)> callback,
bool recursive):
Watcher(client, key, fromIndex, callback, nullptr, recursive) {
}
etcd::Watcher::Watcher(SyncClient const &client, std::string const & key,
std::string const &range_end, int64_t fromIndex,
std::function<void(Response)> callback):
Watcher(client, key, range_end, fromIndex, callback, nullptr) {
}
etcd::Watcher::Watcher(std::string const & address, std::string const & key,
std::function<void(Response)> callback,
bool recursive):
Watcher(address, key, callback, nullptr, recursive) {
}
etcd::Watcher::Watcher(std::string const & address, std::string const & key,
std::string const &range_end,
std::function<void(Response)> callback):
Watcher(address, key, range_end, callback, nullptr) {
}
etcd::Watcher::Watcher(std::string const & address, std::string const & key, int64_t fromIndex,
std::function<void(Response)> callback,
bool recursive):
Watcher(address, key, fromIndex, callback, nullptr, recursive) {
}
etcd::Watcher::Watcher(std::string const & address, std::string const & key,
std::string const &range_end, int64_t fromIndex,
std::function<void(Response)> callback):
Watcher(address, key, range_end, fromIndex, callback, nullptr) {
}
etcd::Watcher::Watcher(std::string const & address,
std::string const & username, std::string const & password,
std::string const & key,
std::function<void(Response)> callback,
bool recursive,
int const auth_token_ttl):
Watcher(address, username, password, key, callback, nullptr, recursive, auth_token_ttl) {
}
etcd::Watcher::Watcher(std::string const & address,
std::string const & username, std::string const & password,
std::string const & key, std::string const &range_end,
std::function<void(Response)> callback,
int const auth_token_ttl):
Watcher(address, username, password, key, range_end, callback, nullptr, auth_token_ttl) {
}
etcd::Watcher::Watcher(std::string const & address,
std::string const & username, std::string const & password,
std::string const & key, int64_t fromIndex,
std::function<void(Response)> callback,
bool recursive,
int const auth_token_ttl):
Watcher(address, username, password, key, fromIndex, callback, nullptr, recursive, auth_token_ttl) {
}
etcd::Watcher::Watcher(std::string const & address,
std::string const & username, std::string const & password,
std::string const & key, std::string const &range_end, int64_t fromIndex,
std::function<void(Response)> callback,
int const auth_token_ttl):
Watcher(address, username, password, key, range_end, fromIndex, callback, nullptr, auth_token_ttl) {
}
etcd::Watcher::Watcher(std::string const & address,
std::string const & ca,
std::string const & cert,
std::string const & privkey,
std::string const & key, int64_t fromIndex,
std::function<void(Response)> callback,
bool recursive,
std::string const & target_name_override):
Watcher(address, ca, cert, privkey, key, fromIndex, callback, nullptr, recursive, target_name_override) {
}
etcd::Watcher::Watcher(std::string const & address,
std::string const & ca,
std::string const & cert,
std::string const & privkey,
std::string const & key, std::string const &range_end, int64_t fromIndex,
std::function<void(Response)> callback,
std::string const & target_name_override):
Watcher(address, ca, cert, privkey, key, range_end, fromIndex, callback, nullptr, target_name_override) {
}
etcd::Watcher::~Watcher()
{
this->Cancel();
}
bool etcd::Watcher::Wait()
{
if (!cancelled.exchange(true)) { if (!cancelled.exchange(true)) {
if (task_.joinable()) { if (task_.joinable()) {
task_.join(); task_.join();
@ -262,31 +229,29 @@ bool etcd::Watcher::Wait()
return stubs->call->Cancelled(); return stubs->call->Cancelled();
} }
void etcd::Watcher::Wait(std::function<void(bool)> callback) void etcd::Watcher::Wait(std::function<void(bool)> callback) {
{
if (wait_callback == nullptr) { if (wait_callback == nullptr) {
wait_callback = callback; wait_callback = callback;
} else { } else {
std::cerr << "Failed to set a asynchronous wait callback since it has already been set" << std::endl; std::cerr << "Failed to set a asynchronous wait callback since it has "
"already been set"
<< std::endl;
} }
} }
bool etcd::Watcher::Cancel() bool etcd::Watcher::Cancel() {
{
stubs->call->CancelWatch(); stubs->call->CancelWatch();
return this->Wait(); return this->Wait();
} }
bool etcd::Watcher::Cancelled() const bool etcd::Watcher::Cancelled() const {
{
return cancelled.load() || stubs->call->Cancelled(); return cancelled.load() || stubs->call->Cancelled();
} }
void etcd::Watcher::doWatch(std::string const & key, void etcd::Watcher::doWatch(std::string const& key,
std::string const & range_end, std::string const& range_end,
std::string const & auth_token, std::string const& auth_token,
std::function<void(Response)> callback) std::function<void(Response)> callback) {
{
etcdv3::ActionParameters params; etcdv3::ActionParameters params;
params.auth_token.assign(auth_token); params.auth_token.assign(auth_token);
// n.b.: watch: no need for timeout // n.b.: watch: no need for timeout
@ -304,13 +269,12 @@ void etcd::Watcher::doWatch(std::string const & key,
stubs->call->waitForResponse(callback); stubs->call->waitForResponse(callback);
if (wait_callback != nullptr) { if (wait_callback != nullptr) {
// issue the callback in another thread (detached) to avoid deadlock, // issue the callback in another thread (detached) to avoid deadlock,
// it is ok to detach a pplx::task, but we don't want to use the pplx::task // it is ok to detach a pplx::task, but we don't want to use the
// in the core library // pplx::task in the core library
bool cancelled = stubs->call->Cancelled(); bool cancelled = stubs->call->Cancelled();
std::function<void(bool)> wait_callback = this->wait_callback; std::function<void(bool)> wait_callback = this->wait_callback;
std::thread canceller([wait_callback, cancelled]() { std::thread canceller(
wait_callback(cancelled); [wait_callback, cancelled]() { wait_callback(cancelled); });
});
canceller.detach(); canceller.detach();
} }
}); });

View File

@ -1,16 +1,14 @@
#include "etcd/v3/Action.hpp"
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpcpp/support/status.h> #include <grpcpp/support/status.h>
#include "etcd/v3/action_constants.hpp" #include "etcd/v3/action_constants.hpp"
#include "etcd/v3/Action.hpp"
etcdv3::Action::Action(etcdv3::ActionParameters const &params) etcdv3::Action::Action(etcdv3::ActionParameters const& params) {
{
parameters = params; parameters = params;
this->InitAction(); this->InitAction();
} }
etcdv3::Action::Action(etcdv3::ActionParameters && params) etcdv3::Action::Action(etcdv3::ActionParameters&& params) {
{
parameters = std::move(params); parameters = std::move(params);
this->InitAction(); this->InitAction();
} }
@ -32,8 +30,7 @@ void etcdv3::Action::InitAction() {
start_timepoint = std::chrono::high_resolution_clock::now(); start_timepoint = std::chrono::high_resolution_clock::now();
} }
etcdv3::ActionParameters::ActionParameters() etcdv3::ActionParameters::ActionParameters() {
{
withPrefix = false; withPrefix = false;
revision = 0; revision = 0;
old_revision = 0; old_revision = 0;
@ -50,11 +47,12 @@ bool etcdv3::ActionParameters::has_grpc_timeout() const {
return this->grpc_timeout != std::chrono::microseconds::zero(); return this->grpc_timeout != std::chrono::microseconds::zero();
} }
std::chrono::system_clock::time_point etcdv3::ActionParameters::grpc_deadline() const { std::chrono::system_clock::time_point etcdv3::ActionParameters::grpc_deadline()
const {
return std::chrono::system_clock::now() + this->grpc_timeout; return std::chrono::system_clock::now() + this->grpc_timeout;
} }
void etcdv3::ActionParameters::dump(std::ostream &os) const { void etcdv3::ActionParameters::dump(std::ostream& os) const {
os << "ActionParameters:" << std::endl; os << "ActionParameters:" << std::endl;
os << " withPrefix: " << withPrefix << std::endl; os << " withPrefix: " << withPrefix << std::endl;
os << " revision: " << revision << std::endl; os << " revision: " << revision << std::endl;
@ -73,39 +71,43 @@ void etcdv3::ActionParameters::dump(std::ostream &os) const {
os << " grpc_timeout: " << grpc_timeout.count() << "(ms)" << std::endl; os << " grpc_timeout: " << grpc_timeout.count() << "(ms)" << std::endl;
} }
void etcdv3::Action::waitForResponse() void etcdv3::Action::waitForResponse() {
{
void* got_tag; void* got_tag;
bool ok = false; bool ok = false;
if (parameters.has_grpc_timeout()) { if (parameters.has_grpc_timeout()) {
switch (cq_.AsyncNext(&got_tag, &ok, parameters.grpc_deadline())) { switch (cq_.AsyncNext(&got_tag, &ok, parameters.grpc_deadline())) {
case CompletionQueue::NextStatus::TIMEOUT: { case CompletionQueue::NextStatus::TIMEOUT: {
status = grpc::Status(grpc::StatusCode::DEADLINE_EXCEEDED, "gRPC timeout"); status =
break; grpc::Status(grpc::StatusCode::DEADLINE_EXCEEDED, "gRPC timeout");
} break;
case CompletionQueue::NextStatus::SHUTDOWN: { }
status = grpc::Status(grpc::StatusCode::UNAVAILABLE, "gRPC already shutdown"); case CompletionQueue::NextStatus::SHUTDOWN: {
break; status =
} grpc::Status(grpc::StatusCode::UNAVAILABLE, "gRPC already shutdown");
case CompletionQueue::NextStatus::GOT_EVENT: { break;
if (!ok) { }
status = grpc::Status(grpc::StatusCode::ABORTED, "Failed to execute the action: not ok or invalid tag"); case CompletionQueue::NextStatus::GOT_EVENT: {
} if (!ok) {
break; status =
grpc::Status(grpc::StatusCode::ABORTED,
"Failed to execute the action: not ok or invalid tag");
} }
break;
}
} }
} else { } else {
cq_.Next(&got_tag, &ok); cq_.Next(&got_tag, &ok);
GPR_ASSERT(got_tag == (void*)this); GPR_ASSERT(got_tag == (void*) this);
} }
} }
const std::chrono::high_resolution_clock::time_point etcdv3::Action::startTimepoint() { const std::chrono::high_resolution_clock::time_point
etcdv3::Action::startTimepoint() {
return this->start_timepoint; return this->start_timepoint;
} }
std::string etcdv3::detail::string_plus_one(std::string const &value) { std::string etcdv3::detail::string_plus_one(std::string const& value) {
// Referred from the Go implementation in etcd. // Referred from the Go implementation in etcd.
for (int32_t i = value.size() - 1; i >= 0; --i) { for (int32_t i = value.size() - 1; i >= 0; --i) {
if (static_cast<unsigned char>(value[i]) < 0xff) { if (static_cast<unsigned char>(value[i]) < 0xff) {
@ -117,7 +119,8 @@ std::string etcdv3::detail::string_plus_one(std::string const &value) {
return {etcdv3::NUL}; return {etcdv3::NUL};
} }
std::string etcdv3::detail::resolve_etcd_endpoints(std::string const&default_endpoints) { std::string etcdv3::detail::resolve_etcd_endpoints(
const char *ep = std::getenv("ETCD_ENDPOINTS"); std::string const& default_endpoints) {
const char* ep = std::getenv("ETCD_ENDPOINTS");
return ep ? ep : default_endpoints; return ep ? ep : default_endpoints;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,7 @@
#include "etcd/v3/KeyValue.hpp" #include "etcd/v3/KeyValue.hpp"
etcdv3::KeyValue::KeyValue() etcdv3::KeyValue::KeyValue() { ttl = 0; }
{
ttl = 0;
}
void etcdv3::KeyValue::set_ttl(int ttl) void etcdv3::KeyValue::set_ttl(int ttl) { this->ttl = ttl; }
{
this->ttl = ttl;
}
int etcdv3::KeyValue::get_ttl() const int etcdv3::KeyValue::get_ttl() const { return ttl; }
{
return ttl;
}

View File

@ -3,199 +3,210 @@
#include "proto/rpc.grpc.pb.h" #include "proto/rpc.grpc.pb.h"
using etcdserverpb::Compare; using etcdserverpb::Compare;
using etcdserverpb::RangeRequest;
using etcdserverpb::PutRequest;
using etcdserverpb::RequestOp;
using etcdserverpb::DeleteRangeRequest; using etcdserverpb::DeleteRangeRequest;
using etcdserverpb::PutRequest;
using etcdserverpb::RangeRequest;
using etcdserverpb::RequestOp;
namespace etcdv3 { namespace etcdv3 {
namespace detail { namespace detail {
static etcdserverpb::Compare::CompareResult to_compare_result(CompareResult r) { static etcdserverpb::Compare::CompareResult to_compare_result(CompareResult r) {
return static_cast<etcdserverpb::Compare::CompareResult>(static_cast<int>(r)); return static_cast<etcdserverpb::Compare::CompareResult>(static_cast<int>(r));
} }
static etcdserverpb::Compare::CompareTarget to_compare_target(CompareTarget t) { static etcdserverpb::Compare::CompareTarget to_compare_target(CompareTarget t) {
return static_cast<etcdserverpb::Compare::CompareTarget>(static_cast<int>(t)); return static_cast<etcdserverpb::Compare::CompareTarget>(static_cast<int>(t));
} }
} } // namespace detail
} } // namespace etcdv3
etcdv3::Transaction::Transaction() { etcdv3::Transaction::Transaction() {
txn_request.reset(new etcdserverpb::TxnRequest{}); txn_request.reset(new etcdserverpb::TxnRequest{});
} }
etcdv3::Transaction::Transaction(const std::string& key) : key(key) { etcdv3::Transaction::Transaction(const std::string& key) : key(key) {
txn_request.reset(new etcdserverpb::TxnRequest{}); txn_request.reset(new etcdserverpb::TxnRequest{});
} }
void etcdv3::Transaction::reset_key(std::string const& newkey) { void etcdv3::Transaction::reset_key(std::string const& newkey) { key = newkey; }
key = newkey;
void etcdv3::Transaction::init_compare(CompareResult result,
CompareTarget target) {
Compare* compare = txn_request->add_compare();
compare->set_result(detail::to_compare_result(result));
compare->set_target(detail::to_compare_target(target));
compare->set_key(key);
compare->set_version(0);
} }
void etcdv3::Transaction::init_compare(CompareResult result, CompareTarget target){ void etcdv3::Transaction::init_compare(std::string const& old_value,
Compare* compare = txn_request->add_compare(); CompareResult result,
compare->set_result(detail::to_compare_result(result)); CompareTarget target) {
compare->set_target(detail::to_compare_target(target)); Compare* compare = txn_request->add_compare();
compare->set_key(key); compare->set_result(detail::to_compare_result(result));
compare->set_target(detail::to_compare_target(target));
compare->set_key(key);
compare->set_version(0); compare->set_value(old_value);
} }
void etcdv3::Transaction::init_compare(std::string const& old_value, CompareResult result, CompareTarget target){ void etcdv3::Transaction::init_compare(int64_t old_index, CompareResult result,
Compare* compare = txn_request->add_compare(); CompareTarget target) {
compare->set_result(detail::to_compare_result(result)); Compare* compare = txn_request->add_compare();
compare->set_target(detail::to_compare_target(target)); compare->set_result(detail::to_compare_result(result));
compare->set_key(key); compare->set_target(detail::to_compare_target(target));
compare->set_key(key);
compare->set_value(old_value); compare->set_mod_revision(old_index);
}
void etcdv3::Transaction::init_compare(int64_t old_index, CompareResult result, CompareTarget target){
Compare* compare = txn_request->add_compare();
compare->set_result(detail::to_compare_result(result));
compare->set_target(detail::to_compare_target(target));
compare->set_key(key);
compare->set_mod_revision(old_index);
} }
/** /**
* get key on failure * get key on failure
*/ */
void etcdv3::Transaction::setup_basic_failure_operation(std::string const& key) { void etcdv3::Transaction::setup_basic_failure_operation(
std::unique_ptr<RangeRequest> get_request(new RangeRequest()); std::string const& key) {
get_request->set_key(key); std::unique_ptr<RangeRequest> get_request(new RangeRequest());
RequestOp* req_failure = txn_request->add_failure(); get_request->set_key(key);
req_failure->set_allocated_request_range(get_request.release()); RequestOp* req_failure = txn_request->add_failure();
req_failure->set_allocated_request_range(get_request.release());
} }
/** /**
* get key on failure, get key before put, modify and then get updated key * get key on failure, get key before put, modify and then get updated key
*/ */
void etcdv3::Transaction::setup_set_failure_operation(std::string const &key, std::string const &value, int64_t leaseid) { void etcdv3::Transaction::setup_set_failure_operation(std::string const& key,
std::unique_ptr<PutRequest> put_request(new PutRequest()); std::string const& value,
put_request->set_key(key); int64_t leaseid) {
put_request->set_value(value); std::unique_ptr<PutRequest> put_request(new PutRequest());
put_request->set_prev_kv(true); put_request->set_key(key);
put_request->set_lease(leaseid); put_request->set_value(value);
RequestOp* req_failure = txn_request->add_failure(); put_request->set_prev_kv(true);
req_failure->set_allocated_request_put(put_request.release()); put_request->set_lease(leaseid);
RequestOp* req_failure = txn_request->add_failure();
req_failure->set_allocated_request_put(put_request.release());
std::unique_ptr<RangeRequest> get_request(new RangeRequest()); std::unique_ptr<RangeRequest> get_request(new RangeRequest());
get_request->set_key(key); get_request->set_key(key);
req_failure = txn_request->add_failure(); req_failure = txn_request->add_failure();
req_failure->set_allocated_request_range(get_request.release()); req_failure->set_allocated_request_range(get_request.release());
} }
/** /**
* add key and then get new value of key * add key and then get new value of key
*/ */
void etcdv3::Transaction::setup_basic_create_sequence(std::string const& key, std::string const& value, int64_t leaseid) { void etcdv3::Transaction::setup_basic_create_sequence(std::string const& key,
std::unique_ptr<PutRequest> put_request(new PutRequest()); std::string const& value,
put_request->set_key(key); int64_t leaseid) {
put_request->set_value(value); std::unique_ptr<PutRequest> put_request(new PutRequest());
put_request->set_prev_kv(true); put_request->set_key(key);
put_request->set_lease(leaseid); put_request->set_value(value);
RequestOp* req_success = txn_request->add_success(); put_request->set_prev_kv(true);
req_success->set_allocated_request_put(put_request.release()); put_request->set_lease(leaseid);
RequestOp* req_success = txn_request->add_success();
req_success->set_allocated_request_put(put_request.release());
std::unique_ptr<RangeRequest> get_request(new RangeRequest()); std::unique_ptr<RangeRequest> get_request(new RangeRequest());
get_request->set_key(key); get_request->set_key(key);
req_success = txn_request->add_success(); req_success = txn_request->add_success();
req_success->set_allocated_request_range(get_request.release()); req_success->set_allocated_request_range(get_request.release());
} }
/** /**
* get key value then modify and get new value * get key value then modify and get new value
*/ */
void etcdv3::Transaction::setup_compare_and_swap_sequence(std::string const& value, int64_t leaseid) { void etcdv3::Transaction::setup_compare_and_swap_sequence(
std::unique_ptr<PutRequest> put_request(new PutRequest()); std::string const& value, int64_t leaseid) {
put_request->set_key(key); std::unique_ptr<PutRequest> put_request(new PutRequest());
put_request->set_value(value); put_request->set_key(key);
put_request->set_prev_kv(true); put_request->set_value(value);
put_request->set_lease(leaseid); put_request->set_prev_kv(true);
RequestOp* req_success = txn_request->add_success(); put_request->set_lease(leaseid);
req_success->set_allocated_request_put(put_request.release()); RequestOp* req_success = txn_request->add_success();
req_success->set_allocated_request_put(put_request.release());
std::unique_ptr<RangeRequest> get_request(new RangeRequest()); std::unique_ptr<RangeRequest> get_request(new RangeRequest());
get_request->set_key(key); get_request->set_key(key);
req_success = txn_request->add_success(); req_success = txn_request->add_success();
req_success->set_allocated_request_range(get_request.release()); req_success->set_allocated_request_range(get_request.release());
} }
/** /**
* get key, delete * get key, delete
*/ */
void etcdv3::Transaction::setup_delete_sequence(std::string const &key, std::string const &range_end, bool recursive) { void etcdv3::Transaction::setup_delete_sequence(std::string const& key,
std::unique_ptr<DeleteRangeRequest> del_request(new DeleteRangeRequest()); std::string const& range_end,
del_request->set_key(key); bool recursive) {
del_request->set_prev_kv(true); std::unique_ptr<DeleteRangeRequest> del_request(new DeleteRangeRequest());
if(recursive) del_request->set_key(key);
{ del_request->set_prev_kv(true);
del_request->set_range_end(range_end); if (recursive) {
} del_request->set_range_end(range_end);
}
RequestOp* req_success = txn_request->add_success(); RequestOp* req_success = txn_request->add_success();
req_success->set_allocated_request_delete_range(del_request.release()); req_success->set_allocated_request_delete_range(del_request.release());
} }
/** /**
* get key, delete * get key, delete
*/ */
void etcdv3::Transaction::setup_delete_failure_operation(std::string const &key, std::string const &range_end, bool recursive) { void etcdv3::Transaction::setup_delete_failure_operation(
std::unique_ptr<RangeRequest> get_request(new RangeRequest()); std::string const& key, std::string const& range_end, bool recursive) {
std::unique_ptr<DeleteRangeRequest> del_request(new DeleteRangeRequest()); std::unique_ptr<RangeRequest> get_request(new RangeRequest());
get_request.reset(new RangeRequest()); std::unique_ptr<DeleteRangeRequest> del_request(new DeleteRangeRequest());
get_request->set_key(key); get_request.reset(new RangeRequest());
if(recursive) get_request->set_key(key);
{ if (recursive) {
get_request->set_range_end(range_end); get_request->set_range_end(range_end);
get_request->set_sort_target(RangeRequest::SortTarget::RangeRequest_SortTarget_KEY); get_request->set_sort_target(
get_request->set_sort_order(RangeRequest::SortOrder::RangeRequest_SortOrder_ASCEND); RangeRequest::SortTarget::RangeRequest_SortTarget_KEY);
} get_request->set_sort_order(
RequestOp* req_failure = txn_request->add_failure(); RangeRequest::SortOrder::RangeRequest_SortOrder_ASCEND);
req_failure->set_allocated_request_range(get_request.release()); }
RequestOp* req_failure = txn_request->add_failure();
req_failure->set_allocated_request_range(get_request.release());
del_request.reset(new DeleteRangeRequest()); del_request.reset(new DeleteRangeRequest());
del_request->set_key(key); del_request->set_key(key);
if(recursive) if (recursive) {
{ del_request->set_range_end(range_end);
del_request->set_range_end(range_end); }
}
req_failure = txn_request->add_failure(); req_failure = txn_request->add_failure();
req_failure->set_allocated_request_delete_range(del_request.release()); req_failure->set_allocated_request_delete_range(del_request.release());
} }
void etcdv3::Transaction::setup_compare_and_delete_operation(std::string const& key) { void etcdv3::Transaction::setup_compare_and_delete_operation(
std::unique_ptr<DeleteRangeRequest> del_request(new DeleteRangeRequest()); std::string const& key) {
del_request->set_key(key); std::unique_ptr<DeleteRangeRequest> del_request(new DeleteRangeRequest());
del_request->set_prev_kv(true); del_request->set_key(key);
RequestOp* req_success = txn_request->add_success(); del_request->set_prev_kv(true);
req_success->set_allocated_request_delete_range(del_request.release()); RequestOp* req_success = txn_request->add_success();
req_success->set_allocated_request_delete_range(del_request.release());
} }
void etcdv3::Transaction::setup_put(std::string const &key, std::string const &value) { void etcdv3::Transaction::setup_put(std::string const& key,
std::unique_ptr<PutRequest> put_request(new PutRequest()); std::string const& value) {
put_request->set_key(key); std::unique_ptr<PutRequest> put_request(new PutRequest());
put_request->set_value(value); put_request->set_key(key);
put_request->set_prev_kv(false); put_request->set_value(value);
RequestOp* req_success = txn_request->add_success(); put_request->set_prev_kv(false);
req_success->set_allocated_request_put(put_request.release()); RequestOp* req_success = txn_request->add_success();
req_success->set_allocated_request_put(put_request.release());
} }
void etcdv3::Transaction::setup_delete(std::string const &key) { void etcdv3::Transaction::setup_delete(std::string const& key) {
std::unique_ptr<DeleteRangeRequest> del_request(new DeleteRangeRequest()); std::unique_ptr<DeleteRangeRequest> del_request(new DeleteRangeRequest());
del_request->set_key(key); del_request->set_key(key);
del_request->set_prev_kv(false); del_request->set_prev_kv(false);
RequestOp* req_success = txn_request->add_success(); RequestOp* req_success = txn_request->add_success();
req_success->set_allocated_request_delete_range(del_request.release()); req_success->set_allocated_request_delete_range(del_request.release());
} }
etcdv3::Transaction::~Transaction() { etcdv3::Transaction::~Transaction() {}
}

View File

@ -1,118 +1,81 @@
#include "etcd/v3/V3Response.hpp" #include "etcd/v3/V3Response.hpp"
#include "etcd/v3/action_constants.hpp" #include "etcd/v3/action_constants.hpp"
void etcdv3::V3Response::set_error_code(int code) void etcdv3::V3Response::set_error_code(int code) { error_code = code; }
{
error_code = code;
}
void etcdv3::V3Response::set_error_message(std::string msg) void etcdv3::V3Response::set_error_message(std::string msg) {
{
error_message = msg; error_message = msg;
} }
int64_t etcdv3::V3Response::get_index() const int64_t etcdv3::V3Response::get_index() const { return index; }
{
return index;
}
std::string const & etcdv3::V3Response::get_action() const std::string const& etcdv3::V3Response::get_action() const { return action; }
{
return action;
}
int etcdv3::V3Response::get_error_code() const int etcdv3::V3Response::get_error_code() const { return error_code; }
{
return error_code;
}
std::string const & etcdv3::V3Response::get_error_message() const std::string const& etcdv3::V3Response::get_error_message() const {
{
return error_message; return error_message;
} }
void etcdv3::V3Response::set_action(std::string action) void etcdv3::V3Response::set_action(std::string action) {
{
this->action = action; this->action = action;
} }
std::vector<etcdv3::KeyValue> const & etcdv3::V3Response::get_values() const std::vector<etcdv3::KeyValue> const& etcdv3::V3Response::get_values() const {
{
return values; return values;
} }
std::vector<etcdv3::KeyValue> const & etcdv3::V3Response::get_prev_values() const std::vector<etcdv3::KeyValue> const& etcdv3::V3Response::get_prev_values()
{ const {
return prev_values; return prev_values;
} }
etcdv3::KeyValue const & etcdv3::V3Response::get_value() const etcdv3::KeyValue const& etcdv3::V3Response::get_value() const { return value; }
{
return value;
}
etcdv3::KeyValue const & etcdv3::V3Response::get_prev_value() const etcdv3::KeyValue const& etcdv3::V3Response::get_prev_value() const {
{
return prev_value; return prev_value;
} }
bool etcdv3::V3Response::has_values() const bool etcdv3::V3Response::has_values() const { return values.size() > 0; }
{
return values.size() > 0;
}
int64_t etcdv3::V3Response::get_compact_revision() const int64_t etcdv3::V3Response::get_compact_revision() const {
{
return compact_revision; return compact_revision;
} }
void etcdv3::V3Response::set_compact_revision(const int64_t compact_revision) void etcdv3::V3Response::set_compact_revision(const int64_t compact_revision) {
{
this->compact_revision = compact_revision; this->compact_revision = compact_revision;
} }
int64_t etcdv3::V3Response::get_watch_id() const int64_t etcdv3::V3Response::get_watch_id() const { return watch_id; }
{
return watch_id;
}
void etcdv3::V3Response::set_watch_id(const int64_t watch_id) void etcdv3::V3Response::set_watch_id(const int64_t watch_id) {
{
this->watch_id = watch_id; this->watch_id = watch_id;
} }
void etcdv3::V3Response::set_lock_key(std::string const &key) { void etcdv3::V3Response::set_lock_key(std::string const& key) {
this->lock_key = key; this->lock_key = key;
} }
std::string const & etcdv3::V3Response::get_lock_key() const { std::string const& etcdv3::V3Response::get_lock_key() const {
return this->lock_key; return this->lock_key;
} }
void etcdv3::V3Response::set_name(std::string const &name) { void etcdv3::V3Response::set_name(std::string const& name) {
this->name = name; this->name = name;
} }
std::string const & etcdv3::V3Response::get_name() const { std::string const& etcdv3::V3Response::get_name() const { return this->name; }
return this->name;
}
std::vector<mvccpb::Event> const & etcdv3::V3Response::get_events() const { std::vector<mvccpb::Event> const& etcdv3::V3Response::get_events() const {
return this->events; return this->events;
} }
uint64_t etcdv3::V3Response::get_cluster_id() const { uint64_t etcdv3::V3Response::get_cluster_id() const { return this->cluster_id; }
return this->cluster_id;
}
uint64_t etcdv3::V3Response::get_member_id() const { uint64_t etcdv3::V3Response::get_member_id() const { return this->member_id; }
return this->member_id;
}
uint64_t etcdv3::V3Response::get_raft_term() const { uint64_t etcdv3::V3Response::get_raft_term() const { return this->raft_term; }
return this->raft_term;
}
std::vector<int64_t> const & etcdv3::V3Response::get_leases() const { std::vector<int64_t> const& etcdv3::V3Response::get_leases() const {
return this->leases; return this->leases;
} }

View File

@ -1,48 +1,48 @@
#include "etcd/v3/action_constants.hpp" #include "etcd/v3/action_constants.hpp"
char const * etcdv3::CREATE_ACTION = "create"; char const* etcdv3::CREATE_ACTION = "create";
char const * etcdv3::COMPARESWAP_ACTION = "compareAndSwap"; char const* etcdv3::COMPARESWAP_ACTION = "compareAndSwap";
char const * etcdv3::UPDATE_ACTION = "update"; char const* etcdv3::UPDATE_ACTION = "update";
char const * etcdv3::SET_ACTION = "set"; char const* etcdv3::SET_ACTION = "set";
char const * etcdv3::GET_ACTION = "get"; char const* etcdv3::GET_ACTION = "get";
char const * etcdv3::PUT_ACTION = "put"; char const* etcdv3::PUT_ACTION = "put";
char const * etcdv3::DELETE_ACTION = "delete"; char const* etcdv3::DELETE_ACTION = "delete";
char const * etcdv3::COMPAREDELETE_ACTION = "compareAndDelete"; char const* etcdv3::COMPAREDELETE_ACTION = "compareAndDelete";
char const * etcdv3::LOCK_ACTION = "lock"; char const* etcdv3::LOCK_ACTION = "lock";
char const * etcdv3::UNLOCK_ACTION = "unlock"; char const* etcdv3::UNLOCK_ACTION = "unlock";
char const * etcdv3::TXN_ACTION = "txn"; char const* etcdv3::TXN_ACTION = "txn";
char const * etcdv3::WATCH_ACTION = "watch"; char const* etcdv3::WATCH_ACTION = "watch";
char const * etcdv3::LEASEGRANT = "leasegrant"; char const* etcdv3::LEASEGRANT = "leasegrant";
char const * etcdv3::LEASEREVOKE = "leaserevoke"; char const* etcdv3::LEASEREVOKE = "leaserevoke";
char const * etcdv3::LEASEKEEPALIVE = "leasekeepalive"; char const* etcdv3::LEASEKEEPALIVE = "leasekeepalive";
char const * etcdv3::LEASETIMETOLIVE = "leasetimetolive"; char const* etcdv3::LEASETIMETOLIVE = "leasetimetolive";
char const * etcdv3::LEASELEASES = "leaseleases"; char const* etcdv3::LEASELEASES = "leaseleases";
char const * etcdv3::CAMPAIGN_ACTION = "campaign"; char const* etcdv3::CAMPAIGN_ACTION = "campaign";
char const * etcdv3::PROCLAIM_ACTION = "preclaim"; char const* etcdv3::PROCLAIM_ACTION = "preclaim";
char const * etcdv3::LEADER_ACTION = "leader"; char const* etcdv3::LEADER_ACTION = "leader";
char const * etcdv3::OBSERVE_ACTION = "obverse"; char const* etcdv3::OBSERVE_ACTION = "obverse";
char const * etcdv3::RESIGN_ACTION = "resign"; char const* etcdv3::RESIGN_ACTION = "resign";
// see: noPrefixEnd in etcd, however c++ doesn't allows naive '\0' inside // see: noPrefixEnd in etcd, however c++ doesn't allows naive '\0' inside
// a string, thus we use std::string(1, '\x00') as the constructor. // a string, thus we use std::string(1, '\x00') as the constructor.
std::string const etcdv3::NUL = std::string(1, '\x00'); std::string const etcdv3::NUL = std::string(1, '\x00');
char const * etcdv3::KEEPALIVE_CREATE = "keepalive create"; char const* etcdv3::KEEPALIVE_CREATE = "keepalive create";
char const * etcdv3::KEEPALIVE_WRITE = "keepalive write"; char const* etcdv3::KEEPALIVE_WRITE = "keepalive write";
char const * etcdv3::KEEPALIVE_READ = "keepalive read"; char const* etcdv3::KEEPALIVE_READ = "keepalive read";
char const * etcdv3::KEEPALIVE_DONE = "keepalive done"; char const* etcdv3::KEEPALIVE_DONE = "keepalive done";
char const * etcdv3::KEEPALIVE_FINISH = "keepalive finish"; char const* etcdv3::KEEPALIVE_FINISH = "keepalive finish";
char const * etcdv3::WATCH_CREATE = "watch create"; char const* etcdv3::WATCH_CREATE = "watch create";
char const * etcdv3::WATCH_WRITE = "watch write"; char const* etcdv3::WATCH_WRITE = "watch write";
char const * etcdv3::WATCH_WRITE_CANCEL = "watch write cancel"; char const* etcdv3::WATCH_WRITE_CANCEL = "watch write cancel";
char const * etcdv3::WATCH_WRITES_DONE = "watch writes done"; char const* etcdv3::WATCH_WRITES_DONE = "watch writes done";
char const * etcdv3::WATCH_FINISH = "watch finish"; char const* etcdv3::WATCH_FINISH = "watch finish";
char const * etcdv3::ELECTION_OBSERVE_CREATE = "observe create"; char const* etcdv3::ELECTION_OBSERVE_CREATE = "observe create";
char const * etcdv3::ELECTION_OBSERVE_FINISH = "observe finish"; char const* etcdv3::ELECTION_OBSERVE_FINISH = "observe finish";
const int etcdv3::ERROR_GRPC_OK = 0; const int etcdv3::ERROR_GRPC_OK = 0;
const int etcdv3::ERROR_GRPC_CANCELLED = 1; const int etcdv3::ERROR_GRPC_CANCELLED = 1;

View File

@ -5,22 +5,21 @@
#include "etcd/Client.hpp" #include "etcd/Client.hpp"
static const std::string etcd_url = etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379"); static const std::string etcd_url =
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
TEST_CASE("setup with auth") TEST_CASE("setup with auth") {
{ etcd::Client* etcd = etcd::Client::WithUser(etcd_url, "root", "root");
etcd::Client *etcd = etcd::Client::WithUser(etcd_url, "root", "root");
etcd->rmdir("/test", true).wait(); etcd->rmdir("/test", true).wait();
} }
TEST_CASE("add a new key after authenticate") TEST_CASE("add a new key after authenticate") {
{ etcd::Client* etcd = etcd::Client::WithUser(etcd_url, "root", "root");
etcd::Client *etcd = etcd::Client::WithUser(etcd_url, "root", "root");
etcd->rmdir("/test", true).wait(); etcd->rmdir("/test", true).wait();
etcd::Response resp = etcd->add("/test/key1", "42").get(); etcd::Response resp = etcd->add("/test/key1", "42").get();
REQUIRE(0 == resp.error_code()); REQUIRE(0 == resp.error_code());
CHECK("create" == resp.action()); CHECK("create" == resp.action());
etcd::Value const & val = resp.value(); etcd::Value const& val = resp.value();
CHECK("42" == val.as_string()); CHECK("42" == val.as_string());
CHECK("/test/key1" == val.key()); CHECK("/test/key1" == val.key());
CHECK(!val.is_dir()); CHECK(!val.is_dir());
@ -28,24 +27,28 @@ TEST_CASE("add a new key after authenticate")
CHECK(0 < val.modified_index()); CHECK(0 < val.modified_index());
CHECK(1 == val.version()); CHECK(1 == val.version());
CHECK(0 < resp.index()); CHECK(0 < resp.index());
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "43").get().error_code()); // Key already exists CHECK(
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "42").get().error_code()); // Key already exists etcd::ERROR_KEY_ALREADY_EXISTS ==
CHECK("etcd-cpp-apiv3: key already exists" == etcd->add("/test/key1", "42").get().error_message()); etcd->add("/test/key1", "43").get().error_code()); // Key already exists
CHECK(
etcd::ERROR_KEY_ALREADY_EXISTS ==
etcd->add("/test/key1", "42").get().error_code()); // Key already exists
CHECK("etcd-cpp-apiv3: key already exists" ==
etcd->add("/test/key1", "42").get().error_message());
} }
TEST_CASE("read a value from etcd") TEST_CASE("read a value from etcd") {
{ etcd::Client* etcd = etcd::Client::WithUser(etcd_url, "root", "root");
etcd::Client *etcd = etcd::Client::WithUser(etcd_url, "root", "root");
etcd::Response resp = etcd->get("/test/key1").get(); etcd::Response resp = etcd->get("/test/key1").get();
CHECK("get" == resp.action()); CHECK("get" == resp.action());
REQUIRE(resp.is_ok()); REQUIRE(resp.is_ok());
REQUIRE(0 == resp.error_code()); REQUIRE(0 == resp.error_code());
CHECK("42" == resp.value().as_string()); CHECK("42" == resp.value().as_string());
CHECK("" == etcd->get("/test").get().value().as_string()); // key points to a directory CHECK("" == etcd->get("/test").get().value().as_string()); // key points to a
// directory
} }
TEST_CASE("cleanup") TEST_CASE("cleanup") {
{ etcd::Client* etcd = etcd::Client::WithUser(etcd_url, "root", "root");
etcd::Client *etcd = etcd::Client::WithUser(etcd_url, "root", "root");
REQUIRE(0 == etcd->rmdir("/test", true).get().error_code()); REQUIRE(0 == etcd->rmdir("/test", true).get().error_code());
} }

View File

@ -11,7 +11,7 @@
#include "etcd/Value.hpp" #include "etcd/Value.hpp"
static std::string etcd_uri = etcdv3::detail::resolve_etcd_endpoints( static std::string etcd_uri = etcdv3::detail::resolve_etcd_endpoints(
"http://127.0.0.1:2379,http://127.0.0.1:2479,http://127.0.0.1:2579"); "http://127.0.0.1:2379,http://127.0.0.1:2479,http://127.0.0.1:2579");
TEST_CASE("campaign and leadership using keepalive") { TEST_CASE("campaign and leadership using keepalive") {
etcd::Client etcd(etcd_uri); etcd::Client etcd(etcd_uri);
@ -39,13 +39,14 @@ TEST_CASE("campaign and leadership using keepalive") {
std::cout << "finish leader" << std::endl; std::cout << "finish leader" << std::endl;
auto resp3 = etcd.resign("/leader", resp1.value().lease(), resp1.value().key(), resp1.value().created_index()).get(); auto resp3 = etcd.resign("/leader", resp1.value().lease(),
resp1.value().key(), resp1.value().created_index())
.get();
CHECK(0 == resp3.error_code()); CHECK(0 == resp3.error_code());
std::cout << "finish resign" << std::endl; std::cout << "finish resign" << std::endl;
} }
TEST_CASE("concurrent campaign with grpc timeout") { TEST_CASE("concurrent campaign with grpc timeout") {
std::string value1 = std::string("192.168.1.6:1880"); std::string value1 = std::string("192.168.1.6:1880");
std::string value2 = std::string("192.168.1.6:1890"); std::string value2 = std::string("192.168.1.6:1890");
@ -60,7 +61,9 @@ TEST_CASE("concurrent campaign with grpc timeout") {
std::this_thread::sleep_for(std::chrono::seconds(10)); std::this_thread::sleep_for(std::chrono::seconds(10));
// resign // resign
auto resp2 = etcd.resign("/leader", resp1.value().lease(), resp1.value().key(), resp1.value().created_index()).get(); auto resp2 = etcd.resign("/leader", resp1.value().lease(),
resp1.value().key(), resp1.value().created_index())
.get();
CHECK(0 == resp2.error_code()); CHECK(0 == resp2.error_code());
}; };
@ -74,7 +77,7 @@ TEST_CASE("concurrent campaign with grpc timeout") {
std::this_thread::sleep_for(std::chrono::seconds(3)); std::this_thread::sleep_for(std::chrono::seconds(3));
auto resp1 = etcd.campaign("/leader", lease_id, value2).get(); auto resp1 = etcd.campaign("/leader", lease_id, value2).get();
std::cout <<resp1.error_code() << resp1.error_message() << std::endl; std::cout << resp1.error_code() << resp1.error_message() << std::endl;
CHECK(0 != resp1.error_code()); CHECK(0 != resp1.error_code());
// wait until success // wait until success
@ -92,7 +95,9 @@ TEST_CASE("concurrent campaign with grpc timeout") {
} }
} }
auto resp2 = etcd.resign("/leader", resp1.value().lease(), resp1.value().key(), resp1.value().created_index()).get(); auto resp2 = etcd.resign("/leader", resp1.value().lease(),
resp1.value().key(), resp1.value().created_index())
.get();
CHECK(0 == resp2.error_code()); CHECK(0 == resp2.error_code());
}; };

View File

@ -8,16 +8,15 @@
#include "etcd/Client.hpp" #include "etcd/Client.hpp"
#include "etcd/KeepAlive.hpp" #include "etcd/KeepAlive.hpp"
static const std::string etcd_url = etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379"); static const std::string etcd_url =
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
TEST_CASE("setup") TEST_CASE("setup") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd.rmdir("/test", true).wait(); etcd.rmdir("/test", true).wait();
} }
TEST_CASE("campaign and resign") TEST_CASE("campaign and resign") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
auto keepalive = etcd.leasekeepalive(60).get(); auto keepalive = etcd.leasekeepalive(60).get();
@ -36,9 +35,9 @@ TEST_CASE("campaign and resign")
} }
// proclaim // proclaim
auto resp3 = etcd.proclaim("test", lease_id, auto resp3 = etcd.proclaim("test", lease_id, resp1.value().key(),
resp1.value().key(), resp1.value().created_index(), resp1.value().created_index(), "tttt")
"tttt").get(); .get();
REQUIRE(0 == resp3.error_code()); REQUIRE(0 == resp3.error_code());
// leader // leader
@ -50,13 +49,13 @@ TEST_CASE("campaign and resign")
} }
// resign // resign
auto resp5 = etcd.resign("test", lease_id, auto resp5 = etcd.resign("test", lease_id, resp1.value().key(),
resp1.value().key(), resp1.value().created_index()).get(); resp1.value().created_index())
.get();
REQUIRE(0 == resp5.error_code()); REQUIRE(0 == resp5.error_code());
} }
TEST_CASE("campaign and observe") TEST_CASE("campaign and observe") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
auto keepalive = etcd.leasekeepalive(60).get(); auto keepalive = etcd.leasekeepalive(60).get();
@ -67,7 +66,8 @@ TEST_CASE("campaign and observe")
// wait many change events, blocked execution // wait many change events, blocked execution
for (size_t i = 0; i < 10; ++i) { for (size_t i = 0; i < 10; ++i) {
etcd::Response resp = observer->WaitOnce(); etcd::Response resp = observer->WaitOnce();
std::cout << "observe " << resp.value().key() << " as the leader: " << resp.value().as_string() << std::endl; std::cout << "observe " << resp.value().key()
<< " as the leader: " << resp.value().as_string() << std::endl;
} }
std::cout << "finish the observe" << std::endl; std::cout << "finish the observe" << std::endl;
// cancel the observers // cancel the observers
@ -109,8 +109,7 @@ TEST_CASE("campaign and observe")
observer_thread.join(); observer_thread.join();
} }
TEST_CASE("cleanup") TEST_CASE("cleanup") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd.rmdir("/test", true).get(); etcd.rmdir("/test", true).get();
} }

View File

@ -5,38 +5,41 @@
#include "etcd/SyncClient.hpp" #include "etcd/SyncClient.hpp"
static const std::string etcd_url = etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379"); static const std::string etcd_url =
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
TEST_CASE("sync operations") TEST_CASE("sync operations") {
{
etcd::SyncClient etcd(etcd_url); etcd::SyncClient etcd(etcd_url);
etcd.rmdir("/test", true); etcd.rmdir("/test", true);
// add // add
CHECK(0 == etcd.add("/test/key1", "42").error_code()); CHECK(0 == etcd.add("/test/key1", "42").error_code());
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd.add("/test/key1", "42").error_code()); // Key already exists CHECK(etcd::ERROR_KEY_ALREADY_EXISTS ==
etcd.add("/test/key1", "42").error_code()); // Key already exists
CHECK("42" == etcd.get("/test/key1").value().as_string()); CHECK("42" == etcd.get("/test/key1").value().as_string());
// modify // modify
CHECK(0 == etcd.modify("/test/key1", "43").error_code()); CHECK(0 == etcd.modify("/test/key1", "43").error_code());
CHECK(etcd::ERROR_KEY_NOT_FOUND == etcd.modify("/test/key2", "43").error_code()); // Key not found CHECK(etcd::ERROR_KEY_NOT_FOUND ==
etcd.modify("/test/key2", "43").error_code()); // Key not found
CHECK("43" == etcd.modify("/test/key1", "42").prev_value().as_string()); CHECK("43" == etcd.modify("/test/key1", "42").prev_value().as_string());
// set // set
CHECK(0 == etcd.set("/test/key1", "43").error_code()); // overwrite CHECK(0 == etcd.set("/test/key1", "43").error_code()); // overwrite
CHECK(0 == etcd.set("/test/key2", "43").error_code()); // create new CHECK(0 == etcd.set("/test/key2", "43").error_code()); // create new
CHECK("43" == etcd.set("/test/key2", "44").prev_value().as_string()); CHECK("43" == etcd.set("/test/key2", "44").prev_value().as_string());
CHECK("" == etcd.set("/test/key3", "44").prev_value().as_string()); CHECK("" == etcd.set("/test/key3", "44").prev_value().as_string());
// get // get
CHECK("43" == etcd.get("/test/key1").value().as_string()); CHECK("43" == etcd.get("/test/key1").value().as_string());
CHECK("44" == etcd.get("/test/key2").value().as_string()); CHECK("44" == etcd.get("/test/key2").value().as_string());
CHECK("44" == etcd.get("/test/key3").value().as_string()); CHECK("44" == etcd.get("/test/key3").value().as_string());
CHECK(etcd::ERROR_KEY_NOT_FOUND == etcd.get("/test/key4").error_code()); // key not found CHECK(etcd::ERROR_KEY_NOT_FOUND ==
etcd.get("/test/key4").error_code()); // key not found
// rm // rm
CHECK(3 == etcd.ls("/test").keys().size()); CHECK(3 == etcd.ls("/test").keys().size());
CHECK(0 == etcd.rm("/test/key1").error_code()); CHECK(0 == etcd.rm("/test/key1").error_code());
CHECK(2 == etcd.ls("/test").keys().size()); CHECK(2 == etcd.ls("/test").keys().size());
// ls // ls
@ -51,71 +54,75 @@ TEST_CASE("sync operations")
CHECK(2 == etcd.keys("/test/new_dir").keys().size()); CHECK(2 == etcd.keys("/test/new_dir").keys().size());
// rmdir // rmdir
CHECK(etcd::ERROR_KEY_NOT_FOUND == etcd.rmdir("/test/new_dir").error_code()); // key not found CHECK(etcd::ERROR_KEY_NOT_FOUND ==
etcd.rmdir("/test/new_dir").error_code()); // key not found
CHECK(0 == etcd.rmdir("/test/new_dir", true).error_code()); CHECK(0 == etcd.rmdir("/test/new_dir", true).error_code());
// compare and swap // compare and swap
etcd.set("/test/key1", "42"); etcd.set("/test/key1", "42");
int64_t index = etcd.modify_if("/test/key1", "43", "42").index(); int64_t index = etcd.modify_if("/test/key1", "43", "42").index();
CHECK(etcd::ERROR_COMPARE_FAILED == etcd.modify_if("/test/key1", "44", "42").error_code()); CHECK(etcd::ERROR_COMPARE_FAILED ==
etcd.modify_if("/test/key1", "44", "42").error_code());
REQUIRE(etcd.modify_if("/test/key1", "44", index).is_ok()); REQUIRE(etcd.modify_if("/test/key1", "44", index).is_ok());
CHECK(etcd::ERROR_COMPARE_FAILED == etcd.modify_if("/test/key1", "45", index).error_code()); CHECK(etcd::ERROR_COMPARE_FAILED ==
etcd.modify_if("/test/key1", "45", index).error_code());
// atomic compare-and-delete based on prevValue // atomic compare-and-delete based on prevValue
etcd.set("/test/key1", "42"); etcd.set("/test/key1", "42");
CHECK(etcd::ERROR_COMPARE_FAILED == etcd.rm_if("/test/key1", "43").error_code()); CHECK(etcd::ERROR_COMPARE_FAILED ==
etcd.rm_if("/test/key1", "43").error_code());
CHECK(0 == etcd.rm_if("/test/key1", "42").error_code()); CHECK(0 == etcd.rm_if("/test/key1", "42").error_code());
// atomic compare-and-delete based on prevIndex // atomic compare-and-delete based on prevIndex
index = etcd.set("/test/key1", "42").index(); index = etcd.set("/test/key1", "42").index();
CHECK(etcd::ERROR_COMPARE_FAILED == etcd.rm_if("/test/key1", index - 1).error_code()); CHECK(etcd::ERROR_COMPARE_FAILED ==
etcd.rm_if("/test/key1", index - 1).error_code());
CHECK(0 == etcd.rm_if("/test/key1", index).error_code()); CHECK(0 == etcd.rm_if("/test/key1", index).error_code());
//leasegrant // leasegrant
etcd::Response res = etcd.leasegrant(60); etcd::Response res = etcd.leasegrant(60);
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());
CHECK(60 == res.value().ttl()); CHECK(60 == res.value().ttl());
CHECK(0 < res.value().lease()); CHECK(0 < res.value().lease());
int64_t leaseid = res.value().lease(); int64_t leaseid = res.value().lease();
//add with lease // add with lease
res = etcd.add("/test/key1111", "43", leaseid); res = etcd.add("/test/key1111", "43", leaseid);
REQUIRE(0 == res.error_code()); // overwrite REQUIRE(0 == res.error_code()); // overwrite
CHECK("create" == res.action()); CHECK("create" == res.action());
CHECK(leaseid == res.value().lease()); CHECK(leaseid == res.value().lease());
//set with lease // set with lease
res = etcd.set("/test/key1", "43", leaseid); res = etcd.set("/test/key1", "43", leaseid);
REQUIRE(0 == res.error_code()); REQUIRE(0 == res.error_code());
CHECK("set" == res.action()); CHECK("set" == res.action());
CHECK(leaseid == res.value().lease()); CHECK(leaseid == res.value().lease());
//modify with lease // modify with lease
res = etcd.modify("/test/key1", "44", leaseid); res = etcd.modify("/test/key1", "44", leaseid);
REQUIRE(0 == res.error_code()); REQUIRE(0 == res.error_code());
CHECK("update" == res.action()); CHECK("update" == res.action());
CHECK(leaseid == res.value().lease()); CHECK(leaseid == res.value().lease());
CHECK("44" == res.value().as_string()); CHECK("44" == res.value().as_string());
res = etcd.modify_if("/test/key1", "45", "44", leaseid); res = etcd.modify_if("/test/key1", "45", "44", leaseid);
index = res.index(); index = res.index();
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());
CHECK("compareAndSwap" == res.action()); CHECK("compareAndSwap" == res.action());
CHECK(leaseid == res.value().lease()); CHECK(leaseid == res.value().lease());
CHECK("45" == res.value().as_string()); CHECK("45" == res.value().as_string());
res = etcd.modify_if("/test/key1", "44", index, leaseid); res = etcd.modify_if("/test/key1", "44", index, leaseid);
index = res.index(); index = res.index();
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());
CHECK("compareAndSwap" == res.action()); CHECK("compareAndSwap" == res.action());
CHECK(leaseid == res.value().lease()); CHECK(leaseid == res.value().lease());
CHECK("44" == res.value().as_string()); CHECK("44" == res.value().as_string());
REQUIRE(0 == etcd.rmdir("/test", true).error_code()); REQUIRE(0 == etcd.rmdir("/test", true).error_code());
} }
TEST_CASE("wait for a value change") TEST_CASE("wait for a value change") {
{
etcd::SyncClient etcd(etcd_url); etcd::SyncClient etcd(etcd_url);
etcd.set("/test/key1", "42"); etcd.set("/test/key1", "42");
@ -132,8 +139,7 @@ TEST_CASE("wait for a value change")
REQUIRE(0 == etcd.rmdir("/test", true).error_code()); REQUIRE(0 == etcd.rmdir("/test", true).error_code());
} }
TEST_CASE("wait for a directory change") TEST_CASE("wait for a directory change") {
{
etcd::SyncClient etcd(etcd_url); etcd::SyncClient etcd(etcd_url);
std::thread watch_thrd1([&]() { std::thread watch_thrd1([&]() {
@ -159,8 +165,7 @@ TEST_CASE("wait for a directory change")
REQUIRE(0 == etcd.rmdir("/test", true).error_code()); REQUIRE(0 == etcd.rmdir("/test", true).error_code());
} }
TEST_CASE("watch changes in the past") TEST_CASE("watch changes in the past") {
{
etcd::SyncClient etcd(etcd_url); etcd::SyncClient etcd(etcd_url);
int64_t index = etcd.set("/test/key1", "42").index(); int64_t index = etcd.set("/test/key1", "42").index();

View File

@ -7,22 +7,21 @@
#include "etcd/Client.hpp" #include "etcd/Client.hpp"
static const std::string etcd_url = etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379"); static const std::string etcd_url =
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
TEST_CASE("setup") TEST_CASE("setup") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd.rmdir("/test", true).wait(); etcd.rmdir("/test", true).wait();
} }
TEST_CASE("add a new key") TEST_CASE("add a new key") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd.rmdir("/test", true).wait(); etcd.rmdir("/test", true).wait();
etcd::Response resp = etcd.add("/test/key1", "42").get(); etcd::Response resp = etcd.add("/test/key1", "42").get();
REQUIRE(0 == resp.error_code()); REQUIRE(0 == resp.error_code());
CHECK("create" == resp.action()); CHECK("create" == resp.action());
etcd::Value const & val = resp.value(); etcd::Value const& val = resp.value();
CHECK("42" == val.as_string()); CHECK("42" == val.as_string());
CHECK("/test/key1" == val.key()); CHECK("/test/key1" == val.key());
CHECK(!val.is_dir()); CHECK(!val.is_dir());
@ -30,32 +29,35 @@ TEST_CASE("add a new key")
CHECK(0 < val.modified_index()); CHECK(0 < val.modified_index());
CHECK(1 == val.version()); CHECK(1 == val.version());
CHECK(0 < resp.index()); CHECK(0 < resp.index());
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd.add("/test/key1", "43").get().error_code()); // Key already exists CHECK(etcd::ERROR_KEY_ALREADY_EXISTS ==
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd.add("/test/key1", "42").get().error_code()); // Key already exists etcd.add("/test/key1", "43").get().error_code()); // Key already exists
CHECK("etcd-cpp-apiv3: key already exists" == etcd.add("/test/key1", "42").get().error_message()); CHECK(etcd::ERROR_KEY_ALREADY_EXISTS ==
etcd.add("/test/key1", "42").get().error_code()); // Key already exists
CHECK("etcd-cpp-apiv3: key already exists" ==
etcd.add("/test/key1", "42").get().error_message());
} }
TEST_CASE("read a value from etcd") TEST_CASE("read a value from etcd") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd::Response resp = etcd.get("/test/key1").get(); etcd::Response resp = etcd.get("/test/key1").get();
CHECK("get" == resp.action()); CHECK("get" == resp.action());
REQUIRE(resp.is_ok()); REQUIRE(resp.is_ok());
REQUIRE(0 == resp.error_code()); REQUIRE(0 == resp.error_code());
CHECK("42" == resp.value().as_string()); CHECK("42" == resp.value().as_string());
CHECK("" == etcd.get("/test").get().value().as_string()); // key points to a directory CHECK("" == etcd.get("/test").get().value().as_string()); // key points to a
// directory
} }
TEST_CASE("simplified read") TEST_CASE("simplified read") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
CHECK("42" == etcd.get("/test/key1").get().value().as_string()); CHECK("42" == etcd.get("/test/key1").get().value().as_string());
CHECK(etcd::ERROR_KEY_NOT_FOUND == etcd.get("/test/key2").get().error_code()); // Key not found CHECK(etcd::ERROR_KEY_NOT_FOUND ==
CHECK("" == etcd.get("/test/key2").get().value().as_string()); // Key not found etcd.get("/test/key2").get().error_code()); // Key not found
CHECK("" ==
etcd.get("/test/key2").get().value().as_string()); // Key not found
} }
TEST_CASE("modify a key") TEST_CASE("modify a key") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
// get // get
@ -66,9 +68,10 @@ TEST_CASE("modify a key")
// modify // modify
resp = etcd.modify("/test/key1", "43").get(); resp = etcd.modify("/test/key1", "43").get();
REQUIRE(0 == resp.error_code()); // overwrite REQUIRE(0 == resp.error_code()); // overwrite
CHECK("update" == resp.action()); CHECK("update" == resp.action());
CHECK(etcd::ERROR_KEY_NOT_FOUND == etcd.modify("/test/key2", "43").get().error_code()); // Key not found CHECK(etcd::ERROR_KEY_NOT_FOUND ==
etcd.modify("/test/key2", "43").get().error_code()); // Key not found
CHECK("43" == etcd.modify("/test/key1", "42").get().prev_value().as_string()); CHECK("43" == etcd.modify("/test/key1", "42").get().prev_value().as_string());
// check previous // check previous
@ -77,28 +80,26 @@ TEST_CASE("modify a key")
CHECK("42" == resp.value().as_string()); CHECK("42" == resp.value().as_string());
} }
TEST_CASE("set a key") TEST_CASE("set a key") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd::Response resp = etcd.set("/test/key1", "43").get(); etcd::Response resp = etcd.set("/test/key1", "43").get();
REQUIRE(0 == resp.error_code()); // overwrite REQUIRE(0 == resp.error_code()); // overwrite
CHECK("set" == resp.action()); CHECK("set" == resp.action());
CHECK(0 == etcd.set("/test/key2", "43").get().error_code()); // create new CHECK(0 == etcd.set("/test/key2", "43").get().error_code()); // create new
CHECK("43" == etcd.set("/test/key2", "44").get().prev_value().as_string()); CHECK("43" == etcd.set("/test/key2", "44").get().prev_value().as_string());
CHECK("" == etcd.set("/test/key3", "44").get().prev_value().as_string()); CHECK("" == etcd.set("/test/key3", "44").get().prev_value().as_string());
CHECK(0 == etcd.set("/test", "42").get().error_code()); // Not a file CHECK(0 == etcd.set("/test", "42").get().error_code()); // Not a file
//set with ttl // set with ttl
resp = etcd.set("/test/key1", "50", 10).get(); resp = etcd.set("/test/key1", "50", 10).get();
REQUIRE(0 == resp.error_code()); // overwrite REQUIRE(0 == resp.error_code()); // overwrite
CHECK("set" == resp.action()); CHECK("set" == resp.action());
CHECK("43" == resp.prev_value().as_string()); CHECK("43" == resp.prev_value().as_string());
CHECK("50" == resp.value().as_string()); CHECK("50" == resp.value().as_string());
CHECK( 0 < resp.value().lease()); CHECK(0 < resp.value().lease());
} }
TEST_CASE("atomic compare-and-swap") TEST_CASE("atomic compare-and-swap") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd.set("/test/key1", "42").wait(); etcd.set("/test/key1", "42").wait();
@ -121,8 +122,7 @@ TEST_CASE("atomic compare-and-swap")
CHECK("etcd-cpp-apiv3: key not found" == res.error_message()); CHECK("etcd-cpp-apiv3: key not found" == res.error_message());
} }
TEST_CASE("delete a value") TEST_CASE("delete a value") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd::Response resp = etcd.rm("/test/key11111").get(); etcd::Response resp = etcd.rm("/test/key11111").get();
CHECK(!resp.is_ok()); CHECK(!resp.is_ok());
@ -139,20 +139,19 @@ TEST_CASE("delete a value")
resp = etcd.rm("/test/key1").get(); resp = etcd.rm("/test/key1").get();
CHECK("43" == resp.prev_value().as_string()); CHECK("43" == resp.prev_value().as_string());
CHECK( "/test/key1" == resp.prev_value().key()); CHECK("/test/key1" == resp.prev_value().key());
CHECK( create_index == resp.prev_value().created_index()); CHECK(create_index == resp.prev_value().created_index());
CHECK( modify_index == resp.prev_value().modified_index()); CHECK(modify_index == resp.prev_value().modified_index());
CHECK( version == resp.prev_value().version()); CHECK(version == resp.prev_value().version());
CHECK("delete" == resp.action()); CHECK("delete" == resp.action());
CHECK( modify_index == resp.value().modified_index()); CHECK(modify_index == resp.value().modified_index());
CHECK( create_index == resp.value().created_index()); CHECK(create_index == resp.value().created_index());
CHECK( version == resp.value().version()); CHECK(version == resp.value().version());
CHECK("" == resp.value().as_string()); CHECK("" == resp.value().as_string());
CHECK( "/test/key1" == resp.value().key()); CHECK("/test/key1" == resp.value().key());
} }
TEST_CASE("atomic compare-and-delete based on prevValue") TEST_CASE("atomic compare-and-delete based on prevValue") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd.set("/test/key1", "42").wait(); etcd.set("/test/key1", "42").wait();
@ -167,8 +166,7 @@ TEST_CASE("atomic compare-and-delete based on prevValue")
CHECK("42" == res.prev_value().as_string()); CHECK("42" == res.prev_value().as_string());
} }
TEST_CASE("atomic compare-and-delete based on prevIndex") TEST_CASE("atomic compare-and-delete based on prevIndex") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
int64_t index = etcd.set("/test/key1", "42").get().index(); int64_t index = etcd.set("/test/key1", "42").get().index();
@ -183,8 +181,7 @@ TEST_CASE("atomic compare-and-delete based on prevIndex")
CHECK("42" == res.prev_value().as_string()); CHECK("42" == res.prev_value().as_string());
} }
TEST_CASE("deep atomic compare-and-swap") TEST_CASE("deep atomic compare-and-swap") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd.set("/test/key1", "42").wait(); etcd.set("/test/key1", "42").wait();
@ -214,8 +211,7 @@ TEST_CASE("deep atomic compare-and-swap")
CHECK("etcd-cpp-apiv3: compare failed" == res.error_message()); CHECK("etcd-cpp-apiv3: compare failed" == res.error_message());
} }
TEST_CASE("using binary keys and values, raw char pointer doesn't work") TEST_CASE("using binary keys and values, raw char pointer doesn't work") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd.rmdir("/test", true).wait(); etcd.rmdir("/test", true).wait();
{ {
@ -244,12 +240,13 @@ TEST_CASE("using binary keys and values, raw char pointer doesn't work")
} }
} }
TEST_CASE("using binary keys and values, std::string is ok for \\0") TEST_CASE("using binary keys and values, std::string is ok for \\0") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd.rmdir("/test", true).wait(); etcd.rmdir("/test", true).wait();
{ {
etcd::Response resp = etcd.put(std::string("/test/key1\0xyz", 14), std::string("42\0foo", 6)).get(); etcd::Response resp =
etcd.put(std::string("/test/key1\0xyz", 14), std::string("42\0foo", 6))
.get();
REQUIRE(resp.is_ok()); REQUIRE(resp.is_ok());
} }
{ {
@ -267,8 +264,7 @@ TEST_CASE("using binary keys and values, std::string is ok for \\0")
} }
} }
TEST_CASE("list a directory") TEST_CASE("list a directory") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
CHECK(0 == etcd.ls("/test/new_dir").get().keys().size()); CHECK(0 == etcd.ls("/test/new_dir").get().keys().size());
@ -304,8 +300,7 @@ TEST_CASE("list a directory")
CHECK(etcd.rmdir("/test/new_dir", true).get().is_ok()); CHECK(etcd.rmdir("/test/new_dir", true).get().is_ok());
} }
TEST_CASE("list by range") TEST_CASE("list by range") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
CHECK(0 == etcd.ls("/test/new_dir").get().keys().size()); CHECK(0 == etcd.ls("/test/new_dir").get().keys().size());
@ -315,13 +310,15 @@ TEST_CASE("list by range")
etcd.set("/test/new_dir/key3", "value3").wait(); etcd.set("/test/new_dir/key3", "value3").wait();
etcd.set("/test/new_dir/key4", "value4").wait(); etcd.set("/test/new_dir/key4", "value4").wait();
etcd::Response resp1 = etcd.ls("/test/new_dir/key1", "/test/new_dir/key3").get(); etcd::Response resp1 =
etcd.ls("/test/new_dir/key1", "/test/new_dir/key3").get();
REQUIRE(resp1.is_ok()); REQUIRE(resp1.is_ok());
CHECK("get" == resp1.action()); CHECK("get" == resp1.action());
REQUIRE(2 == resp1.keys().size()); REQUIRE(2 == resp1.keys().size());
REQUIRE(2 == resp1.values().size()); REQUIRE(2 == resp1.values().size());
etcd::Response resp2 = etcd.ls("/test/new_dir/key1", "/test/new_dir/key4").get(); etcd::Response resp2 =
etcd.ls("/test/new_dir/key1", "/test/new_dir/key4").get();
REQUIRE(resp2.is_ok()); REQUIRE(resp2.is_ok());
CHECK("get" == resp2.action()); CHECK("get" == resp2.action());
REQUIRE(3 == resp2.keys().size()); REQUIRE(3 == resp2.keys().size());
@ -333,7 +330,10 @@ TEST_CASE("list by range")
REQUIRE(4 == resp3.keys().size()); REQUIRE(4 == resp3.keys().size());
REQUIRE(4 == resp3.values().size()); REQUIRE(4 == resp3.values().size());
etcd::Response resp4 = etcd.ls("/test/new_dir/key1", etcdv3::detail::string_plus_one("/test/new_dir/key")).get(); etcd::Response resp4 =
etcd.ls("/test/new_dir/key1",
etcdv3::detail::string_plus_one("/test/new_dir/key"))
.get();
REQUIRE(resp4.is_ok()); REQUIRE(resp4.is_ok());
CHECK("get" == resp4.action()); CHECK("get" == resp4.action());
REQUIRE(4 == resp4.keys().size()); REQUIRE(4 == resp4.keys().size());
@ -344,8 +344,7 @@ TEST_CASE("list by range")
CHECK(etcd.rmdir("/test/new_dir", true).get().is_ok()); CHECK(etcd.rmdir("/test/new_dir", true).get().is_ok());
} }
TEST_CASE("list by range, w/o values") TEST_CASE("list by range, w/o values") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
CHECK(0 == etcd.ls("/test/new_dir").get().keys().size()); CHECK(0 == etcd.ls("/test/new_dir").get().keys().size());
@ -355,14 +354,16 @@ TEST_CASE("list by range, w/o values")
etcd.set("/test/new_dir/key3", "value3").wait(); etcd.set("/test/new_dir/key3", "value3").wait();
etcd.set("/test/new_dir/key4", "value4").wait(); etcd.set("/test/new_dir/key4", "value4").wait();
etcd::Response resp1 = etcd.ls("/test/new_dir/key1", "/test/new_dir/key2").get(); etcd::Response resp1 =
etcd.ls("/test/new_dir/key1", "/test/new_dir/key2").get();
REQUIRE(resp1.is_ok()); REQUIRE(resp1.is_ok());
CHECK("get" == resp1.action()); CHECK("get" == resp1.action());
REQUIRE(1 == resp1.keys().size()); REQUIRE(1 == resp1.keys().size());
REQUIRE(1 == resp1.values().size()); REQUIRE(1 == resp1.values().size());
REQUIRE(resp1.values()[0].as_string() == "value1"); REQUIRE(resp1.values()[0].as_string() == "value1");
etcd::Response resp2 = etcd.keys("/test/new_dir/key1", "/test/new_dir/key2").get(); etcd::Response resp2 =
etcd.keys("/test/new_dir/key1", "/test/new_dir/key2").get();
REQUIRE(resp1.is_ok()); REQUIRE(resp1.is_ok());
CHECK("get" == resp2.action()); CHECK("get" == resp2.action());
REQUIRE(1 == resp2.keys().size()); REQUIRE(1 == resp2.keys().size());
@ -372,15 +373,15 @@ TEST_CASE("list by range, w/o values")
CHECK(etcd.rmdir("/test/new_dir", true).get().is_ok()); CHECK(etcd.rmdir("/test/new_dir", true).get().is_ok());
} }
TEST_CASE("delete a directory") TEST_CASE("delete a directory") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd.set("/test/new_dir/key1", "value1").wait(); etcd.set("/test/new_dir/key1", "value1").wait();
etcd.set("/test/new_dir/key2", "value2").wait(); etcd.set("/test/new_dir/key2", "value2").wait();
etcd.set("/test/new_dir/key3", "value3").wait(); etcd.set("/test/new_dir/key3", "value3").wait();
CHECK(etcd::ERROR_KEY_NOT_FOUND == etcd.rmdir("/test/new_dir").get().error_code()); // key not found CHECK(etcd::ERROR_KEY_NOT_FOUND ==
etcd.rmdir("/test/new_dir").get().error_code()); // key not found
etcd::Response resp = etcd.ls("/test/new_dir").get(); etcd::Response resp = etcd.ls("/test/new_dir").get();
resp = etcd.rmdir("/test/new_dir", true).get(); resp = etcd.rmdir("/test/new_dir", true).get();
@ -391,7 +392,6 @@ TEST_CASE("delete a directory")
CHECK("value1" == resp.value(0).as_string()); CHECK("value1" == resp.value(0).as_string());
CHECK("value2" == resp.value(1).as_string()); CHECK("value2" == resp.value(1).as_string());
resp = etcd.rmdir("/test/dirnotfound", true).get(); resp = etcd.rmdir("/test/dirnotfound", true).get();
CHECK(!resp.is_ok()); CHECK(!resp.is_ok());
CHECK(etcd::ERROR_KEY_NOT_FOUND == resp.error_code()); CHECK(etcd::ERROR_KEY_NOT_FOUND == resp.error_code());
@ -403,8 +403,7 @@ TEST_CASE("delete a directory")
CHECK("etcd-cpp-apiv3: key not found" == resp.error_message()); CHECK("etcd-cpp-apiv3: key not found" == resp.error_message());
} }
TEST_CASE("delete all keys with rmdir(\"\", true)") TEST_CASE("delete all keys with rmdir(\"\", true)") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd.rmdir("", true).wait(); etcd.rmdir("", true).wait();
@ -417,11 +416,11 @@ TEST_CASE("delete all keys with rmdir(\"\", true)")
CHECK(resp.values().size() == 3); CHECK(resp.values().size() == 3);
} }
TEST_CASE("delete by range") TEST_CASE("delete by range") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
CHECK(etcd::ERROR_KEY_NOT_FOUND == etcd.rmdir("/test/new_dir").get().error_code()); // key not found CHECK(etcd::ERROR_KEY_NOT_FOUND ==
etcd.rmdir("/test/new_dir").get().error_code()); // key not found
etcd::Response resp = etcd.ls("/test/new_dir").get(); etcd::Response resp = etcd.ls("/test/new_dir").get();
etcd.set("/test/new_dir/key1", "value1").wait(); etcd.set("/test/new_dir/key1", "value1").wait();
@ -438,8 +437,7 @@ TEST_CASE("delete by range")
CHECK("value2" == resp.value(1).as_string()); CHECK("value2" == resp.value(1).as_string());
} }
TEST_CASE("wait for a value change") TEST_CASE("wait for a value change") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd.set("/test/key1", "42").wait(); etcd.set("/test/key1", "42").wait();
@ -447,7 +445,7 @@ TEST_CASE("wait for a value change")
CHECK(!res.is_done()); CHECK(!res.is_done());
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));
CHECK(!res.is_done()); CHECK(!res.is_done());
etcd.set("/test/key1", "43").get(); etcd.set("/test/key1", "43").get();
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));
REQUIRE(res.is_done()); REQUIRE(res.is_done());
@ -456,8 +454,7 @@ TEST_CASE("wait for a value change")
CHECK("42" == res.get().prev_value().as_string()); CHECK("42" == res.get().prev_value().as_string());
} }
TEST_CASE("wait for a directory change") TEST_CASE("wait for a directory change") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
pplx::task<etcd::Response> res = etcd.watch("/test", true); pplx::task<etcd::Response> res = etcd.watch("/test", true);
@ -483,8 +480,7 @@ TEST_CASE("wait for a directory change")
CHECK("45" == res2.get().value().as_string()); CHECK("45" == res2.get().value().as_string());
} }
TEST_CASE("watch changes in the past") TEST_CASE("watch changes in the past") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
REQUIRE(0 == etcd.rmdir("/test", true).get().error_code()); REQUIRE(0 == etcd.rmdir("/test", true).get().error_code());
int64_t index = etcd.set("/test/key1", "42").get().index(); int64_t index = etcd.set("/test/key1", "42").get().index();
@ -510,8 +506,7 @@ TEST_CASE("watch changes in the past")
CHECK("45" == res.value().as_string()); CHECK("45" == res.value().as_string());
} }
TEST_CASE("watch range changes in the past") TEST_CASE("watch range changes in the past") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
REQUIRE(0 == etcd.rmdir("/test", true).get().error_code()); REQUIRE(0 == etcd.rmdir("/test", true).get().error_code());
int64_t index = etcd.set("/test/key1", "42").get().index(); int64_t index = etcd.set("/test/key1", "42").get().index();
@ -542,53 +537,53 @@ TEST_CASE("watch multiple keys and use promise") {
int64_t start_index = etcd.set("/test/key1", "value1").get().index(); int64_t start_index = etcd.set("/test/key1", "value1").get().index();
etcd.set("/test/key2", "value2").get(); etcd.set("/test/key2", "value2").get();
pplx::task<size_t> res = etcd.watch("/test", start_index, true) pplx::task<size_t> res =
.then([](pplx::task<etcd::Response> const &resp_task) -> size_t { etcd.watch("/test", start_index, true)
auto const &resp = resp_task.get(); .then([](pplx::task<etcd::Response> const& resp_task) -> size_t {
return resp.events().size(); auto const& resp = resp_task.get();
}); return resp.events().size();
});
size_t event_size = res.get(); size_t event_size = res.get();
CHECK(2 == event_size); CHECK(2 == event_size);
} }
TEST_CASE("lease grant") TEST_CASE("lease grant") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd::Response res = etcd.leasegrant(60).get(); etcd::Response res = etcd.leasegrant(60).get();
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());
CHECK(60 == res.value().ttl()); CHECK(60 == res.value().ttl());
CHECK(0 < res.value().lease()); CHECK(0 < res.value().lease());
int64_t leaseid = res.value().lease(); int64_t leaseid = res.value().lease();
res = etcd.set("/test/key1", "43", leaseid).get(); res = etcd.set("/test/key1", "43", leaseid).get();
REQUIRE(0 == res.error_code()); // overwrite REQUIRE(0 == res.error_code()); // overwrite
CHECK("set" == res.action()); CHECK("set" == res.action());
CHECK(leaseid == res.value().lease()); CHECK(leaseid == res.value().lease());
// change with lease id // change with lease id
res = etcd.leasegrant(10).get(); res = etcd.leasegrant(10).get();
leaseid = res.value().lease(); leaseid = res.value().lease();
res = etcd.set("/test/key1", "43", leaseid).get(); res = etcd.set("/test/key1", "43", leaseid).get();
REQUIRE(0 == res.error_code()); // overwrite REQUIRE(0 == res.error_code()); // overwrite
CHECK("set" == res.action()); CHECK("set" == res.action());
CHECK(leaseid == res.value().lease()); CHECK(leaseid == res.value().lease());
// failure to attach lease id // failure to attach lease id
res = etcd.set("/test/key1", "43", leaseid+1).get(); res = etcd.set("/test/key1", "43", leaseid + 1).get();
REQUIRE(!res.is_ok()); REQUIRE(!res.is_ok());
REQUIRE(5 == res.error_code()); REQUIRE(5 == res.error_code());
CHECK("etcdserver: requested lease not found" == res.error_message()); CHECK("etcdserver: requested lease not found" == res.error_message());
res = etcd.modify("/test/key1", "44", leaseid).get(); res = etcd.modify("/test/key1", "44", leaseid).get();
REQUIRE(0 == res.error_code()); // overwrite REQUIRE(0 == res.error_code()); // overwrite
CHECK("update" == res.action()); CHECK("update" == res.action());
CHECK(leaseid == res.value().lease()); CHECK(leaseid == res.value().lease());
CHECK("44" == res.value().as_string()); CHECK("44" == res.value().as_string());
// failure to attach invalid lease id // failure to attach invalid lease id
res = etcd.modify("/test/key1", "45", leaseid+1).get(); res = etcd.modify("/test/key1", "45", leaseid + 1).get();
REQUIRE(!res.is_ok()); REQUIRE(!res.is_ok());
REQUIRE(5 == res.error_code()); REQUIRE(5 == res.error_code());
CHECK("etcdserver: requested lease not found" == res.error_message()); CHECK("etcdserver: requested lease not found" == res.error_message());
res = etcd.modify_if("/test/key1", "45", "44", leaseid).get(); res = etcd.modify_if("/test/key1", "45", "44", leaseid).get();
@ -598,9 +593,9 @@ TEST_CASE("lease grant")
CHECK("45" == res.value().as_string()); CHECK("45" == res.value().as_string());
// failure to attach invalid lease id // failure to attach invalid lease id
res = etcd.modify_if("/test/key1", "46", "45", leaseid+1).get(); res = etcd.modify_if("/test/key1", "46", "45", leaseid + 1).get();
REQUIRE(!res.is_ok()); REQUIRE(!res.is_ok());
REQUIRE(5 == res.error_code()); REQUIRE(5 == res.error_code());
CHECK("etcdserver: requested lease not found" == res.error_message()); CHECK("etcdserver: requested lease not found" == res.error_message());
// succes with the correct index & lease id // succes with the correct index & lease id
@ -610,36 +605,35 @@ TEST_CASE("lease grant")
CHECK("compareAndSwap" == res.action()); CHECK("compareAndSwap" == res.action());
CHECK("44" == res.value().as_string()); CHECK("44" == res.value().as_string());
res = etcd.modify_if("/test/key1", "44", index, leaseid+1).get(); res = etcd.modify_if("/test/key1", "44", index, leaseid + 1).get();
REQUIRE(!res.is_ok()); REQUIRE(!res.is_ok());
REQUIRE(5 == res.error_code()); REQUIRE(5 == res.error_code());
CHECK("etcdserver: requested lease not found" == res.error_message()); CHECK("etcdserver: requested lease not found" == res.error_message());
res = etcd.add("/test/key11111", "43", leaseid).get(); res = etcd.add("/test/key11111", "43", leaseid).get();
REQUIRE(0 == res.error_code()); REQUIRE(0 == res.error_code());
CHECK("create" == res.action()); CHECK("create" == res.action());
CHECK(leaseid == res.value().lease()); CHECK(leaseid == res.value().lease());
//failure to attach invalid lease id // failure to attach invalid lease id
res = etcd.set("/test/key11111", "43", leaseid+1).get(); res = etcd.set("/test/key11111", "43", leaseid + 1).get();
REQUIRE(!res.is_ok()); REQUIRE(!res.is_ok());
REQUIRE(5 == res.error_code()); REQUIRE(5 == res.error_code());
CHECK("etcdserver: requested lease not found" == res.error_message()); CHECK("etcdserver: requested lease not found" == res.error_message());
} }
TEST_CASE("lease list") TEST_CASE("lease list") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd::Response res = etcd.leasegrant(60).get(); etcd::Response res = etcd.leasegrant(60).get();
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());
CHECK(60 == res.value().ttl()); CHECK(60 == res.value().ttl());
CHECK(0 < res.value().lease()); CHECK(0 < res.value().lease());
int64_t leaseid = res.value().lease(); int64_t leaseid = res.value().lease();
etcd::Response leasesresp = etcd.leases().get(); etcd::Response leasesresp = etcd.leases().get();
if (leasesresp.is_ok()) { if (leasesresp.is_ok()) {
REQUIRE(leasesresp.is_ok()); REQUIRE(leasesresp.is_ok());
auto const &leases = leasesresp.leases(); auto const& leases = leasesresp.leases();
REQUIRE(leases.size() > 0); REQUIRE(leases.size() > 0);
CHECK(std::find(leases.begin(), leases.end(), leaseid) != leases.end()); CHECK(std::find(leases.begin(), leases.end(), leaseid) != leases.end());
} else { } else {
@ -647,8 +641,7 @@ TEST_CASE("lease list")
} }
} }
TEST_CASE("cleanup") TEST_CASE("cleanup") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
REQUIRE(0 == etcd.rmdir("/test", true).get().error_code()); REQUIRE(0 == etcd.rmdir("/test", true).get().error_code());
} }

View File

@ -12,10 +12,10 @@
#include "etcd/Client.hpp" #include "etcd/Client.hpp"
#include "etcd/KeepAlive.hpp" #include "etcd/KeepAlive.hpp"
static const std::string etcd_url = etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379"); static const std::string etcd_url =
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
TEST_CASE("fork: set in child and get from self") TEST_CASE("fork: set in child and get from self") {
{
pid_t pid = fork(); pid_t pid = fork();
REQUIRE(pid >= 0); REQUIRE(pid >= 0);
@ -29,15 +29,15 @@ TEST_CASE("fork: set in child and get from self")
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
size_t check = 0; size_t check = 0;
while (check < 10) { while (check < 10) {
auto resp = etcd.get("/test/fork-key1").get(); auto resp = etcd.get("/test/fork-key1").get();
if (!resp.is_ok()) { if (!resp.is_ok()) {
check += 1; check += 1;
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));
continue; continue;
} else { } else {
CHECK(resp.value().as_string() == "fork: abcdefgh"); CHECK(resp.value().as_string() == "fork: abcdefgh");
break; break;
} }
} }
std::cout << "self: get finished ..." << std::endl; std::cout << "self: get finished ..." << std::endl;
} }

View File

@ -10,8 +10,8 @@
#include "etcd/SyncClient.hpp" #include "etcd/SyncClient.hpp"
#include "etcd/Value.hpp" #include "etcd/Value.hpp"
static std::string etcd_uri = etcdv3::detail::resolve_etcd_endpoints( static std::string etcd_uri =
"http://127.0.0.1:2379,http://127.0.0.1:2479,http://127.0.0.1:2579"); etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
TEST_CASE("keepalive revoke and check if alive") { TEST_CASE("keepalive revoke and check if alive") {
etcd::Client etcd(etcd_uri); etcd::Client etcd(etcd_uri);
@ -33,3 +33,30 @@ TEST_CASE("keepalive revoke and check if alive") {
// expect keep_alive->Check() to throw exception // expect keep_alive->Check() to throw exception
REQUIRE_THROWS(keepalive->Check()); REQUIRE_THROWS(keepalive->Check());
} }
TEST_CASE("keepalive won't expire") {
etcd::Client etcd(etcd_uri);
const int64_t ttl = 3;
const std::string key = "key";
const std::string meta_str = "meta ....";
etcd::Response resp = etcd.leasegrant(ttl).get();
auto lease_id = resp.value().lease();
etcd.add(key, meta_str, lease_id);
std::function<void(std::exception_ptr)> handler =
[](std::exception_ptr eptr) {
try {
if (eptr) {
std::rethrow_exception(eptr);
}
} catch (const std::runtime_error& e) {
std::cerr << "Connection failure \"" << e.what() << "\"\n";
} catch (const std::out_of_range& e) {
std::cerr << "Lease expiry \"" << e.what() << "\"\n";
}
};
etcd::KeepAlive keepalive(etcd, handler, ttl, lease_id);
std::this_thread::sleep_for(std::chrono::seconds(5));
}

View File

@ -10,10 +10,10 @@
#include "etcd/Client.hpp" #include "etcd/Client.hpp"
#include "etcd/KeepAlive.hpp" #include "etcd/KeepAlive.hpp"
static const std::string etcd_url = etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379"); static const std::string etcd_url =
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
TEST_CASE("lock and unlock") TEST_CASE("lock and unlock") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
// lock // lock
@ -29,8 +29,7 @@ TEST_CASE("lock and unlock")
REQUIRE(0 == resp2.error_code()); REQUIRE(0 == resp2.error_code());
} }
TEST_CASE("double lock will fail") TEST_CASE("double lock will fail") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
// lock // lock
@ -42,7 +41,7 @@ TEST_CASE("double lock will fail")
bool first_lock_release = false; bool first_lock_release = false;
std::string lock_key = resp1.lock_key(); std::string lock_key = resp1.lock_key();
auto second_lock_thr = std::thread([&](){ auto second_lock_thr = std::thread([&]() {
// lock again // lock again
etcd::Response resp2 = etcd.lock("/test/abcd").get(); etcd::Response resp2 = etcd.lock("/test/abcd").get();
CHECK("lock" == resp2.action()); CHECK("lock" == resp2.action());
@ -62,7 +61,8 @@ TEST_CASE("double lock will fail")
REQUIRE(0 == resp3.error_code()); REQUIRE(0 == resp3.error_code());
// create a duration // create a duration
// using a duration longer than default lease TTL for lock (see: DEFAULT_LEASE_TTL_FOR_LOCK) // using a duration longer than default lease TTL for lock (see:
// DEFAULT_LEASE_TTL_FOR_LOCK)
std::this_thread::sleep_for(std::chrono::seconds(15)); std::this_thread::sleep_for(std::chrono::seconds(15));
// unlock the first lock // unlock the first lock
@ -84,8 +84,7 @@ TEST_CASE("double lock will fail")
REQUIRE(0 == resp5.error_code()); REQUIRE(0 == resp5.error_code());
} }
TEST_CASE("lock could be timeout") TEST_CASE("lock could be timeout") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
// setup the timeout // setup the timeout
@ -97,7 +96,7 @@ TEST_CASE("lock could be timeout")
REQUIRE(resp1.is_ok()); REQUIRE(resp1.is_ok());
REQUIRE(0 == resp1.error_code()); REQUIRE(0 == resp1.error_code());
auto lock_in_another_thread = std::thread([&](){ auto lock_in_another_thread = std::thread([&]() {
// lock again // lock again
etcd::Response resp2 = etcd.lock("/test/abcd").get(); etcd::Response resp2 = etcd.lock("/test/abcd").get();
CHECK("lock" == resp2.action()); CHECK("lock" == resp2.action());
@ -113,22 +112,22 @@ TEST_CASE("lock could be timeout")
REQUIRE(0 == resp5.error_code()); REQUIRE(0 == resp5.error_code());
} }
TEST_CASE("lock using lease") TEST_CASE("lock using lease") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
bool failed = false; bool failed = false;
std::function<void (std::exception_ptr)> handler = [&failed](std::exception_ptr eptr) { std::function<void(std::exception_ptr)> handler =
try { [&failed](std::exception_ptr eptr) {
if (eptr) { try {
if (eptr) {
std::rethrow_exception(eptr); std::rethrow_exception(eptr);
}
} catch (const std::exception& e) {
std::cerr << "Caught exception \"" << e.what() << "\"\n";
failed = true;
} }
} catch(const std::exception& e) { };
std::cerr << "Caught exception \"" << e.what() << "\"\n";
failed = true;
}
};
// with handler // with handler
{ {
@ -197,25 +196,31 @@ TEST_CASE("lock using lease")
} }
} }
TEST_CASE("concurrent lock & unlock") TEST_CASE("concurrent lock & unlock") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
std::string const lock_key = "/test/test_key"; std::string const lock_key = "/test/test_key";
constexpr size_t trials = 192; constexpr size_t trials = 192;
std::function<void(std::string const &, const size_t)> locker = [&etcd](std::string const &key, const size_t index) { std::function<void(std::string const&, const size_t)> locker =
std::cout << "start lock for " << key << ", index is " << index << std::endl; [&etcd](std::string const& key, const size_t index) {
auto resp = etcd.lock(key).get(); std::cout << "start lock for " << key << ", index is " << index
std::cout << "lock for " << index << " is ok, starts sleeping: ..." << resp.error_message() << std::endl << std::flush; << std::endl;
REQUIRE(resp.is_ok()); auto resp = etcd.lock(key).get();
std::srand(index); std::cout << "lock for " << index << " is ok, starts sleeping: ..."
size_t time_to_sleep = 1; << resp.error_message() << std::endl
std::this_thread::sleep_for(std::chrono::seconds(time_to_sleep)); << std::flush;
std::cout << "lock for " << index << " resumes from sleep: ..." << resp.error_message() << std::endl << std::flush; REQUIRE(resp.is_ok());
REQUIRE(etcd.unlock(resp.lock_key()).get().is_ok()); std::srand(index);
std::cout << "thread " << index << " been unlocked" << std::endl << std::flush; size_t time_to_sleep = 1;
}; std::this_thread::sleep_for(std::chrono::seconds(time_to_sleep));
std::cout << "lock for " << index << " resumes from sleep: ..."
<< resp.error_message() << std::endl
<< std::flush;
REQUIRE(etcd.unlock(resp.lock_key()).get().is_ok());
std::cout << "thread " << index << " been unlocked" << std::endl
<< std::flush;
};
std::vector<std::thread> locks(trials); std::vector<std::thread> locks(trials);
for (size_t index = 0; index < trials; ++index) { for (size_t index = 0; index < trials; ++index) {
@ -233,16 +238,19 @@ TEST_CASE("concurrent lock & unlock with a put in between") {
constexpr size_t trials = 128; constexpr size_t trials = 128;
std::function<void(std::string const &, const size_t)> locker = [&etcd](std::string const &key, const size_t index) { std::function<void(std::string const&, const size_t)> locker =
std::cout << "start lock for " << index << std::endl; [&etcd](std::string const& key, const size_t index) {
auto resp = etcd.lock(key, true).get(); std::cout << "start lock for " << index << std::endl;
std::cout << "lock for " << index << " is ok, start put and unlock: ..." << resp.error_message() << std::endl; auto resp = etcd.lock(key, true).get();
REQUIRE(resp.is_ok()); std::cout << "lock for " << index << " is ok, start put and unlock: ..."
auto put_resp = etcd.put("/test/test_put", "hello" + std::to_string(index)).get(); << resp.error_message() << std::endl;
REQUIRE(put_resp.is_ok()); REQUIRE(resp.is_ok());
REQUIRE(etcd.unlock(resp.lock_key()).get().is_ok()); auto put_resp =
std::cout << "thread " << index << " been unlocked" << std::endl; etcd.put("/test/test_put", "hello" + std::to_string(index)).get();
}; REQUIRE(put_resp.is_ok());
REQUIRE(etcd.unlock(resp.lock_key()).get().is_ok());
std::cout << "thread " << index << " been unlocked" << std::endl;
};
std::vector<std::thread> locks(trials); std::vector<std::thread> locks(trials);
for (size_t index = 0; index < trials; ++index) { for (size_t index = 0; index < trials; ++index) {

View File

@ -6,25 +6,22 @@
#include "etcd/Client.hpp" #include "etcd/Client.hpp"
#include "etcd/KeepAlive.hpp" #include "etcd/KeepAlive.hpp"
static const std::string etcd_url = etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379"); static const std::string etcd_url =
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
class DistributedLock { class DistributedLock {
public: public:
DistributedLock(const std::string &lock_name, DistributedLock(const std::string& lock_name, uint timeout = 0);
uint timeout = 0); ~DistributedLock() noexcept;
~DistributedLock() noexcept; inline bool lock_acquired() { return _acquired; }
inline bool lock_acquired() {
return _acquired;
}
private: private:
bool _acquired = false; bool _acquired = false;
std::string _lock_key; std::string _lock_key;
std::unique_ptr<::etcd::Client> _etcd_client; std::unique_ptr<::etcd::Client> _etcd_client;
}; };
DistributedLock::DistributedLock(const std::string &lock_name, DistributedLock::DistributedLock(const std::string& lock_name, uint timeout) {
uint timeout) {
_etcd_client = std::unique_ptr<etcd::Client>(new etcd::Client(etcd_url)); _etcd_client = std::unique_ptr<etcd::Client>(new etcd::Client(etcd_url));
try { try {
@ -35,12 +32,14 @@ DistributedLock::DistributedLock(const std::string &lock_name,
_acquired = true; _acquired = true;
} }
} else { } else {
std::future<etcd::Response> future = std::async(std::launch::async, [&]() { std::future<etcd::Response> future =
etcd::Response resp = _etcd_client->lock(lock_name).get(); std::async(std::launch::async, [&]() {
return resp; etcd::Response resp = _etcd_client->lock(lock_name).get();
}); return resp;
});
std::future_status status = future.wait_for(std::chrono::seconds(timeout)); std::future_status status =
future.wait_for(std::chrono::seconds(timeout));
if (status == std::future_status::ready) { if (status == std::future_status::ready) {
auto resp = future.get(); auto resp = future.get();
if (resp.is_ok()) { if (resp.is_ok()) {
@ -48,12 +47,13 @@ DistributedLock::DistributedLock(const std::string &lock_name,
_acquired = true; _acquired = true;
} }
} else if (status == std::future_status::timeout) { } else if (status == std::future_status::timeout) {
std::cerr << "failed to acquire distributed because of lock timeout" << std::endl; std::cerr << "failed to acquire distributed because of lock timeout"
<< std::endl;
} else { } else {
std::cerr << "failed to acquire distributed lock" << std::endl; std::cerr << "failed to acquire distributed lock" << std::endl;
} }
} }
} catch (std::exception &e) { } catch (std::exception& e) {
std::cerr << "failed to construct: " << e.what() << std::endl; std::cerr << "failed to construct: " << e.what() << std::endl;
} }
} }
@ -68,17 +68,17 @@ DistributedLock::~DistributedLock() noexcept {
if (!resp.is_ok()) { if (!resp.is_ok()) {
std::cout << resp.error_code() << std::endl; std::cout << resp.error_code() << std::endl;
} }
} catch (std::exception &e) { } catch (std::exception& e) {
std::cerr << "failed to destruct: " << e.what() << std::endl; std::cerr << "failed to destruct: " << e.what() << std::endl;
} }
} }
int main() { int main() {
int i = 0, t = 0; int i = 0, t = 0;
while(t < 100 /* update this value to make it run for longer */) { while (t < 100 /* update this value to make it run for longer */) {
{ {
DistributedLock lock(std::to_string(i), 0); DistributedLock lock(std::to_string(i), 0);
if(!lock.lock_acquired()) { if (!lock.lock_acquired()) {
std::cerr << "failed to acquire lock" << std::endl; std::cerr << "failed to acquire lock" << std::endl;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1));

View File

@ -8,14 +8,12 @@
#include "etcd/KeepAlive.hpp" #include "etcd/KeepAlive.hpp"
#include "etcd/Watcher.hpp" #include "etcd/Watcher.hpp"
static const std::string etcd_url = etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379"); static const std::string etcd_url =
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
static std::atomic_int watcher_called; static std::atomic_int watcher_called;
void print_response(etcd::Response const & resp) void print_response(etcd::Response const& resp) { watcher_called.fetch_add(1); }
{
watcher_called.fetch_add(1);
}
/** /**
* @brief emulate the behavior of creating watcher many times: * @brief emulate the behavior of creating watcher many times:
@ -24,7 +22,8 @@ void print_response(etcd::Response const & resp)
* 2. change a value * 2. change a value
* 3. cancel the watcher * 3. cancel the watcher
*/ */
void watch_once(etcd::Client & client, std::unique_ptr<etcd::Watcher> &watcher, const size_t round) { void watch_once(etcd::Client& client, std::unique_ptr<etcd::Watcher>& watcher,
const size_t round) {
const std::string my_prefix = "/test"; const std::string my_prefix = "/test";
const std::string my_key = my_prefix + "/foo"; const std::string my_key = my_prefix + "/foo";
watcher.reset(new etcd::Watcher(client, my_prefix, print_response, true)); watcher.reset(new etcd::Watcher(client, my_prefix, print_response, true));
@ -42,19 +41,20 @@ void watch_once(etcd::Client & client, std::unique_ptr<etcd::Watcher> &watcher,
watcher->Cancel(); watcher->Cancel();
} }
TEST_CASE("watch shouldn't leak memory") TEST_CASE("watch shouldn't leak memory") {
{
watcher_called.store(0); watcher_called.store(0);
// issue some changes to see if the watcher works // issue some changes to see if the watcher works
etcd::Client client(etcd_url); etcd::Client client(etcd_url);
std::unique_ptr<etcd::Watcher> watcher; std::unique_ptr<etcd::Watcher> watcher;
for (int round = 0; round < 10 /* update this value to make it run for longer */; ++round) { for (int round = 0;
round < 10 /* update this value to make it run for longer */; ++round) {
if (round % 50 == 0) { if (round % 50 == 0) {
std::cout << "starting round " << round << std::endl; std::cout << "starting round " << round << std::endl;
} }
watch_once(client, watcher, round); watch_once(client, watcher, round);
} }
std::cout << "watcher been called for " << watcher_called.load() << " times" << std::endl; std::cout << "watcher been called for " << watcher_called.load() << " times"
<< std::endl;
} }

View File

@ -8,27 +8,28 @@
#include "etcd/SyncClient.hpp" #include "etcd/SyncClient.hpp"
#include "etcd/Watcher.hpp" #include "etcd/Watcher.hpp"
static const std::string etcd_url = etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379"); static const std::string etcd_url =
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
static int watcher_called = 0; static int watcher_called = 0;
void print_response(etcd::Response const & resp) void print_response(etcd::Response const& resp) {
{
++watcher_called; ++watcher_called;
std::cout << "print response called" << std::endl; std::cout << "print response called" << std::endl;
if (resp.error_code()) { if (resp.error_code()) {
std::cout << resp.error_code() << ": " << resp.error_message() << std::endl; std::cout << resp.error_code() << ": " << resp.error_message() << std::endl;
} } else {
else {
std::cout << resp.action() << " " << resp.value().as_string() << std::endl; std::cout << resp.action() << " " << resp.value().as_string() << std::endl;
std::cout << "Previous value: " << resp.prev_value().as_string() << std::endl; std::cout << "Previous value: " << resp.prev_value().as_string()
<< std::endl;
std::cout << "Events size: " << resp.events().size() << std::endl; std::cout << "Events size: " << resp.events().size() << std::endl;
for (auto const &ev: resp.events()) { for (auto const& ev : resp.events()) {
std::cout << "Value change in events: " << static_cast<int>(ev.event_type()) std::cout << "Value change in events: "
<< ", prev kv = " << ev.prev_kv().key() << " -> " << ev.prev_kv().as_string() << static_cast<int>(ev.event_type())
<< ", kv = " << ev.kv().key() << " -> " << ev.kv().as_string() << ", prev kv = " << ev.prev_kv().key() << " -> "
<< std::endl; << ev.prev_kv().as_string() << ", kv = " << ev.kv().key()
<< " -> " << ev.kv().as_string() << std::endl;
} }
} }
} }
@ -48,8 +49,7 @@ void wait_for_connection(std::string endpoints) {
} }
} }
void initialize_watcher(const std::string& endpoints, void initialize_watcher(const std::string& endpoints, const std::string& prefix,
const std::string& prefix,
std::function<void(etcd::Response)> callback, std::function<void(etcd::Response)> callback,
std::shared_ptr<etcd::Watcher>& watcher) { std::shared_ptr<etcd::Watcher>& watcher) {
// wait until the endpoints turn to be available // wait until the endpoints turn to be available
@ -64,18 +64,19 @@ void initialize_watcher(const std::string& endpoints,
watcher.reset(new etcd::Watcher(client, prefix, callback, true)); watcher.reset(new etcd::Watcher(client, prefix, callback, true));
// Note that lambda requires `mutable`qualifier. // Note that lambda requires `mutable`qualifier.
watcher->Wait([endpoints, prefix, callback, watcher->Wait(
/* By reference for renewing */ &watcher](bool cancelled) mutable { [endpoints, prefix, callback,
if (cancelled) { /* By reference for renewing */ &watcher](bool cancelled) mutable {
std::cout << "watcher's reconnect loop stopped as been cancelled" << std::endl; if (cancelled) {
return; std::cout << "watcher's reconnect loop stopped as been cancelled"
} << std::endl;
initialize_watcher(endpoints, prefix, callback, watcher); return;
}); }
initialize_watcher(endpoints, prefix, callback, watcher);
});
} }
TEST_CASE("watch should can be re-established") TEST_CASE("watch should can be re-established") {
{
const std::string my_prefix = "/test"; const std::string my_prefix = "/test";
// the watcher initialized in this way will auto re-connect to etcd // the watcher initialized in this way will auto re-connect to etcd
@ -86,8 +87,8 @@ TEST_CASE("watch should can be re-established")
for (int round = 0; round < 100000; ++round) { for (int round = 0; round < 100000; ++round) {
try { try {
etcd::Client client(etcd_url); etcd::Client client(etcd_url);
auto response = client.set( auto response =
my_prefix + "/foo", "bar-" + std::to_string(round)).get(); client.set(my_prefix + "/foo", "bar-" + std::to_string(round)).get();
} catch (...) { } catch (...) {
// pass // pass
} }
@ -102,8 +103,8 @@ TEST_CASE("watch should can be re-established")
for (int round = 10; round < 20; ++round) { for (int round = 10; round < 20; ++round) {
try { try {
etcd::Client client(etcd_url); etcd::Client client(etcd_url);
auto response = client.set( auto response =
my_prefix + "/foo", "bar-" + std::to_string(round)).get(); client.set(my_prefix + "/foo", "bar-" + std::to_string(round)).get();
} catch (...) { } catch (...) {
// pass // pass
} }

View File

@ -9,22 +9,21 @@ static std::string ca = "security-config/certs/ca.crt";
static std::string cert = "security-config/certs/etcd0.example.com.crt"; static std::string cert = "security-config/certs/etcd0.example.com.crt";
static std::string key = "security-config/private/etcd0.example.com.key"; static std::string key = "security-config/private/etcd0.example.com.key";
static const std::string etcd_url = etcdv3::detail::resolve_etcd_endpoints("https://127.0.0.1:2379"); static const std::string etcd_url =
etcdv3::detail::resolve_etcd_endpoints("https://127.0.0.1:2379");
TEST_CASE("setup with auth") TEST_CASE("setup with auth") {
{ etcd::Client* etcd = etcd::Client::WithSSL(etcd_url, ca, cert, key);
etcd::Client *etcd = etcd::Client::WithSSL(etcd_url, ca, cert, key);
etcd->rmdir("/test", true).wait(); etcd->rmdir("/test", true).wait();
} }
TEST_CASE("add a new key after authenticate") TEST_CASE("add a new key after authenticate") {
{ etcd::Client* etcd = etcd::Client::WithSSL(etcd_url, ca, cert, key);
etcd::Client *etcd = etcd::Client::WithSSL(etcd_url, ca, cert, key);
etcd->rmdir("/test", true).wait(); etcd->rmdir("/test", true).wait();
etcd::Response resp = etcd->add("/test/key1", "42").get(); etcd::Response resp = etcd->add("/test/key1", "42").get();
REQUIRE(0 == resp.error_code()); REQUIRE(0 == resp.error_code());
CHECK("create" == resp.action()); CHECK("create" == resp.action());
etcd::Value const & val = resp.value(); etcd::Value const& val = resp.value();
CHECK("42" == val.as_string()); CHECK("42" == val.as_string());
CHECK("/test/key1" == val.key()); CHECK("/test/key1" == val.key());
CHECK(!val.is_dir()); CHECK(!val.is_dir());
@ -32,24 +31,28 @@ TEST_CASE("add a new key after authenticate")
CHECK(0 < val.modified_index()); CHECK(0 < val.modified_index());
CHECK(1 == val.version()); CHECK(1 == val.version());
CHECK(0 < resp.index()); CHECK(0 < resp.index());
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "43").get().error_code()); // Key already exists CHECK(
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "42").get().error_code()); // Key already exists etcd::ERROR_KEY_ALREADY_EXISTS ==
CHECK("etcd-cpp-apiv3: key already exists" == etcd->add("/test/key1", "42").get().error_message()); etcd->add("/test/key1", "43").get().error_code()); // Key already exists
CHECK(
etcd::ERROR_KEY_ALREADY_EXISTS ==
etcd->add("/test/key1", "42").get().error_code()); // Key already exists
CHECK("etcd-cpp-apiv3: key already exists" ==
etcd->add("/test/key1", "42").get().error_message());
} }
TEST_CASE("read a value from etcd") TEST_CASE("read a value from etcd") {
{ etcd::Client* etcd = etcd::Client::WithSSL(etcd_url, ca, cert, key);
etcd::Client *etcd = etcd::Client::WithSSL(etcd_url, ca, cert, key);
etcd::Response resp = etcd->get("/test/key1").get(); etcd::Response resp = etcd->get("/test/key1").get();
CHECK("get" == resp.action()); CHECK("get" == resp.action());
REQUIRE(resp.is_ok()); REQUIRE(resp.is_ok());
REQUIRE(0 == resp.error_code()); REQUIRE(0 == resp.error_code());
CHECK("42" == resp.value().as_string()); CHECK("42" == resp.value().as_string());
CHECK("" == etcd->get("/test").get().value().as_string()); // key points to a directory CHECK("" == etcd->get("/test").get().value().as_string()); // key points to a
// directory
} }
TEST_CASE("cleanup") TEST_CASE("cleanup") {
{ etcd::Client* etcd = etcd::Client::WithSSL(etcd_url, ca, cert, key);
etcd::Client *etcd = etcd::Client::WithSSL(etcd_url, ca, cert, key);
REQUIRE(0 == etcd->rmdir("/test", true).get().error_code()); REQUIRE(0 == etcd->rmdir("/test", true).get().error_code());
} }

View File

@ -8,16 +8,15 @@
#include "etcd/Client.hpp" #include "etcd/Client.hpp"
#include "etcd/v3/Transaction.hpp" #include "etcd/v3/Transaction.hpp"
static const std::string etcd_url = etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379"); static const std::string etcd_url =
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
TEST_CASE("setup") TEST_CASE("setup") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd.rmdir("/test", true).wait(); etcd.rmdir("/test", true).wait();
} }
TEST_CASE("add a new key") TEST_CASE("add a new key") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
etcd.rmdir("/test", true).wait(); etcd.rmdir("/test", true).wait();
@ -49,13 +48,15 @@ TEST_CASE("add a new key")
// do some put and delete using txn // do some put and delete using txn
{ {
etcdv3::Transaction txn; etcdv3::Transaction txn;
// setup the conditions // setup the conditions
txn.reset_key("/test/x1"); txn.reset_key("/test/x1");
txn.init_compare("1", etcdv3::CompareResult::EQUAL, etcdv3::CompareTarget::VALUE); txn.init_compare("1", etcdv3::CompareResult::EQUAL,
etcdv3::CompareTarget::VALUE);
txn.reset_key("/test/x2"); txn.reset_key("/test/x2");
txn.init_compare("2", etcdv3::CompareResult::EQUAL, etcdv3::CompareTarget::VALUE); txn.init_compare("2", etcdv3::CompareResult::EQUAL,
etcdv3::CompareTarget::VALUE);
txn.setup_put("/test/x1", "111"); txn.setup_put("/test/x1", "111");
txn.setup_delete("/test/x2"); txn.setup_delete("/test/x2");
@ -83,8 +84,7 @@ TEST_CASE("add a new key")
} }
} }
TEST_CASE("cleanup") TEST_CASE("cleanup") {
{
etcd::Client etcd(etcd_url); etcd::Client etcd(etcd_url);
REQUIRE(0 == etcd.rmdir("/test", true).get().error_code()); REQUIRE(0 == etcd.rmdir("/test", true).get().error_code());
} }

View File

@ -4,41 +4,42 @@
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include "etcd/Watcher.hpp"
#include "etcd/SyncClient.hpp" #include "etcd/SyncClient.hpp"
#include "etcd/Watcher.hpp"
static const std::string etcd_url = etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379"); static const std::string etcd_url =
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
static int watcher_called = 0; static int watcher_called = 0;
void printResponse(etcd::Response const & resp) void printResponse(etcd::Response const& resp) {
{
if (resp.error_code()) { if (resp.error_code()) {
std::cout << "Watcher "<< resp.watch_id() std::cout << "Watcher " << resp.watch_id() << " fails with "
<< " fails with " << resp.error_code() << ": " << resp.error_message() << std::endl; << resp.error_code() << ": " << resp.error_message() << std::endl;
} } else {
else { std::cout << "Watcher " << resp.watch_id() << " responses with "
std::cout << "Watcher " << resp.watch_id() << resp.action() << " " << resp.value().as_string() << std::endl;
<< " responses with " << resp.action() << " " << resp.value().as_string() << std::endl; std::cout << "Previous value: " << resp.prev_value().as_string()
std::cout << "Previous value: " << resp.prev_value().as_string() << std::endl; << std::endl;
std::cout << "Events size: " << resp.events().size() << std::endl; std::cout << "Events size: " << resp.events().size() << std::endl;
for (auto const &ev: resp.events()) { for (auto const& ev : resp.events()) {
if (ev.prev_kv().key().find("/leader") == 0 || ev.kv().key().find("/leader") == 0) { if (ev.prev_kv().key().find("/leader") == 0 ||
ev.kv().key().find("/leader") == 0) {
return; return;
} }
std::cout << "Value change in events: " << static_cast<int>(ev.event_type()) std::cout << "Value change in events: "
<< ", prev kv = " << ev.prev_kv().key() << " -> " << ev.prev_kv().as_string() << static_cast<int>(ev.event_type())
<< ", kv = " << ev.kv().key() << " -> " << ev.kv().as_string() << ", prev kv = " << ev.prev_kv().key() << " -> "
<< std::endl; << ev.prev_kv().as_string() << ", kv = " << ev.kv().key()
<< " -> " << ev.kv().as_string() << std::endl;
} }
} }
std::cout << "print response called" << std::endl; std::cout << "print response called" << std::endl;
++watcher_called; ++watcher_called;
} }
TEST_CASE("create watcher") TEST_CASE("create watcher") {
{
etcd::SyncClient etcd(etcd_url); etcd::SyncClient etcd(etcd_url);
etcd.rmdir("/test", true); etcd.rmdir("/test", true);
@ -55,8 +56,7 @@ TEST_CASE("create watcher")
etcd.rmdir("/test", true); etcd.rmdir("/test", true);
} }
TEST_CASE("watch with correct prefix") TEST_CASE("watch with correct prefix") {
{
etcd::SyncClient etcd(etcd_url); etcd::SyncClient etcd(etcd_url);
etcd.rmdir("/test", true); etcd.rmdir("/test", true);
@ -92,8 +92,7 @@ TEST_CASE("watch with correct prefix")
etcd.rmdir("/test", true); etcd.rmdir("/test", true);
} }
TEST_CASE("create watcher with cancel") TEST_CASE("create watcher with cancel") {
{
etcd::SyncClient etcd(etcd_url); etcd::SyncClient etcd(etcd_url);
etcd.rmdir("/test", true); etcd.rmdir("/test", true);
@ -115,8 +114,7 @@ TEST_CASE("create watcher with cancel")
etcd.rmdir("/test", true); etcd.rmdir("/test", true);
} }
TEST_CASE("create watcher on ranges with cancel") TEST_CASE("create watcher on ranges with cancel") {
{
etcd::SyncClient etcd(etcd_url); etcd::SyncClient etcd(etcd_url);
etcd.rmdir("/test", true); etcd.rmdir("/test", true);
@ -138,29 +136,24 @@ TEST_CASE("create watcher on ranges with cancel")
etcd.rmdir("/test", true); etcd.rmdir("/test", true);
} }
TEST_CASE("watch should exit normally") TEST_CASE("watch should exit normally") {
{
// cancel immediately after start watch. // cancel immediately after start watch.
etcd::Watcher watcher(etcd_url, "/test", printResponse, true); etcd::Watcher watcher(etcd_url, "/test", printResponse, true);
watcher.Cancel(); watcher.Cancel();
} }
TEST_CASE("watch should can be cancelled repeatedly") TEST_CASE("watch should can be cancelled repeatedly") {
{
etcd::Watcher watcher(etcd_url, "/test", printResponse, true); etcd::Watcher watcher(etcd_url, "/test", printResponse, true);
std::vector<std::thread> threads(10); std::vector<std::thread> threads(10);
for (size_t i = 0; i < 10; ++i) { for (size_t i = 0; i < 10; ++i) {
threads[i] = std::thread([&]() { threads[i] = std::thread([&]() { watcher.Cancel(); });
watcher.Cancel();
});
} }
for (size_t i = 0; i < 10; ++i) { for (size_t i = 0; i < 10; ++i) {
threads[i].join(); threads[i].join();
} }
} }
TEST_CASE("watch changes on the same key (#212)") TEST_CASE("watch changes on the same key (#212)") {
{
std::string key_watch = "key watch"; std::string key_watch = "key watch";
etcd::SyncClient client(etcd_url); etcd::SyncClient client(etcd_url);
client.put(key_watch, "inittt"); client.put(key_watch, "inittt");
@ -168,33 +161,30 @@ TEST_CASE("watch changes on the same key (#212)")
auto current_index = client.head().index(); auto current_index = client.head().index();
std::cout << "Current index " << current_index << std::endl; std::cout << "Current index " << current_index << std::endl;
auto internal_cb = [&](etcd::Response resp) -> void { auto internal_cb = [&](etcd::Response resp) -> void {
if (!resp.is_ok()) { if (!resp.is_ok()) {
std::cout << "Error: " << resp.error_message() << std::endl; std::cout << "Error: " << resp.error_message() << std::endl;
return; return;
} }
for (auto const &event: resp.events()) { for (auto const& event : resp.events()) {
std::cout << "Watch '" << event.kv().key() std::cout << "Watch '" << event.kv().key()
<< "'. ModifedRevision : " << event.kv().modified_index() << "'. ModifedRevision : " << event.kv().modified_index()
<< "', Vision : " << event.kv().version() << "', Vision : " << event.kv().version()
<< ", value = " << event.kv().as_string() << std::endl; << ", value = " << event.kv().as_string() << std::endl;
} }
}; };
auto wait_cb = [&](bool) {}; auto wait_cb = [&](bool) {};
etcd::Watcher w(client, key_watch, current_index, etcd::Watcher w(client, key_watch, current_index, std::move(internal_cb),
std::move(internal_cb), std::move(wait_cb), false);
std::move(wait_cb),
false);
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
for (int i = 0; i < 10; ) { for (int i = 0; i < 10; ++i) {
std::string value = "watch_" + std::to_string(i++); std::string value = "watch_" + std::to_string(i);
client.put(key_watch, value); client.put(key_watch, value);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
} }
} }
TEST_CASE("create two watcher") TEST_CASE("create two watcher") {
{
etcd::Watcher w1(etcd_url, "/test", printResponse, true); etcd::Watcher w1(etcd_url, "/test", printResponse, true);
etcd::Watcher w2(etcd_url, "/test", printResponse, true); etcd::Watcher w2(etcd_url, "/test", printResponse, true);