Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

filters: support internal buffering #1090

Merged
merged 11 commits into from
Sep 22, 2020
Merged

filters: support internal buffering #1090

merged 11 commits into from
Sep 22, 2020

Conversation

goaway
Copy link
Contributor

@goaway goaway commented Sep 14, 2020

Description: Adds internal buffering support for platform filters. Filters may now utilize Envoy's internal buffering by returning the status StopIterationAndBuffer. The complete buffer will be passed on subsequent on*Data invocations until iteration is resumed. This change does not support modifying the buffer (support coming in #1100 ).
Risk Level: Moderate
Testing: Unit coverage, local and CI

Signed-off-by: Mike Schore mike.schore@gmail.com

Base automatically changed from ms/pbf-unit to main September 14, 2020 18:49
@goaway goaway force-pushed the ms/filter-buffering branch 4 times, most recently from c78828f to c885cb7 Compare September 16, 2020 08:50
@goaway goaway marked this pull request as ready for review September 16, 2020 11:25
@goaway goaway requested a review from junr03 September 16, 2020 18:22
switch (status) {
case Http::FilterDataStatus::Continue:
if (iteration_mode_ == IterationMode::Stopped) {
// Error: iteration must be Resumed first.

Choose a reason for hiding this comment

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

Are we planning to add an error here or will we silently fail?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Options are to fail the request or crash the app. Neither seems terribly ideal, but perhaps neither is silently failing. I hadn't made up my mind here yet.

Copy link
Member

Choose a reason for hiding this comment

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

Seems like the place for an assertion? i.e the contract is that if the FilterDataStatus is to continue it is a programming error to have the manager's iteration_mode as anything but ongoing?

Related. Can we write API docs for the programming contract that these filters have?

Copy link
Member

Choose a reason for hiding this comment

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

^ Yeah, after going through this section in it entirety I think we need some more comments about all the combinations and why we are treating them as we are.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed about public documentation (there's an issue tracking it) - also this is currently captured in the planning doc I shared when we decided on this behavior. Whether and how it's a programming error is something I'm still ambivalent about. We could also generate an error response, too. Or do nothing here, and let Envoy do whatever it does when requests/responses try to forward invalid state. I'm going to make this a TODO I think for now.

break;
case Http::FilterDataStatus::StopIterationAndBuffer:
if (iteration_mode_ == IterationMode::Stopped) {
// Data has already have been buffered.

Choose a reason for hiding this comment

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

Do we use the no buffer variant here because the data is being buffered in this filter?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's correct.

Copy link
Member

@junr03 junr03 left a comment

Choose a reason for hiding this comment

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

Some comments!

library/common/buffer/utility.h Outdated Show resolved Hide resolved
library/common/buffer/utility.h Outdated Show resolved Hide resolved
@@ -29,6 +29,8 @@ class PlatformBridgeFilterConfig {

typedef std::shared_ptr<PlatformBridgeFilterConfig> PlatformBridgeFilterConfigSharedPtr;

enum class IterationMode { Ongoing, Stopped };
Copy link
Member

Choose a reason for hiding this comment

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

nit: The filter manager in envoy defines this as IterationState. Should we keep the same language here?

Copy link
Member

Choose a reason for hiding this comment

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

Similarly internally Ongoing/Continue?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Given that we now have a Resume status, I felt Ongoing was a bit clearer. Iteration will be ongoing or iteration will be stopped. I'm fine with IterationState though.

internal_buffer->move(data);
in_data = Buffer::Utility::copyToBridgeData(*internal_buffer);
} else {
in_data = Buffer::Utility::copyToBridgeData(data);
Copy link
Member

Choose a reason for hiding this comment

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

maybe this will become clear later, but why is this a copy rather than a drain like before?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When the buffer is unmodified, we shouldn't be draining Envoy's buffer. Per our discussed API, we now explicitly disallow the buffer to be modified in any state other than Continue or Resume.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There are also other ways we could potentially handle this, but for now, this is expedient and has no real downside since transform was doing a copy anyways.

switch (status) {
case Http::FilterDataStatus::Continue:
if (iteration_mode_ == IterationMode::Stopped) {
// Error: iteration must be Resumed first.
Copy link
Member

Choose a reason for hiding this comment

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

Seems like the place for an assertion? i.e the contract is that if the FilterDataStatus is to continue it is a programming error to have the manager's iteration_mode as anything but ongoing?

Related. Can we write API docs for the programming contract that these filters have?

break;
case Http::FilterDataStatus::StopIterationAndBuffer:
if (iteration_mode_ == IterationMode::Stopped) {
// Data has already have been buffered.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// Data has already have been buffered.
// Data has already have been buffered by the PlatformBridgeFilter.

Just want something more explicit about whose responsibility it is to buffer

iteration_mode_ = IterationMode::Stopped;
break;
default:
PANIC("unsupported status for platform filters");
Copy link
Member

Choose a reason for hiding this comment

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

convention is to use NOT_REACHED_GCOVR_EXCL_LINE. You can leave a comment above why the default should not be reached.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, the default can be reached - we haven't enumerated all statuses Envoy defines, and a truly strange implementation of a filter could try to break things here. I think the assertion is maybe warranted?

Copy link
Member

Choose a reason for hiding this comment

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

@goaway, under the hood NOT_REACHED_GCOVR_EXCL_LINE panics. It doesn't mean that it cannot be reached, it means that if it reaches it is an error.

Copy link
Member

Choose a reason for hiding this comment

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

^ bump on this

// TODO(goaway): Current platform implementations expose immutable data, thus any modification
// necessitates a full copy. Add 'modified' bit to determine when we can elide the copy. See also
// https://github.com/lyft/envoy-mobile/issues/949 for potential future optimization.
data.drain(data.length());
Copy link
Member

Choose a reason for hiding this comment

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

hmmm were we double draining before? Once in toBridge data and once here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, we were double draining before. Which was benign, but not ideal.

switch (status) {
case Http::FilterDataStatus::Continue:
if (iteration_mode_ == IterationMode::Stopped) {
// Error: iteration must be Resumed first.
Copy link
Member

Choose a reason for hiding this comment

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

^ Yeah, after going through this section in it entirety I think we need some more comments about all the combinations and why we are treating them as we are.

@goaway
Copy link
Contributor Author

goaway commented Sep 18, 2020

@junr03 I tried to make comments a little bit more explicit. Let me know if you have other suggestions. In general, I agree on the need for holistic documentation of all this, but I do think the tests ultimately also make explicit the intended behavior.

@junr03
Copy link
Member

junr03 commented Sep 18, 2020

I do think the tests ultimately also make explicit the intended behavior.

Yeah that helps internally. I also worry about platform filter authors. But happy to see in a subsequent PR per your other comment

@junr03
Copy link
Member

junr03 commented Sep 18, 2020

Looks like ASAN is still failing on the latter two tests. Just need to release the received data in the callback I think

@goaway
Copy link
Contributor Author

goaway commented Sep 18, 2020

@junr03 I actually am releasing it. Not sure why it's still failing.

junr03
junr03 previously approved these changes Sep 21, 2020
Copy link
Member

@junr03 junr03 left a comment

Choose a reason for hiding this comment

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

Thanks for the comments and the todo. Just one small bump on the panic, otherwise lgtm.

iteration_mode_ = IterationMode::Stopped;
break;
default:
PANIC("unsupported status for platform filters");
Copy link
Member

Choose a reason for hiding this comment

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

^ bump on this

Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
Signed-off-by: Mike Schore <mike.schore@gmail.com>
@goaway goaway merged commit 8cec75c into main Sep 22, 2020
@goaway goaway deleted the ms/filter-buffering branch September 22, 2020 04:52
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