From e601192217df0054bd124913aab6e28c16bd1fe7 Mon Sep 17 00:00:00 2001 From: levy Date: Thu, 24 Jun 2021 18:20:21 +0800 Subject: [PATCH 1/2] feat: add partition guardian --- src/meta/partition_guardian.cpp | 50 ++++ src/meta/partition_guardian.h | 49 ++++ src/meta/test/partition_guardian_test.cpp | 290 ++++++++++++++++++++++ src/meta/test/partition_guardian_test.h | 31 +++ 4 files changed, 420 insertions(+) create mode 100644 src/meta/partition_guardian.cpp create mode 100644 src/meta/partition_guardian.h create mode 100644 src/meta/test/partition_guardian_test.cpp create mode 100644 src/meta/test/partition_guardian_test.h diff --git a/src/meta/partition_guardian.cpp b/src/meta/partition_guardian.cpp new file mode 100644 index 0000000000..dea3cba49c --- /dev/null +++ b/src/meta/partition_guardian.cpp @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#include "partition_guardian.h" +namespace dsn { +namespace replication { +partition_guardian::partition_guardian(meta_service *svc) : _svc(svc) {} + +bool partition_guardian::collect_replica(meta_view view, + const rpc_address &node, + const replica_info &info) +{ + partition_configuration &pc = *get_config(*view.apps, info.pid); + // current partition is during partition split + if (pc.ballot == invalid_ballot) { + return false; + } + + config_context &cc = *get_config_context(*view.apps, info.pid); + if (is_member(pc, node)) { + cc.collect_serving_replica(node, info); + return true; + } + + // compare current node's replica information with current proposal, + // and try to find abnormal situations in send proposal + cc.adjust_proposal(node, info); + + // adjust the drop list + int ans = cc.collect_drop_replica(node, info); + dassert(cc.check_order(), ""); + + return info.status == partition_status::PS_POTENTIAL_SECONDARY || ans != -1; +} +} // namespace replication +} // namespace dsn diff --git a/src/meta/partition_guardian.h b/src/meta/partition_guardian.h new file mode 100644 index 0000000000..2f12030545 --- /dev/null +++ b/src/meta/partition_guardian.h @@ -0,0 +1,49 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#pragma once + +#include "meta_data.h" + +namespace dsn { +namespace replication { +class meta_service; + +class partition_guardian +{ +public: + explicit partition_guardian(meta_service *svc); + ~partition_guardian() = default; + + // + // When replica infos are collected from replica servers, meta-server + // will use this to check if a replica on a server is useful + // params: + // node: the owner of the replica info + // info: the replica info on node + // ret: + // return true if the replica is accepted as an useful replica. Or-else false. + // WARNING: if false is returned, the replica on node may be garbage-collected + // + bool collect_replica(meta_view view, const rpc_address &node, const replica_info &info); + +private: + meta_service *_svc; +}; + +} // namespace replication +} // namespace dsn diff --git a/src/meta/test/partition_guardian_test.cpp b/src/meta/test/partition_guardian_test.cpp new file mode 100644 index 0000000000..ccb9144a79 --- /dev/null +++ b/src/meta/test/partition_guardian_test.cpp @@ -0,0 +1,290 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#include "meta/partition_guardian.h" +#include "meta/meta_service.h" +#include "partition_guardian_test.h" +#include "misc/misc.h" + +namespace dsn { +namespace replication { +static bool vec_equal(const std::vector &vec1, + const std::vector &vec2) +{ + if (vec1.size() != vec2.size()) + return false; + for (unsigned int i = 0; i != vec1.size(); ++i) { + const dropped_replica &ds1 = vec1[i]; + const dropped_replica &ds2 = vec2[i]; + if (ds1.ballot != ds2.ballot) + return false; + if (ds1.last_prepared_decree != ds2.last_prepared_decree) + return false; + if (ds1.node != ds2.node) + return false; + if (ds1.time != ds2.time) + return false; + } + return true; +} + +void partition_guardian_test::collect_replica() +{ + app_mapper app; + node_mapper nodes; + + dsn::app_info info; + info.app_id = 1; + info.is_stateful = true; + info.status = dsn::app_status::AS_AVAILABLE; + info.app_name = "test"; + info.app_type = "test"; + info.max_replica_count = 3; + info.partition_count = 1024; + std::shared_ptr the_app = app_state::create(info); + app.emplace(the_app->app_id, the_app); + meta_view view = {&app, &nodes}; + + replica_info rep; + rep.app_type = "test"; + rep.pid = dsn::gpid(1, 0); + + dsn::partition_configuration &pc = *get_config(app, rep.pid); + config_context &cc = *get_config_context(app, rep.pid); + + meta_service svc; + partition_guardian guardian(&svc); + + std::vector node_list; + generate_node_list(node_list, 10, 10); + +#define CLEAR_REPLICA \ + do { \ + pc.primary.set_invalid(); \ + pc.secondaries.clear(); \ + pc.last_drops.clear(); \ + } while (false) + +#define CLEAR_DROP_LIST \ + do { \ + cc.dropped.clear(); \ + } while (false) + +#define CLEAR_ALL \ + CLEAR_REPLICA; \ + CLEAR_DROP_LIST + + { + // replica is primary of partition + CLEAR_ALL; + rep.ballot = 10; + pc.ballot = 9; + pc.primary = node_list[0]; + ASSERT_TRUE(guardian.collect_replica(view, node_list[0], rep)); + } + + { + // replica is secondary of partition + CLEAR_ALL; + pc.secondaries.push_back(node_list[0]); + ASSERT_TRUE(guardian.collect_replica(view, node_list[0], rep)); + } + + { + // replica has been in the drop_list + CLEAR_ALL; + cc.dropped.push_back({node_list[0], 5, 0, 0}); + ASSERT_TRUE(guardian.collect_replica(view, node_list[0], rep)); + } + + { + // drop_list all have timestamp, full + CLEAR_ALL; + cc.dropped = { + dropped_replica{node_list[0], 5, 1, 1, 2}, + dropped_replica{node_list[1], 6, 1, 1, 2}, + dropped_replica{node_list[2], 7, 1, 1, 2}, + dropped_replica{node_list[3], 8, 1, 1, 2}, + }; + rep.ballot = 10; + rep.last_prepared_decree = 10; + ASSERT_FALSE(guardian.collect_replica(view, node_list[5], rep)); + } + + { + // drop_list all have timestamp, not full + CLEAR_ALL; + cc.dropped = { + dropped_replica{node_list[0], 5, 1, 1, 2}, + dropped_replica{node_list[1], 6, 1, 1, 2}, + dropped_replica{node_list[2], 7, 1, 1, 2}, + }; + rep.ballot = 10; + rep.last_durable_decree = 6; + rep.last_committed_decree = 8; + rep.last_prepared_decree = 10; + + ASSERT_TRUE(guardian.collect_replica(view, node_list[4], rep)); + dropped_replica &d = cc.dropped.front(); + ASSERT_EQ(d.ballot, rep.ballot); + ASSERT_EQ(d.last_prepared_decree, rep.last_prepared_decree); + } + + { + // drop_list mixed, full, minimal position + CLEAR_ALL; + cc.dropped = { + dropped_replica{node_list[0], dropped_replica::INVALID_TIMESTAMP, 2, 3, 5}, + dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 5}, + dropped_replica{node_list[2], 7, 1, 1, 5}, + dropped_replica{node_list[3], 8, 1, 1, 5}, + }; + + rep.ballot = 1; + rep.last_committed_decree = 3; + rep.last_prepared_decree = 5; + ASSERT_FALSE(guardian.collect_replica(view, node_list[5], rep)); + } + + { + // drop_list mixed, not full, minimal position + CLEAR_ALL; + cc.dropped = { + dropped_replica{node_list[0], dropped_replica::INVALID_TIMESTAMP, 2, 3, 5}, + dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 5}, + dropped_replica{node_list[2], 7, 1, 1, 6}, + }; + + rep.ballot = 1; + rep.last_committed_decree = 3; + rep.last_prepared_decree = 5; + ASSERT_TRUE(guardian.collect_replica(view, node_list[5], rep)); + dropped_replica &d = cc.dropped.front(); + ASSERT_EQ(d.node, node_list[5]); + ASSERT_EQ(d.ballot, rep.ballot); + ASSERT_EQ(d.last_prepared_decree, rep.last_prepared_decree); + } + + { + // drop_list mixed, full, not minimal position + CLEAR_ALL; + cc.dropped = { + dropped_replica{node_list[0], dropped_replica::INVALID_TIMESTAMP, 2, 2, 6}, + dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 6}, + dropped_replica{node_list[2], 7, 1, 1, 6}, + dropped_replica{node_list[3], 8, 1, 1, 6}, + }; + + rep.ballot = 2; + rep.last_committed_decree = 3; + rep.last_prepared_decree = 6; + ASSERT_TRUE(guardian.collect_replica(view, node_list[5], rep)); + dropped_replica &d = cc.dropped.front(); + ASSERT_EQ(rep.ballot, d.ballot); + ASSERT_EQ(rep.last_committed_decree, rep.last_committed_decree); + + ASSERT_EQ(4, cc.dropped[1].last_committed_decree); + } + + { + // drop_list mixed, not full, not minimal position + CLEAR_ALL; + cc.dropped = {dropped_replica{node_list[0], dropped_replica::INVALID_TIMESTAMP, 2, 2, 6}, + dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 6}, + dropped_replica{node_list[2], 7, 1, 1, 6}}; + + rep.ballot = 3; + rep.last_committed_decree = 1; + rep.last_prepared_decree = 6; + ASSERT_TRUE(guardian.collect_replica(view, node_list[5], rep)); + + std::vector result_dropped = { + dropped_replica{node_list[0], dropped_replica::INVALID_TIMESTAMP, 2, 2, 6}, + dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 6}, + dropped_replica{node_list[5], dropped_replica::INVALID_TIMESTAMP, 3, 1, 6}, + dropped_replica{node_list[2], 7, 1, 1, 6}}; + + ASSERT_TRUE(vec_equal(result_dropped, cc.dropped)); + } + + { + // drop_list no timestamp, full, minimal position + CLEAR_ALL; + cc.dropped = { + dropped_replica{node_list[0], dropped_replica::INVALID_TIMESTAMP, 2, 2, 8}, + dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 8}, + dropped_replica{node_list[2], dropped_replica::INVALID_TIMESTAMP, 2, 6, 8}, + dropped_replica{node_list[3], dropped_replica::INVALID_TIMESTAMP, 4, 2, 8}, + }; + + rep.ballot = 1; + rep.last_committed_decree = 7; + rep.last_prepared_decree = 10; + ASSERT_FALSE(guardian.collect_replica(view, node_list[5], rep)); + } + + { + // drop_list no timestamp, full, middle position + CLEAR_ALL; + cc.dropped = { + dropped_replica{node_list[0], dropped_replica::INVALID_TIMESTAMP, 2, 2, 8}, + dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 8}, + dropped_replica{node_list[2], dropped_replica::INVALID_TIMESTAMP, 2, 6, 8}, + dropped_replica{node_list[3], dropped_replica::INVALID_TIMESTAMP, 4, 2, 8}, + }; + + rep.ballot = 3; + rep.last_committed_decree = 6; + rep.last_prepared_decree = 8; + ASSERT_TRUE(guardian.collect_replica(view, node_list[5], rep)); + + std::vector result_dropped = { + dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 8}, + dropped_replica{node_list[2], dropped_replica::INVALID_TIMESTAMP, 2, 6, 8}, + dropped_replica{node_list[5], dropped_replica::INVALID_TIMESTAMP, 3, 6, 8}, + dropped_replica{node_list[3], dropped_replica::INVALID_TIMESTAMP, 4, 2, 8}, + }; + + ASSERT_TRUE(vec_equal(result_dropped, cc.dropped)); + } + + { + // drop_list no timestamp, full, largest position + CLEAR_ALL; + cc.dropped = {dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 8}, + dropped_replica{node_list[2], dropped_replica::INVALID_TIMESTAMP, 2, 6, 8}, + dropped_replica{node_list[3], dropped_replica::INVALID_TIMESTAMP, 4, 2, 8}, + dropped_replica{node_list[4], dropped_replica::INVALID_TIMESTAMP, 4, 6, 8}}; + + rep.ballot = 4; + rep.last_committed_decree = 8; + rep.last_prepared_decree = 8; + ASSERT_TRUE(guardian.collect_replica(view, node_list[5], rep)); + + std::vector result_dropped = { + dropped_replica{node_list[2], dropped_replica::INVALID_TIMESTAMP, 2, 6, 8}, + dropped_replica{node_list[3], dropped_replica::INVALID_TIMESTAMP, 4, 2, 8}, + dropped_replica{node_list[4], dropped_replica::INVALID_TIMESTAMP, 4, 6, 8}, + dropped_replica{node_list[5], dropped_replica::INVALID_TIMESTAMP, 4, 8, 8}}; + + ASSERT_TRUE(vec_equal(result_dropped, cc.dropped)); + } +} + +TEST_F(partition_guardian_test, collect_replica) { collect_replica(); } +} // namespace replication +} // namespace dsn diff --git a/src/meta/test/partition_guardian_test.h b/src/meta/test/partition_guardian_test.h new file mode 100644 index 0000000000..47e52548b4 --- /dev/null +++ b/src/meta/test/partition_guardian_test.h @@ -0,0 +1,31 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#pragma once + +#include "meta_test_base.h" + +namespace dsn { +namespace replication { +class partition_guardian_test : public meta_test_base +{ +public: + void collect_replica(); +}; + +} // namespace replication +} // namespace dsn From 53e7803f40824a960b1dc3ad9b6a59e434c2e05c Mon Sep 17 00:00:00 2001 From: levy Date: Fri, 2 Jul 2021 11:28:12 +0800 Subject: [PATCH 2/2] fix --- src/meta/partition_guardian.cpp | 67 +++-- src/meta/partition_guardian.h | 18 +- src/meta/test/partition_guardian_test.cpp | 290 ---------------------- src/meta/test/partition_guardian_test.h | 31 --- 4 files changed, 55 insertions(+), 351 deletions(-) delete mode 100644 src/meta/test/partition_guardian_test.cpp delete mode 100644 src/meta/test/partition_guardian_test.h diff --git a/src/meta/partition_guardian.cpp b/src/meta/partition_guardian.cpp index dea3cba49c..401a4558c9 100644 --- a/src/meta/partition_guardian.cpp +++ b/src/meta/partition_guardian.cpp @@ -20,31 +20,60 @@ namespace dsn { namespace replication { partition_guardian::partition_guardian(meta_service *svc) : _svc(svc) {} -bool partition_guardian::collect_replica(meta_view view, - const rpc_address &node, - const replica_info &info) +pc_status partition_guardian::cure(meta_view view, + const dsn::gpid &gpid, + configuration_proposal_action &action) { - partition_configuration &pc = *get_config(*view.apps, info.pid); - // current partition is during partition split - if (pc.ballot == invalid_ballot) { - return false; - } + if (from_proposals(view, gpid, action)) + return pc_status::ill; + + std::shared_ptr &app = (*view.apps)[gpid.get_app_id()]; + const partition_configuration &pc = *get_config(*(view.apps), gpid); + const proposal_actions &acts = get_config_context(*view.apps, gpid)->lb_actions; + + dassert(app->is_stateful, ""); + dassert(acts.empty(), ""); + + pc_status status; + if (pc.primary.is_invalid()) + status = on_missing_primary(view, gpid); + else if (static_cast(pc.secondaries.size()) + 1 < pc.max_replica_count) + status = on_missing_secondary(view, gpid); + else if (static_cast(pc.secondaries.size()) >= pc.max_replica_count) + status = on_redundant_secondary(view, gpid); + else + status = pc_status::healthy; - config_context &cc = *get_config_context(*view.apps, info.pid); - if (is_member(pc, node)) { - cc.collect_serving_replica(node, info); - return true; + if (!acts.empty()) { + action = *acts.front(); } + return status; +} - // compare current node's replica information with current proposal, - // and try to find abnormal situations in send proposal - cc.adjust_proposal(node, info); +bool partition_guardian::from_proposals(meta_view &view, + const dsn::gpid &gpid, + configuration_proposal_action &action) +{ + // TBD(zlw) + return false; +} - // adjust the drop list - int ans = cc.collect_drop_replica(node, info); - dassert(cc.check_order(), ""); +pc_status partition_guardian::on_missing_primary(meta_view &view, const dsn::gpid &gpid) +{ + // TBD(zlw) + return pc_status::invalid; +} + +pc_status partition_guardian::on_missing_secondary(meta_view &view, const dsn::gpid &gpid) +{ + // TBD(zlw) + return pc_status::invalid; +} - return info.status == partition_status::PS_POTENTIAL_SECONDARY || ans != -1; +pc_status partition_guardian::on_redundant_secondary(meta_view &view, const dsn::gpid &gpid) +{ + // TBD(zlw) + return pc_status::invalid; } } // namespace replication } // namespace dsn diff --git a/src/meta/partition_guardian.h b/src/meta/partition_guardian.h index 2f12030545..46ac75151d 100644 --- a/src/meta/partition_guardian.h +++ b/src/meta/partition_guardian.h @@ -29,19 +29,15 @@ class partition_guardian explicit partition_guardian(meta_service *svc); ~partition_guardian() = default; - // - // When replica infos are collected from replica servers, meta-server - // will use this to check if a replica on a server is useful - // params: - // node: the owner of the replica info - // info: the replica info on node - // ret: - // return true if the replica is accepted as an useful replica. Or-else false. - // WARNING: if false is returned, the replica on node may be garbage-collected - // - bool collect_replica(meta_view view, const rpc_address &node, const replica_info &info); + pc_status cure(meta_view view, const dsn::gpid &gpid, configuration_proposal_action &action); private: + bool + from_proposals(meta_view &view, const dsn::gpid &gpid, configuration_proposal_action &action); + pc_status on_missing_primary(meta_view &view, const dsn::gpid &gpid); + pc_status on_missing_secondary(meta_view &view, const dsn::gpid &gpid); + pc_status on_redundant_secondary(meta_view &view, const dsn::gpid &gpid); + meta_service *_svc; }; diff --git a/src/meta/test/partition_guardian_test.cpp b/src/meta/test/partition_guardian_test.cpp deleted file mode 100644 index ccb9144a79..0000000000 --- a/src/meta/test/partition_guardian_test.cpp +++ /dev/null @@ -1,290 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -#include "meta/partition_guardian.h" -#include "meta/meta_service.h" -#include "partition_guardian_test.h" -#include "misc/misc.h" - -namespace dsn { -namespace replication { -static bool vec_equal(const std::vector &vec1, - const std::vector &vec2) -{ - if (vec1.size() != vec2.size()) - return false; - for (unsigned int i = 0; i != vec1.size(); ++i) { - const dropped_replica &ds1 = vec1[i]; - const dropped_replica &ds2 = vec2[i]; - if (ds1.ballot != ds2.ballot) - return false; - if (ds1.last_prepared_decree != ds2.last_prepared_decree) - return false; - if (ds1.node != ds2.node) - return false; - if (ds1.time != ds2.time) - return false; - } - return true; -} - -void partition_guardian_test::collect_replica() -{ - app_mapper app; - node_mapper nodes; - - dsn::app_info info; - info.app_id = 1; - info.is_stateful = true; - info.status = dsn::app_status::AS_AVAILABLE; - info.app_name = "test"; - info.app_type = "test"; - info.max_replica_count = 3; - info.partition_count = 1024; - std::shared_ptr the_app = app_state::create(info); - app.emplace(the_app->app_id, the_app); - meta_view view = {&app, &nodes}; - - replica_info rep; - rep.app_type = "test"; - rep.pid = dsn::gpid(1, 0); - - dsn::partition_configuration &pc = *get_config(app, rep.pid); - config_context &cc = *get_config_context(app, rep.pid); - - meta_service svc; - partition_guardian guardian(&svc); - - std::vector node_list; - generate_node_list(node_list, 10, 10); - -#define CLEAR_REPLICA \ - do { \ - pc.primary.set_invalid(); \ - pc.secondaries.clear(); \ - pc.last_drops.clear(); \ - } while (false) - -#define CLEAR_DROP_LIST \ - do { \ - cc.dropped.clear(); \ - } while (false) - -#define CLEAR_ALL \ - CLEAR_REPLICA; \ - CLEAR_DROP_LIST - - { - // replica is primary of partition - CLEAR_ALL; - rep.ballot = 10; - pc.ballot = 9; - pc.primary = node_list[0]; - ASSERT_TRUE(guardian.collect_replica(view, node_list[0], rep)); - } - - { - // replica is secondary of partition - CLEAR_ALL; - pc.secondaries.push_back(node_list[0]); - ASSERT_TRUE(guardian.collect_replica(view, node_list[0], rep)); - } - - { - // replica has been in the drop_list - CLEAR_ALL; - cc.dropped.push_back({node_list[0], 5, 0, 0}); - ASSERT_TRUE(guardian.collect_replica(view, node_list[0], rep)); - } - - { - // drop_list all have timestamp, full - CLEAR_ALL; - cc.dropped = { - dropped_replica{node_list[0], 5, 1, 1, 2}, - dropped_replica{node_list[1], 6, 1, 1, 2}, - dropped_replica{node_list[2], 7, 1, 1, 2}, - dropped_replica{node_list[3], 8, 1, 1, 2}, - }; - rep.ballot = 10; - rep.last_prepared_decree = 10; - ASSERT_FALSE(guardian.collect_replica(view, node_list[5], rep)); - } - - { - // drop_list all have timestamp, not full - CLEAR_ALL; - cc.dropped = { - dropped_replica{node_list[0], 5, 1, 1, 2}, - dropped_replica{node_list[1], 6, 1, 1, 2}, - dropped_replica{node_list[2], 7, 1, 1, 2}, - }; - rep.ballot = 10; - rep.last_durable_decree = 6; - rep.last_committed_decree = 8; - rep.last_prepared_decree = 10; - - ASSERT_TRUE(guardian.collect_replica(view, node_list[4], rep)); - dropped_replica &d = cc.dropped.front(); - ASSERT_EQ(d.ballot, rep.ballot); - ASSERT_EQ(d.last_prepared_decree, rep.last_prepared_decree); - } - - { - // drop_list mixed, full, minimal position - CLEAR_ALL; - cc.dropped = { - dropped_replica{node_list[0], dropped_replica::INVALID_TIMESTAMP, 2, 3, 5}, - dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 5}, - dropped_replica{node_list[2], 7, 1, 1, 5}, - dropped_replica{node_list[3], 8, 1, 1, 5}, - }; - - rep.ballot = 1; - rep.last_committed_decree = 3; - rep.last_prepared_decree = 5; - ASSERT_FALSE(guardian.collect_replica(view, node_list[5], rep)); - } - - { - // drop_list mixed, not full, minimal position - CLEAR_ALL; - cc.dropped = { - dropped_replica{node_list[0], dropped_replica::INVALID_TIMESTAMP, 2, 3, 5}, - dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 5}, - dropped_replica{node_list[2], 7, 1, 1, 6}, - }; - - rep.ballot = 1; - rep.last_committed_decree = 3; - rep.last_prepared_decree = 5; - ASSERT_TRUE(guardian.collect_replica(view, node_list[5], rep)); - dropped_replica &d = cc.dropped.front(); - ASSERT_EQ(d.node, node_list[5]); - ASSERT_EQ(d.ballot, rep.ballot); - ASSERT_EQ(d.last_prepared_decree, rep.last_prepared_decree); - } - - { - // drop_list mixed, full, not minimal position - CLEAR_ALL; - cc.dropped = { - dropped_replica{node_list[0], dropped_replica::INVALID_TIMESTAMP, 2, 2, 6}, - dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 6}, - dropped_replica{node_list[2], 7, 1, 1, 6}, - dropped_replica{node_list[3], 8, 1, 1, 6}, - }; - - rep.ballot = 2; - rep.last_committed_decree = 3; - rep.last_prepared_decree = 6; - ASSERT_TRUE(guardian.collect_replica(view, node_list[5], rep)); - dropped_replica &d = cc.dropped.front(); - ASSERT_EQ(rep.ballot, d.ballot); - ASSERT_EQ(rep.last_committed_decree, rep.last_committed_decree); - - ASSERT_EQ(4, cc.dropped[1].last_committed_decree); - } - - { - // drop_list mixed, not full, not minimal position - CLEAR_ALL; - cc.dropped = {dropped_replica{node_list[0], dropped_replica::INVALID_TIMESTAMP, 2, 2, 6}, - dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 6}, - dropped_replica{node_list[2], 7, 1, 1, 6}}; - - rep.ballot = 3; - rep.last_committed_decree = 1; - rep.last_prepared_decree = 6; - ASSERT_TRUE(guardian.collect_replica(view, node_list[5], rep)); - - std::vector result_dropped = { - dropped_replica{node_list[0], dropped_replica::INVALID_TIMESTAMP, 2, 2, 6}, - dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 6}, - dropped_replica{node_list[5], dropped_replica::INVALID_TIMESTAMP, 3, 1, 6}, - dropped_replica{node_list[2], 7, 1, 1, 6}}; - - ASSERT_TRUE(vec_equal(result_dropped, cc.dropped)); - } - - { - // drop_list no timestamp, full, minimal position - CLEAR_ALL; - cc.dropped = { - dropped_replica{node_list[0], dropped_replica::INVALID_TIMESTAMP, 2, 2, 8}, - dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 8}, - dropped_replica{node_list[2], dropped_replica::INVALID_TIMESTAMP, 2, 6, 8}, - dropped_replica{node_list[3], dropped_replica::INVALID_TIMESTAMP, 4, 2, 8}, - }; - - rep.ballot = 1; - rep.last_committed_decree = 7; - rep.last_prepared_decree = 10; - ASSERT_FALSE(guardian.collect_replica(view, node_list[5], rep)); - } - - { - // drop_list no timestamp, full, middle position - CLEAR_ALL; - cc.dropped = { - dropped_replica{node_list[0], dropped_replica::INVALID_TIMESTAMP, 2, 2, 8}, - dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 8}, - dropped_replica{node_list[2], dropped_replica::INVALID_TIMESTAMP, 2, 6, 8}, - dropped_replica{node_list[3], dropped_replica::INVALID_TIMESTAMP, 4, 2, 8}, - }; - - rep.ballot = 3; - rep.last_committed_decree = 6; - rep.last_prepared_decree = 8; - ASSERT_TRUE(guardian.collect_replica(view, node_list[5], rep)); - - std::vector result_dropped = { - dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 8}, - dropped_replica{node_list[2], dropped_replica::INVALID_TIMESTAMP, 2, 6, 8}, - dropped_replica{node_list[5], dropped_replica::INVALID_TIMESTAMP, 3, 6, 8}, - dropped_replica{node_list[3], dropped_replica::INVALID_TIMESTAMP, 4, 2, 8}, - }; - - ASSERT_TRUE(vec_equal(result_dropped, cc.dropped)); - } - - { - // drop_list no timestamp, full, largest position - CLEAR_ALL; - cc.dropped = {dropped_replica{node_list[1], dropped_replica::INVALID_TIMESTAMP, 2, 4, 8}, - dropped_replica{node_list[2], dropped_replica::INVALID_TIMESTAMP, 2, 6, 8}, - dropped_replica{node_list[3], dropped_replica::INVALID_TIMESTAMP, 4, 2, 8}, - dropped_replica{node_list[4], dropped_replica::INVALID_TIMESTAMP, 4, 6, 8}}; - - rep.ballot = 4; - rep.last_committed_decree = 8; - rep.last_prepared_decree = 8; - ASSERT_TRUE(guardian.collect_replica(view, node_list[5], rep)); - - std::vector result_dropped = { - dropped_replica{node_list[2], dropped_replica::INVALID_TIMESTAMP, 2, 6, 8}, - dropped_replica{node_list[3], dropped_replica::INVALID_TIMESTAMP, 4, 2, 8}, - dropped_replica{node_list[4], dropped_replica::INVALID_TIMESTAMP, 4, 6, 8}, - dropped_replica{node_list[5], dropped_replica::INVALID_TIMESTAMP, 4, 8, 8}}; - - ASSERT_TRUE(vec_equal(result_dropped, cc.dropped)); - } -} - -TEST_F(partition_guardian_test, collect_replica) { collect_replica(); } -} // namespace replication -} // namespace dsn diff --git a/src/meta/test/partition_guardian_test.h b/src/meta/test/partition_guardian_test.h deleted file mode 100644 index 47e52548b4..0000000000 --- a/src/meta/test/partition_guardian_test.h +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -#pragma once - -#include "meta_test_base.h" - -namespace dsn { -namespace replication { -class partition_guardian_test : public meta_test_base -{ -public: - void collect_replica(); -}; - -} // namespace replication -} // namespace dsn