Refine source code, improve the quality and readability.

Signed-off-by: Tao He <sighingnow@gmail.com>
This commit is contained in:
Tao He 2021-09-15 14:18:04 +08:00
parent 42c2fdf58c
commit 4d6d0e2732
42 changed files with 344 additions and 251 deletions

View File

@ -125,10 +125,9 @@ install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/etcd/Client.hpp
${CMAKE_CURRENT_SOURCE_DIR}/etcd/Response.hpp
${CMAKE_CURRENT_SOURCE_DIR}/etcd/Value.hpp
${CMAKE_CURRENT_SOURCE_DIR}/etcd/Watcher.hpp
${CMAKE_CURRENT_BINARY_DIR}/proto/gen/proto/kv.pb.h
DESTINATION include/etcd)
install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/etcd/v3/Transaction.hpp
${CMAKE_CURRENT_BINARY_DIR}/proto/gen/proto/txn.pb.h
install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/etcd/v3/action_constants.hpp
${CMAKE_CURRENT_SOURCE_DIR}/etcd/v3/Transaction.hpp
DESTINATION include/etcd/v3)
configure_file(etcd-cpp-api-config.in.cmake
@ -201,8 +200,8 @@ set(CPACK_DEBIAN_PACKAGE_INSTALL "/usr/lib/lib*.so*"
"/usr/lib/cmake/etcd-cpp-api/*.cmake"
"/usr/include/etcd/*.h"
"/usr/include/etcd/*.hpp"
"/usr/include/etcd/v3/*.h"
"/usr/include/etcd/v3/*.hpp"
"/usr/include/etcd/v3/action_constants.hpp"
"/usr/include/etcd/v3/Transaction.hpp"
)
set(CPACK_DEBIAN_PACKAGE_BUILD_NUMBER_PREFIX "")

111
README.md
View File

@ -11,9 +11,11 @@ i.e., `ETCDCTL_API=3`.
+ **Linux**
- Ubuntu 18.04, requires upgrade gRPC libraries (has been tested with 1.27.x).
- Ubuntu 20.04
+ **MacOS**
- MacOS 10.15
- MacOS 11.0
+ **Windows**
- Windows 10, with [vcpkg](https://github.com/microsoft/vcpkg)
@ -85,13 +87,13 @@ Github when you encounter problems when working with etcd 3.x releases.
```
Methods of the etcd client object are sending the corresponding gRPC requests and are returning
immediately with a ```pplx::task``` object. The task object is responsible for handling the
immediately with a `pplx::task` object. The task object is responsible for handling the
reception of the HTTP response as well as parsing the gRPC of the response. All of this is done
asynchronously in a background thread so you can continue your code to do other operations while the
current etcd operation is executing in the background or you can wait for the response with the
```wait()``` or ```get()``` methods if a synchronous behavior is enough for your needs. These methods
are blocking until the HTTP response arrives or some error situation happens. ```get()``` method
also returns the ```etcd::Response``` object.
`wait()` or `get()` methods if a synchronous behavior is enough for your needs. These methods
are blocking until the HTTP response arrives or some error situation happens. `get()` method
also returns the `etcd::Response` object.
```c++
etcd::Client etcd("http://127.0.0.1:4001");
@ -103,9 +105,9 @@ also returns the ```etcd::Response``` object.
The pplx library allows to do even more. You can attach continuation objects to the task if you do
not care about when the response is coming you only want to specify what to do then. This
can be achieved by calling the ```then``` method of the task, giving a function object parameter to
can be achieved by calling the `then` method of the task, giving a function object parameter to
it that can be used as a callback when the response is arrived and processed. The parameter of this
callback should be either a ```etcd::Response``` or a ```pplx::task<etcd:Response>```. You should
callback should be either a `etcd::Response` or a `pplx::task<etcd:Response>`. You should
probably use a C++ lambda function here as a callback.
```c++
@ -118,10 +120,10 @@ probably use a C++ lambda function here as a callback.
// ... your code can continue here without any delay
```
Your lambda function should have a parameter of type ```etcd::Response``` or
```pplx::task<etcd::Response>```. In the latter case you can get the actual ```etcd::Response```
object with the ```get()``` function of the task. Calling get can raise exceptions so this is the way
how you can catch the errors generated by the REST interface. The ```get()``` call will not block in
Your lambda function should have a parameter of type `etcd::Response` or
`pplx::task<etcd::Response>`. In the latter case you can get the actual `etcd::Response`
object with the `get()` function of the task. Calling get can raise exceptions so this is the way
how you can catch the errors generated by the REST interface. The `get()` call will not block in
this case since the response has been already arrived (we are inside the callback).
```c++
@ -238,21 +240,21 @@ We also provide a tool [`setup-ca.sh`](./security-config/setup-ca.sh) as a helpe
### Reading a value
You can read a value with the ```get``` method of the client instance. The only parameter is the
You can read a value with the `get()` method of the client instance. The only parameter is the
key to be read. If the read operation is successful then the value of the key can be acquired with
the ```value()``` method of the response. Success of the operation can be checked with the
```is_ok()``` method of the response. In case of an error, the ```error_code()``` and
```error_message()``` methods can be called for some further detail.
the `value()` method of the response. Success of the operation can be checked with the
`is_ok()` method of the response. In case of an error, the `error_code()` and
`error_message()` methods can be called for some further detail.
Please note that there can be two kind of error situations. There can be some problem with the
communication between the client and the etcd server. In this case the ```get()``` method of the
communication between the client and the etcd server. In this case the `get()``` method of the
response task will throw an exception as shown above. If the communication is ok but there is some
problem with the content of the actual operation, like attempting to read a non-existing key then the
response object will give you all the details. Let's see this in an example.
The Value object of the response also holds some extra information besides the string value of the
key. You can also get the index number of the creation and the last modification of this key with
the ```created_index()``` and the ```modified_index()``` methods.
the `created_index()` and the `modified_index()` methods.
```c++
etcd::Client etcd("http://127.0.0.1:4001");
@ -274,12 +276,12 @@ the ```created_index()``` and the ```modified_index()``` methods.
### Modifying a value
Setting the value of a key can be done with the ```set()``` method of the client. You simply pass
Setting the value of a key can be done with the `set()` method of the client. You simply pass
the key and the value as string parameters and you are done. The newly set value object can be asked
from the response object exactly the same way as in case of the reading (with the ```value()```
from the response object exactly the same way as in case of the reading (with the `value()`
method). This way you can check for example the index value of your modification. You can also check
what was the previous value that this operation was overwritten. You can do that with the
```prev_value()``` method of the response object.
`prev_value()` method of the response object.
```c++
etcd::Client etcd("http://127.0.0.1:4001");
@ -304,28 +306,28 @@ The set method creates a new leaf node if it weren't exists already or modifies
There are a couple of other modification methods that are executing the write operation only upon
some specific conditions.
* ```add(key, value)``` creates a new value if it's key does not exists and returns a "Key
already exists" error otherwise (error code 105)
* ```modify(key, value)``` modifies an already existing value or returns a "Key not found" error
otherwise (error code 100)
* ```modify_if(key, value, old_value)``` modifies an already existing value but only if the previous
* `add(key, value)` creates a new value if it's key does not exists and returns a "Key
already exists" error otherwise (error code `ERROR_KEY_ALREADY_EXISTS`)
* `modify(key, value)` modifies an already existing value or returns a "Key not found" error
otherwise (error code `KEY_NOT_FOUND`)
* `modify_if(key, value, old_value)` modifies 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 101)
* ```modify_if(key, value, old_index)``` modifies an already existing value but only if the index of
(code `ERROR_COMPARE_FAILED`)
* `modify_if(key, value, old_index)` modifies 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
failed" error (code 101)
failed" error (code `ERROR_COMPARE_FAILED`)
### Deleting a value
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.
* ```rm_if(key, value, old_value)``` deletes an already existing value but only if the previous
* `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 101)
* ```rm_if(key, value, old_index)``` deletes an already existing value but only if the index of
(code `ERROR_COMPARE_FAILED`)
* `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
failed" error (code 101)
failed" error (code `ERROR_COMPARE_FAILED`)
### Handling directory nodes
@ -367,10 +369,9 @@ keys defined by the prefix. mkdir method is removed since etcdv3 treats everythi
+ While in etcdv2 cpp client it will return "key1" and "/test/new_dir" directory should
be created first before you can set "key1".
When you list a directory the response object's ```keys()``` and ```values()``` methods gives
you a vector of key names and values. The ```value()``` method with an integer parameter also
returns with the i-th element of the values vector, so ```response.values()[i] ==
response.value(i)```.
When you list a directory the response object's `keys()` and `values()` methods gives
you a vector of key names and values. The `value()` method with an integer parameter also
returns with the i-th element of the values vector, so `response.values()[i] == response.value(i)`.
```c++
etcd::Client etcd("http://127.0.0.1:4001");
@ -384,10 +385,10 @@ keys defined by the prefix. mkdir method is removed since etcdv3 treats everythi
3. Removing directory:
If you want the delete recursively then you have to pass a second ```true``` parameter
If you want the delete recursively then you have to pass a second `true` parameter
to rmdir and supply a key. This key will be treated as a prefix. All keys that match the
prefix will be deleted. All deleted keys will be placed in ```response.values()``` and
```response.keys()```. This parameter defaults to ```false```.
prefix will be deleted. All deleted keys will be placed in `response.values()` and
`response.keys()`. This parameter defaults to `false`.
```c++
etcd::Client etcd("http://127.0.0.1:4001");
@ -426,22 +427,22 @@ Users can also feed their own lease directory for lock:
### Watching for changes
Watching for a change is possible with the ```watch()``` operation of the client. The watch method
Watching for a change is possible with the `watch()` operation of the client. The watch method
simply does not deliver a response object until the watched value changes in any way (modified or
deleted). When a change happens the returned result object will be the same as the result object of
the modification operation. So if the change is triggered by a value change, then
```response.action()``` will return "set", ```response.value()``` will hold the new
value and ```response.prev_value()``` will contain the previous value. In case of a delete
```response.action()``` will return "delete", ```response.value()``` will be empty and should not be
called at all and ```response.prev_value()``` will contain the deleted value.
`response.action()` will return "set", `response.value()` will hold the new
value and `response.prev_value()` will contain the previous value. In case of a delete
`response.action()` will return "delete", `response.value()` will be empty and should not be
called at all and `response.prev_value()` will contain the deleted value.
As mentioned in the section "handling directory nodes", directory nodes are not supported anymore
in etcdv3.
However it is still possible to watch a whole "directory subtree", or more specifically a set of
keys that match the prefix, for changes with passing ```true``` to the second ```recursive```
parameter of ```watch``` (this parameter defaults to ```false``` if omitted). In this case the
modified value object's ```key()``` method can be handy to determine what key is actually changed.
keys that match the prefix, for changes with passing `true` to the second `recursive`
parameter of `watch` (this parameter defaults to `false` if omitted). In this case the
modified value object's `key()` method can be handy to determine what key is actually changed.
Since this can be a long lasting operation you have to be prepared that is terminated by an
exception and you have to restart the watch operation.
@ -468,17 +469,17 @@ void watch_for_changes()
}
```
At first glance it seems that ```watch_for_changes()``` calls itself on every value change but in
At first glance it seems that `watch_for_changes()` calls itself on every value change but in
fact it just sends the asynchronous request, sets up a callback for the response and then returns. The
callback is executed by some thread from the pplx library's thread pool and the callback (in this
case a small lambda function actually) will call ```watch_for_changes``` again from there.
case a small lambda function actually) will call `watch_for_changes()` again from there.
#### Watcher Class
Users can watch a key indefinitely or until user cancels the watch. This can be done by
instantiating a Watcher class. The supplied callback function in Watcher class will be
called every time there is an event for the specified key. Watch stream will be cancelled
either by user implicitly calling ```Cancel()``` or when watcher class is destroyed.
either by user implicitly calling `Cancel()` or when watcher class is destroyed.
```c++
etcd::Watcher watcher("http://127.0.0.1:2379", "/test", printResponse);
@ -491,7 +492,9 @@ either by user implicitly calling ```Cancel()``` or when watcher class is destro
#### Watcher re-connection
A watcher will be disconnected from etcd server in some cases, for some examples, the etcd server is restarted, or the network is temporarily unavailable. It is users' responsibility to decide if a watcher should re-connect to the etcd server.
A watcher will be disconnected from etcd server in some cases, for some examples, the etcd
server is restarted, or the network is temporarily unavailable. It is users' responsibility
to decide if a watcher should re-connect to the etcd server.
Here is an example how users can make a watcher re-connect to server after disconnected.
@ -534,9 +537,9 @@ initialize_watcher(endpoints, prefix, callback, watcher);
### Requesting for lease
Users can request for lease which is governed by a time-to-live(TTL) value given by the user.
Moreover, user can attached the lease to a key(s) by indicating the lease id in ```add()```,
```set()```, ```modify()``` and ```modify_if()```. Also the ttl will that was granted by etcd
server will be indicated in ```ttl()```.
Moreover, user can attached the lease to a key(s) by indicating the lease id in `add()`,
`set()`, `modify()` and `modify_if()`. Also the ttl will that was granted by etcd
server will be indicated in `ttl()`.
```c++
etcd::Client etcd("http://127.0.0.1:4001");

View File

@ -8,6 +8,7 @@
#include "pplx/pplxtasks.h"
#include "etcd/Response.hpp"
#include "etcd/v3/action_constants.hpp"
namespace etcdv3 {
class Transaction;
@ -29,6 +30,10 @@ namespace grpc_impl {
namespace etcd
{
using etcdv3::ERROR_KEY_NOT_FOUND;
using etcdv3::ERROR_COMPARE_FAILED;
using etcdv3::ERROR_KEY_ALREADY_EXISTS;
class KeepAlive;
class Watcher;

View File

@ -18,7 +18,7 @@ using v3lockpb::Lock;
namespace etcdv3
{
enum Atomicity_Type
enum AtomicityType
{
PREV_INDEX = 0,
PREV_VALUE = 1
@ -47,7 +47,7 @@ namespace etcdv3
class Action
{
public:
Action(etcdv3::ActionParameters params);
Action(etcdv3::ActionParameters const &params);
void waitForResponse();
const std::chrono::high_resolution_clock::time_point startTimepoint();
protected:

View File

@ -16,7 +16,7 @@ namespace etcdv3
class AsyncCompareAndDeleteAction : public etcdv3::Action
{
public:
AsyncCompareAndDeleteAction(etcdv3::ActionParameters param, etcdv3::Atomicity_Type type);
AsyncCompareAndDeleteAction(etcdv3::ActionParameters const &param, etcdv3::AtomicityType type);
AsyncTxnResponse ParseResponse();
private:
TxnResponse reply;

View File

@ -16,7 +16,7 @@ namespace etcdv3
class AsyncCompareAndSwapAction : public etcdv3::Action
{
public:
AsyncCompareAndSwapAction(etcdv3::ActionParameters param, etcdv3::Atomicity_Type type);
AsyncCompareAndSwapAction(etcdv3::ActionParameters const &param, etcdv3::AtomicityType type);
AsyncTxnResponse ParseResponse();
private:
TxnResponse reply;

View File

@ -15,7 +15,7 @@ namespace etcdv3
class AsyncDeleteAction : public etcdv3::Action
{
public:
AsyncDeleteAction(etcdv3::ActionParameters param);
AsyncDeleteAction(etcdv3::ActionParameters const &param);
AsyncDeleteRangeResponse ParseResponse();
private:
DeleteRangeResponse reply;

View File

@ -15,7 +15,7 @@ namespace etcdv3
class AsyncHeadAction : public etcdv3::Action
{
public:
AsyncHeadAction(etcdv3::ActionParameters param);
AsyncHeadAction(etcdv3::ActionParameters const &param);
AsyncHeadResponse ParseResponse();
private:
RangeResponse reply;

View File

@ -15,7 +15,7 @@ namespace etcdv3
{
public:
AsyncHeadResponse(){};
void ParseResponse(RangeResponse& resp, bool prefix=false);
void ParseResponse(RangeResponse& resp);
};
}

View File

@ -25,7 +25,7 @@ namespace etcdv3
{
class AsyncLeaseGrantAction : public etcdv3::Action {
public:
AsyncLeaseGrantAction(etcdv3::ActionParameters param);
AsyncLeaseGrantAction(etcdv3::ActionParameters const &param);
AsyncLeaseGrantResponse ParseResponse();
private:
LeaseGrantResponse reply;
@ -34,7 +34,7 @@ namespace etcdv3
class AsyncLeaseRevokeAction: public etcdv3::Action {
public:
AsyncLeaseRevokeAction(etcdv3::ActionParameters param);
AsyncLeaseRevokeAction(etcdv3::ActionParameters const &param);
AsyncLeaseRevokeResponse ParseResponse();
private:
LeaseRevokeResponse reply;
@ -43,7 +43,7 @@ namespace etcdv3
class AsyncLeaseKeepAliveAction: public etcdv3::Action {
public:
AsyncLeaseKeepAliveAction(etcdv3::ActionParameters param);
AsyncLeaseKeepAliveAction(etcdv3::ActionParameters const &param);
AsyncLeaseKeepAliveResponse ParseResponse();
etcd::Response Refresh();
@ -61,7 +61,7 @@ namespace etcdv3
class AsyncLeaseTimeToLiveAction: public etcdv3::Action {
public:
AsyncLeaseTimeToLiveAction(etcdv3::ActionParameters param);
AsyncLeaseTimeToLiveAction(etcdv3::ActionParameters const &param);
AsyncLeaseTimeToLiveResponse ParseResponse();
private:
LeaseTimeToLiveResponse reply;
@ -70,7 +70,7 @@ namespace etcdv3
class AsyncLeaseLeasesAction: public etcdv3::Action {
public:
AsyncLeaseLeasesAction(etcdv3::ActionParameters param);
AsyncLeaseLeasesAction(etcdv3::ActionParameters const &param);
AsyncLeaseLeasesResponse ParseResponse();
private:
LeaseLeasesResponse reply;

View File

@ -20,7 +20,7 @@ namespace etcdv3
class AsyncLockAction : public etcdv3::Action
{
public:
AsyncLockAction(etcdv3::ActionParameters param);
AsyncLockAction(etcdv3::ActionParameters const &param);
AsyncLockResponse ParseResponse();
private:
LockResponse reply;
@ -30,7 +30,7 @@ namespace etcdv3
class AsyncUnlockAction : public etcdv3::Action
{
public:
AsyncUnlockAction(etcdv3::ActionParameters param);
AsyncUnlockAction(etcdv3::ActionParameters const &param);
AsyncUnlockResponse ParseResponse();
private:
UnlockResponse reply;

View File

@ -15,7 +15,7 @@ namespace etcdv3
class AsyncRangeAction : public etcdv3::Action
{
public:
AsyncRangeAction(etcdv3::ActionParameters param);
AsyncRangeAction(etcdv3::ActionParameters const &param);
AsyncRangeResponse ParseResponse();
private:
RangeResponse reply;

View File

@ -16,7 +16,7 @@ namespace etcdv3
class AsyncSetAction : public etcdv3::Action
{
public:
AsyncSetAction(etcdv3::ActionParameters param, bool create=false);
AsyncSetAction(etcdv3::ActionParameters const &param, bool create=false);
AsyncTxnResponse ParseResponse();
private:
TxnResponse reply;

View File

@ -9,6 +9,7 @@
using grpc::ClientAsyncResponseReader;
using etcdserverpb::TxnRequest;
using etcdserverpb::TxnResponse;
using etcdserverpb::KV;
@ -17,7 +18,7 @@ namespace etcdv3
class AsyncTxnAction : public etcdv3::Action
{
public:
AsyncTxnAction(etcdv3::ActionParameters param, etcdv3::Transaction const &tx);
AsyncTxnAction(etcdv3::ActionParameters const &param, etcdv3::Transaction const &tx);
AsyncTxnResponse ParseResponse();
private:
TxnResponse reply;

View File

@ -16,7 +16,7 @@ namespace etcdv3
class AsyncUpdateAction : public etcdv3::Action
{
public:
AsyncUpdateAction(etcdv3::ActionParameters param);
AsyncUpdateAction(etcdv3::ActionParameters const &param);
AsyncTxnResponse ParseResponse();
private:
TxnResponse reply;

View File

@ -19,7 +19,7 @@ namespace etcdv3
class AsyncWatchAction : public etcdv3::Action
{
public:
AsyncWatchAction(etcdv3::ActionParameters param);
AsyncWatchAction(etcdv3::ActionParameters const &param);
AsyncWatchResponse ParseResponse();
void waitForResponse();
void waitForResponse(std::function<void(etcd::Response)> callback);

View File

@ -3,22 +3,35 @@
#include <string>
#include "txn.pb.h"
namespace etcdserverpb {
class TxnRequest;
}
namespace etcdv3 {
enum class CompareResult {
EQUAL = 0,
GREATER = 1,
LESS = 2,
NOT_EQUAL = 3,
};
enum class CompareTarget {
VERSION = 0,
CREATE = 1,
MOD = 2,
VALUE = 3,
LEASE = 4,
};
class Transaction {
public:
Transaction();
Transaction(std::string const&);
virtual ~Transaction();
void init_compare(etcdserverpb::Compare::CompareResult, etcdserverpb::Compare::CompareTarget);
void init_compare(std::string const &, etcdserverpb::Compare::CompareResult, etcdserverpb::Compare::CompareTarget);
void init_compare(int, etcdserverpb::Compare::CompareResult, etcdserverpb::Compare::CompareTarget);
void init_compare(CompareResult, CompareTarget);
void init_compare(std::string const &old_value, CompareResult, CompareTarget);
void init_compare(int old_value, CompareResult, CompareTarget);
void setup_basic_failure_operation(std::string const &key);
void setup_set_failure_operation(std::string const &key, std::string const &value, int64_t leaseid);

View File

@ -13,6 +13,13 @@ namespace etcdv3
extern char const * LOCK_ACTION;
extern char const * UNLOCK_ACTION;
extern char const * TXN_ACTION;
extern char const * WATCH_ACTION;
extern char const * LEASEGRANT;
extern char const * LEASEREVOKE;
extern char const * LEASEKEEPALIVE;
extern char const * LEASETIMETOLIVE;
extern char const * LEASELEASES;
extern char const * NUL;
@ -24,6 +31,10 @@ namespace etcdv3
extern char const * WATCH_CREATE;
extern char const * WATCH_WRITE;
extern char const * WATCH_WRITES_DONE;
extern const int ERROR_KEY_NOT_FOUND;
extern const int ERROR_COMPARE_FAILED;
extern const int ERROR_KEY_ALREADY_EXISTS;
}
#endif

View File

@ -4,7 +4,6 @@ package etcdserverpb;
import "gogoproto/gogo.proto";
import "kv.proto";
import "auth.proto";
import "txn.proto";
// for grpc-gateway
import "google/api/annotations.proto";
@ -533,6 +532,46 @@ message ResponseOp {
}
}
message Compare {
enum CompareResult {
EQUAL = 0;
GREATER = 1;
LESS = 2;
NOT_EQUAL = 3;
}
enum CompareTarget {
VERSION = 0;
CREATE = 1;
MOD = 2;
VALUE = 3;
LEASE = 4;
}
// result is logical comparison operation for this comparison.
CompareResult result = 1;
// target is the key-value field to inspect for the comparison.
CompareTarget target = 2;
// key is the subject key for the comparison operation.
bytes key = 3;
oneof target_union {
// version is the version of the given key
int64 version = 4;
// create_revision is the creation revision of the given key
int64 create_revision = 5;
// mod_revision is the last modified revision of the given key.
int64 mod_revision = 6;
// value is the value of the given key, in bytes.
bytes value = 7;
// lease is the lease id of the given key.
int64 lease = 8;
// leave room for more target_union field tags, jump to 64
}
// range_end compares the given target to all keys in the range [key, range_end).
// See RangeRequest for more details on key ranges.
bytes range_end = 64;
// TODO: fill out with most of the rest of RangeRequest fields when needed.
}
// From google paxosdb paper:
// Our implementation hinges around a powerful primitive which we call MultiOp. All other database
// operations except for iteration are implemented as a single call to MultiOp. A MultiOp is applied atomically

View File

@ -1,42 +0,0 @@
syntax = "proto3";
package etcdserverpb;
message Compare {
enum CompareResult {
EQUAL = 0;
GREATER = 1;
LESS = 2;
NOT_EQUAL = 3;
}
enum CompareTarget {
VERSION = 0;
CREATE = 1;
MOD = 2;
VALUE = 3;
LEASE = 4;
}
// result is logical comparison operation for this comparison.
CompareResult result = 1;
// target is the key-value field to inspect for the comparison.
CompareTarget target = 2;
// key is the subject key for the comparison operation.
bytes key = 3;
oneof target_union {
// version is the version of the given key
int64 version = 4;
// create_revision is the creation revision of the given key
int64 create_revision = 5;
// mod_revision is the last modified revision of the given key.
int64 mod_revision = 6;
// value is the value of the given key, in bytes.
bytes value = 7;
// lease is the lease id of the given key.
int64 lease = 8;
// leave room for more target_union field tags, jump to 64
}
// range_end compares the given target to all keys in the range [key, range_end).
// See RangeRequest for more details on key ranges.
bytes range_end = 64;
// TODO: fill out with most of the rest of RangeRequest fields when needed.
}

View File

@ -428,7 +428,8 @@ pplx::task<etcd::Response> etcd::Client::modify_if(std::string const & key, std:
params.lease_id = res.value().lease();
}
}
std::shared_ptr<etcdv3::AsyncCompareAndSwapAction> call(new etcdv3::AsyncCompareAndSwapAction(params,etcdv3::Atomicity_Type::PREV_VALUE));
std::shared_ptr<etcdv3::AsyncCompareAndSwapAction> call(
new etcdv3::AsyncCompareAndSwapAction(params,etcdv3::AtomicityType::PREV_VALUE));
return Response::create(call);
}
@ -441,7 +442,8 @@ pplx::task<etcd::Response> etcd::Client::modify_if(std::string const & key, std:
params.old_value.assign(old_value);
params.lease_id = leaseid;
params.kv_stub = stubs->kvServiceStub.get();
std::shared_ptr<etcdv3::AsyncCompareAndSwapAction> call(new etcdv3::AsyncCompareAndSwapAction(params,etcdv3::Atomicity_Type::PREV_VALUE));
std::shared_ptr<etcdv3::AsyncCompareAndSwapAction> call(
new etcdv3::AsyncCompareAndSwapAction(params,etcdv3::AtomicityType::PREV_VALUE));
return Response::create(call);
}
@ -468,7 +470,8 @@ pplx::task<etcd::Response> etcd::Client::modify_if(std::string const & key, std:
params.lease_id = res.value().lease();
}
}
std::shared_ptr<etcdv3::AsyncCompareAndSwapAction> call(new etcdv3::AsyncCompareAndSwapAction(params,etcdv3::Atomicity_Type::PREV_INDEX));
std::shared_ptr<etcdv3::AsyncCompareAndSwapAction> call(
new etcdv3::AsyncCompareAndSwapAction(params,etcdv3::AtomicityType::PREV_INDEX));
return Response::create(call);
}
@ -481,7 +484,8 @@ pplx::task<etcd::Response> etcd::Client::modify_if(std::string const & key, std:
params.lease_id = leaseid;
params.old_revision = old_index;
params.kv_stub = stubs->kvServiceStub.get();
std::shared_ptr<etcdv3::AsyncCompareAndSwapAction> call(new etcdv3::AsyncCompareAndSwapAction(params,etcdv3::Atomicity_Type::PREV_INDEX));
std::shared_ptr<etcdv3::AsyncCompareAndSwapAction> call(
new etcdv3::AsyncCompareAndSwapAction(params,etcdv3::AtomicityType::PREV_INDEX));
return Response::create(call);
}
@ -504,7 +508,8 @@ pplx::task<etcd::Response> etcd::Client::rm_if(std::string const & key, std::str
params.key.assign(key);
params.old_value.assign(old_value);
params.kv_stub = stubs->kvServiceStub.get();
std::shared_ptr<etcdv3::AsyncCompareAndDeleteAction> call(new etcdv3::AsyncCompareAndDeleteAction(params,etcdv3::Atomicity_Type::PREV_VALUE));
std::shared_ptr<etcdv3::AsyncCompareAndDeleteAction> call(
new etcdv3::AsyncCompareAndDeleteAction(params,etcdv3::AtomicityType::PREV_VALUE));
return Response::create(call);
}
@ -515,7 +520,8 @@ pplx::task<etcd::Response> etcd::Client::rm_if(std::string const & key, int old_
params.key.assign(key);
params.old_revision = old_index;
params.kv_stub = stubs->kvServiceStub.get();
std::shared_ptr<etcdv3::AsyncCompareAndDeleteAction> call(new etcdv3::AsyncCompareAndDeleteAction(params, etcdv3::Atomicity_Type::PREV_INDEX));;
std::shared_ptr<etcdv3::AsyncCompareAndDeleteAction> call(
new etcdv3::AsyncCompareAndDeleteAction(params, etcdv3::AtomicityType::PREV_INDEX));;
return Response::create(call);
}

View File

@ -2,7 +2,7 @@
#include "etcd/v3/action_constants.hpp"
#include "etcd/v3/Action.hpp"
etcdv3::Action::Action(etcdv3::ActionParameters params)
etcdv3::Action::Action(etcdv3::ActionParameters const &params)
{
parameters = params;
if (!parameters.auth_token.empty()) {

View File

@ -1,27 +1,30 @@
#include "etcd/v3/AsyncCompareAndDeleteAction.hpp"
#include "etcd/v3/action_constants.hpp"
#include "etcd/v3/Transaction.hpp"
using etcdserverpb::Compare;
using etcdserverpb::RangeRequest;
using etcdserverpb::PutRequest;
using etcdserverpb::RequestOp;
using etcdserverpb::ResponseOp;
using etcdserverpb::TxnRequest;
etcdv3::AsyncCompareAndDeleteAction::AsyncCompareAndDeleteAction(etcdv3::ActionParameters param, etcdv3::Atomicity_Type type)
etcdv3::AsyncCompareAndDeleteAction::AsyncCompareAndDeleteAction(
etcdv3::ActionParameters const &param, etcdv3::AtomicityType type)
:etcdv3::Action(param)
{
etcdv3::Transaction transaction(parameters.key);
if(type == etcdv3::Atomicity_Type::PREV_VALUE)
if(type == etcdv3::AtomicityType::PREV_VALUE)
{
transaction.init_compare(parameters.old_value, Compare::CompareResult::Compare_CompareResult_EQUAL,
Compare::CompareTarget::Compare_CompareTarget_VALUE);
transaction.init_compare(parameters.old_value,
CompareResult::EQUAL,
CompareTarget::VALUE);
}
else if (type == etcdv3::Atomicity_Type::PREV_INDEX)
else if (type == etcdv3::AtomicityType::PREV_INDEX)
{
transaction.init_compare(parameters.old_revision, Compare::CompareResult::Compare_CompareResult_EQUAL,
Compare::CompareTarget::Compare_CompareTarget_MOD);
transaction.init_compare(parameters.old_revision,
CompareResult::EQUAL,
CompareTarget::MOD);
}
transaction.setup_compare_and_delete_operation(parameters.key);
@ -34,6 +37,8 @@ etcdv3::AsyncCompareAndDeleteAction::AsyncCompareAndDeleteAction(etcdv3::ActionP
etcdv3::AsyncTxnResponse etcdv3::AsyncCompareAndDeleteAction::ParseResponse()
{
AsyncTxnResponse txn_resp;
txn_resp.set_action(etcdv3::COMPAREDELETE_ACTION);
if(!status.ok())
{
txn_resp.set_error_code(status.error_code());
@ -42,11 +47,10 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncCompareAndDeleteAction::ParseResponse()
else
{
txn_resp.ParseResponse(parameters.key, parameters.withPrefix, reply);
txn_resp.set_action(etcdv3::COMPAREDELETE_ACTION);
if(!reply.succeeded())
{
txn_resp.set_error_code(101);
txn_resp.set_error_code(ERROR_COMPARE_FAILED);
txn_resp.set_error_message("Compare failed");
}
}

View File

@ -1,27 +1,30 @@
#include "etcd/v3/AsyncCompareAndSwapAction.hpp"
#include "etcd/v3/action_constants.hpp"
#include "etcd/v3/Transaction.hpp"
using etcdserverpb::Compare;
using etcdserverpb::RangeRequest;
using etcdserverpb::PutRequest;
using etcdserverpb::RequestOp;
using etcdserverpb::ResponseOp;
using etcdserverpb::TxnRequest;
etcdv3::AsyncCompareAndSwapAction::AsyncCompareAndSwapAction(etcdv3::ActionParameters param, etcdv3::Atomicity_Type type)
etcdv3::AsyncCompareAndSwapAction::AsyncCompareAndSwapAction(
etcdv3::ActionParameters const &param, etcdv3::AtomicityType type)
: etcdv3::Action(param)
{
etcdv3::Transaction transaction(parameters.key);
if(type == etcdv3::Atomicity_Type::PREV_VALUE)
if(type == etcdv3::AtomicityType::PREV_VALUE)
{
transaction.init_compare(parameters.old_value, Compare::CompareResult::Compare_CompareResult_EQUAL,
Compare::CompareTarget::Compare_CompareTarget_VALUE);
transaction.init_compare(parameters.old_value,
CompareResult::EQUAL,
CompareTarget::VALUE);
}
else if (type == etcdv3::Atomicity_Type::PREV_INDEX)
else if (type == etcdv3::AtomicityType::PREV_INDEX)
{
transaction.init_compare(parameters.old_revision, Compare::CompareResult::Compare_CompareResult_EQUAL,
Compare::CompareTarget::Compare_CompareTarget_MOD);
transaction.init_compare(parameters.old_revision,
CompareResult::EQUAL,
CompareTarget::MOD);
}
transaction.setup_basic_failure_operation(parameters.key);
@ -34,6 +37,7 @@ etcdv3::AsyncCompareAndSwapAction::AsyncCompareAndSwapAction(etcdv3::ActionParam
etcdv3::AsyncTxnResponse etcdv3::AsyncCompareAndSwapAction::ParseResponse()
{
AsyncTxnResponse txn_resp;
txn_resp.set_action(etcdv3::COMPARESWAP_ACTION);
if(!status.ok())
{
@ -43,13 +47,12 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncCompareAndSwapAction::ParseResponse()
else
{
txn_resp.ParseResponse(parameters.key, parameters.withPrefix, reply);
txn_resp.set_action(etcdv3::COMPARESWAP_ACTION);
//if there is an error code returned by parseResponse, we must
//not overwrite it.
if(!reply.succeeded() && !txn_resp.get_error_code())
{
txn_resp.set_error_code(101);
txn_resp.set_error_code(ERROR_COMPARE_FAILED);
txn_resp.set_error_message("Compare failed");
}
}

View File

@ -3,7 +3,8 @@
using etcdserverpb::DeleteRangeRequest;
etcdv3::AsyncDeleteAction::AsyncDeleteAction(ActionParameters param)
etcdv3::AsyncDeleteAction::AsyncDeleteAction(
ActionParameters const &param)
: etcdv3::Action(param)
{
DeleteRangeRequest del_request;
@ -28,6 +29,7 @@ etcdv3::AsyncDeleteAction::AsyncDeleteAction(ActionParameters param)
etcdv3::AsyncDeleteRangeResponse etcdv3::AsyncDeleteAction::ParseResponse()
{
AsyncDeleteRangeResponse del_resp;
del_resp.set_action(etcdv3::DELETE_ACTION);
if(!status.ok())
{

View File

@ -8,12 +8,11 @@ void etcdv3::AsyncDeleteRangeResponse::ParseResponse(std::string const& key, boo
if(resp.prev_kvs_size() == 0)
{
error_code=100;
error_code = etcdv3::ERROR_KEY_NOT_FOUND;
error_message = "Key not found";
}
else
{
action = etcdv3::DELETE_ACTION;
//get all previous values
for(int cnt=0; cnt < resp.prev_kvs_size(); cnt++)
{
@ -29,6 +28,5 @@ void etcdv3::AsyncDeleteRangeResponse::ParseResponse(std::string const& key, boo
value.kvs.clear_value();
values.clear();
}
}
}

View File

@ -6,7 +6,8 @@
using etcdserverpb::RangeRequest;
etcdv3::AsyncHeadAction::AsyncHeadAction(etcdv3::ActionParameters param)
etcdv3::AsyncHeadAction::AsyncHeadAction(
etcdv3::ActionParameters const &param)
: etcdv3::Action(param)
{
RangeRequest get_request;
@ -18,15 +19,17 @@ etcdv3::AsyncHeadAction::AsyncHeadAction(etcdv3::ActionParameters param)
etcdv3::AsyncHeadResponse etcdv3::AsyncHeadAction::ParseResponse()
{
AsyncHeadResponse range_resp;
AsyncHeadResponse head_resp;
head_resp.set_action(etcdv3::GET_ACTION);
if(!status.ok())
{
range_resp.set_error_code(status.error_code());
range_resp.set_error_message(status.error_message());
head_resp.set_error_code(status.error_code());
head_resp.set_error_message(status.error_message());
}
else
{
range_resp.ParseResponse(reply, parameters.withPrefix || !parameters.range_end.empty());
head_resp.ParseResponse(reply);
}
return range_resp;
return head_resp;
}

View File

@ -2,8 +2,7 @@
#include "etcd/v3/action_constants.hpp"
void etcdv3::AsyncHeadResponse::ParseResponse(RangeResponse& resp, bool prefix)
void etcdv3::AsyncHeadResponse::ParseResponse(RangeResponse& resp)
{
action = etcdv3::GET_ACTION;
index = resp.header().revision();
}

View File

@ -9,7 +9,8 @@ using etcdserverpb::LeaseKeepAliveRequest;
using etcdserverpb::LeaseTimeToLiveRequest;
using etcdserverpb::LeaseLeasesRequest;
etcdv3::AsyncLeaseGrantAction::AsyncLeaseGrantAction(etcdv3::ActionParameters param)
etcdv3::AsyncLeaseGrantAction::AsyncLeaseGrantAction(
etcdv3::ActionParameters const &param)
: etcdv3::Action(param)
{
LeaseGrantRequest leasegrant_request;
@ -24,6 +25,8 @@ etcdv3::AsyncLeaseGrantAction::AsyncLeaseGrantAction(etcdv3::ActionParameters pa
etcdv3::AsyncLeaseGrantResponse etcdv3::AsyncLeaseGrantAction::ParseResponse()
{
AsyncLeaseGrantResponse lease_resp;
lease_resp.set_action(etcdv3::LEASEGRANT);
if (!status.ok()) {
lease_resp.set_error_code(status.error_code());
lease_resp.set_error_message(status.error_message());
@ -33,7 +36,8 @@ etcdv3::AsyncLeaseGrantResponse etcdv3::AsyncLeaseGrantAction::ParseResponse()
return lease_resp;
}
etcdv3::AsyncLeaseRevokeAction::AsyncLeaseRevokeAction(etcdv3::ActionParameters param)
etcdv3::AsyncLeaseRevokeAction::AsyncLeaseRevokeAction(
etcdv3::ActionParameters const &param)
: etcdv3::Action(param)
{
LeaseRevokeRequest leaserevoke_request;
@ -46,6 +50,8 @@ etcdv3::AsyncLeaseRevokeAction::AsyncLeaseRevokeAction(etcdv3::ActionParameters
etcdv3::AsyncLeaseRevokeResponse etcdv3::AsyncLeaseRevokeAction::ParseResponse()
{
AsyncLeaseRevokeResponse lease_resp;
lease_resp.set_action(etcdv3::LEASEREVOKE);
if (!status.ok()) {
lease_resp.set_error_code(status.error_code());
lease_resp.set_error_message(status.error_message());
@ -55,7 +61,8 @@ etcdv3::AsyncLeaseRevokeResponse etcdv3::AsyncLeaseRevokeAction::ParseResponse()
return lease_resp;
}
etcdv3::AsyncLeaseKeepAliveAction::AsyncLeaseKeepAliveAction(etcdv3::ActionParameters param)
etcdv3::AsyncLeaseKeepAliveAction::AsyncLeaseKeepAliveAction(
etcdv3::ActionParameters const &param)
: etcdv3::Action(param)
{
isCancelled = false;
@ -73,6 +80,8 @@ etcdv3::AsyncLeaseKeepAliveAction::AsyncLeaseKeepAliveAction(etcdv3::ActionParam
etcdv3::AsyncLeaseKeepAliveResponse etcdv3::AsyncLeaseKeepAliveAction::ParseResponse()
{
AsyncLeaseKeepAliveResponse lease_resp;
lease_resp.set_action(etcdv3::LEASEKEEPALIVE);
if (!status.ok()) {
lease_resp.set_error_code(status.error_code());
lease_resp.set_error_message(status.error_message());
@ -133,7 +142,8 @@ bool etcdv3::AsyncLeaseKeepAliveAction::Cancelled() const
return isCancelled;
}
etcdv3::AsyncLeaseTimeToLiveAction::AsyncLeaseTimeToLiveAction(etcdv3::ActionParameters param)
etcdv3::AsyncLeaseTimeToLiveAction::AsyncLeaseTimeToLiveAction(
etcdv3::ActionParameters const &param)
: etcdv3::Action(param)
{
LeaseTimeToLiveRequest leasetimetolive_request;
@ -148,6 +158,8 @@ etcdv3::AsyncLeaseTimeToLiveAction::AsyncLeaseTimeToLiveAction(etcdv3::ActionPar
etcdv3::AsyncLeaseTimeToLiveResponse etcdv3::AsyncLeaseTimeToLiveAction::ParseResponse()
{
AsyncLeaseTimeToLiveResponse lease_resp;
lease_resp.set_action(etcdv3::LEASETIMETOLIVE);
if (!status.ok()) {
lease_resp.set_error_code(status.error_code());
lease_resp.set_error_message(status.error_message());
@ -157,7 +169,8 @@ etcdv3::AsyncLeaseTimeToLiveResponse etcdv3::AsyncLeaseTimeToLiveAction::ParseRe
return lease_resp;
}
etcdv3::AsyncLeaseLeasesAction::AsyncLeaseLeasesAction(etcdv3::ActionParameters param)
etcdv3::AsyncLeaseLeasesAction::AsyncLeaseLeasesAction(
etcdv3::ActionParameters const &param)
: etcdv3::Action(param)
{
LeaseLeasesRequest leaseleases_request;
@ -169,6 +182,8 @@ etcdv3::AsyncLeaseLeasesAction::AsyncLeaseLeasesAction(etcdv3::ActionParameters
etcdv3::AsyncLeaseLeasesResponse etcdv3::AsyncLeaseLeasesAction::ParseResponse()
{
AsyncLeaseLeasesResponse lease_resp;
lease_resp.set_action(etcdv3::LEASELEASES);
if (!status.ok()) {
lease_resp.set_error_code(status.error_code());
lease_resp.set_error_message(status.error_message());

View File

@ -4,7 +4,8 @@
using v3lockpb::LockRequest;
using v3lockpb::UnlockRequest;
etcdv3::AsyncLockAction::AsyncLockAction(ActionParameters param)
etcdv3::AsyncLockAction::AsyncLockAction(
ActionParameters const &param)
: etcdv3::Action(param)
{
LockRequest lock_request;
@ -18,6 +19,7 @@ etcdv3::AsyncLockAction::AsyncLockAction(ActionParameters param)
etcdv3::AsyncLockResponse etcdv3::AsyncLockAction::ParseResponse()
{
AsyncLockResponse lock_resp;
lock_resp.set_action(etcdv3::LOCK_ACTION);
if(!status.ok())
{
@ -27,13 +29,13 @@ etcdv3::AsyncLockResponse etcdv3::AsyncLockAction::ParseResponse()
else
{
lock_resp.ParseResponse(reply);
lock_resp.set_action(etcdv3::LOCK_ACTION);
}
return lock_resp;
}
etcdv3::AsyncUnlockAction::AsyncUnlockAction(ActionParameters param)
etcdv3::AsyncUnlockAction::AsyncUnlockAction(
ActionParameters const &param)
: etcdv3::Action(param)
{
UnlockRequest unlock_request;
@ -46,6 +48,7 @@ etcdv3::AsyncUnlockAction::AsyncUnlockAction(ActionParameters param)
etcdv3::AsyncUnlockResponse etcdv3::AsyncUnlockAction::ParseResponse()
{
AsyncUnlockResponse unlock_resp;
unlock_resp.set_action(etcdv3::UNLOCK_ACTION);
if(!status.ok())
{
@ -55,7 +58,6 @@ etcdv3::AsyncUnlockResponse etcdv3::AsyncUnlockAction::ParseResponse()
else
{
unlock_resp.ParseResponse(reply);
unlock_resp.set_action(etcdv3::UNLOCK_ACTION);
}
return unlock_resp;

View File

@ -6,7 +6,8 @@
using etcdserverpb::RangeRequest;
etcdv3::AsyncRangeAction::AsyncRangeAction(etcdv3::ActionParameters param)
etcdv3::AsyncRangeAction::AsyncRangeAction(
etcdv3::ActionParameters const &param)
: etcdv3::Action(param)
{
RangeRequest get_request;
@ -36,6 +37,8 @@ etcdv3::AsyncRangeAction::AsyncRangeAction(etcdv3::ActionParameters param)
etcdv3::AsyncRangeResponse etcdv3::AsyncRangeAction::ParseResponse()
{
AsyncRangeResponse range_resp;
range_resp.set_action(etcdv3::GET_ACTION);
if(!status.ok())
{
range_resp.set_error_code(status.error_code());

View File

@ -4,11 +4,10 @@
void etcdv3::AsyncRangeResponse::ParseResponse(RangeResponse& resp, bool prefix)
{
action = etcdv3::GET_ACTION;
index = resp.header().revision();
if(resp.kvs_size() == 0 && !prefix)
{
error_code=100;
error_code = etcdv3::ERROR_KEY_NOT_FOUND;
error_message = "Key not found";
return;
}

View File

@ -1,16 +1,16 @@
#include "etcd/v3/AsyncSetAction.hpp"
#include "etcd/v3/action_constants.hpp"
#include "etcd/v3/Transaction.hpp"
using etcdserverpb::Compare;
etcdv3::AsyncSetAction::AsyncSetAction(etcdv3::ActionParameters param, bool create)
etcdv3::AsyncSetAction::AsyncSetAction(
etcdv3::ActionParameters const &param, bool create)
: etcdv3::Action(param)
{
etcdv3::Transaction transaction(parameters.key);
isCreate = create;
transaction.init_compare(Compare::CompareResult::Compare_CompareResult_EQUAL,
Compare::CompareTarget::Compare_CompareTarget_VERSION);
transaction.init_compare(CompareResult::EQUAL,
CompareTarget::VERSION);
transaction.setup_basic_create_sequence(parameters.key, parameters.value, parameters.lease_id);
@ -30,6 +30,7 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncSetAction::ParseResponse()
{
AsyncTxnResponse txn_resp;
txn_resp.set_action(isCreate? etcdv3::CREATE_ACTION : etcdv3::SET_ACTION);
if(!status.ok())
{
@ -39,12 +40,10 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncSetAction::ParseResponse()
else
{
txn_resp.ParseResponse(parameters.key, parameters.withPrefix, reply);
std::string action = isCreate? etcdv3::CREATE_ACTION:etcdv3::SET_ACTION;
txn_resp.set_action(action);
if(!reply.succeeded() && action == etcdv3::CREATE_ACTION)
if(!reply.succeeded() && isCreate)
{
txn_resp.set_error_code(105);
txn_resp.set_error_code(etcdv3::ERROR_KEY_ALREADY_EXISTS);
txn_resp.set_error_message("Key already exists");
}
}

View File

@ -3,7 +3,8 @@
#include "etcd/v3/Transaction.hpp"
etcdv3::AsyncTxnAction::AsyncTxnAction(etcdv3::ActionParameters param, etcdv3::Transaction const &tx)
etcdv3::AsyncTxnAction::AsyncTxnAction(
etcdv3::ActionParameters const &param, etcdv3::Transaction const &tx)
: etcdv3::Action(param)
{
response_reader = parameters.kv_stub->AsyncTxn(&context, *tx.txn_request, &cq_);
@ -13,6 +14,7 @@ etcdv3::AsyncTxnAction::AsyncTxnAction(etcdv3::ActionParameters param, etcdv3::T
etcdv3::AsyncTxnResponse etcdv3::AsyncTxnAction::ParseResponse()
{
AsyncTxnResponse txn_resp;
txn_resp.set_action(etcdv3::TXN_ACTION);
if(!status.ok())
{
@ -22,13 +24,12 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncTxnAction::ParseResponse()
else
{
txn_resp.ParseResponse(parameters.key, parameters.withPrefix, reply);
txn_resp.set_action(etcdv3::TXN_ACTION);
//if there is an error code returned by parseResponse, we must
//not overwrite it.
if(!reply.succeeded() && !txn_resp.get_error_code())
{
txn_resp.set_error_code(101);
txn_resp.set_error_code(ERROR_COMPARE_FAILED);
txn_resp.set_error_message("compare failed");
}
}

View File

@ -1,21 +1,22 @@
#include "etcd/v3/AsyncUpdateAction.hpp"
#include "etcd/v3/AsyncRangeResponse.hpp"
#include "etcd/v3/action_constants.hpp"
#include "etcd/v3/AsyncRangeResponse.hpp"
#include "etcd/v3/Transaction.hpp"
using etcdserverpb::Compare;
using etcdserverpb::RangeRequest;
using etcdserverpb::PutRequest;
using etcdserverpb::RequestOp;
using etcdserverpb::ResponseOp;
using etcdserverpb::TxnRequest;
etcdv3::AsyncUpdateAction::AsyncUpdateAction(etcdv3::ActionParameters param)
etcdv3::AsyncUpdateAction::AsyncUpdateAction(
etcdv3::ActionParameters const &param)
: etcdv3::Action(param)
{
etcdv3::Transaction transaction(parameters.key);
transaction.init_compare(Compare::CompareResult::Compare_CompareResult_GREATER,
Compare::CompareTarget::Compare_CompareTarget_VERSION);
transaction.init_compare(CompareResult::GREATER,
CompareTarget::VERSION);
transaction.setup_compare_and_swap_sequence(parameters.value, parameters.lease_id);
@ -41,10 +42,9 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncUpdateAction::ParseResponse()
}
else
{
txn_resp.set_error_code(100);
txn_resp.set_error_code(etcdv3::ERROR_KEY_NOT_FOUND);
txn_resp.set_error_message("Key not found");
}
}
return txn_resp;
}

View File

@ -6,7 +6,8 @@ using etcdserverpb::RangeRequest;
using etcdserverpb::RangeResponse;
using etcdserverpb::WatchCreateRequest;
etcdv3::AsyncWatchAction::AsyncWatchAction(etcdv3::ActionParameters param)
etcdv3::AsyncWatchAction::AsyncWatchAction(
etcdv3::ActionParameters const &param)
: etcdv3::Action(param)
{
isCancelled.store(false);
@ -158,6 +159,8 @@ void etcdv3::AsyncWatchAction::waitForResponse(std::function<void(etcd::Response
etcdv3::AsyncWatchResponse etcdv3::AsyncWatchAction::ParseResponse()
{
AsyncWatchResponse watch_resp;
watch_resp.set_action(etcdv3::WATCH_ACTION);
if(!status.ok())
{
watch_resp.set_error_code(status.error_code());

View File

@ -8,6 +8,22 @@ using etcdserverpb::PutRequest;
using etcdserverpb::RequestOp;
using etcdserverpb::DeleteRangeRequest;
namespace etcdv3 {
namespace detail {
static etcdserverpb::Compare::CompareResult to_compare_result(CompareResult r) {
return static_cast<etcdserverpb::Compare::CompareResult>(static_cast<int>(r));
}
static etcdserverpb::Compare::CompareTarget to_compare_target(CompareTarget t) {
return static_cast<etcdserverpb::Compare::CompareTarget>(static_cast<int>(t));
}
}
}
etcdv3::Transaction::Transaction() {
txn_request.reset(new etcdserverpb::TxnRequest{});
}
@ -16,28 +32,28 @@ etcdv3::Transaction::Transaction(const std::string& key) : key(key) {
txn_request.reset(new etcdserverpb::TxnRequest{});
}
void etcdv3::Transaction::init_compare(Compare::CompareResult result, Compare::CompareTarget target){
void etcdv3::Transaction::init_compare(CompareResult result, CompareTarget target){
Compare* compare = txn_request->add_compare();
compare->set_result(result);
compare->set_target(target);
compare->set_result(detail::to_compare_result(result));
compare->set_target(detail::to_compare_target(target));
compare->set_key(key);
compare->set_version(0);
}
void etcdv3::Transaction::init_compare(std::string const& old_value, Compare::CompareResult result, Compare::CompareTarget target){
void etcdv3::Transaction::init_compare(std::string const& old_value, CompareResult result, CompareTarget target){
Compare* compare = txn_request->add_compare();
compare->set_result(result);
compare->set_target(target);
compare->set_result(detail::to_compare_result(result));
compare->set_target(detail::to_compare_target(target));
compare->set_key(key);
compare->set_value(old_value);
}
void etcdv3::Transaction::init_compare(int old_index, Compare::CompareResult result, Compare::CompareTarget target){
void etcdv3::Transaction::init_compare(int old_index, CompareResult result, CompareTarget target){
Compare* compare = txn_request->add_compare();
compare->set_result(result);
compare->set_target(target);
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);

View File

@ -10,6 +10,13 @@ char const * etcdv3::COMPAREDELETE_ACTION = "compareAndDelete";
char const * etcdv3::LOCK_ACTION = "lock";
char const * etcdv3::UNLOCK_ACTION = "unlock";
char const * etcdv3::TXN_ACTION = "txn";
char const * etcdv3::WATCH_ACTION = "watch";
char const * etcdv3::LEASEGRANT = "leasegrant";
char const * etcdv3::LEASEREVOKE = "leaserevoke";
char const * etcdv3::LEASEKEEPALIVE = "leasekeepalive";
char const * etcdv3::LEASETIMETOLIVE = "leasetimetolive";
char const * etcdv3::LEASELEASES = "leaseleases";
// see: noPrefixEnd in etcd, however c++ doesn't allows '\0' inside a string, thus we use
// the UTF-8 char U+0000 (i.e., "\xC0\x80").
@ -23,3 +30,7 @@ char const * etcdv3::KEEPALIVE_DONE = "keepalive done";
char const * etcdv3::WATCH_CREATE = "watch create";
char const * etcdv3::WATCH_WRITE = "watch write";
char const * etcdv3::WATCH_WRITES_DONE = "watch writes done";
const int etcdv3::ERROR_KEY_NOT_FOUND = 100;
const int etcdv3::ERROR_COMPARE_FAILED = 101;
const int etcdv3::ERROR_KEY_ALREADY_EXISTS = 105;

View File

@ -26,8 +26,8 @@ TEST_CASE("add a new key after authenticate")
CHECK(0 < val.created_index());
CHECK(0 < val.modified_index());
CHECK(0 < resp.index());
CHECK(105 == etcd->add("/test/key1", "43").get().error_code()); // Key already exists
CHECK(105 == etcd->add("/test/key1", "42").get().error_code()); // Key already exists
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "43").get().error_code()); // Key already exists
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "42").get().error_code()); // Key already exists
CHECK("Key already exists" == etcd->add("/test/key1", "42").get().error_message());
}

View File

@ -14,12 +14,12 @@ TEST_CASE("sync operations")
// add
CHECK(0 == etcd.add("/test/key1", "42").error_code());
CHECK(105 == etcd.add("/test/key1", "42").error_code()); // Key already exists
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd.add("/test/key1", "42").error_code()); // Key already exists
CHECK("42" == etcd.get("/test/key1").value().as_string());
// modify
CHECK(0 == etcd.modify("/test/key1", "43").error_code());
CHECK(100 == etcd.modify("/test/key2", "43").error_code()); // Key not found
CHECK(etcd::ERROR_KEY_NOT_FOUND == etcd.modify("/test/key2", "43").error_code()); // Key not found
CHECK("43" == etcd.modify("/test/key1", "42").prev_value().as_string());
// set
@ -32,7 +32,7 @@ TEST_CASE("sync operations")
CHECK("43" == etcd.get("/test/key1").value().as_string());
CHECK("44" == etcd.get("/test/key2").value().as_string());
CHECK("44" == etcd.get("/test/key3").value().as_string());
CHECK(100 == etcd.get("/test/key4").error_code()); // key not found
CHECK(etcd::ERROR_KEY_NOT_FOUND == etcd.get("/test/key4").error_code()); // key not found
// rm
CHECK(3 == etcd.ls("/test").keys().size());
@ -46,24 +46,24 @@ TEST_CASE("sync operations")
CHECK(2 == etcd.ls("/test/new_dir").keys().size());
// rmdir
CHECK(100 == etcd.rmdir("/test/new_dir").error_code()); // key not found
CHECK(etcd::ERROR_KEY_NOT_FOUND == etcd.rmdir("/test/new_dir").error_code()); // key not found
CHECK(0 == etcd.rmdir("/test/new_dir", true).error_code());
// compare and swap
etcd.set("/test/key1", "42");
int index = etcd.modify_if("/test/key1", "43", "42").index();
CHECK(101 == etcd.modify_if("/test/key1", "44", "42").error_code());
CHECK(etcd::ERROR_COMPARE_FAILED == etcd.modify_if("/test/key1", "44", "42").error_code());
REQUIRE(etcd.modify_if("/test/key1", "44", index).is_ok());
CHECK(101 == etcd.modify_if("/test/key1", "45", index).error_code());
CHECK(etcd::ERROR_COMPARE_FAILED == etcd.modify_if("/test/key1", "45", index).error_code());
// atomic compare-and-delete based on prevValue
etcd.set("/test/key1", "42");
CHECK(101 == etcd.rm_if("/test/key1", "43").error_code());
CHECK(etcd::ERROR_COMPARE_FAILED == etcd.rm_if("/test/key1", "43").error_code());
CHECK(0 == etcd.rm_if("/test/key1", "42").error_code());
// atomic compare-and-delete based on prevIndex
index = etcd.set("/test/key1", "42").index();
CHECK(101 == etcd.rm_if("/test/key1", index - 1).error_code());
CHECK(etcd::ERROR_COMPARE_FAILED == etcd.rm_if("/test/key1", index - 1).error_code());
CHECK(0 == etcd.rm_if("/test/key1", index).error_code());
//leasegrant

View File

@ -28,8 +28,8 @@ TEST_CASE("add a new key")
CHECK(0 < val.created_index());
CHECK(0 < val.modified_index());
CHECK(0 < resp.index());
CHECK(105 == etcd.add("/test/key1", "43").get().error_code()); // Key already exists
CHECK(105 == etcd.add("/test/key1", "42").get().error_code()); // Key already exists
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd.add("/test/key1", "43").get().error_code()); // Key already exists
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd.add("/test/key1", "42").get().error_code()); // Key already exists
CHECK("Key already exists" == etcd.add("/test/key1", "42").get().error_message());
}
@ -48,7 +48,7 @@ TEST_CASE("simplified read")
{
etcd::Client etcd("http://127.0.0.1:2379");
CHECK("42" == etcd.get("/test/key1").get().value().as_string());
CHECK(100 == etcd.get("/test/key2").get().error_code()); // Key not found
CHECK(etcd::ERROR_KEY_NOT_FOUND == etcd.get("/test/key2").get().error_code()); // Key not found
CHECK("" == etcd.get("/test/key2").get().value().as_string()); // Key not found
}
@ -58,7 +58,7 @@ TEST_CASE("modify a key")
etcd::Response resp = etcd.modify("/test/key1", "43").get();
REQUIRE(0 == resp.error_code()); // overwrite
CHECK("update" == resp.action());
CHECK(100 == etcd.modify("/test/key2", "43").get().error_code()); // Key not found
CHECK(etcd::ERROR_KEY_NOT_FOUND == etcd.modify("/test/key2", "43").get().error_code()); // Key not found
CHECK("43" == etcd.modify("/test/key1", "42").get().prev_value().as_string());
}
@ -96,13 +96,13 @@ TEST_CASE("atomic compare-and-swap")
// modify fails the second time
res = etcd.modify_if("/test/key1", "44", "42").get();
CHECK(!res.is_ok());
CHECK(101 == res.error_code());
CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code());
CHECK("Compare failed" == res.error_message());
// modify fails the second time
res = etcd.modify_if("/test/key222", "44", "42").get();
CHECK(!res.is_ok());
CHECK(100 == res.error_code());
CHECK(etcd::ERROR_KEY_NOT_FOUND == res.error_code());
CHECK("Key not found" == res.error_message());
}
@ -111,7 +111,7 @@ TEST_CASE("delete a value")
etcd::Client etcd("http://127.0.0.1:2379");
etcd::Response resp = etcd.rm("/test/key11111").get();
CHECK(!resp.is_ok());
CHECK(100 == resp.error_code());
CHECK(etcd::ERROR_KEY_NOT_FOUND == resp.error_code());
CHECK("Key not found" == resp.error_message());
int index = etcd.get("/test/key1").get().index();
@ -145,7 +145,7 @@ TEST_CASE("atomic compare-and-delete based on prevValue")
etcd::Response res = etcd.rm_if("/test/key1", "43").get();
CHECK(!res.is_ok());
CHECK(101 == res.error_code());
CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code());
CHECK("Compare failed" == res.error_message());
res = etcd.rm_if("/test/key1", "42").get();
@ -161,7 +161,7 @@ TEST_CASE("atomic compare-and-delete based on prevIndex")
etcd::Response res = etcd.rm_if("/test/key1", index - 1).get();
CHECK(!res.is_ok());
CHECK(101 == res.error_code());
CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code());
CHECK("Compare failed" == res.error_message());
res = etcd.rm_if("/test/key1", index).get();
@ -186,7 +186,7 @@ TEST_CASE("deep atomic compare-and-swap")
// modify fails the second time
res = etcd.modify_if("/test/key1", "44", "42").get();
CHECK(!res.is_ok());
CHECK(101 == res.error_code());
CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code());
CHECK("Compare failed" == res.error_message());
// succes with the correct index
@ -198,7 +198,7 @@ TEST_CASE("deep atomic compare-and-swap")
// index changes so second modify fails
res = etcd.modify_if("/test/key1", "45", index).get();
CHECK(!res.is_ok());
CHECK(101 == res.error_code());
CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code());
CHECK("Compare failed" == res.error_message());
}
@ -282,7 +282,7 @@ TEST_CASE("delete a directory")
etcd.set("/test/new_dir/key2", "value2").wait();
etcd.set("/test/new_dir/key3", "value3").wait();
CHECK(100 == etcd.rmdir("/test/new_dir").get().error_code()); // key not found
CHECK(etcd::ERROR_KEY_NOT_FOUND == etcd.rmdir("/test/new_dir").get().error_code()); // key not found
etcd::Response resp = etcd.ls("/test/new_dir").get();
resp = etcd.rmdir("/test/new_dir", true).get();
@ -296,12 +296,12 @@ TEST_CASE("delete a directory")
resp = etcd.rmdir("/test/dirnotfound", true).get();
CHECK(!resp.is_ok());
CHECK(100 == resp.error_code());
CHECK(etcd::ERROR_KEY_NOT_FOUND == resp.error_code());
CHECK("Key not found" == resp.error_message());
resp = etcd.rmdir("/test/new_dir", false).get();
CHECK(!resp.is_ok());
CHECK(100 == resp.error_code());
CHECK(etcd::ERROR_KEY_NOT_FOUND == resp.error_code());
CHECK("Key not found" == resp.error_message());
}
@ -309,7 +309,7 @@ TEST_CASE("delete by range")
{
etcd::Client etcd("http://127.0.0.1:2379");
CHECK(100 == etcd.rmdir("/test/new_dir").get().error_code()); // key not found
CHECK(etcd::ERROR_KEY_NOT_FOUND == etcd.rmdir("/test/new_dir").get().error_code()); // key not found
etcd::Response resp = etcd.ls("/test/new_dir").get();
etcd.set("/test/new_dir/key1", "value1").wait();

View File

@ -29,8 +29,8 @@ TEST_CASE("add a new key after authenticate")
CHECK(0 < val.created_index());
CHECK(0 < val.modified_index());
CHECK(0 < resp.index());
CHECK(105 == etcd->add("/test/key1", "43").get().error_code()); // Key already exists
CHECK(105 == etcd->add("/test/key1", "42").get().error_code()); // Key already exists
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "43").get().error_code()); // Key already exists
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "42").get().error_code()); // Key already exists
CHECK("Key already exists" == etcd->add("/test/key1", "42").get().error_message());
}