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

filter chain: prefer vector over list for filter chain #37665

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

wbpcode
Copy link
Member

@wbpcode wbpcode commented Dec 15, 2024

Commit Message: filter chain: prefer vector over list for filter chain
Additional Description:

Use vector to store the filter chain rather than list. Note, we never require to insert/remove element in the intermediate node of filter chain container. In this scenario, vector is much more memory-friend than list.

Risk Level: mid.
Testing: n/a.
Docs Changes: n/a.
Release Notes: n/a.
Platform Specific Features: n/a.

Signed-off-by: wangbaiping(wbpcode) <[email protected]>
@wbpcode
Copy link
Member Author

wbpcode commented Dec 15, 2024

This is why I created PRs to unify the creation downstream and upstream filter chains. All for this PR.

@wbpcode
Copy link
Member Author

wbpcode commented Dec 15, 2024

hi, @adisuissa , could you take a look at this also if you get some free time? I think you also did some similar work. Thanks.

@@ -919,7 +936,7 @@ FilterManager::commonEncodePrefix(ActiveStreamEncoderFilter* filter, bool end_st
state_.decoder_filter_chain_aborted_ = true;
}
}
return encoder_filters_.begin();
return encoder_filters_.rbegin();
Copy link
Contributor

Choose a reason for hiding this comment

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

why are we changing these to reverse iterators?
/wait-any

Copy link
Member Author

@wbpcode wbpcode Dec 16, 2024

Choose a reason for hiding this comment

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

See, the original container of filter chain is list. When a new filter is added, it will be inserted to the begin of the encoder_filters_ to ensure the first added filter will be called at last for encoding path.

And now, we changed the container to vector and the filter will always be appended to the end of the vector. So, we use the reverse iterator to ensure the previous behavior will not be effected.

Copy link
Contributor

Choose a reason for hiding this comment

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

ah yep, I missed that we inserted in order before and now we don't. IMO it's worth C++ comments either where the vectors are defined or where we get iterators to call out that's what's going on

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it is commented at the function where the filter is inserted to the container. I will add some more details at there.

@@ -42,12 +37,36 @@ void recordLatestDataFilter(const typename FilterList<T>::iterator current_filte
// correctly iterate over the filters and set latest, but on subsequent onData iterations
// we'd start from the beginning again, potentially allowing filter N to modify the buffer even
// though filter M > N was the filter that inserted data into the buffer.
if (current_filter != filters.begin() && latest_filter == std::prev(current_filter)->get()) {
latest_filter = current_filter->get();
if (std::distance(decoder_filters_.begin(), current_filter->entry()) >
Copy link
Contributor

Choose a reason for hiding this comment

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

ok sorry I feel like I'm live blogging comments but did we need to rewrite this? we've still got iterators so I'd think it would be ok and I find prior syntax easier to read.
/wait-any

Copy link
Member Author

Choose a reason for hiding this comment

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

I will check this tomorrow to see if it's necessary. I think I rewrite it mainly because I don't want to use a reference to raw pointer. &*

@@ -919,7 +936,7 @@ FilterManager::commonEncodePrefix(ActiveStreamEncoderFilter* filter, bool end_st
state_.decoder_filter_chain_aborted_ = true;
}
}
return encoder_filters_.begin();
return encoder_filters_.rbegin();
Copy link
Contributor

Choose a reason for hiding this comment

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

ah yep, I missed that we inserted in order before and now we don't. IMO it's worth C++ comments either where the vectors are defined or where we get iterators to call out that's what's going on

Copy link
Contributor

@adisuissa adisuissa left a comment

Choose a reason for hiding this comment

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

Thanks! I think it makes sense to use a vector instead of a list, as filters aren't removed from the middle of the chain.

One high-level comment about the iteration order:
My personal preference is to have non-simple iterators (those that are changed and picked up in multiple places) use the simple begin()->end() forward iteration. IMHO it makes the code more readable, and one less thing to worry about when this code is modified. From big-O notation reversing the container first should also be an O(N).
Another option is to abstract over the iterators, so it will always look like this is a forward iterator, and the underlying abstraction will take care of the iteration direction.

template <class T>
void recordLatestDataFilter(const typename FilterList<T>::iterator current_filter,
T*& latest_filter, const FilterList<T>& filters) {
template <class Iterator, class Filter>
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems that the function's code requires a strict relationship between the types of Iterator and Filter. Can this be rewritten with a single template type?

Copy link
Member Author

Choose a reason for hiding this comment

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

sgtm.

@wbpcode
Copy link
Member Author

wbpcode commented Dec 17, 2024

My personal preference is to have non-simple iterators (those that are changed and picked up in multiple places) use the simple begin()->end() forward iteration. IMHO it makes the code more readable, and one less thing to worry about when this code is modified. From big-O notation reversing the container first should also be an O(N).
Another option is to abstract over the iterators, so it will always look like this is a forward iterator, and the underlying abstraction will take care of the iteration direction.

Thanks for this comment. It's pretty easy to reverse the vector first because the unique pointer is used. The reason I use the rbegin is because another long-term target is to avoid creating unique pointer of the filter but construct the filter in the vector directly. At that time, the reverse may bring lot of memory copy. (but no sure to that actually).

Another option is to abstract over the iterators, so it will always look like this is a forward iterator, and the underlying abstraction will take care of the iteration direction.

This sound reasonable to me.

Signed-off-by: wangbaiping(wbpcode) <[email protected]>
Signed-off-by: wangbaiping(wbpcode) <[email protected]>
@wbpcode
Copy link
Member Author

wbpcode commented Dec 17, 2024

cc @adisuissa is this what you want? Now, even the PR self is more cleaner.

Copy link
Contributor

@adisuissa adisuissa left a comment

Choose a reason for hiding this comment

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

Thanks, looks better IMHO.
Left a request for adding comments but otherwise LGTM.

source/common/http/filter_manager.h Show resolved Hide resolved
Iterator begin() { return entries.begin(); }
Iterator end() { return entries.end(); }

std::vector<ActiveStreamDecoderFilterPtr> entries;
Copy link
Contributor

Choose a reason for hiding this comment

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

not sure if the style guide states that it needs to end with _ or not.

Copy link
Member Author

Choose a reason for hiding this comment

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

it should be added according to our style. added it.

Signed-off-by: wangbaiping(wbpcode) <[email protected]>
@wbpcode
Copy link
Member Author

wbpcode commented Dec 18, 2024

I did nothing to quic.

Code coverage for source/common/quic is lower than limit of 93.4 (93.3)

Let'me merge main and try again.

@wbpcode
Copy link
Member Author

wbpcode commented Dec 18, 2024

retest

@wbpcode
Copy link
Member Author

wbpcode commented Dec 18, 2024

/retest

Copy link
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.

much more comfortable with this version, thanks for the update. LGTM modulo two little comment nits
/wait

source/common/http/filter_manager.h Outdated Show resolved Hide resolved
source/common/http/filter_manager.h Outdated Show resolved Hide resolved
@wbpcode
Copy link
Member Author

wbpcode commented Dec 19, 2024

much more comfortable with this version, thanks for the update. LGTM modulo two little comment nits /wait

That's why need code review! 😄

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