std::vector<McrouterRouteHandlePtr> makeShadowRoutes( RouteHandleFactory<McrouterRouteHandleIf>& factory, const folly::dynamic& json, std::vector<McrouterRouteHandlePtr> children, proxy_t& proxy, ExtraRouteHandleProviderIf& extraProvider) { folly::StringPiece shadowPolicy = "default"; if (auto jshadow_policy = json.get_ptr("shadow_policy")) { checkLogic(jshadow_policy->isString(), "ShadowRoute: shadow_policy is not a string"); shadowPolicy = jshadow_policy->stringPiece(); } auto jshadows = json.get_ptr("shadows"); checkLogic(jshadows, "ShadowRoute: route doesn't contain shadows field"); if (!jshadows->isArray()) { MC_LOG_FAILURE(proxy.router().opts(), failure::Category::kInvalidConfig, "ShadowRoute: shadows specified in route is not an array"); return children; } McrouterShadowData data; for (auto& shadow : *jshadows) { if (!shadow.isObject()) { MC_LOG_FAILURE(proxy.router().opts(), failure::Category::kInvalidConfig, "ShadowRoute: shadow is not an object"); continue; } auto jtarget = shadow.get_ptr("target"); if (!jtarget) { MC_LOG_FAILURE(proxy.router().opts(), failure::Category::kInvalidConfig, "ShadowRoute shadows: no target for shadow"); continue; } try { auto s = ShadowSettings::create(shadow, proxy.router()); if (s) { data.emplace_back(factory.create(*jtarget), std::move(s)); } } catch (const std::exception& e) { MC_LOG_FAILURE(proxy.router().opts(), failure::Category::kInvalidConfig, "Can not create shadow for ShadowRoute: {}", e.what()); } } for (size_t i = 0; i < children.size(); ++i) { McrouterShadowData childrenShadows; for (const auto& shadowData : data) { if (shadowData.second->startIndex() <= i && i < shadowData.second->endIndex()) { childrenShadows.push_back(shadowData); } } if (!childrenShadows.empty()) { childrenShadows.shrink_to_fit(); children[i] = extraProvider.makeShadow(proxy, std::move(children[i]), std::move(childrenShadows), shadowPolicy); } } return children; }
McrouterRouteHandlePtr McRouteHandleProvider::makePoolRoute( McRouteHandleFactory& factory, const folly::dynamic& json) { checkLogic(json.isObject() || json.isString(), "PoolRoute should be object or string"); const folly::dynamic* jpool; if (json.isObject()) { jpool = json.get_ptr("pool"); checkLogic(jpool, "PoolRoute: pool not found"); } else { jpool = &json; } auto p = makePool(*jpool); auto pool = std::move(p.first); auto destinations = std::move(p.second); if (json.isObject()) { if (auto maxOutstandingPtr = json.get_ptr("max_outstanding")) { checkLogic(maxOutstandingPtr->isInt(), "PoolRoute {}: max_outstanding is not int", pool->getName()); auto maxOutstanding = maxOutstandingPtr->asInt(); if (maxOutstanding) { for (auto& destination: destinations) { destination = makeOutstandingLimitRoute(std::move(destination), maxOutstanding); } } } } if (json.isObject() && json.count("shadows")) { folly::StringPiece shadowPolicy = "default"; if (auto jshadow_policy = json.get_ptr("shadow_policy")) { checkLogic(jshadow_policy->isString(), "PoolRoute: shadow_policy is not a string"); shadowPolicy = jshadow_policy->stringPiece(); } McrouterShadowData data; for (auto& shadow : json["shadows"]) { checkLogic(shadow.count("target"), "PoolRoute {} shadows: no target for shadow", pool->getName()); auto s = ShadowSettings::create(shadow, proxy_->router()); if (s) { data.emplace_back(factory.create(shadow["target"]), std::move(s)); } } for (size_t i = 0; i < destinations.size(); ++i) { McrouterShadowData destinationShadows; for (const auto& shadowData : data) { if (shadowData.second->startIndex() <= i && i < shadowData.second->endIndex()) { destinationShadows.push_back(shadowData); } } if (!destinationShadows.empty()) { destinationShadows.shrink_to_fit(); destinations[i] = extraProvider_->makeShadow( proxy_, std::move(destinations[i]), std::move(destinationShadows), shadowPolicy); } } } // add weights and override whatever we have in PoolRoute::hash folly::dynamic jhashWithWeights = folly::dynamic::object(); if (pool->getWeights()) { jhashWithWeights = folly::dynamic::object ("hash_func", WeightedCh3HashFunc::type()) ("weights", *pool->getWeights()); } if (json.isObject()) { if (auto jhash = json.get_ptr("hash")) { checkLogic(jhash->isObject() || jhash->isString(), "PoolRoute {}: hash is not object/string", pool->getName()); if (jhash->isString()) { jhashWithWeights["hash_func"] = *jhash; } else { // object for (const auto& it : jhash->items()) { jhashWithWeights[it.first] = it.second; } } } } auto route = makeHashRoute(jhashWithWeights, std::move(destinations)); if (json.isObject()) { if (proxy_->router().opts().destination_rate_limiting) { if (auto jrates = json.get_ptr("rates")) { route = makeRateLimitRoute(std::move(route), RateLimiter(*jrates)); } } if (auto jsplits = json.get_ptr("shard_splits")) { route = makeShardSplitRoute(std::move(route), ShardSplitter(*jsplits)); } } auto asynclogName = pool->getName(); bool needAsynclog = true; if (json.isObject()) { if (auto jasynclog = json.get_ptr("asynclog")) { checkLogic(jasynclog->isBool(), "PoolRoute: asynclog is not bool"); needAsynclog = jasynclog->getBool(); } if (auto jname = json.get_ptr("name")) { checkLogic(jname->isString(), "PoolRoute: name is not a string"); asynclogName = jname->stringPiece().str(); } } if (needAsynclog) { route = createAsynclogRoute(std::move(route), asynclogName); } return route; }