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

rds: split subscription out from RdsRouteConfigProviderImpl #3960

Merged
merged 6 commits into from
Jul 27, 2018

Conversation

lizan
Copy link
Member

@lizan lizan commented Jul 26, 2018

Signed-off-by: Lizan Zhou zlizan@google.com

Description:
RdsRouteConfigProviderImpl holds reference to FactoryContext (implemented by ListenerImpl), which could be freed after LDS update (#3953), this PR split subscription part out and make RdsRouteConfigProviderImpl 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

Signed-off-by: Lizan Zhou <zlizan@google.com>
@lizan
Copy link
Member Author

lizan commented Jul 26, 2018

Thanks to integration test added by @qiwzhang (#3955) and @PiotrSikora (#3957).

This PR is still WIP: need cleanup interface between RdsRouteConfig*, add comment for them, and tests in rds_impl_test. At least ads_integration_test passes with ASAN for now.

Let me know if you think this is a right approach. @htuch @mattklein123 @PiotrSikora @qiwzhang @mandarjog


Router::ConfigConstSharedPtr RdsRouteConfigProviderImpl::config() {
return tls_->getTyped<ThreadLocalConfig>().config_;
route_config_provider_manager_.route_config_subscriptions_.erase(manager_identifier_);
Copy link
Member

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.

Copy link
Contributor

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.

Copy link
Member Author

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.

@qiwzhang
Copy link
Contributor

@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.

@lizan
Copy link
Member Author

lizan commented Jul 26, 2018

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()) {
Copy link
Contributor

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);
Copy link
Contributor

@qiwzhang qiwzhang Jul 26, 2018

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);

Copy link
Member Author

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{
Copy link
Contributor

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?

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 will involving interface changes and make them consistent with StaticRouteConfigProviders, and update HttpConnectionManager too.

Copy link
Contributor

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;
Copy link
Contributor

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.

Copy link
Member Author

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_;
Copy link
Contributor

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.

Copy link
Member Author

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.

Copy link
Contributor

@qiwzhang qiwzhang Jul 26, 2018

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

Copy link
Member Author

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.


friend class RouteConfigProviderManagerImpl;
friend class RdsRouteConfigSubscription;
Copy link
Contributor

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?

Copy link
Member Author

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.

Copy link
Contributor

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.

@mattklein123
Copy link
Member

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!

@mattklein123 mattklein123 self-assigned this Jul 26, 2018
sendDiscoveryResponse<envoy::api::v2::RouteConfiguration>(
Config::TypeUrl::get().RouteConfiguration, {buildRouteConfig("route_config_0", "cluster_0")},
"2");
}
Copy link
Contributor

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");
}
Copy link
Contributor

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>
@lizan lizan changed the title [WIP] rds: split subscription out from RdsRouteConfigProviderImpl rds: split subscription out from RdsRouteConfigProviderImpl Jul 26, 2018
@qiwzhang
Copy link
Contributor

LGTM for the quick fix.

Maybe a follow up PR to do the follow clean up:

  1. use unique_ptr for Provider
  2. Try to cleanly separate Subscription class with ProviderImpl class.

@lizan
Copy link
Member Author

lizan commented Jul 26, 2018

@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.

@lizan lizan requested review from mattklein123 and htuch July 26, 2018 23:41
Copy link
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; nice find and fix to all involved.

Copy link
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 for fixing this.

@lizan lizan merged commit 280baee into envoyproxy:master Jul 27, 2018
@lizan lizan deleted the rds_crash branch July 27, 2018 04:37
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