topology: optimize compare_endpoints

This function is called on the fast data path
from storage_proxy when sorting multiple endpoints
by proximity.

This change calculates numeric node diff metrics
based on each address proximity to a given node
(by <dc, rack, same node>) to eliminate logic
branches in the function and reduce its footprint.

based on objdump -d output, compare_endpoints
footprint was reduced by 58.5% (3632 / 8752 bytes)
with clang version 15.0.7 (Fedora 15.0.7-1.fc37)

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
This commit is contained in:
Benny Halevy
2023-02-07 11:31:21 +02:00
parent 3ac2df9480
commit bb36237cf4
3 changed files with 29 additions and 54 deletions

View File

@@ -166,53 +166,26 @@ void topology::sort_by_proximity(inet_address address, inet_address_vector_repli
}
}
int topology::compare_endpoints(const inet_address& address, const inet_address& a1, const inet_address& a2) const {
//
// if one of the Nodes IS the Node we are comparing to and the other one
// IS NOT - then return the appropriate result.
//
if (address == a1 && address != a2) {
return -1;
}
std::weak_ordering topology::compare_endpoints(const inet_address& address, const inet_address& a1, const inet_address& a2) const {
const auto& loc = get_location(address);
const auto& loc1 = get_location(a1);
const auto& loc2 = get_location(a2);
if (address == a2 && address != a1) {
return 1;
}
// The farthest nodes from a given node are:
// 1. Nodes in other DCs then the reference node
// 2. Nodes in the other RACKs in the same DC as the reference node
// 3. Other nodes in the same DC/RACk as the reference node
int same_dc1 = loc1.dc == loc.dc;
int same_rack1 = same_dc1 & (loc1.rack == loc.rack);
int same_node1 = a1 == address;
int d1 = ((same_dc1 << 2) | (same_rack1 << 1) | same_node1) ^ 7;
// ...otherwise perform the similar check in regard to Data Center
sstring address_datacenter = get_datacenter(address);
sstring a1_datacenter = get_datacenter(a1);
sstring a2_datacenter = get_datacenter(a2);
int same_dc2 = loc2.dc == loc.dc;
int same_rack2 = same_dc2 & (loc2.rack == loc.rack);
int same_node2 = a2 == address;
int d2 = ((same_dc2 << 2) | (same_rack2 << 1) | same_node2) ^ 7;
if (address_datacenter == a1_datacenter &&
address_datacenter != a2_datacenter) {
return -1;
} else if (address_datacenter == a2_datacenter &&
address_datacenter != a1_datacenter) {
return 1;
} else if (address_datacenter == a2_datacenter &&
address_datacenter == a1_datacenter) {
//
// ...otherwise (in case Nodes belong to the same Data Center) check
// the racks they belong to.
//
sstring address_rack = get_rack(address);
sstring a1_rack = get_rack(a1);
sstring a2_rack = get_rack(a2);
if (address_rack == a1_rack && address_rack != a2_rack) {
return -1;
}
if (address_rack == a2_rack && address_rack != a1_rack) {
return 1;
}
}
//
// We don't differentiate between Nodes if all Nodes belong to different
// Data Centers, thus make them equal.
//
return 0;
return d1 <=> d2;
}
} // namespace locator

View File

@@ -12,6 +12,7 @@
#include <unordered_set>
#include <unordered_map>
#include <compare>
#include <seastar/core/future.hh>
#include <seastar/core/sstring.hh>
@@ -106,7 +107,7 @@ private:
* 2. Nodes in the same RACK as the reference node
* 3. Nodes in the same DC as the reference node
*/
int compare_endpoints(const inet_address& address, const inet_address& a1, const inet_address& a2) const;
std::weak_ordering compare_endpoints(const inet_address& address, const inet_address& a1, const inet_address& a2) const;
/** multi-map: DC -> endpoints in that DC */
std::unordered_map<sstring,