This is the complete implementation for delete functionalities.

Index is now also supported

notes/TODOs:
1) We should consider adding an algo for mod/update functions
to consider BOTH creation index and modify index
2) Watch functionality
This commit is contained in:
lampayan 2016-06-09 13:53:58 +02:00
parent 008693a276
commit 6fb775218d
4 changed files with 74 additions and 63 deletions

View File

@ -165,8 +165,10 @@ namespace etcd
etcdv3::grpcClient grpcClient; etcdv3::grpcClient grpcClient;
private: private:
pplx::task<Response> removeEntryWithKey(std::string const &); pplx::task<Response> removeEntryWithKey(std::string const &entryKey);
pplx::task<Response> removeEntryWithKeyAndValue(std::string const &, std::string const &); pplx::task<Response> removeEntryWithKeyAndValue(std::string const &entryKey, std::string const &oldValue);
pplx::task<Response> removeEntryWithKeyAndIndex(std::string const &entryKey, int oldIndex);
}; };

View File

@ -45,6 +45,7 @@ namespace etcd
{ {
auto v3resp = call->ParseResponse(); auto v3resp = call->ParseResponse();
resp = etcd::Response(v3resp); resp = etcd::Response(v3resp);
resp._index = call->reply.header().revision();
} }
else else
{ {

View File

@ -54,7 +54,6 @@ pplx::task<etcd::Response> etcd::Client::modify_if(std::string const & key, std:
return send_asyncmodify_if(key, value, old_value); return send_asyncmodify_if(key, value, old_value);
} }
//FBDL
pplx::task<etcd::Response> etcd::Client::modify_if(std::string const & key, std::string const & value, int old_index) pplx::task<etcd::Response> etcd::Client::modify_if(std::string const & key, std::string const & value, int old_index)
{ {
web::http::uri_builder uri("/v2/keys" + key); web::http::uri_builder uri("/v2/keys" + key);
@ -131,12 +130,40 @@ pplx::task<etcd::Response> etcd::Client::rm_if(std::string const & key, std::str
return removeEntryWithKeyAndValue(key, old_value); return removeEntryWithKeyAndValue(key, old_value);
} }
pplx::task<etcd::Response> etcd::Client::removeEntryWithKeyAndIndex(std::string const &entryKey, int oldIndex) {
etcdv3::AsyncRangeResponse *searchResult = etcdv3::Utils::getKey(entryKey, grpcClient);
std::cout << "found revision in item is: " << searchResult->reply.kvs(0).create_revision() << std::endl;
if(!searchResult->reply.kvs_size()) {
searchResult->error_code = 100;
searchResult->error_message = "Key not Found";
return Response::createResponse(*searchResult);
}
else if(searchResult->reply.kvs(0).create_revision() != oldIndex) {
searchResult->error_code = 101;
searchResult->error_message = "Compare failed";
return Response::createResponse(*searchResult);
}
etcdserverpb::DeleteRangeRequest deleteRangeRequest;
deleteRangeRequest.set_key(entryKey);
etcdv3::AsyncDelResponse *deleteResponseCall = new etcdv3::AsyncDelResponse("compareAndDelete");
deleteResponseCall->prev_value = searchResult->reply.kvs(0);
deleteResponseCall->client = &grpcClient;
deleteResponseCall->key = entryKey;
deleteResponseCall->rpcInstance = grpcClient.stub_->AsyncDeleteRange(&deleteResponseCall->context, deleteRangeRequest, &deleteResponseCall->cq_);
deleteResponseCall->rpcInstance->Finish(&deleteResponseCall->deleteResponse, &deleteResponseCall->status, (void*)deleteResponseCall);
return Response::createResponse(*deleteResponseCall);
}
pplx::task<etcd::Response> etcd::Client::rm_if(std::string const & key, int old_index) pplx::task<etcd::Response> etcd::Client::rm_if(std::string const & key, int old_index)
{ {
web::http::uri_builder uri("/v2/keys" + key); return removeEntryWithKeyAndIndex(key, old_index);
uri.append_query("dir=false");
uri.append_query("prevIndex", old_index);
return send_del_request(uri);
} }
pplx::task<etcd::Response> etcd::Client::mkdir(std::string const & key) pplx::task<etcd::Response> etcd::Client::mkdir(std::string const & key)
@ -299,7 +326,6 @@ pplx::task<etcd::Response> etcd::Client::send_asyncget(std::string const & key)
pplx::task<etcd::Response> etcd::Client::send_asyncput(std::string const & key, std::string const & value) pplx::task<etcd::Response> etcd::Client::send_asyncput(std::string const & key, std::string const & value)
{ {
PutRequest put_request; PutRequest put_request;
put_request.set_key(key); put_request.set_key(key);
put_request.set_value(value); put_request.set_value(value);
@ -316,7 +342,6 @@ pplx::task<etcd::Response> etcd::Client::send_asyncput(std::string const & key,
call->client = &grpcClient; call->client = &grpcClient;
call->key = key; call->key = key;
call->response_reader = grpcClient.stub_->AsyncPut(&call->context,put_request,&call->cq_); call->response_reader = grpcClient.stub_->AsyncPut(&call->context,put_request,&call->cq_);
call->response_reader->Finish(&call->reply, &call->status, (void*)call); call->response_reader->Finish(&call->reply, &call->status, (void*)call);

View File

@ -64,7 +64,6 @@ TEST_CASE("modify a key")
} }
TEST_CASE("set a key") TEST_CASE("set a key")
{ {
etcd::Client etcd("http://127.0.0.1:4001"); etcd::Client etcd("http://127.0.0.1:4001");
@ -120,29 +119,10 @@ TEST_CASE("atomic compare-and-delete based on prevValue")
CHECK("42" == res.prev_value().as_string()); CHECK("42" == res.prev_value().as_string());
} }
TEST_CASE("atomic compare-and-delete based on prevValue checking index")
{
etcd::Client etcd("http://127.0.0.1:4001");
std::cout << "index: " << etcd.set("/test/key1", "42").get().index() << std::endl;
etcd::Response res = etcd.rm_if("/test/key1", "43").get();
CHECK(!res.is_ok());
CHECK(101 == res.error_code());
CHECK("Compare failed" == res.error_message());
res = etcd.rm_if("/test/key1", "42").get();
REQUIRE(res.is_ok());
CHECK("compareAndDelete" == res.action());
CHECK("42" == res.prev_value().as_string());
}
#if 0
TEST_CASE("atomic compare-and-delete based on prevIndex") TEST_CASE("atomic compare-and-delete based on prevIndex")
{ {
etcd::Client etcd("http://127.0.0.1:4001"); etcd::Client etcd("http://127.0.0.1:4001");
int index = etcd.set("/test/key1", "42").get().index(); int index = etcd.set("/test/key1", "42").get().index();
std::cout << "index of old: " << index << std::endl;
etcd::Response res = etcd.rm_if("/test/key1", index - 1).get(); etcd::Response res = etcd.rm_if("/test/key1", index - 1).get();
CHECK(!res.is_ok()); CHECK(!res.is_ok());
@ -155,6 +135,40 @@ TEST_CASE("atomic compare-and-delete based on prevIndex")
CHECK("42" == res.prev_value().as_string()); CHECK("42" == res.prev_value().as_string());
} }
#if 0
TEST_CASE("deep atomic compare-and-swap")
{
etcd::Client etcd("http://127.0.0.1:4001");
etcd.set("/test/key1", "42").wait();
// modify success
etcd::Response res = etcd.modify_if("/test/key1", "43", "42").get();
int index = res.index();
std::cout << "index to use: " << index << std::endl;
REQUIRE(res.is_ok());
CHECK("compareAndSwap" == res.action());
CHECK("43" == res.value().as_string());
// modify fails the second time
res = etcd.modify_if("/test/key1", "44", "42").get();
CHECK(!res.is_ok());
CHECK(101 == res.error_code());
CHECK("Compare failed" == res.error_message());
// succes with the correct index
res = etcd.modify_if("/test/key1", "44", index).get();
REQUIRE(res.is_ok());
CHECK("compareAndSwap" == res.action());
CHECK("44" == res.value().as_string());
// 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("Compare failed" == res.error_message());
}
TEST_CASE("create a directory") TEST_CASE("create a directory")
{ {
etcd::Client etcd("http://127.0.0.1:4001"); etcd::Client etcd("http://127.0.0.1:4001");
@ -258,37 +272,6 @@ TEST_CASE("watch changes in the past")
CHECK("45" == res.value().as_string()); CHECK("45" == res.value().as_string());
} }
TEST_CASE("atomic compare-and-swap")
{
etcd::Client etcd("http://127.0.0.1:4001");
etcd.set("/test/key1", "42").wait();
// modify success
etcd::Response res = etcd.modify_if("/test/key1", "43", "42").get();
int index = res.index();
REQUIRE(res.is_ok());
CHECK("compareAndSwap" == res.action());
CHECK("43" == res.value().as_string());
// modify fails the second time
res = etcd.modify_if("/test/key1", "44", "42").get();
CHECK(!res.is_ok());
CHECK(101 == res.error_code());
CHECK("Compare failed" == res.error_message());
// succes with the correct index
res = etcd.modify_if("/test/key1", "44", index).get();
REQUIRE(res.is_ok());
CHECK("compareAndSwap" == res.action());
CHECK("44" == res.value().as_string());
// 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("Compare failed" == res.error_message());
}
TEST_CASE("cleanup") TEST_CASE("cleanup")
{ {
etcd::Client etcd("http://127.0.0.1:4001"); etcd::Client etcd("http://127.0.0.1:4001");