Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion source/common/common/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ envoy_cc_library(
envoy_cc_library(
name = "hash_lib",
hdrs = ["hash.h"],
external_deps = ["xxhash"],
external_deps = [
"abseil_strings",
"xxhash",
],
)

envoy_cc_library(
Expand Down
5 changes: 2 additions & 3 deletions source/common/common/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <string>

#include "absl/strings/string_view.h"
#include "xxhash.h"

namespace Envoy {
Expand All @@ -12,9 +13,7 @@ class HashUtil {
* Return 64-bit hash with seed of 0 from the xxHash algorithm.
* See https://github.com/Cyan4973/xxHash for details.
*/
static uint64_t xxHash64(const std::string& input) {
return XXH64(input.c_str(), input.size(), 0);
}
static uint64_t xxHash64(absl::string_view input) { return XXH64(input.data(), input.size(), 0); }
};

} // namespace Envoy
3 changes: 2 additions & 1 deletion source/common/common/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,11 @@ class StringUtil {
/**
* Convert an unsigned integer to a base 10 string as fast as possible.
* @param out supplies the string to fill.
* @param out_len supplies the length of the output buffer. Must be >= 21.
* @param out_len supplies the length of the output buffer. Must be >= MIN_ITOA_OUT_LEN.
* @param i supplies the number to convert.
* @return the size of the string, not including the null termination.
*/
static constexpr size_t MIN_ITOA_OUT_LEN = 21;
static uint32_t itoa(char* out, size_t out_len, uint64_t i);

/**
Expand Down
3 changes: 3 additions & 0 deletions source/common/upstream/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ envoy_cc_library(
name = "ring_hash_lb_lib",
srcs = ["ring_hash_lb.cc"],
hdrs = ["ring_hash_lb.h"],
external_deps = [
"abseil_strings",
],
deps = [
":load_balancer_lib",
"//include/envoy/runtime:runtime_interface",
Expand Down
32 changes: 28 additions & 4 deletions source/common/upstream/ring_hash_lb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include "common/common/assert.h"
#include "common/upstream/load_balancer_impl.h"

#include "absl/strings/string_view.h"

namespace Envoy {
namespace Upstream {

Expand Down Expand Up @@ -136,12 +138,34 @@ RingHashLoadBalancer::Ring::Ring(const Optional<envoy::api::v2::Cluster::RingHas
config.valid()
? PROTOBUF_GET_WRAPPED_OR_DEFAULT(config.value().deprecated_v1(), use_std_hash, true)
: true;

char hash_key_buffer[196];
for (const auto& host : hosts) {
const std::string& address_string = host->address()->asString();
uint64_t offset_start = address_string.size();

// Currently, we support both IP and UDS addresses. The UDS max path length is ~108 on all Unix
// platforms that I know of. Given that, we can use a 196 char buffer which is plenty of room
// for UDS, '_', and up to 21 characters for the node ID. To be on the super safe side, there
// is a RELEASE_ASSERT here that checks this, in case someone in the future adds some type of
// new address that is larger, or runs on a platform where UDS is larger. I don't think it's
// worth the defensive coding to deal with the heap allocation case (e.g. via
// absl::InlinedVector) at the current time.
RELEASE_ASSERT(address_string.size() + 1 + StringUtil::MIN_ITOA_OUT_LEN <=
sizeof(hash_key_buffer));
memcpy(hash_key_buffer, address_string.c_str(), offset_start);
hash_key_buffer[offset_start++] = '_';
for (uint64_t i = 0; i < hashes_per_host; i++) {
const std::string hash_key(host->address()->asString() + "_" + std::to_string(i));
const uint64_t hash =
use_std_hash ? std::hash<std::string>()(hash_key) : HashUtil::xxHash64(hash_key);
ENVOY_LOG(trace, "ring hash: hash_key={} hash={}", hash_key, hash);
const uint64_t total_hash_key_len =
offset_start +
StringUtil::itoa(hash_key_buffer + offset_start, StringUtil::MIN_ITOA_OUT_LEN, i);
absl::string_view hash_key(hash_key_buffer, total_hash_key_len);

// Sadly std::hash provides no mechanism for hashing arbitrary bytes so we must copy here.
// xxHash is done wihout copies.
const uint64_t hash = use_std_hash ? std::hash<std::string>()(std::string(hash_key))
: HashUtil::xxHash64(hash_key);
ENVOY_LOG(trace, "ring hash: hash_key={} hash={}", hash_key.data(), hash);
ring_.push_back({hash, host});
}
}
Expand Down