-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
rds: split subscription out from RdsRouteConfigProviderImpl #3960
Conversation
Signed-off-by: Lizan Zhou <zlizan@google.com>
Thanks to integration test added by @qiwzhang (#3955) and @PiotrSikora (#3957). This PR is still WIP: need cleanup interface between Let me know if you think this is a right approach. @htuch @mattklein123 @PiotrSikora @qiwzhang @mandarjog |
source/common/router/rds_impl.cc
Outdated
|
||
Router::ConfigConstSharedPtr RdsRouteConfigProviderImpl::config() { | ||
return tls_->getTyped<ThreadLocalConfig>().config_; | ||
route_config_provider_manager_.route_config_subscriptions_.erase(manager_identifier_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how do you avoid the race here?
an updated lister's rdsrouteconfig object is being deleted and tries to tell the routeconfig manager that it should be removed..
At the same time, an RDS update arrives and the subscription manager is updating all the routeconfig objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is not race. ProviderImpl and RdsSubscription are separated. ProviderImpl is tightly associated with ListenerImpl, one per one. But RdsSubscription is shared, across ListenerImpl, the ones with different names, or old one with the new one with config change. A freed ProviderImpl will not free RdsSubscription if it is shared by others.
BTW, here provider_manager should be called subscripton_manager.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, here provider_manager should be called subscripton_manager.
provider_manager still manage providers (both static and rds), it doesn't own each rds provider but manages them through subscriptions.
@lizan I think this approach should work. This is the smallest change I can think of to fix this crash. BTW, provider should be changed to use unique_ptr instead of shared_ptr. |
I think eventually we will need to break FactoryContext into small pieces and locking them down, but for now this should be good. shared_ptr is used for a couple reasons (weak_ptr, config_dump), I will see if it can be unique_ptr as follow up. |
Signed-off-by: Lizan Zhou <zlizan@google.com>
Signed-off-by: Lizan Zhou <zlizan@google.com>
Signed-off-by: Lizan Zhou <zlizan@google.com>
Signed-off-by: Lizan Zhou <zlizan@google.com>
: subscription_(std::move(subscription)), factory_context_(factory_context), | ||
tls_(factory_context.threadLocal().allocateSlot()) { | ||
ConfigConstSharedPtr initial_config; | ||
if (subscription_->config_info_.has_value()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we define a getter function? not to use subscription member directly.
tls_->set([initial_config](Event::Dispatcher&) -> ThreadLocal::ThreadLocalObjectSharedPtr { | ||
return std::make_shared<ThreadLocalConfig>(initial_config); | ||
}); | ||
subscription_->route_config_providers_.insert(this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Subscription defines a OnUpdate interface, it only stores the interface pointers.
It should be
subscription_->add_update_callback(this);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No it won't work, you will need a pointer to RdsRouteConfigProviderImpl to implement std::vector<RouteConfigProviderSharedPtr> getRdsRouteConfigProviders()
in RouteConfigProviderManagerImpl
All the onUpdate is only used in rds_impl
and should not be used elsewhere, would rather keep this in private.
// of this code, locking the weak_ptr will not fail. | ||
Router::RouteConfigProviderSharedPtr new_provider = it->second.lock(); | ||
ASSERT(new_provider); | ||
Router::RouteConfigProviderSharedPtr new_provider{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be unique_ptr?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will involving interface changes and make them consistent with StaticRouteConfigProviders, and update HttpConnectionManager
too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO, it is important to use unique_ptr to show Provider object is not shared, only HttpConnectionManager owns it.
std::unordered_set<RdsRouteConfigProviderImpl*> route_config_providers_; | ||
|
||
friend class RouteConfigProviderManagerImpl; | ||
friend class RdsRouteConfigProviderImpl; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we not use friend class? define some getter functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the point of define more getter functions? No other classes should access them via getter than friend classes listed here.
SystemTime last_updated_; | ||
absl::optional<LastConfigInfo> config_info_; | ||
envoy::api::v2::RouteConfiguration route_config_proto_; | ||
std::unordered_set<RdsRouteConfigProviderImpl*> route_config_providers_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not to store the whole provider object, define OnUpdate interface, only store the interface pointers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto above, you need pointer to ProviderImpl to get shared_ptr of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what I mean:
class RdsSubscriptionCallback {
public:
virtual onConfigUpdate() PURE;
};
Here RdsConfigSubscription uses it as:
std::unordered_set<RdsSubscriptionCallback*> update_callbacks_;
ProviderImpl will also implement such Callback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I know what you meant, then you won't be able to do https://github.com/lizan/envoy/blob/6d433fef72eebc37b63acef63fd492cbbb9ff659/source/common/router/rds_impl.cc#L204 without dynamic_cast.
It doesn't make sense to make an interface which is completely implementation detail.
source/common/router/rds_impl.h
Outdated
|
||
friend class RouteConfigProviderManagerImpl; | ||
friend class RdsRouteConfigSubscription; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does Subscription need to access ProviderImpl private members?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mostly for for onConfigUpdate since no class other than Subscription should call it. will make it public and remove friend here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we use SubscriptionCallback interface, this friend class will not be needed.
Talked to @lizan offline. This approach/fix LGTM. Please let me know when the rest of the comments are finished and I can take a look. Thank you for fixing! |
sendDiscoveryResponse<envoy::api::v2::RouteConfiguration>( | ||
Config::TypeUrl::get().RouteConfiguration, {buildRouteConfig("route_config_0", "cluster_0")}, | ||
"2"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we make "makeSingleRequest()" call here
sendDiscoveryResponse<envoy::api::v2::RouteConfiguration>( | ||
Config::TypeUrl::get().RouteConfiguration, {buildRouteConfig("route_config_0", "cluster_1")}, | ||
"2"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we add "makeSingleRequest()" call here to make sure it works?
May have to wait for rds update success.
Signed-off-by: Lizan Zhou <zlizan@google.com>
LGTM for the quick fix. Maybe a follow up PR to do the follow clean up:
|
@mattklein123 and/or @htuch PTAL. @qiwzhang I'm looking at how large it will be to do unique_ptr, within or not in this PR. Though not convinced that we need to do 2. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM; nice find and fix to all involved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks for fixing this.
Signed-off-by: Lizan Zhou zlizan@google.com
Description:
RdsRouteConfigProviderImpl
holds reference toFactoryContext
(implemented byListenerImpl
), which could be freed after LDS update (#3953), this PR split subscription part out and makeRdsRouteConfigProviderImpl
owned by each Listener. The subscription class holds references to all live providers to provide RDS update.Risk Level: Low
Testing: unit test, integration test
Docs Changes:
Release Notes:
Fixes #3953