Skip to content

Support multiple hash policies for HTTP routing#1756

Merged
mattklein123 merged 10 commits intoenvoyproxy:masterfrom
akonradi:http-routing-multiple-hashes
Sep 27, 2017
Merged

Support multiple hash policies for HTTP routing#1756
mattklein123 merged 10 commits intoenvoyproxy:masterfrom
akonradi:http-routing-multiple-hashes

Conversation

@akonradi
Copy link
Copy Markdown
Contributor

Fixes #1422

Fixes envoyproxy#1422

Signed-off-by: Alex Konradi <akonradi@google.com>
Copy link
Copy Markdown
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General approach looks good.

Optional<uint64_t> generateHash(const std::string& downstream_addr,
const Http::HeaderMap& headers) const override;

class HashImpl {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is a pure interface, it probably belongs in include/envoy/router. Also, for conventions, we tend not to suffix pure interfaces with Impl.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thought was that it's part of HashPolicyImpl's implementation, not part of its publicly accessible API. I'll change "HashImpl" to "HashMethod"; the intent was to signify that this is an interface for various ways of producing a hash.

for (const HashImplPtr& hash_impl : hash_impls_) {
Optional<uint64_t> new_hash = hash_impl->evaluate(downstream_addr, headers);
if (new_hash.valid()) {
hash.value(hash.valid() ? (hash.value() ^ new_hash.value()) : new_hash.value());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want something like a shift + XOR or multiplication (I don't think performance is a big issue here, it's a few cycles more). Otherwise, you can get degenerate situations, for example the same hash policy repeated twice, which will just give you zero always.

}
break;
default:
ASSERT(false);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might consider moving to throwing an EnvoyException here. I was a bit lazy initially as I expected to fill in all cases (or have constraints to cover them), but if we're writing new code, we should either add a TODO about using constraints to catch this/implement or throw.

if (header) {
hash.value(HashUtil::xxHash64(header->value().c_str()));
}
return hash;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth the complexity to have this optional? Why not just return a zero hash value if missing?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intent was to remain compatible with the existing interface. Zero is a valid hash value, even if it doesn't show up often.

public:
IpHashImpl() {}

~IpHashImpl() override {}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need to override these if default.

Signed-off-by: Alex Konradi <akonradi@google.com>
Signed-off-by: Alex Konradi <akonradi@google.com>
Signed-off-by: Alex Konradi <akonradi@google.com>
This prevents the degenerate case that htuch mentioned, where a
duplicated hash policy would cancel out the first one.

Signed-off-by: Alex Konradi <akonradi@google.com>
Signed-off-by: Alex Konradi <akonradi@google.com>
Copy link
Copy Markdown
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

if (header) {
hash.value(HashUtil::xxHash64(header->value().c_str()));
for (const HashMethodPtr& hash_impl : hash_impls_) {
Optional<uint64_t> new_hash = hash_impl->evaluate(downstream_addr, headers);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: const

}
EXPECT_NE(hash_ip, hash_h);
EXPECT_NE(hash_ip, hash_both);
EXPECT_NE(hash_h, hash_both);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about validating that if you hash twice the same input, you get a deterministic result, i.e. eq?

}

private:
Http::LowerCaseString header_name_;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: const

break;
default:
throw EnvoyException(
fmt::format("Unsupported hash policy {}", hash_policy.policy_specifier_case()));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test for this?

Copy link
Copy Markdown
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks good apart from @htuch comments and my small one.

for (const HashMethodPtr& hash_impl : hash_impls_) {
Optional<uint64_t> new_hash = hash_impl->evaluate(downstream_addr, headers);
if (new_hash.valid()) {
hash.value(hash.valid() ? (((hash.value() << 1) | (hash.value() >> 63)) ^ new_hash.value())
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a comment on how this bit shifting was chosen?

Signed-off-by: Alex Konradi <akonradi@google.com>
Signed-off-by: Alex Konradi <akonradi@google.com>
Signed-off-by: Alex Konradi <akonradi@google.com>
@mattklein123
Copy link
Copy Markdown
Member

Sorry please merge master again. Still trying to sort out CI issues.

…iple-hashes

Signed-off-by: Alex Konradi <akonradi@google.com>
@mattklein123 mattklein123 merged commit 8880857 into envoyproxy:master Sep 27, 2017
costinm pushed a commit to costinm/envoy that referenced this pull request Oct 2, 2017
Fixes envoyproxy#1422

Signed-off-by: Alex Konradi <akonradi@google.com>
@akonradi akonradi deleted the http-routing-multiple-hashes branch October 16, 2017 19:51
jpsim pushed a commit that referenced this pull request Nov 28, 2022
Description: Adding these has had no measurable benefit, and they're likely detrimental to timely passive healthchecking and  interactions tuned for specific TCP keepalive settings.
Risk Level: Low
Testing: Local & CI

Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: JP Simard <jp@jpsim.com>
jpsim pushed a commit that referenced this pull request Nov 29, 2022
Description: Adding these has had no measurable benefit, and they're likely detrimental to timely passive healthchecking and  interactions tuned for specific TCP keepalive settings.
Risk Level: Low
Testing: Local & CI

Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: JP Simard <jp@jpsim.com>
mathetake added a commit that referenced this pull request Mar 3, 2026
**Description**

This commit cleans up Makefile by removing unnecessary variables etc.

Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants