-
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
reduce number of srds update callbacks #12118
Conversation
Signed-off-by: chaoqinli <chaoqinli@google.com>
Signed-off-by: chaoqinli <chaoqinli@google.com>
Signed-off-by: chaoqinli <chaoqinli@google.com>
Signed-off-by: chaoqinli <chaoqinli@google.com>
Merge branch 'master' of https://github.com/envoyproxy/envoy into srds_update
Merge branch 'master' of https://github.com/envoyproxy/envoy into srds_update
@AndresGuedez could you take a pass at 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.
Thanks! Just a few comments.
scoped_route_info_by_key_.erase(iter->second->scopeKey().hash()); | ||
scoped_route_info_by_name_.erase(iter); | ||
void ScopedConfigImpl::removeRoutingScopes(const std::vector<std::string>& scope_names) { | ||
for (std::string const& scope_name : scope_names) { |
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.
nit: for consistency, I suggest using auto
here as well.
source/common/router/scoped_rds.cc
Outdated
thread_local_scoped_config->addOrUpdateRoutingScope(scoped_route_info); | ||
return config; | ||
}); | ||
updated_scopes.push_back(scoped_route_info); | ||
any_applied = true; | ||
ENVOY_LOG(debug, "srds: add/update scoped_route '{}', version: {}", |
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.
I suggest slightly changing the wording of this log message to clarify that the config has not yet been applied. e.g., "srds: queueing add/update of scoped_route ..."
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 makes sense, the changes are applied after the log.
any_applied = true; | ||
ENVOY_LOG(debug, "srds: add/update scoped_route '{}', version: {}", | ||
scoped_route_info->scopeName(), version_info); | ||
} catch (const EnvoyException& e) { | ||
exception_msgs.emplace_back(absl::StrCat("", e.what())); | ||
} | ||
} | ||
if (!updated_scopes.empty()) { |
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.
Note that this changes the logic such that partial application of an SRDS config update is no longer possible. For example, if there is a duplicate scoped route, all preceding routes would have been applied prior to this change.
I actually think the new behavior is preferable; I suggest adding a test to explicitly validate this logic.
FYI @stevenzzzz
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, currently the srds uses SotW. A test to validate that partial update is not accepted will be good.
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.
I think Andres is saying in delta XDS within a response handling, we could have a portion of the list applied, as the previous scope info is distributed to workers. We need to get this behavior tested.
I actually dont have a strong opinion of it, delta xDS cant send per-resource status back to management server anyway, so go ahead.
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.
Even for a regular SOTW config update, the existing logic could partially apply config since applyConfigUpdate()
is called inline for each scoped route distributed in the DiscoveryResponse
.
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.
for the SotW api, the two errors has been checked before the Delta interface is called.
Actually a good refactoring could be moving the verification code into a helper fuction. @chaoqin-li1123
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.
Good point, thanks Xin. This only applies to delta updates.
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.
So if the new change is applied, in delta api, partial updates is accepted in main thread when exception happens, but the partial updates are not applied to worker threads. We want the update to be fully rejected in both main thread and worker thread, right?
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.
Maybe we can store all the incoming scoped_route_config in a vector, pass the reference of this vector to a helper function to detect any scope key or scope name conflict. If there is any conflict, no change will be applied, otherwise all changes will be applied by creating corresponding RdsRouteConfigProviderHelper and push scope_route_info into the maps.
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.
A helper function has been added to detect key and scope name conflict.
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.
thanks
source/common/router/scoped_rds.cc
Outdated
thread_local_scoped_config->removeRoutingScope(scope_name); | ||
return config; | ||
}); | ||
removed_scope_names.push_back(scope_name); | ||
ENVOY_LOG(debug, "srds: remove scoped route '{}', version: {}", scope_name, version_info); |
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.
Same as prior comment, I suggest modifying the wording to clarify that the update has not yet been applied.
Signed-off-by: chaoqinli <chaoqinli@google.com>
Signed-off-by: chaoqinli <chaoqinli@google.com>
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.
looks good
source/common/router/scoped_rds.cc
Outdated
scoped_route_map_[scoped_route_info->scopeName()] = scoped_route_info; | ||
updated_scopes.push_back(scoped_route_info); | ||
any_applied = true; | ||
ENVOY_LOG(debug, "srds: add/update scoped_route '{}', version: {}", |
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.
out of date comment, follow Andres' suggestion here as well.
source/common/router/scoped_rds.cc
Outdated
} | ||
return any_applied; | ||
} | ||
} // namespace Router |
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.
remove?
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.
sure, I will remove it.
source/common/router/scoped_rds.cc
Outdated
// Do not delete RDS config providers just yet, in case the to be deleted RDS subscriptions could | ||
// be reused by some to be added scopes. | ||
std::list<ScopedRdsConfigSubscription::RdsRouteConfigProviderHelperPtr> | ||
to_be_removed_rds_providers = removeScopes(removed_resources, version_info); | ||
|
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.
extra blank lines
source/common/router/scoped_rds.cc
Outdated
@@ -137,64 +138,52 @@ ScopedRdsConfigSubscription::RdsRouteConfigProviderHelper::RdsRouteConfigProvide | |||
bool ScopedRdsConfigSubscription::addOrUpdateScopes( | |||
const std::vector<Envoy::Config::DecodedResourceRef>& resources, Init::Manager& init_manager, | |||
const std::string& version_info, std::vector<std::string>& exception_msgs) { | |||
ASSERT(exception_msgs.empty()); |
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 need to, this parameter is not used in this method now, remove 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.
yes, and we don't need any_applied anymore if addOrUpdateScopes() doesn't do validation.
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.
I think anyapplied is still required to give an signal to whether call the setLastConfigInfo method.
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
source/common/router/scoped_rds.cc
Outdated
} catch (const EnvoyException& e) { | ||
exception_msgs.emplace_back(absl::StrCat("", e.what())); | ||
} | ||
if (!exception_msgs.empty()) { |
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.
whynot throw in the above catch clause?
source/common/router/scoped_rds.cc
Outdated
// if new scope have key conflict with scope that is not going to be removed | ||
if (scope_name_by_hash_.find(key_fingerprint) != scope_name_by_hash_.end() && | ||
scope_name_by_hash_[key_fingerprint] != scope_name && | ||
removed_scopes.find(scope_name_by_hash_[key_fingerprint]) == removed_scopes.end()) { |
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.
use contains instead of comparing the iterator.
source/common/router/scoped_rds.cc
Outdated
@@ -330,17 +346,24 @@ void ScopedRdsConfigSubscription::onConfigUpdate( | |||
fmt::format("scope key conflict found, first scope is '{}', second scope is '{}'", | |||
scope_name_by_key_hash[key_fingerprint], scope_name)); | |||
} | |||
// if new scope have key conflict with scope that is not going to be removed | |||
if (scope_name_by_hash_.find(key_fingerprint) != scope_name_by_hash_.end() && |
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.
nit: using a iterator to avoid multiple look up.
} | ||
|
||
Protobuf::RepeatedPtrField<std::string> | ||
ScopedRdsConfigSubscription::detectUpdateConflictAndCleanupRemoved( |
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.
the order is problematic here:
lets say we have {h1:scope1, h2:scope2}, and the update is like {scope1:h2, scope2:h3}
the update will be rejected as the hash of new scope1 is conflicting the original scope2.
But you can see we should not reject that, this is not introduced by your change, but rather something we can improve, could you make this improvement?
also remember deletions are done ahead of add/updates, let's add a final-state hash, apply deletions first, apply ALL the add/updates, and then count the hash conflict.
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.
The update won't be rejected in this case.
There are 3 cases where update will be rejected:
In sotw api, when the incoming resources have key or scope name conflict.
In delta api, when the incoming resources have key or scope name conflict.
In delta api, when the incoming resources have key or scope name conflict with old scope that are not removed.
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.
In the new procedure, in an sotw update, we mark all old scopes as removed scopes from the beginning, and conflict key and scope name with removed scopes will be ignored.
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.
I am not following.
I think SotW and Delta form now uses the same verification logic.
There might be some confusion, but the case I was proposing is like "an incoming resource has a hash conflict with an existing scope, which will be updated by the same update but haven't yet".
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.
right, in Delta APi, this is still a probelm. I missed your last reply, sorry.
source/common/router/scoped_rds.cc
Outdated
// if new scope have key conflict with scope that is not going to be removed | ||
if (scope_name_by_hash_.find(key_fingerprint) != scope_name_by_hash_.end() && | ||
scope_name_by_hash_[key_fingerprint] != scope_name && | ||
removed_scopes.find(scope_name_by_hash_[key_fingerprint]) == removed_scopes.end()) { |
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.
for delta API, lets say previously it's {scope1:h1}, the update is ({scope2:h1, scope1:h2},removed={})
will the update gets rejected 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.
yes, it will gets rejected because scope2:h1 has key conflict with old scope with different name scope1:h1. This can be fixed easily though. Just marked all updated scopes as removed scope.
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.
Maybe I should add a unit test to cover this corner case?
please do.
…On Mon, Jul 20, 2020 at 12:30 PM chaoqin-li1123 ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In source/common/router/scoped_rds.cc
<#12118 (comment)>:
> @@ -330,17 +346,24 @@ void ScopedRdsConfigSubscription::onConfigUpdate(
fmt::format("scope key conflict found, first scope is '{}', second scope is '{}'",
scope_name_by_key_hash[key_fingerprint], scope_name));
}
+ // if new scope have key conflict with scope that is not going to be removed
+ if (scope_name_by_hash_.find(key_fingerprint) != scope_name_by_hash_.end() &&
+ scope_name_by_hash_[key_fingerprint] != scope_name &&
+ removed_scopes.find(scope_name_by_hash_[key_fingerprint]) == removed_scopes.end()) {
Maybe I should add a unit test to cover this corner case?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#12118 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AA2I6TFGZPWJAZL3X5XHAQTR4RWJLANCNFSM4O3AUKCA>
.
--
Xin Zhuang
|
Signed-off-by: chaoqinli <chaoqinli@google.com>
source/common/router/scoped_rds.cc
Outdated
Protobuf::RepeatedPtrField<std::string> clean_removed_resources; | ||
try { | ||
clean_removed_resources = | ||
detectUpdateConflictAndCleanupRemoved(added_resources, removed_resources); |
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.
I suggest avoiding the use of an exception to return the conflicting resources. It complicates the error handling logic for an event that is not really "exceptional" (i.e., this function is explicitly checking for that condition).
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.
Agree, I have changed the validation function to return normally instead of throwing an exception when detecting conflict.
->name(), | ||
"foo_routes"); | ||
// Scope key "x-foo-key" points to nowhere. | ||
EXPECT_NE(getScopedRdsProvider(), nullptr); |
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.
I suggest the more readable (IMO): ASSERT_THAT(getScopedRdsProvider(), Not(IsNull()))
instead.
Also, use ASSERT instead of EXPECT. Same below.
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.
Sounds good.
EXPECT_EQ(getScopedRouteMap().size(), 1UL); | ||
EXPECT_EQ(getScopedRouteMap().count("foo_scope"), 1); | ||
// Scope key "x-foo-key" points to nowhere. | ||
EXPECT_NE(getScopedRdsProvider(), nullptr); |
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.
Same as above, consider using ASSERT_THAT()
.
source/common/router/scoped_rds.cc
Outdated
// Do not delete RDS config providers just yet, in case the to be deleted RDS subscriptions could | ||
// be reused by some to be added scopes. | ||
std::list<ScopedRdsConfigSubscription::RdsRouteConfigProviderHelperPtr> | ||
to_be_removed_rds_providers = removeScopes(removed_resources, version_info); | ||
std::list<std::unique_ptr<ScopedRdsConfigSubscription::RdsRouteConfigProviderHelper>> |
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.
unintentional?
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.
fixed
Signed-off-by: chaoqinli <chaoqinli@google.com>
Signed-off-by: chaoqinli <chaoqinli@google.com>
Signed-off-by: chaoqinli <chaoqinli@google.com>
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.
Thanks for all the cleanup!
source/common/router/scoped_rds.cc
Outdated
std::vector<std::string> exception_msgs; | ||
std::string exception_msg; | ||
Protobuf::RepeatedPtrField<std::string> clean_removed_resources; | ||
detectUpdateConflictAndCleanupRemoved(added_resources, removed_resources, clean_removed_resources, |
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.
nit: it's generally preferable for readability to use a return arg as opposed to output parameters.
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.
Agreed, I have changed clean_removed_resources to be the explicitly returned value.
Signed-off-by: chaoqinli <chaoqinli@google.com>
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.
Thanks!
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.
fix the nits please
any_applied = true; | ||
ENVOY_LOG(debug, "srds: add/update scoped_route '{}', version: {}", | ||
scoped_route_info->scopeName(), version_info); | ||
} catch (const EnvoyException& e) { | ||
exception_msgs.emplace_back(absl::StrCat("", e.what())); | ||
} | ||
} | ||
if (!updated_scopes.empty()) { |
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.
thanks
source/common/router/scoped_rds.cc
Outdated
const std::vector<Envoy::Config::DecodedResourceRef>& resources, | ||
const Protobuf::RepeatedPtrField<std::string>& removed_resources, std::string& exception_msg) { | ||
Protobuf::RepeatedPtrField<std::string> clean_removed_resources; | ||
// all the scope names to be removed or updated. |
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.
nit capitalize
source/common/router/scoped_rds.cc
Outdated
} | ||
|
||
absl::flat_hash_map<uint64_t, std::string> scope_name_by_hash = scope_name_by_hash_; | ||
// don't check key conflict with scopes to be updated or removed |
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
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 comment is also confusing, I think we checked the conflict later in the for loops.
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.
We only check conflict with scopes that are not updated or removed. Maybe we can change the wording a little bit to make it less confusing?
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.
I think it's confusing as it says "we dont check conflict within the updated scopes."
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 about "Don't check key conflict with old scopes to be updated or removed."?
Signed-off-by: chaoqinli <chaoqinli@google.com>
5ab8734
/assign htuch |
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.
Thanks, this seems a good idea! A few minor bits of feedback.
/wait
source/common/router/scoped_rds.cc
Outdated
absl::flat_hash_map<uint64_t, std::string> scope_name_by_hash = scope_name_by_hash_; | ||
absl::erase_if(scope_name_by_hash, [&updated_or_removed_scopes](const auto& key_name) { | ||
auto const& [key, name] = key_name; | ||
return (updated_or_removed_scopes.contains(name)); |
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.
Nit: superfluous parens.
@@ -319,28 +340,27 @@ void ScopedRdsConfigSubscription::onConfigUpdate( | |||
const std::string& scope_name = scoped_route.name(); | |||
auto scope_config_inserted = scoped_routes.try_emplace(scope_name, std::move(scoped_route)); | |||
if (!scope_config_inserted.second) { | |||
throw EnvoyException( | |||
fmt::format("duplicate scoped route configuration '{}' found", scope_name)); | |||
exception_msg = fmt::format("duplicate scoped route configuration '{}' found", scope_name); |
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 are we no longer throwing and doing error-by-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.
Because Andres think it is not a good style to throw exception in a validation function. "I suggest avoiding the use of an exception to return the conflicting resources. It complicates the error handling logic for an event that is not really "exceptional" (i.e., this function is explicitly checking for that condition)."
std::vector<std::string> exception_msgs; | ||
std::string exception_msg; | ||
Protobuf::RepeatedPtrField<std::string> clean_removed_resources = | ||
detectUpdateConflictAndCleanupRemoved(added_resources, removed_resources, exception_msg); |
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.
Add comments.
onConfigUpdate(resources, to_remove_repeated, version_info); | ||
} | ||
|
||
Protobuf::RepeatedPtrField<std::string> |
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 you add some comment here explaining what this does? What kind of update conflict?
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.
Both scope name and scope key conflicts. The conflict can be between new scopes and old scopes, and it can also be between new scopes.
Signed-off-by: chaoqinli <chaoqinli@google.com>
Signed-off-by: chaoqinli <chaoqinli@google.com>
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!
Currently, in scope route discovery service, when resources are received from a management server, for each added, updated and removed scope route, a callback is fired. If several update callbacks are combined into a single update callback, less performance penalty will be incurred. This can be achieved by moving applyConfigUpdate out of the for loop and applying all the updates in a single callback. In this case, partial update won't be accepted both in sotw and delta srds. Scope key and scope name conflicts will be checked before any config update is applied. Risk Level: Low Testing: Modify a unit test related to change. Docs Changes: The behavior of delta srds will be changed, partial update won't be accepted. Signed-off-by: chaoqinli <chaoqinli@google.com> Signed-off-by: Kevin Baichoo <kbaichoo@google.com>
Currently, in scope route discovery service, when resources are received from a management server, for each added, updated and removed scope route, a callback is fired. If several update callbacks are combined into a single update callback, less performance penalty will be incurred. This can be achieved by moving applyConfigUpdate out of the for loop and applying all the updates in a single callback. In this case, partial update won't be accepted both in sotw and delta srds. Scope key and scope name conflicts will be checked before any config update is applied. Risk Level: Low Testing: Modify a unit test related to change. Docs Changes: The behavior of delta srds will be changed, partial update won't be accepted. Signed-off-by: chaoqinli <chaoqinli@google.com>
Commit Message:
Currently, in scope route discovery service, when resources are received from a management server, for each added, updated and removed scope route, a callback is fired. If several update callbacks are combined into a single update callback, less performance penalty will be incurred. This can be achieved by moving applyConfigUpdate out of the for loop and applying all the updates in a single callback. In this case, partial update won't be accepted both in sotw and delta srds. Scope key and scope name conflicts will be checked before any config update is applied.
Additional Description:
Risk Level: Low
Testing: Modify a unit test related to change.
Docs Changes: The behavior of delta srds will be changed, partial update won't be accepted.
Release Notes:
[Optional Runtime guard:]
[Optional Fixes #Issue]
[Optional Deprecated:]