in mcrouter/routes/ShardSelectionRouteFactory-inl.h [498:713]
typename RouterInfo::RouteHandlePtr createEagerShardSelectionShadowRoute(
RouteHandleFactory<typename RouterInfo::RouteHandleIf>& factory,
const folly::dynamic& json,
const ChildrenFactoryMap<RouterInfo>& childrenFactoryMap,
const ChildrenFactoryMap<RouterInfo>& shadowChildrenFactoryMap,
const folly::Optional<ShadowSelectorPolicy>& shadowSelectorPolicy,
const uint32_t seed) {
checkLogic(
json.isObject(),
"EagerShardSelectionShadowRoute config should be an object");
const auto childrenType = [&json]() {
auto jChildType = json.get_ptr("children_type");
checkLogic(
jChildType && jChildType->isString(),
"EagerShardSelectionShadowRoute: 'children_type' not found or is not a "
"string");
return jChildType->stringPiece();
}();
const auto& childrenSettings = [&json]() {
auto jSettings = json.get_ptr("children_settings");
checkLogic(
jSettings && jSettings->isObject(),
"EagerShardSelectionShadowRoute: 'children_settings' not found or not an "
"object");
return *jSettings;
}();
std::vector<typename RouterInfo::RouteHandlePtr> destinations;
auto shardMap = detail::getShardDestinationsMap<RouterInfo>(factory, json);
MapType shardToDestinationIndexMap = detail::prepareMap<MapType>(
shardMap.size(), detail::getMaxShardId(shardMap));
if (!shardMap.empty()) {
if (childrenType == "LoadBalancerRoute") {
detail::buildChildrenLoadBalancerRoutes<RouterInfo, MapType>(
factory,
childrenSettings,
shardMap,
destinations,
shardToDestinationIndexMap);
} else if (childrenType == "LatestRoute") {
detail::buildChildrenLatestRoutes<RouterInfo, MapType>(
factory,
childrenSettings,
shardMap,
destinations,
shardToDestinationIndexMap);
} else if (childrenType == "CustomJsonmRoute") {
detail::buildChildrenCustomJsonmRoutes<RouterInfo, MapType>(
factory,
childrenSettings,
shardMap,
destinations,
shardToDestinationIndexMap);
} else {
auto it = childrenFactoryMap.find(childrenType.str());
if (it != childrenFactoryMap.end()) {
detail::buildChildrenCustomRoutesFromMap<RouterInfo, MapType>(
factory,
childrenSettings,
shardMap,
it->second,
destinations,
shardToDestinationIndexMap);
} else {
throwLogic(
"EagerShardSelectionRoute: 'children_type' {} not supported",
childrenType);
}
}
}
// Out Of Range Destinations
typename RouterInfo::RouteHandlePtr outOfRangeDestination = nullptr;
if (auto outOfRangeJson = json.get_ptr("out_of_range")) {
outOfRangeDestination = factory.create(*outOfRangeJson);
}
// If shard map is empty, the selector will mark everything out_of_range
ShardSelector selector(std::move(shardToDestinationIndexMap));
/**
* Shadow settings
*/
// Shadow children type
const auto shadowChildrenType = [&json]() {
auto jChildType = json.get_ptr("shadow_children_type");
checkLogic(
jChildType && jChildType->isString(),
"EagerShardSelectionShadowRoute: 'shadow_children_type' not found or is not a "
"string");
return jChildType->stringPiece();
}();
// Shadow children settings
const auto& shadowChildrenSettings = [&json]() {
auto jSettings = json.get_ptr("shadow_children_settings");
checkLogic(
jSettings && jSettings->isObject(),
"EagerShardSelectionShadowRoute: 'shadow_children_settings' not found or not an "
"object");
return *jSettings;
}();
// Weight of hosts in shadow shard map. If > 1.0, hosts in shadow shard map
// will receive more shadow requests. If < 1.0, hosts in shadow shard map
// will receive less shadow requests.
double shadowWeights = 1.0;
if (auto jShadowWeights = json.get_ptr("shadow_weights")) {
checkLogic(jShadowWeights->isDouble(), "shadow_weights is not a double");
shadowWeights = jShadowWeights->asDouble();
}
constexpr folly::StringPiece shadowShardName = "shadow_shards";
if (detail::hasShardsJson<RouterInfo>(factory, json, shadowShardName) ==
false) {
// Shadow shards property is missing, create a regular selection route
return createSelectionRoute<RouterInfo, ShardSelector>(
std::move(destinations),
std::move(selector),
std::move(outOfRangeDestination));
}
// Create Shadow Shard Map
auto shadowShardMap = detail::getShardDestinationsMap<RouterInfo>(
factory, json, shadowShardName);
if (shadowShardMap.empty()) {
// Shard and Shadow Shard maps are empty, create error route.
if (shardMap.empty()) {
return mcrouter::createErrorRoute<RouterInfo>(
"EagerShardSelectionShadowRoute has an empty list of destinations");
} else {
// Shadow shards are empty, create a regular selection route
return createSelectionRoute<RouterInfo, ShardSelector>(
std::move(destinations),
std::move(selector),
std::move(outOfRangeDestination));
}
}
// Builds vector containing the probabilities
std::vector<uint16_t> shadowProbabilities;
detail::ShardDestinationsMapCustomFn<RouterInfo> probabilityBuilderFn =
[&shadowProbabilities, &shardMap, &shadowWeights](
uint32_t shardId,
std::vector<typename RouterInfo::RouteHandlePtr>&
childrenRouteHandles) {
auto it = shardMap.find(shardId);
size_t shardSize = 0;
if (it != shardMap.end()) {
// Implementation goes here
shardSize = it->second.size();
}
// Entries in vector are from (0,100] representing % of time that if
// selected by shadowSelector that request will be shadowed to child
// route handle.
uint16_t probability =
(((uint16_t)(100 * childrenRouteHandles.size() * shadowWeights)) /
(shardSize + childrenRouteHandles.size()));
shadowProbabilities.push_back(probability);
};
MapType shadowShardToDestinationIndexMap = detail::prepareMap<MapType>(
shadowShardMap.size(), detail::getMaxShardId(shadowShardMap));
std::vector<typename RouterInfo::RouteHandlePtr> shadowDestinations;
if (shadowChildrenType == "LoadBalancerRoute") {
detail::buildChildrenLoadBalancerRoutes<RouterInfo, MapType>(
factory,
shadowChildrenSettings,
shadowShardMap,
shadowDestinations,
shadowShardToDestinationIndexMap,
probabilityBuilderFn);
} else if (shadowChildrenType == "LatestRoute") {
detail::buildChildrenLatestRoutes<RouterInfo, MapType>(
factory,
shadowChildrenSettings,
shadowShardMap,
shadowDestinations,
shadowShardToDestinationIndexMap,
probabilityBuilderFn);
} else if (shadowChildrenType == "CustomJsonmRoute") {
throwLogic(
"EagerShardSelectionShadowRoute: {} not supported", shadowChildrenType);
} else {
auto it = shadowChildrenFactoryMap.find(shadowChildrenType.str());
if (it != shadowChildrenFactoryMap.end()) {
detail::buildChildrenCustomRoutesFromMap<RouterInfo, MapType>(
factory,
shadowChildrenSettings,
shadowShardMap,
it->second,
shadowDestinations,
shadowShardToDestinationIndexMap,
probabilityBuilderFn);
} else {
throwLogic(
"EagerShardSelectionRoute: 'shadow_children_type' {} not supported",
shadowChildrenType);
}
}
ShardSelector shadowSelector(std::move(shadowShardToDestinationIndexMap));
shadowProbabilities.shrink_to_fit();
return createSelectionRoute<RouterInfo, ShardSelector, ShadowSelectorPolicy>(
std::move(destinations),
std::move(selector),
std::move(outOfRangeDestination),
std::move(shadowDestinations),
std::move(shadowSelector),
std::move(shadowProbabilities),
std::move(shadowSelectorPolicy),
seed);
}