From 52a951ea596b467ad9164b1410d5ebcce8050f2e Mon Sep 17 00:00:00 2001 From: Celina Tala Date: Wed, 14 Sep 2022 18:23:51 +0000 Subject: SERVER-65103 Use case-insensitive comparator for sorting hedging targets in tests --- src/mongo/executor/SConscript | 2 + src/mongo/executor/network_interface_tl.cpp | 34 ++++++++++--- src/mongo/executor/network_interface_tl.h | 6 +++ src/mongo/executor/network_interface_tl_test.cpp | 64 ++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 src/mongo/executor/network_interface_tl_test.cpp diff --git a/src/mongo/executor/SConscript b/src/mongo/executor/SConscript index 5ff35f0db4d..815159efd70 100644 --- a/src/mongo/executor/SConscript +++ b/src/mongo/executor/SConscript @@ -318,6 +318,7 @@ env.CppUnitTest( 'mock_remote_command_runner_test.cpp', 'network_interface_mock_test.cpp', 'network_interface_mock_test_fixture.cpp', + 'network_interface_tl_test.cpp', 'remote_command_runner_test.cpp', 'scoped_task_executor_test.cpp', 'task_executor_cursor_test.cpp', @@ -332,6 +333,7 @@ env.CppUnitTest( 'connection_pool_executor', 'egress_tag_closer_manager', 'network_interface_mock', + 'network_interface_tl', 'network_test_env', 'remote_command_runner', 'scoped_task_executor', diff --git a/src/mongo/executor/network_interface_tl.cpp b/src/mongo/executor/network_interface_tl.cpp index 6b3aab3f26a..f6979f18462 100644 --- a/src/mongo/executor/network_interface_tl.cpp +++ b/src/mongo/executor/network_interface_tl.cpp @@ -115,6 +115,17 @@ bool skipHedgeResult(const Status& status) { ErrorCodes::isNetworkTimeoutError(status) || ErrorCodes::isStaleShardVersionError(status); } +template +int compareTransformed(IA a1, IA a2, IB b1, IB b2, F&& f) { + for (;; ++a1, ++b1) + if (a1 == a2) + return b1 == b2 ? 0 : -1; + else if (b1 == b2) + return 1; + else if (int r = f(*a1) - f(*b1)) + return r; +} + } // namespace /** @@ -572,15 +583,12 @@ Status NetworkInterfaceTL::startCommand(const TaskExecutor::CallbackHandle& cbHa bool targetHostsInAlphabeticalOrder = MONGO_unlikely(networkInterfaceSendRequestsToTargetHostsInAlphabeticalOrder.shouldFail( - [request](const BSONObj&) { return request.options.isHedgeEnabled; })); + [&](const BSONObj&) { return request.options.isHedgeEnabled; })); if (targetHostsInAlphabeticalOrder) { - // Sort the target hosts by host names. - std::sort(request.target.begin(), - request.target.end(), - [](const HostAndPort& target1, const HostAndPort& target2) { - return target1.toString() < target2.toString(); - }); + std::sort(request.target.begin(), request.target.end(), [](auto&& a, auto&& b) { + return detail::orderByLowerHostThenPort(a, b); + }); } if ((request.target.size() > 1) && !request.options.isHedgeEnabled && @@ -1387,5 +1395,17 @@ void NetworkInterfaceTL::dropConnections(const HostAndPort& hostAndPort) { _pool->dropConnections(hostAndPort); } +namespace detail { + +bool orderByLowerHostThenPort(const HostAndPort& a, const HostAndPort& b) { + const auto& ah = a.host(); + const auto& bh = b.host(); + if (int r = compareTransformed( + ah.begin(), ah.end(), bh.begin(), bh.end(), [](auto&& c) { return ctype::toLower(c); })) + return r < 0; + return a.port() < b.port(); +} + +} // namespace detail } // namespace executor } // namespace mongo diff --git a/src/mongo/executor/network_interface_tl.h b/src/mongo/executor/network_interface_tl.h index fefb300f6fe..7353c92cd26 100644 --- a/src/mongo/executor/network_interface_tl.h +++ b/src/mongo/executor/network_interface_tl.h @@ -395,5 +395,11 @@ private: bool _isExecutorRunnable = false; }; +namespace detail { + +/** Order HostAndPorts by their lowercased hostnames then port number */ +bool orderByLowerHostThenPort(const HostAndPort& a, const HostAndPort& b); + +} // namespace detail } // namespace executor } // namespace mongo diff --git a/src/mongo/executor/network_interface_tl_test.cpp b/src/mongo/executor/network_interface_tl_test.cpp new file mode 100644 index 00000000000..06bafcbafe3 --- /dev/null +++ b/src/mongo/executor/network_interface_tl_test.cpp @@ -0,0 +1,64 @@ +/** + * Copyright (C) 2022-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + + +#include "mongo/executor/network_interface_tl.h" +#include "mongo/unittest/unittest.h" +#include "mongo/util/net/hostandport.h" + +namespace mongo { +namespace executor { +namespace { + +TEST(NetworkInterfaceTL, HostAndPortSorting) { + struct Spec { + HostAndPort a; + HostAndPort b; + bool out; + }; + static const Spec specs[]{ + {HostAndPort("ABC"), HostAndPort("abb"), false}, + {HostAndPort("abc"), HostAndPort("abcd"), true}, + {HostAndPort("abc", 1), HostAndPort("abc", 2), true}, + {HostAndPort("de:35"), HostAndPort("de:32"), false}, + {HostAndPort("def:34"), HostAndPort("dEF:39"), true}, + {HostAndPort("[0:0:0]"), HostAndPort("abc"), true}, + {HostAndPort("[0:0:0]"), HostAndPort("ABC"), true}, + }; + for (const auto& [a, b, out] : specs) { + ASSERT_EQ(detail::orderByLowerHostThenPort(a, b), out) << ", a:" << a << ", b:" << b; + if (out) { + ASSERT_EQ(detail::orderByLowerHostThenPort(b, a), !out) << ", a:" << a << ", b:" << b; + } + } +} + +} // namespace +} // namespace executor +} // namespace mongo -- cgit v1.2.1