Taking error code from grpc. (#172)

Signed-off-by: Tao He <sighingnow@gmail.com>
This commit is contained in:
Tao He 2022-10-09 10:25:50 +08:00 committed by GitHub
parent 2e38d3c11e
commit ab255467d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 138 additions and 58 deletions

View File

@ -181,8 +181,6 @@ this case since the response has been already arrived (we are inside the callbac
// ... your code can continue here without any delay
```
## etcd operations
### Multiple endpoints
Connecting to multiple endpoints is supported:
@ -364,6 +362,46 @@ Note that the timeout value is the "timeout" when waiting for responses upon the
It doesn't means the timeout between issuing a `.set()` method getting the `etcd::Response`, as in the async mode the such a time
duration is unpredictable and the gRPC timeout should be enough to avoid deadly waiting (e.g., waiting for a `lock()`).
### Error code in responses
The `class etcd::Response` may yield an error code and error message when error occurs,
```cpp
int error_code() const;
std::string const & error_message() const;
bool is_ok() const;
```
The error code would be `0` when succeed, otherwise the error code might be
```cpp
extern const int ERROR_GRPC_OK;
extern const int ERROR_GRPC_CANCELLED;
extern const int ERROR_GRPC_UNKNOWN;
extern const int ERROR_GRPC_INVALID_ARGUMENT;
extern const int ERROR_GRPC_DEADLINE_EXCEEDED;
extern const int ERROR_GRPC_NOT_FOUND;
extern const int ERROR_GRPC_ALREADY_EXISTS;
extern const int ERROR_GRPC_PERMISSION_DENIED;
extern const int ERROR_GRPC_UNAUTHENTICATED;
extern const int ERROR_GRPC_RESOURCE_EXHAUSTED;
extern const int ERROR_GRPC_FAILED_PRECONDITION;
extern const int ERROR_GRPC_ABORTED;
extern const int ERROR_GRPC_OUT_OF_RANGE;
extern const int ERROR_GRPC_UNIMPLEMENTED;
extern const int ERROR_GRPC_INTERNAL;
extern const int ERROR_GRPC_UNAVAILABLE;
extern const int ERROR_GRPC_DATA_LOSS;
extern const int ERROR_KEY_NOT_FOUND;
extern const int ERROR_COMPARE_FAILED;
extern const int ERROR_KEY_ALREADY_EXISTS;
extern const int ERROR_ACTION_CANCELLED;
```
## Etcd operations
### Reading a value
You can read a value with the `get()` method of the client instance. The only parameter is the
@ -434,7 +472,7 @@ 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 `ERROR_KEY_ALREADY_EXISTS`)
* `modify(key, value)` modifies an already existing value or returns a "Key not found" error
* `modify(key, value)` modifies an already existing value or returns a "etcd-cpp-apiv3: 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

View File

@ -16,7 +16,6 @@
namespace etcd
{
// FIXME
/**
* Client is responsible for maintaining a connection towards an etcd server.
* Etcd operations can be reached via the methods of the client.

View File

@ -63,9 +63,9 @@ namespace etcd
}
template <typename T>
static etcd::Response create(std::function<std::unique_ptr<T>()> callfn)
static etcd::Response create(std::function<std::unique_ptr<T>()> fn)
{
auto call = callfn();
auto call = fn();
call->waitForResponse();
auto v3resp = call->ParseResponse();
@ -76,9 +76,9 @@ namespace etcd
}
template <typename T>
static etcd::Response create(std::function<std::shared_ptr<T>()> callfn)
static etcd::Response create(std::function<std::shared_ptr<T>()> fn)
{
auto call = callfn();
auto call = fn();
call->waitForResponse();
auto v3resp = call->ParseResponse();
@ -92,6 +92,16 @@ namespace etcd
Response(const Response &);
/**
* Returns the error code received from the etcd server. In case of success the error code is 0.
*/
int error_code() const;
/**
* Returns the string representation of the error code
*/
std::string const & error_message() const;
/**
* Returns true if this is a successful response
*/
@ -102,21 +112,11 @@ namespace etcd
*/
bool is_network_unavailable() const;
/**
* Returns the error code received from the etcd server. In case of success the error code is 0.
*/
int error_code() const;
/**
* Check whether the response contains a grpc TIMEOUT error.
*/
bool is_grpc_timeout() const;
/**
* Returns the string representation of the error code
*/
std::string const & error_message() const;
/**
* Returns the action type of the operation that this response belongs to.
*/
@ -200,6 +200,7 @@ namespace etcd
protected:
Response(const etcdv3::V3Response& response, std::chrono::microseconds const& duration);
Response(int error_code, std::string const& error_message);
Response(int error_code, char const * error_message);
int _error_code;

View File

@ -68,7 +68,6 @@ namespace etcd
class Watcher;
class Client;
// FIXME
/**
* Client is responsible for maintaining a connection towards an etcd server.
* Etcd operations can be reached via the methods of the client.

View File

@ -41,6 +41,24 @@ namespace etcdv3
extern char const * ELECTION_OBSERVE_CREATE;
extern const int ERROR_GRPC_OK;
extern const int ERROR_GRPC_CANCELLED;
extern const int ERROR_GRPC_UNKNOWN;
extern const int ERROR_GRPC_INVALID_ARGUMENT;
extern const int ERROR_GRPC_DEADLINE_EXCEEDED;
extern const int ERROR_GRPC_NOT_FOUND;
extern const int ERROR_GRPC_ALREADY_EXISTS;
extern const int ERROR_GRPC_PERMISSION_DENIED;
extern const int ERROR_GRPC_UNAUTHENTICATED;
extern const int ERROR_GRPC_RESOURCE_EXHAUSTED;
extern const int ERROR_GRPC_FAILED_PRECONDITION;
extern const int ERROR_GRPC_ABORTED;
extern const int ERROR_GRPC_OUT_OF_RANGE;
extern const int ERROR_GRPC_UNIMPLEMENTED;
extern const int ERROR_GRPC_INTERNAL;
extern const int ERROR_GRPC_UNAVAILABLE;
extern const int ERROR_GRPC_DATA_LOSS;
extern const int ERROR_KEY_NOT_FOUND;
extern const int ERROR_COMPARE_FAILED;
extern const int ERROR_KEY_ALREADY_EXISTS;

View File

@ -67,6 +67,13 @@ etcd::Response::Response(const etcdv3::V3Response& reply, std::chrono::microseco
_raft_term = reply.get_raft_term();
}
etcd::Response::Response(int error_code, std::string const& error_message)
: _error_code(error_code),
_error_message(error_message),
_index(0)
{
}
etcd::Response::Response(int error_code, char const * error_message)
: _error_code(error_code),
_error_message(error_message),
@ -84,21 +91,6 @@ std::string const & etcd::Response::error_message() const
return _error_message;
}
bool etcd::Response::is_grpc_timeout() const
{
return _error_code == grpc::StatusCode::DEADLINE_EXCEEDED;
}
int64_t etcd::Response::index() const
{
return _index;
}
std::string const & etcd::Response::action() const
{
return _action;
}
bool etcd::Response::is_ok() const
{
return error_code() == 0;
@ -109,6 +101,21 @@ bool etcd::Response::is_network_unavailable() const
return error_code() == ::grpc::StatusCode::UNAVAILABLE;
}
bool etcd::Response::is_grpc_timeout() const
{
return _error_code == grpc::StatusCode::DEADLINE_EXCEEDED;
}
std::string const & etcd::Response::action() const
{
return _action;
}
int64_t etcd::Response::index() const
{
return _index;
}
etcd::Value const & etcd::Response::value() const
{
return _value;

View File

@ -530,7 +530,7 @@ etcd::Response etcd::SyncClient::set(std::string const & key, std::string const
auto res = this->leasegrant(ttl);
if(!res.is_ok())
{
return etcd::Response(res.error_code(), res.error_message().c_str());
return etcd::Response(res.error_code(), res.error_message());
}
else
{
@ -565,7 +565,7 @@ etcd::Response etcd::SyncClient::add(std::string const & key, std::string const
auto res = this->leasegrant(ttl);
if(!res.is_ok())
{
return etcd::Response(res.error_code(), res.error_message().c_str());
return etcd::Response(res.error_code(), res.error_message());
}
else
{
@ -614,7 +614,7 @@ etcd::Response etcd::SyncClient::modify(std::string const & key, std::string con
auto res = leasegrant(ttl);
if(!res.is_ok())
{
return etcd::Response(res.error_code(), res.error_message().c_str());
return etcd::Response(res.error_code(), res.error_message());
}
else
{
@ -649,7 +649,7 @@ etcd::Response etcd::SyncClient::modify_if(std::string const & key, std::string
auto res = leasegrant(ttl);
if(!res.is_ok())
{
return etcd::Response(res.error_code(), res.error_message().c_str());
return etcd::Response(res.error_code(), res.error_message());
}
else
{
@ -673,7 +673,7 @@ etcd::Response etcd::SyncClient::modify_if(std::string const & key, std::string
auto res = leasegrant(ttl);
if(!res.is_ok())
{
return etcd::Response(res.error_code(), res.error_message().c_str());
return etcd::Response(res.error_code(), res.error_message());
}
else
{

View File

@ -51,7 +51,7 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncCompareAndDeleteAction::ParseResponse()
if(!reply.succeeded())
{
txn_resp.set_error_code(ERROR_COMPARE_FAILED);
txn_resp.set_error_message("Compare failed");
txn_resp.set_error_message("etcd-cpp-apiv3: compare failed");
}
}

View File

@ -53,7 +53,7 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncCompareAndSwapAction::ParseResponse()
if(!reply.succeeded() && !txn_resp.get_error_code())
{
txn_resp.set_error_code(ERROR_COMPARE_FAILED);
txn_resp.set_error_message("Compare failed");
txn_resp.set_error_message("etcd-cpp-apiv3: compare failed");
}
}

View File

@ -9,7 +9,7 @@ void etcdv3::AsyncDeleteResponse::ParseResponse(std::string const& key, bool pre
if(resp.prev_kvs_size() == 0)
{
error_code = etcdv3::ERROR_KEY_NOT_FOUND;
error_message = "Key not found";
error_message = "etcd-cpp-apiv3: key not found";
}
else
{

View File

@ -8,7 +8,7 @@ void etcdv3::AsyncRangeResponse::ParseResponse(RangeResponse& resp, bool prefix)
if(resp.kvs_size() == 0 && !prefix)
{
error_code = etcdv3::ERROR_KEY_NOT_FOUND;
error_message = "Key not found";
error_message = "etcd-cpp-apiv3: key not found";
return;
}
else

View File

@ -44,7 +44,7 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncSetAction::ParseResponse()
if(!reply.succeeded() && isCreate)
{
txn_resp.set_error_code(etcdv3::ERROR_KEY_ALREADY_EXISTS);
txn_resp.set_error_message("Key already exists");
txn_resp.set_error_message("etcd-cpp-apiv3: key already exists");
}
}
return txn_resp;

View File

@ -30,7 +30,7 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncTxnAction::ParseResponse()
if(!reply.succeeded() && !txn_resp.get_error_code())
{
txn_resp.set_error_code(ERROR_COMPARE_FAILED);
txn_resp.set_error_message("compare failed");
txn_resp.set_error_message("etcd-cpp-apiv3: compare failed");
}
}

View File

@ -43,7 +43,7 @@ etcdv3::AsyncTxnResponse etcdv3::AsyncUpdateAction::ParseResponse()
else
{
txn_resp.set_error_code(etcdv3::ERROR_KEY_NOT_FOUND);
txn_resp.set_error_message("Key not found");
txn_resp.set_error_message("etcd-cpp-apiv3: key not found");
}
}
return txn_resp;

View File

@ -40,6 +40,24 @@ char const * etcdv3::WATCH_WRITES_DONE = "watch writes done";
char const * etcdv3::ELECTION_OBSERVE_CREATE = "observe create";
const int etcdv3::ERROR_GRPC_OK = 0;
const int etcdv3::ERROR_GRPC_CANCELLED = 1;
const int etcdv3::ERROR_GRPC_UNKNOWN = 2;
const int etcdv3::ERROR_GRPC_INVALID_ARGUMENT = 3;
const int etcdv3::ERROR_GRPC_DEADLINE_EXCEEDED = 4;
const int etcdv3::ERROR_GRPC_NOT_FOUND = 5;
const int etcdv3::ERROR_GRPC_ALREADY_EXISTS = 6;
const int etcdv3::ERROR_GRPC_PERMISSION_DENIED = 7;
const int etcdv3::ERROR_GRPC_UNAUTHENTICATED = 16;
const int etcdv3::ERROR_GRPC_RESOURCE_EXHAUSTED = 8;
const int etcdv3::ERROR_GRPC_FAILED_PRECONDITION = 9;
const int etcdv3::ERROR_GRPC_ABORTED = 10;
const int etcdv3::ERROR_GRPC_OUT_OF_RANGE = 11;
const int etcdv3::ERROR_GRPC_UNIMPLEMENTED = 12;
const int etcdv3::ERROR_GRPC_INTERNAL = 13;
const int etcdv3::ERROR_GRPC_UNAVAILABLE = 14;
const int etcdv3::ERROR_GRPC_DATA_LOSS = 15;
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

@ -29,7 +29,7 @@ TEST_CASE("add a new key after authenticate")
CHECK(0 < resp.index());
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "43").get().error_code()); // Key already exists
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "42").get().error_code()); // Key already exists
CHECK("Key already exists" == etcd->add("/test/key1", "42").get().error_message());
CHECK("etcd-cpp-apiv3: key already exists" == etcd->add("/test/key1", "42").get().error_message());
}
TEST_CASE("read a value from etcd")

View File

@ -31,7 +31,7 @@ TEST_CASE("add a new key")
CHECK(0 < resp.index());
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd.add("/test/key1", "43").get().error_code()); // Key already exists
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd.add("/test/key1", "42").get().error_code()); // Key already exists
CHECK("Key already exists" == etcd.add("/test/key1", "42").get().error_message());
CHECK("etcd-cpp-apiv3: key already exists" == etcd.add("/test/key1", "42").get().error_message());
}
TEST_CASE("read a value from etcd")
@ -98,13 +98,13 @@ TEST_CASE("atomic compare-and-swap")
res = etcd.modify_if("/test/key1", "44", "42").get();
CHECK(!res.is_ok());
CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code());
CHECK("Compare failed" == res.error_message());
CHECK("etcd-cpp-apiv3: compare failed" == res.error_message());
// modify fails the second time
res = etcd.modify_if("/test/key222", "44", "42").get();
CHECK(!res.is_ok());
CHECK(etcd::ERROR_KEY_NOT_FOUND == res.error_code());
CHECK("Key not found" == res.error_message());
CHECK("etcd-cpp-apiv3: key not found" == res.error_message());
}
TEST_CASE("delete a value")
@ -113,7 +113,7 @@ TEST_CASE("delete a value")
etcd::Response resp = etcd.rm("/test/key11111").get();
CHECK(!resp.is_ok());
CHECK(etcd::ERROR_KEY_NOT_FOUND == resp.error_code());
CHECK("Key not found" == resp.error_message());
CHECK("etcd-cpp-apiv3: key not found" == resp.error_message());
int64_t index = etcd.get("/test/key1").get().index();
int64_t create_index = etcd.get("/test/key1").get().value().created_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(etcd::ERROR_COMPARE_FAILED == res.error_code());
CHECK("Compare failed" == res.error_message());
CHECK("etcd-cpp-apiv3: compare failed" == res.error_message());
res = etcd.rm_if("/test/key1", "42").get();
REQUIRE(res.is_ok());
@ -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(etcd::ERROR_COMPARE_FAILED == res.error_code());
CHECK("Compare failed" == res.error_message());
CHECK("etcd-cpp-apiv3: compare failed" == res.error_message());
res = etcd.rm_if("/test/key1", index).get();
REQUIRE(res.is_ok());
@ -185,7 +185,7 @@ TEST_CASE("deep atomic compare-and-swap")
res = etcd.modify_if("/test/key1", "44", "42").get();
CHECK(!res.is_ok());
CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code());
CHECK("Compare failed" == res.error_message());
CHECK("etcd-cpp-apiv3: compare failed" == res.error_message());
// succes with the correct index
res = etcd.modify_if("/test/key1", "44", index).get();
@ -197,7 +197,7 @@ TEST_CASE("deep atomic compare-and-swap")
res = etcd.modify_if("/test/key1", "45", index).get();
CHECK(!res.is_ok());
CHECK(etcd::ERROR_COMPARE_FAILED == res.error_code());
CHECK("Compare failed" == res.error_message());
CHECK("etcd-cpp-apiv3: compare failed" == res.error_message());
}
TEST_CASE("list a directory")
@ -295,12 +295,12 @@ TEST_CASE("delete a directory")
resp = etcd.rmdir("/test/dirnotfound", true).get();
CHECK(!resp.is_ok());
CHECK(etcd::ERROR_KEY_NOT_FOUND == resp.error_code());
CHECK("Key not found" == resp.error_message());
CHECK("etcd-cpp-apiv3: key not found" == resp.error_message());
resp = etcd.rmdir("/test/new_dir", false).get();
CHECK(!resp.is_ok());
CHECK(etcd::ERROR_KEY_NOT_FOUND == resp.error_code());
CHECK("Key not found" == resp.error_message());
CHECK("etcd-cpp-apiv3: key not found" == resp.error_message());
}
TEST_CASE("delete by range")

View File

@ -32,7 +32,7 @@ TEST_CASE("add a new key after authenticate")
CHECK(0 < resp.index());
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "43").get().error_code()); // Key already exists
CHECK(etcd::ERROR_KEY_ALREADY_EXISTS == etcd->add("/test/key1", "42").get().error_code()); // Key already exists
CHECK("Key already exists" == etcd->add("/test/key1", "42").get().error_message());
CHECK("etcd-cpp-apiv3: key already exists" == etcd->add("/test/key1", "42").get().error_message());
}
TEST_CASE("read a value from etcd")