diff --git a/README.md b/README.md index dbd265f..1e0625e 100644 --- a/README.md +++ b/README.md @@ -557,6 +557,17 @@ keys defined by the prefix. mkdir method is removed since etcdv3 treats everythi } ``` + etcd-cpp-apiv3 supports lists keys only without fetching values from etcd server: + + ```c++ + etcd::Client etcd("http://127.0.0.1:2379"); + etcd::Response resp = etcd.keys("/test/new_dir").get(); + for (int i = 0; i < resp.keys().size(); ++i) + { + std::cout << resp.keys(i); + } + ``` + 3. Removing directory: If you want the delete recursively then you have to pass a second `true` parameter diff --git a/etcd/Client.hpp b/etcd/Client.hpp index 2e76935..43e84d3 100644 --- a/etcd/Client.hpp +++ b/etcd/Client.hpp @@ -373,12 +373,6 @@ namespace etcd */ pplx::task rm_if(std::string const & key, int64_t old_index); - /** - * Gets a directory listing of the directory identified by the key. - * @param key is the key to be listed - */ - pplx::task ls(std::string const & key); - /** * Removes a directory node. Fails if the parent directory dos not exists or not a directory. * @param key is the directory to be created to be listed @@ -405,7 +399,15 @@ namespace etcd pplx::task rmdir(std::string const & key, std::string const &range_end); /** - * Gets a directory listing of the directory identified by the key. + * Gets a directory listing of the directory prefixed by the key. + * + * @param key is the key to be listed + */ + pplx::task ls(std::string const & key); + + /** + * Gets a directory listing of the directory prefixed by the key. + * * @param key is the key to be listed * @param limit is the size limit of results to be listed, we don't use default parameters * to ensure backwards binary compatibility. @@ -421,10 +423,9 @@ namespace etcd */ pplx::task ls(std::string const & key, std::string const &range_end); - /** * Gets a directory listing of the directory identified by the key and range_end, i.e., get - * all keys in the range [key, range_end). + * all keys in the range [key, range_end), and respects the given limit. * * @param key is the key to be listed * @param range_end is the end of key range to be listed @@ -433,6 +434,50 @@ namespace etcd */ pplx::task ls(std::string const & key, std::string const &range_end, size_t const limit); + /** + * Gets a directory listing of the directory prefixed by the key. + * + * Note that only keys are included in the response. + * + * @param key is the key to be listed + */ + pplx::task keys(std::string const & key); + + /** + * Gets a directory listing of the directory prefixed by the key. + * + * Note that only keys are included in the response. + * + * @param key is the key to be listed + * @param limit is the size limit of results to be listed, we don't use default parameters + * to ensure backwards binary compatibility. + */ + pplx::task keys(std::string const & key, size_t const limit); + + /** + * List keys identified by the key and range_end, i.e., get all keys in the range [key, + * range_end), and respects the given limit. + * + * Note that only keys are included in the response. + * + * @param key is the key to be listed + * @param range_end is the end of key range to be listed + */ + pplx::task keys(std::string const & key, std::string const &range_end); + + /** + * List keys identified by the key and range_end, i.e., get all keys in the range [key, + * range_end). + * + * Note that only keys are included in the response. + * + * @param key is the key to be listed + * @param range_end is the end of key range to be listed + * @param limit is the size limit of results to be listed, we don't use default parameters + * to ensure backwards binary compatibility. + */ + pplx::task keys(std::string const & key, std::string const &range_end, size_t const limit); + /** * Watches for changes of a key or a subtree. Please note that if you watch e.g. "/testdir" and * a new key is created, like "/testdir/newkey" then no change happened in the value of diff --git a/etcd/SyncClient.hpp b/etcd/SyncClient.hpp index dfcc7da..121c2be 100644 --- a/etcd/SyncClient.hpp +++ b/etcd/SyncClient.hpp @@ -454,13 +454,15 @@ namespace etcd Response rmdir(std::string const & key, std::string const &range_end); /** - * Gets a directory listing of the directory identified by the key. + * Gets a directory listing of the directory prefixed by the key. + * * @param key is the key to be listed */ Response ls(std::string const & key); /** - * Gets a directory listing of the directory identified by the key. + * Gets a directory listing of the directory prefixed by the key. + * * @param key is the key to be listed * @param limit is the size limit of results to be listed, we don't use default parameters * to ensure backwards binary compatibility. @@ -478,7 +480,7 @@ namespace etcd /** * Gets a directory listing of the directory identified by the key and range_end, i.e., get - * all keys in the range [key, range_end). + * all keys in the range [key, range_end), and respects the given limit. * * @param key is the key to be listed * @param range_end is the end of key range to be listed @@ -487,6 +489,50 @@ namespace etcd */ Response ls(std::string const & key, std::string const &range_end, size_t const limit); + /** + * Gets a directory listing of the directory prefixed by the key. + * + * Note that only keys are included in the response. + * + * @param key is the key to be listed + */ + Response keys(std::string const & key); + + /** + * Gets a directory listing of the directory prefixed by the key. + * + * Note that only keys are included in the response. + * + * @param key is the key to be listed + * @param limit is the size limit of results to be listed, we don't use default parameters + * to ensure backwards binary compatibility. + */ + Response keys(std::string const & key, size_t const limit); + + /** + * List keys identified by the key and range_end, i.e., get all keys in the range [key, + * range_end). + * + * Note that only keys are included in the response. + * + * @param key is the key to be listed + * @param range_end is the end of key range to be listed + */ + Response keys(std::string const & key, std::string const &range_end); + + /** + * List keys identified by the key and range_end, i.e., get all keys in the range [key, + * range_end), and respects the given limit. + * + * Note that only keys are included in the response. + * + * @param key is the key to be listed + * @param range_end is the end of key range to be listed + * @param limit is the size limit of results to be listed, we don't use default parameters + * to ensure backwards binary compatibility. + */ + Response keys(std::string const & key, std::string const &range_end, size_t const limit); + /** * Watches for changes of a key or a subtree. Please note that if you watch e.g. "/testdir" and * a new key is created, like "/testdir/newkey" then no change happened in the value of @@ -684,8 +730,8 @@ namespace etcd std::shared_ptr rm_if_internal(std::string const & key, int64_t old_index, const std::string & old_value, etcdv3::AtomicityType const & atomicity_type); std::shared_ptr rmdir_internal(std::string const & key, bool recursive = false); std::shared_ptr rmdir_internal(std::string const & key, std::string const &range_end); - std::shared_ptr ls_internal(std::string const & key, size_t const limit); - std::shared_ptr ls_internal(std::string const & key, std::string const &range_end, size_t const limit); + std::shared_ptr ls_internal(std::string const & key, size_t const limit, bool const keys_only = false); + std::shared_ptr ls_internal(std::string const & key, std::string const &range_end, size_t const limit, bool const keys_only = false); std::shared_ptr watch_internal(std::string const & key, int64_t fromIndex, bool recursive = false); std::shared_ptr watch_internal(std::string const & key, std::string const &range_end, int64_t fromIndex); std::shared_ptr leaserevoke_internal(int64_t lease_id); diff --git a/etcd/v3/Action.hpp b/etcd/v3/Action.hpp index aa7df04..b4b76a0 100644 --- a/etcd/v3/Action.hpp +++ b/etcd/v3/Action.hpp @@ -43,6 +43,8 @@ namespace etcdv3 std::string name; // for campaign (in v3election) std::string key; std::string range_end; + bool keys_only; + bool count_only; std::string value; std::string old_value; std::string auth_token; diff --git a/src/Client.cpp b/src/Client.cpp index 96a09be..028ad72 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -487,6 +487,34 @@ pplx::task etcd::Client::ls(std::string const & key, std::string this->client->ls_internal(key, range_end, limit)); } +pplx::task etcd::Client::keys(std::string const & key) +{ + return etcd::detail::asyncify( + static_cast>(Response::create), + this->client->ls_internal(key, 0, true)); +} + +pplx::task etcd::Client::keys(std::string const & key, size_t const limit) +{ + return etcd::detail::asyncify( + static_cast>(Response::create), + this->client->ls_internal(key, limit, true)); +} + +pplx::task etcd::Client::keys(std::string const & key, std::string const &range_end) +{ + return etcd::detail::asyncify( + static_cast>(Response::create), + this->client->ls_internal(key, range_end, 0, true)); +} + +pplx::task etcd::Client::keys(std::string const & key, std::string const &range_end, size_t const limit) +{ + return etcd::detail::asyncify( + static_cast>(Response::create), + this->client->ls_internal(key, range_end, limit, true)); +} + pplx::task etcd::Client::watch(std::string const & key, bool recursive) { return etcd::detail::asyncify( diff --git a/src/SyncClient.cpp b/src/SyncClient.cpp index e6044a3..7114f1a 100644 --- a/src/SyncClient.cpp +++ b/src/SyncClient.cpp @@ -787,17 +787,6 @@ etcd::Response etcd::SyncClient::ls(std::string const & key, size_t const limit) return Response::create(this->ls_internal(key, limit)); } -std::shared_ptr etcd::SyncClient::ls_internal(std::string const & key, size_t const limit) { - etcdv3::ActionParameters params; - params.key.assign(key); - params.withPrefix = true; - params.limit = limit; - params.auth_token.assign(this->token_authenticator->renew_if_expired()); - params.grpc_timeout = this->grpc_timeout; - params.kv_stub = stubs->kvServiceStub.get(); - return std::make_shared(std::move(params)); -} - etcd::Response etcd::SyncClient::ls(std::string const & key, std::string const &range_end) { return Response::create(this->ls_internal(key, range_end, 0 /* default: no limit */)); @@ -808,10 +797,43 @@ etcd::Response etcd::SyncClient::ls(std::string const & key, std::string const & return Response::create(this->ls_internal(key, range_end, limit)); } -std::shared_ptr etcd::SyncClient::ls_internal(std::string const & key, std::string const &range_end, size_t const limit) { +etcd::Response etcd::SyncClient::keys(std::string const & key) +{ + return Response::create(this->ls_internal(key, 0 /* default: no limit */, true)); +} + +etcd::Response etcd::SyncClient::keys(std::string const & key, size_t const limit) +{ + return Response::create(this->ls_internal(key, limit, true)); +} + +etcd::Response etcd::SyncClient::keys(std::string const & key, std::string const &range_end) +{ + return Response::create(this->ls_internal(key, range_end, 0 /* default: no limit */, true)); +} + +etcd::Response etcd::SyncClient::keys(std::string const & key, std::string const &range_end, size_t const limit) +{ + return Response::create(this->ls_internal(key, range_end, limit, true)); +} + +std::shared_ptr etcd::SyncClient::ls_internal(std::string const & key, size_t const limit, bool const keys_only) { + etcdv3::ActionParameters params; + params.key.assign(key); + params.keys_only = keys_only; + params.withPrefix = true; + params.limit = limit; + params.auth_token.assign(this->token_authenticator->renew_if_expired()); + params.grpc_timeout = this->grpc_timeout; + params.kv_stub = stubs->kvServiceStub.get(); + return std::make_shared(std::move(params)); +} + +std::shared_ptr etcd::SyncClient::ls_internal(std::string const & key, std::string const &range_end, size_t const limit, bool const keys_only) { etcdv3::ActionParameters params; params.key.assign(key); params.range_end.assign(range_end); + params.keys_only = keys_only; params.withPrefix = false; params.limit = limit; params.auth_token.assign(this->token_authenticator->renew_if_expired()); diff --git a/src/v3/Action.cpp b/src/v3/Action.cpp index dfe7e84..aafb64d 100644 --- a/src/v3/Action.cpp +++ b/src/v3/Action.cpp @@ -32,6 +32,8 @@ etcdv3::ActionParameters::ActionParameters() old_revision = 0; lease_id = 0; ttl = 0; + keys_only = false; + count_only = false; kv_stub = NULL; watch_stub = NULL; lease_stub = NULL; @@ -56,6 +58,8 @@ void etcdv3::ActionParameters::dump(std::ostream &os) const { os << " name: " << name << std::endl; os << " key: " << key << std::endl; os << " range_end: " << range_end << std::endl; + os << " keys_only: " << keys_only << std::endl; + os << " count_only: " << count_only << std::endl; os << " value: " << value << std::endl; os << " old_value: " << old_value << std::endl; os << " auth_token: " << auth_token << std::endl; diff --git a/src/v3/AsyncRangeAction.cpp b/src/v3/AsyncRangeAction.cpp index 123c36b..9b64c8f 100644 --- a/src/v3/AsyncRangeAction.cpp +++ b/src/v3/AsyncRangeAction.cpp @@ -30,6 +30,10 @@ etcdv3::AsyncRangeAction::AsyncRangeAction( } get_request.set_sort_order(RangeRequest::SortOrder::RangeRequest_SortOrder_NONE); + // set keys_only and count_only + get_request.set_keys_only(params.keys_only); + get_request.set_count_only(params.count_only); + response_reader = parameters.kv_stub->AsyncRange(&context,get_request,&cq_); response_reader->Finish(&reply, &status, (void*)this); } diff --git a/tst/EtcdSyncTest.cpp b/tst/EtcdSyncTest.cpp index dd202ba..87eb316 100644 --- a/tst/EtcdSyncTest.cpp +++ b/tst/EtcdSyncTest.cpp @@ -45,6 +45,12 @@ TEST_CASE("sync operations") etcd.set("/test/new_dir/key2", "value2"); CHECK(2 == etcd.ls("/test/new_dir").keys().size()); + // keys + CHECK(0 == etcd.keys("/test/new_dir").keys().size()); + etcd.set("/test/new_dir/key1", "value1"); + etcd.set("/test/new_dir/key2", "value2"); + CHECK(2 == etcd.keys("/test/new_dir").keys().size()); + // rmdir 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()); diff --git a/tst/EtcdTest.cpp b/tst/EtcdTest.cpp index ff3a16c..7161831 100644 --- a/tst/EtcdTest.cpp +++ b/tst/EtcdTest.cpp @@ -326,6 +326,36 @@ TEST_CASE("list by range") CHECK(etcd.rmdir("/test/new_dir", true).get().is_ok()); } +TEST_CASE("list by range, w/o values") +{ + etcd::Client etcd(etcd_url); + CHECK(0 == etcd.ls("/test/new_dir").get().keys().size()); + + etcd.set("/test/new_dir/key0", "value0").wait(); + etcd.set("/test/new_dir/key1", "value1").wait(); + etcd.set("/test/new_dir/key2", "value2").wait(); + etcd.set("/test/new_dir/key3", "value3").wait(); + etcd.set("/test/new_dir/key4", "value4").wait(); + + etcd::Response resp1 = etcd.ls("/test/new_dir/key1", "/test/new_dir/key3").get(); + REQUIRE(resp1.is_ok()); + CHECK("get" == resp1.action()); + REQUIRE(2 == resp1.keys().size()); + REQUIRE(2 == resp1.values().size()); + REQUIRE(resp1.values()[0].as_string() == "value0"); + REQUIRE(resp1.values()[1].as_string() == "value1"); + + etcd::Response resp2 = etcd.keys("/test/new_dir/key1", "/test/new_dir/key3").get(); + REQUIRE(resp1.is_ok()); + CHECK("get" == resp2.action()); + REQUIRE(2 == resp2.keys().size()); + REQUIRE(2 == resp2.values().size()); + REQUIRE(resp2.values()[0].as_string() == ""); + REQUIRE(resp2.values()[1].as_string() == ""); + + CHECK(etcd.rmdir("/test/new_dir", true).get().is_ok()); +} + TEST_CASE("delete a directory") { etcd::Client etcd(etcd_url);