Skip to content

Commit

Permalink
Refactor the implementation of etcd transactions. (#236)
Browse files Browse the repository at this point in the history
Fixes #234.

Signed-off-by: Tao He <sighingnow@gmail.com>
  • Loading branch information
sighingnow committed Jul 15, 2023
1 parent 204038c commit 153546f
Show file tree
Hide file tree
Showing 16 changed files with 866 additions and 681 deletions.
60 changes: 56 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,36 @@ dependencies have been successfully installed:
cmake ..
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

The _etcd-cpp-apiv3_ should work well with etcd > 3.0. Feel free to issue an issue to us on
Expand Down Expand Up @@ -495,6 +525,7 @@ some specific conditions.
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.
* `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
value equals with old_value. If the values does not match returns with "Compare failed" error
(code `ERROR_COMPARE_FAILED`)
Expand Down Expand Up @@ -852,11 +883,32 @@ Transactions in etcd supports set a set of comparison targets to specify the con
etcdv3::Transaction txn;

// setup the conditions
txn.reset_key("/test/x1");
txn.init_compare("1", etcdv3::CompareResult::EQUAL, etcdv3::CompareTarget::VALUE);
txn.add_compare_value("/test/x1", "1");
txn.add_compare_value("/test/x2", "2");

// or, compare the last modified revision
txn.add_compare_mod("/test/x3", 0); // not exists
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

txn.reset_key("/test/x2");
txn.init_compare("2", etcdv3::CompareResult::EQUAL, etcdv3::CompareTarget::VALUE);
```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),
Expand Down
5 changes: 4 additions & 1 deletion etcd-cpp-api-config.in.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,8 @@ set(ETCD_CPP_INCLUDE_DIRS "${ETCD_CPP_INCLUDE_DIR}")
include(FindPackageMessage)
find_package_message(etcd
"Found etcd: ${CMAKE_CURRENT_LIST_FILE} (found version \"@etcd-cpp-api_VERSION@\")"
"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 version: @etcd-cpp-api_VERSION@\n"
"etcd-cpp-apiv3 libraries: ${ETCD_CPP_LIBRARIES}\n"
"etcd-cpp-apiv3 core libraries: ${ETCD_CPP_CORE_LIBRARIES}\n"
"include directories: ${ETCD_CPP_INCLUDE_DIRS}"
)
74 changes: 24 additions & 50 deletions etcd/Client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,15 +271,6 @@ class Client {
*/
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
* created if it does not exists.
Expand All @@ -288,15 +279,7 @@ class Client {
* @param leaseId is the lease attached to the key
*/
pplx::task<Response> set(std::string const& key, std::string const& value,
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);
const int64_t leaseId = 0);

/**
* Creates a new key and sets it's value. Fails if the key already exists.
Expand All @@ -305,7 +288,7 @@ class Client {
* @param leaseId is the lease attached to the key
*/
pplx::task<Response> add(std::string const& key, std::string const& value,
int64_t leaseId);
const int64_t leaseId = 0);

/**
* Put a new key-value pair.
Expand All @@ -315,12 +298,13 @@ class Client {
pplx::task<Response> put(std::string const& key, std::string const& value);

/**
* Modifies an existing key. Fails if the key does not exists.
* @param key is the key to be modified
* @param value is the new value to be set
* Put a new key-value pair.
* @param key is the key to be put
* @param value is the value to be put
* @param leaseId is the lease id to be associated with the key
*/
pplx::task<Response> modify(std::string const& key, std::string const& value,
int ttl = 0);
pplx::task<Response> put(std::string const& key, std::string const& value,
const int64_t leaseId);

/**
* Modifies an existing key. Fails if the key does not exists.
Expand All @@ -329,18 +313,7 @@ class Client {
* @param leaseId is the lease attached to the key
*/
pplx::task<Response> modify(std::string const& key, std::string const& value,
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);
const int64_t leaseId = 0);

/**
* Modifies an existing key only if it has a specific value. Fails if the key
Expand All @@ -352,19 +325,8 @@ class Client {
*/
pplx::task<Response> modify_if(std::string const& key,
std::string const& value,
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
*/
pplx::task<Response> modify_if(std::string const& key,
std::string const& value, int64_t old_index,
int ttl = 0);
std::string const& old_value,
const int64_t leaseId = 0);

/**
* Modifies an existing key only if it has a specific modification index
Expand All @@ -377,18 +339,22 @@ class Client {
*/
pplx::task<Response> modify_if(std::string const& key,
std::string const& value, int64_t old_index,
int64_t leaseId);
const int64_t leaseId = 0);

/**
* Removes a single key. The key has to point to a plain, non directory entry.
* @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);

/**
* 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.
* @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,
std::string const& old_value);
Expand All @@ -399,6 +365,8 @@ class Client {
* from the expected one.
* @param key is the key to be deleted
* @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);

Expand All @@ -408,6 +376,8 @@ class Client {
* @param key is the directory to be created to be listed
* @param recursive if true then delete a whole subtree, otherwise deletes
* 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);

Expand All @@ -419,6 +389,8 @@ class Client {
*
* @param key is the directory to be created to be listed
* @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);

Expand All @@ -427,6 +399,8 @@ class Client {
*
* @param key is the directory to be created to be listed
* @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,
std::string const& range_end);
Expand Down
Loading

0 comments on commit 153546f

Please sign in to comment.