diff --git a/etcd/Client.hpp b/etcd/Client.hpp index f0f2dea..19cbd3f 100644 --- a/etcd/Client.hpp +++ b/etcd/Client.hpp @@ -13,6 +13,7 @@ using etcdserverpb::KV; using etcdserverpb::Watch; +using etcdserverpb::Lease; namespace etcd { @@ -41,21 +42,47 @@ namespace etcd * @param key is the key to be created or modified * @param value is the new value to be set */ - pplx::task set(std::string const & key, std::string const & value); + pplx::task 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. + * @param key is the key to be created or modified + * @param value is the new value to be set + * @param leaseId is the lease attached to the key + */ + pplx::task 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 add(std::string const & key, std::string const & value); + pplx::task add(std::string const & key, std::string const & value, int ttl = 0); + + /** + * Creates a new key and sets it's value. Fails if the key already exists. + * @param key is the key to be created + * @param value is the value to be set + * @param leaseId is the lease attached to the key + */ + pplx::task add(std::string const & key, std::string const & value, int64_t leaseId); /** * 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 */ - pplx::task modify(std::string const & key, std::string const & value); + pplx::task modify(std::string const & key, std::string const & value, int ttl = 0); + + /** + * 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 + * @param leaseId is the lease attached to the key + */ + pplx::task 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 @@ -64,7 +91,17 @@ namespace etcd * @param value is the new value to be set * @param old_value is the value to be replaced */ - pplx::task modify_if(std::string const & key, std::string const & value, std::string const & old_value); + pplx::task modify_if(std::string const & key, std::string const & value, std::string const & old_value, int ttl = 0); + + /** + * Modifies an existing key only if it has a specific value. Fails if the key 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 + * @param leaseId is the lease attached to the key + */ + pplx::task 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 @@ -73,7 +110,17 @@ namespace etcd * @param value is the new value to be set * @param old_index is the expected index of the original value */ - pplx::task modify_if(std::string const & key, std::string const & value, int old_index); + pplx::task modify_if(std::string const & key, std::string const & value, int old_index, int ttl = 0); + + /** + * Modifies an existing key only if it has a specific modification index value. Fails if the key + * does not exists or the modification index of the previous value differs from the expected one. + * @param key is the key to be modified + * @param value is the new value to be set + * @param old_index is the expected index of the original value + * @param leaseId is the lease attached to the key + */ + pplx::task modify_if(std::string const & key, std::string const & value, int old_index, int64_t leaseId); /** * Removes a single key. The key has to point to a plain, non directory entry. @@ -128,10 +175,17 @@ namespace etcd */ pplx::task watch(std::string const & key, int fromIndex, bool recursive = false); - protected: + /** + * Grants a lease. + * @param ttl is the time to live of the lease + */ + pplx::task leasegrant(int ttl); + + private: std::unique_ptr stub_; std::unique_ptr watchServiceStub; + std::unique_ptr leaseServiceStub; }; diff --git a/etcd/Response.hpp b/etcd/Response.hpp index 0faf1c7..1b945f1 100644 --- a/etcd/Response.hpp +++ b/etcd/Response.hpp @@ -112,6 +112,7 @@ namespace etcd Keys _keys; friend class SyncClient; friend class etcdv3::AsyncWatchAction; + friend class Client; }; } diff --git a/etcd/Value.hpp b/etcd/Value.hpp index f91e5ca..f1e5b3b 100644 --- a/etcd/Value.hpp +++ b/etcd/Value.hpp @@ -4,7 +4,7 @@ #include #include #include -#include "proto/kv.pb.h" +#include "v3/include/KeyValue.hpp" namespace etcd { @@ -40,6 +40,13 @@ namespace etcd */ int modified_index() const; + /** + * Returns the ttl of this value or 0 if ttl is not set + */ + int ttl() const; + + int64_t lease() const; + protected: friend class Response; friend class BaseResponse; //deliberately done since Value class will be removed during full V3 @@ -47,12 +54,14 @@ namespace etcd friend class AsyncDeleteResponse; Value(); Value(web::json::value const & json_value); - Value(mvccpb::KeyValue const & kvs); + Value(etcdv3::KeyValue const & kvs); std::string _key; bool dir; std::string value; int created; int modified; + int _ttl; + int64_t leaseId; }; typedef std::vector Values; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index edb6a79..3f7567b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(etcd-cpp-api SHARED ../proto/kv.pb.cc ../proto/auth.pb.cc ../proto/rpc.pb.cc ../proto/rpc.grpc.pb.cc ../v3/src/AsyncTxnResponse.cpp ../v3/src/AsyncRangeResponse.cpp ../v3/src/Transaction.cpp ../v3/src/action_constants.cpp ../v3/src/AsyncSetAction.cpp ../v3/src/AsyncCompareAndSwapAction.cpp ../v3/src/AsyncUpdateAction.cpp ../v3/src/AsyncGetAction.cpp ../v3/src/AsyncDeleteAction.cpp ../v3/src/AsyncCompareAndDeleteAction.cpp ../v3/src/Action.cpp ../v3/src/AsyncWatchAction.cpp ../v3/src/V3Response.cpp ../v3/src/AsyncDeleteRangeResponse.cpp ../v3/src/AsyncWatchResponse.cpp Client.cpp Response.cpp Value.cpp SyncClient.cpp Watcher.cpp) +add_library(etcd-cpp-api SHARED ../proto/kv.pb.cc ../proto/auth.pb.cc ../proto/rpc.pb.cc ../proto/rpc.grpc.pb.cc ../v3/src/AsyncTxnResponse.cpp ../v3/src/AsyncRangeResponse.cpp ../v3/src/Transaction.cpp ../v3/src/action_constants.cpp ../v3/src/AsyncSetAction.cpp ../v3/src/AsyncCompareAndSwapAction.cpp ../v3/src/AsyncUpdateAction.cpp ../v3/src/AsyncGetAction.cpp ../v3/src/AsyncDeleteAction.cpp ../v3/src/AsyncCompareAndDeleteAction.cpp ../v3/src/Action.cpp ../v3/src/AsyncWatchAction.cpp ../v3/src/V3Response.cpp ../v3/src/AsyncDeleteRangeResponse.cpp ../v3/src/AsyncWatchResponse.cpp ../v3/src/AsyncLeaseGrantResponse.cpp ../v3/src/AsyncLeaseGrantAction.cpp ../v3/src/KeyValue.cpp Client.cpp Response.cpp Value.cpp SyncClient.cpp Watcher.cpp) set_property(TARGET etcd-cpp-api PROPERTY CXX_STANDARD 11) target_link_libraries(etcd-cpp-api ${CPPREST_LIB} boost_system ssl crypto protobuf grpc++) diff --git a/src/Client.cpp b/src/Client.cpp index 31dd760..6fc8153 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -15,14 +15,11 @@ #include "v3/include/AsyncGetAction.hpp" #include "v3/include/AsyncDeleteAction.hpp" #include "v3/include/AsyncWatchAction.hpp" +#include "v3/include/AsyncLeaseGrantAction.hpp" + using grpc::Channel; -using etcdserverpb::PutRequest; -using etcdserverpb::RangeRequest; -using etcdserverpb::TxnRequest; -using etcdserverpb::DeleteRangeRequest; -using etcdserverpb::Compare; -using etcdserverpb::RequestOp; + etcd::Client::Client(std::string const & address) @@ -37,6 +34,7 @@ etcd::Client::Client(std::string const & address) std::shared_ptr channel = grpc::CreateChannel(stripped_address, grpc::InsecureChannelCredentials()); stub_= KV::NewStub(channel); watchServiceStub= Watch::NewStub(channel); + leaseServiceStub= Lease::NewStub(channel); } @@ -50,57 +48,197 @@ pplx::task etcd::Client::get(std::string const & key) return Response::create(call); } -pplx::task etcd::Client::set(std::string const & key, std::string const & value) +pplx::task etcd::Client::set(std::string const & key, std::string const & value, int ttl) { etcdv3::ActionParameters params; params.key.assign(key); params.value.assign(value); params.kv_stub = stub_.get(); + + if(ttl > 0) + { + auto res = leasegrant(ttl).get(); + if(!res.is_ok()) + { + return pplx::task([res]() + { + return etcd::Response(res.error_code(), res.error_message().c_str()); + }); + } + else + { + params.lease_id = res.value().lease(); + } + } + std::shared_ptr call(new etcdv3::AsyncSetAction(params)); - return Response::create(call);; + return Response::create(call); } -pplx::task etcd::Client::add(std::string const & key, std::string const & value) +pplx::task etcd::Client::set(std::string const & key, std::string const & value, int64_t leaseid) { etcdv3::ActionParameters params; params.key.assign(key); params.value.assign(value); + params.lease_id = leaseid; + params.kv_stub = stub_.get(); + std::shared_ptr call(new etcdv3::AsyncSetAction(params)); + return Response::create(call); +} + + +pplx::task etcd::Client::add(std::string const & key, std::string const & value, int ttl) +{ + etcdv3::ActionParameters params; + params.key.assign(key); + params.value.assign(value); + params.kv_stub = stub_.get(); + + if(ttl > 0) + { + auto res = leasegrant(ttl).get(); + if(!res.is_ok()) + { + return pplx::task([res]() + { + return etcd::Response(res.error_code(), res.error_message().c_str()); + }); + } + else + { + params.lease_id = res.value().lease(); + } + } + std::shared_ptr call(new etcdv3::AsyncSetAction(params,true)); + return Response::create(call); +} + +pplx::task etcd::Client::add(std::string const & key, std::string const & value, int64_t leaseid) +{ + etcdv3::ActionParameters params; + params.key.assign(key); + params.value.assign(value); + params.lease_id = leaseid; params.kv_stub = stub_.get(); std::shared_ptr call(new etcdv3::AsyncSetAction(params,true)); return Response::create(call); } -pplx::task etcd::Client::modify(std::string const & key, std::string const & value) + +pplx::task etcd::Client::modify(std::string const & key, std::string const & value, int ttl) { etcdv3::ActionParameters params; params.key.assign(key); params.value.assign(value); params.kv_stub = stub_.get(); + + if(ttl > 0) + { + auto res = leasegrant(ttl).get(); + if(!res.is_ok()) + { + return pplx::task([res]() + { + return etcd::Response(res.error_code(), res.error_message().c_str()); + }); + } + else + { + params.lease_id = res.value().lease(); + } + } + std::shared_ptr call(new etcdv3::AsyncUpdateAction(params)); + return Response::create(call); +} + +pplx::task etcd::Client::modify(std::string const & key, std::string const & value, int64_t leaseid) +{ + etcdv3::ActionParameters params; + params.key.assign(key); + params.value.assign(value); + params.lease_id = leaseid; + params.kv_stub = stub_.get(); std::shared_ptr call(new etcdv3::AsyncUpdateAction(params)); return Response::create(call); } -pplx::task etcd::Client::modify_if(std::string const & key, std::string const & value, std::string const & old_value) +pplx::task etcd::Client::modify_if(std::string const & key, std::string const & value, std::string const & old_value, int ttl) { etcdv3::ActionParameters params; params.key.assign(key); params.value.assign(value); params.old_value.assign(old_value); params.kv_stub = stub_.get(); + + if(ttl > 0) + { + auto res = leasegrant(ttl).get(); + if(!res.is_ok()) + { + return pplx::task([res]() + { + return etcd::Response(res.error_code(), res.error_message().c_str()); + }); + } + else + { + params.lease_id = res.value().lease(); + } + } + std::shared_ptr call(new etcdv3::AsyncCompareAndSwapAction(params,etcdv3::Atomicity_Type::PREV_VALUE)); + return Response::create(call); +} + +pplx::task etcd::Client::modify_if(std::string const & key, std::string const & value, std::string const & old_value, int64_t leaseid) +{ + etcdv3::ActionParameters params; + params.key.assign(key); + params.value.assign(value); + params.old_value.assign(old_value); + params.lease_id = leaseid; + params.kv_stub = stub_.get(); std::shared_ptr call(new etcdv3::AsyncCompareAndSwapAction(params,etcdv3::Atomicity_Type::PREV_VALUE)); return Response::create(call); } -pplx::task etcd::Client::modify_if(std::string const & key, std::string const & value, int old_index) + +pplx::task etcd::Client::modify_if(std::string const & key, std::string const & value, int old_index, int ttl) { etcdv3::ActionParameters params; params.key.assign(key); params.value.assign(value); params.old_revision = old_index; params.kv_stub = stub_.get(); - std::shared_ptr call(new etcdv3::AsyncCompareAndSwapAction(params,etcdv3::Atomicity_Type::PREV_INDEX));; + if(ttl > 0) + { + auto res = leasegrant(ttl).get(); + if(!res.is_ok()) + { + return pplx::task([res]() + { + return etcd::Response(res.error_code(), res.error_message().c_str()); + }); + } + else + { + params.lease_id = res.value().lease(); + } + } + std::shared_ptr call(new etcdv3::AsyncCompareAndSwapAction(params,etcdv3::Atomicity_Type::PREV_INDEX)); + return Response::create(call); +} + +pplx::task etcd::Client::modify_if(std::string const & key, std::string const & value, int old_index, int64_t leaseid) +{ + etcdv3::ActionParameters params; + params.key.assign(key); + params.value.assign(value); + params.lease_id = leaseid; + params.old_revision = old_index; + params.kv_stub = stub_.get(); + std::shared_ptr call(new etcdv3::AsyncCompareAndSwapAction(params,etcdv3::Atomicity_Type::PREV_INDEX)); return Response::create(call); } @@ -122,7 +260,7 @@ pplx::task etcd::Client::rm_if(std::string const & key, std::str params.key.assign(key); params.old_value.assign(old_value); params.kv_stub = stub_.get(); - std::shared_ptr call(new etcdv3::AsyncCompareAndDeleteAction(params,etcdv3::Atomicity_Type::PREV_VALUE));; + std::shared_ptr call(new etcdv3::AsyncCompareAndDeleteAction(params,etcdv3::Atomicity_Type::PREV_VALUE)); return Response::create(call); } @@ -163,7 +301,6 @@ pplx::task etcd::Client::watch(std::string const & key, bool rec params.key.assign(key); params.withPrefix = recursive; params.watch_stub = watchServiceStub.get(); - params.revision = 0; std::shared_ptr call(new etcdv3::AsyncWatchAction(params)); return Response::create(call); } @@ -179,4 +316,14 @@ pplx::task etcd::Client::watch(std::string const & key, int from return Response::create(call); } +pplx::task etcd::Client::leasegrant(int ttl) +{ + etcdv3::ActionParameters params; + params.ttl = ttl; + params.lease_stub = leaseServiceStub.get(); + std::shared_ptr call(new etcdv3::AsyncLeaseGrantAction(params)); + return Response::create(call); +} + + diff --git a/src/Value.cpp b/src/Value.cpp index dc16a93..8e0820f 100644 --- a/src/Value.cpp +++ b/src/Value.cpp @@ -1,21 +1,26 @@ +#include #include "etcd/Value.hpp" -#include "proto/kv.pb.h" +#include "v3/include/KeyValue.hpp" etcd::Value::Value() : dir(false), created(0), - modified(0) + modified(0), + _ttl(0), + leaseId(0) { } -etcd::Value::Value(mvccpb::KeyValue const & kvs) +etcd::Value::Value(etcdv3::KeyValue const & kvs) { dir=false; _key=kvs.key(); value=kvs.value(); created=kvs.create_revision(); modified=kvs.mod_revision(); + leaseId = kvs.lease(); + _ttl = kvs.get_ttl(); } std::string const & etcd::Value::key() const @@ -42,3 +47,15 @@ int etcd::Value::modified_index() const { return modified; } + +int etcd::Value::ttl() const +{ + return _ttl; +} + +int64_t etcd::Value::lease() const +{ + return leaseId; +} + + diff --git a/tst/EtcdTest.cpp b/tst/EtcdTest.cpp index f8ff1ea..1b66890 100644 --- a/tst/EtcdTest.cpp +++ b/tst/EtcdTest.cpp @@ -75,6 +75,14 @@ TEST_CASE("set a key") CHECK("43" == etcd.set("/test/key2", "44").get().prev_value().as_string()); CHECK("" == etcd.set("/test/key3", "44").get().prev_value().as_string()); CHECK(0 == etcd.set("/test", "42").get().error_code()); // Not a file + + //set with ttl + resp = etcd.set("/test/key1", "50", 10).get(); + REQUIRE(0 == resp.error_code()); // overwrite + CHECK("set" == resp.action()); + CHECK("43" == resp.prev_value().as_string()); + CHECK("50" == resp.value().as_string()); + CHECK( 0 < resp.value().lease()); } TEST_CASE("atomic compare-and-swap") @@ -344,6 +352,86 @@ TEST_CASE("watch changes in the past") CHECK("45" == res.value().as_string()); } +TEST_CASE("lease grant") +{ + etcd::Client etcd("http://127.0.0.1:2379"); + etcd::Response res = etcd.leasegrant(60).get(); + REQUIRE(res.is_ok()); + CHECK(60 == res.value().ttl()); + CHECK(0 < res.value().lease()); + int64_t leaseid = res.value().lease(); + + res = etcd.set("/test/key1", "43", leaseid).get(); + REQUIRE(0 == res.error_code()); // overwrite + CHECK("set" == res.action()); + CHECK(leaseid == res.value().lease()); + + //change leaseid + res = etcd.leasegrant(10).get(); + leaseid = res.value().lease(); + res = etcd.set("/test/key1", "43", leaseid).get(); + REQUIRE(0 == res.error_code()); // overwrite + CHECK("set" == res.action()); + CHECK(leaseid == res.value().lease()); + + //failure to attach lease id + res = etcd.set("/test/key1", "43", leaseid+1).get(); + REQUIRE(!res.is_ok()); + REQUIRE(5 == res.error_code()); + CHECK("etcdserver: requested lease not found" == res.error_message()); + + res = etcd.modify("/test/key1", "44", leaseid).get(); + REQUIRE(0 == res.error_code()); // overwrite + CHECK("update" == res.action()); + CHECK(leaseid == res.value().lease()); + CHECK("44" == res.value().as_string()); + + //failure to attach lease id + res = etcd.modify("/test/key1", "45", leaseid+1).get(); + REQUIRE(!res.is_ok()); + REQUIRE(5 == res.error_code()); + CHECK("etcdserver: requested lease not found" == res.error_message()); + + res = etcd.modify_if("/test/key1", "45", "44", leaseid).get(); + int index = res.index(); + REQUIRE(res.is_ok()); + CHECK("compareAndSwap" == res.action()); + CHECK("45" == res.value().as_string()); + + //failure to attach lease id + res = etcd.modify_if("/test/key1", "46", "45", leaseid+1).get(); + REQUIRE(!res.is_ok()); + REQUIRE(5 == res.error_code()); + CHECK("etcdserver: requested lease not found" == res.error_message()); + + // succes with the correct index + res = etcd.modify_if("/test/key1", "44", index, leaseid).get(); + index = res.index(); + REQUIRE(res.is_ok()); + CHECK("compareAndSwap" == res.action()); + CHECK("44" == res.value().as_string()); + + res = etcd.modify_if("/test/key1", "44", index, leaseid+1).get(); + REQUIRE(!res.is_ok()); + REQUIRE(5 == res.error_code()); + CHECK("etcdserver: requested lease not found" == res.error_message()); + + res = etcd.add("/test/key11111", "43", leaseid).get(); + REQUIRE(0 == res.error_code()); + CHECK("create" == res.action()); + CHECK(leaseid == res.value().lease()); + + //failure to attach lease id + res = etcd.set("/test/key11111", "43", leaseid+1).get(); + REQUIRE(!res.is_ok()); + REQUIRE(5 == res.error_code()); + CHECK("etcdserver: requested lease not found" == res.error_message()); + + + + + +} TEST_CASE("cleanup") { diff --git a/tst/etcd_test b/tst/etcd_test index 62bc6ee..5dafdf5 100755 Binary files a/tst/etcd_test and b/tst/etcd_test differ diff --git a/v3/include/Action.hpp b/v3/include/Action.hpp index 29ace6b..7edec8f 100644 --- a/v3/include/Action.hpp +++ b/v3/include/Action.hpp @@ -10,6 +10,7 @@ using grpc::Status; using etcdserverpb::KV; using etcdserverpb::Watch; +using etcdserverpb::Lease; namespace etcdv3 { @@ -21,14 +22,18 @@ namespace etcdv3 struct ActionParameters { + ActionParameters(); bool withPrefix; int revision; int old_revision; + int64_t lease_id; + int ttl; std::string key; std::string value; std::string old_value; KV::Stub* kv_stub; Watch::Stub* watch_stub; + Lease::Stub* lease_stub; }; class Action diff --git a/v3/include/AsyncLeaseGrantAction.hpp b/v3/include/AsyncLeaseGrantAction.hpp new file mode 100644 index 0000000..892f48c --- /dev/null +++ b/v3/include/AsyncLeaseGrantAction.hpp @@ -0,0 +1,25 @@ +#ifndef __ASYNC_LEASEGRANTACTION_HPP__ +#define __ASYNC_LEASEGRANTACTION_HPP__ + +#include +#include "proto/rpc.grpc.pb.h" +#include "v3/include/Action.hpp" +#include "v3/include/AsyncLeaseGrantResponse.hpp" + +using grpc::ClientAsyncResponseReader; +using etcdserverpb::LeaseGrantResponse; + +namespace etcdv3 +{ + class AsyncLeaseGrantAction : public etcdv3::Action + { + public: + AsyncLeaseGrantAction(etcdv3::ActionParameters param); + AsyncLeaseGrantResponse ParseResponse(); + private: + LeaseGrantResponse reply; + std::unique_ptr> response_reader; + }; +} + +#endif diff --git a/v3/include/AsyncLeaseGrantResponse.hpp b/v3/include/AsyncLeaseGrantResponse.hpp new file mode 100644 index 0000000..3855c9b --- /dev/null +++ b/v3/include/AsyncLeaseGrantResponse.hpp @@ -0,0 +1,21 @@ +#ifndef __ASYNC_LEASEGRANTRESPONSE_HPP__ +#define __ASYNC_LEASEGRANTRESPONSE_HPP__ + +#include +#include "proto/rpc.grpc.pb.h" +#include "v3/include/V3Response.hpp" + + +using etcdserverpb::LeaseGrantResponse; + +namespace etcdv3 +{ + class AsyncLeaseGrantResponse : public etcdv3::V3Response + { + public: + AsyncLeaseGrantResponse(){}; + void ParseResponse(LeaseGrantResponse& resp); + }; +} + +#endif diff --git a/v3/include/KeyValue.hpp b/v3/include/KeyValue.hpp new file mode 100644 index 0000000..f2dfdaf --- /dev/null +++ b/v3/include/KeyValue.hpp @@ -0,0 +1,20 @@ +#ifndef __V3_ETCDV3KEYVALUE_HPP__ +#define __V3_ETCDV3KEYVALUE_HPP__ + +#include "proto/kv.pb.h" + + +namespace etcdv3 +{ + class KeyValue : public mvccpb::KeyValue + { + public: + KeyValue(); + KeyValue(const mvccpb::KeyValue& from); + void set_ttl(int ttl); + int get_ttl() const; + private: + int ttl; + }; +} +#endif diff --git a/v3/include/Transaction.hpp b/v3/include/Transaction.hpp index 3c3cb14..f15c2be 100644 --- a/v3/include/Transaction.hpp +++ b/v3/include/Transaction.hpp @@ -18,14 +18,16 @@ public: void init_compare(int, etcdserverpb::Compare::CompareResult, etcdserverpb::Compare::CompareTarget); void setup_basic_failure_operation(std::string const &key); - void setup_set_failure_operation(std::string const &key, std::string const &value); - void setup_basic_create_sequence(std::string const &key, std::string const &value); - void setup_compare_and_swap_sequence(std::string const &valueToSwap); + void setup_set_failure_operation(std::string const &key, std::string const &value, int64_t leaseid); + void setup_basic_create_sequence(std::string const &key, std::string const &value, int64_t leaseid); + void setup_compare_and_swap_sequence(std::string const &valueToSwap, int64_t leaseid); void setup_delete_sequence(std::string const &key, std::string const &range_end, bool recursive); void setup_delete_failure_operation(std::string const &key, std::string const &range_end, bool recursive); void setup_compare_and_delete_operation(std::string const& key); + void setup_lease_grant_operation(int ttl); etcdserverpb::TxnRequest txn_request; + etcdserverpb::LeaseGrantRequest leasegrant_request; private: std::string key; diff --git a/v3/include/V3Response.hpp b/v3/include/V3Response.hpp index 5b864dd..a293adb 100644 --- a/v3/include/V3Response.hpp +++ b/v3/include/V3Response.hpp @@ -2,14 +2,14 @@ #define __V3_RESPONSE_HPP__ #include -#include "proto/kv.pb.h" +#include "v3/include/KeyValue.hpp" namespace etcdv3 { class V3Response { public: - V3Response(): error_code(0), index(0), isPrefix(false) {}; + V3Response(): error_code(0), index(0){}; void set_error_code(int code); int get_error_code() const; std::string const & get_error_message() const; @@ -17,21 +17,20 @@ namespace etcdv3 void set_action(std::string action); int get_index() const; std::string const & get_action() const; - std::vector const & get_values() const; - std::vector const & get_prev_values() const; - mvccpb::KeyValue const & get_value() const; - mvccpb::KeyValue const & get_prev_value() const; + std::vector const & get_values() const; + std::vector const & get_prev_values() const; + etcdv3::KeyValue const & get_value() const; + etcdv3::KeyValue const & get_prev_value() const; bool has_values() const; protected: int error_code; int index; - bool isPrefix; std::string error_message; std::string action; - mvccpb::KeyValue value; - mvccpb::KeyValue prev_value; - std::vector values; - std::vector prev_values; + etcdv3::KeyValue value; + etcdv3::KeyValue prev_value; + std::vector values; + std::vector prev_values; }; } #endif diff --git a/v3/src/Action.cpp b/v3/src/Action.cpp index 392954b..747afe6 100644 --- a/v3/src/Action.cpp +++ b/v3/src/Action.cpp @@ -5,6 +5,18 @@ etcdv3::Action::Action(etcdv3::ActionParameters params) parameters = params; } +etcdv3::ActionParameters::ActionParameters() +{ + withPrefix = false; + revision = 0; + old_revision = 0; + lease_id = 0; + ttl = 0; + kv_stub = NULL; + watch_stub = NULL; + lease_stub = NULL; +} + void etcdv3::Action::waitForResponse() { void* got_tag; diff --git a/v3/src/AsyncCompareAndSwapAction.cpp b/v3/src/AsyncCompareAndSwapAction.cpp index 5f3900b..85974e8 100644 --- a/v3/src/AsyncCompareAndSwapAction.cpp +++ b/v3/src/AsyncCompareAndSwapAction.cpp @@ -25,7 +25,7 @@ etcdv3::AsyncCompareAndSwapAction::AsyncCompareAndSwapAction(etcdv3::ActionParam } transaction.setup_basic_failure_operation(parameters.key); - transaction.setup_compare_and_swap_sequence(parameters.value); + transaction.setup_compare_and_swap_sequence(parameters.value, parameters.lease_id); response_reader = parameters.kv_stub->AsyncTxn(&context, transaction.txn_request, &cq_); response_reader->Finish(&reply, &status, (void*)this); diff --git a/v3/src/AsyncLeaseGrantAction.cpp b/v3/src/AsyncLeaseGrantAction.cpp new file mode 100644 index 0000000..087f658 --- /dev/null +++ b/v3/src/AsyncLeaseGrantAction.cpp @@ -0,0 +1,32 @@ +#include "v3/include/AsyncLeaseGrantAction.hpp" +#include "v3/include/action_constants.hpp" +#include "v3/include/Transaction.hpp" + +using etcdserverpb::LeaseGrantRequest; + +etcdv3::AsyncLeaseGrantAction::AsyncLeaseGrantAction(etcdv3::ActionParameters param) + : etcdv3::Action(param) +{ + etcdv3::Transaction transaction; + transaction.setup_lease_grant_operation(parameters.ttl); + + response_reader = parameters.lease_stub->AsyncLeaseGrant(&context, transaction.leasegrant_request, &cq_); + response_reader->Finish(&reply, &status, (void*)this); + +} + + +etcdv3::AsyncLeaseGrantResponse etcdv3::AsyncLeaseGrantAction::ParseResponse() +{ + AsyncLeaseGrantResponse lease_resp; + if(!status.ok()) + { + lease_resp.set_error_code(status.error_code()); + lease_resp.set_error_message(status.error_message()); + } + else + { + lease_resp.ParseResponse(reply); + } + return lease_resp; +} diff --git a/v3/src/AsyncLeaseGrantResponse.cpp b/v3/src/AsyncLeaseGrantResponse.cpp new file mode 100644 index 0000000..f20e2da --- /dev/null +++ b/v3/src/AsyncLeaseGrantResponse.cpp @@ -0,0 +1,11 @@ +#include "v3/include/AsyncLeaseGrantResponse.hpp" +#include "v3/include/action_constants.hpp" + + +void etcdv3::AsyncLeaseGrantResponse::ParseResponse(LeaseGrantResponse& resp) +{ + index = resp.header().revision(); + value.set_lease(resp.id()); + value.set_ttl(resp.ttl()); + error_message = resp.error(); +} diff --git a/v3/src/AsyncRangeResponse.cpp b/v3/src/AsyncRangeResponse.cpp index 060f459..4df54a6 100644 --- a/v3/src/AsyncRangeResponse.cpp +++ b/v3/src/AsyncRangeResponse.cpp @@ -16,7 +16,8 @@ void etcdv3::AsyncRangeResponse::ParseResponse(RangeResponse& resp, bool prefix) { for(int index=0; index < resp.kvs_size(); index++) { - values.push_back(resp.kvs(index)); + etcdv3::KeyValue kvs(resp.kvs(index)); + values.push_back(kvs); } if(!prefix) diff --git a/v3/src/AsyncSetAction.cpp b/v3/src/AsyncSetAction.cpp index 5b71caf..ef374bf 100644 --- a/v3/src/AsyncSetAction.cpp +++ b/v3/src/AsyncSetAction.cpp @@ -1,14 +1,8 @@ #include "v3/include/AsyncSetAction.hpp" -#include "v3/include/AsyncRangeResponse.hpp" #include "v3/include/action_constants.hpp" #include "v3/include/Transaction.hpp" using etcdserverpb::Compare; -using etcdserverpb::RangeRequest; -using etcdserverpb::PutRequest; -using etcdserverpb::RequestOp; -using etcdserverpb::ResponseOp; -using etcdserverpb::TxnRequest; etcdv3::AsyncSetAction::AsyncSetAction(etcdv3::ActionParameters param, bool create) : etcdv3::Action(param) @@ -18,7 +12,7 @@ etcdv3::AsyncSetAction::AsyncSetAction(etcdv3::ActionParameters param, bool crea transaction.init_compare(Compare::CompareResult::Compare_CompareResult_EQUAL, Compare::CompareTarget::Compare_CompareTarget_VERSION); - transaction.setup_basic_create_sequence(parameters.key, parameters.value); + transaction.setup_basic_create_sequence(parameters.key, parameters.value, parameters.lease_id); if(isCreate) { @@ -26,7 +20,7 @@ etcdv3::AsyncSetAction::AsyncSetAction(etcdv3::ActionParameters param, bool crea } else { - transaction.setup_set_failure_operation(parameters.key, parameters.value); + transaction.setup_set_failure_operation(parameters.key, parameters.value, parameters.lease_id); } response_reader = parameters.kv_stub->AsyncTxn(&context, transaction.txn_request, &cq_); response_reader->Finish(&reply, &status, (void*)this); diff --git a/v3/src/AsyncTxnResponse.cpp b/v3/src/AsyncTxnResponse.cpp index 00d375e..6b6588b 100644 --- a/v3/src/AsyncTxnResponse.cpp +++ b/v3/src/AsyncTxnResponse.cpp @@ -27,7 +27,7 @@ void etcdv3::AsyncTxnResponse::ParseResponse(std::string const& key, bool prefix auto put_resp = resp.response_put(); if(put_resp.has_prev_kv()) { - prev_value = put_resp.prev_kv(); + prev_value.CopyFrom(put_resp.prev_kv()); } } else if(ResponseOp::ResponseCase::kResponseDeleteRange == resp.response_case()) @@ -35,7 +35,7 @@ void etcdv3::AsyncTxnResponse::ParseResponse(std::string const& key, bool prefix AsyncDeleteRangeResponse response; response.ParseResponse(key,prefix,*(resp.mutable_response_delete_range())); - prev_value = response.get_prev_value(); + prev_value.CopyFrom(response.get_prev_value()); values = response.get_values(); value = response.get_value(); diff --git a/v3/src/AsyncUpdateAction.cpp b/v3/src/AsyncUpdateAction.cpp index 123f9fa..8b76688 100644 --- a/v3/src/AsyncUpdateAction.cpp +++ b/v3/src/AsyncUpdateAction.cpp @@ -17,7 +17,7 @@ etcdv3::AsyncUpdateAction::AsyncUpdateAction(etcdv3::ActionParameters param) transaction.init_compare(Compare::CompareResult::Compare_CompareResult_GREATER, Compare::CompareTarget::Compare_CompareTarget_VERSION); - transaction.setup_compare_and_swap_sequence(parameters.value); + transaction.setup_compare_and_swap_sequence(parameters.value, parameters.lease_id); response_reader = parameters.kv_stub->AsyncTxn(&context, transaction.txn_request, &cq_); response_reader->Finish(&reply, &status, (void*)this); diff --git a/v3/src/KeyValue.cpp b/v3/src/KeyValue.cpp new file mode 100644 index 0000000..78d135a --- /dev/null +++ b/v3/src/KeyValue.cpp @@ -0,0 +1,22 @@ +#include "v3/include/KeyValue.hpp" + +etcdv3::KeyValue::KeyValue() +{ + ttl = 0; +} + +etcdv3::KeyValue::KeyValue(const mvccpb::KeyValue& from) + : mvccpb::KeyValue(from) +{ + ttl =0; +} + +void etcdv3::KeyValue::set_ttl(int ttl) +{ + this->ttl = ttl; +} + +int etcdv3::KeyValue::get_ttl() const +{ + return ttl; +} diff --git a/v3/src/Transaction.cpp b/v3/src/Transaction.cpp index 63b97e1..f354568 100644 --- a/v3/src/Transaction.cpp +++ b/v3/src/Transaction.cpp @@ -52,11 +52,12 @@ void etcdv3::Transaction::setup_basic_failure_operation(std::string const& key) /** * get key on failure, get key before put, modify and then get updated key */ -void etcdv3::Transaction::setup_set_failure_operation(std::string const &key, std::string const &value) { +void etcdv3::Transaction::setup_set_failure_operation(std::string const &key, std::string const &value, int64_t leaseid) { std::unique_ptr put_request(new PutRequest()); put_request->set_key(key); put_request->set_value(value); put_request->set_prev_kv(true); + put_request->set_lease(leaseid); RequestOp* req_failure = txn_request.add_failure(); req_failure->set_allocated_request_put(put_request.release()); @@ -97,11 +98,12 @@ void etcdv3::Transaction::setup_delete_failure_operation(std::string const &key, /** * add key and then get new value of key */ -void etcdv3::Transaction::setup_basic_create_sequence(std::string const& key, std::string const& value) { +void etcdv3::Transaction::setup_basic_create_sequence(std::string const& key, std::string const& value, int64_t leaseid) { std::unique_ptr put_request(new PutRequest()); put_request->set_key(key); put_request->set_value(value); put_request->set_prev_kv(true); + put_request->set_lease(leaseid); RequestOp* req_success = txn_request.add_success(); req_success->set_allocated_request_put(put_request.release()); @@ -114,11 +116,12 @@ void etcdv3::Transaction::setup_basic_create_sequence(std::string const& key, st /** * get key value then modify and get new value */ -void etcdv3::Transaction::setup_compare_and_swap_sequence(std::string const& value) { +void etcdv3::Transaction::setup_compare_and_swap_sequence(std::string const& value, int64_t leaseid) { std::unique_ptr put_request(new PutRequest()); put_request->set_key(key); put_request->set_value(value); put_request->set_prev_kv(true); + put_request->set_lease(leaseid); RequestOp* req_success = txn_request.add_success(); req_success->set_allocated_request_put(put_request.release()); @@ -152,6 +155,11 @@ void etcdv3::Transaction::setup_compare_and_delete_operation(std::string const& req_success->set_allocated_request_delete_range(del_request.release()); } +void etcdv3::Transaction::setup_lease_grant_operation(int ttl) +{ + leasegrant_request.set_ttl(ttl); +} + etcdv3::Transaction::~Transaction() { } diff --git a/v3/src/V3Response.cpp b/v3/src/V3Response.cpp index 822ce48..3aa0bec 100644 --- a/v3/src/V3Response.cpp +++ b/v3/src/V3Response.cpp @@ -36,22 +36,22 @@ void etcdv3::V3Response::set_action(std::string action) this->action = action; } -std::vector const & etcdv3::V3Response::get_values() const +std::vector const & etcdv3::V3Response::get_values() const { return values; } -std::vector const & etcdv3::V3Response::get_prev_values() const +std::vector const & etcdv3::V3Response::get_prev_values() const { return prev_values; } -mvccpb::KeyValue const & etcdv3::V3Response::get_value() const +etcdv3::KeyValue const & etcdv3::V3Response::get_value() const { return value; } -mvccpb::KeyValue const & etcdv3::V3Response::get_prev_value() const +etcdv3::KeyValue const & etcdv3::V3Response::get_prev_value() const { return prev_value; }