Skip to content

stream_info: Add the concept of "life span" to StreamInfo::FilterState#9202

Merged
mattklein123 merged 32 commits intoenvoyproxy:masterfrom
penguingao:filter-state
Dec 11, 2019
Merged

stream_info: Add the concept of "life span" to StreamInfo::FilterState#9202
mattklein123 merged 32 commits intoenvoyproxy:masterfrom
penguingao:filter-state

Conversation

@penguingao
Copy link
Copy Markdown
Contributor

@penguingao penguingao commented Dec 3, 2019

Description: Add the concept of "life span" to StreamInfo::FilterState so that we can make some object survive across recreateStream during internal redirect handling. Since internal redirect recreates the entire filter chain, we need a mechanism for router filter to keep track of number of redirects that have been followed in order to support multiple hop redirects. Connection level sharing is also possible with FilterState::LifeSpan::DownstreamConnection.

This makes the filter implementation explicitly set the desire life span of their filter state object, so that the implementation can be internal redirect aware if so desired.

This is part of #9143. I intend to better handle StreamInfo/logging for internal redirect handling in a separate PR.

Risk Level: Medium
Testing: Unit test added
Docs Changes: N/A
Release Notes: N/A

FilterState objects across recreateStream.

Signed-off-by: Peng Gao <pengg@google.com>
Signed-off-by: Peng Gao <pengg@google.com>
Signed-off-by: Peng Gao <pengg@google.com>
Signed-off-by: Peng Gao <pengg@google.com>
@penguingao
Copy link
Copy Markdown
Contributor Author

@alyssawilk

it instead of a pointer to FilterState.

Signed-off-by: Peng Gao <pengg@google.com>
alyssawilk
alyssawilk previously approved these changes Dec 3, 2019
Copy link
Copy Markdown
Contributor

@alyssawilk alyssawilk left a comment

Choose a reason for hiding this comment

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

I think this is a simple and elegant way to allow the custom data to persist, regardless of what entity is doing the redirect.
Tagging @mattklein123 for thoughts rather than merging because he may see some gotchas I'm missing.

Signed-off-by: Peng Gao <pengg@google.com>
@kyessenov
Copy link
Copy Markdown
Contributor

Neat design. I wonder if we can add Connection life span that allows copying from a connection stream info to a request stream info. That way a TCP filter can pass data to HTTP filters. We would make Connection life span the lowest and copy FilterChain and above data into HTTP filter stream info.

@penguingao
Copy link
Copy Markdown
Contributor Author

penguingao commented Dec 3, 2019

@alyssawilk Thanks for the review!

@kyessenov I did think about it, and I actually left a comment in filter_state.h saying we can do that in the future. The connection level sharing will be a little trickier than DownstreamRequest scope since there may be multiple active streams at the same time. We need some callback and feedback mechanisms to make it work. That said, I wanted to do it, but changed my mind to defer to when we need such capability.

@kyessenov
Copy link
Copy Markdown
Contributor

kyessenov commented Dec 3, 2019

@penguingao We do have a need so I can follow up with that. Can you clarify a bit what you mean by callbacks needed to make it work? I would assume it's a matter of copying connection filter state into stream filter state on creation. It might be OK to mutate the connection filter state from multiple HTTP streams (e.g. count number of active streams?), it's a single silo after all.

@penguingao
Copy link
Copy Markdown
Contributor Author

@kyessenov, ok. Let me prepare another PR to add it.

I think what I meant is that we should better pass objects created by setData that has Connection life span to a connection level data structure during the call, because multiple active streams can call setData.

That way, we don't have to explicitly copy the newly added object to all other active stream's filter state.

@kyessenov
Copy link
Copy Markdown
Contributor

@penguingao I just discussed this with @gargnupur. We have some concerns about the copying that would happen with every request. Have you considered chaining filter states instead? We can change lookup function to traverse a parent as a fallback at a specific life span. Given that the lifetimes are clear in the case of HTTP vs TCP stream infos, the ownership is a non-issue.

@penguingao
Copy link
Copy Markdown
Contributor Author

@kyessenov that's exactly what I was proposing for my next PR

@gargnupur
Copy link
Copy Markdown
Contributor

@penguingao : This solution is quite neat!

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.

At a high this looks good to me. If we know that we need connection level sharing, can we potentially merge it into this PR? It's not that big and I'm a little concerned that connection level sharing is going to slightly change the design. Also, is it possible to have an internal redirection test that shows this new behavior to verify that aspect of the code? Thank you!

/wait

@penguingao
Copy link
Copy Markdown
Contributor Author

@mattklein123
re: merge connection level sharing into this PR. SGTM. I'll make that change.

re: internal redirect test: I was planning to add that test when I add multiple hop redirects, where the state sharing is actually used. Let me make internal redirect to use FilterState in this PR to make it tested as well.

Signed-off-by: Peng Gao <pengg@google.com>
callers explicitly specify what they want. Fixing tests as well.

Signed-off-by: Peng Gao <pengg@google.com>
Signed-off-by: Peng Gao <pengg@google.com>
@penguingao
Copy link
Copy Markdown
Contributor Author

/wait

Signed-off-by: Peng Gao <pengg@google.com>
Signed-off-by: Peng Gao <pengg@google.com>
@penguingao
Copy link
Copy Markdown
Contributor Author

@alyssawilk @mattklein123 PTAL when you have a chance.

This has gotten a bit more complicated than I imagined to support the connection level sharing, but at least I made the FilterStateImpl self contained to support lazy init of parent state - only HCM needs to care about the slightly complex constructor with a reference to a shared_ptr. Let me know what you think.

Thanks!

in the constructor.

Signed-off-by: Peng Gao <pengg@google.com>
Copy link
Copy Markdown
Contributor

@alyssawilk alyssawilk left a comment

Choose a reason for hiding this comment

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

Well this got more complicated since last I looked. Also far more useful - thanks! :-)

Update FilterState top level comment.
Add comment in recreateStream for on-demand copy.
Rename FilterState(Impl)::hasDataAtOrAboveLifeSpan.

Signed-off-by: Peng Gao <pengg@google.com>
Signed-off-by: Peng Gao <pengg@google.com>
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.

Thanks this is really awesome work! Just a bunch of random small comments. Can you also check the code coverage report in CI to make sure you have 100% coverage for all of the new branching states you added? Thank you!

/wait

// FilterStateImpl at the same life span. This interface is supposed to be accessed at the leaf
// level (FilterChain) for objects with any desired longer life span.
//
// - FilterChain has the shortest life span, which is as long as the http filter chain lives.
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: would remove http here as this equally applies to network filters.

//
// - DownstreamRequest is longer than FilterChain. When internal redirect is enabled, one
// downstream request may create multiple filter chains. DownstreamRequest allows an Object to
// survived across filter chains for book needs.
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.

survive across filter chains for bookkeeping needs.

*/
virtual LifeSpan lifeSpan() const PURE;

/**
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.

   * @return the pointer of the parent FilterState that has longer life span. nullptr means this is
   * either the top LifeSpan or the parent is not yet created.


TimeSource& timeSource() { return time_source_; }

std::shared_ptr<StreamInfo::FilterState>& filterState() { return filter_state_; }
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: can you add a small comment on why we return this by reference?

throw EnvoyException(
"FilterState::setData<T> called twice with conflicting life_span on the same data_name.");
}
maybeCreateParent(/* read_only = */ 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.

nit: if you find yourself wanting to have these comments here, I would recommend making this function take a dual state enum that will provide more clarity. TIOLO.

: time_source_(time_source), start_time_(time_source.systemTime()),
start_time_monotonic_(time_source.monotonicTime()),
filter_state_(std::make_shared<FilterStateImpl>(FilterState::LifeSpan::FilterChain)) {
protocol_ = protocol;
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: while you are in here, initialize protocol_ in the initializer list, same below.

- remove http from FilterState::LifeSpan::FilterChain comment.
- correctly spell survive and bookkeeping.
- point -> pointer and grammar
- comment why return reference from ConnectionManagerImpl::filterState().
- make FilterStateImpl::maybeCreateParent take a two state enum to avoid comment for boolean value.
- Init protocol_ in the constructors of StreamInfoImpl.

Signed-off-by: Peng Gao <pengg@google.com>
mattklein123
mattklein123 previously approved these changes Dec 10, 2019
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.

LGTM, thanks. @alyssawilk any further comments? @penguingao did you check the coverage report also?

@penguingao
Copy link
Copy Markdown
Contributor Author

@mattklein123 for some reason, my ci run is saying this: "Coverage report will not be uploaded for this build."

I am running the coverage on my workstation to see if I can get a read on the coverage report.

@mattklein123
Copy link
Copy Markdown
Member

@penguingao that is probably just a script bug. I see the artifacts in the circle CI UI: https://305966-65214191-gh.circle-artifacts.com/0/coverage/index.html

@penguingao
Copy link
Copy Markdown
Contributor Author

@mattklein123 Ah, thanks. I am not yet familiar with CI. Should have looked deeper.

I checked files I modified, all new branches are covered.

@penguingao
Copy link
Copy Markdown
Contributor Author

/azp run envoy-windows

@azure-pipelines
Copy link
Copy Markdown

Commenter does not have sufficient privileges for PR 9202 in repo envoyproxy/envoy

@penguingao
Copy link
Copy Markdown
Contributor Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

🙀 Error while processing event:

evaluation error
error: function error error: user: combined status is failure, but no failed builds.
🐱

Caused by: a #9202 (comment) was created by @penguingao.

see: more, trace.

- Object -> object
- sni_cluster is a network filter so call FilterState with the correct life span

Signed-off-by: Peng Gao <pengg@google.com>
…etwork filters.

Signed-off-by: Peng Gao <pengg@google.com>
@penguingao
Copy link
Copy Markdown
Contributor Author

@alyssawilk I've made change to address your comments. Tests are running.

@mattklein123 mattklein123 merged commit ed29591 into envoyproxy:master Dec 11, 2019
@penguingao penguingao deleted the filter-state branch December 11, 2019 23:52
prakhag1 pushed a commit to prakhag1/envoy that referenced this pull request Jan 3, 2020
envoyproxy#9202)

Signed-off-by: Peng Gao <pengg@google.com>
Signed-off-by: Prakhar <prakhar_au@yahoo.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.

5 participants