mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-17 13:13:36 +00:00
Improve performance of TestKeeper
This commit is contained in:
parent
ffe2cecb1b
commit
b665413869
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
|
||||||
namespace Coordination
|
namespace Coordination
|
||||||
@ -25,11 +26,14 @@ static String baseName(const String & path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
using Undo = std::function<void()>;
|
||||||
|
|
||||||
|
|
||||||
struct TestKeeperRequest : virtual Request
|
struct TestKeeperRequest : virtual Request
|
||||||
{
|
{
|
||||||
virtual bool isMutable() const { return false; }
|
virtual bool isMutable() const { return false; }
|
||||||
virtual ResponsePtr createResponse() const = 0;
|
virtual ResponsePtr createResponse() const = 0;
|
||||||
virtual ResponsePtr process(TestKeeper::Container & container, int64_t zxid) const = 0;
|
virtual std::pair<ResponsePtr, Undo> process(TestKeeper::Container & container, int64_t zxid) const = 0;
|
||||||
virtual void processWatches(TestKeeper::Watches & /*watches*/, TestKeeper::Watches & /*list_watches*/) const {}
|
virtual void processWatches(TestKeeper::Watches & /*watches*/, TestKeeper::Watches & /*list_watches*/) const {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -69,7 +73,7 @@ struct TestKeeperCreateRequest final : CreateRequest, TestKeeperRequest
|
|||||||
TestKeeperCreateRequest() = default;
|
TestKeeperCreateRequest() = default;
|
||||||
explicit TestKeeperCreateRequest(const CreateRequest & base) : CreateRequest(base) {}
|
explicit TestKeeperCreateRequest(const CreateRequest & base) : CreateRequest(base) {}
|
||||||
ResponsePtr createResponse() const override;
|
ResponsePtr createResponse() const override;
|
||||||
ResponsePtr process(TestKeeper::Container & container, int64_t zxid) const override;
|
std::pair<ResponsePtr, Undo> process(TestKeeper::Container & container, int64_t zxid) const override;
|
||||||
|
|
||||||
void processWatches(TestKeeper::Watches & node_watches, TestKeeper::Watches & list_watches) const override
|
void processWatches(TestKeeper::Watches & node_watches, TestKeeper::Watches & list_watches) const override
|
||||||
{
|
{
|
||||||
@ -83,7 +87,7 @@ struct TestKeeperRemoveRequest final : RemoveRequest, TestKeeperRequest
|
|||||||
explicit TestKeeperRemoveRequest(const RemoveRequest & base) : RemoveRequest(base) {}
|
explicit TestKeeperRemoveRequest(const RemoveRequest & base) : RemoveRequest(base) {}
|
||||||
bool isMutable() const override { return true; }
|
bool isMutable() const override { return true; }
|
||||||
ResponsePtr createResponse() const override;
|
ResponsePtr createResponse() const override;
|
||||||
ResponsePtr process(TestKeeper::Container & container, int64_t zxid) const override;
|
std::pair<ResponsePtr, Undo> process(TestKeeper::Container & container, int64_t zxid) const override;
|
||||||
|
|
||||||
void processWatches(TestKeeper::Watches & node_watches, TestKeeper::Watches & list_watches) const override
|
void processWatches(TestKeeper::Watches & node_watches, TestKeeper::Watches & list_watches) const override
|
||||||
{
|
{
|
||||||
@ -94,14 +98,14 @@ struct TestKeeperRemoveRequest final : RemoveRequest, TestKeeperRequest
|
|||||||
struct TestKeeperExistsRequest final : ExistsRequest, TestKeeperRequest
|
struct TestKeeperExistsRequest final : ExistsRequest, TestKeeperRequest
|
||||||
{
|
{
|
||||||
ResponsePtr createResponse() const override;
|
ResponsePtr createResponse() const override;
|
||||||
ResponsePtr process(TestKeeper::Container & container, int64_t zxid) const override;
|
std::pair<ResponsePtr, Undo> process(TestKeeper::Container & container, int64_t zxid) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TestKeeperGetRequest final : GetRequest, TestKeeperRequest
|
struct TestKeeperGetRequest final : GetRequest, TestKeeperRequest
|
||||||
{
|
{
|
||||||
TestKeeperGetRequest() = default;
|
TestKeeperGetRequest() = default;
|
||||||
ResponsePtr createResponse() const override;
|
ResponsePtr createResponse() const override;
|
||||||
ResponsePtr process(TestKeeper::Container & container, int64_t zxid) const override;
|
std::pair<ResponsePtr, Undo> process(TestKeeper::Container & container, int64_t zxid) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TestKeeperSetRequest final : SetRequest, TestKeeperRequest
|
struct TestKeeperSetRequest final : SetRequest, TestKeeperRequest
|
||||||
@ -110,7 +114,7 @@ struct TestKeeperSetRequest final : SetRequest, TestKeeperRequest
|
|||||||
explicit TestKeeperSetRequest(const SetRequest & base) : SetRequest(base) {}
|
explicit TestKeeperSetRequest(const SetRequest & base) : SetRequest(base) {}
|
||||||
bool isMutable() const override { return true; }
|
bool isMutable() const override { return true; }
|
||||||
ResponsePtr createResponse() const override;
|
ResponsePtr createResponse() const override;
|
||||||
ResponsePtr process(TestKeeper::Container & container, int64_t zxid) const override;
|
std::pair<ResponsePtr, Undo> process(TestKeeper::Container & container, int64_t zxid) const override;
|
||||||
|
|
||||||
void processWatches(TestKeeper::Watches & node_watches, TestKeeper::Watches & list_watches) const override
|
void processWatches(TestKeeper::Watches & node_watches, TestKeeper::Watches & list_watches) const override
|
||||||
{
|
{
|
||||||
@ -121,7 +125,7 @@ struct TestKeeperSetRequest final : SetRequest, TestKeeperRequest
|
|||||||
struct TestKeeperListRequest final : ListRequest, TestKeeperRequest
|
struct TestKeeperListRequest final : ListRequest, TestKeeperRequest
|
||||||
{
|
{
|
||||||
ResponsePtr createResponse() const override;
|
ResponsePtr createResponse() const override;
|
||||||
ResponsePtr process(TestKeeper::Container & container, int64_t zxid) const override;
|
std::pair<ResponsePtr, Undo> process(TestKeeper::Container & container, int64_t zxid) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TestKeeperCheckRequest final : CheckRequest, TestKeeperRequest
|
struct TestKeeperCheckRequest final : CheckRequest, TestKeeperRequest
|
||||||
@ -129,7 +133,7 @@ struct TestKeeperCheckRequest final : CheckRequest, TestKeeperRequest
|
|||||||
TestKeeperCheckRequest() = default;
|
TestKeeperCheckRequest() = default;
|
||||||
explicit TestKeeperCheckRequest(const CheckRequest & base) : CheckRequest(base) {}
|
explicit TestKeeperCheckRequest(const CheckRequest & base) : CheckRequest(base) {}
|
||||||
ResponsePtr createResponse() const override;
|
ResponsePtr createResponse() const override;
|
||||||
ResponsePtr process(TestKeeper::Container & container, int64_t zxid) const override;
|
std::pair<ResponsePtr, Undo> process(TestKeeper::Container & container, int64_t zxid) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TestKeeperMultiRequest final : MultiRequest, TestKeeperRequest
|
struct TestKeeperMultiRequest final : MultiRequest, TestKeeperRequest
|
||||||
@ -169,13 +173,15 @@ struct TestKeeperMultiRequest final : MultiRequest, TestKeeperRequest
|
|||||||
}
|
}
|
||||||
|
|
||||||
ResponsePtr createResponse() const override;
|
ResponsePtr createResponse() const override;
|
||||||
ResponsePtr process(TestKeeper::Container & container, int64_t zxid) const override;
|
std::pair<ResponsePtr, Undo> process(TestKeeper::Container & container, int64_t zxid) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
ResponsePtr TestKeeperCreateRequest::process(TestKeeper::Container & container, int64_t zxid) const
|
std::pair<ResponsePtr, Undo> TestKeeperCreateRequest::process(TestKeeper::Container & container, int64_t zxid) const
|
||||||
{
|
{
|
||||||
CreateResponse response;
|
CreateResponse response;
|
||||||
|
Undo undo;
|
||||||
|
|
||||||
if (container.count(path))
|
if (container.count(path))
|
||||||
{
|
{
|
||||||
response.error = Error::ZNODEEXISTS;
|
response.error = Error::ZNODEEXISTS;
|
||||||
@ -219,7 +225,18 @@ ResponsePtr TestKeeperCreateRequest::process(TestKeeper::Container & container,
|
|||||||
}
|
}
|
||||||
|
|
||||||
response.path_created = path_created;
|
response.path_created = path_created;
|
||||||
container.emplace(std::move(path_created), std::move(created_node));
|
container.emplace(path_created, std::move(created_node));
|
||||||
|
|
||||||
|
undo = [&container, path_created, is_sequential = is_sequential, parent_path = it->first]
|
||||||
|
{
|
||||||
|
container.erase(path_created);
|
||||||
|
auto & undo_parent = container.at(parent_path);
|
||||||
|
--undo_parent.stat.cversion;
|
||||||
|
--undo_parent.stat.numChildren;
|
||||||
|
|
||||||
|
if (is_sequential)
|
||||||
|
--undo_parent.seq_num;
|
||||||
|
};
|
||||||
|
|
||||||
++it->second.stat.cversion;
|
++it->second.stat.cversion;
|
||||||
++it->second.stat.numChildren;
|
++it->second.stat.numChildren;
|
||||||
@ -228,12 +245,13 @@ ResponsePtr TestKeeperCreateRequest::process(TestKeeper::Container & container,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<CreateResponse>(response);
|
return { std::make_shared<CreateResponse>(response), undo };
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponsePtr TestKeeperRemoveRequest::process(TestKeeper::Container & container, int64_t) const
|
std::pair<ResponsePtr, Undo> TestKeeperRemoveRequest::process(TestKeeper::Container & container, int64_t) const
|
||||||
{
|
{
|
||||||
RemoveResponse response;
|
RemoveResponse response;
|
||||||
|
Undo undo;
|
||||||
|
|
||||||
auto it = container.find(path);
|
auto it = container.find(path);
|
||||||
if (it == container.end())
|
if (it == container.end())
|
||||||
@ -250,17 +268,26 @@ ResponsePtr TestKeeperRemoveRequest::process(TestKeeper::Container & container,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
auto prev_node = it->second;
|
||||||
container.erase(it);
|
container.erase(it);
|
||||||
auto & parent = container.at(parentPath(path));
|
auto & parent = container.at(parentPath(path));
|
||||||
--parent.stat.numChildren;
|
--parent.stat.numChildren;
|
||||||
++parent.stat.cversion;
|
++parent.stat.cversion;
|
||||||
response.error = Error::ZOK;
|
response.error = Error::ZOK;
|
||||||
|
|
||||||
|
undo = [prev_node, &container, path = path]
|
||||||
|
{
|
||||||
|
container.emplace(path, prev_node);
|
||||||
|
auto & undo_parent = container.at(parentPath(path));
|
||||||
|
++undo_parent.stat.numChildren;
|
||||||
|
--undo_parent.stat.cversion;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<RemoveResponse>(response);
|
return { std::make_shared<RemoveResponse>(response), undo };
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponsePtr TestKeeperExistsRequest::process(TestKeeper::Container & container, int64_t) const
|
std::pair<ResponsePtr, Undo> TestKeeperExistsRequest::process(TestKeeper::Container & container, int64_t) const
|
||||||
{
|
{
|
||||||
ExistsResponse response;
|
ExistsResponse response;
|
||||||
|
|
||||||
@ -275,10 +302,10 @@ ResponsePtr TestKeeperExistsRequest::process(TestKeeper::Container & container,
|
|||||||
response.error = Error::ZNONODE;
|
response.error = Error::ZNONODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<ExistsResponse>(response);
|
return { std::make_shared<ExistsResponse>(response), {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponsePtr TestKeeperGetRequest::process(TestKeeper::Container & container, int64_t) const
|
std::pair<ResponsePtr, Undo> TestKeeperGetRequest::process(TestKeeper::Container & container, int64_t) const
|
||||||
{
|
{
|
||||||
GetResponse response;
|
GetResponse response;
|
||||||
|
|
||||||
@ -294,12 +321,13 @@ ResponsePtr TestKeeperGetRequest::process(TestKeeper::Container & container, int
|
|||||||
response.error = Error::ZOK;
|
response.error = Error::ZOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<GetResponse>(response);
|
return { std::make_shared<GetResponse>(response), {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponsePtr TestKeeperSetRequest::process(TestKeeper::Container & container, int64_t zxid) const
|
std::pair<ResponsePtr, Undo> TestKeeperSetRequest::process(TestKeeper::Container & container, int64_t zxid) const
|
||||||
{
|
{
|
||||||
SetResponse response;
|
SetResponse response;
|
||||||
|
Undo undo;
|
||||||
|
|
||||||
auto it = container.find(path);
|
auto it = container.find(path);
|
||||||
if (it == container.end())
|
if (it == container.end())
|
||||||
@ -308,6 +336,8 @@ ResponsePtr TestKeeperSetRequest::process(TestKeeper::Container & container, int
|
|||||||
}
|
}
|
||||||
else if (version == -1 || version == it->second.stat.version)
|
else if (version == -1 || version == it->second.stat.version)
|
||||||
{
|
{
|
||||||
|
auto prev_node = it->second;
|
||||||
|
|
||||||
it->second.data = data;
|
it->second.data = data;
|
||||||
++it->second.stat.version;
|
++it->second.stat.version;
|
||||||
it->second.stat.mzxid = zxid;
|
it->second.stat.mzxid = zxid;
|
||||||
@ -316,16 +346,22 @@ ResponsePtr TestKeeperSetRequest::process(TestKeeper::Container & container, int
|
|||||||
++container.at(parentPath(path)).stat.cversion;
|
++container.at(parentPath(path)).stat.cversion;
|
||||||
response.stat = it->second.stat;
|
response.stat = it->second.stat;
|
||||||
response.error = Error::ZOK;
|
response.error = Error::ZOK;
|
||||||
|
|
||||||
|
undo = [prev_node, &container, path = path]
|
||||||
|
{
|
||||||
|
container.at(path) = prev_node;
|
||||||
|
--container.at(parentPath(path)).stat.cversion;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
response.error = Error::ZBADVERSION;
|
response.error = Error::ZBADVERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<SetResponse>(response);
|
return { std::make_shared<SetResponse>(response), undo };
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponsePtr TestKeeperListRequest::process(TestKeeper::Container & container, int64_t) const
|
std::pair<ResponsePtr, Undo> TestKeeperListRequest::process(TestKeeper::Container & container, int64_t) const
|
||||||
{
|
{
|
||||||
ListResponse response;
|
ListResponse response;
|
||||||
|
|
||||||
@ -344,18 +380,22 @@ ResponsePtr TestKeeperListRequest::process(TestKeeper::Container & container, in
|
|||||||
path_prefix += '/';
|
path_prefix += '/';
|
||||||
|
|
||||||
/// Fairly inefficient.
|
/// Fairly inefficient.
|
||||||
for (auto child_it = container.upper_bound(path_prefix); child_it != container.end() && startsWith(child_it->first, path_prefix); ++child_it)
|
for (auto child_it = container.upper_bound(path_prefix);
|
||||||
|
child_it != container.end() && startsWith(child_it->first, path_prefix);
|
||||||
|
++child_it)
|
||||||
|
{
|
||||||
if (parentPath(child_it->first) == path)
|
if (parentPath(child_it->first) == path)
|
||||||
response.names.emplace_back(baseName(child_it->first));
|
response.names.emplace_back(baseName(child_it->first));
|
||||||
|
}
|
||||||
|
|
||||||
response.stat = it->second.stat;
|
response.stat = it->second.stat;
|
||||||
response.error = Error::ZOK;
|
response.error = Error::ZOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<ListResponse>(response);
|
return { std::make_shared<ListResponse>(response), {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponsePtr TestKeeperCheckRequest::process(TestKeeper::Container & container, int64_t) const
|
std::pair<ResponsePtr, Undo> TestKeeperCheckRequest::process(TestKeeper::Container & container, int64_t) const
|
||||||
{
|
{
|
||||||
CheckResponse response;
|
CheckResponse response;
|
||||||
auto it = container.find(path);
|
auto it = container.find(path);
|
||||||
@ -372,38 +412,42 @@ ResponsePtr TestKeeperCheckRequest::process(TestKeeper::Container & container, i
|
|||||||
response.error = Error::ZOK;
|
response.error = Error::ZOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<CheckResponse>(response);
|
return { std::make_shared<CheckResponse>(response), {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponsePtr TestKeeperMultiRequest::process(TestKeeper::Container & container, int64_t zxid) const
|
std::pair<ResponsePtr, Undo> TestKeeperMultiRequest::process(TestKeeper::Container & container, int64_t zxid) const
|
||||||
{
|
{
|
||||||
MultiResponse response;
|
MultiResponse response;
|
||||||
response.responses.reserve(requests.size());
|
response.responses.reserve(requests.size());
|
||||||
|
std::vector<Undo> undo_actions;
|
||||||
/// Fairly inefficient.
|
|
||||||
auto container_copy = container;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
for (const auto & request : requests)
|
for (const auto & request : requests)
|
||||||
{
|
{
|
||||||
const TestKeeperRequest & concrete_request = dynamic_cast<const TestKeeperRequest &>(*request);
|
const TestKeeperRequest & concrete_request = dynamic_cast<const TestKeeperRequest &>(*request);
|
||||||
auto cur_response = concrete_request.process(container, zxid);
|
auto [ cur_response, undo_action ] = concrete_request.process(container, zxid);
|
||||||
response.responses.emplace_back(cur_response);
|
response.responses.emplace_back(cur_response);
|
||||||
if (cur_response->error != Error::ZOK)
|
if (cur_response->error != Error::ZOK)
|
||||||
{
|
{
|
||||||
response.error = cur_response->error;
|
response.error = cur_response->error;
|
||||||
container = container_copy;
|
|
||||||
return std::make_shared<MultiResponse>(response);
|
for (auto it = undo_actions.rbegin(); it != undo_actions.rend(); ++it)
|
||||||
|
(*it)();
|
||||||
|
|
||||||
|
return { std::make_shared<MultiResponse>(response), {} };
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
undo_actions.emplace_back(std::move(undo_action));
|
||||||
}
|
}
|
||||||
|
|
||||||
response.error = Error::ZOK;
|
response.error = Error::ZOK;
|
||||||
return std::make_shared<MultiResponse>(response);
|
return { std::make_shared<MultiResponse>(response), {} };
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
container = container_copy;
|
for (auto it = undo_actions.rbegin(); it != undo_actions.rend(); ++it)
|
||||||
|
(*it)();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -476,7 +520,7 @@ void TestKeeper::processingThread()
|
|||||||
++zxid;
|
++zxid;
|
||||||
|
|
||||||
info.request->addRootPath(root_path);
|
info.request->addRootPath(root_path);
|
||||||
ResponsePtr response = info.request->process(container, zxid);
|
auto [response, _] = info.request->process(container, zxid);
|
||||||
if (response->error == Error::ZOK)
|
if (response->error == Error::ZOK)
|
||||||
info.request->processWatches(watches, list_watches);
|
info.request->processWatches(watches, list_watches);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user