TEST(routeHandleTest, allSyncTyped) { vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(mc_res_found, "a")), make_shared<TestHandle>(GetRouteTestData(mc_res_notfound, "b")), make_shared<TestHandle>(GetRouteTestData(mc_res_remote_error, "c")) }; TestFiberManager fm; TestRouteHandle<AllSyncRoute<TestRouteHandleIf>> rh( get_route_handles(test_handles)); fm.runAll( { [&]() { TypedThriftRequest<cpp2::McGetRequest> req; req.setKey("key"); auto reply = rh.route(req); /* Check that we got the worst result back */ EXPECT_EQ(mc_res_remote_error, reply.result()); EXPECT_EQ("c", toString(*reply->get_value())); for (auto& h : test_handles) { EXPECT_EQ(vector<string>{"key"}, h->saw_keys); } } }); }
TEST(routeHandleTest, allSync) { vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(mc_res_found, "a")), make_shared<TestHandle>(GetRouteTestData(mc_res_notfound, "b")), make_shared<TestHandle>(GetRouteTestData(mc_res_remote_error, "c")) }; TestFiberManager fm; TestRouteHandle<AllSyncRoute<TestRouteHandleIf>> rh( get_route_handles(test_handles)); fm.runAll( { [&]() { auto reply = rh.route(McRequestWithMcOp<mc_op_get>("key")); /* Check that we got the worst result back */ EXPECT_TRUE(reply.result() == mc_res_remote_error); EXPECT_TRUE(toString(reply.value()) == "c"); for (auto& h : test_handles) { EXPECT_TRUE(h->saw_keys == vector<string>{"key"}); } } }); }
TEST(routeHandleTest, allInitial) { vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(mc_res_found, "a")), make_shared<TestHandle>(GetRouteTestData(mc_res_notfound, "b")), make_shared<TestHandle>(GetRouteTestData(mc_res_remote_error, "c")), }; TestFiberManager fm; auto routeHandles = get_route_handles(test_handles); TestRouteHandle<AllInitialRoute<TestRouteHandleIf>> rh(routeHandles); fm.runAll( { [&]() { auto reply = rh.route(McRequestWithMcOp<mc_op_get>("key")); /* Check that we got the initial result back */ EXPECT_TRUE(reply.result() == mc_res_found); EXPECT_TRUE(toString(reply.value()) == "a"); } }); /* Check that everything is complete in the background */ for (auto& h : test_handles) { EXPECT_TRUE(h->saw_keys == vector<string>{"key"}); } /* Check that traverse is correct */ int cnt = 0; RouteHandleTraverser<TestRouteHandleIf> t{ [&cnt](const TestRouteHandleIf&){ ++cnt; } }; rh.traverse(McRequestWithMcOp<mc_op_get>("key"), t); EXPECT_EQ(cnt, routeHandles.size()); }
TEST(BigValueRouteTest, smallvalue) { // for small values, this route handle simply passes it to child route handle vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(mc_res_found, "a"), UpdateRouteTestData(mc_res_stored), DeleteRouteTestData(mc_res_deleted)) }; auto route_handles = get_route_handles(test_handles); TestFiberManager fm; std::shared_ptr<ProxyRequestContext> ctx; fm.runAll({ [&]() { McrouterRouteHandle<BigValueRoute> rh(route_handles[0], opts); string key = "key_get"; auto msg = createMcMsgRef(key, "value"); msg->op = mc_op_get; ProxyMcRequest req_get(std::move(msg)); auto f_get = rh.route(req_get, McOperation<mc_op_get>(), ctx); EXPECT_TRUE(toString(f_get.value()) == "a"); EXPECT_TRUE(test_handles[0]->saw_keys == vector<string>{"key_get"}); (test_handles[0]->saw_keys).clear(); string key_set = "key_set"; auto msg_set = createMcMsgRef(key_set, "value"); msg_set->op = mc_op_set; ProxyMcRequest req_set(std::move(msg_set)); auto f_set = rh.route(req_set, McOperation<mc_op_set>(), ctx); EXPECT_TRUE(toString(f_set.value()) == "value"); EXPECT_TRUE(test_handles[0]->saw_keys == vector<string>{"key_set"}); } }); }
TEST(routeHandleTest, allMajorityTie) { TestFiberManager fm; vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(mc_res_remote_error, "a")), make_shared<TestHandle>(GetRouteTestData(mc_res_notfound, "b")), make_shared<TestHandle>(GetRouteTestData(mc_res_notfound, "c")), make_shared<TestHandle>(GetRouteTestData(mc_res_remote_error, "d")) }; TestRouteHandle<AllMajorityRoute<TestRouteHandleIf>> rh( get_route_handles(test_handles)); fm.runAll( { [&]() { auto reply = rh.route(McRequestWithMcOp<mc_op_get>("key")); /* Check that we got the _worst_ majority reply */ EXPECT_TRUE(reply.result() == mc_res_remote_error); } }); /* Check that everything is complete */ for (auto& h : test_handles) { EXPECT_TRUE(h->saw_keys == vector<string>{"key"}); } }
TEST(routeHandleTest, allMajorityTie) { TestFiberManager fm; vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>( GetRouteTestData(carbon::Result::REMOTE_ERROR, "a")), make_shared<TestHandle>(GetRouteTestData(carbon::Result::NOTFOUND, "b")), make_shared<TestHandle>(GetRouteTestData(carbon::Result::NOTFOUND, "c")), make_shared<TestHandle>( GetRouteTestData(carbon::Result::REMOTE_ERROR, "d"))}; TestRouteHandle<AllMajorityRoute<TestRouteHandleIf>> rh( get_route_handles(test_handles)); fm.runAll({[&]() { auto reply = rh.route(McGetRequest("key")); /* Check that we got the _worst_ majority reply */ EXPECT_EQ(carbon::Result::REMOTE_ERROR, reply.result()); }}); /* Check that everything is complete */ for (auto& h : test_handles) { EXPECT_EQ(vector<string>{"key"}, h->saw_keys); } }
TEST(routeHandleTest, allMajority) { TestFiberManager fm; vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>( GetRouteTestData(carbon::Result::REMOTE_ERROR, "a")), make_shared<TestHandle>(GetRouteTestData(carbon::Result::NOTFOUND, "b")), make_shared<TestHandle>( GetRouteTestData(carbon::Result::REMOTE_ERROR, "c"))}; TestRouteHandle<AllMajorityRoute<TestRouteHandleIf>> rh( get_route_handles(test_handles)); test_handles[1]->pause(); fm.runAll({[&]() { auto reply = rh.route(McGetRequest("key")); /* Check that we got the majority reply without waiting for "b", which is paused */ EXPECT_EQ(carbon::Result::REMOTE_ERROR, reply.result()); EXPECT_EQ(vector<string>{"key"}, test_handles[0]->saw_keys); EXPECT_EQ(vector<string>{}, test_handles[1]->saw_keys); EXPECT_EQ(vector<string>{"key"}, test_handles[2]->saw_keys); test_handles[1]->unpause(); }}); /* Check that everything is complete in the background */ for (auto& h : test_handles) { EXPECT_EQ(vector<string>{"key"}, h->saw_keys); } }
TEST(ReliablePoolRouteTest, deleteOps) { counter = 0; vector<std::shared_ptr<TestHandle>> saltedHandle{ make_shared<TestHandle>(DeleteRouteTestData(mc_res_found)), make_shared<TestHandle>(DeleteRouteTestData(mc_res_notfound)), make_shared<TestHandle>(DeleteRouteTestData(mc_res_found)), }; TestFiberManager fm; fm.runAll( { [&] () { TestRouteHandle<ReliablePoolRoute<TestRouteHandleIf, HashFunc>> rh( get_route_handles(saltedHandle), HashFunc(saltedHandle.size()), "", 5); auto reply = rh.routeSimple(McRequest("key"), McOperation<mc_op_delete>()); // Get the most awfull reply EXPECT_EQ(reply.result(), mc_res_notfound); } }); EXPECT_TRUE(saltedHandle[0]->saw_keys == (vector<std::string>{"key", "key"})); EXPECT_TRUE(saltedHandle[1]->saw_keys == (vector<std::string>{"key", "key"})); EXPECT_TRUE(saltedHandle[2]->saw_keys == (vector<std::string>{"key", "key"})); }
TEST(routeHandleTest, allSyncTyped) { vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(carbon::Result::FOUND, "a")), make_shared<TestHandle>(GetRouteTestData(carbon::Result::NOTFOUND, "b")), make_shared<TestHandle>( GetRouteTestData(carbon::Result::REMOTE_ERROR, "c"))}; TestFiberManager fm; TestRouteHandle<AllSyncRoute<TestRouteHandleIf>> rh( get_route_handles(test_handles)); fm.runAll({[&]() { McGetRequest req("key"); auto reply = rh.route(req); /* Check that we got the worst result back */ EXPECT_EQ(carbon::Result::REMOTE_ERROR, reply.result()); EXPECT_EQ("c", coalesceAndGetRange(reply.value()).str()); for (auto& h : test_handles) { EXPECT_EQ(vector<string>{"key"}, h->saw_keys); } }}); }
TEST(routeHandleTest, allInitial) { vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(carbon::Result::FOUND, "a")), make_shared<TestHandle>(GetRouteTestData(carbon::Result::NOTFOUND, "b")), make_shared<TestHandle>( GetRouteTestData(carbon::Result::REMOTE_ERROR, "c")), }; TestFiberManager fm; auto routeHandles = get_route_handles(test_handles); TestRouteHandle<AllInitialRoute<TestRouteHandleIf>> rh(routeHandles); fm.runAll({[&]() { auto reply = rh.route(McGetRequest("key")); /* Check that we got the initial result back */ EXPECT_EQ(carbon::Result::FOUND, reply.result()); EXPECT_EQ("a", carbon::valueRangeSlow(reply).str()); }}); /* Check that everything is complete in the background */ for (auto& h : test_handles) { EXPECT_EQ(vector<string>{"key"}, h->saw_keys); } /* Check that traverse is correct */ int cnt = 0; RouteHandleTraverser<TestRouteHandleIf> t{ [&cnt](const TestRouteHandleIf&) { ++cnt; }}; rh.traverse(McGetRequest("key"), t); EXPECT_EQ(cnt, routeHandles.size()); }
TEST(routeHandleTest, allAsync) { vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(mc_res_found, "a")), make_shared<TestHandle>(GetRouteTestData(mc_res_notfound, "b")), make_shared<TestHandle>(GetRouteTestData(mc_res_remote_error, "c")) }; TestFiberManager fm; TestRouteHandle<AllAsyncRoute<TestRouteHandleIf>> rh( get_route_handles(test_handles)); fm.runAll( { [&]() { auto op = McOperation<mc_op_get>(); auto reply = rh.route(McRequest("key"), op); /* Check that we got no result back */ EXPECT_TRUE(reply.result() == mc_res_notfound); } }); /* Check that everything is complete in the background */ for (auto& h : test_handles) { EXPECT_TRUE(h->saw_keys == vector<string> {"key"}); } }
TEST(BigValueRouteTest, smallvalue) { // for small values, this route handle simply passes it to child route handle vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(mc_res_found, "a"), UpdateRouteTestData(mc_res_stored), DeleteRouteTestData(mc_res_deleted)) }; auto route_handles = get_route_handles(test_handles); TestFiberManager fm; fm.runAll({ [&]() { McrouterRouteHandle<BigValueRoute> rh(route_handles[0], opts); std::string key = "key_get"; auto msg = createMcMsgRef(key, "value"); msg->op = mc_op_get; McRequestWithMcOp<mc_op_get> req_get(std::move(msg)); auto f_get = rh.route(req_get); EXPECT_EQ("a", toString(f_get.value())); EXPECT_EQ(test_handles[0]->saw_keys, vector<std::string>{"key_get"}); test_handles[0]->saw_keys.clear(); std::string key_set = "key_set"; auto msg_set = createMcMsgRef(key_set, "value"); msg_set->op = mc_op_set; McRequestWithMcOp<mc_op_set> req_set(std::move(msg_set)); auto f_set = rh.route(req_set); EXPECT_EQ(mc_res_stored, f_set.result()); EXPECT_EQ(test_handles[0]->saw_keys, vector<std::string>{"key_set"}); } }); }
TEST(routeHandleTest, allMajorityTieTyped) { TestFiberManager fm; vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(mc_res_remote_error, "a")), make_shared<TestHandle>(GetRouteTestData(mc_res_notfound, "b")), make_shared<TestHandle>(GetRouteTestData(mc_res_notfound, "c")), make_shared<TestHandle>(GetRouteTestData(mc_res_remote_error, "d")) }; TestRouteHandle<AllMajorityRoute<TestRouteHandleIf>> rh( get_route_handles(test_handles)); fm.runAll( { [&]() { TypedThriftRequest<cpp2::McGetRequest> req; req.setKey("key"); auto reply = rh.route(req); /* Check that we got the _worst_ majority reply */ EXPECT_TRUE(reply.result() == mc_res_remote_error); } }); /* Check that everything is complete */ for (auto& h : test_handles) { EXPECT_EQ(vector<string>{"key"}, h->saw_keys); } }
TEST(routeHandleTest, allFastest) { TestFiberManager fm; vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>( GetRouteTestData(carbon::Result::REMOTE_ERROR, "a")), make_shared<TestHandle>(GetRouteTestData(carbon::Result::NOTFOUND, "b")), make_shared<TestHandle>(GetRouteTestData(carbon::Result::FOUND, "c"))}; TestRouteHandle<AllFastestRoute<TestRouteHandleIf>> rh( get_route_handles(test_handles)); test_handles[1]->pause(); fm.runAll({[&]() { auto reply = rh.route(McGetRequest("key")); /* Check that we got the fastest non-error result back ('b' is paused) */ EXPECT_EQ(carbon::Result::FOUND, reply.result()); EXPECT_EQ("c", carbon::valueRangeSlow(reply).str()); EXPECT_EQ(vector<string>{"key"}, test_handles[0]->saw_keys); EXPECT_EQ(vector<string>{}, test_handles[1]->saw_keys); EXPECT_EQ(vector<string>{"key"}, test_handles[2]->saw_keys); test_handles[1]->unpause(); }}); /* Check that everything is complete in the background */ for (auto& h : test_handles) { EXPECT_EQ(vector<string>{"key"}, h->saw_keys); } }
TEST(routeHandleTest, allFastestTyped) { TestFiberManager fm; vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(mc_res_remote_error, "a")), make_shared<TestHandle>(GetRouteTestData(mc_res_notfound, "b")), make_shared<TestHandle>(GetRouteTestData(mc_res_found, "c")) }; TestRouteHandle<AllFastestRoute<TestRouteHandleIf>> rh( get_route_handles(test_handles)); test_handles[1]->pause(); fm.runAll( { [&]() { TypedThriftRequest<cpp2::McGetRequest> req; req.setKey("key"); auto reply = rh.route(req); /* Check that we got the fastest non-error result back ('b' is paused) */ EXPECT_EQ(mc_res_found, reply.result()); EXPECT_EQ("c", toString(*reply->get_value())); EXPECT_EQ(vector<string>{"key"}, test_handles[0]->saw_keys); EXPECT_EQ(vector<string>{}, test_handles[1]->saw_keys); EXPECT_EQ(vector<string>{"key"}, test_handles[2]->saw_keys); test_handles[1]->unpause(); } }); /* Check that everything is complete in the background */ for (auto& h : test_handles) { EXPECT_EQ(vector<string>{"key"}, h->saw_keys); } }
TEST(routeHandleTest, allMajorityTyped) { TestFiberManager fm; vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(mc_res_remote_error, "a")), make_shared<TestHandle>(GetRouteTestData(mc_res_notfound, "b")), make_shared<TestHandle>(GetRouteTestData(mc_res_remote_error, "c")) }; TestRouteHandle<AllMajorityRoute<TestRouteHandleIf>> rh( get_route_handles(test_handles)); test_handles[1]->pause(); fm.runAll( { [&]() { TypedThriftRequest<cpp2::McGetRequest> req; req.setKey("key"); auto reply = rh.route(req); /* Check that we got the majority reply without waiting for "b", which is paused */ EXPECT_TRUE(reply.result() == mc_res_remote_error); EXPECT_TRUE(test_handles[0]->saw_keys == vector<string>{"key"}); EXPECT_TRUE(test_handles[1]->saw_keys == vector<string>{}); EXPECT_TRUE(test_handles[2]->saw_keys == vector<string>{"key"}); test_handles[1]->unpause(); } }); /* Check that everything is complete in the background */ for (auto& h : test_handles) { EXPECT_TRUE(h->saw_keys == vector<string>{"key"}); } }
TEST(routeHandleTest, allInitialTyped) { vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(mc_res_found, "a")), make_shared<TestHandle>(GetRouteTestData(mc_res_notfound, "b")), make_shared<TestHandle>(GetRouteTestData(mc_res_remote_error, "c")), }; TestFiberManager fm; auto routeHandles = get_route_handles(test_handles); TestRouteHandle<AllInitialRoute<TestRouteHandleIf>> rh(routeHandles); TypedThriftRequest<cpp2::McGetRequest> req; req.setKey("key"); fm.runAll( { [&]() { auto reply = rh.route(req); /* Check that we got the initial result back */ EXPECT_EQ(mc_res_found, reply.result()); EXPECT_EQ("a", toString(*reply->get_value())); } }); /* Check that everything is complete in the background */ for (auto& h : test_handles) { EXPECT_EQ(vector<string>{"key"}, h->saw_keys); } /* Check that traverse is correct */ int cnt = 0; RouteHandleTraverser<TestRouteHandleIf> t{ [&cnt](const TestRouteHandleIf&){ ++cnt; } }; rh.traverse(req, t); EXPECT_EQ(cnt, routeHandles.size()); }
TEST(routeHandleTest, allFastest) { TestFiberManager fm; vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(mc_res_remote_error, "a")), make_shared<TestHandle>(GetRouteTestData(mc_res_notfound, "b")), make_shared<TestHandle>(GetRouteTestData(mc_res_found, "c")) }; TestRouteHandle<AllFastestRoute<TestRouteHandleIf>> rh( get_route_handles(test_handles)); test_handles[1]->pause(); fm.runAll( { [&]() { auto reply = rh.route(McRequestWithMcOp<mc_op_get>("key")); /* Check that we got the fastest non-error result back ('b' is paused) */ EXPECT_TRUE(reply.result() == mc_res_found); EXPECT_TRUE(toString(reply.value()) == "c"); EXPECT_TRUE(test_handles[0]->saw_keys == vector<string>{"key"}); EXPECT_TRUE(test_handles[1]->saw_keys == vector<string>{}); EXPECT_TRUE(test_handles[2]->saw_keys == vector<string>{"key"}); test_handles[1]->unpause(); } }); /* Check that everything is complete in the background */ for (auto& h : test_handles) { EXPECT_TRUE(h->saw_keys == vector<string>{"key"}); } }
TEST(shadowRouteTest, defaultPolicy) { vector<std::shared_ptr<TestHandle>> normalHandle{ make_shared<TestHandle>(GetRouteTestData(mc_res_found, "a")), }; auto normalRh = get_route_handles(normalHandle)[0]; vector<std::shared_ptr<TestHandle>> shadowHandles{ make_shared<TestHandle>(GetRouteTestData(mc_res_found, "b")), make_shared<TestHandle>(GetRouteTestData(mc_res_found, "c")), }; TestFiberManager fm; auto data = make_shared<proxy_pool_shadowing_policy_t::Data>(); vector<std::shared_ptr<proxy_pool_shadowing_policy_t>> settings { make_shared<proxy_pool_shadowing_policy_t>(data, nullptr), make_shared<proxy_pool_shadowing_policy_t>(data, nullptr), }; auto shadowRhs = get_route_handles(shadowHandles); ShadowData<TestRouteHandleIf> shadowData = { {std::move(shadowRhs[0]), std::move(settings[0])}, {std::move(shadowRhs[1]), std::move(settings[1])}, }; TestRouteHandle<ShadowRoute<TestRouteHandleIf, DefaultShadowPolicy>> rh( normalRh, std::move(shadowData), 0, DefaultShadowPolicy()); fm.runAll( { [&] () { auto reply = rh.route(McRequest("key"), McOperation<mc_op_get>()); EXPECT_TRUE(reply.result() == mc_res_found); EXPECT_TRUE(toString(reply.value()) == "a"); } }); EXPECT_TRUE(shadowHandles[0]->saw_keys.empty()); EXPECT_TRUE(shadowHandles[1]->saw_keys.empty()); data->end_index = 1; data->end_key_fraction = 1.0; fm.runAll( { [&] () { auto reply = rh.route(McRequest("key"), McOperation<mc_op_get>()); EXPECT_TRUE(reply.result() == mc_res_found); EXPECT_TRUE(toString(reply.value()) == "a"); } }); EXPECT_TRUE(shadowHandles[0]->saw_keys == vector<string>{"key"}); EXPECT_TRUE(shadowHandles[1]->saw_keys == vector<string>{"key"}); }
TEST(BigValueRouteTest, bigvalue) { // for big values, used saw_keys of test route handle to verify that // get path and set path saw original key and chunk keys in correct sequesne. std::string rand_suffix_get ("123456"); int num_chunks = 10; // initial reply of the form version-num_chunks-rand_suffix for get path std::string init_reply = folly::format("{}-{}-{}", version, num_chunks, rand_suffix_get).str(); std::string init_reply_error = folly::format("{}-{}", version, num_chunks).str(); vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData( mc_res_found, init_reply, MC_MSG_FLAG_BIG_VALUE)), make_shared<TestHandle>(GetRouteTestData( mc_res_found, init_reply_error, MC_MSG_FLAG_BIG_VALUE)), make_shared<TestHandle>(UpdateRouteTestData(mc_res_stored)), make_shared<TestHandle>(UpdateRouteTestData(mc_res_stored)) }; auto route_handles = get_route_handles(test_handles); TestFiberManager fm; std::shared_ptr<ProxyRequestContext> ctx; fm.runAll({ [&]() { { // Test Get Like path with init_reply in corect format McrouterRouteHandle<BigValueRoute> rh(route_handles[0], opts); auto msg = createMcMsgRef("key_get"); msg->op = mc_op_get; ProxyMcRequest req_get(std::move(msg)); auto f_get = rh.route(req_get, McOperation<mc_op_get>(), ctx); auto keys_get = test_handles[0]->saw_keys; EXPECT_TRUE(keys_get.size() == num_chunks + 1); // first get the result for original key EXPECT_TRUE(keys_get.front() == "key_get"); std::string merged_str; // since reply for first key indicated that it is for a big get request, // perform get request on chunk keys for (int i = 1; i < num_chunks + 1; i++) { auto chunk_key = folly::format( "key_get|#|{}:{}", i-1, rand_suffix_get).str(); EXPECT_EQ(chunk_key, keys_get[i]); merged_str.append(init_reply); } // each chunk_key saw value as init_reply. // In GetLike path, it gets appended num_chunks time EXPECT_TRUE(toString(f_get.value()) == merged_str); } { // Test Get Like path with init_reply_error McrouterRouteHandle<BigValueRoute> rh(route_handles[1], opts); auto msg = createMcMsgRef("key_get"); msg->op = mc_op_get; ProxyMcRequest req_get(std::move(msg)); auto f_get = rh.route(req_get, McOperation<mc_op_get>(), ctx); auto keys_get = test_handles[1]->saw_keys; EXPECT_TRUE(keys_get.size() == 1); // first get the result for original key, then return mc_res_notfound EXPECT_TRUE(keys_get.front() == "key_get"); EXPECT_TRUE(f_get.result() == mc_res_notfound); EXPECT_TRUE(toString(f_get.value()) == ""); } { // Test Update Like path with mc_op_set op McrouterRouteHandle<BigValueRoute> rh(route_handles[2], opts); std::string big_value = folly::to<std::string>( std::string(threshold*(num_chunks/2), 't'), std::string(threshold*(num_chunks/2), 's')); std::string chunk_type_1 = std::string(threshold, 't'); std::string chunk_type_2 = std::string(threshold, 's'); auto msg_set = createMcMsgRef("key_set", big_value); msg_set->op = mc_op_set; ProxyMcRequest req_set(std::move(msg_set)); auto f_set = rh.route(req_set, McOperation<mc_op_set>(), ctx); auto keys_set = test_handles[2]->saw_keys; auto values_set = test_handles[2]->sawValues; EXPECT_TRUE(keys_set.size() == num_chunks + 1); std::string rand_suffix_set; // first set chunk values corresponding to chunk keys for(int i = 0; i < num_chunks; i++) { auto chunk_key_prefix = folly::format("key_set|#|{}:", i).str(); auto length = chunk_key_prefix.length(); auto saw_prefix = keys_set[i].substr(0, length); EXPECT_TRUE(saw_prefix == chunk_key_prefix); if (rand_suffix_set.empty()) { // rand_suffic same for all chunk_keys rand_suffix_set = keys_set[i].substr(length); } else { EXPECT_TRUE(rand_suffix_set == keys_set[i].substr(length)); } if (i < num_chunks/2) { EXPECT_TRUE(values_set[i] == chunk_type_1); } else { EXPECT_TRUE(values_set[i] == chunk_type_2); } } // if set for chunk keys succeed, // set original key with chunks info as modified value EXPECT_TRUE(keys_set[num_chunks] == "key_set"); auto chunks_info = folly::format( "{}-{}-{}", version, num_chunks, rand_suffix_set).str(); EXPECT_TRUE(values_set[num_chunks] == chunks_info); EXPECT_TRUE(toString(f_set.value()) == values_set[num_chunks]); } { // Test Update Like path with mc_op_lease_set op McrouterRouteHandle<BigValueRoute> rh(route_handles[3], opts); std::string big_value = folly::to<std::string>( std::string(threshold*(num_chunks/2), 't'), std::string(threshold*(num_chunks/2), 's')); auto msg_set = createMcMsgRef("key_set", big_value); msg_set->op = mc_op_lease_set; ProxyMcRequest req_set(std::move(msg_set)); auto f_set = rh.route(req_set, McOperation<mc_op_lease_set>(), ctx); auto keys_set = test_handles[3]->saw_keys; auto operations_set = test_handles[3]->sawOperations; EXPECT_TRUE(keys_set.size() == num_chunks + 1); std::string rand_suffix_set; // first set chunk values corresponding to chunk keys for(int i = 0; i < num_chunks; i++) { auto chunk_key_prefix = folly::format("key_set|#|{}:", i).str(); auto length = chunk_key_prefix.length(); auto saw_prefix = keys_set[i].substr(0, length); EXPECT_TRUE(saw_prefix == chunk_key_prefix); EXPECT_TRUE(operations_set[i] == mc_op_set); } // if set for chunk keys succeed, // set original key with chunks info as modified value EXPECT_TRUE(keys_set[num_chunks] == "key_set"); EXPECT_TRUE(operations_set[num_chunks] == mc_op_lease_set); } } }); }
TEST(migrateRouteTest, migrate) { auto curr_time = time(nullptr); auto interval = 50; auto tp_func = []() { return time(nullptr); }; typedef decltype(tp_func) TimeProviderFunc; vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(mc_res_found, "a"), UpdateRouteTestData(), DeleteRouteTestData(mc_res_deleted)), make_shared<TestHandle>(GetRouteTestData(mc_res_found, "b"), UpdateRouteTestData(), DeleteRouteTestData(mc_res_notfound)), }; auto route_handles = get_route_handles(test_handles); TestFiberManager fm; fm.runAll({ [&]() { // case 1: curr_time < start_time TestRouteHandle<MigrateRoute<TestRouteHandleIf, TimeProviderFunc>> rh( route_handles[0], route_handles[1], curr_time + 25, interval, tp_func); TypedThriftRequest<cpp2::McGetRequest> req_get("key_get"); int cnt = 0; RouteHandleTraverser<TestRouteHandleIf> t{ [&cnt](const TestRouteHandleIf&) { ++cnt; } }; rh.traverse(req_get, t); EXPECT_EQ(1, cnt); auto reply_get = rh.route(req_get); EXPECT_EQ("a", reply_get.valueRangeSlow().str()); EXPECT_EQ(vector<string>{"key_get"}, test_handles[0]->saw_keys); EXPECT_NE(vector<string>{"key_get"}, test_handles[1]->saw_keys); (test_handles[0]->saw_keys).clear(); (test_handles[1]->saw_keys).clear(); TypedThriftRequest<cpp2::McDeleteRequest> req_del("key_del"); cnt = 0; rh.traverse(req_del, t); EXPECT_EQ(1, cnt); auto reply_del = rh.route(req_del); EXPECT_EQ(mc_res_deleted, reply_del.result()); EXPECT_EQ(vector<string>{"key_del"}, test_handles[0]->saw_keys); EXPECT_NE(vector<string>{"key_del"}, test_handles[1]->saw_keys); }, [&]() { // case 2: curr_time < start_time + interval vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(mc_res_found, "a"), UpdateRouteTestData(), DeleteRouteTestData(mc_res_deleted)), make_shared<TestHandle>(GetRouteTestData(mc_res_notfound, "b"), UpdateRouteTestData(), DeleteRouteTestData(mc_res_notfound)), }; auto route_handles_c2 = get_route_handles(test_handles); TestRouteHandle<MigrateRoute<TestRouteHandleIf, TimeProviderFunc>> rh( route_handles_c2[0], route_handles_c2[1], curr_time - 25, interval, tp_func); TypedThriftRequest<cpp2::McGetRequest> req_get("key_get"); int cnt = 0; RouteHandleTraverser<TestRouteHandleIf> t{ [&cnt](const TestRouteHandleIf&) { ++cnt; } }; rh.traverse(req_get, t); EXPECT_EQ(cnt, 1); auto reply_get = rh.route(req_get); EXPECT_EQ("a", reply_get.valueRangeSlow().str()); EXPECT_EQ(vector<string>{"key_get"}, test_handles[0]->saw_keys); EXPECT_NE(vector<string>{"key_get"}, test_handles[1]->saw_keys); (test_handles[0]->saw_keys).clear(); (test_handles[1]->saw_keys).clear(); TypedThriftRequest<cpp2::McDeleteRequest> req_del("key_del"); cnt = 0; rh.traverse(req_del, t); EXPECT_EQ(cnt, 2); auto reply_del = rh.route(req_del); EXPECT_EQ(mc_res_notfound, reply_del.result()); EXPECT_EQ(vector<string>{"key_del"}, test_handles[0]->saw_keys); EXPECT_EQ(vector<string>{"key_del"}, test_handles[1]->saw_keys); }, [&]() { // case 3: curr_time < start_time + 2*interval vector<std::shared_ptr<TestHandle>> test_handles{ make_shared<TestHandle>(GetRouteTestData(mc_res_notfound, "a"), UpdateRouteTestData(), DeleteRouteTestData(mc_res_notfound)), make_shared<TestHandle>(GetRouteTestData(mc_res_found, "b"), UpdateRouteTestData(), DeleteRouteTestData(mc_res_deleted)), }; auto route_handles_c3 = get_route_handles(test_handles); TestRouteHandle<MigrateRoute<TestRouteHandleIf, TimeProviderFunc>> rh( route_handles_c3[0], route_handles_c3[1], curr_time - 75, interval, tp_func); TypedThriftRequest<cpp2::McGetRequest> req_get("key_get"); int cnt = 0; RouteHandleTraverser<TestRouteHandleIf> t{ [&cnt](const TestRouteHandleIf&) { ++cnt; } }; rh.traverse(req_get, t); EXPECT_EQ(1, cnt); auto reply_get = rh.route(req_get); EXPECT_EQ("b", reply_get.valueRangeSlow().str()); EXPECT_NE(vector<string>{"key_get"}, test_handles[0]->saw_keys); EXPECT_EQ(vector<string>{"key_get"}, test_handles[1]->saw_keys); (test_handles[0]->saw_keys).clear(); (test_handles[1]->saw_keys).clear(); TypedThriftRequest<cpp2::McDeleteRequest> req_del("key_del"); cnt = 0; rh.traverse(req_del, t); EXPECT_EQ(2, cnt); auto reply_del = rh.route(req_del); EXPECT_EQ(mc_res_notfound, reply_del.result()); EXPECT_EQ(vector<string>{"key_del"}, test_handles[0]->saw_keys); EXPECT_EQ(vector<string>{"key_del"}, test_handles[1]->saw_keys); }, [&]() { // case 4: curr_time > start_time + 2*interval TestRouteHandle<MigrateRoute<TestRouteHandleIf, TimeProviderFunc>> rh( route_handles[0], route_handles[1], curr_time - 125, interval, tp_func); TypedThriftRequest<cpp2::McGetRequest> req_get("key_get"); int cnt = 0; RouteHandleTraverser<TestRouteHandleIf> t{ [&cnt](const TestRouteHandleIf&) { ++cnt; } }; rh.traverse(req_get, t); EXPECT_EQ(cnt, 1); auto reply_get = rh.route(req_get); EXPECT_EQ("b", reply_get.valueRangeSlow().str()); EXPECT_NE(vector<string>{"key_get"}, test_handles[0]->saw_keys); EXPECT_EQ(vector<string>{"key_get"}, test_handles[1]->saw_keys); (test_handles[0]->saw_keys).clear(); (test_handles[1]->saw_keys).clear(); TypedThriftRequest<cpp2::McDeleteRequest> req_del("key_del"); cnt = 0; rh.traverse(req_del, t); EXPECT_EQ(1, cnt); auto reply_del = rh.route(req_del); EXPECT_EQ(mc_res_notfound, reply_del.result()); EXPECT_NE(vector<string>{"key_del"}, test_handles[0]->saw_keys); EXPECT_EQ(vector<string>{"key_del"}, test_handles[1]->saw_keys); } }); }