Compare commits
No commits in common. "master" and "v0.15.0" have entirely different histories.
|
|
@ -16,7 +16,7 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-20.04, ubuntu-22.04, macos-11, macos-12]
|
os: [ubuntu-20.04, ubuntu-22.04, macos-11, macos-12]
|
||||||
etcd: [v3.2.32, v3.3.27, v3.4.27, v3.5.9]
|
etcd: [v3.2.26, v3.3.11, v3.4.13, v3.5.7]
|
||||||
exclude:
|
exclude:
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
etcd: v3.2.26
|
etcd: v3.2.26
|
||||||
|
|
@ -243,10 +243,6 @@ jobs:
|
||||||
|
|
||||||
# tests without auth
|
# tests without auth
|
||||||
|
|
||||||
echo "Run the etcd resolver test ........................."
|
|
||||||
# there's no ipv6 on github CI runner
|
|
||||||
# ./build/bin/EtcdResolverTest
|
|
||||||
|
|
||||||
echo "Run the etcd sync test ........................."
|
echo "Run the etcd sync test ........................."
|
||||||
./build/bin/EtcdSyncTest
|
./build/bin/EtcdSyncTest
|
||||||
|
|
||||||
|
|
@ -403,26 +399,6 @@ jobs:
|
||||||
killall -TERM etcd
|
killall -TERM etcd
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|
||||||
- name: Etcd Member test
|
|
||||||
run: |
|
|
||||||
killall -TERM etcd || true
|
|
||||||
sleep 5
|
|
||||||
|
|
||||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib:/usr/local/lib/x86_64-linux-gnu
|
|
||||||
|
|
||||||
# use etcd v3 api
|
|
||||||
export ETCDCTL_API="3"
|
|
||||||
|
|
||||||
|
|
||||||
rm -rf default.etcd
|
|
||||||
/usr/local/bin/etcd &
|
|
||||||
sleep 5
|
|
||||||
|
|
||||||
./build/bin/EtcdMemberTest
|
|
||||||
|
|
||||||
killall -TERM etcd
|
|
||||||
sleep 5
|
|
||||||
|
|
||||||
- name: Check ccache
|
- name: Check ccache
|
||||||
run: |
|
run: |
|
||||||
ccache --show-stats
|
ccache --show-stats
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
set(etcd-cpp-api_VERSION_MAJOR 0)
|
set(etcd-cpp-api_VERSION_MAJOR 0)
|
||||||
set(etcd-cpp-api_VERSION_MINOR 15)
|
set(etcd-cpp-api_VERSION_MINOR 15)
|
||||||
set(etcd-cpp-api_VERSION_PATCH 5)
|
set(etcd-cpp-api_VERSION_PATCH 0)
|
||||||
set(etcd-cpp-api_VERSION ${etcd-cpp-api_VERSION_MAJOR}.${etcd-cpp-api_VERSION_MINOR}.${etcd-cpp-api_VERSION_PATCH})
|
set(etcd-cpp-api_VERSION ${etcd-cpp-api_VERSION_MAJOR}.${etcd-cpp-api_VERSION_MINOR}.${etcd-cpp-api_VERSION_PATCH})
|
||||||
set(CMAKE_PROJECT_HOMEPAGE_URL https://github.com/etcd-cpp-apiv3/etcd-cpp-apiv3)
|
set(CMAKE_PROJECT_HOMEPAGE_URL https://github.com/etcd-cpp-apiv3/etcd-cpp-apiv3)
|
||||||
|
|
||||||
|
|
@ -26,7 +26,6 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(BUILD_WITH_NO_EXCEPTIONS "Build etcd-cpp-apiv3 with disabling exception handling, i.e., -fno-exceptions" OFF)
|
|
||||||
option(BUILD_SHARED_LIBS "Build etcd-cpp-apiv3 shared libraries" ON)
|
option(BUILD_SHARED_LIBS "Build etcd-cpp-apiv3 shared libraries" ON)
|
||||||
option(BUILD_ETCD_CORE_ONLY "Build etcd-cpp-apiv3 core library (the synchronous runtime) only" OFF)
|
option(BUILD_ETCD_CORE_ONLY "Build etcd-cpp-apiv3 core library (the synchronous runtime) only" OFF)
|
||||||
option(BUILD_ETCD_TESTS "Build etcd-cpp-apiv3 test cases" OFF)
|
option(BUILD_ETCD_TESTS "Build etcd-cpp-apiv3 test cases" OFF)
|
||||||
|
|
@ -89,21 +88,6 @@ macro(use_cxx target)
|
||||||
endif()
|
endif()
|
||||||
endmacro(use_cxx)
|
endmacro(use_cxx)
|
||||||
|
|
||||||
macro(set_exceptions target)
|
|
||||||
if(BUILD_WITH_NO_EXCEPTIONS)
|
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
||||||
target_compile_options(${target} PRIVATE "-fno-exceptions")
|
|
||||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
|
||||||
target_compile_options(${target} PRIVATE "-fno-exceptions")
|
|
||||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
|
||||||
target_compile_options(${target} PRIVATE "-fno-exceptions")
|
|
||||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
|
||||||
target_compile_options(${target} PRIVATE "/EHs-c-")
|
|
||||||
endif()
|
|
||||||
target_compile_definitions(${target} PUBLIC -D_ETCD_NO_EXCEPTIONS)
|
|
||||||
endif()
|
|
||||||
endmacro(set_exceptions)
|
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
# If we're on OS X check for Homebrew's copy of OpenSSL instead of Apple's
|
# If we're on OS X check for Homebrew's copy of OpenSSL instead of Apple's
|
||||||
if(NOT OpenSSL_DIR)
|
if(NOT OpenSSL_DIR)
|
||||||
|
|
@ -136,34 +120,10 @@ if(Protobuf_PROTOC_EXECUTABLE)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# When cross compiling we look for the native protoc compiler
|
|
||||||
# overwrite protobuf::protoc with the proper protoc
|
|
||||||
if(CMAKE_CROSSCOMPILING)
|
|
||||||
find_program(Protobuf_PROTOC_EXECUTABLE REQUIRED NAMES protoc)
|
|
||||||
if(NOT TARGET protobuf::protoc)
|
|
||||||
add_executable(protobuf::protoc IMPORTED)
|
|
||||||
endif()
|
|
||||||
set_target_properties(protobuf::protoc PROPERTIES
|
|
||||||
IMPORTED_LOCATION "${Protobuf_PROTOC_EXECUTABLE}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package(gRPC QUIET)
|
find_package(gRPC QUIET)
|
||||||
if(gRPC_FOUND AND TARGET gRPC::grpc)
|
if(gRPC_FOUND AND TARGET gRPC::grpc AND TARGET gRPC::grpc_cpp_plugin)
|
||||||
# When cross compiling we look for the native grpc_cpp_plugin
|
|
||||||
if(CMAKE_CROSSCOMPILING)
|
|
||||||
find_program(GRPC_CPP_PLUGIN REQUIRED NAMES grpc_cpp_plugin)
|
|
||||||
if(NOT TARGET gRPC::grpc_cpp_plugin)
|
|
||||||
add_executable(gRPC::grpc_cpp_plugin IMPORTED)
|
|
||||||
endif()
|
|
||||||
set_target_properties(gRPC::grpc_cpp_plugin PROPERTIES
|
|
||||||
IMPORTED_LOCATION "${GRPC_CPP_PLUGIN}")
|
|
||||||
elseif(TARGET gRPC::grpc_cpp_plugin)
|
|
||||||
get_target_property(GRPC_CPP_PLUGIN gRPC::grpc_cpp_plugin LOCATION)
|
|
||||||
else()
|
|
||||||
message(FATAL_ERROR "Found gRPC but no gRPC CPP plugin defined")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(GRPC_LIBRARIES gRPC::gpr gRPC::grpc gRPC::grpc++)
|
set(GRPC_LIBRARIES gRPC::gpr gRPC::grpc gRPC::grpc++)
|
||||||
|
get_target_property(GRPC_CPP_PLUGIN gRPC::grpc_cpp_plugin LOCATION)
|
||||||
get_target_property(GRPC_INCLUDE_DIR gRPC::grpc INTERFACE_INCLUDE_DIRECTORIES)
|
get_target_property(GRPC_INCLUDE_DIR gRPC::grpc INTERFACE_INCLUDE_DIRECTORIES)
|
||||||
else()
|
else()
|
||||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindGRPC.cmake)
|
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindGRPC.cmake)
|
||||||
|
|
@ -182,9 +142,6 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GenerateProtobufGRPC.cmake)
|
||||||
if(gRPC_VERSION VERSION_LESS "1.21" OR gRPC_VERSION VERSION_GREATER "1.31")
|
if(gRPC_VERSION VERSION_LESS "1.21" OR gRPC_VERSION VERSION_GREATER "1.31")
|
||||||
add_definitions(-DWITH_GRPC_CHANNEL_CLASS)
|
add_definitions(-DWITH_GRPC_CHANNEL_CLASS)
|
||||||
endif()
|
endif()
|
||||||
if(gRPC_VERSION VERSION_LESS "1.17")
|
|
||||||
add_definitions(-DWITH_GRPC_CREATE_CHANNEL_INTERNAL_UNIQUE_POINTER)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# will set `PROTOBUF_GENERATES`, indicates all generated .cc files, and a target `protobuf_generates`.
|
# will set `PROTOBUF_GENERATES`, indicates all generated .cc files, and a target `protobuf_generates`.
|
||||||
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GenerateProtobuf.cmake)
|
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GenerateProtobuf.cmake)
|
||||||
|
|
@ -224,13 +181,9 @@ if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
check_cxx_compiler_flag(-Wno-c++17-extensions W_NO_CPP17_EXTENSIONS)
|
check_cxx_compiler_flag(-Wno-c++17-extensions W_NO_CPP17_EXTENSIONS)
|
||||||
check_cxx_compiler_flag(-Wno-extra-semi W_NO_EXTRA_SEMI)
|
|
||||||
if(W_NO_CPP17_EXTENSIONS)
|
if(W_NO_CPP17_EXTENSIONS)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++17-extensions")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++17-extensions")
|
||||||
endif()
|
endif()
|
||||||
if(W_NO_EXTRA_SEMI)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-extra-semi")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||||
|
|
||||||
|
|
@ -252,7 +205,6 @@ if(NOT BUILD_ETCD_CORE_ONLY)
|
||||||
endif()
|
endif()
|
||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/etcd/v3/action_constants.hpp
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/etcd/v3/action_constants.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/etcd/v3/Transaction.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/etcd/v3/Transaction.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/etcd/v3/Member.hpp
|
|
||||||
DESTINATION include/etcd/v3)
|
DESTINATION include/etcd/v3)
|
||||||
|
|
||||||
configure_file(etcd-cpp-api-config.in.cmake
|
configure_file(etcd-cpp-api-config.in.cmake
|
||||||
|
|
@ -338,7 +290,6 @@ set(CPACK_DEBIAN_PACKAGE_INSTALL "/usr/lib/lib*.so*"
|
||||||
"/usr/include/etcd/*.hpp"
|
"/usr/include/etcd/*.hpp"
|
||||||
"/usr/include/etcd/v3/action_constants.hpp"
|
"/usr/include/etcd/v3/action_constants.hpp"
|
||||||
"/usr/include/etcd/v3/Transaction.hpp"
|
"/usr/include/etcd/v3/Transaction.hpp"
|
||||||
"/usr/include/etcd/v3/Member.hpp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(CPACK_DEBIAN_PACKAGE_BUILD_NUMBER_PREFIX "")
|
set(CPACK_DEBIAN_PACKAGE_BUILD_NUMBER_PREFIX "")
|
||||||
|
|
|
||||||
84
README.md
84
README.md
|
|
@ -83,36 +83,6 @@ dependencies have been successfully installed:
|
||||||
cmake ..
|
cmake ..
|
||||||
make -j$(nproc) && make install
|
make -j$(nproc) && make install
|
||||||
|
|
||||||
## Using this package in your CMake project
|
|
||||||
|
|
||||||
To use this package in your CMake project, you can either
|
|
||||||
|
|
||||||
- install, then find the library using `find_package()`:
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
find_package(etcd-cpp-apiv3 REQUIRED)
|
|
||||||
target_link_libraries(your_target PRIVATE etcd-cpp-api)
|
|
||||||
```
|
|
||||||
|
|
||||||
- or, add this repository as a subdirectory in your project, and link the library directly:
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
add_subdirectory(thirdparty/etcd-cpp-apiv3)
|
|
||||||
target_link_libraries(your_target PRIVATE etcd-cpp-api)
|
|
||||||
```
|
|
||||||
|
|
||||||
- or, use [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html):
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
include(FetchContent)
|
|
||||||
FetchContent_Declare(
|
|
||||||
etcd-cpp-apiv3
|
|
||||||
https://github.com/etcd-cpp-apiv3/etcd-cpp-apiv3.git
|
|
||||||
)
|
|
||||||
FetchContent_MakeAvailable(etcd-cpp-apiv3)
|
|
||||||
target_link_libraries(your_target PRIVATE etcd-cpp-api)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Compatible etcd version
|
## Compatible etcd version
|
||||||
|
|
||||||
The _etcd-cpp-apiv3_ should work well with etcd > 3.0. Feel free to issue an issue to us on
|
The _etcd-cpp-apiv3_ should work well with etcd > 3.0. Feel free to issue an issue to us on
|
||||||
|
|
@ -222,14 +192,6 @@ Connecting to multiple endpoints is supported:
|
||||||
etcd::Client etcd("http://a.com:2379;http://b.com:2379;http://c.com:2379");
|
etcd::Client etcd("http://a.com:2379;http://b.com:2379;http://c.com:2379");
|
||||||
```
|
```
|
||||||
|
|
||||||
### IPv6
|
|
||||||
|
|
||||||
Connecting to IPv6 endpoints is supported:
|
|
||||||
|
|
||||||
```c++
|
|
||||||
etcd::Client etcd("http://::1:2379");
|
|
||||||
```
|
|
||||||
|
|
||||||
Behind the screen, gRPC's load balancer is used and the round-robin strategy will
|
Behind the screen, gRPC's load balancer is used and the round-robin strategy will
|
||||||
be used by default.
|
be used by default.
|
||||||
|
|
||||||
|
|
@ -533,11 +495,10 @@ some specific conditions.
|
||||||
Values can be deleted with the `rm` method passing the key to be deleted as a parameter. The key
|
Values can be deleted with the `rm` method passing the key to be deleted as a parameter. The key
|
||||||
should point to an existing value. There are conditional variations for deletion too.
|
should point to an existing value. There are conditional variations for deletion too.
|
||||||
|
|
||||||
* `rm(std::string const& key)` unconditionally deletes the given key
|
* `rm_if(key, value, old_value)` deletes an already existing value but only if the previous
|
||||||
* `rm_if(key, old_value)` deletes an already existing value but only if the previous
|
|
||||||
value equals with old_value. If the values does not match returns with "Compare failed" error
|
value equals with old_value. If the values does not match returns with "Compare failed" error
|
||||||
(code `ERROR_COMPARE_FAILED`)
|
(code `ERROR_COMPARE_FAILED`)
|
||||||
* `rm_if(key, old_index)` deletes an already existing value but only if the index of
|
* `rm_if(key, value, old_index)` deletes an already existing value but only if the index of
|
||||||
the previous value equals with old_index. If the indices does not match returns with "Compare
|
the previous value equals with old_index. If the indices does not match returns with "Compare
|
||||||
failed" error (code `ERROR_COMPARE_FAILED`)
|
failed" error (code `ERROR_COMPARE_FAILED`)
|
||||||
|
|
||||||
|
|
@ -871,8 +832,6 @@ Without handler, the internal state can be checked via `KeepAlive::Check()` and
|
||||||
the async exception when there are errors during keeping the lease alive.
|
the async exception when there are errors during keeping the lease alive.
|
||||||
|
|
||||||
Note that even with `handler`, the `KeepAlive::Check()` still rethrow if there's an async exception.
|
Note that even with `handler`, the `KeepAlive::Check()` still rethrow if there's an async exception.
|
||||||
When the library is built with `-fno-exceptions`, the `handler` argument and the `Check()` method
|
|
||||||
will abort the program when there are errors during keeping the lease alive.
|
|
||||||
|
|
||||||
### Etcd transactions
|
### Etcd transactions
|
||||||
|
|
||||||
|
|
@ -893,32 +852,11 @@ Transactions in etcd supports set a set of comparison targets to specify the con
|
||||||
etcdv3::Transaction txn;
|
etcdv3::Transaction txn;
|
||||||
|
|
||||||
// setup the conditions
|
// setup the conditions
|
||||||
txn.add_compare_value("/test/x1", "1");
|
txn.reset_key("/test/x1");
|
||||||
txn.add_compare_value("/test/x2", "2");
|
txn.init_compare("1", etcdv3::CompareResult::EQUAL, etcdv3::CompareTarget::VALUE);
|
||||||
|
|
||||||
// or, compare the last modified revision
|
txn.reset_key("/test/x2");
|
||||||
txn.add_compare_mod("/test/x3", 0); // not exists
|
txn.init_compare("2", etcdv3::CompareResult::EQUAL, etcdv3::CompareTarget::VALUE);
|
||||||
txn.add_compare_mod("/test/x4", etcdv3::CompareResult::GREATER, 1234); // the modified revision is greater than 1234
|
|
||||||
```
|
|
||||||
|
|
||||||
High-level APIs (e.g., `compare_and_create`, `compare_and_swap`) are also provided, e.g.,
|
|
||||||
`fetch-and-add` operation can be implemented as
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
auto fetch_and_add = [](etcd::Client& client,
|
|
||||||
std::string const& key) -> void {
|
|
||||||
auto value = stoi(client.get(key).get().value().as_string());
|
|
||||||
while (true) {
|
|
||||||
auto txn = etcdv3::Transaction();
|
|
||||||
txn.setup_compare_and_swap(key, std::to_string(value),
|
|
||||||
std::to_string(value + 1));
|
|
||||||
etcd::Response resp = client.txn(txn).get();
|
|
||||||
if (resp.is_ok()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
value = stoi(resp.value().as_string());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
```
|
```
|
||||||
|
|
||||||
See full example of the usages of transaction APIs, please refer to [./tst/TransactionTest.cpp](./tst/TransactionTest.cpp),
|
See full example of the usages of transaction APIs, please refer to [./tst/TransactionTest.cpp](./tst/TransactionTest.cpp),
|
||||||
|
|
@ -970,15 +908,7 @@ The observer stream will be canceled when been destructed.
|
||||||
|
|
||||||
for more details, please refer to [etcd/Client.hpp](./etcd/Client.hpp) and [tst/ElectionTest.cpp](./tst/ElectionTest.cpp).
|
for more details, please refer to [etcd/Client.hpp](./etcd/Client.hpp) and [tst/ElectionTest.cpp](./tst/ElectionTest.cpp).
|
||||||
|
|
||||||
## `-fno-exceptions`
|
### TODO
|
||||||
|
|
||||||
The _etcd-cpp-apiv3_ library supports to be built with `-fno-exceptions` flag, controlled by the
|
|
||||||
cmake option `BUILD_WITH_NO_EXCEPTIONS=ON/OFF` (defaults to `OFF`).
|
|
||||||
|
|
||||||
When building with `-fno-exceptions`, the library will abort the program under certain circumstances,
|
|
||||||
e.g., when calling `.Check()` method of `KeepAlive` and there are errors during keeping the lease alive,
|
|
||||||
|
|
||||||
## TODO
|
|
||||||
|
|
||||||
1. Cancellation of asynchronous calls(except for watch)
|
1. Cancellation of asynchronous calls(except for watch)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,5 @@ set(ETCD_CPP_INCLUDE_DIRS "${ETCD_CPP_INCLUDE_DIR}")
|
||||||
include(FindPackageMessage)
|
include(FindPackageMessage)
|
||||||
find_package_message(etcd
|
find_package_message(etcd
|
||||||
"Found etcd: ${CMAKE_CURRENT_LIST_FILE} (found version \"@etcd-cpp-api_VERSION@\")"
|
"Found etcd: ${CMAKE_CURRENT_LIST_FILE} (found version \"@etcd-cpp-api_VERSION@\")"
|
||||||
"etcd-cpp-apiv3 version: @etcd-cpp-api_VERSION@\n"
|
"etcd-cpp-apiv3 version: @etcd-cpp-api_VERSION@\netcd-cpp-apiv3 libraries: ${ETCD_CPP_LIBRARIES}, \netcd-cpp-apiv3 core libraries: ${ETCD_CPP_CORE_LIBRARIES}\ninclude directories: ${ETCD_CPP_INCLUDE_DIRS}"
|
||||||
"etcd-cpp-apiv3 libraries: ${ETCD_CPP_LIBRARIES}\n"
|
|
||||||
"etcd-cpp-apiv3 core libraries: ${ETCD_CPP_CORE_LIBRARIES}\n"
|
|
||||||
"include directories: ${ETCD_CPP_INCLUDE_DIRS}"
|
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,15 @@ class Client {
|
||||||
*/
|
*/
|
||||||
pplx::task<Response> get(std::string const& key, int64_t revision);
|
pplx::task<Response> get(std::string const& key, int64_t revision);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of a key. The key will be modified if already exists or
|
||||||
|
* created if it does not exists.
|
||||||
|
* @param key is the key to be created or modified
|
||||||
|
* @param value is the new value to be set
|
||||||
|
*/
|
||||||
|
pplx::task<Response> set(std::string const& key, std::string const& value,
|
||||||
|
int ttl = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value of a key. The key will be modified if already exists or
|
* Sets the value of a key. The key will be modified if already exists or
|
||||||
* created if it does not exists.
|
* created if it does not exists.
|
||||||
|
|
@ -279,7 +288,15 @@ class Client {
|
||||||
* @param leaseId is the lease attached to the key
|
* @param leaseId is the lease attached to the key
|
||||||
*/
|
*/
|
||||||
pplx::task<Response> set(std::string const& key, std::string const& value,
|
pplx::task<Response> set(std::string const& key, std::string const& value,
|
||||||
const int64_t leaseId = 0);
|
int64_t leaseId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new key and sets it's value. Fails if the key already exists.
|
||||||
|
* @param key is the key to be created
|
||||||
|
* @param value is the value to be set
|
||||||
|
*/
|
||||||
|
pplx::task<Response> add(std::string const& key, std::string const& value,
|
||||||
|
int ttl = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new key and sets it's value. Fails if the key already exists.
|
* Creates a new key and sets it's value. Fails if the key already exists.
|
||||||
|
|
@ -288,7 +305,7 @@ class Client {
|
||||||
* @param leaseId is the lease attached to the key
|
* @param leaseId is the lease attached to the key
|
||||||
*/
|
*/
|
||||||
pplx::task<Response> add(std::string const& key, std::string const& value,
|
pplx::task<Response> add(std::string const& key, std::string const& value,
|
||||||
const int64_t leaseId = 0);
|
int64_t leaseId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Put a new key-value pair.
|
* Put a new key-value pair.
|
||||||
|
|
@ -298,13 +315,12 @@ class Client {
|
||||||
pplx::task<Response> put(std::string const& key, std::string const& value);
|
pplx::task<Response> put(std::string const& key, std::string const& value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Put a new key-value pair.
|
* Modifies an existing key. Fails if the key does not exists.
|
||||||
* @param key is the key to be put
|
* @param key is the key to be modified
|
||||||
* @param value is the value to be put
|
* @param value is the new value to be set
|
||||||
* @param leaseId is the lease id to be associated with the key
|
|
||||||
*/
|
*/
|
||||||
pplx::task<Response> put(std::string const& key, std::string const& value,
|
pplx::task<Response> modify(std::string const& key, std::string const& value,
|
||||||
const int64_t leaseId);
|
int ttl = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modifies an existing key. Fails if the key does not exists.
|
* Modifies an existing key. Fails if the key does not exists.
|
||||||
|
|
@ -313,7 +329,18 @@ class Client {
|
||||||
* @param leaseId is the lease attached to the key
|
* @param leaseId is the lease attached to the key
|
||||||
*/
|
*/
|
||||||
pplx::task<Response> modify(std::string const& key, std::string const& value,
|
pplx::task<Response> modify(std::string const& key, std::string const& value,
|
||||||
const int64_t leaseId = 0);
|
int64_t leaseId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifies an existing key only if it has a specific value. Fails if the key
|
||||||
|
* does not exists or the original value differs from the expected one.
|
||||||
|
* @param key is the key to be modified
|
||||||
|
* @param value is the new value to be set
|
||||||
|
* @param old_value is the value to be replaced
|
||||||
|
*/
|
||||||
|
pplx::task<Response> modify_if(std::string const& key,
|
||||||
|
std::string const& value,
|
||||||
|
std::string const& old_value, int ttl = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modifies an existing key only if it has a specific value. Fails if the key
|
* Modifies an existing key only if it has a specific value. Fails if the key
|
||||||
|
|
@ -325,8 +352,19 @@ class Client {
|
||||||
*/
|
*/
|
||||||
pplx::task<Response> modify_if(std::string const& key,
|
pplx::task<Response> modify_if(std::string const& key,
|
||||||
std::string const& value,
|
std::string const& value,
|
||||||
std::string const& old_value,
|
std::string const& old_value, int64_t leaseId);
|
||||||
const int64_t leaseId = 0);
|
|
||||||
|
/**
|
||||||
|
* Modifies an existing key only if it has a specific modification index
|
||||||
|
* value. Fails if the key does not exists or the modification index of the
|
||||||
|
* previous value differs from the expected one.
|
||||||
|
* @param key is the key to be modified
|
||||||
|
* @param value is the new value to be set
|
||||||
|
* @param old_index is the expected index of the original value
|
||||||
|
*/
|
||||||
|
pplx::task<Response> modify_if(std::string const& key,
|
||||||
|
std::string const& value, int64_t old_index,
|
||||||
|
int ttl = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modifies an existing key only if it has a specific modification index
|
* Modifies an existing key only if it has a specific modification index
|
||||||
|
|
@ -339,13 +377,11 @@ class Client {
|
||||||
*/
|
*/
|
||||||
pplx::task<Response> modify_if(std::string const& key,
|
pplx::task<Response> modify_if(std::string const& key,
|
||||||
std::string const& value, int64_t old_index,
|
std::string const& value, int64_t old_index,
|
||||||
const int64_t leaseId = 0);
|
int64_t leaseId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a single key. The key has to point to a plain, non directory entry.
|
* Removes a single key. The key has to point to a plain, non directory entry.
|
||||||
* @param key is the key to be deleted
|
* @param key is the key to be deleted
|
||||||
*
|
|
||||||
* @return Returns etcdv3::ERROR_KEY_NOT_FOUND if the key does not exist.
|
|
||||||
*/
|
*/
|
||||||
pplx::task<Response> rm(std::string const& key);
|
pplx::task<Response> rm(std::string const& key);
|
||||||
|
|
||||||
|
|
@ -353,8 +389,6 @@ class Client {
|
||||||
* Removes a single key but only if it has a specific value. Fails if the key
|
* Removes a single key but only if it has a specific value. Fails if the key
|
||||||
* does not exists or the its value differs from the expected one.
|
* does not exists or the its value differs from the expected one.
|
||||||
* @param key is the key to be deleted
|
* @param key is the key to be deleted
|
||||||
*
|
|
||||||
* @return Returns etcdv3::ERROR_KEY_NOT_FOUND if the key does not exist.
|
|
||||||
*/
|
*/
|
||||||
pplx::task<Response> rm_if(std::string const& key,
|
pplx::task<Response> rm_if(std::string const& key,
|
||||||
std::string const& old_value);
|
std::string const& old_value);
|
||||||
|
|
@ -365,8 +399,6 @@ class Client {
|
||||||
* from the expected one.
|
* from the expected one.
|
||||||
* @param key is the key to be deleted
|
* @param key is the key to be deleted
|
||||||
* @param old_index is the expected index of the existing value
|
* @param old_index is the expected index of the existing value
|
||||||
*
|
|
||||||
* @return Returns etcdv3::ERROR_KEY_NOT_FOUND if the key does not exist.
|
|
||||||
*/
|
*/
|
||||||
pplx::task<Response> rm_if(std::string const& key, int64_t old_index);
|
pplx::task<Response> rm_if(std::string const& key, int64_t old_index);
|
||||||
|
|
||||||
|
|
@ -376,8 +408,6 @@ class Client {
|
||||||
* @param key is the directory to be created to be listed
|
* @param key is the directory to be created to be listed
|
||||||
* @param recursive if true then delete a whole subtree, otherwise deletes
|
* @param recursive if true then delete a whole subtree, otherwise deletes
|
||||||
* only an empty directory.
|
* only an empty directory.
|
||||||
*
|
|
||||||
* @return Returns etcdv3::ERROR_KEY_NOT_FOUND if the no key been deleted.
|
|
||||||
*/
|
*/
|
||||||
pplx::task<Response> rmdir(std::string const& key, bool recursive = false);
|
pplx::task<Response> rmdir(std::string const& key, bool recursive = false);
|
||||||
|
|
||||||
|
|
@ -389,8 +419,6 @@ class Client {
|
||||||
*
|
*
|
||||||
* @param key is the directory to be created to be listed
|
* @param key is the directory to be created to be listed
|
||||||
* @param range_end is the end of key range to be removed.
|
* @param range_end is the end of key range to be removed.
|
||||||
*
|
|
||||||
* @return Returns etcdv3::ERROR_KEY_NOT_FOUND if the no key been deleted.
|
|
||||||
*/
|
*/
|
||||||
pplx::task<Response> rmdir(std::string const& key, const char* range_end);
|
pplx::task<Response> rmdir(std::string const& key, const char* range_end);
|
||||||
|
|
||||||
|
|
@ -399,8 +427,6 @@ class Client {
|
||||||
*
|
*
|
||||||
* @param key is the directory to be created to be listed
|
* @param key is the directory to be created to be listed
|
||||||
* @param range_end is the end of key range to be removed.
|
* @param range_end is the end of key range to be removed.
|
||||||
*
|
|
||||||
* @return Returns etcdv3::ERROR_KEY_NOT_FOUND if the no key been deleted.
|
|
||||||
*/
|
*/
|
||||||
pplx::task<Response> rmdir(std::string const& key,
|
pplx::task<Response> rmdir(std::string const& key,
|
||||||
std::string const& range_end);
|
std::string const& range_end);
|
||||||
|
|
@ -630,25 +656,6 @@ class Client {
|
||||||
*/
|
*/
|
||||||
pplx::task<Response> leases();
|
pplx::task<Response> leases();
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an etcd member to the etcd cluster, equivalent to `etcdctl member add`.
|
|
||||||
* @param peer_urls is comma separated list of URLs for the new member.
|
|
||||||
* @param is_learner is true if the added member is a learner.
|
|
||||||
*/
|
|
||||||
pplx::task<Response> add_member(std::string const& peer_urls,
|
|
||||||
bool is_learner);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List all members, equivalent to `etcdctl member list`.
|
|
||||||
*/
|
|
||||||
pplx::task<Response> list_member();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an etcd member to the etcd cluster, equivalent to `etcdctl member add`.
|
|
||||||
* @param member_id is the ID of the member to be removed.
|
|
||||||
*/
|
|
||||||
pplx::task<Response> remove_member(const uint64_t member_id);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gains a lock at a key, using a default created lease, using the default
|
* Gains a lock at a key, using a default created lease, using the default
|
||||||
* lease (10 seconds), with keeping alive has already been taken care of by
|
* lease (10 seconds), with keeping alive has already been taken care of by
|
||||||
|
|
|
||||||
|
|
@ -85,10 +85,10 @@ class KeepAlive {
|
||||||
~KeepAlive();
|
~KeepAlive();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// automatically refresh loop, returns the error message if failed
|
// automatically refresh loop
|
||||||
std::string refresh();
|
void refresh();
|
||||||
// refresh once immediately, returns the error message if failed
|
// refresh once immediately
|
||||||
std::string refresh_once();
|
void refresh_once();
|
||||||
|
|
||||||
struct EtcdServerStubs;
|
struct EtcdServerStubs;
|
||||||
struct EtcdServerStubsDeleter {
|
struct EtcdServerStubsDeleter {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "etcd/Value.hpp"
|
#include "etcd/Value.hpp"
|
||||||
#include "etcd/v3/Member.hpp"
|
|
||||||
|
|
||||||
namespace etcdv3 {
|
namespace etcdv3 {
|
||||||
class AsyncWatchAction;
|
class AsyncWatchAction;
|
||||||
|
|
@ -35,7 +34,7 @@ class KeepAlive;
|
||||||
class Watcher;
|
class Watcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Response object received for the requests of etcd::Client
|
* The Reponse object received for the requests of etcd::Client
|
||||||
*/
|
*/
|
||||||
class Response {
|
class Response {
|
||||||
public:
|
public:
|
||||||
|
|
@ -209,11 +208,6 @@ class Response {
|
||||||
*/
|
*/
|
||||||
std::vector<int64_t> const& leases() const;
|
std::vector<int64_t> const& leases() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the member list.
|
|
||||||
*/
|
|
||||||
std::vector<etcdv3::Member> const& members() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Response(const etcdv3::V3Response& response,
|
Response(const etcdv3::V3Response& response,
|
||||||
std::chrono::microseconds const& duration);
|
std::chrono::microseconds const& duration);
|
||||||
|
|
@ -245,9 +239,6 @@ class Response {
|
||||||
// for lease list
|
// for lease list
|
||||||
std::vector<int64_t> _leases;
|
std::vector<int64_t> _leases;
|
||||||
|
|
||||||
// for member list
|
|
||||||
std::vector<etcdv3::Member> _members;
|
|
||||||
|
|
||||||
friend class Client;
|
friend class Client;
|
||||||
friend class SyncClient;
|
friend class SyncClient;
|
||||||
friend class KeepAlive;
|
friend class KeepAlive;
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,6 @@ class AsyncLeaseKeepAliveAction;
|
||||||
class AsyncLeaseTimeToLiveAction;
|
class AsyncLeaseTimeToLiveAction;
|
||||||
class AsyncLeaseLeasesAction;
|
class AsyncLeaseLeasesAction;
|
||||||
class AsyncLockAction;
|
class AsyncLockAction;
|
||||||
class AsyncAddMemberAction;
|
|
||||||
class AsyncListMemberAction;
|
|
||||||
class AsyncRemoveMemberAction;
|
|
||||||
class AsyncUnlockAction;
|
class AsyncUnlockAction;
|
||||||
class AsyncPutAction;
|
class AsyncPutAction;
|
||||||
class AsyncRangeAction;
|
class AsyncRangeAction;
|
||||||
|
|
@ -330,6 +327,14 @@ class SyncClient {
|
||||||
*/
|
*/
|
||||||
Response get(std::string const& key, int64_t revision);
|
Response get(std::string const& key, int64_t revision);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of a key. The key will be modified if already exists or
|
||||||
|
* created if it does not exists.
|
||||||
|
* @param key is the key to be created or modified
|
||||||
|
* @param value is the new value to be set
|
||||||
|
*/
|
||||||
|
Response set(std::string const& key, std::string const& value, int ttl = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value of a key. The key will be modified if already exists or
|
* Sets the value of a key. The key will be modified if already exists or
|
||||||
* created if it does not exists.
|
* created if it does not exists.
|
||||||
|
|
@ -338,7 +343,14 @@ class SyncClient {
|
||||||
* @param leaseId is the lease attached to the key
|
* @param leaseId is the lease attached to the key
|
||||||
*/
|
*/
|
||||||
Response set(std::string const& key, std::string const& value,
|
Response set(std::string const& key, std::string const& value,
|
||||||
const int64_t leaseId = 0);
|
int64_t leaseId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new key and sets it's value. Fails if the key already exists.
|
||||||
|
* @param key is the key to be created
|
||||||
|
* @param value is the value to be set
|
||||||
|
*/
|
||||||
|
Response add(std::string const& key, std::string const& value, int ttl = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new key and sets it's value. Fails if the key already exists.
|
* Creates a new key and sets it's value. Fails if the key already exists.
|
||||||
|
|
@ -347,7 +359,7 @@ class SyncClient {
|
||||||
* @param leaseId is the lease attached to the key
|
* @param leaseId is the lease attached to the key
|
||||||
*/
|
*/
|
||||||
Response add(std::string const& key, std::string const& value,
|
Response add(std::string const& key, std::string const& value,
|
||||||
const int64_t leaseId = 0);
|
int64_t leaseId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Put a new key-value pair.
|
* Put a new key-value pair.
|
||||||
|
|
@ -357,13 +369,12 @@ class SyncClient {
|
||||||
Response put(std::string const& key, std::string const& value);
|
Response put(std::string const& key, std::string const& value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Put a new key-value pair.
|
* Modifies an existing key. Fails if the key does not exists.
|
||||||
* @param key is the key to be put
|
* @param key is the key to be modified
|
||||||
* @param value is the value to be put
|
* @param value is the new value to be set
|
||||||
* @param leaseId is the lease id to be associated with the key
|
|
||||||
*/
|
*/
|
||||||
Response put(std::string const& key, std::string const& value,
|
Response modify(std::string const& key, std::string const& value,
|
||||||
const int64_t leaseId);
|
int ttl = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modifies an existing key. Fails if the key does not exists.
|
* Modifies an existing key. Fails if the key does not exists.
|
||||||
|
|
@ -372,7 +383,17 @@ class SyncClient {
|
||||||
* @param leaseId is the lease attached to the key
|
* @param leaseId is the lease attached to the key
|
||||||
*/
|
*/
|
||||||
Response modify(std::string const& key, std::string const& value,
|
Response modify(std::string const& key, std::string const& value,
|
||||||
const int64_t leaseId = 0);
|
int64_t leaseId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifies an existing key only if it has a specific value. Fails if the key
|
||||||
|
* does not exists or the original value differs from the expected one.
|
||||||
|
* @param key is the key to be modified
|
||||||
|
* @param value is the new value to be set
|
||||||
|
* @param old_value is the value to be replaced
|
||||||
|
*/
|
||||||
|
Response modify_if(std::string const& key, std::string const& value,
|
||||||
|
std::string const& old_value, int ttl = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modifies an existing key only if it has a specific value. Fails if the key
|
* Modifies an existing key only if it has a specific value. Fails if the key
|
||||||
|
|
@ -383,7 +404,18 @@ class SyncClient {
|
||||||
* @param leaseId is the lease attached to the key
|
* @param leaseId is the lease attached to the key
|
||||||
*/
|
*/
|
||||||
Response modify_if(std::string const& key, std::string const& value,
|
Response modify_if(std::string const& key, std::string const& value,
|
||||||
std::string const& old_value, const int64_t leaseId = 0);
|
std::string const& old_value, int64_t leaseId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifies an existing key only if it has a specific modification index
|
||||||
|
* value. Fails if the key does not exists or the modification index of the
|
||||||
|
* previous value differs from the expected one.
|
||||||
|
* @param key is the key to be modified
|
||||||
|
* @param value is the new value to be set
|
||||||
|
* @param old_index is the expected index of the original value
|
||||||
|
*/
|
||||||
|
Response modify_if(std::string const& key, std::string const& value,
|
||||||
|
int64_t old_index, int ttl = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modifies an existing key only if it has a specific modification index
|
* Modifies an existing key only if it has a specific modification index
|
||||||
|
|
@ -395,13 +427,11 @@ class SyncClient {
|
||||||
* @param leaseId is the lease attached to the key
|
* @param leaseId is the lease attached to the key
|
||||||
*/
|
*/
|
||||||
Response modify_if(std::string const& key, std::string const& value,
|
Response modify_if(std::string const& key, std::string const& value,
|
||||||
int64_t old_index, const int64_t leaseId = 0);
|
int64_t old_index, int64_t leaseId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a single key. The key has to point to a plain, non directory entry.
|
* Removes a single key. The key has to point to a plain, non directory entry.
|
||||||
* @param key is the key to be deleted
|
* @param key is the key to be deleted
|
||||||
*
|
|
||||||
* @return Returns etcdv3::ERROR_KEY_NOT_FOUND if the key does not exist.
|
|
||||||
*/
|
*/
|
||||||
Response rm(std::string const& key);
|
Response rm(std::string const& key);
|
||||||
|
|
||||||
|
|
@ -409,8 +439,6 @@ class SyncClient {
|
||||||
* Removes a single key but only if it has a specific value. Fails if the key
|
* Removes a single key but only if it has a specific value. Fails if the key
|
||||||
* does not exists or the its value differs from the expected one.
|
* does not exists or the its value differs from the expected one.
|
||||||
* @param key is the key to be deleted
|
* @param key is the key to be deleted
|
||||||
*
|
|
||||||
* @return Returns etcdv3::ERROR_KEY_NOT_FOUND if the key does not exist.
|
|
||||||
*/
|
*/
|
||||||
Response rm_if(std::string const& key, std::string const& old_value);
|
Response rm_if(std::string const& key, std::string const& old_value);
|
||||||
|
|
||||||
|
|
@ -420,8 +448,6 @@ class SyncClient {
|
||||||
* from the expected one.
|
* from the expected one.
|
||||||
* @param key is the key to be deleted
|
* @param key is the key to be deleted
|
||||||
* @param old_index is the expected index of the existing value
|
* @param old_index is the expected index of the existing value
|
||||||
*
|
|
||||||
* @return Returns etcdv3::ERROR_KEY_NOT_FOUND if the key does not exist.
|
|
||||||
*/
|
*/
|
||||||
Response rm_if(std::string const& key, int64_t old_index);
|
Response rm_if(std::string const& key, int64_t old_index);
|
||||||
|
|
||||||
|
|
@ -431,8 +457,6 @@ class SyncClient {
|
||||||
* @param key is the directory to be created to be listed
|
* @param key is the directory to be created to be listed
|
||||||
* @param recursive if true then delete a whole subtree, otherwise deletes
|
* @param recursive if true then delete a whole subtree, otherwise deletes
|
||||||
* only an empty directory.
|
* only an empty directory.
|
||||||
*
|
|
||||||
* @return Returns etcdv3::ERROR_KEY_NOT_FOUND if the no key been deleted.
|
|
||||||
*/
|
*/
|
||||||
Response rmdir(std::string const& key, bool recursive = false);
|
Response rmdir(std::string const& key, bool recursive = false);
|
||||||
|
|
||||||
|
|
@ -444,8 +468,6 @@ class SyncClient {
|
||||||
*
|
*
|
||||||
* @param key is the directory to be created to be listed
|
* @param key is the directory to be created to be listed
|
||||||
* @param range_end is the end of key range to be removed.
|
* @param range_end is the end of key range to be removed.
|
||||||
*
|
|
||||||
* @return Returns etcdv3::ERROR_KEY_NOT_FOUND if the no key been deleted.
|
|
||||||
*/
|
*/
|
||||||
Response rmdir(std::string const& key, const char* range_end);
|
Response rmdir(std::string const& key, const char* range_end);
|
||||||
|
|
||||||
|
|
@ -454,8 +476,6 @@ class SyncClient {
|
||||||
*
|
*
|
||||||
* @param key is the directory to be created to be listed
|
* @param key is the directory to be created to be listed
|
||||||
* @param range_end is the end of key range to be removed.
|
* @param range_end is the end of key range to be removed.
|
||||||
*
|
|
||||||
* @return Returns etcdv3::ERROR_KEY_NOT_FOUND if the no key been deleted.
|
|
||||||
*/
|
*/
|
||||||
Response rmdir(std::string const& key, std::string const& range_end);
|
Response rmdir(std::string const& key, std::string const& range_end);
|
||||||
|
|
||||||
|
|
@ -682,24 +702,6 @@ class SyncClient {
|
||||||
*/
|
*/
|
||||||
Response leases();
|
Response leases();
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an etcd member to the etcd cluster, equivalent to `etcdctl member add`.
|
|
||||||
* @param peer_urls is comma separated list of URLs for the new member.
|
|
||||||
* @param is_learner is true if the added member is a learner.
|
|
||||||
*/
|
|
||||||
Response add_member(std::string const& peer_urls, bool is_learner);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List all members, equivalent to `etcdctl member list`.
|
|
||||||
*/
|
|
||||||
Response list_member();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a member of an etcd cluster, equivalent to `etcdctl member remove`.
|
|
||||||
* @param member_id is the id of the member to be removed.
|
|
||||||
*/
|
|
||||||
Response remove_member(uint64_t member_id);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gains a lock at a key, using a default created lease, using the default
|
* Gains a lock at a key, using a default created lease, using the default
|
||||||
* lease (10 seconds), with keeping alive has already been taken care of by
|
* lease (10 seconds), with keeping alive has already been taken care of by
|
||||||
|
|
@ -817,21 +819,22 @@ class SyncClient {
|
||||||
private:
|
private:
|
||||||
// TODO: use std::unique_ptr<>
|
// TODO: use std::unique_ptr<>
|
||||||
std::shared_ptr<etcdv3::AsyncHeadAction> head_internal();
|
std::shared_ptr<etcdv3::AsyncHeadAction> head_internal();
|
||||||
std::shared_ptr<etcdv3::AsyncRangeAction> get_internal(
|
std::shared_ptr<etcdv3::AsyncRangeAction> get_internal(std::string const& key,
|
||||||
std::string const& key, const int64_t revision = 0);
|
int64_t revision = 0);
|
||||||
std::shared_ptr<etcdv3::AsyncSetAction> add_internal(
|
std::shared_ptr<etcdv3::AsyncSetAction> set_internal(std::string const& key,
|
||||||
std::string const& key, std::string const& value,
|
std::string const& value,
|
||||||
const int64_t leaseId = 0);
|
int64_t leaseId);
|
||||||
|
std::shared_ptr<etcdv3::AsyncSetAction> add_internal(std::string const& key,
|
||||||
|
std::string const& value,
|
||||||
|
int64_t leaseId);
|
||||||
std::shared_ptr<etcdv3::AsyncPutAction> put_internal(
|
std::shared_ptr<etcdv3::AsyncPutAction> put_internal(
|
||||||
std::string const& key, std::string const& value,
|
std::string const& key, std::string const& value);
|
||||||
const int64_t leaseId = 0);
|
|
||||||
std::shared_ptr<etcdv3::AsyncUpdateAction> modify_internal(
|
std::shared_ptr<etcdv3::AsyncUpdateAction> modify_internal(
|
||||||
std::string const& key, std::string const& value,
|
std::string const& key, std::string const& value, int64_t leaseId);
|
||||||
const int64_t leaseId = 0);
|
|
||||||
std::shared_ptr<etcdv3::AsyncCompareAndSwapAction> modify_if_internal(
|
std::shared_ptr<etcdv3::AsyncCompareAndSwapAction> modify_if_internal(
|
||||||
std::string const& key, std::string const& value, int64_t old_index,
|
std::string const& key, std::string const& value, int64_t old_index,
|
||||||
std::string const& old_value, etcdv3::AtomicityType const& atomicity_type,
|
std::string const& old_value, int64_t leaseId,
|
||||||
const int64_t leaseId = 0);
|
etcdv3::AtomicityType const& atomicity_type);
|
||||||
std::shared_ptr<etcdv3::AsyncDeleteAction> rm_internal(
|
std::shared_ptr<etcdv3::AsyncDeleteAction> rm_internal(
|
||||||
std::string const& key);
|
std::string const& key);
|
||||||
std::shared_ptr<etcdv3::AsyncCompareAndDeleteAction> rm_if_internal(
|
std::shared_ptr<etcdv3::AsyncCompareAndDeleteAction> rm_if_internal(
|
||||||
|
|
@ -856,11 +859,6 @@ class SyncClient {
|
||||||
std::shared_ptr<etcdv3::AsyncLeaseTimeToLiveAction> leasetimetolive_internal(
|
std::shared_ptr<etcdv3::AsyncLeaseTimeToLiveAction> leasetimetolive_internal(
|
||||||
int64_t lease_id);
|
int64_t lease_id);
|
||||||
std::shared_ptr<etcdv3::AsyncLeaseLeasesAction> leases_internal();
|
std::shared_ptr<etcdv3::AsyncLeaseLeasesAction> leases_internal();
|
||||||
std::shared_ptr<etcdv3::AsyncAddMemberAction> add_member_internal(
|
|
||||||
std::string const& peer_urls, bool is_learner);
|
|
||||||
std::shared_ptr<etcdv3::AsyncListMemberAction> list_member_internal();
|
|
||||||
std::shared_ptr<etcdv3::AsyncRemoveMemberAction> remove_member_internal(
|
|
||||||
const uint64_t member_id);
|
|
||||||
Response lock_internal(std::string const& key,
|
Response lock_internal(std::string const& key,
|
||||||
std::shared_ptr<etcd::KeepAlive> const& keepalive);
|
std::shared_ptr<etcd::KeepAlive> const& keepalive);
|
||||||
std::shared_ptr<etcdv3::AsyncLockAction> lock_with_lease_internal(
|
std::shared_ptr<etcdv3::AsyncLockAction> lock_with_lease_internal(
|
||||||
|
|
|
||||||
|
|
@ -91,9 +91,7 @@ class Value {
|
||||||
int64_t leaseId;
|
int64_t leaseId;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Values = std::vector<Value>;
|
typedef std::vector<Value> Values;
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const Value& value);
|
|
||||||
|
|
||||||
class Event {
|
class Event {
|
||||||
public:
|
public:
|
||||||
|
|
@ -124,12 +122,7 @@ class Event {
|
||||||
bool _has_kv, _has_prev_kv;
|
bool _has_kv, _has_prev_kv;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Events = std::vector<Event>;
|
typedef std::vector<Event> Events;
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const Event::EventType& value);
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const Event& event);
|
|
||||||
|
|
||||||
} // namespace etcd
|
} // namespace etcd
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -162,11 +162,8 @@ class Watcher {
|
||||||
* Note that you shouldn't use the watcher itself inside the `Wait()` callback
|
* 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
|
* as the callback will be invoked in a separate **detached** thread where the
|
||||||
* watcher may have been destroyed.
|
* watcher may have been destroyed.
|
||||||
*
|
|
||||||
* @return true if the callback has been set successfully (no existing
|
|
||||||
* callback).
|
|
||||||
*/
|
*/
|
||||||
bool Wait(std::function<void(bool)> callback);
|
void Wait(std::function<void(bool)> callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop the watching action.
|
* Stop the watching action.
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,10 @@
|
||||||
#include "proto/v3election.grpc.pb.h"
|
#include "proto/v3election.grpc.pb.h"
|
||||||
#include "proto/v3lock.grpc.pb.h"
|
#include "proto/v3lock.grpc.pb.h"
|
||||||
|
|
||||||
#include "etcd/v3/action_constants.hpp"
|
|
||||||
|
|
||||||
using grpc::ClientContext;
|
using grpc::ClientContext;
|
||||||
using grpc::CompletionQueue;
|
using grpc::CompletionQueue;
|
||||||
using grpc::Status;
|
using grpc::Status;
|
||||||
|
|
||||||
using etcdserverpb::Cluster;
|
|
||||||
using etcdserverpb::KV;
|
using etcdserverpb::KV;
|
||||||
using etcdserverpb::Lease;
|
using etcdserverpb::Lease;
|
||||||
using etcdserverpb::Watch;
|
using etcdserverpb::Watch;
|
||||||
|
|
@ -45,16 +42,9 @@ struct ActionParameters {
|
||||||
std::string value;
|
std::string value;
|
||||||
std::string old_value;
|
std::string old_value;
|
||||||
std::string auth_token;
|
std::string auth_token;
|
||||||
|
|
||||||
// for cluster management apis
|
|
||||||
std::vector<std::string> peer_urls;
|
|
||||||
bool is_learner;
|
|
||||||
uint64_t member_id;
|
|
||||||
|
|
||||||
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;
|
||||||
Cluster::Stub* cluster_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;
|
||||||
|
|
@ -91,27 +81,6 @@ class Action {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
std::string string_plus_one(std::string const& value);
|
std::string string_plus_one(std::string const& value);
|
||||||
std::string resolve_etcd_endpoints(std::string const& default_endpoints);
|
std::string resolve_etcd_endpoints(std::string const& default_endpoints);
|
||||||
|
|
||||||
template <typename Req>
|
|
||||||
void make_request_with_ranges(Req& req, std::string const& key,
|
|
||||||
std::string const& range_end,
|
|
||||||
bool const recursive) {
|
|
||||||
if (!recursive) {
|
|
||||||
req.set_key(key);
|
|
||||||
} else {
|
|
||||||
if (key.empty()) {
|
|
||||||
req.set_key(etcdv3::NUL);
|
|
||||||
req.set_range_end(etcdv3::NUL);
|
|
||||||
} else {
|
|
||||||
req.set_key(key);
|
|
||||||
req.set_range_end(detail::string_plus_one(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!range_end.empty()) {
|
|
||||||
req.set_range_end(range_end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace etcdv3
|
} // namespace etcdv3
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -37,12 +37,6 @@ using etcdserverpb::LeaseRevokeRequest;
|
||||||
using etcdserverpb::LeaseRevokeResponse;
|
using etcdserverpb::LeaseRevokeResponse;
|
||||||
using etcdserverpb::LeaseTimeToLiveRequest;
|
using etcdserverpb::LeaseTimeToLiveRequest;
|
||||||
using etcdserverpb::LeaseTimeToLiveResponse;
|
using etcdserverpb::LeaseTimeToLiveResponse;
|
||||||
using etcdserverpb::MemberAddRequest;
|
|
||||||
using etcdserverpb::MemberAddResponse;
|
|
||||||
using etcdserverpb::MemberListRequest;
|
|
||||||
using etcdserverpb::MemberListResponse;
|
|
||||||
using etcdserverpb::MemberRemoveRequest;
|
|
||||||
using etcdserverpb::MemberRemoveResponse;
|
|
||||||
using etcdserverpb::PutRequest;
|
using etcdserverpb::PutRequest;
|
||||||
using etcdserverpb::PutResponse;
|
using etcdserverpb::PutResponse;
|
||||||
using etcdserverpb::RangeRequest;
|
using etcdserverpb::RangeRequest;
|
||||||
|
|
@ -82,7 +76,8 @@ class AsyncCampaignResponse : public etcdv3::V3Response {
|
||||||
class AsyncDeleteResponse : public etcdv3::V3Response {
|
class AsyncDeleteResponse : public etcdv3::V3Response {
|
||||||
public:
|
public:
|
||||||
AsyncDeleteResponse(){};
|
AsyncDeleteResponse(){};
|
||||||
void ParseResponse(DeleteRangeResponse& resp);
|
void ParseResponse(std::string const& key, bool prefix,
|
||||||
|
DeleteRangeResponse& resp);
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsyncHeadResponse : public etcdv3::V3Response {
|
class AsyncHeadResponse : public etcdv3::V3Response {
|
||||||
|
|
@ -109,24 +104,6 @@ class AsyncLeaseKeepAliveResponse : public etcdv3::V3Response {
|
||||||
void ParseResponse(LeaseKeepAliveResponse& resp);
|
void ParseResponse(LeaseKeepAliveResponse& resp);
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsyncMemberAddResponse : public etcdv3::V3Response {
|
|
||||||
public:
|
|
||||||
AsyncMemberAddResponse(){};
|
|
||||||
void ParseResponse(MemberAddResponse& resp);
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncMemberListResponse : public etcdv3::V3Response {
|
|
||||||
public:
|
|
||||||
AsyncMemberListResponse(){};
|
|
||||||
void ParseResponse(MemberListResponse& resp);
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncMemberRemoveResponse : public etcdv3::V3Response {
|
|
||||||
public:
|
|
||||||
AsyncMemberRemoveResponse(){};
|
|
||||||
void ParseResponse(MemberRemoveResponse& resp);
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncLeaseLeasesResponse : public etcdv3::V3Response {
|
class AsyncLeaseLeasesResponse : public etcdv3::V3Response {
|
||||||
public:
|
public:
|
||||||
AsyncLeaseLeasesResponse(){};
|
AsyncLeaseLeasesResponse(){};
|
||||||
|
|
@ -185,6 +162,7 @@ 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);
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsyncUnlockResponse : public etcdv3::V3Response {
|
class AsyncUnlockResponse : public etcdv3::V3Response {
|
||||||
|
|
@ -293,44 +271,12 @@ class AsyncLeaseKeepAliveAction : public etcdv3::Action {
|
||||||
stream;
|
stream;
|
||||||
|
|
||||||
LeaseKeepAliveRequest req;
|
LeaseKeepAliveRequest req;
|
||||||
std::atomic_bool isCancelled;
|
bool isCancelled;
|
||||||
std::recursive_mutex protect_is_cancelled;
|
std::recursive_mutex protect_is_cancelled;
|
||||||
|
|
||||||
friend class etcd::KeepAlive;
|
friend class etcd::KeepAlive;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsyncAddMemberAction : public etcdv3::Action {
|
|
||||||
public:
|
|
||||||
AsyncAddMemberAction(etcdv3::ActionParameters&& params);
|
|
||||||
AsyncMemberAddResponse ParseResponse();
|
|
||||||
|
|
||||||
private:
|
|
||||||
MemberAddResponse reply;
|
|
||||||
std::unique_ptr<ClientAsyncResponseReader<MemberAddResponse>> response_reader;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncListMemberAction : public etcdv3::Action {
|
|
||||||
public:
|
|
||||||
AsyncListMemberAction(etcdv3::ActionParameters&& params);
|
|
||||||
AsyncMemberListResponse ParseResponse();
|
|
||||||
|
|
||||||
private:
|
|
||||||
MemberListResponse reply;
|
|
||||||
std::unique_ptr<ClientAsyncResponseReader<MemberListResponse>>
|
|
||||||
response_reader;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncRemoveMemberAction : public etcdv3::Action {
|
|
||||||
public:
|
|
||||||
AsyncRemoveMemberAction(etcdv3::ActionParameters&& params);
|
|
||||||
AsyncMemberRemoveResponse ParseResponse();
|
|
||||||
|
|
||||||
private:
|
|
||||||
MemberRemoveResponse reply;
|
|
||||||
std::unique_ptr<ClientAsyncResponseReader<MemberRemoveResponse>>
|
|
||||||
response_reader;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncLeaseLeasesAction : public etcdv3::Action {
|
class AsyncLeaseLeasesAction : public etcdv3::Action {
|
||||||
public:
|
public:
|
||||||
AsyncLeaseLeasesAction(etcdv3::ActionParameters&& params);
|
AsyncLeaseLeasesAction(etcdv3::ActionParameters&& params);
|
||||||
|
|
@ -386,7 +332,7 @@ class AsyncObserveAction : public etcdv3::Action {
|
||||||
LeaderResponse reply;
|
LeaderResponse reply;
|
||||||
std::unique_ptr<ClientAsyncReader<LeaderResponse>> response_reader;
|
std::unique_ptr<ClientAsyncReader<LeaderResponse>> response_reader;
|
||||||
std::atomic_bool isCancelled;
|
std::atomic_bool isCancelled;
|
||||||
std::mutex protect_is_cancelled;
|
std::mutex protect_is_cancalled;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsyncProclaimAction : public etcdv3::Action {
|
class AsyncProclaimAction : public etcdv3::Action {
|
||||||
|
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
#ifndef __V3_ETCDV3MEMBERS_HPP__
|
|
||||||
#define __V3_ETCDV3MEMBERS_HPP__
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
namespace etcdv3 {
|
|
||||||
class Member {
|
|
||||||
public:
|
|
||||||
Member();
|
|
||||||
|
|
||||||
void set_id(uint64_t const& id);
|
|
||||||
uint64_t const& get_id() const;
|
|
||||||
void set_name(std::string const& name);
|
|
||||||
std::string const& get_name() const;
|
|
||||||
void set_peerURLs(std::vector<std::string> const& peerURLs);
|
|
||||||
std::vector<std::string> const& get_peerURLs() const;
|
|
||||||
void set_clientURLs(std::vector<std::string> const& clientURLs);
|
|
||||||
std::vector<std::string> const& get_clientURLs() const;
|
|
||||||
void set_learner(bool isLearner);
|
|
||||||
bool get_learner() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint64_t id;
|
|
||||||
std::string name;
|
|
||||||
std::vector<std::string> peerURLs;
|
|
||||||
std::vector<std::string> clientURLs;
|
|
||||||
bool isLearner;
|
|
||||||
};
|
|
||||||
} // namespace etcdv3
|
|
||||||
#endif
|
|
||||||
|
|
@ -28,194 +28,38 @@ enum class CompareTarget {
|
||||||
class Transaction {
|
class Transaction {
|
||||||
public:
|
public:
|
||||||
Transaction();
|
Transaction();
|
||||||
~Transaction();
|
Transaction(std::string const&);
|
||||||
|
virtual ~Transaction();
|
||||||
|
|
||||||
union Value {
|
// Set a new key for different comparisons and /put/get/delete requests.
|
||||||
int64_t version;
|
void reset_key(std::string const& newkey);
|
||||||
int64_t create_revision;
|
|
||||||
int64_t mod_revision;
|
|
||||||
std::string value;
|
|
||||||
int64_t lease;
|
|
||||||
};
|
|
||||||
|
|
||||||
void add_compare(std::string const& key, CompareTarget const& target,
|
void init_compare(CompareResult, CompareTarget);
|
||||||
CompareResult const& result, Value const& target_value,
|
void init_compare(std::string const& old_value, CompareResult, CompareTarget);
|
||||||
std::string const& range_end = "");
|
void init_compare(int64_t old_value, CompareResult, CompareTarget);
|
||||||
|
|
||||||
void add_compare_version(std::string const& key, int64_t const& version,
|
void setup_basic_failure_operation(std::string const& key);
|
||||||
std::string const& range_end = "");
|
void setup_set_failure_operation(std::string const& key,
|
||||||
void add_compare_version(std::string const& key, CompareResult const& result,
|
std::string const& value, int64_t leaseid);
|
||||||
int64_t const& version,
|
void setup_basic_create_sequence(std::string const& key,
|
||||||
std::string const& range_end = "");
|
std::string const& value, int64_t leaseid);
|
||||||
void add_compare_create(std::string const& key,
|
void setup_compare_and_swap_sequence(std::string const& valueToSwap,
|
||||||
int64_t const& create_revision,
|
int64_t leaseid);
|
||||||
std::string const& range_end = "");
|
void setup_delete_sequence(std::string const& key,
|
||||||
void add_compare_create(std::string const& key, CompareResult const& result,
|
std::string const& range_end, bool recursive);
|
||||||
int64_t const& create_revision,
|
void setup_delete_failure_operation(std::string const& key,
|
||||||
std::string const& range_end = "");
|
std::string const& range_end,
|
||||||
void add_compare_mod(std::string const& key, int64_t const& mod_revision,
|
bool recursive);
|
||||||
std::string const& range_end = "");
|
void setup_compare_and_delete_operation(std::string const& key);
|
||||||
void add_compare_mod(std::string const& key, CompareResult const& result,
|
|
||||||
int64_t const& mod_revision,
|
|
||||||
std::string const& range_end = "");
|
|
||||||
void add_compare_value(std::string const& key, std::string const& value,
|
|
||||||
std::string const& range_end = "");
|
|
||||||
void add_compare_value(std::string const& key, CompareResult const& result,
|
|
||||||
std::string const& value,
|
|
||||||
std::string const& range_end = "");
|
|
||||||
void add_compare_lease(std::string const& key, int64_t const& lease,
|
|
||||||
std::string const& range_end = "");
|
|
||||||
void add_compare_lease(std::string const& key, CompareResult const& result,
|
|
||||||
int64_t const& lease,
|
|
||||||
std::string const& range_end = "");
|
|
||||||
|
|
||||||
void add_success_range(std::string const& key,
|
|
||||||
std::string const& range_end = "",
|
|
||||||
bool const recursive = false, const int64_t limit = 0);
|
|
||||||
void add_success_put(std::string const& key, std::string const& value,
|
|
||||||
int64_t const leaseid = 0, const bool prev_kv = false);
|
|
||||||
void add_success_delete(std::string const& key,
|
|
||||||
std::string const& range_end = "",
|
|
||||||
bool const recursive = false,
|
|
||||||
const bool prev_kv = false);
|
|
||||||
void add_success_txn(const std::shared_ptr<Transaction> txn);
|
|
||||||
|
|
||||||
void add_failure_range(std::string const& key,
|
|
||||||
std::string const& range_end = "",
|
|
||||||
bool const recursive = false, const int64_t limit = 0);
|
|
||||||
void add_failure_put(std::string const& key, std::string const& value,
|
|
||||||
int64_t const leaseid = 0, const bool prev_kv = false);
|
|
||||||
void add_failure_delete(std::string const& key,
|
|
||||||
std::string const& range_end = "",
|
|
||||||
bool const recursive = false,
|
|
||||||
const bool prev_kv = false);
|
|
||||||
void add_failure_txn(const std::shared_ptr<Transaction> txn);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compare, and create if succeed. If failed, the response will
|
|
||||||
* contains the previous value in "values()" field.
|
|
||||||
*/
|
|
||||||
void setup_compare_and_create(std::string const& key,
|
|
||||||
std::string const& prev_value,
|
|
||||||
std::string const& create_key,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid = 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compare, or create if failed. If failed, the response will contains
|
|
||||||
* the previous value in "values()" field.
|
|
||||||
*/
|
|
||||||
void setup_compare_or_create(std::string const& key,
|
|
||||||
std::string const& prev_value,
|
|
||||||
std::string const& create_key,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid = 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compare, and swap if succeed. If failed, the response will contains
|
|
||||||
* the previous value in "values()" field.
|
|
||||||
*/
|
|
||||||
void setup_compare_and_swap(std::string const& key,
|
|
||||||
std::string const& prev_value,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid = 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compare, and swap if failed. If failed, the response will contains
|
|
||||||
* the previous value in "values()" field.
|
|
||||||
*/
|
|
||||||
void setup_compare_or_swap(std::string const& key,
|
|
||||||
std::string const& prev_value,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid = 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compare, and delete if succeed. If failed, the response will
|
|
||||||
* contains the previous value in "values()" field.
|
|
||||||
*/
|
|
||||||
void setup_compare_and_delete(std::string const& key,
|
|
||||||
std::string const& prev_value,
|
|
||||||
std::string const& delete_key,
|
|
||||||
std::string const& range_end = "",
|
|
||||||
const bool recursive = false);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compare, or delete if failed. If failed, the response will contains
|
|
||||||
* the previous value in "values()" field.
|
|
||||||
*/
|
|
||||||
void setup_compare_or_delete(std::string const& key,
|
|
||||||
std::string const& prev_value,
|
|
||||||
std::string const& delete_key,
|
|
||||||
std::string const& range_end = "",
|
|
||||||
const bool recursive = false);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compare, and create if succeed. If failed, the response will
|
|
||||||
* contains the previous value in "values()" field.
|
|
||||||
*/
|
|
||||||
void setup_compare_and_create(std::string const& key,
|
|
||||||
const int64_t prev_revision,
|
|
||||||
std::string const& create_key,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid = 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compare, or create if failed. If failed, the response will contains
|
|
||||||
* the previous value in "values()" field.
|
|
||||||
*/
|
|
||||||
void setup_compare_or_create(std::string const& key,
|
|
||||||
const int64_t prev_revision,
|
|
||||||
std::string const& create_key,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid = 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compare, and swap if succeed. If failed, the response will contains
|
|
||||||
* the previous value in "values()" field.
|
|
||||||
*/
|
|
||||||
void setup_compare_and_swap(std::string const& key,
|
|
||||||
const int64_t prev_revision,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid = 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compare, and swap if failed. If failed, the response will contains
|
|
||||||
* the previous value in "values()" field.
|
|
||||||
*/
|
|
||||||
void setup_compare_or_swap(std::string const& key,
|
|
||||||
const int64_t prev_revision,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid = 0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compare, and delete if succeed. If failed, the response will
|
|
||||||
* contains the previous value in "values()" field.
|
|
||||||
*/
|
|
||||||
void setup_compare_and_delete(std::string const& key,
|
|
||||||
const int64_t prev_revision,
|
|
||||||
std::string const& delete_key,
|
|
||||||
std::string const& range_end = "",
|
|
||||||
const bool recursive = false);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compare, or delete if failed. If failed, the response will contains
|
|
||||||
* the previous value in "values()" field.
|
|
||||||
*/
|
|
||||||
void setup_compare_or_delete(std::string const& key,
|
|
||||||
const int64_t prev_revision,
|
|
||||||
std::string const& delete_key,
|
|
||||||
std::string const& range_end = "",
|
|
||||||
const bool recursive = false);
|
|
||||||
|
|
||||||
// Keep for backwards compatibility.
|
|
||||||
|
|
||||||
// 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);
|
||||||
void setup_delete(std::string const& key, std::string const& range_end,
|
|
||||||
const bool recursive = false);
|
|
||||||
|
|
||||||
std::shared_ptr<etcdserverpb::TxnRequest> txn_request;
|
std::shared_ptr<etcdserverpb::TxnRequest> txn_request;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string key;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace etcdv3
|
} // namespace etcdv3
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
#include "proto/v3election.pb.h"
|
#include "proto/v3election.pb.h"
|
||||||
|
|
||||||
#include "etcd/v3/KeyValue.hpp"
|
#include "etcd/v3/KeyValue.hpp"
|
||||||
#include "etcd/v3/Member.hpp"
|
|
||||||
|
|
||||||
namespace etcdv3 {
|
namespace etcdv3 {
|
||||||
class V3Response {
|
class V3Response {
|
||||||
|
|
@ -37,7 +36,6 @@ class V3Response {
|
||||||
uint64_t get_member_id() const;
|
uint64_t get_member_id() const;
|
||||||
uint64_t get_raft_term() const;
|
uint64_t get_raft_term() const;
|
||||||
std::vector<int64_t> const& get_leases() const;
|
std::vector<int64_t> const& get_leases() const;
|
||||||
std::vector<etcdv3::Member> const& get_members() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int error_code;
|
int error_code;
|
||||||
|
|
@ -61,8 +59,6 @@ class V3Response {
|
||||||
|
|
||||||
// for lease list
|
// for lease list
|
||||||
std::vector<int64_t> leases;
|
std::vector<int64_t> leases;
|
||||||
// for member list
|
|
||||||
std::vector<etcdv3::Member> members;
|
|
||||||
};
|
};
|
||||||
} // namespace etcdv3
|
} // namespace etcdv3
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,6 @@ extern char const* LEASEKEEPALIVE;
|
||||||
extern char const* LEASETIMETOLIVE;
|
extern char const* LEASETIMETOLIVE;
|
||||||
extern char const* LEASELEASES;
|
extern char const* LEASELEASES;
|
||||||
|
|
||||||
extern char const* ADDMEMBER;
|
|
||||||
extern char const* LISTMEMBER;
|
|
||||||
extern char const* REMOVEMEMBER;
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
||||||
|
|
@ -19,50 +19,35 @@ file(GLOB_RECURSE CPP_CLIENT_CORE_SRC
|
||||||
|
|
||||||
add_library(etcd-cpp-api-core-objects OBJECT ${CPP_CLIENT_CORE_SRC} ${PROTOBUF_GENERATES})
|
add_library(etcd-cpp-api-core-objects OBJECT ${CPP_CLIENT_CORE_SRC} ${PROTOBUF_GENERATES})
|
||||||
use_cxx(etcd-cpp-api-core-objects)
|
use_cxx(etcd-cpp-api-core-objects)
|
||||||
set_exceptions(etcd-cpp-api-core-objects)
|
|
||||||
add_dependencies(etcd-cpp-api-core-objects protobuf_generates)
|
add_dependencies(etcd-cpp-api-core-objects protobuf_generates)
|
||||||
include_generated_protobuf_files(etcd-cpp-api-core-objects)
|
include_generated_protobuf_files(etcd-cpp-api-core-objects)
|
||||||
target_link_libraries(etcd-cpp-api-core-objects PUBLIC
|
target_link_libraries(etcd-cpp-api-core-objects PUBLIC
|
||||||
|
${PROTOBUF_LIBRARIES}
|
||||||
${OPENSSL_LIBRARIES}
|
${OPENSSL_LIBRARIES}
|
||||||
${GRPC_LIBRARIES}
|
${GRPC_LIBRARIES}
|
||||||
)
|
)
|
||||||
if(TARGET protobuf::libprotobuf)
|
|
||||||
target_link_libraries(etcd-cpp-api-core-objects PUBLIC protobuf::libprotobuf)
|
|
||||||
else()
|
|
||||||
target_link_libraries(etcd-cpp-api-core-objects PUBLIC ${PROTOBUF_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(BUILD_ETCD_CORE_ONLY)
|
if(BUILD_ETCD_CORE_ONLY)
|
||||||
# add the core library, includes the sycnhronous client only
|
# add the core library, includes the sycnhronous client only
|
||||||
add_library(etcd-cpp-api-core $<TARGET_OBJECTS:etcd-cpp-api-core-objects>)
|
add_library(etcd-cpp-api-core $<TARGET_OBJECTS:etcd-cpp-api-core-objects>)
|
||||||
use_cxx(etcd-cpp-api-core)
|
use_cxx(etcd-cpp-api-core)
|
||||||
set_exceptions(etcd-cpp-api-core)
|
|
||||||
target_link_libraries(etcd-cpp-api-core PUBLIC
|
target_link_libraries(etcd-cpp-api-core PUBLIC
|
||||||
|
${PROTOBUF_LIBRARIES}
|
||||||
${OPENSSL_LIBRARIES}
|
${OPENSSL_LIBRARIES}
|
||||||
${GRPC_LIBRARIES}
|
${GRPC_LIBRARIES}
|
||||||
)
|
)
|
||||||
if(TARGET protobuf::libprotobuf)
|
|
||||||
target_link_libraries(etcd-cpp-api-core PUBLIC protobuf::libprotobuf)
|
|
||||||
else()
|
|
||||||
target_link_libraries(etcd-cpp-api-core PUBLIC ${PROTOBUF_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
include_generated_protobuf_files(etcd-cpp-api-core)
|
include_generated_protobuf_files(etcd-cpp-api-core)
|
||||||
else()
|
else()
|
||||||
# add the client with asynchronus client
|
# add the client with asynchronus client
|
||||||
add_library(etcd-cpp-api $<TARGET_OBJECTS:etcd-cpp-api-core-objects>
|
add_library(etcd-cpp-api $<TARGET_OBJECTS:etcd-cpp-api-core-objects>
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/Client.cpp")
|
"${CMAKE_CURRENT_SOURCE_DIR}/Client.cpp")
|
||||||
use_cxx(etcd-cpp-api)
|
use_cxx(etcd-cpp-api)
|
||||||
set_exceptions(etcd-cpp-api)
|
|
||||||
target_link_libraries(etcd-cpp-api PUBLIC
|
target_link_libraries(etcd-cpp-api PUBLIC
|
||||||
${CPPREST_LIB} # n.b.: the asynchronous client requires pplx in cpprestsdk
|
${CPPREST_LIB} # n.b.: the asynchronous client requires pplx in cpprestsdk
|
||||||
|
${PROTOBUF_LIBRARIES}
|
||||||
${OPENSSL_LIBRARIES}
|
${OPENSSL_LIBRARIES}
|
||||||
${GRPC_LIBRARIES}
|
${GRPC_LIBRARIES}
|
||||||
)
|
)
|
||||||
if(TARGET protobuf::libprotobuf)
|
|
||||||
target_link_libraries(etcd-cpp-api PUBLIC protobuf::libprotobuf)
|
|
||||||
else()
|
|
||||||
target_link_libraries(etcd-cpp-api PUBLIC ${PROTOBUF_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
include_generated_protobuf_files(etcd-cpp-api)
|
include_generated_protobuf_files(etcd-cpp-api)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
170
src/Client.cpp
170
src/Client.cpp
|
|
@ -231,15 +231,61 @@ pplx::task<etcd::Response> etcd::Client::get(std::string const& key,
|
||||||
|
|
||||||
pplx::task<etcd::Response> etcd::Client::set(std::string const& key,
|
pplx::task<etcd::Response> etcd::Client::set(std::string const& key,
|
||||||
std::string const& value,
|
std::string const& value,
|
||||||
const int64_t leaseid) {
|
int ttl) {
|
||||||
|
if (ttl > 0) {
|
||||||
|
return this->leasegrant(ttl).then(
|
||||||
|
[this, key, value](pplx::task<etcd::Response> const& task) {
|
||||||
|
auto resp = task.get();
|
||||||
|
if (resp.error_code() == 0) {
|
||||||
return etcd::detail::asyncify(
|
return etcd::detail::asyncify(
|
||||||
static_cast<responser_t<etcdv3::AsyncPutAction>>(Response::create),
|
static_cast<responser_t<etcdv3::AsyncSetAction>>(
|
||||||
this->client->put_internal(key, value, leaseid));
|
Response::create),
|
||||||
|
this->client->set_internal(key, value, resp.value().lease()));
|
||||||
|
} else {
|
||||||
|
return pplx::task_from_result(resp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return etcd::detail::asyncify(
|
||||||
|
static_cast<responser_t<etcdv3::AsyncSetAction>>(Response::create),
|
||||||
|
this->client->set_internal(key, value, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pplx::task<etcd::Response> etcd::Client::set(std::string const& key,
|
||||||
|
std::string const& value,
|
||||||
|
int64_t leaseid) {
|
||||||
|
return etcd::detail::asyncify(
|
||||||
|
static_cast<responser_t<etcdv3::AsyncSetAction>>(Response::create),
|
||||||
|
this->client->set_internal(key, value, leaseid));
|
||||||
}
|
}
|
||||||
|
|
||||||
pplx::task<etcd::Response> etcd::Client::add(std::string const& key,
|
pplx::task<etcd::Response> etcd::Client::add(std::string const& key,
|
||||||
std::string const& value,
|
std::string const& value,
|
||||||
const int64_t leaseid) {
|
int ttl) {
|
||||||
|
if (ttl > 0) {
|
||||||
|
return this->leasegrant(ttl).then(
|
||||||
|
[this, key, value](pplx::task<etcd::Response> const& task) {
|
||||||
|
auto resp = task.get();
|
||||||
|
if (resp.error_code() == 0) {
|
||||||
|
return etcd::detail::asyncify(
|
||||||
|
static_cast<responser_t<etcdv3::AsyncSetAction>>(
|
||||||
|
Response::create),
|
||||||
|
this->client->add_internal(key, value, resp.value().lease()));
|
||||||
|
} else {
|
||||||
|
return pplx::task_from_result(resp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return etcd::detail::asyncify(
|
||||||
|
static_cast<responser_t<etcdv3::AsyncSetAction>>(Response::create),
|
||||||
|
this->client->add_internal(key, value, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pplx::task<etcd::Response> etcd::Client::add(std::string const& key,
|
||||||
|
std::string const& value,
|
||||||
|
int64_t leaseid) {
|
||||||
return etcd::detail::asyncify(
|
return etcd::detail::asyncify(
|
||||||
static_cast<responser_t<etcdv3::AsyncSetAction>>(Response::create),
|
static_cast<responser_t<etcdv3::AsyncSetAction>>(Response::create),
|
||||||
this->client->add_internal(key, value, leaseid));
|
this->client->add_internal(key, value, leaseid));
|
||||||
|
|
@ -252,17 +298,33 @@ pplx::task<etcd::Response> etcd::Client::put(std::string const& key,
|
||||||
this->client->put_internal(key, value));
|
this->client->put_internal(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
pplx::task<etcd::Response> etcd::Client::put(std::string const& key,
|
pplx::task<etcd::Response> etcd::Client::modify(std::string const& key,
|
||||||
std::string const& value,
|
std::string const& value,
|
||||||
const int64_t leaseId) {
|
int ttl) {
|
||||||
|
if (ttl > 0) {
|
||||||
|
return this->leasegrant(ttl).then(
|
||||||
|
[this, key, value](pplx::task<etcd::Response> const& task) {
|
||||||
|
auto resp = task.get();
|
||||||
|
if (resp.error_code() == 0) {
|
||||||
return etcd::detail::asyncify(
|
return etcd::detail::asyncify(
|
||||||
static_cast<responser_t<etcdv3::AsyncPutAction>>(Response::create),
|
static_cast<responser_t<etcdv3::AsyncUpdateAction>>(
|
||||||
this->client->put_internal(key, value, leaseId));
|
Response::create),
|
||||||
|
this->client->modify_internal(key, value,
|
||||||
|
resp.value().lease()));
|
||||||
|
} else {
|
||||||
|
return pplx::task_from_result(resp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return etcd::detail::asyncify(
|
||||||
|
static_cast<responser_t<etcdv3::AsyncUpdateAction>>(Response::create),
|
||||||
|
this->client->modify_internal(key, value, 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pplx::task<etcd::Response> etcd::Client::modify(std::string const& key,
|
pplx::task<etcd::Response> etcd::Client::modify(std::string const& key,
|
||||||
std::string const& value,
|
std::string const& value,
|
||||||
const int64_t leaseid) {
|
int64_t leaseid) {
|
||||||
return etcd::detail::asyncify(
|
return etcd::detail::asyncify(
|
||||||
static_cast<responser_t<etcdv3::AsyncUpdateAction>>(Response::create),
|
static_cast<responser_t<etcdv3::AsyncUpdateAction>>(Response::create),
|
||||||
this->client->modify_internal(key, value, leaseid));
|
this->client->modify_internal(key, value, leaseid));
|
||||||
|
|
@ -271,25 +333,78 @@ pplx::task<etcd::Response> etcd::Client::modify(std::string const& key,
|
||||||
pplx::task<etcd::Response> etcd::Client::modify_if(std::string const& key,
|
pplx::task<etcd::Response> etcd::Client::modify_if(std::string const& key,
|
||||||
std::string const& value,
|
std::string const& value,
|
||||||
std::string const& old_value,
|
std::string const& old_value,
|
||||||
const int64_t leaseid) {
|
int ttl) {
|
||||||
|
if (ttl > 0) {
|
||||||
|
return this->leasegrant(ttl).then(
|
||||||
|
[this, key, value, old_value](pplx::task<etcd::Response> const& task) {
|
||||||
|
auto resp = task.get();
|
||||||
|
if (resp.error_code() == 0) {
|
||||||
return etcd::detail::asyncify(
|
return etcd::detail::asyncify(
|
||||||
static_cast<responser_t<etcdv3::AsyncCompareAndSwapAction>>(
|
static_cast<responser_t<etcdv3::AsyncCompareAndSwapAction>>(
|
||||||
Response::create),
|
Response::create),
|
||||||
this->client->modify_if_internal(key, value, 0, old_value,
|
this->client->modify_if_internal(
|
||||||
etcdv3::AtomicityType::PREV_VALUE,
|
key, value, 0, old_value, resp.value().lease(),
|
||||||
leaseid));
|
etcdv3::AtomicityType::PREV_VALUE));
|
||||||
|
} else {
|
||||||
|
return pplx::task_from_result(resp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return etcd::detail::asyncify(
|
||||||
|
static_cast<responser_t<etcdv3::AsyncCompareAndSwapAction>>(
|
||||||
|
Response::create),
|
||||||
|
this->client->modify_if_internal(key, value, 0, old_value, 0,
|
||||||
|
etcdv3::AtomicityType::PREV_VALUE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pplx::task<etcd::Response> etcd::Client::modify_if(std::string const& key,
|
||||||
|
std::string const& value,
|
||||||
|
std::string const& old_value,
|
||||||
|
int64_t leaseid) {
|
||||||
|
return etcd::detail::asyncify(
|
||||||
|
static_cast<responser_t<etcdv3::AsyncCompareAndSwapAction>>(
|
||||||
|
Response::create),
|
||||||
|
this->client->modify_if_internal(key, value, 0, old_value, leaseid,
|
||||||
|
etcdv3::AtomicityType::PREV_VALUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
pplx::task<etcd::Response> etcd::Client::modify_if(std::string const& key,
|
||||||
|
std::string const& value,
|
||||||
|
int64_t old_index, int ttl) {
|
||||||
|
if (ttl > 0) {
|
||||||
|
return this->leasegrant(ttl).then(
|
||||||
|
[this, key, value, old_index](pplx::task<etcd::Response> const& task) {
|
||||||
|
auto resp = task.get();
|
||||||
|
if (resp.error_code() == 0) {
|
||||||
|
return etcd::detail::asyncify(
|
||||||
|
static_cast<responser_t<etcdv3::AsyncCompareAndSwapAction>>(
|
||||||
|
Response::create),
|
||||||
|
this->client->modify_if_internal(
|
||||||
|
key, value, old_index, "", resp.value().lease(),
|
||||||
|
etcdv3::AtomicityType::PREV_INDEX));
|
||||||
|
} else {
|
||||||
|
return pplx::task_from_result(resp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return etcd::detail::asyncify(
|
||||||
|
static_cast<responser_t<etcdv3::AsyncCompareAndSwapAction>>(
|
||||||
|
Response::create),
|
||||||
|
this->client->modify_if_internal(key, value, old_index, "", 0,
|
||||||
|
etcdv3::AtomicityType::PREV_INDEX));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pplx::task<etcd::Response> etcd::Client::modify_if(std::string const& key,
|
pplx::task<etcd::Response> etcd::Client::modify_if(std::string const& key,
|
||||||
std::string const& value,
|
std::string const& value,
|
||||||
int64_t old_index,
|
int64_t old_index,
|
||||||
const int64_t leaseid) {
|
int64_t leaseid) {
|
||||||
return etcd::detail::asyncify(
|
return etcd::detail::asyncify(
|
||||||
static_cast<responser_t<etcdv3::AsyncCompareAndSwapAction>>(
|
static_cast<responser_t<etcdv3::AsyncCompareAndSwapAction>>(
|
||||||
Response::create),
|
Response::create),
|
||||||
this->client->modify_if_internal(key, value, old_index, "",
|
this->client->modify_if_internal(key, value, old_index, "", leaseid,
|
||||||
etcdv3::AtomicityType::PREV_INDEX,
|
etcdv3::AtomicityType::PREV_INDEX));
|
||||||
leaseid));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pplx::task<etcd::Response> etcd::Client::rm(std::string const& key) {
|
pplx::task<etcd::Response> etcd::Client::rm(std::string const& key) {
|
||||||
|
|
@ -494,27 +609,6 @@ pplx::task<etcd::Response> etcd::Client::leases() {
|
||||||
this->client->leases_internal());
|
this->client->leases_internal());
|
||||||
}
|
}
|
||||||
|
|
||||||
pplx::task<etcd::Response> etcd::Client::add_member(
|
|
||||||
std::string const& peer_urls, bool is_learner) {
|
|
||||||
return etcd::detail::asyncify(
|
|
||||||
static_cast<responser_t<etcdv3::AsyncAddMemberAction>>(Response::create),
|
|
||||||
this->client->add_member_internal(peer_urls, is_learner));
|
|
||||||
}
|
|
||||||
|
|
||||||
pplx::task<etcd::Response> etcd::Client::list_member() {
|
|
||||||
return etcd::detail::asyncify(
|
|
||||||
static_cast<responser_t<etcdv3::AsyncListMemberAction>>(Response::create),
|
|
||||||
this->client->list_member_internal());
|
|
||||||
}
|
|
||||||
|
|
||||||
pplx::task<etcd::Response> etcd::Client::remove_member(
|
|
||||||
const uint64_t member_id) {
|
|
||||||
return etcd::detail::asyncify(
|
|
||||||
static_cast<responser_t<etcdv3::AsyncRemoveMemberAction>>(
|
|
||||||
Response::create),
|
|
||||||
this->client->remove_member_internal(member_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
pplx::task<etcd::Response> etcd::Client::lock(std::string const& key) {
|
pplx::task<etcd::Response> etcd::Client::lock(std::string const& key) {
|
||||||
static const int DEFAULT_LEASE_TTL_FOR_LOCK =
|
static const int DEFAULT_LEASE_TTL_FOR_LOCK =
|
||||||
10; // see also etcd::SyncClient::lock
|
10; // see also etcd::SyncClient::lock
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <iostream>
|
|
||||||
#include <ratio>
|
#include <ratio>
|
||||||
|
|
||||||
#include "etcd/KeepAlive.hpp"
|
#include "etcd/KeepAlive.hpp"
|
||||||
|
|
@ -29,10 +28,6 @@ etcd::KeepAlive::KeepAlive(SyncClient const& client, int ttl, int64_t lease_id)
|
||||||
lease_id(lease_id),
|
lease_id(lease_id),
|
||||||
continue_next(true),
|
continue_next(true),
|
||||||
grpc_timeout(client.get_grpc_timeout()) {
|
grpc_timeout(client.get_grpc_timeout()) {
|
||||||
if (ttl > 0 && lease_id == 0) {
|
|
||||||
this->lease_id =
|
|
||||||
const_cast<SyncClient&>(client).leasegrant(ttl).value().lease();
|
|
||||||
}
|
|
||||||
stubs.reset(new EtcdServerStubs{});
|
stubs.reset(new EtcdServerStubs{});
|
||||||
stubs->leaseServiceStub = Lease::NewStub(client.grpc_channel());
|
stubs->leaseServiceStub = Lease::NewStub(client.grpc_channel());
|
||||||
|
|
||||||
|
|
@ -46,7 +41,6 @@ etcd::KeepAlive::KeepAlive(SyncClient const& client, int ttl, int64_t lease_id)
|
||||||
|
|
||||||
stubs->call.reset(new etcdv3::AsyncLeaseKeepAliveAction(std::move(params)));
|
stubs->call.reset(new etcdv3::AsyncLeaseKeepAliveAction(std::move(params)));
|
||||||
refresh_task_ = std::thread([this]() {
|
refresh_task_ = std::thread([this]() {
|
||||||
#ifndef _ETCD_NO_EXCEPTIONS
|
|
||||||
try {
|
try {
|
||||||
// start refresh
|
// start refresh
|
||||||
this->refresh();
|
this->refresh();
|
||||||
|
|
@ -54,12 +48,6 @@ etcd::KeepAlive::KeepAlive(SyncClient const& client, int ttl, int64_t lease_id)
|
||||||
// propagate the exception
|
// propagate the exception
|
||||||
eptr_ = std::current_exception();
|
eptr_ = std::current_exception();
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
const std::string err = this->refresh();
|
|
||||||
if (!err.empty()) {
|
|
||||||
eptr_ = std::make_exception_ptr(std::runtime_error(err));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,7 +68,7 @@ etcd::KeepAlive::KeepAlive(
|
||||||
std::function<void(std::exception_ptr)> const& handler, int ttl,
|
std::function<void(std::exception_ptr)> const& handler, int ttl,
|
||||||
int64_t lease_id, std::string const& target_name_override)
|
int64_t lease_id, std::string const& target_name_override)
|
||||||
: KeepAlive(SyncClient(address, ca, cert, privkey, target_name_override),
|
: KeepAlive(SyncClient(address, ca, cert, privkey, target_name_override),
|
||||||
handler, ttl, lease_id) {}
|
ttl, lease_id) {}
|
||||||
|
|
||||||
etcd::KeepAlive::KeepAlive(
|
etcd::KeepAlive::KeepAlive(
|
||||||
SyncClient const& client,
|
SyncClient const& client,
|
||||||
|
|
@ -91,10 +79,6 @@ etcd::KeepAlive::KeepAlive(
|
||||||
lease_id(lease_id),
|
lease_id(lease_id),
|
||||||
continue_next(true),
|
continue_next(true),
|
||||||
grpc_timeout(client.get_grpc_timeout()) {
|
grpc_timeout(client.get_grpc_timeout()) {
|
||||||
if (ttl > 0 && lease_id == 0) {
|
|
||||||
this->lease_id =
|
|
||||||
const_cast<SyncClient&>(client).leasegrant(ttl).value().lease();
|
|
||||||
}
|
|
||||||
stubs.reset(new EtcdServerStubs{});
|
stubs.reset(new EtcdServerStubs{});
|
||||||
stubs->leaseServiceStub = Lease::NewStub(client.grpc_channel());
|
stubs->leaseServiceStub = Lease::NewStub(client.grpc_channel());
|
||||||
|
|
||||||
|
|
@ -106,23 +90,16 @@ etcd::KeepAlive::KeepAlive(
|
||||||
|
|
||||||
stubs->call.reset(new etcdv3::AsyncLeaseKeepAliveAction(std::move(params)));
|
stubs->call.reset(new etcdv3::AsyncLeaseKeepAliveAction(std::move(params)));
|
||||||
refresh_task_ = std::thread([this]() {
|
refresh_task_ = std::thread([this]() {
|
||||||
#ifndef _ETCD_NO_EXCEPTIONS
|
|
||||||
try {
|
try {
|
||||||
// start refresh
|
// start refresh
|
||||||
this->refresh();
|
this->refresh();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
// propagate the exception
|
// propogate the exception
|
||||||
eptr_ = std::current_exception();
|
eptr_ = std::current_exception();
|
||||||
}
|
if (handler_) {
|
||||||
#else
|
|
||||||
const std::string err = this->refresh();
|
|
||||||
if (!err.empty()) {
|
|
||||||
eptr_ = std::make_exception_ptr(std::runtime_error(err));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (eptr_ && handler_) {
|
|
||||||
handler_(eptr_);
|
handler_(eptr_);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,7 +140,6 @@ void etcd::KeepAlive::Check() {
|
||||||
std::rethrow_exception(eptr_);
|
std::rethrow_exception(eptr_);
|
||||||
}
|
}
|
||||||
// issue an refresh to make sure it still alive
|
// issue an refresh to make sure it still alive
|
||||||
#ifndef _ETCD_NO_EXCEPTIONS
|
|
||||||
try {
|
try {
|
||||||
this->refresh_once();
|
this->refresh_once();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|
@ -173,35 +149,19 @@ void etcd::KeepAlive::Check() {
|
||||||
// propagate the exception, as we throw in `Check()`, the `handler` won't be
|
// propagate the exception, as we throw in `Check()`, the `handler` won't be
|
||||||
// touched
|
// touched
|
||||||
eptr_ = std::current_exception();
|
eptr_ = std::current_exception();
|
||||||
}
|
if (handler_) {
|
||||||
#else
|
|
||||||
const std::string err = this->refresh_once();
|
|
||||||
if (!err.empty()) {
|
|
||||||
// run canceller first
|
|
||||||
this->Cancel();
|
|
||||||
|
|
||||||
// propagate the exception, as we throw in `Check()`, the `handler` won't be
|
|
||||||
// touched
|
|
||||||
eptr_ = std::make_exception_ptr(std::runtime_error(err));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (eptr_ && handler_) {
|
|
||||||
handler_(eptr_);
|
handler_(eptr_);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _ETCD_NO_EXCEPTIONS
|
|
||||||
if (eptr_) {
|
|
||||||
// rethrow in `Check()` to keep the consistent semantics
|
// rethrow in `Check()` to keep the consistent semantics
|
||||||
std::rethrow_exception(eptr_);
|
std::rethrow_exception(eptr_);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string etcd::KeepAlive::refresh() {
|
void etcd::KeepAlive::refresh() {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!continue_next.load()) {
|
if (!continue_next.load()) {
|
||||||
return std::string{};
|
return;
|
||||||
}
|
}
|
||||||
// minimal resolution: 1 second
|
// minimal resolution: 1 second
|
||||||
int keepalive_ttl = std::max(ttl - 1, 1);
|
int keepalive_ttl = std::max(ttl - 1, 1);
|
||||||
|
|
@ -209,50 +169,29 @@ std::string etcd::KeepAlive::refresh() {
|
||||||
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)) ==
|
if (cv_for_refresh_.wait_for(lock, std::chrono::seconds(keepalive_ttl)) ==
|
||||||
std::cv_status::no_timeout) {
|
std::cv_status::no_timeout) {
|
||||||
if (!continue_next.load()) {
|
return;
|
||||||
return std::string{};
|
|
||||||
}
|
|
||||||
#ifndef NDEBUG
|
|
||||||
std::cerr
|
|
||||||
<< "[warn] awaked from condition_variable but continue_next is "
|
|
||||||
"not set, maybe due to clock drift."
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// execute refresh
|
// execute refresh
|
||||||
const std::string err = this->refresh_once();
|
this->refresh_once();
|
||||||
if (!err.empty()) {
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return std::string{};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string 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 std::string{};
|
return;
|
||||||
}
|
}
|
||||||
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()) {
|
||||||
const std::string err = "Failed to refresh lease: error code: " +
|
throw std::runtime_error("Failed to refresh lease: error code: " +
|
||||||
std::to_string(resp.error_code()) +
|
std::to_string(resp.error_code()) +
|
||||||
", message: " + resp.error_message();
|
", message: " + resp.error_message());
|
||||||
#ifndef _ETCD_NO_EXCEPTIONS
|
|
||||||
throw std::runtime_error(err);
|
|
||||||
#endif
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
if (resp.value().ttl() == 0) {
|
if (resp.value().ttl() == 0) {
|
||||||
const std::string err =
|
throw std::out_of_range(
|
||||||
"Failed to refresh lease due to expiration: the new TTL is 0.";
|
"Failed to refresh lease due to expiration: the new TTL is 0.");
|
||||||
#ifndef _ETCD_NO_EXCEPTIONS
|
|
||||||
throw std::out_of_range(err);
|
|
||||||
#endif
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
return std::string{};
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ etcd::Response::Response(const etcd::Response& response) {
|
||||||
this->_raft_term = response._raft_term;
|
this->_raft_term = response._raft_term;
|
||||||
|
|
||||||
this->_leases = response._leases;
|
this->_leases = response._leases;
|
||||||
this->_members = response._members;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
etcd::Response::Response(const etcdv3::V3Response& reply,
|
etcd::Response::Response(const etcdv3::V3Response& reply,
|
||||||
|
|
@ -40,7 +39,6 @@ etcd::Response::Response(const etcdv3::V3Response& reply,
|
||||||
_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());
|
||||||
}
|
}
|
||||||
_value = Value(reply.get_values()[0]);
|
|
||||||
} else {
|
} else {
|
||||||
_value = Value(reply.get_value());
|
_value = Value(reply.get_value());
|
||||||
}
|
}
|
||||||
|
|
@ -65,8 +63,6 @@ etcd::Response::Response(const etcdv3::V3Response& reply,
|
||||||
|
|
||||||
// lease list
|
// lease list
|
||||||
this->_leases = reply.get_leases();
|
this->_leases = reply.get_leases();
|
||||||
// member list
|
|
||||||
this->_members = reply.get_members();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
etcd::Response::Response(int error_code, std::string const& error_message)
|
etcd::Response::Response(int error_code, std::string const& error_message)
|
||||||
|
|
@ -134,7 +130,3 @@ uint64_t etcd::Response::raft_term() const { 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<etcdv3::Member> const& etcd::Response::members() const {
|
|
||||||
return this->_members;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,6 @@
|
||||||
#define NOMINMAX
|
#define NOMINMAX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
@ -38,7 +33,6 @@
|
||||||
#include <grpc++/grpc++.h>
|
#include <grpc++/grpc++.h>
|
||||||
#include <grpc++/security/credentials.h>
|
#include <grpc++/security/credentials.h>
|
||||||
#include <grpc++/support/status_code_enum.h>
|
#include <grpc++/support/status_code_enum.h>
|
||||||
#include <grpc/grpc.h> // for grpc_lame_client_channel_create()
|
|
||||||
|
|
||||||
#include "proto/rpc.grpc.pb.h"
|
#include "proto/rpc.grpc.pb.h"
|
||||||
#include "proto/v3election.grpc.pb.h"
|
#include "proto/v3election.grpc.pb.h"
|
||||||
|
|
@ -51,22 +45,6 @@
|
||||||
#include "etcd/v3/Transaction.hpp"
|
#include "etcd/v3/Transaction.hpp"
|
||||||
#include "etcd/v3/action_constants.hpp"
|
#include "etcd/v3/action_constants.hpp"
|
||||||
|
|
||||||
namespace grpc {
|
|
||||||
// forward declaration for compatibility with older grpc versions
|
|
||||||
std::shared_ptr<Channel> CreateChannelInternal(
|
|
||||||
const std::string& host, grpc_channel* c_channel,
|
|
||||||
#if defined(WITH_GRPC_CREATE_CHANNEL_INTERNAL_UNIQUE_POINTER)
|
|
||||||
std::unique_ptr<std::vector<
|
|
||||||
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>>
|
|
||||||
interceptor_creators
|
|
||||||
#else
|
|
||||||
std::vector<
|
|
||||||
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
|
|
||||||
interceptor_creators
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
} // namespace grpc
|
|
||||||
|
|
||||||
namespace etcd {
|
namespace etcd {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
|
@ -88,7 +66,7 @@ static void string_split(std::vector<std::string>& dests,
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string string_join(std::vector<std::string> const& srcs,
|
static std::string string_join(std::vector<std::string> const& srcs,
|
||||||
std::string const& sep) {
|
std::string const sep) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
if (!srcs.empty()) {
|
if (!srcs.empty()) {
|
||||||
ss << srcs[0];
|
ss << srcs[0];
|
||||||
|
|
@ -100,32 +78,19 @@ static std::string string_join(std::vector<std::string> const& srcs,
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool dns_resolve(std::string const& target,
|
static bool dns_resolve(std::string const& target,
|
||||||
std::vector<std::string>& endpoints, bool ipv4 = true) {
|
std::vector<std::string>& endpoints) {
|
||||||
|
struct addrinfo hints = {}, *addrs;
|
||||||
|
hints.ai_family = AF_INET;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
|
|
||||||
std::vector<std::string> target_parts;
|
std::vector<std::string> target_parts;
|
||||||
bool ipv6_url{false};
|
string_split(target_parts, target, ":");
|
||||||
{
|
if (target_parts.size() != 2) {
|
||||||
size_t rindex = target.rfind(':');
|
std::cerr << "warn: invalid URL: " << target << std::endl;
|
||||||
if (rindex == target.npos) {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
std::cerr << "[warn] invalid URL: " << target << ", expects 'host:port'"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string host(target.substr(0, rindex));
|
|
||||||
|
|
||||||
// host format is [ipv6]
|
|
||||||
if (!ipv4 && !host.empty() && host[0] == '[' &&
|
|
||||||
host[host.size() - 1] == ']') {
|
|
||||||
host = target.substr(1, rindex - 2);
|
|
||||||
ipv6_url = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
target_parts.push_back(host);
|
|
||||||
target_parts.push_back(target.substr(rindex + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
{
|
{
|
||||||
// Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h.
|
// Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h.
|
||||||
|
|
@ -135,61 +100,26 @@ static bool dns_resolve(std::string const& target,
|
||||||
int err = WSAStartup(wVersionRequested, &wsaData);
|
int err = WSAStartup(wVersionRequested, &wsaData);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
// Tell the user that we could not find a usable Winsock DLL.
|
// Tell the user that we could not find a usable Winsock DLL.
|
||||||
#ifndef NDEBUG
|
std::cerr << "WSAStartup failed with error: %d" << err << std::endl;
|
||||||
std::cerr << "[warn] WSAStartup failed with error: %d" << err
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ipv6_url) {
|
|
||||||
// check valid ipv6
|
|
||||||
struct sockaddr_in6 sa6;
|
|
||||||
if (inet_pton(AF_INET6, target_parts[0].c_str(), &(sa6.sin6_addr)) == 1) {
|
|
||||||
endpoints.emplace_back(target);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct addrinfo hints = {}, *addrs;
|
|
||||||
hints.ai_family = ipv4 ? AF_INET : AF_INET6;
|
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
|
||||||
hints.ai_protocol = IPPROTO_TCP;
|
|
||||||
|
|
||||||
int r = getaddrinfo(target_parts[0].c_str(), target_parts[1].c_str(), &hints,
|
int r = getaddrinfo(target_parts[0].c_str(), target_parts[1].c_str(), &hints,
|
||||||
&addrs);
|
&addrs);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
#ifndef NDEBUG
|
std::cerr << "warn: getaddrinfo() failed for endpoint " << target
|
||||||
std::cerr << "[warn] getaddrinfo() as " << (ipv4 ? "ipv4" : "ipv6")
|
<< " with error: " << r << std::endl;
|
||||||
<< " failed for endpoint " << target << " with error: " << r
|
|
||||||
<< ", " << strerror(errno) << std::endl;
|
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char host[16] = {'\0'};
|
char host[16] = {'\0'};
|
||||||
for (struct addrinfo* addr = addrs; addr != nullptr; addr = addr->ai_next) {
|
for (struct addrinfo* addr = addrs; addr != nullptr; addr = addr->ai_next) {
|
||||||
if (addr->ai_family != AF_INET && addr->ai_family != AF_INET6) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
memset(host, '\0', sizeof(host));
|
memset(host, '\0', sizeof(host));
|
||||||
int r = getnameinfo(addr->ai_addr, addr->ai_addrlen, host, sizeof(host),
|
getnameinfo(addr->ai_addr, addr->ai_addrlen, host, sizeof(host), NULL, 0,
|
||||||
NULL, 0, NI_NUMERICHOST);
|
NI_NUMERICHOST);
|
||||||
if (r != 0) {
|
endpoints.emplace_back(std::string(host) + ":" + target_parts[1]);
|
||||||
#ifndef NDEBUG
|
|
||||||
std::cerr << "[warn] getnameinfo() failed for endpoint " << target
|
|
||||||
<< " with error: " << r << ", " << strerror(errno) << std::endl;
|
|
||||||
#endif
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
std::string host_string = host;
|
|
||||||
if (addr->ai_family == AF_INET6) {
|
|
||||||
host_string = "[" + host_string + "]";
|
|
||||||
}
|
|
||||||
endpoints.emplace_back(host_string + ":" + target_parts[1]);
|
|
||||||
}
|
}
|
||||||
freeaddrinfo(addrs);
|
freeaddrinfo(addrs);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -198,32 +128,24 @@ static bool dns_resolve(std::string const& target,
|
||||||
const std::string strip_and_resolve_addresses(std::string const& address) {
|
const std::string strip_and_resolve_addresses(std::string const& address) {
|
||||||
std::vector<std::string> addresses;
|
std::vector<std::string> addresses;
|
||||||
string_split(addresses, address, ",;");
|
string_split(addresses, address, ",;");
|
||||||
std::string stripped_v4_address, stripped_v6_address;
|
std::string stripped_address;
|
||||||
{
|
{
|
||||||
std::vector<std::string> stripped_v4_addresses, stripped_v6_addresses;
|
std::vector<std::string> stripped_addresses;
|
||||||
std::string substr("://");
|
std::string substr("://");
|
||||||
for (auto const& addr : addresses) {
|
for (auto const& addr : addresses) {
|
||||||
std::string::size_type idx = addr.find(substr);
|
std::string::size_type idx = addr.find(substr);
|
||||||
std::string target =
|
std::string target =
|
||||||
idx == std::string::npos ? addr : addr.substr(idx + substr.length());
|
idx == std::string::npos ? addr : addr.substr(idx + substr.length());
|
||||||
etcd::detail::dns_resolve(target, stripped_v4_addresses, true);
|
etcd::detail::dns_resolve(target, stripped_addresses);
|
||||||
etcd::detail::dns_resolve(target, stripped_v6_addresses, false);
|
|
||||||
}
|
}
|
||||||
stripped_v4_address = string_join(stripped_v4_addresses, ",");
|
stripped_address = string_join(stripped_addresses, ",");
|
||||||
stripped_v6_address = string_join(stripped_v6_addresses, ",");
|
|
||||||
}
|
}
|
||||||
// prefer resolved ipv4 addresses
|
return "ipv4:///" + stripped_address;
|
||||||
if (!stripped_v4_address.empty()) {
|
|
||||||
return "ipv4:///" + stripped_v4_address;
|
|
||||||
}
|
|
||||||
if (!stripped_v6_address.empty()) {
|
|
||||||
return "ipv6:///" + stripped_v6_address;
|
|
||||||
}
|
|
||||||
return std::string{};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool authenticate(std::shared_ptr<grpc::Channel> const& channel,
|
const bool authenticate(std::shared_ptr<grpc::Channel> const& channel,
|
||||||
std::string const& username, std::string const& password,
|
std::string const& username,
|
||||||
|
std::string const& password,
|
||||||
std::string& token_or_message) {
|
std::string& token_or_message) {
|
||||||
// run a round of auth
|
// run a round of auth
|
||||||
auto auth_stub = etcdserverpb::Auth::NewStub(channel);
|
auto auth_stub = etcdserverpb::Auth::NewStub(channel);
|
||||||
|
|
@ -250,12 +172,10 @@ static std::string read_from_file(std::string const& filename) {
|
||||||
file.close();
|
file.close();
|
||||||
return ss.str();
|
return ss.str();
|
||||||
} else {
|
} else {
|
||||||
#ifndef NDEBUG
|
std::cerr << "[ERROR] failed to load given file '" << filename << "', "
|
||||||
std::cerr << "[error] failed to load given file '" << filename << "', "
|
|
||||||
<< strerror(errno) << std::endl;
|
<< strerror(errno) << std::endl;
|
||||||
#endif
|
|
||||||
return std::string{};
|
|
||||||
}
|
}
|
||||||
|
return std::string{};
|
||||||
}
|
}
|
||||||
|
|
||||||
static grpc::SslCredentialsOptions make_ssl_credentials(
|
static grpc::SslCredentialsOptions make_ssl_credentials(
|
||||||
|
|
@ -272,33 +192,6 @@ std::unique_ptr<T> make_unique_ptr(Args&&... args) {
|
||||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<grpc::Channel> create_grpc_channel(
|
|
||||||
const std::string& address,
|
|
||||||
const std::shared_ptr<grpc::ChannelCredentials> creds,
|
|
||||||
const grpc::ChannelArguments& grpc_args) {
|
|
||||||
const std::string addresses =
|
|
||||||
etcd::detail::strip_and_resolve_addresses(address);
|
|
||||||
#ifndef NDEBUG
|
|
||||||
std::cerr << "[debug] resolved addresses: " << addresses << std::endl;
|
|
||||||
#endif
|
|
||||||
if (addresses.empty() || addresses == "ipv4:///" || addresses == "ipv6:///") {
|
|
||||||
// bypass grpc initialization to avoid noisy logs from grpc
|
|
||||||
return grpc::CreateChannelInternal(
|
|
||||||
"",
|
|
||||||
grpc_lame_client_channel_create(addresses.c_str(), GRPC_STATUS_INTERNAL,
|
|
||||||
"the target uri is not valid"),
|
|
||||||
#if defined(WITH_GRPC_CREATE_CHANNEL_INTERNAL_UNIQUE_POINTER)
|
|
||||||
nullptr
|
|
||||||
#else
|
|
||||||
std::vector<std::unique_ptr<
|
|
||||||
grpc::experimental::ClientInterceptorFactoryInterface>>()
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return grpc::CreateCustomChannel(addresses, creds, grpc_args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace etcd
|
} // namespace etcd
|
||||||
|
|
||||||
|
|
@ -342,11 +235,7 @@ class etcd::SyncClient::TokenAuthenticator {
|
||||||
// auth
|
// auth
|
||||||
if (!etcd::detail::authenticate(this->channel_, username_, password_,
|
if (!etcd::detail::authenticate(this->channel_, username_, password_,
|
||||||
token_)) {
|
token_)) {
|
||||||
// n.b.: no throw here as the failure of auth will be propagated
|
throw std::invalid_argument("Etcd authentication failed: " + token_);
|
||||||
// to client when it is asked to issue requests.
|
|
||||||
//
|
|
||||||
// throw std::invalid_argument("Etcd authentication failed: " +
|
|
||||||
// token_);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -364,7 +253,6 @@ void etcd::SyncClient::TokenAuthenticatorDeleter::operator()(
|
||||||
struct etcd::SyncClient::EtcdServerStubs {
|
struct etcd::SyncClient::EtcdServerStubs {
|
||||||
std::unique_ptr<etcdserverpb::KV::Stub> kvServiceStub;
|
std::unique_ptr<etcdserverpb::KV::Stub> kvServiceStub;
|
||||||
std::unique_ptr<etcdserverpb::Watch::Stub> watchServiceStub;
|
std::unique_ptr<etcdserverpb::Watch::Stub> watchServiceStub;
|
||||||
std::unique_ptr<etcdserverpb::Cluster::Stub> clusterServiceStub;
|
|
||||||
std::unique_ptr<etcdserverpb::Lease::Stub> leaseServiceStub;
|
std::unique_ptr<etcdserverpb::Lease::Stub> leaseServiceStub;
|
||||||
std::unique_ptr<v3lockpb::Lock::Stub> lockServiceStub;
|
std::unique_ptr<v3lockpb::Lock::Stub> lockServiceStub;
|
||||||
std::unique_ptr<v3electionpb::Election::Stub> electionServiceStub;
|
std::unique_ptr<v3electionpb::Election::Stub> electionServiceStub;
|
||||||
|
|
@ -380,20 +268,21 @@ void etcd::SyncClient::EtcdServerStubsDeleter::operator()(
|
||||||
etcd::SyncClient::SyncClient(std::string const& address,
|
etcd::SyncClient::SyncClient(std::string const& address,
|
||||||
std::string const& load_balancer) {
|
std::string const& load_balancer) {
|
||||||
// create channels
|
// create channels
|
||||||
|
std::string const addresses =
|
||||||
|
etcd::detail::strip_and_resolve_addresses(address);
|
||||||
grpc::ChannelArguments grpc_args;
|
grpc::ChannelArguments grpc_args;
|
||||||
grpc_args.SetMaxSendMessageSize(std::numeric_limits<int>::max());
|
grpc_args.SetMaxSendMessageSize(std::numeric_limits<int>::max());
|
||||||
grpc_args.SetMaxReceiveMessageSize(std::numeric_limits<int>::max());
|
grpc_args.SetMaxReceiveMessageSize(std::numeric_limits<int>::max());
|
||||||
std::shared_ptr<grpc::ChannelCredentials> creds =
|
std::shared_ptr<grpc::ChannelCredentials> creds =
|
||||||
grpc::InsecureChannelCredentials();
|
grpc::InsecureChannelCredentials();
|
||||||
grpc_args.SetLoadBalancingPolicyName(load_balancer);
|
grpc_args.SetLoadBalancingPolicyName(load_balancer);
|
||||||
this->channel = etcd::detail::create_grpc_channel(address, creds, grpc_args);
|
this->channel = grpc::CreateCustomChannel(addresses, creds, grpc_args);
|
||||||
this->token_authenticator.reset(new TokenAuthenticator());
|
this->token_authenticator.reset(new TokenAuthenticator());
|
||||||
|
|
||||||
// create stubs
|
// create stubs
|
||||||
stubs.reset(new EtcdServerStubs{});
|
stubs.reset(new EtcdServerStubs{});
|
||||||
stubs->kvServiceStub = KV::NewStub(this->channel);
|
stubs->kvServiceStub = KV::NewStub(this->channel);
|
||||||
stubs->watchServiceStub = Watch::NewStub(this->channel);
|
stubs->watchServiceStub = Watch::NewStub(this->channel);
|
||||||
stubs->clusterServiceStub = Cluster::NewStub(this->channel);
|
|
||||||
stubs->leaseServiceStub = Lease::NewStub(this->channel);
|
stubs->leaseServiceStub = Lease::NewStub(this->channel);
|
||||||
stubs->lockServiceStub = Lock::NewStub(this->channel);
|
stubs->lockServiceStub = Lock::NewStub(this->channel);
|
||||||
stubs->electionServiceStub = Election::NewStub(this->channel);
|
stubs->electionServiceStub = Election::NewStub(this->channel);
|
||||||
|
|
@ -402,12 +291,14 @@ etcd::SyncClient::SyncClient(std::string const& address,
|
||||||
etcd::SyncClient::SyncClient(std::string const& address,
|
etcd::SyncClient::SyncClient(std::string const& address,
|
||||||
grpc::ChannelArguments const& arguments) {
|
grpc::ChannelArguments const& arguments) {
|
||||||
// create channels
|
// create channels
|
||||||
|
std::string const addresses =
|
||||||
|
etcd::detail::strip_and_resolve_addresses(address);
|
||||||
grpc::ChannelArguments grpc_args = arguments;
|
grpc::ChannelArguments grpc_args = arguments;
|
||||||
grpc_args.SetMaxSendMessageSize(std::numeric_limits<int>::max());
|
grpc_args.SetMaxSendMessageSize(std::numeric_limits<int>::max());
|
||||||
grpc_args.SetMaxReceiveMessageSize(std::numeric_limits<int>::max());
|
grpc_args.SetMaxReceiveMessageSize(std::numeric_limits<int>::max());
|
||||||
std::shared_ptr<grpc::ChannelCredentials> creds =
|
std::shared_ptr<grpc::ChannelCredentials> creds =
|
||||||
grpc::InsecureChannelCredentials();
|
grpc::InsecureChannelCredentials();
|
||||||
this->channel = etcd::detail::create_grpc_channel(address, creds, grpc_args);
|
this->channel = grpc::CreateCustomChannel(addresses, creds, grpc_args);
|
||||||
this->token_authenticator.reset(new TokenAuthenticator());
|
this->token_authenticator.reset(new TokenAuthenticator());
|
||||||
|
|
||||||
// create stubs
|
// create stubs
|
||||||
|
|
@ -435,13 +326,15 @@ etcd::SyncClient::SyncClient(std::string const& address,
|
||||||
int const auth_token_ttl,
|
int const auth_token_ttl,
|
||||||
std::string const& load_balancer) {
|
std::string const& load_balancer) {
|
||||||
// create channels
|
// create channels
|
||||||
|
std::string const addresses =
|
||||||
|
etcd::detail::strip_and_resolve_addresses(address);
|
||||||
grpc::ChannelArguments grpc_args;
|
grpc::ChannelArguments grpc_args;
|
||||||
grpc_args.SetMaxSendMessageSize(std::numeric_limits<int>::max());
|
grpc_args.SetMaxSendMessageSize(std::numeric_limits<int>::max());
|
||||||
grpc_args.SetMaxReceiveMessageSize(std::numeric_limits<int>::max());
|
grpc_args.SetMaxReceiveMessageSize(std::numeric_limits<int>::max());
|
||||||
std::shared_ptr<grpc::ChannelCredentials> creds =
|
std::shared_ptr<grpc::ChannelCredentials> creds =
|
||||||
grpc::InsecureChannelCredentials();
|
grpc::InsecureChannelCredentials();
|
||||||
grpc_args.SetLoadBalancingPolicyName(load_balancer);
|
grpc_args.SetLoadBalancingPolicyName(load_balancer);
|
||||||
this->channel = etcd::detail::create_grpc_channel(address, creds, grpc_args);
|
this->channel = grpc::CreateCustomChannel(addresses, creds, grpc_args);
|
||||||
|
|
||||||
// auth
|
// auth
|
||||||
this->token_authenticator.reset(new TokenAuthenticator(
|
this->token_authenticator.reset(new TokenAuthenticator(
|
||||||
|
|
@ -462,12 +355,14 @@ etcd::SyncClient::SyncClient(std::string const& address,
|
||||||
int const auth_token_ttl,
|
int const auth_token_ttl,
|
||||||
grpc::ChannelArguments const& arguments) {
|
grpc::ChannelArguments const& arguments) {
|
||||||
// create channels
|
// create channels
|
||||||
|
std::string const addresses =
|
||||||
|
etcd::detail::strip_and_resolve_addresses(address);
|
||||||
grpc::ChannelArguments grpc_args = arguments;
|
grpc::ChannelArguments grpc_args = arguments;
|
||||||
grpc_args.SetMaxSendMessageSize(std::numeric_limits<int>::max());
|
grpc_args.SetMaxSendMessageSize(std::numeric_limits<int>::max());
|
||||||
grpc_args.SetMaxReceiveMessageSize(std::numeric_limits<int>::max());
|
grpc_args.SetMaxReceiveMessageSize(std::numeric_limits<int>::max());
|
||||||
std::shared_ptr<grpc::ChannelCredentials> creds =
|
std::shared_ptr<grpc::ChannelCredentials> creds =
|
||||||
grpc::InsecureChannelCredentials();
|
grpc::InsecureChannelCredentials();
|
||||||
this->channel = etcd::detail::create_grpc_channel(address, creds, grpc_args);
|
this->channel = grpc::CreateCustomChannel(addresses, creds, grpc_args);
|
||||||
|
|
||||||
// auth
|
// auth
|
||||||
this->token_authenticator.reset(new TokenAuthenticator(
|
this->token_authenticator.reset(new TokenAuthenticator(
|
||||||
|
|
@ -505,6 +400,8 @@ etcd::SyncClient::SyncClient(std::string const& address, std::string const& ca,
|
||||||
std::string const& target_name_override,
|
std::string const& target_name_override,
|
||||||
std::string const& load_balancer) {
|
std::string const& load_balancer) {
|
||||||
// create channels
|
// create channels
|
||||||
|
std::string const addresses =
|
||||||
|
etcd::detail::strip_and_resolve_addresses(address);
|
||||||
grpc::ChannelArguments grpc_args;
|
grpc::ChannelArguments grpc_args;
|
||||||
grpc_args.SetMaxSendMessageSize(std::numeric_limits<int>::max());
|
grpc_args.SetMaxSendMessageSize(std::numeric_limits<int>::max());
|
||||||
grpc_args.SetMaxReceiveMessageSize(std::numeric_limits<int>::max());
|
grpc_args.SetMaxReceiveMessageSize(std::numeric_limits<int>::max());
|
||||||
|
|
@ -515,7 +412,7 @@ etcd::SyncClient::SyncClient(std::string const& address, std::string const& ca,
|
||||||
grpc_args.SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
|
grpc_args.SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
|
||||||
target_name_override);
|
target_name_override);
|
||||||
}
|
}
|
||||||
this->channel = etcd::detail::create_grpc_channel(address, creds, grpc_args);
|
this->channel = grpc::CreateCustomChannel(addresses, creds, grpc_args);
|
||||||
this->token_authenticator.reset(new TokenAuthenticator());
|
this->token_authenticator.reset(new TokenAuthenticator());
|
||||||
|
|
||||||
// setup stubs
|
// setup stubs
|
||||||
|
|
@ -533,6 +430,8 @@ etcd::SyncClient::SyncClient(std::string const& address, std::string const& ca,
|
||||||
std::string const& target_name_override,
|
std::string const& target_name_override,
|
||||||
grpc::ChannelArguments const& arguments) {
|
grpc::ChannelArguments const& arguments) {
|
||||||
// create channels
|
// create channels
|
||||||
|
std::string const addresses =
|
||||||
|
etcd::detail::strip_and_resolve_addresses(address);
|
||||||
grpc::ChannelArguments grpc_args = arguments;
|
grpc::ChannelArguments grpc_args = arguments;
|
||||||
grpc_args.SetMaxSendMessageSize(std::numeric_limits<int>::max());
|
grpc_args.SetMaxSendMessageSize(std::numeric_limits<int>::max());
|
||||||
grpc_args.SetMaxReceiveMessageSize(std::numeric_limits<int>::max());
|
grpc_args.SetMaxReceiveMessageSize(std::numeric_limits<int>::max());
|
||||||
|
|
@ -542,7 +441,7 @@ etcd::SyncClient::SyncClient(std::string const& address, std::string const& ca,
|
||||||
grpc_args.SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
|
grpc_args.SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
|
||||||
target_name_override);
|
target_name_override);
|
||||||
}
|
}
|
||||||
this->channel = etcd::detail::create_grpc_channel(address, creds, grpc_args);
|
this->channel = grpc::CreateCustomChannel(addresses, creds, grpc_args);
|
||||||
this->token_authenticator.reset(new TokenAuthenticator());
|
this->token_authenticator.reset(new TokenAuthenticator());
|
||||||
|
|
||||||
// setup stubs
|
// setup stubs
|
||||||
|
|
@ -575,6 +474,18 @@ etcd::SyncClient::~SyncClient() {
|
||||||
channel.reset();
|
channel.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note [lease with TTL and issue the actual request]
|
||||||
|
*
|
||||||
|
* We sometime use the request like `set(key, value, TTL)`, we explain the TTL
|
||||||
|
* as the time between the user call the `set()` method between the request is
|
||||||
|
* actually executed in etcd server. Thus, we issue a lease request with that
|
||||||
|
* TTL value immediately, and pass it to the `set_internal()` method, the later
|
||||||
|
* may be issues asynchronously.
|
||||||
|
*
|
||||||
|
* Thus the TTL could keep the expected semantic even in the async runtime.
|
||||||
|
*/
|
||||||
|
|
||||||
etcd::Response etcd::SyncClient::head() {
|
etcd::Response etcd::SyncClient::head() {
|
||||||
return Response::create(this->head_internal());
|
return Response::create(this->head_internal());
|
||||||
}
|
}
|
||||||
|
|
@ -591,8 +502,7 @@ etcd::Response etcd::SyncClient::get(std::string const& key) {
|
||||||
return Response::create(this->get_internal(key));
|
return Response::create(this->get_internal(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
etcd::Response etcd::SyncClient::get(std::string const& key,
|
etcd::Response etcd::SyncClient::get(std::string const& key, int64_t revision) {
|
||||||
const int64_t revision) {
|
|
||||||
return Response::create(this->get_internal(key, revision));
|
return Response::create(this->get_internal(key, revision));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -608,20 +518,62 @@ std::shared_ptr<etcdv3::AsyncRangeAction> etcd::SyncClient::get_internal(
|
||||||
return std::make_shared<etcdv3::AsyncRangeAction>(std::move(params));
|
return std::make_shared<etcdv3::AsyncRangeAction>(std::move(params));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
etcd::Response etcd::SyncClient::set(std::string const& key,
|
||||||
|
std::string const& value, int ttl) {
|
||||||
|
// See Note [lease with TTL and issue the actual request]
|
||||||
|
int64_t leaseId = 0;
|
||||||
|
if (ttl > 0) {
|
||||||
|
auto res = this->leasegrant(ttl);
|
||||||
|
if (!res.is_ok()) {
|
||||||
|
return etcd::Response(res.error_code(), res.error_message());
|
||||||
|
} else {
|
||||||
|
leaseId = res.value().lease();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Response::create(this->set_internal(key, value, leaseId));
|
||||||
|
}
|
||||||
|
|
||||||
etcd::Response etcd::SyncClient::set(std::string const& key,
|
etcd::Response etcd::SyncClient::set(std::string const& key,
|
||||||
std::string const& value,
|
std::string const& value,
|
||||||
const int64_t leaseid) {
|
int64_t leaseid) {
|
||||||
return Response::create(this->put_internal(key, value, leaseid));
|
return Response::create(this->set_internal(key, value, leaseid));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<etcdv3::AsyncSetAction> etcd::SyncClient::set_internal(
|
||||||
|
std::string const& key, std::string const& value, int64_t leaseid) {
|
||||||
|
etcdv3::ActionParameters params;
|
||||||
|
params.key.assign(key);
|
||||||
|
params.value.assign(value);
|
||||||
|
params.lease_id = leaseid;
|
||||||
|
params.auth_token.assign(this->token_authenticator->renew_if_expired());
|
||||||
|
params.grpc_timeout = this->grpc_timeout;
|
||||||
|
params.kv_stub = stubs->kvServiceStub.get();
|
||||||
|
return std::make_shared<etcdv3::AsyncSetAction>(std::move(params), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
etcd::Response etcd::SyncClient::add(std::string const& key,
|
||||||
|
std::string const& value, int ttl) {
|
||||||
|
// See Note [lease with TTL and issue the actual request]
|
||||||
|
int64_t leaseId = 0;
|
||||||
|
if (ttl > 0) {
|
||||||
|
auto res = this->leasegrant(ttl);
|
||||||
|
if (!res.is_ok()) {
|
||||||
|
return etcd::Response(res.error_code(), res.error_message());
|
||||||
|
} else {
|
||||||
|
leaseId = res.value().lease();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Response::create(this->add_internal(key, value, leaseId));
|
||||||
}
|
}
|
||||||
|
|
||||||
etcd::Response etcd::SyncClient::add(std::string const& key,
|
etcd::Response etcd::SyncClient::add(std::string const& key,
|
||||||
std::string const& value,
|
std::string const& value,
|
||||||
const int64_t leaseid) {
|
int64_t leaseid) {
|
||||||
return Response::create(this->add_internal(key, value, leaseid));
|
return Response::create(this->add_internal(key, value, leaseid));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<etcdv3::AsyncSetAction> etcd::SyncClient::add_internal(
|
std::shared_ptr<etcdv3::AsyncSetAction> etcd::SyncClient::add_internal(
|
||||||
std::string const& key, std::string const& value, const int64_t leaseid) {
|
std::string const& key, std::string const& value, int64_t leaseid) {
|
||||||
etcdv3::ActionParameters params;
|
etcdv3::ActionParameters params;
|
||||||
params.key.assign(key);
|
params.key.assign(key);
|
||||||
params.value.assign(value);
|
params.value.assign(value);
|
||||||
|
|
@ -637,32 +589,40 @@ etcd::Response etcd::SyncClient::put(std::string const& key,
|
||||||
return Response::create(this->put_internal(key, value));
|
return Response::create(this->put_internal(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
etcd::Response etcd::SyncClient::put(std::string const& key,
|
|
||||||
std::string const& value,
|
|
||||||
const int64_t leaseId) {
|
|
||||||
return Response::create(this->put_internal(key, value, leaseId));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<etcdv3::AsyncPutAction> etcd::SyncClient::put_internal(
|
std::shared_ptr<etcdv3::AsyncPutAction> etcd::SyncClient::put_internal(
|
||||||
std::string const& key, std::string const& value, const int64_t leaseId) {
|
std::string const& key, std::string const& value) {
|
||||||
etcdv3::ActionParameters params;
|
etcdv3::ActionParameters params;
|
||||||
params.key.assign(key);
|
params.key.assign(key);
|
||||||
params.value.assign(value);
|
params.value.assign(value);
|
||||||
params.lease_id = leaseId;
|
|
||||||
params.auth_token.assign(this->token_authenticator->renew_if_expired());
|
params.auth_token.assign(this->token_authenticator->renew_if_expired());
|
||||||
params.grpc_timeout = this->grpc_timeout;
|
params.grpc_timeout = this->grpc_timeout;
|
||||||
params.kv_stub = stubs->kvServiceStub.get();
|
params.kv_stub = stubs->kvServiceStub.get();
|
||||||
return std::make_shared<etcdv3::AsyncPutAction>(std::move(params));
|
return std::make_shared<etcdv3::AsyncPutAction>(std::move(params));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
etcd::Response etcd::SyncClient::modify(std::string const& key,
|
||||||
|
std::string const& value, int ttl) {
|
||||||
|
// See Note [lease with TTL and issue the actual request]
|
||||||
|
int64_t leaseId = 0;
|
||||||
|
if (ttl > 0) {
|
||||||
|
auto res = leasegrant(ttl);
|
||||||
|
if (!res.is_ok()) {
|
||||||
|
return etcd::Response(res.error_code(), res.error_message());
|
||||||
|
} else {
|
||||||
|
leaseId = res.value().lease();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Response::create(this->modify_internal(key, value, leaseId));
|
||||||
|
}
|
||||||
|
|
||||||
etcd::Response etcd::SyncClient::modify(std::string const& key,
|
etcd::Response etcd::SyncClient::modify(std::string const& key,
|
||||||
std::string const& value,
|
std::string const& value,
|
||||||
const int64_t leaseid) {
|
int64_t leaseid) {
|
||||||
return Response::create(this->modify_internal(key, value, leaseid));
|
return Response::create(this->modify_internal(key, value, leaseid));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<etcdv3::AsyncUpdateAction> etcd::SyncClient::modify_internal(
|
std::shared_ptr<etcdv3::AsyncUpdateAction> etcd::SyncClient::modify_internal(
|
||||||
std::string const& key, std::string const& value, const int64_t leaseid) {
|
std::string const& key, std::string const& value, int64_t leaseid) {
|
||||||
etcdv3::ActionParameters params;
|
etcdv3::ActionParameters params;
|
||||||
params.key.assign(key);
|
params.key.assign(key);
|
||||||
params.value.assign(value);
|
params.value.assign(value);
|
||||||
|
|
@ -676,23 +636,58 @@ std::shared_ptr<etcdv3::AsyncUpdateAction> etcd::SyncClient::modify_internal(
|
||||||
etcd::Response etcd::SyncClient::modify_if(std::string const& key,
|
etcd::Response etcd::SyncClient::modify_if(std::string const& key,
|
||||||
std::string const& value,
|
std::string const& value,
|
||||||
std::string const& old_value,
|
std::string const& old_value,
|
||||||
const int64_t leaseid) {
|
int ttl) {
|
||||||
|
// See Note [lease with TTL and issue the actual request]
|
||||||
|
int64_t leaseId = 0;
|
||||||
|
if (ttl > 0) {
|
||||||
|
auto res = leasegrant(ttl);
|
||||||
|
if (!res.is_ok()) {
|
||||||
|
return etcd::Response(res.error_code(), res.error_message());
|
||||||
|
} else {
|
||||||
|
leaseId = res.value().lease();
|
||||||
|
}
|
||||||
|
}
|
||||||
return Response::create(this->modify_if_internal(
|
return Response::create(this->modify_if_internal(
|
||||||
key, value, 0, old_value, etcdv3::AtomicityType::PREV_VALUE, leaseid));
|
key, value, 0, old_value, leaseId, etcdv3::AtomicityType::PREV_VALUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
etcd::Response etcd::SyncClient::modify_if(std::string const& key,
|
||||||
|
std::string const& value,
|
||||||
|
std::string const& old_value,
|
||||||
|
int64_t leaseid) {
|
||||||
|
return Response::create(this->modify_if_internal(
|
||||||
|
key, value, 0, old_value, leaseid, etcdv3::AtomicityType::PREV_VALUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
etcd::Response etcd::SyncClient::modify_if(std::string const& key,
|
||||||
|
std::string const& value,
|
||||||
|
int64_t old_index, int ttl) {
|
||||||
|
// See Note [lease with TTL and issue the actual request]
|
||||||
|
int64_t leaseId = 0;
|
||||||
|
if (ttl > 0) {
|
||||||
|
auto res = leasegrant(ttl);
|
||||||
|
if (!res.is_ok()) {
|
||||||
|
return etcd::Response(res.error_code(), res.error_message());
|
||||||
|
} else {
|
||||||
|
leaseId = res.value().lease();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Response::create(this->modify_if_internal(
|
||||||
|
key, value, old_index, "", leaseId, etcdv3::AtomicityType::PREV_INDEX));
|
||||||
}
|
}
|
||||||
|
|
||||||
etcd::Response etcd::SyncClient::modify_if(std::string const& key,
|
etcd::Response etcd::SyncClient::modify_if(std::string const& key,
|
||||||
std::string const& value,
|
std::string const& value,
|
||||||
int64_t old_index, int64_t leaseid) {
|
int64_t old_index, int64_t leaseid) {
|
||||||
return Response::create(this->modify_if_internal(
|
return Response::create(this->modify_if_internal(
|
||||||
key, value, old_index, "", etcdv3::AtomicityType::PREV_INDEX, leaseid));
|
key, value, old_index, "", leaseid, etcdv3::AtomicityType::PREV_INDEX));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<etcdv3::AsyncCompareAndSwapAction>
|
std::shared_ptr<etcdv3::AsyncCompareAndSwapAction>
|
||||||
etcd::SyncClient::modify_if_internal(
|
etcd::SyncClient::modify_if_internal(
|
||||||
std::string const& key, std::string const& value, int64_t old_index,
|
std::string const& key, std::string const& value, int64_t old_index,
|
||||||
std::string const& old_value, etcdv3::AtomicityType const& atomicity_type,
|
std::string const& old_value, int64_t leaseId,
|
||||||
const int64_t leaseId) {
|
etcdv3::AtomicityType const& atomicity_type) {
|
||||||
etcdv3::ActionParameters params;
|
etcdv3::ActionParameters params;
|
||||||
params.key.assign(key);
|
params.key.assign(key);
|
||||||
params.value.assign(value);
|
params.value.assign(value);
|
||||||
|
|
@ -1019,60 +1014,6 @@ etcd::SyncClient::leases_internal() {
|
||||||
return std::make_shared<etcdv3::AsyncLeaseLeasesAction>(std::move(params));
|
return std::make_shared<etcdv3::AsyncLeaseLeasesAction>(std::move(params));
|
||||||
}
|
}
|
||||||
|
|
||||||
etcd::Response etcd::SyncClient::add_member(std::string const& peer_urls,
|
|
||||||
bool is_learner) {
|
|
||||||
return Response::create(this->add_member_internal(peer_urls, is_learner));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<etcdv3::AsyncAddMemberAction>
|
|
||||||
etcd::SyncClient::add_member_internal(std::string const& peer_urls,
|
|
||||||
bool is_learner) {
|
|
||||||
etcdv3::ActionParameters params;
|
|
||||||
params.auth_token.assign(this->token_authenticator->renew_if_expired());
|
|
||||||
params.grpc_timeout = this->grpc_timeout;
|
|
||||||
params.cluster_stub = stubs->clusterServiceStub.get();
|
|
||||||
|
|
||||||
std::vector<std::string> peer_urls_vector;
|
|
||||||
std::istringstream iss(peer_urls);
|
|
||||||
std::string peer_url;
|
|
||||||
while (std::getline(iss, peer_url, ',')) {
|
|
||||||
peer_urls_vector.push_back(peer_url);
|
|
||||||
}
|
|
||||||
|
|
||||||
params.is_learner = is_learner;
|
|
||||||
params.peer_urls = peer_urls_vector;
|
|
||||||
|
|
||||||
return std::make_shared<etcdv3::AsyncAddMemberAction>(std::move(params));
|
|
||||||
}
|
|
||||||
|
|
||||||
etcd::Response etcd::SyncClient::list_member() {
|
|
||||||
return Response::create(this->list_member_internal());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<etcdv3::AsyncListMemberAction>
|
|
||||||
etcd::SyncClient::list_member_internal() {
|
|
||||||
etcdv3::ActionParameters params;
|
|
||||||
params.auth_token.assign(this->token_authenticator->renew_if_expired());
|
|
||||||
params.grpc_timeout = this->grpc_timeout;
|
|
||||||
params.cluster_stub = stubs->clusterServiceStub.get();
|
|
||||||
return std::make_shared<etcdv3::AsyncListMemberAction>(std::move(params));
|
|
||||||
}
|
|
||||||
|
|
||||||
etcd::Response etcd::SyncClient::remove_member(const uint64_t member_id) {
|
|
||||||
return Response::create(this->remove_member_internal(member_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<etcdv3::AsyncRemoveMemberAction>
|
|
||||||
etcd::SyncClient::remove_member_internal(const uint64_t member_id) {
|
|
||||||
etcdv3::ActionParameters params;
|
|
||||||
params.auth_token.assign(this->token_authenticator->renew_if_expired());
|
|
||||||
params.grpc_timeout = this->grpc_timeout;
|
|
||||||
params.cluster_stub = stubs->clusterServiceStub.get();
|
|
||||||
params.member_id = member_id;
|
|
||||||
|
|
||||||
return std::make_shared<etcdv3::AsyncRemoveMemberAction>(std::move(params));
|
|
||||||
}
|
|
||||||
|
|
||||||
etcd::Response etcd::SyncClient::lock(std::string const& key) {
|
etcd::Response etcd::SyncClient::lock(std::string const& key) {
|
||||||
// routines in lock usually will be fast, less than 10 seconds.
|
// routines in lock usually will be fast, less than 10 seconds.
|
||||||
//
|
//
|
||||||
|
|
@ -1157,15 +1098,15 @@ std::shared_ptr<etcdv3::AsyncUnlockAction> etcd::SyncClient::unlock_internal(
|
||||||
if (p_keeps_alive != this->keep_alive_for_locks.end()) {
|
if (p_keeps_alive != this->keep_alive_for_locks.end()) {
|
||||||
this->keep_alive_for_locks.erase(p_keeps_alive);
|
this->keep_alive_for_locks.erase(p_keeps_alive);
|
||||||
} else {
|
} else {
|
||||||
#ifndef NDEBUG
|
#if !defined(NDEBUG)
|
||||||
std::cerr << "[warn] keepalive for lease not found" << std::endl;
|
std::cerr << "Keepalive for lease not found" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
lock_lease_id = p_leases->second;
|
lock_lease_id = p_leases->second;
|
||||||
this->leases_for_locks.erase(p_leases);
|
this->leases_for_locks.erase(p_leases);
|
||||||
} else {
|
} else {
|
||||||
#ifndef NDEBUG
|
#if !defined(NDEBUG)
|
||||||
std::cerr << "[warn] lease for lock not found" << std::endl;
|
std::cerr << "Lease for lock not found" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (lock_lease_id != 0) {
|
if (lock_lease_id != 0) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
#include <cstdint>
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
#include "etcd/Value.hpp"
|
#include "etcd/Value.hpp"
|
||||||
|
|
@ -45,19 +44,6 @@ int etcd::Value::ttl() const { return _ttl; }
|
||||||
|
|
||||||
int64_t etcd::Value::lease() const { return leaseId; }
|
int64_t etcd::Value::lease() const { return leaseId; }
|
||||||
|
|
||||||
std::ostream& etcd::operator<<(std::ostream& os, const etcd::Value& value) {
|
|
||||||
os << "Event: {";
|
|
||||||
os << "Key: " << value.key() << ", ";
|
|
||||||
os << "Value: " << value.as_string() << ", ";
|
|
||||||
os << "Created: " << value.created_index() << ", ";
|
|
||||||
os << "Modified: " << value.modified_index() << ", ";
|
|
||||||
os << "Version: " << value.version() << ", ";
|
|
||||||
os << "TTL: " << value.ttl() << ", ";
|
|
||||||
os << "Lease: " << value.lease() << ", ";
|
|
||||||
os << "}";
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
||||||
|
|
@ -87,30 +73,3 @@ bool etcd::Event::has_prev_kv() const { return _has_prev_kv; }
|
||||||
const etcd::Value& etcd::Event::kv() const { return _kv; }
|
const etcd::Value& etcd::Event::kv() const { return _kv; }
|
||||||
|
|
||||||
const etcd::Value& etcd::Event::prev_kv() const { return _prev_kv; }
|
const etcd::Value& etcd::Event::prev_kv() const { return _prev_kv; }
|
||||||
|
|
||||||
std::ostream& etcd::operator<<(std::ostream& os,
|
|
||||||
const etcd::Event::EventType& value) {
|
|
||||||
switch (value) {
|
|
||||||
case etcd::Event::EventType::PUT:
|
|
||||||
os << "PUT";
|
|
||||||
break;
|
|
||||||
case etcd::Event::EventType::DELETE_:
|
|
||||||
os << "DELETE";
|
|
||||||
break;
|
|
||||||
case etcd::Event::EventType::INVALID:
|
|
||||||
os << "INVALID";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& etcd::operator<<(std::ostream& os, const etcd::Event& event) {
|
|
||||||
os << "Event type: " << event.event_type();
|
|
||||||
if (event.has_kv()) {
|
|
||||||
os << ", KV: " << event.kv();
|
|
||||||
}
|
|
||||||
if (event.has_prev_kv()) {
|
|
||||||
os << ", Prev KV: " << event.prev_kv();
|
|
||||||
}
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -229,18 +229,13 @@ bool etcd::Watcher::Wait() {
|
||||||
return stubs->call->Cancelled();
|
return stubs->call->Cancelled();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool 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;
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
#ifndef NDEBUG
|
std::cerr << "Failed to set a asynchronous wait callback since it has "
|
||||||
std::cerr
|
|
||||||
<< "[warn] failed to set a asynchronous wait callback since it has "
|
|
||||||
"already been set"
|
"already been set"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
#endif
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,6 @@
|
||||||
#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 <cstdlib>
|
|
||||||
|
|
||||||
#ifndef GPR_ASSERT
|
|
||||||
#define GPR_ASSERT(x) \
|
|
||||||
if (!(x)) { \
|
|
||||||
fprintf(stderr, "%s:%d assert failed\n", __FILE__, __LINE__); \
|
|
||||||
abort(); \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
etcdv3::Action::Action(etcdv3::ActionParameters const& params) {
|
etcdv3::Action::Action(etcdv3::ActionParameters const& params) {
|
||||||
parameters = params;
|
parameters = params;
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,9 @@ void etcdv3::AsyncCampaignResponse::ParseResponse(CampaignResponse& reply) {
|
||||||
value.kvs.set_lease(leader.lease());
|
value.kvs.set_lease(leader.lease());
|
||||||
}
|
}
|
||||||
|
|
||||||
void etcdv3::AsyncDeleteResponse::ParseResponse(DeleteRangeResponse& resp) {
|
void etcdv3::AsyncDeleteResponse::ParseResponse(std::string const& key,
|
||||||
|
bool prefix,
|
||||||
|
DeleteRangeResponse& resp) {
|
||||||
index = resp.header().revision();
|
index = resp.header().revision();
|
||||||
|
|
||||||
if (resp.prev_kvs_size() == 0) {
|
if (resp.prev_kvs_size() == 0) {
|
||||||
|
|
@ -55,15 +57,13 @@ void etcdv3::AsyncDeleteResponse::ParseResponse(DeleteRangeResponse& resp) {
|
||||||
etcdv3::KeyValue kv;
|
etcdv3::KeyValue kv;
|
||||||
kv.kvs.CopyFrom(resp.prev_kvs(cnt));
|
kv.kvs.CopyFrom(resp.prev_kvs(cnt));
|
||||||
values.push_back(kv);
|
values.push_back(kv);
|
||||||
prev_values.push_back(kv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// flatten values/prev_values 0 to value/prev_value
|
if (!prefix) {
|
||||||
if (!values.empty()) {
|
prev_value = values[0];
|
||||||
value = values[0];
|
value = values[0];
|
||||||
}
|
value.kvs.clear_value();
|
||||||
if (!prev_values.empty()) {
|
values.clear();
|
||||||
prev_value = prev_values[0];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -95,43 +95,6 @@ void etcdv3::AsyncLeaseKeepAliveResponse::ParseResponse(
|
||||||
value.set_ttl(resp.ttl());
|
value.set_ttl(resp.ttl());
|
||||||
}
|
}
|
||||||
|
|
||||||
void etcdv3::AsyncMemberAddResponse::ParseResponse(MemberAddResponse& resp) {
|
|
||||||
index = resp.header().revision();
|
|
||||||
std::string member_type = "Member";
|
|
||||||
if (resp.member().islearner()) {
|
|
||||||
member_type = "Learner";
|
|
||||||
}
|
|
||||||
std::cout << "Member (" << resp.member().id() << ")"
|
|
||||||
<< " Added to the etcd cluster as " << member_type << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::AsyncMemberListResponse::ParseResponse(MemberListResponse& resp) {
|
|
||||||
index = resp.header().revision();
|
|
||||||
for (auto member : resp.members()) {
|
|
||||||
etcdv3::Member m;
|
|
||||||
m.set_id(member.id());
|
|
||||||
m.set_name(member.name());
|
|
||||||
|
|
||||||
std::vector<std::string> clientUrlsVec, peerUrlsVec;
|
|
||||||
for (const auto& clientUrl : member.clienturls()) {
|
|
||||||
clientUrlsVec.push_back(clientUrl);
|
|
||||||
}
|
|
||||||
for (const auto& peerUrl : member.peerurls()) {
|
|
||||||
peerUrlsVec.push_back(peerUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
m.set_clientURLs(clientUrlsVec);
|
|
||||||
m.set_peerURLs(peerUrlsVec);
|
|
||||||
|
|
||||||
members.push_back(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::AsyncMemberRemoveResponse::ParseResponse(
|
|
||||||
MemberRemoveResponse& resp) {
|
|
||||||
index = resp.header().revision();
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::AsyncLeaseLeasesResponse::ParseResponse(
|
void etcdv3::AsyncLeaseLeasesResponse::ParseResponse(
|
||||||
LeaseLeasesResponse& resp) {
|
LeaseLeasesResponse& resp) {
|
||||||
index = resp.header().revision();
|
index = resp.header().revision();
|
||||||
|
|
@ -174,7 +137,6 @@ void etcdv3::AsyncPutResponse::ParseResponse(PutResponse& resp) {
|
||||||
// get all previous values
|
// get all previous values
|
||||||
etcdv3::KeyValue kv;
|
etcdv3::KeyValue kv;
|
||||||
kv.kvs.CopyFrom(resp.prev_kv());
|
kv.kvs.CopyFrom(resp.prev_kv());
|
||||||
prev_values.push_back(kv);
|
|
||||||
prev_value = kv;
|
prev_value = kv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,99 +167,38 @@ void etcdv3::AsyncResignResponse::ParseResponse(ResignResponse& reply) {
|
||||||
|
|
||||||
void etcdv3::AsyncTxnResponse::ParseResponse(TxnResponse& reply) {
|
void etcdv3::AsyncTxnResponse::ParseResponse(TxnResponse& reply) {
|
||||||
index = reply.header().revision();
|
index = reply.header().revision();
|
||||||
|
}
|
||||||
|
|
||||||
|
void etcdv3::AsyncTxnResponse::ParseResponse(std::string const& key,
|
||||||
|
bool prefix, TxnResponse& reply) {
|
||||||
|
index = reply.header().revision();
|
||||||
for (int index = 0; index < reply.responses_size(); index++) {
|
for (int index = 0; index < reply.responses_size(); index++) {
|
||||||
auto resp = reply.responses(index);
|
auto resp = reply.responses(index);
|
||||||
if (ResponseOp::ResponseCase::kResponseRange == resp.response_case()) {
|
if (ResponseOp::ResponseCase::kResponseRange == resp.response_case()) {
|
||||||
AsyncRangeResponse response;
|
AsyncRangeResponse response;
|
||||||
response.ParseResponse(*(resp.mutable_response_range()), true);
|
response.ParseResponse(*(resp.mutable_response_range()), prefix);
|
||||||
|
|
||||||
if (error_code == 0) {
|
|
||||||
error_code = response.get_error_code();
|
error_code = response.get_error_code();
|
||||||
}
|
error_message = response.get_error_message();
|
||||||
if (!response.get_error_message().empty()) {
|
|
||||||
if (!error_message.empty()) {
|
values = response.get_values();
|
||||||
error_message += "\n";
|
value = response.get_value();
|
||||||
}
|
|
||||||
error_message += response.get_error_message();
|
|
||||||
}
|
|
||||||
for (auto const& value : response.get_values()) {
|
|
||||||
values.emplace_back(value);
|
|
||||||
}
|
|
||||||
for (auto const& prev_value : response.get_prev_values()) {
|
|
||||||
prev_values.emplace_back(prev_value);
|
|
||||||
}
|
|
||||||
} else if (ResponseOp::ResponseCase::kResponsePut == resp.response_case()) {
|
} else if (ResponseOp::ResponseCase::kResponsePut == resp.response_case()) {
|
||||||
AsyncPutResponse response;
|
auto put_resp = resp.response_put();
|
||||||
response.ParseResponse(*(resp.mutable_response_put()));
|
if (put_resp.has_prev_kv()) {
|
||||||
if (error_code == 0) {
|
prev_value.kvs.CopyFrom(put_resp.prev_kv());
|
||||||
error_code = response.get_error_code();
|
|
||||||
}
|
|
||||||
if (!response.get_error_message().empty()) {
|
|
||||||
if (!error_message.empty()) {
|
|
||||||
error_message += "\n";
|
|
||||||
}
|
|
||||||
error_message += response.get_error_message();
|
|
||||||
}
|
|
||||||
for (auto const& value : response.get_values()) {
|
|
||||||
values.emplace_back(value);
|
|
||||||
}
|
|
||||||
for (auto const& prev_value : response.get_prev_values()) {
|
|
||||||
prev_values.emplace_back(prev_value);
|
|
||||||
}
|
}
|
||||||
} else if (ResponseOp::ResponseCase::kResponseDeleteRange ==
|
} else if (ResponseOp::ResponseCase::kResponseDeleteRange ==
|
||||||
resp.response_case()) {
|
resp.response_case()) {
|
||||||
AsyncDeleteResponse response;
|
AsyncDeleteResponse response;
|
||||||
response.ParseResponse(*(resp.mutable_response_delete_range()));
|
response.ParseResponse(key, prefix,
|
||||||
|
*(resp.mutable_response_delete_range()));
|
||||||
|
|
||||||
// Ignore "key not found" error for delete in txn, keep backwards
|
prev_value.kvs.CopyFrom(response.get_prev_value().kvs);
|
||||||
// compatibility.
|
|
||||||
if (response.get_error_code() != 0 &&
|
|
||||||
response.get_error_code() != etcdv3::ERROR_KEY_NOT_FOUND) {
|
|
||||||
error_code = response.get_error_code();
|
|
||||||
}
|
|
||||||
if (!response.get_error_message().empty()) {
|
|
||||||
if (response.get_error_code() != 0 &&
|
|
||||||
response.get_error_code() != etcdv3::ERROR_KEY_NOT_FOUND) {
|
|
||||||
if (!error_message.empty()) {
|
|
||||||
error_message += "\n";
|
|
||||||
}
|
|
||||||
error_message += response.get_error_message();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto const& value : response.get_values()) {
|
|
||||||
values.emplace_back(value);
|
|
||||||
}
|
|
||||||
for (auto const& prev_value : response.get_prev_values()) {
|
|
||||||
prev_values.emplace_back(prev_value);
|
|
||||||
}
|
|
||||||
} else if (ResponseOp::ResponseCase::kResponseTxn == resp.response_case()) {
|
|
||||||
AsyncTxnResponse response;
|
|
||||||
response.ParseResponse(*(resp.mutable_response_txn()));
|
|
||||||
|
|
||||||
if (error_code == 0) {
|
values = response.get_values();
|
||||||
error_code = response.get_error_code();
|
value = response.get_value();
|
||||||
}
|
}
|
||||||
if (!response.get_error_message().empty()) {
|
|
||||||
if (!error_message.empty()) {
|
|
||||||
error_message += "\n";
|
|
||||||
}
|
|
||||||
error_message += response.get_error_message();
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip
|
|
||||||
#ifndef NDEBUG
|
|
||||||
std::cerr << "[debug] not implemented error: unable to parse nested "
|
|
||||||
"transaction "
|
|
||||||
"response"
|
|
||||||
<< std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!values.empty()) {
|
|
||||||
value = values[0];
|
|
||||||
}
|
|
||||||
if (!prev_values.empty()) {
|
|
||||||
prev_value = prev_values[0];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -369,17 +270,20 @@ etcdv3::AsyncCampaignResponse etcdv3::AsyncCampaignAction::ParseResponse() {
|
||||||
etcdv3::AsyncCompareAndDeleteAction::AsyncCompareAndDeleteAction(
|
etcdv3::AsyncCompareAndDeleteAction::AsyncCompareAndDeleteAction(
|
||||||
etcdv3::ActionParameters&& params, etcdv3::AtomicityType type)
|
etcdv3::ActionParameters&& params, etcdv3::AtomicityType type)
|
||||||
: etcdv3::Action(std::move(params)) {
|
: etcdv3::Action(std::move(params)) {
|
||||||
etcdv3::Transaction txn;
|
etcdv3::Transaction transaction(parameters.key);
|
||||||
if (type == etcdv3::AtomicityType::PREV_VALUE) {
|
if (type == etcdv3::AtomicityType::PREV_VALUE) {
|
||||||
txn.setup_compare_and_delete(parameters.key, parameters.old_value,
|
transaction.init_compare(parameters.old_value, CompareResult::EQUAL,
|
||||||
parameters.key);
|
CompareTarget::VALUE);
|
||||||
} else if (type == etcdv3::AtomicityType::PREV_INDEX) {
|
} else if (type == etcdv3::AtomicityType::PREV_INDEX) {
|
||||||
txn.setup_compare_and_delete(parameters.key, parameters.old_revision,
|
transaction.init_compare(parameters.old_revision, CompareResult::EQUAL,
|
||||||
parameters.key);
|
CompareTarget::MOD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transaction.setup_compare_and_delete_operation(parameters.key);
|
||||||
|
transaction.setup_basic_failure_operation(parameters.key);
|
||||||
|
|
||||||
response_reader =
|
response_reader =
|
||||||
parameters.kv_stub->AsyncTxn(&context, *txn.txn_request, &cq_);
|
parameters.kv_stub->AsyncTxn(&context, *transaction.txn_request, &cq_);
|
||||||
response_reader->Finish(&reply, &status, (void*) this);
|
response_reader->Finish(&reply, &status, (void*) this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -391,32 +295,35 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncCompareAndDeleteAction::ParseResponse() {
|
||||||
txn_resp.set_error_code(status.error_code());
|
txn_resp.set_error_code(status.error_code());
|
||||||
txn_resp.set_error_message(status.error_message());
|
txn_resp.set_error_message(status.error_message());
|
||||||
} else {
|
} else {
|
||||||
txn_resp.ParseResponse(reply);
|
txn_resp.ParseResponse(parameters.key, parameters.withPrefix, reply);
|
||||||
|
|
||||||
if (!reply.succeeded()) {
|
if (!reply.succeeded()) {
|
||||||
txn_resp.set_error_code(ERROR_COMPARE_FAILED);
|
txn_resp.set_error_code(ERROR_COMPARE_FAILED);
|
||||||
txn_resp.set_error_message("etcd-cpp-apiv3: compare failed");
|
txn_resp.set_error_message("etcd-cpp-apiv3: compare failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return txn_resp;
|
return txn_resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
etcdv3::AsyncCompareAndSwapAction::AsyncCompareAndSwapAction(
|
etcdv3::AsyncCompareAndSwapAction::AsyncCompareAndSwapAction(
|
||||||
etcdv3::ActionParameters&& params, etcdv3::AtomicityType type)
|
etcdv3::ActionParameters&& params, etcdv3::AtomicityType type)
|
||||||
: etcdv3::Action(std::move(params)) {
|
: etcdv3::Action(std::move(params)) {
|
||||||
etcdv3::Transaction txn;
|
etcdv3::Transaction transaction(parameters.key);
|
||||||
if (type == etcdv3::AtomicityType::PREV_VALUE) {
|
if (type == etcdv3::AtomicityType::PREV_VALUE) {
|
||||||
txn.setup_compare_and_swap(parameters.key, parameters.old_value,
|
transaction.init_compare(parameters.old_value, CompareResult::EQUAL,
|
||||||
parameters.value, parameters.lease_id);
|
CompareTarget::VALUE);
|
||||||
} else if (type == etcdv3::AtomicityType::PREV_INDEX) {
|
} else if (type == etcdv3::AtomicityType::PREV_INDEX) {
|
||||||
txn.setup_compare_and_swap(parameters.key, parameters.old_revision,
|
transaction.init_compare(parameters.old_revision, CompareResult::EQUAL,
|
||||||
parameters.value, parameters.lease_id);
|
CompareTarget::MOD);
|
||||||
}
|
}
|
||||||
// backwards compatibility
|
|
||||||
txn.add_success_range(parameters.key);
|
transaction.setup_basic_failure_operation(parameters.key);
|
||||||
|
transaction.setup_compare_and_swap_sequence(parameters.value,
|
||||||
|
parameters.lease_id);
|
||||||
|
|
||||||
response_reader =
|
response_reader =
|
||||||
parameters.kv_stub->AsyncTxn(&context, *txn.txn_request, &cq_);
|
parameters.kv_stub->AsyncTxn(&context, *transaction.txn_request, &cq_);
|
||||||
response_reader->Finish(&reply, &status, (void*) this);
|
response_reader->Finish(&reply, &status, (void*) this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -428,7 +335,7 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncCompareAndSwapAction::ParseResponse() {
|
||||||
txn_resp.set_error_code(status.error_code());
|
txn_resp.set_error_code(status.error_code());
|
||||||
txn_resp.set_error_message(status.error_message());
|
txn_resp.set_error_message(status.error_message());
|
||||||
} else {
|
} else {
|
||||||
txn_resp.ParseResponse(reply);
|
txn_resp.ParseResponse(parameters.key, parameters.withPrefix, reply);
|
||||||
|
|
||||||
// if there is an error code returned by parseResponse, we must
|
// if there is an error code returned by parseResponse, we must
|
||||||
// not overwrite it.
|
// not overwrite it.
|
||||||
|
|
@ -437,15 +344,30 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncCompareAndSwapAction::ParseResponse() {
|
||||||
txn_resp.set_error_message("etcd-cpp-apiv3: compare failed");
|
txn_resp.set_error_message("etcd-cpp-apiv3: compare failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return txn_resp;
|
return txn_resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
etcdv3::AsyncDeleteAction::AsyncDeleteAction(ActionParameters&& params)
|
etcdv3::AsyncDeleteAction::AsyncDeleteAction(ActionParameters&& params)
|
||||||
: etcdv3::Action(std::move(params)) {
|
: etcdv3::Action(std::move(params)) {
|
||||||
DeleteRangeRequest del_request;
|
DeleteRangeRequest del_request;
|
||||||
detail::make_request_with_ranges(del_request, parameters.key,
|
if (!parameters.withPrefix) {
|
||||||
parameters.range_end, parameters.withPrefix);
|
del_request.set_key(parameters.key);
|
||||||
del_request.set_prev_kv(true /* fetch prev values */);
|
} else {
|
||||||
|
if (parameters.key.empty()) {
|
||||||
|
// see: WithFromKey in etcdv3/client
|
||||||
|
del_request.set_key(etcdv3::NUL);
|
||||||
|
del_request.set_range_end(etcdv3::NUL);
|
||||||
|
} else {
|
||||||
|
del_request.set_key(parameters.key);
|
||||||
|
del_request.set_range_end(detail::string_plus_one(parameters.key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!parameters.range_end.empty()) {
|
||||||
|
del_request.set_range_end(parameters.range_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
del_request.set_prev_kv(true);
|
||||||
|
|
||||||
response_reader =
|
response_reader =
|
||||||
parameters.kv_stub->AsyncDeleteRange(&context, del_request, &cq_);
|
parameters.kv_stub->AsyncDeleteRange(&context, del_request, &cq_);
|
||||||
|
|
@ -460,8 +382,11 @@ etcdv3::AsyncDeleteResponse etcdv3::AsyncDeleteAction::ParseResponse() {
|
||||||
del_resp.set_error_code(status.error_code());
|
del_resp.set_error_code(status.error_code());
|
||||||
del_resp.set_error_message(status.error_message());
|
del_resp.set_error_message(status.error_message());
|
||||||
} else {
|
} else {
|
||||||
del_resp.ParseResponse(reply);
|
del_resp.ParseResponse(
|
||||||
|
parameters.key, parameters.withPrefix || !parameters.range_end.empty(),
|
||||||
|
reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
return del_resp;
|
return del_resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -549,10 +474,7 @@ etcdv3::AsyncLeaseKeepAliveAction::AsyncLeaseKeepAliveAction(
|
||||||
got_tag == (void*) etcdv3::KEEPALIVE_CREATE) {
|
got_tag == (void*) etcdv3::KEEPALIVE_CREATE) {
|
||||||
// ok
|
// ok
|
||||||
} else {
|
} else {
|
||||||
status = grpc::Status(grpc::StatusCode::CANCELLED,
|
throw std::runtime_error("Failed to create a lease keep-alive connection");
|
||||||
"Failed to create a lease keep-alive connection");
|
|
||||||
// cannot continue for further refresh
|
|
||||||
isCancelled.store(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -574,7 +496,7 @@ etcd::Response etcdv3::AsyncLeaseKeepAliveAction::Refresh() {
|
||||||
std::lock_guard<std::recursive_mutex> scope_lock(this->protect_is_cancelled);
|
std::lock_guard<std::recursive_mutex> scope_lock(this->protect_is_cancelled);
|
||||||
|
|
||||||
auto start_timepoint = std::chrono::high_resolution_clock::now();
|
auto start_timepoint = std::chrono::high_resolution_clock::now();
|
||||||
if (isCancelled.load()) {
|
if (isCancelled) {
|
||||||
status = grpc::Status::CANCELLED;
|
status = grpc::Status::CANCELLED;
|
||||||
return etcd::Response(ParseResponse(),
|
return etcd::Response(ParseResponse(),
|
||||||
etcd::detail::duration_till_now(start_timepoint));
|
etcd::detail::duration_till_now(start_timepoint));
|
||||||
|
|
@ -661,7 +583,9 @@ etcd::Response etcdv3::AsyncLeaseKeepAliveAction::Refresh() {
|
||||||
|
|
||||||
void etcdv3::AsyncLeaseKeepAliveAction::CancelKeepAlive() {
|
void etcdv3::AsyncLeaseKeepAliveAction::CancelKeepAlive() {
|
||||||
std::lock_guard<std::recursive_mutex> scope_lock(this->protect_is_cancelled);
|
std::lock_guard<std::recursive_mutex> scope_lock(this->protect_is_cancelled);
|
||||||
if (!isCancelled.exchange(true)) {
|
if (isCancelled == false) {
|
||||||
|
isCancelled = true;
|
||||||
|
|
||||||
void* got_tag = nullptr;
|
void* got_tag = nullptr;
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
|
||||||
|
|
@ -670,22 +594,17 @@ void etcdv3::AsyncLeaseKeepAliveAction::CancelKeepAlive() {
|
||||||
got_tag == (void*) etcdv3::KEEPALIVE_DONE) {
|
got_tag == (void*) etcdv3::KEEPALIVE_DONE) {
|
||||||
// ok
|
// ok
|
||||||
} else {
|
} else {
|
||||||
#ifndef NDEBUG
|
std::cerr << "Failed to mark a lease keep-alive connection as DONE: "
|
||||||
std::cerr
|
|
||||||
<< "[debug] failed to mark a lease keep-alive connection as DONE: "
|
|
||||||
<< context.debug_error_string() << std::endl;
|
<< context.debug_error_string() << std::endl;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stream->Finish(&status, (void*) KEEPALIVE_FINISH);
|
stream->Finish(&status, (void*) KEEPALIVE_FINISH);
|
||||||
if (cq_.Next(&got_tag, &ok) && ok && got_tag == (void*) KEEPALIVE_FINISH) {
|
if (cq_.Next(&got_tag, &ok) && ok && got_tag == (void*) KEEPALIVE_FINISH) {
|
||||||
// ok
|
// ok
|
||||||
} else {
|
} else {
|
||||||
#ifndef NDEBUG
|
std::cerr << "Failed to finish a lease keep-alive connection: "
|
||||||
std::cerr << "[debug] failed to finish a lease keep-alive connection: "
|
|
||||||
<< status.error_message() << ", "
|
<< status.error_message() << ", "
|
||||||
<< context.debug_error_string() << std::endl;
|
<< context.debug_error_string() << std::endl;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cancel on-the-fly calls
|
// cancel on-the-fly calls
|
||||||
|
|
@ -696,7 +615,7 @@ void etcdv3::AsyncLeaseKeepAliveAction::CancelKeepAlive() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool etcdv3::AsyncLeaseKeepAliveAction::Cancelled() const {
|
bool etcdv3::AsyncLeaseKeepAliveAction::Cancelled() const {
|
||||||
return isCancelled.load();
|
return isCancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
etcdv3::ActionParameters&
|
etcdv3::ActionParameters&
|
||||||
|
|
@ -704,81 +623,6 @@ etcdv3::AsyncLeaseKeepAliveAction::mutable_parameters() {
|
||||||
return this->parameters;
|
return this->parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
etcdv3::AsyncAddMemberAction::AsyncAddMemberAction(
|
|
||||||
etcdv3::ActionParameters&& params)
|
|
||||||
: etcdv3::Action(std::move(params)) {
|
|
||||||
MemberAddRequest add_member_request;
|
|
||||||
|
|
||||||
for (const auto& url : parameters.peer_urls) {
|
|
||||||
add_member_request.add_peerurls(url);
|
|
||||||
}
|
|
||||||
add_member_request.set_islearner(parameters.is_learner);
|
|
||||||
response_reader = parameters.cluster_stub->AsyncMemberAdd(
|
|
||||||
&context, add_member_request, &cq_);
|
|
||||||
response_reader->Finish(&reply, &status, (void*) this);
|
|
||||||
}
|
|
||||||
|
|
||||||
etcdv3::AsyncMemberAddResponse etcdv3::AsyncAddMemberAction::ParseResponse() {
|
|
||||||
AsyncMemberAddResponse add_member_resp;
|
|
||||||
add_member_resp.set_action(etcdv3::ADDMEMBER);
|
|
||||||
|
|
||||||
if (!status.ok()) {
|
|
||||||
add_member_resp.set_error_code(status.error_code());
|
|
||||||
add_member_resp.set_error_message(status.error_message());
|
|
||||||
} else {
|
|
||||||
add_member_resp.ParseResponse(reply);
|
|
||||||
}
|
|
||||||
return add_member_resp;
|
|
||||||
}
|
|
||||||
|
|
||||||
etcdv3::AsyncListMemberAction::AsyncListMemberAction(
|
|
||||||
etcdv3::ActionParameters&& params)
|
|
||||||
: etcdv3::Action(std::move(params)) {
|
|
||||||
MemberListRequest member_list_request;
|
|
||||||
|
|
||||||
response_reader = parameters.cluster_stub->AsyncMemberList(
|
|
||||||
&context, member_list_request, &cq_);
|
|
||||||
response_reader->Finish(&reply, &status, (void*) this);
|
|
||||||
}
|
|
||||||
|
|
||||||
etcdv3::AsyncMemberListResponse etcdv3::AsyncListMemberAction::ParseResponse() {
|
|
||||||
AsyncMemberListResponse list_member_resp;
|
|
||||||
list_member_resp.set_action(etcdv3::LISTMEMBER);
|
|
||||||
|
|
||||||
if (!status.ok()) {
|
|
||||||
list_member_resp.set_error_code(status.error_code());
|
|
||||||
list_member_resp.set_error_message(status.error_message());
|
|
||||||
} else {
|
|
||||||
list_member_resp.ParseResponse(reply);
|
|
||||||
}
|
|
||||||
return list_member_resp;
|
|
||||||
}
|
|
||||||
|
|
||||||
etcdv3::AsyncRemoveMemberAction::AsyncRemoveMemberAction(
|
|
||||||
etcdv3::ActionParameters&& params)
|
|
||||||
: etcdv3::Action(std::move(params)) {
|
|
||||||
MemberRemoveRequest remove_member_request;
|
|
||||||
|
|
||||||
remove_member_request.set_id(parameters.member_id);
|
|
||||||
response_reader = parameters.cluster_stub->AsyncMemberRemove(
|
|
||||||
&context, remove_member_request, &cq_);
|
|
||||||
response_reader->Finish(&reply, &status, (void*) this);
|
|
||||||
}
|
|
||||||
|
|
||||||
etcdv3::AsyncMemberRemoveResponse
|
|
||||||
etcdv3::AsyncRemoveMemberAction::ParseResponse() {
|
|
||||||
AsyncMemberRemoveResponse remove_member_resp;
|
|
||||||
remove_member_resp.set_action(etcdv3::REMOVEMEMBER);
|
|
||||||
|
|
||||||
if (!status.ok()) {
|
|
||||||
remove_member_resp.set_error_code(status.error_code());
|
|
||||||
remove_member_resp.set_error_message(status.error_message());
|
|
||||||
} else {
|
|
||||||
remove_member_resp.ParseResponse(reply);
|
|
||||||
}
|
|
||||||
return remove_member_resp;
|
|
||||||
}
|
|
||||||
|
|
||||||
etcdv3::AsyncLeaseLeasesAction::AsyncLeaseLeasesAction(
|
etcdv3::AsyncLeaseLeasesAction::AsyncLeaseLeasesAction(
|
||||||
etcdv3::ActionParameters&& params)
|
etcdv3::ActionParameters&& params)
|
||||||
: etcdv3::Action(std::move(params)) {
|
: etcdv3::Action(std::move(params)) {
|
||||||
|
|
@ -895,10 +739,7 @@ etcdv3::AsyncObserveAction::AsyncObserveAction(
|
||||||
got_tag == (void*) etcdv3::ELECTION_OBSERVE_CREATE) {
|
got_tag == (void*) etcdv3::ELECTION_OBSERVE_CREATE) {
|
||||||
// n.b.: leave the issue of `Read` to the `waitForResponse`
|
// n.b.: leave the issue of `Read` to the `waitForResponse`
|
||||||
} else {
|
} else {
|
||||||
status = grpc::Status(grpc::StatusCode::CANCELLED,
|
throw std::runtime_error("failed to create a observe connection");
|
||||||
"failed to create a observe connection");
|
|
||||||
// cannot continue for further observing
|
|
||||||
isCancelled.store(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -926,7 +767,7 @@ void etcdv3::AsyncObserveAction::waitForResponse() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void etcdv3::AsyncObserveAction::CancelObserve() {
|
void etcdv3::AsyncObserveAction::CancelObserve() {
|
||||||
std::lock_guard<std::mutex> scope_lock(this->protect_is_cancelled);
|
std::lock_guard<std::mutex> scope_lock(this->protect_is_cancalled);
|
||||||
if (!isCancelled.exchange(true)) {
|
if (!isCancelled.exchange(true)) {
|
||||||
void* got_tag;
|
void* got_tag;
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
|
@ -944,10 +785,8 @@ void etcdv3::AsyncObserveAction::CancelObserve() {
|
||||||
break;
|
break;
|
||||||
case CompletionQueue::NextStatus::GOT_EVENT:
|
case CompletionQueue::NextStatus::GOT_EVENT:
|
||||||
if (!ok || got_tag != (void*) ELECTION_OBSERVE_FINISH) {
|
if (!ok || got_tag != (void*) ELECTION_OBSERVE_FINISH) {
|
||||||
#ifndef NDEBUG
|
std::cerr << "Failed to finish a election observing connection"
|
||||||
std::cerr << "[debug] failed to finish a election observing connection"
|
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1035,8 +874,21 @@ etcdv3::AsyncPutResponse etcdv3::AsyncPutAction::ParseResponse() {
|
||||||
etcdv3::AsyncRangeAction::AsyncRangeAction(etcdv3::ActionParameters&& params)
|
etcdv3::AsyncRangeAction::AsyncRangeAction(etcdv3::ActionParameters&& params)
|
||||||
: etcdv3::Action(std::move(params)) {
|
: etcdv3::Action(std::move(params)) {
|
||||||
RangeRequest get_request;
|
RangeRequest get_request;
|
||||||
detail::make_request_with_ranges(get_request, parameters.key,
|
if (!parameters.withPrefix) {
|
||||||
parameters.range_end, parameters.withPrefix);
|
get_request.set_key(parameters.key);
|
||||||
|
} else {
|
||||||
|
if (parameters.key.empty()) {
|
||||||
|
// see: WithFromKey in etcdv3/client
|
||||||
|
get_request.set_key(etcdv3::NUL);
|
||||||
|
get_request.set_range_end(etcdv3::NUL);
|
||||||
|
} else {
|
||||||
|
get_request.set_key(parameters.key);
|
||||||
|
get_request.set_range_end(detail::string_plus_one(parameters.key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!parameters.range_end.empty()) {
|
||||||
|
get_request.set_range_end(parameters.range_end);
|
||||||
|
}
|
||||||
if (parameters.revision > 0) {
|
if (parameters.revision > 0) {
|
||||||
get_request.set_revision(parameters.revision);
|
get_request.set_revision(parameters.revision);
|
||||||
}
|
}
|
||||||
|
|
@ -1099,19 +951,21 @@ etcdv3::AsyncResignResponse etcdv3::AsyncResignAction::ParseResponse() {
|
||||||
etcdv3::AsyncSetAction::AsyncSetAction(etcdv3::ActionParameters&& params,
|
etcdv3::AsyncSetAction::AsyncSetAction(etcdv3::ActionParameters&& params,
|
||||||
bool create)
|
bool create)
|
||||||
: etcdv3::Action(std::move(params)) {
|
: etcdv3::Action(std::move(params)) {
|
||||||
etcdv3::Transaction txn;
|
etcdv3::Transaction transaction(parameters.key);
|
||||||
isCreate = create;
|
isCreate = create;
|
||||||
txn.add_compare_mod(parameters.key, 0 /* not exists */);
|
transaction.init_compare(CompareResult::EQUAL, CompareTarget::VERSION);
|
||||||
txn.add_success_put(parameters.key, parameters.value, parameters.lease_id);
|
|
||||||
// backwards compatibility
|
transaction.setup_basic_create_sequence(parameters.key, parameters.value,
|
||||||
txn.add_success_range(parameters.key);
|
parameters.lease_id);
|
||||||
if (create) {
|
|
||||||
txn.add_failure_range(parameters.key);
|
if (isCreate) {
|
||||||
|
transaction.setup_basic_failure_operation(parameters.key);
|
||||||
} else {
|
} else {
|
||||||
txn.add_failure_put(parameters.key, parameters.value, parameters.lease_id);
|
transaction.setup_set_failure_operation(parameters.key, parameters.value,
|
||||||
|
parameters.lease_id);
|
||||||
}
|
}
|
||||||
response_reader =
|
response_reader =
|
||||||
parameters.kv_stub->AsyncTxn(&context, *txn.txn_request, &cq_);
|
parameters.kv_stub->AsyncTxn(&context, *transaction.txn_request, &cq_);
|
||||||
response_reader->Finish(&reply, &status, (void*) this);
|
response_reader->Finish(&reply, &status, (void*) this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1123,7 +977,7 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncSetAction::ParseResponse() {
|
||||||
txn_resp.set_error_code(status.error_code());
|
txn_resp.set_error_code(status.error_code());
|
||||||
txn_resp.set_error_message(status.error_message());
|
txn_resp.set_error_message(status.error_message());
|
||||||
} else {
|
} else {
|
||||||
txn_resp.ParseResponse(reply);
|
txn_resp.ParseResponse(parameters.key, parameters.withPrefix, reply);
|
||||||
|
|
||||||
if (!reply.succeeded() && isCreate) {
|
if (!reply.succeeded() && isCreate) {
|
||||||
txn_resp.set_error_code(etcdv3::ERROR_KEY_ALREADY_EXISTS);
|
txn_resp.set_error_code(etcdv3::ERROR_KEY_ALREADY_EXISTS);
|
||||||
|
|
@ -1149,7 +1003,7 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncTxnAction::ParseResponse() {
|
||||||
txn_resp.set_error_code(status.error_code());
|
txn_resp.set_error_code(status.error_code());
|
||||||
txn_resp.set_error_message(status.error_message());
|
txn_resp.set_error_message(status.error_message());
|
||||||
} else {
|
} else {
|
||||||
txn_resp.ParseResponse(reply);
|
txn_resp.ParseResponse(parameters.key, parameters.withPrefix, reply);
|
||||||
|
|
||||||
// if there is an error code returned by parseResponse, we must
|
// if there is an error code returned by parseResponse, we must
|
||||||
// not overwrite it.
|
// not overwrite it.
|
||||||
|
|
@ -1188,15 +1042,14 @@ etcdv3::AsyncUnlockResponse etcdv3::AsyncUnlockAction::ParseResponse() {
|
||||||
|
|
||||||
etcdv3::AsyncUpdateAction::AsyncUpdateAction(etcdv3::ActionParameters&& params)
|
etcdv3::AsyncUpdateAction::AsyncUpdateAction(etcdv3::ActionParameters&& params)
|
||||||
: etcdv3::Action(std::move(params)) {
|
: etcdv3::Action(std::move(params)) {
|
||||||
etcdv3::Transaction txn;
|
etcdv3::Transaction transaction(parameters.key);
|
||||||
txn.add_compare_version(parameters.key, CompareResult::GREATER, 0); // exists
|
transaction.init_compare(CompareResult::GREATER, CompareTarget::VERSION);
|
||||||
txn.add_success_put(parameters.key, parameters.value, parameters.lease_id,
|
|
||||||
true /* for backwards compatibility */);
|
transaction.setup_compare_and_swap_sequence(parameters.value,
|
||||||
// backwards compatibility
|
parameters.lease_id);
|
||||||
txn.add_success_range(parameters.key);
|
|
||||||
txn.add_failure_range(parameters.key);
|
|
||||||
response_reader =
|
response_reader =
|
||||||
parameters.kv_stub->AsyncTxn(&context, *txn.txn_request, &cq_);
|
parameters.kv_stub->AsyncTxn(&context, *transaction.txn_request, &cq_);
|
||||||
response_reader->Finish(&reply, &status, (void*) this);
|
response_reader->Finish(&reply, &status, (void*) this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1208,7 +1061,7 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncUpdateAction::ParseResponse() {
|
||||||
txn_resp.set_error_message(status.error_message());
|
txn_resp.set_error_message(status.error_message());
|
||||||
} else {
|
} else {
|
||||||
if (reply.succeeded()) {
|
if (reply.succeeded()) {
|
||||||
txn_resp.ParseResponse(reply);
|
txn_resp.ParseResponse(parameters.key, parameters.withPrefix, reply);
|
||||||
txn_resp.set_action(etcdv3::UPDATE_ACTION);
|
txn_resp.set_action(etcdv3::UPDATE_ACTION);
|
||||||
} else {
|
} else {
|
||||||
txn_resp.set_error_code(etcdv3::ERROR_KEY_NOT_FOUND);
|
txn_resp.set_error_code(etcdv3::ERROR_KEY_NOT_FOUND);
|
||||||
|
|
@ -1225,14 +1078,28 @@ etcdv3::AsyncWatchAction::AsyncWatchAction(etcdv3::ActionParameters&& params)
|
||||||
(void*) etcdv3::WATCH_CREATE);
|
(void*) etcdv3::WATCH_CREATE);
|
||||||
this->watch_id =
|
this->watch_id =
|
||||||
std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||||
// #ifndef NDEBUG
|
// #ifndef NDEBUG
|
||||||
// std::clog << "etcd-cpp-apiv3: watch_id: " << this->watch_id << std::endl;
|
// std::clog << "etcd-cpp-apiv3: watch_id: " << this->watch_id << std::endl;
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
WatchRequest watch_req;
|
WatchRequest watch_req;
|
||||||
WatchCreateRequest watch_create_req;
|
WatchCreateRequest watch_create_req;
|
||||||
detail::make_request_with_ranges(watch_create_req, parameters.key,
|
|
||||||
parameters.range_end, parameters.withPrefix);
|
if (!parameters.withPrefix) {
|
||||||
|
watch_create_req.set_key(parameters.key);
|
||||||
|
} else {
|
||||||
|
if (parameters.key.empty()) {
|
||||||
|
watch_create_req.set_key(etcdv3::NUL);
|
||||||
|
watch_create_req.set_range_end(etcdv3::NUL);
|
||||||
|
} else {
|
||||||
|
watch_create_req.set_key(parameters.key);
|
||||||
|
watch_create_req.set_range_end(detail::string_plus_one(parameters.key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!parameters.range_end.empty()) {
|
||||||
|
watch_create_req.set_range_end(parameters.range_end);
|
||||||
|
}
|
||||||
|
|
||||||
watch_create_req.set_prev_kv(true);
|
watch_create_req.set_prev_kv(true);
|
||||||
watch_create_req.set_start_revision(parameters.revision);
|
watch_create_req.set_start_revision(parameters.revision);
|
||||||
watch_create_req.set_watch_id(this->watch_id);
|
watch_create_req.set_watch_id(this->watch_id);
|
||||||
|
|
@ -1246,14 +1113,7 @@ etcdv3::AsyncWatchAction::AsyncWatchAction(etcdv3::ActionParameters&& params)
|
||||||
got_tag == (void*) etcdv3::WATCH_CREATE) {
|
got_tag == (void*) etcdv3::WATCH_CREATE) {
|
||||||
stream->Write(watch_req, (void*) etcdv3::WATCH_WRITE);
|
stream->Write(watch_req, (void*) etcdv3::WATCH_WRITE);
|
||||||
} else {
|
} else {
|
||||||
status = grpc::Status(grpc::StatusCode::CANCELLED,
|
throw std::runtime_error("failed to create a watch connection");
|
||||||
"failed to create a watch connection");
|
|
||||||
// cannot continue for further watching
|
|
||||||
isCancelled.store(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!status.ok()) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait "write" (WatchCreateRequest) success, and start to read the first
|
// wait "write" (WatchCreateRequest) success, and start to read the first
|
||||||
|
|
@ -1261,66 +1121,15 @@ etcdv3::AsyncWatchAction::AsyncWatchAction(etcdv3::ActionParameters&& params)
|
||||||
if (cq_.Next(&got_tag, &ok) && ok && got_tag == (void*) etcdv3::WATCH_WRITE) {
|
if (cq_.Next(&got_tag, &ok) && ok && got_tag == (void*) etcdv3::WATCH_WRITE) {
|
||||||
stream->Read(&reply, (void*) this);
|
stream->Read(&reply, (void*) this);
|
||||||
} else {
|
} else {
|
||||||
status = grpc::Status(grpc::StatusCode::CANCELLED,
|
throw std::runtime_error("failed to write WatchCreateRequest to server");
|
||||||
"failed to write WatchCreateRequest to server");
|
|
||||||
// cannot continue for further watching
|
|
||||||
isCancelled.store(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Notes: `Cancel` and `waitForResponse` of watchers.
|
|
||||||
*
|
|
||||||
* We meet failures about failed to cancel the watcher on Ubuntu 20.04
|
|
||||||
* due to unable to receive the "etcdv3::WATCH_FINISH" tag from the gRPC
|
|
||||||
* completion queue.
|
|
||||||
*
|
|
||||||
* See CI:
|
|
||||||
* https://github.com/etcd-cpp-apiv3/etcd-cpp-apiv3/actions/runs/5561458372/jobs/10159155857
|
|
||||||
*
|
|
||||||
* To address the problem, we use the `AsyncNext()` to wait for the
|
|
||||||
* the last token from the completion queue (wait for 1 second, once
|
|
||||||
* we called the method `stream->Finish()`).
|
|
||||||
*
|
|
||||||
* Remark: the issue might be caused by lower version etcd.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void etcdv3::AsyncWatchAction::waitForResponse() {
|
void etcdv3::AsyncWatchAction::waitForResponse() {
|
||||||
void* got_tag;
|
void* got_tag;
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
bool the_final_round = false;
|
|
||||||
|
|
||||||
// failed to create the watcher
|
while (cq_.Next(&got_tag, &ok)) {
|
||||||
if (!status.ok()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (!the_final_round) {
|
|
||||||
if (!cq_.Next(&got_tag, &ok)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
auto deadline =
|
|
||||||
std::chrono::system_clock::now() + std::chrono::seconds(1);
|
|
||||||
switch (cq_.AsyncNext(&got_tag, &ok, deadline)) {
|
|
||||||
case CompletionQueue::NextStatus::TIMEOUT:
|
|
||||||
case CompletionQueue::NextStatus::SHUTDOWN: {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
std::cerr << "[warn] watcher does't exit normally" << std::endl;
|
|
||||||
#endif
|
|
||||||
// pretend to be received a "WATCH_FINISH" tag: shutdown
|
|
||||||
context.TryCancel();
|
|
||||||
cq_.Shutdown();
|
|
||||||
ok = false; // jump out
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CompletionQueue::NextStatus::GOT_EVENT: {
|
|
||||||
// normal execution flow
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ok == false) {
|
if (ok == false) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1329,7 +1138,6 @@ void etcdv3::AsyncWatchAction::waitForResponse() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (got_tag == (void*) etcdv3::WATCH_WRITES_DONE) {
|
if (got_tag == (void*) etcdv3::WATCH_WRITES_DONE) {
|
||||||
the_final_round = true;
|
|
||||||
stream->Finish(&status, (void*) etcdv3::WATCH_FINISH);
|
stream->Finish(&status, (void*) etcdv3::WATCH_FINISH);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -1362,6 +1170,7 @@ void etcdv3::AsyncWatchAction::waitForResponse() {
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cout << "issue a watch cancel" << std::endl;
|
||||||
// cancel the watcher after receiving the good response
|
// cancel the watcher after receiving the good response
|
||||||
this->CancelWatch();
|
this->CancelWatch();
|
||||||
|
|
||||||
|
|
@ -1381,44 +1190,23 @@ void etcdv3::AsyncWatchAction::waitForResponse() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void etcdv3::AsyncWatchAction::CancelWatch() {
|
||||||
|
if (!isCancelled.exchange(true)) {
|
||||||
|
WatchRequest cancel_req;
|
||||||
|
cancel_req.mutable_cancel_request()->set_watch_id(this->watch_id);
|
||||||
|
stream->Write(cancel_req, (void*) etcdv3::WATCH_WRITE_CANCEL);
|
||||||
|
isCancelled.store(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool etcdv3::AsyncWatchAction::Cancelled() const { return isCancelled.load(); }
|
||||||
|
|
||||||
void etcdv3::AsyncWatchAction::waitForResponse(
|
void etcdv3::AsyncWatchAction::waitForResponse(
|
||||||
std::function<void(etcd::Response)> callback) {
|
std::function<void(etcd::Response)> callback) {
|
||||||
void* got_tag;
|
void* got_tag;
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
bool the_final_round = false;
|
|
||||||
|
|
||||||
// failed to create the watcher
|
while (cq_.Next(&got_tag, &ok)) {
|
||||||
if (!status.ok()) {
|
|
||||||
auto resp = ParseResponse();
|
|
||||||
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
|
|
||||||
std::chrono::high_resolution_clock::now() - start_timepoint);
|
|
||||||
callback(etcd::Response(resp, duration));
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (!the_final_round) {
|
|
||||||
if (!cq_.Next(&got_tag, &ok)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
auto deadline =
|
|
||||||
std::chrono::system_clock::now() + std::chrono::seconds(1);
|
|
||||||
switch (cq_.AsyncNext(&got_tag, &ok, deadline)) {
|
|
||||||
case CompletionQueue::NextStatus::TIMEOUT:
|
|
||||||
case CompletionQueue::NextStatus::SHUTDOWN: {
|
|
||||||
std::cerr << "[warn] watcher does't exit normally" << std::endl;
|
|
||||||
// pretend to be received a "WATCH_FINISH" tag: shutdown
|
|
||||||
context.TryCancel();
|
|
||||||
cq_.Shutdown();
|
|
||||||
ok = false; // jump out
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CompletionQueue::NextStatus::GOT_EVENT: {
|
|
||||||
// normal execution flow
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ok == false) {
|
if (ok == false) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1427,7 +1215,6 @@ void etcdv3::AsyncWatchAction::waitForResponse(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (got_tag == (void*) etcdv3::WATCH_WRITES_DONE) {
|
if (got_tag == (void*) etcdv3::WATCH_WRITES_DONE) {
|
||||||
the_final_round = true;
|
|
||||||
stream->Finish(&status, (void*) etcdv3::WATCH_FINISH);
|
stream->Finish(&status, (void*) etcdv3::WATCH_FINISH);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -1470,17 +1257,6 @@ void etcdv3::AsyncWatchAction::waitForResponse(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void etcdv3::AsyncWatchAction::CancelWatch() {
|
|
||||||
if (!isCancelled.exchange(true)) {
|
|
||||||
WatchRequest cancel_req;
|
|
||||||
cancel_req.mutable_cancel_request()->set_watch_id(this->watch_id);
|
|
||||||
stream->Write(cancel_req, (void*) etcdv3::WATCH_WRITE_CANCEL);
|
|
||||||
isCancelled.store(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool etcdv3::AsyncWatchAction::Cancelled() const { return isCancelled.load(); }
|
|
||||||
|
|
||||||
etcdv3::AsyncWatchResponse etcdv3::AsyncWatchAction::ParseResponse() {
|
etcdv3::AsyncWatchResponse etcdv3::AsyncWatchAction::ParseResponse() {
|
||||||
AsyncWatchResponse watch_resp;
|
AsyncWatchResponse watch_resp;
|
||||||
watch_resp.set_action(etcdv3::WATCH_ACTION);
|
watch_resp.set_action(etcdv3::WATCH_ACTION);
|
||||||
|
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
#include "etcd/v3/Member.hpp"
|
|
||||||
|
|
||||||
etcdv3::Member::Member() {
|
|
||||||
id = 0;
|
|
||||||
name = "";
|
|
||||||
peerURLs = {};
|
|
||||||
clientURLs = {};
|
|
||||||
isLearner = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Member::set_id(uint64_t const& id) { this->id = id; }
|
|
||||||
|
|
||||||
void etcdv3::Member::set_name(std::string const& name) { this->name = name; }
|
|
||||||
|
|
||||||
void etcdv3::Member::set_peerURLs(std::vector<std::string> const& peerURLs) {
|
|
||||||
this->peerURLs = peerURLs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Member::set_clientURLs(
|
|
||||||
std::vector<std::string> const& clientURLs) {
|
|
||||||
this->clientURLs = clientURLs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Member::set_learner(bool isLearner) {
|
|
||||||
this->isLearner = isLearner;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t const& etcdv3::Member::get_id() const { return id; }
|
|
||||||
|
|
||||||
std::string const& etcdv3::Member::get_name() const { return name; }
|
|
||||||
|
|
||||||
std::vector<std::string> const& etcdv3::Member::get_peerURLs() const {
|
|
||||||
return peerURLs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> const& etcdv3::Member::get_clientURLs() const {
|
|
||||||
return clientURLs;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool etcdv3::Member::get_learner() const { return isLearner; }
|
|
||||||
|
|
@ -2,7 +2,11 @@
|
||||||
|
|
||||||
#include "proto/rpc.grpc.pb.h"
|
#include "proto/rpc.grpc.pb.h"
|
||||||
|
|
||||||
#include "etcd/v3/Action.hpp"
|
using etcdserverpb::Compare;
|
||||||
|
using etcdserverpb::DeleteRangeRequest;
|
||||||
|
using etcdserverpb::PutRequest;
|
||||||
|
using etcdserverpb::RangeRequest;
|
||||||
|
using etcdserverpb::RequestOp;
|
||||||
|
|
||||||
namespace etcdv3 {
|
namespace etcdv3 {
|
||||||
|
|
||||||
|
|
@ -24,337 +28,185 @@ etcdv3::Transaction::Transaction() {
|
||||||
txn_request.reset(new etcdserverpb::TxnRequest{});
|
txn_request.reset(new etcdserverpb::TxnRequest{});
|
||||||
}
|
}
|
||||||
|
|
||||||
etcdv3::Transaction::~Transaction() {}
|
etcdv3::Transaction::Transaction(const std::string& key) : key(key) {
|
||||||
|
txn_request.reset(new etcdserverpb::TxnRequest{});
|
||||||
|
}
|
||||||
|
|
||||||
void etcdv3::Transaction::add_compare(std::string const& key,
|
void etcdv3::Transaction::reset_key(std::string const& newkey) { key = newkey; }
|
||||||
CompareTarget const& target,
|
|
||||||
CompareResult const& result,
|
void etcdv3::Transaction::init_compare(CompareResult result,
|
||||||
Value const& target_value,
|
CompareTarget target) {
|
||||||
std::string const& range_end) {
|
Compare* compare = txn_request->add_compare();
|
||||||
switch (target) {
|
compare->set_result(detail::to_compare_result(result));
|
||||||
case CompareTarget::VERSION:
|
compare->set_target(detail::to_compare_target(target));
|
||||||
add_compare_version(key, result, target_value.version, range_end);
|
compare->set_key(key);
|
||||||
break;
|
|
||||||
case CompareTarget::CREATE:
|
compare->set_version(0);
|
||||||
add_compare_create(key, result, target_value.create_revision, range_end);
|
}
|
||||||
break;
|
|
||||||
case CompareTarget::MOD:
|
void etcdv3::Transaction::init_compare(std::string const& old_value,
|
||||||
add_compare_mod(key, result, target_value.mod_revision, range_end);
|
CompareResult result,
|
||||||
break;
|
CompareTarget target) {
|
||||||
case CompareTarget::VALUE:
|
Compare* compare = txn_request->add_compare();
|
||||||
add_compare_value(key, result, target_value.value, range_end);
|
compare->set_result(detail::to_compare_result(result));
|
||||||
break;
|
compare->set_target(detail::to_compare_target(target));
|
||||||
case CompareTarget::LEASE:
|
compare->set_key(key);
|
||||||
add_compare_lease(key, result, target_value.lease, range_end);
|
|
||||||
break;
|
compare->set_value(old_value);
|
||||||
default:
|
}
|
||||||
// ignore invalid compare target
|
|
||||||
break;
|
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
|
||||||
|
*/
|
||||||
|
void etcdv3::Transaction::setup_basic_failure_operation(
|
||||||
|
std::string const& key) {
|
||||||
|
std::unique_ptr<RangeRequest> get_request(new RangeRequest());
|
||||||
|
get_request->set_key(key);
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
void etcdv3::Transaction::setup_set_failure_operation(std::string const& key,
|
||||||
|
std::string const& value,
|
||||||
|
int64_t leaseid) {
|
||||||
|
std::unique_ptr<PutRequest> put_request(new PutRequest());
|
||||||
|
put_request->set_key(key);
|
||||||
|
put_request->set_value(value);
|
||||||
|
put_request->set_prev_kv(true);
|
||||||
|
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());
|
||||||
|
get_request->set_key(key);
|
||||||
|
req_failure = txn_request->add_failure();
|
||||||
|
req_failure->set_allocated_request_range(get_request.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
std::unique_ptr<PutRequest> put_request(new PutRequest());
|
||||||
|
put_request->set_key(key);
|
||||||
|
put_request->set_value(value);
|
||||||
|
put_request->set_prev_kv(true);
|
||||||
|
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());
|
||||||
|
get_request->set_key(key);
|
||||||
|
req_success = txn_request->add_success();
|
||||||
|
req_success->set_allocated_request_range(get_request.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get key value then modify and get new value
|
||||||
|
*/
|
||||||
|
void etcdv3::Transaction::setup_compare_and_swap_sequence(
|
||||||
|
std::string const& value, int64_t leaseid) {
|
||||||
|
std::unique_ptr<PutRequest> put_request(new PutRequest());
|
||||||
|
put_request->set_key(key);
|
||||||
|
put_request->set_value(value);
|
||||||
|
put_request->set_prev_kv(true);
|
||||||
|
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());
|
||||||
|
get_request->set_key(key);
|
||||||
|
req_success = txn_request->add_success();
|
||||||
|
req_success->set_allocated_request_range(get_request.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get key, delete
|
||||||
|
*/
|
||||||
|
void etcdv3::Transaction::setup_delete_sequence(std::string const& key,
|
||||||
|
std::string const& range_end,
|
||||||
|
bool recursive) {
|
||||||
|
std::unique_ptr<DeleteRangeRequest> del_request(new DeleteRangeRequest());
|
||||||
|
del_request->set_key(key);
|
||||||
|
del_request->set_prev_kv(true);
|
||||||
|
if (recursive) {
|
||||||
|
del_request->set_range_end(range_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RequestOp* req_success = txn_request->add_success();
|
||||||
|
req_success->set_allocated_request_delete_range(del_request.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
void etcdv3::Transaction::add_compare_version(std::string const& key,
|
/**
|
||||||
int64_t const& version,
|
* get key, delete
|
||||||
std::string const& range_end) {
|
*/
|
||||||
this->add_compare_version(key, CompareResult::EQUAL, version, range_end);
|
void etcdv3::Transaction::setup_delete_failure_operation(
|
||||||
|
std::string const& key, std::string const& range_end, bool recursive) {
|
||||||
|
std::unique_ptr<RangeRequest> get_request(new RangeRequest());
|
||||||
|
std::unique_ptr<DeleteRangeRequest> del_request(new DeleteRangeRequest());
|
||||||
|
get_request.reset(new RangeRequest());
|
||||||
|
get_request->set_key(key);
|
||||||
|
if (recursive) {
|
||||||
|
get_request->set_range_end(range_end);
|
||||||
|
get_request->set_sort_target(
|
||||||
|
RangeRequest::SortTarget::RangeRequest_SortTarget_KEY);
|
||||||
|
get_request->set_sort_order(
|
||||||
|
RangeRequest::SortOrder::RangeRequest_SortOrder_ASCEND);
|
||||||
|
}
|
||||||
|
RequestOp* req_failure = txn_request->add_failure();
|
||||||
|
req_failure->set_allocated_request_range(get_request.release());
|
||||||
|
|
||||||
|
del_request.reset(new DeleteRangeRequest());
|
||||||
|
del_request->set_key(key);
|
||||||
|
if (recursive) {
|
||||||
|
del_request->set_range_end(range_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
req_failure = txn_request->add_failure();
|
||||||
|
req_failure->set_allocated_request_delete_range(del_request.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
void etcdv3::Transaction::add_compare_version(std::string const& key,
|
void etcdv3::Transaction::setup_compare_and_delete_operation(
|
||||||
CompareResult const& result,
|
std::string const& key) {
|
||||||
int64_t const& version,
|
std::unique_ptr<DeleteRangeRequest> del_request(new DeleteRangeRequest());
|
||||||
std::string const& range_end) {
|
del_request->set_key(key);
|
||||||
auto compare = txn_request->add_compare();
|
del_request->set_prev_kv(true);
|
||||||
compare->set_result(detail::to_compare_result(result));
|
RequestOp* req_success = txn_request->add_success();
|
||||||
compare->set_target(detail::to_compare_target(CompareTarget::VERSION));
|
req_success->set_allocated_request_delete_range(del_request.release());
|
||||||
compare->set_key(key);
|
|
||||||
compare->set_version(version);
|
|
||||||
compare->set_range_end(range_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_compare_create(std::string const& key,
|
|
||||||
int64_t const& create_revision,
|
|
||||||
std::string const& range_end) {
|
|
||||||
this->add_compare_create(key, CompareResult::EQUAL, create_revision,
|
|
||||||
range_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_compare_create(std::string const& key,
|
|
||||||
CompareResult const& result,
|
|
||||||
int64_t const& create_revision,
|
|
||||||
std::string const& range_end) {
|
|
||||||
auto compare = txn_request->add_compare();
|
|
||||||
compare->set_result(detail::to_compare_result(result));
|
|
||||||
compare->set_target(detail::to_compare_target(CompareTarget::CREATE));
|
|
||||||
compare->set_key(key);
|
|
||||||
compare->set_create_revision(create_revision);
|
|
||||||
compare->set_range_end(range_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_compare_mod(std::string const& key,
|
|
||||||
int64_t const& mod_revision,
|
|
||||||
std::string const& range_end) {
|
|
||||||
this->add_compare_mod(key, CompareResult::EQUAL, mod_revision, range_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_compare_mod(std::string const& key,
|
|
||||||
CompareResult const& result,
|
|
||||||
int64_t const& mod_revision,
|
|
||||||
std::string const& range_end) {
|
|
||||||
auto compare = txn_request->add_compare();
|
|
||||||
compare->set_result(detail::to_compare_result(result));
|
|
||||||
compare->set_target(detail::to_compare_target(CompareTarget::MOD));
|
|
||||||
compare->set_key(key);
|
|
||||||
compare->set_mod_revision(mod_revision);
|
|
||||||
compare->set_range_end(range_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_compare_value(std::string const& key,
|
|
||||||
std::string const& value,
|
|
||||||
std::string const& range_end) {
|
|
||||||
this->add_compare_value(key, CompareResult::EQUAL, value, range_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_compare_value(std::string const& key,
|
|
||||||
CompareResult const& result,
|
|
||||||
std::string const& value,
|
|
||||||
std::string const& range_end) {
|
|
||||||
auto compare = txn_request->add_compare();
|
|
||||||
compare->set_result(detail::to_compare_result(result));
|
|
||||||
compare->set_target(detail::to_compare_target(CompareTarget::VALUE));
|
|
||||||
compare->set_key(key);
|
|
||||||
compare->set_value(value);
|
|
||||||
compare->set_range_end(range_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_compare_lease(std::string const& key,
|
|
||||||
int64_t const& lease,
|
|
||||||
std::string const& range_end) {
|
|
||||||
this->add_compare_lease(key, CompareResult::EQUAL, lease, range_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_compare_lease(std::string const& key,
|
|
||||||
CompareResult const& result,
|
|
||||||
int64_t const& lease,
|
|
||||||
std::string const& range_end) {
|
|
||||||
auto compare = txn_request->add_compare();
|
|
||||||
compare->set_result(detail::to_compare_result(result));
|
|
||||||
compare->set_target(detail::to_compare_target(CompareTarget::LEASE));
|
|
||||||
compare->set_key(key);
|
|
||||||
compare->set_lease(lease);
|
|
||||||
compare->set_range_end(range_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_success_range(std::string const& key,
|
|
||||||
std::string const& range_end,
|
|
||||||
bool const recursive,
|
|
||||||
const int64_t limit) {
|
|
||||||
auto succ = txn_request->add_success();
|
|
||||||
auto get_request = succ->mutable_request_range();
|
|
||||||
etcdv3::detail::make_request_with_ranges(*get_request, key, range_end,
|
|
||||||
recursive);
|
|
||||||
get_request->set_limit(limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_success_put(std::string const& key,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid,
|
|
||||||
const bool prev_kv) {
|
|
||||||
auto succ = txn_request->add_success();
|
|
||||||
auto put_request = succ->mutable_request_put();
|
|
||||||
put_request->set_key(key);
|
|
||||||
put_request->set_value(value);
|
|
||||||
put_request->set_prev_kv(prev_kv);
|
|
||||||
put_request->set_lease(leaseid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_success_delete(std::string const& key,
|
|
||||||
std::string const& range_end,
|
|
||||||
bool const recursive,
|
|
||||||
const bool prev_kv) {
|
|
||||||
auto succ = txn_request->add_success();
|
|
||||||
auto del_request = succ->mutable_request_delete_range();
|
|
||||||
etcdv3::detail::make_request_with_ranges(*del_request, key, range_end,
|
|
||||||
recursive);
|
|
||||||
del_request->set_prev_kv(prev_kv);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_success_txn(
|
|
||||||
const std::shared_ptr<Transaction> txn) {
|
|
||||||
auto succ = txn_request->add_success();
|
|
||||||
auto txn_request = succ->mutable_request_txn();
|
|
||||||
txn_request->CopyFrom(*txn->txn_request);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_failure_range(std::string const& key,
|
|
||||||
std::string const& range_end,
|
|
||||||
bool const recursive,
|
|
||||||
const int64_t limit) {
|
|
||||||
auto fail = txn_request->add_failure();
|
|
||||||
auto get_request = fail->mutable_request_range();
|
|
||||||
etcdv3::detail::make_request_with_ranges(*get_request, key, range_end,
|
|
||||||
recursive);
|
|
||||||
get_request->set_limit(limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_failure_put(std::string const& key,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid,
|
|
||||||
const bool prev_kv) {
|
|
||||||
auto fail = txn_request->add_failure();
|
|
||||||
auto put_request = fail->mutable_request_put();
|
|
||||||
put_request->set_key(key);
|
|
||||||
put_request->set_value(value);
|
|
||||||
put_request->set_prev_kv(prev_kv);
|
|
||||||
put_request->set_lease(leaseid);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_failure_delete(std::string const& key,
|
|
||||||
std::string const& range_end,
|
|
||||||
bool const recursive,
|
|
||||||
const bool prev_kv) {
|
|
||||||
auto fail = txn_request->add_failure();
|
|
||||||
auto del_request = fail->mutable_request_delete_range();
|
|
||||||
etcdv3::detail::make_request_with_ranges(*del_request, key, range_end,
|
|
||||||
recursive);
|
|
||||||
del_request->set_prev_kv(prev_kv);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::add_failure_txn(
|
|
||||||
const std::shared_ptr<Transaction> txn) {
|
|
||||||
auto fail = txn_request->add_failure();
|
|
||||||
auto txn_request = fail->mutable_request_txn();
|
|
||||||
txn_request->CopyFrom(*txn->txn_request);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::setup_compare_and_create(
|
|
||||||
std::string const& key, std::string const& prev_value,
|
|
||||||
std::string const& create_key, std::string const& value,
|
|
||||||
int64_t const leaseid) {
|
|
||||||
this->add_compare_value(key, CompareResult::EQUAL, prev_value);
|
|
||||||
this->add_success_put(create_key, value, leaseid);
|
|
||||||
this->add_failure_range(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::setup_compare_or_create(std::string const& key,
|
|
||||||
std::string const& prev_value,
|
|
||||||
std::string const& create_key,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid) {
|
|
||||||
this->add_compare_value(key, CompareResult::NOT_EQUAL, prev_value);
|
|
||||||
this->add_success_put(create_key, value, leaseid);
|
|
||||||
this->add_failure_range(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::setup_compare_and_swap(std::string const& key,
|
|
||||||
std::string const& prev_value,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid) {
|
|
||||||
this->add_compare_value(key, CompareResult::EQUAL, prev_value);
|
|
||||||
this->add_success_put(key, value, leaseid);
|
|
||||||
this->add_failure_range(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::setup_compare_or_swap(std::string const& key,
|
|
||||||
std::string const& prev_value,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid) {
|
|
||||||
this->add_compare_value(key, CompareResult::NOT_EQUAL, prev_value);
|
|
||||||
this->add_success_put(key, value, leaseid);
|
|
||||||
this->add_failure_range(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::setup_compare_and_delete(
|
|
||||||
std::string const& key, std::string const& prev_value,
|
|
||||||
std::string const& delete_key, std::string const& range_end,
|
|
||||||
const bool recursive) {
|
|
||||||
this->add_compare_value(key, CompareResult::EQUAL, prev_value);
|
|
||||||
this->add_success_delete(delete_key, range_end, recursive,
|
|
||||||
true /* for backwards compatibility */);
|
|
||||||
this->add_failure_range(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::setup_compare_or_delete(std::string const& key,
|
|
||||||
std::string const& prev_value,
|
|
||||||
std::string const& delete_key,
|
|
||||||
std::string const& range_end,
|
|
||||||
const bool recursive) {
|
|
||||||
this->add_compare_value(key, CompareResult::NOT_EQUAL, prev_value);
|
|
||||||
this->add_success_delete(delete_key, range_end, recursive,
|
|
||||||
true /* for backwards compatibility */);
|
|
||||||
this->add_failure_range(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::setup_compare_and_create(
|
|
||||||
std::string const& key, const int64_t prev_revision,
|
|
||||||
std::string const& create_key, std::string const& value,
|
|
||||||
int64_t const leaseid) {
|
|
||||||
this->add_compare_mod(key, CompareResult::EQUAL, prev_revision);
|
|
||||||
this->add_success_put(create_key, value, leaseid);
|
|
||||||
this->add_failure_range(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::setup_compare_or_create(std::string const& key,
|
|
||||||
const int64_t prev_revision,
|
|
||||||
std::string const& create_key,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid) {
|
|
||||||
this->add_compare_mod(key, CompareResult::NOT_EQUAL, prev_revision);
|
|
||||||
this->add_success_put(create_key, value, leaseid);
|
|
||||||
this->add_failure_range(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::setup_compare_and_swap(std::string const& key,
|
|
||||||
const int64_t prev_revision,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid) {
|
|
||||||
this->add_compare_mod(key, CompareResult::EQUAL, prev_revision);
|
|
||||||
this->add_success_put(key, value, leaseid);
|
|
||||||
this->add_failure_range(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::setup_compare_or_swap(std::string const& key,
|
|
||||||
const int64_t prev_revision,
|
|
||||||
std::string const& value,
|
|
||||||
int64_t const leaseid) {
|
|
||||||
this->add_compare_mod(key, CompareResult::NOT_EQUAL, prev_revision);
|
|
||||||
this->add_success_put(key, value, leaseid);
|
|
||||||
this->add_failure_range(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::setup_compare_and_delete(
|
|
||||||
std::string const& key, const int64_t prev_revision,
|
|
||||||
std::string const& delete_key, std::string const& range_end,
|
|
||||||
const bool recursive) {
|
|
||||||
this->add_compare_mod(key, CompareResult::EQUAL, prev_revision);
|
|
||||||
this->add_success_delete(delete_key, range_end, recursive,
|
|
||||||
true /* for backwards compatibility */);
|
|
||||||
this->add_failure_range(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void etcdv3::Transaction::setup_compare_or_delete(std::string const& key,
|
|
||||||
const int64_t prev_revision,
|
|
||||||
std::string const& delete_key,
|
|
||||||
std::string const& range_end,
|
|
||||||
const bool recursive) {
|
|
||||||
this->add_compare_mod(key, CompareResult::NOT_EQUAL, prev_revision);
|
|
||||||
this->add_success_delete(delete_key, range_end, recursive,
|
|
||||||
true /* for backwards compatibility */);
|
|
||||||
this->add_failure_range(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void etcdv3::Transaction::setup_put(std::string const& key,
|
void etcdv3::Transaction::setup_put(std::string const& key,
|
||||||
std::string const& value) {
|
std::string const& value) {
|
||||||
this->add_success_put(key, value);
|
std::unique_ptr<PutRequest> put_request(new PutRequest());
|
||||||
|
put_request->set_key(key);
|
||||||
|
put_request->set_value(value);
|
||||||
|
put_request->set_prev_kv(false);
|
||||||
|
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) {
|
||||||
this->add_success_delete(key, "", false,
|
std::unique_ptr<DeleteRangeRequest> del_request(new DeleteRangeRequest());
|
||||||
true /* for backwards compatibility */);
|
del_request->set_key(key);
|
||||||
|
del_request->set_prev_kv(false);
|
||||||
|
|
||||||
|
RequestOp* req_success = txn_request->add_success();
|
||||||
|
req_success->set_allocated_request_delete_range(del_request.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
void etcdv3::Transaction::setup_delete(std::string const& key,
|
etcdv3::Transaction::~Transaction() {}
|
||||||
std::string const& range_end,
|
|
||||||
const bool recursive) {
|
|
||||||
this->add_success_delete(key, range_end, recursive,
|
|
||||||
true /* for backwards compatibility */);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
#include "etcd/v3/V3Response.hpp"
|
#include "etcd/v3/V3Response.hpp"
|
||||||
#include "etcd/v3/Member.hpp"
|
|
||||||
#include "etcd/v3/action_constants.hpp"
|
#include "etcd/v3/action_constants.hpp"
|
||||||
|
|
||||||
void etcdv3::V3Response::set_error_code(int code) { error_code = code; }
|
void etcdv3::V3Response::set_error_code(int code) { error_code = code; }
|
||||||
|
|
@ -80,7 +79,3 @@ uint64_t etcdv3::V3Response::get_raft_term() const { 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<etcdv3::Member> const& etcdv3::V3Response::get_members() const {
|
|
||||||
return this->members;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ 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 = "set"; // alias
|
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";
|
||||||
|
|
@ -19,10 +19,6 @@ 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::ADDMEMBER = "addmember";
|
|
||||||
char const* etcdv3::LISTMEMBER = "listmember";
|
|
||||||
char const* etcdv3::REMOVEMEMBER = "removemember";
|
|
||||||
|
|
||||||
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";
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ foreach(testfile ${TEST_FILES})
|
||||||
add_executable(${test_name} EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/${testfile})
|
add_executable(${test_name} EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/${testfile})
|
||||||
endif()
|
endif()
|
||||||
use_cxx(${test_name})
|
use_cxx(${test_name})
|
||||||
set_exceptions(${test_name})
|
|
||||||
add_test(NAME ${test_name} COMMAND $<TARGET_FILE:${test_name}>)
|
add_test(NAME ${test_name} COMMAND $<TARGET_FILE:${test_name}>)
|
||||||
|
|
||||||
target_include_directories(${test_name} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../proto/gen)
|
target_include_directories(${test_name} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../proto/gen)
|
||||||
|
|
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
#include <cmath>
|
|
||||||
#define CATCH_CONFIG_MAIN
|
|
||||||
#include <catch.hpp>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <chrono>
|
|
||||||
#include <cstring>
|
|
||||||
#include <iostream>
|
|
||||||
#include <thread>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "etcd/Client.hpp"
|
|
||||||
|
|
||||||
static const std::string etcd_url =
|
|
||||||
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
|
|
||||||
|
|
||||||
pid_t new_etcd_pid = 0;
|
|
||||||
|
|
||||||
pid_t start_etcd_server(const std::string& etcd_path,
|
|
||||||
const std::vector<std::string>& args) {
|
|
||||||
pid_t pid = fork();
|
|
||||||
if (pid == -1) {
|
|
||||||
std::cout << "Failed to fork process" << std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
} else if (pid == 0) {
|
|
||||||
std::vector<char*> c_args;
|
|
||||||
c_args.push_back(const_cast<char*>(etcd_path.c_str()));
|
|
||||||
for (const auto& arg : args) {
|
|
||||||
c_args.push_back(const_cast<char*>(arg.c_str()));
|
|
||||||
}
|
|
||||||
c_args.push_back(nullptr);
|
|
||||||
|
|
||||||
if (execvp(etcd_path.c_str(), c_args.data()) == -1) {
|
|
||||||
std::cout << "Failed to exec etcd process: " << std::strerror(errno)
|
|
||||||
<< std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("add member") {
|
|
||||||
etcd::Client etcd(etcd_url);
|
|
||||||
etcd::Response res = etcd.list_member().get();
|
|
||||||
REQUIRE(res.is_ok());
|
|
||||||
CHECK(1 == res.members().size());
|
|
||||||
|
|
||||||
std::string member_name = res.members()[0].get_name();
|
|
||||||
std::string prev_peer_urls = res.members()[0].get_peerURLs()[0];
|
|
||||||
|
|
||||||
// Add a new member
|
|
||||||
std::string peer_urls = "http://127.0.0.1:33691";
|
|
||||||
std::string client_urls = "http://127.0.0.1:33690";
|
|
||||||
bool is_learner = false;
|
|
||||||
res = etcd.add_member(peer_urls, is_learner).get();
|
|
||||||
REQUIRE(res.is_ok());
|
|
||||||
|
|
||||||
// Create the directory for the new etcd server
|
|
||||||
std::string cmd = "mkdir -p /tmp/new_etcd_member";
|
|
||||||
system(cmd.c_str());
|
|
||||||
|
|
||||||
// Start a new etcd server
|
|
||||||
std::vector<std::string> args = {
|
|
||||||
"--name",
|
|
||||||
"new_etcd_member",
|
|
||||||
"--initial-advertise-peer-urls",
|
|
||||||
peer_urls,
|
|
||||||
"--listen-peer-urls",
|
|
||||||
peer_urls,
|
|
||||||
"--initial-cluster",
|
|
||||||
member_name + "=" + prev_peer_urls + ",new_etcd_member=" + peer_urls,
|
|
||||||
"--initial-cluster-state",
|
|
||||||
"existing",
|
|
||||||
"--listen-client-urls",
|
|
||||||
client_urls,
|
|
||||||
"--advertise-client-urls",
|
|
||||||
client_urls,
|
|
||||||
"--data-dir",
|
|
||||||
"/tmp/new_etcd_member",
|
|
||||||
};
|
|
||||||
|
|
||||||
new_etcd_pid = start_etcd_server("/usr/local/bin/etcd", args);
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(30));
|
|
||||||
|
|
||||||
// Check the member's number
|
|
||||||
{
|
|
||||||
etcd::Response res = etcd.list_member().get();
|
|
||||||
REQUIRE(res.is_ok());
|
|
||||||
CHECK(2 == res.members().size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("member remove") {
|
|
||||||
etcd::Client etcd(etcd_url);
|
|
||||||
etcd::Response res = etcd.list_member().get();
|
|
||||||
REQUIRE(res.is_ok());
|
|
||||||
CHECK(2 == res.members().size());
|
|
||||||
|
|
||||||
uint64_t member_id = 0;
|
|
||||||
for (const auto& member : res.members()) {
|
|
||||||
if (member.get_name() == "new_etcd_member") {
|
|
||||||
member_id = member.get_id();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
REQUIRE(member_id != 0);
|
|
||||||
// Remove the new member
|
|
||||||
res = etcd.remove_member(member_id).get();
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(30));
|
|
||||||
|
|
||||||
// Check whether the new etcd server is quited
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
pid_t wpid = waitpid(new_etcd_pid, &status, WNOHANG);
|
|
||||||
REQUIRE(wpid == new_etcd_pid);
|
|
||||||
REQUIRE(WIFEXITED(status));
|
|
||||||
REQUIRE(WEXITSTATUS(status) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the directory for the new etcd server
|
|
||||||
std::string cmd = "rm -rf /tmp/new_etcd_member";
|
|
||||||
system(cmd.c_str());
|
|
||||||
|
|
||||||
// Check the member's number
|
|
||||||
{
|
|
||||||
etcd::Response res = etcd.list_member().get();
|
|
||||||
REQUIRE(res.is_ok());
|
|
||||||
CHECK(1 == res.members().size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
#define CATCH_CONFIG_MAIN
|
|
||||||
#include <catch.hpp>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "etcd/Client.hpp"
|
|
||||||
|
|
||||||
static const std::string etcd_v4_url =
|
|
||||||
etcdv3::detail::resolve_etcd_endpoints("http://127.0.0.1:2379");
|
|
||||||
static const std::string etcd_v6_url =
|
|
||||||
etcdv3::detail::resolve_etcd_endpoints("http://::1:2379");
|
|
||||||
// http://[ipv6]:port url
|
|
||||||
static const std::string etcd_ipv6_url =
|
|
||||||
etcdv3::detail::resolve_etcd_endpoints("http://[::1]:2379");
|
|
||||||
|
|
||||||
TEST_CASE("test ipv4 connection") {
|
|
||||||
std::cout << "ipv4 endpoints: " << etcd_v4_url << std::endl;
|
|
||||||
etcd::Client etcd(etcd_v4_url);
|
|
||||||
REQUIRE(etcd.head().get().is_ok());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("test ipv6 connection") {
|
|
||||||
std::cout << "ipv6 endpoints: " << etcd_v6_url << std::endl;
|
|
||||||
etcd::Client etcd(etcd_v6_url);
|
|
||||||
REQUIRE(etcd.head().get().is_ok());
|
|
||||||
|
|
||||||
std::cout << "ipv6 endpoints: " << etcd_ipv6_url << std::endl;
|
|
||||||
etcd::Client etcd1(etcd_ipv6_url);
|
|
||||||
REQUIRE(etcd1.head().get().is_ok());
|
|
||||||
}
|
|
||||||
|
|
@ -12,22 +12,17 @@ TEST_CASE("sync operations") {
|
||||||
etcd::SyncClient etcd(etcd_url);
|
etcd::SyncClient etcd(etcd_url);
|
||||||
etcd.rmdir("/test", true);
|
etcd.rmdir("/test", true);
|
||||||
|
|
||||||
etcd::Response res;
|
|
||||||
int64_t index;
|
|
||||||
|
|
||||||
// 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 ==
|
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS ==
|
||||||
etcd.add("/test/key1", "41").error_code()); // 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 ==
|
CHECK(etcd::ERROR_KEY_NOT_FOUND ==
|
||||||
etcd.modify("/test/key2", "43").error_code()); // Key not found
|
etcd.modify("/test/key2", "43").error_code()); // Key not found
|
||||||
res = etcd.modify("/test/key1", "42");
|
CHECK("43" == etcd.modify("/test/key1", "42").prev_value().as_string());
|
||||||
CHECK(0 == res.error_code());
|
|
||||||
CHECK("43" == res.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
|
||||||
|
|
@ -65,7 +60,7 @@ TEST_CASE("sync operations") {
|
||||||
|
|
||||||
// compare and swap
|
// compare and swap
|
||||||
etcd.set("/test/key1", "42");
|
etcd.set("/test/key1", "42");
|
||||||
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 ==
|
CHECK(etcd::ERROR_COMPARE_FAILED ==
|
||||||
etcd.modify_if("/test/key1", "44", "42").error_code());
|
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());
|
||||||
|
|
@ -76,20 +71,16 @@ TEST_CASE("sync operations") {
|
||||||
etcd.set("/test/key1", "42");
|
etcd.set("/test/key1", "42");
|
||||||
CHECK(etcd::ERROR_COMPARE_FAILED ==
|
CHECK(etcd::ERROR_COMPARE_FAILED ==
|
||||||
etcd.rm_if("/test/key1", "43").error_code());
|
etcd.rm_if("/test/key1", "43").error_code());
|
||||||
res = etcd.rm_if("/test/key1", "42");
|
CHECK(0 == etcd.rm_if("/test/key1", "42").error_code());
|
||||||
CHECK(
|
|
||||||
(0 == res.error_code() || etcd::ERROR_KEY_NOT_FOUND == res.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 ==
|
CHECK(etcd::ERROR_COMPARE_FAILED ==
|
||||||
etcd.rm_if("/test/key1", index - 1).error_code());
|
etcd.rm_if("/test/key1", index - 1).error_code());
|
||||||
res = etcd.rm_if("/test/key1", index);
|
CHECK(0 == etcd.rm_if("/test/key1", index).error_code());
|
||||||
CHECK(
|
|
||||||
(0 == res.error_code() || etcd::ERROR_KEY_NOT_FOUND == res.error_code()));
|
|
||||||
|
|
||||||
// leasegrant
|
// leasegrant
|
||||||
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());
|
||||||
|
|
@ -105,7 +96,6 @@ TEST_CASE("sync operations") {
|
||||||
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());
|
||||||
res = etcd.get("/test/key1");
|
|
||||||
CHECK(leaseid == res.value().lease());
|
CHECK(leaseid == res.value().lease());
|
||||||
|
|
||||||
// modify with lease
|
// modify with lease
|
||||||
|
|
|
||||||
|
|
@ -91,13 +91,12 @@ TEST_CASE("set a key") {
|
||||||
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").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());
|
||||||
resp = etcd.get("/test/key1").get();
|
|
||||||
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") {
|
||||||
|
|
@ -116,11 +115,11 @@ TEST_CASE("atomic compare-and-swap") {
|
||||||
CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code());
|
CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code());
|
||||||
CHECK("etcd-cpp-apiv3: compare failed" == res.error_message());
|
CHECK("etcd-cpp-apiv3: compare failed" == res.error_message());
|
||||||
|
|
||||||
// modify fails on non-existing keys
|
// modify fails the second time
|
||||||
res = etcd.modify_if("/test/key222", "44", "42").get();
|
res = etcd.modify_if("/test/key222", "44", "42").get();
|
||||||
CHECK(!res.is_ok());
|
CHECK(!res.is_ok());
|
||||||
CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code());
|
CHECK(etcd::ERROR_KEY_NOT_FOUND == res.error_code());
|
||||||
CHECK("etcd-cpp-apiv3: compare failed" == res.error_message());
|
CHECK("etcd-cpp-apiv3: key not found" == res.error_message());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("delete a value") {
|
TEST_CASE("delete a value") {
|
||||||
|
|
@ -145,10 +144,10 @@ TEST_CASE("delete a value") {
|
||||||
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(create_index == resp.value().created_index());
|
|
||||||
CHECK(modify_index == resp.value().modified_index());
|
CHECK(modify_index == resp.value().modified_index());
|
||||||
|
CHECK(create_index == resp.value().created_index());
|
||||||
CHECK(version == resp.value().version());
|
CHECK(version == resp.value().version());
|
||||||
CHECK("43" == resp.value().as_string());
|
CHECK("" == resp.value().as_string());
|
||||||
CHECK("/test/key1" == resp.value().key());
|
CHECK("/test/key1" == resp.value().key());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -559,8 +558,6 @@ TEST_CASE("lease grant") {
|
||||||
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());
|
||||||
res = etcd.get("/test/key1").get();
|
|
||||||
REQUIRE(0 == res.error_code()); // overwrite
|
|
||||||
CHECK(leaseid == res.value().lease());
|
CHECK(leaseid == res.value().lease());
|
||||||
|
|
||||||
// change with lease id
|
// change with lease id
|
||||||
|
|
@ -569,8 +566,6 @@ TEST_CASE("lease grant") {
|
||||||
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());
|
||||||
res = etcd.get("/test/key1").get();
|
|
||||||
REQUIRE(0 == res.error_code()); // overwrite
|
|
||||||
CHECK(leaseid == res.value().lease());
|
CHECK(leaseid == res.value().lease());
|
||||||
|
|
||||||
// failure to attach lease id
|
// failure to attach lease id
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,7 @@ TEST_CASE("keepalive revoke and check if alive") {
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
|
||||||
// expect keep_alive->Check() to throw exception
|
// expect keep_alive->Check() to throw exception
|
||||||
#ifndef _ETCD_NO_EXCEPTIONS
|
|
||||||
REQUIRE_THROWS(keepalive->Check());
|
REQUIRE_THROWS(keepalive->Check());
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("keepalive won't expire") {
|
TEST_CASE("keepalive won't expire") {
|
||||||
|
|
@ -47,7 +45,6 @@ TEST_CASE("keepalive won't expire") {
|
||||||
auto lease_id = resp.value().lease();
|
auto lease_id = resp.value().lease();
|
||||||
etcd.add(key, meta_str, lease_id);
|
etcd.add(key, meta_str, lease_id);
|
||||||
|
|
||||||
#ifndef _ETCD_NO_EXCEPTIONS
|
|
||||||
std::function<void(std::exception_ptr)> handler =
|
std::function<void(std::exception_ptr)> handler =
|
||||||
[](std::exception_ptr eptr) {
|
[](std::exception_ptr eptr) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -60,22 +57,6 @@ TEST_CASE("keepalive won't expire") {
|
||||||
std::cerr << "Lease expiry \"" << e.what() << "\"\n";
|
std::cerr << "Lease expiry \"" << e.what() << "\"\n";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#else
|
|
||||||
std::function<void(std::exception_ptr)> handler;
|
|
||||||
#endif
|
|
||||||
etcd::KeepAlive keepalive(etcd, handler, ttl, lease_id);
|
etcd::KeepAlive keepalive(etcd, handler, ttl, lease_id);
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("keepalive auto-grant") {
|
|
||||||
etcd::Client etcd(etcd_uri);
|
|
||||||
|
|
||||||
// create a lease without pre-granted lease id
|
|
||||||
auto keepalive = std::make_shared<etcd::KeepAlive>(etcd, 10 /* ttl */);
|
|
||||||
auto lease_id = keepalive->Lease();
|
|
||||||
REQUIRE(lease_id != 0);
|
|
||||||
|
|
||||||
// sleep for a while, and cancel
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
|
||||||
keepalive->Cancel();
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,6 @@ TEST_CASE("lock using lease") {
|
||||||
|
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
|
|
||||||
#ifndef _ETCD_NO_EXCEPTIONS
|
|
||||||
std::function<void(std::exception_ptr)> handler =
|
std::function<void(std::exception_ptr)> handler =
|
||||||
[&failed](std::exception_ptr eptr) {
|
[&failed](std::exception_ptr eptr) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -129,9 +128,6 @@ TEST_CASE("lock using lease") {
|
||||||
failed = true;
|
failed = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#else
|
|
||||||
std::function<void(std::exception_ptr)> handler;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// with handler
|
// with handler
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ class DistributedLock {
|
||||||
DistributedLock::DistributedLock(const std::string& lock_name, uint timeout) {
|
DistributedLock::DistributedLock(const std::string& lock_name, 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 {
|
||||||
if (timeout == 0) {
|
if (timeout == 0) {
|
||||||
etcd::Response resp = _etcd_client->lock(lock_name).get();
|
etcd::Response resp = _etcd_client->lock(lock_name).get();
|
||||||
if (resp.is_ok()) {
|
if (resp.is_ok()) {
|
||||||
|
|
@ -31,12 +32,14 @@ DistributedLock::DistributedLock(const std::string& lock_name, uint timeout) {
|
||||||
_acquired = true;
|
_acquired = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std::future<etcd::Response> future = std::async(std::launch::async, [&]() {
|
std::future<etcd::Response> future =
|
||||||
|
std::async(std::launch::async, [&]() {
|
||||||
etcd::Response resp = _etcd_client->lock(lock_name).get();
|
etcd::Response resp = _etcd_client->lock(lock_name).get();
|
||||||
return resp;
|
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()) {
|
||||||
|
|
@ -50,6 +53,9 @@ DistributedLock::DistributedLock(const std::string& lock_name, uint timeout) {
|
||||||
std::cerr << "failed to acquire distributed lock" << std::endl;
|
std::cerr << "failed to acquire distributed lock" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
std::cerr << "failed to construct: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DistributedLock::~DistributedLock() noexcept {
|
DistributedLock::~DistributedLock() noexcept {
|
||||||
|
|
@ -57,10 +63,14 @@ DistributedLock::~DistributedLock() noexcept {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
auto resp = _etcd_client->unlock(_lock_key).get();
|
auto resp = _etcd_client->unlock(_lock_key).get();
|
||||||
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) {
|
||||||
|
std::cerr << "failed to destruct: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ void print_response(etcd::Response const& resp) {
|
||||||
void wait_for_connection(std::string endpoints) {
|
void wait_for_connection(std::string endpoints) {
|
||||||
// wait until the client connects to etcd server
|
// wait until the client connects to etcd server
|
||||||
while (true) {
|
while (true) {
|
||||||
#ifndef _ETCD_NO_EXCEPTIONS
|
|
||||||
try {
|
try {
|
||||||
etcd::Client client(endpoints);
|
etcd::Client client(endpoints);
|
||||||
if (client.head().get().is_ok()) {
|
if (client.head().get().is_ok()) {
|
||||||
|
|
@ -46,12 +45,6 @@ void wait_for_connection(std::string endpoints) {
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
// pass
|
// pass
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
etcd::Client client(endpoints);
|
|
||||||
if (client.head().get().is_ok()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -92,7 +85,6 @@ TEST_CASE("watch should can be re-established") {
|
||||||
|
|
||||||
// issue some changes to see if the watcher works
|
// issue some changes to see if the watcher works
|
||||||
for (int round = 0; round < 100000; ++round) {
|
for (int round = 0; round < 100000; ++round) {
|
||||||
#ifndef _ETCD_NO_EXCEPTIONS
|
|
||||||
try {
|
try {
|
||||||
etcd::Client client(etcd_url);
|
etcd::Client client(etcd_url);
|
||||||
auto response =
|
auto response =
|
||||||
|
|
@ -100,11 +92,6 @@ TEST_CASE("watch should can be re-established") {
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
// pass
|
// pass
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
etcd::Client client(etcd_url);
|
|
||||||
auto response =
|
|
||||||
client.set(my_prefix + "/foo", "bar-" + std::to_string(round)).get();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||||
}
|
}
|
||||||
|
|
@ -114,7 +101,6 @@ TEST_CASE("watch should can be re-established") {
|
||||||
|
|
||||||
// the watcher has been cancelled and shouldn't work anymore
|
// the watcher has been cancelled and shouldn't work anymore
|
||||||
for (int round = 10; round < 20; ++round) {
|
for (int round = 10; round < 20; ++round) {
|
||||||
#ifndef _ETCD_NO_EXCEPTIONS
|
|
||||||
try {
|
try {
|
||||||
etcd::Client client(etcd_url);
|
etcd::Client client(etcd_url);
|
||||||
auto response =
|
auto response =
|
||||||
|
|
@ -122,11 +108,6 @@ TEST_CASE("watch should can be re-established") {
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
// pass
|
// pass
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
etcd::Client client(etcd_url);
|
|
||||||
auto response =
|
|
||||||
client.set(my_prefix + "/foo", "bar-" + std::to_string(round)).get();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,13 @@ TEST_CASE("add a new key") {
|
||||||
etcdv3::Transaction txn;
|
etcdv3::Transaction txn;
|
||||||
|
|
||||||
// setup the conditions
|
// setup the conditions
|
||||||
txn.add_compare_value("/test/x1", "1");
|
txn.reset_key("/test/x1");
|
||||||
txn.add_compare_value("/test/x2", "2");
|
txn.init_compare("1", etcdv3::CompareResult::EQUAL,
|
||||||
|
etcdv3::CompareTarget::VALUE);
|
||||||
|
|
||||||
|
txn.reset_key("/test/x2");
|
||||||
|
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");
|
||||||
|
|
@ -79,51 +84,6 @@ TEST_CASE("add a new key") {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("fetch & add") {
|
|
||||||
etcd::Client etcd(etcd_url);
|
|
||||||
etcd.rmdir("/test", true).wait();
|
|
||||||
|
|
||||||
etcd.set("/test/key", "0").wait();
|
|
||||||
|
|
||||||
auto fetch_and_add = [](etcd::Client& client,
|
|
||||||
std::string const& key) -> void {
|
|
||||||
auto value = stoi(client.get(key).get().value().as_string());
|
|
||||||
while (true) {
|
|
||||||
auto txn = etcdv3::Transaction();
|
|
||||||
txn.setup_compare_and_swap(key, std::to_string(value),
|
|
||||||
std::to_string(value + 1));
|
|
||||||
etcd::Response resp = client.txn(txn).get();
|
|
||||||
if (resp.is_ok()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
value = stoi(resp.value().as_string());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// run 1000 times
|
|
||||||
const size_t rounds = 100;
|
|
||||||
std::atomic_size_t counter(0);
|
|
||||||
|
|
||||||
std::vector<std::thread> threads;
|
|
||||||
for (size_t i = 0; i < 10; ++i) {
|
|
||||||
threads.emplace_back([&]() {
|
|
||||||
while (counter.fetch_add(1) < rounds) {
|
|
||||||
fetch_and_add(etcd, "/test/key");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for (auto& thr : threads) {
|
|
||||||
thr.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the value
|
|
||||||
{
|
|
||||||
etcd::Response resp = etcd.get("/test/key").get();
|
|
||||||
REQUIRE(0 == resp.error_code());
|
|
||||||
CHECK(resp.value().as_string() == std::to_string(rounds));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
||||||
|
|
|
||||||
|
|
@ -191,41 +191,6 @@ TEST_CASE("create two watcher") {
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("using two watcher") {
|
|
||||||
etcd::SyncClient etcd(etcd_url);
|
|
||||||
|
|
||||||
int watched1 = 0;
|
|
||||||
int watched2 = 0;
|
|
||||||
|
|
||||||
etcd::Watcher w1(
|
|
||||||
etcd, "/test/def",
|
|
||||||
[&](etcd::Response const& resp) {
|
|
||||||
std::cout << "w1 called: " << resp.events().at(0).event_type() << " on "
|
|
||||||
<< resp.events().at(0).kv().key() << std::endl;
|
|
||||||
++watched1;
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
etcd::Watcher w2(
|
|
||||||
etcd, "/test",
|
|
||||||
[&](etcd::Response const& resp) {
|
|
||||||
std::cout << "w2 called: " << resp.events().at(0).event_type() << " on "
|
|
||||||
<< resp.events().at(0).kv().key() << std::endl;
|
|
||||||
++watched2;
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
|
||||||
|
|
||||||
etcd.put("/test/def/xxx", "42");
|
|
||||||
etcd.put("/test/abc", "42");
|
|
||||||
etcd.rm("/test/def/xxx");
|
|
||||||
etcd.rm("/test/abc");
|
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
|
||||||
CHECK(2 == watched1);
|
|
||||||
CHECK(4 == watched2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEST_CASE("request cancellation")
|
// TEST_CASE("request cancellation")
|
||||||
// {
|
// {
|
||||||
// etcd::Client etcd(etcd_url);
|
// etcd::Client etcd(etcd_url);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue