ProxyConfig::ProxyConfig(proxy_t* proxy, const folly::dynamic& json, std::string configMd5Digest, std::shared_ptr<PoolFactory> poolFactory) : poolFactory_(std::move(poolFactory)), configMd5Digest_(std::move(configMd5Digest)) { McRouteHandleProvider provider(proxy, *proxy->destinationMap, *poolFactory_); RouteHandleFactory<McrouterRouteHandleIf> factory(provider); checkLogic(json.isObject(), "Config is not an object"); if (json.count("named_handles")) { checkLogic(json["named_handles"].isArray(), "named_handles is not array"); for (const auto& it : json["named_handles"]) { factory.create(it); } } RouteSelectorMap routeSelectors; auto jRoute = json.get_ptr("route"); auto jRoutes = json.get_ptr("routes"); checkLogic(!jRoute || !jRoutes, "Invalid config: both 'route' and 'routes' are specified"); checkLogic(jRoute || jRoutes, "No route/routes in config"); if (jRoute) { routeSelectors[proxy->getRouterOptions().default_route] = std::make_shared<PrefixSelectorRoute>(factory, *jRoute); } else { // jRoutes checkLogic(jRoutes->isArray() || jRoutes->isObject(), "Config: routes is not array/object"); if (jRoutes->isArray()) { for (const auto& it : *jRoutes) { checkLogic(it.isObject(), "RoutePolicy is not an object"); auto jCurRoute = it.get_ptr("route"); auto jAliases = it.get_ptr("aliases"); checkLogic(jCurRoute, "RoutePolicy: no route"); checkLogic(jAliases, "RoutePolicy: no aliases"); checkLogic(jAliases->isArray(), "RoutePolicy: aliases is not an array"); auto routeSelector = std::make_shared<PrefixSelectorRoute>(factory, *jCurRoute); for (const auto& alias : *jAliases) { checkLogic(alias.isString(), "RoutePolicy: alias is not a string"); routeSelectors[alias.stringPiece()] = routeSelector; } } } else { // object for (const auto& it : jRoutes->items()) { checkLogic(it.first.isString(), "RoutePolicy: alias is not a string"); routeSelectors[it.first.stringPiece()] = std::make_shared<PrefixSelectorRoute>(factory, it.second); } } } asyncLogRoutes_ = provider.releaseAsyncLogRoutes(); proxyRoute_ = std::make_shared<ProxyRoute>(proxy, routeSelectors); serviceInfo_ = std::make_shared<ServiceInfo>(proxy, *this); }
McrouterRouteHandlePtr makeErrorRoute( RouteHandleFactory<McrouterRouteHandleIf>& factory, const folly::dynamic& json) { checkLogic(json.isObject() || json.isString() || json.isNull(), "ErrorRoute: should be string or object"); std::string response; if (json.isString()) { response = json.stringPiece().str(); } else if (json.isObject()) { if (auto jResponse = json.get_ptr("response")) { checkLogic(jResponse->isString(), "ErrorRoute: response is not a string"); response = jResponse->stringPiece().str(); } } return makeErrorRoute(std::move(response)); }
McrouterRouteHandlePtr makeHashRoute( const folly::dynamic& json, std::vector<McrouterRouteHandlePtr> rh, size_t threadId) { std::string salt; folly::StringPiece funcType = Ch3HashFunc::type(); if (json.isObject()) { if (auto jsalt = json.get_ptr("salt")) { checkLogic(jsalt->isString(), "HashRoute: salt is not a string"); salt = jsalt->getString(); } if (auto jhashFunc = json.get_ptr("hash_func")) { checkLogic(jhashFunc->isString(), "HashRoute: hash_func is not a string"); funcType = jhashFunc->stringPiece(); } } if (funcType == Ch3HashFunc::type()) { return makeHashRouteCh3(std::move(rh), std::move(salt)); } else if (funcType == Crc32HashFunc::type()) { return makeHashRouteCrc32(std::move(rh), std::move(salt)); } else if (funcType == WeightedCh3HashFunc::type()) { WeightedCh3HashFunc func{json, rh.size()}; return makeHashRouteWeightedCh3(std::move(rh), std::move(salt), std::move(func)); } else if (funcType == ConstShardHashFunc::type()) { return makeHashRouteConstShard(std::move(rh), std::move(salt)); } else if (funcType == "Latest") { return makeLatestRoute(json, std::move(rh), threadId); } throwLogic("Unknown hash function: {}", funcType); }
FailoverWithExptimeRoute::FailoverWithExptimeRoute( RouteHandleFactory<McrouterRouteHandleIf>& factory, const folly::dynamic& json) : failoverExptime_(60) { checkLogic(json.isObject(), "FailoverWithExptimeRoute is not object"); std::vector<McrouterRouteHandlePtr> failoverTargets; if (json.count("failover")) { failoverTargets = factory.createList(json["failover"]); } failover_ = FailoverRoute<McrouterRouteHandleIf>(std::move(failoverTargets)); if (json.count("normal")) { normal_ = factory.create(json["normal"]); } if (json.count("failover_exptime")) { checkLogic(json["failover_exptime"].isInt(), "failover_exptime is not integer"); failoverExptime_ = json["failover_exptime"].asInt(); } if (json.count("settings")) { settings_ = FailoverWithExptimeSettings(json["settings"]); } }
McrouterRouteHandlePtr makeFailoverWithExptimeRoute( RouteHandleFactory<McrouterRouteHandleIf>& factory, const folly::dynamic& json) { checkLogic(json.isObject(), "FailoverWithExptimeRoute is not an object"); auto jnormal = json.get_ptr("normal"); checkLogic(jnormal, "FailoverWithExptimeRoute: normal not found"); auto normal = factory.create(*jnormal); int32_t failoverExptime = 60; if (auto jexptime = json.get_ptr("failover_exptime")) { checkLogic(jexptime->isInt(), "FailoverWithExptimeRoute: " "failover_exptime is not an integer"); failoverExptime = jexptime->getInt(); } std::vector<McrouterRouteHandlePtr> failover; if (auto jfailover = json.get_ptr("failover")) { failover = factory.createList(*jfailover); } auto children = getFailoverChildren(std::move(normal), std::move(failover), failoverExptime); return makeFailoverRoute(json, std::move(children)); }
void PoolFactory::parseQos(std::string parentName, const folly::dynamic& jQos, uint64_t& qosClass, uint64_t& qosPath) { if (!jQos.isObject()) { MC_LOG_FAILURE(opts_, memcache::failure::Category::kInvalidConfig, "{}: qos must be an object.", parentName); return; } uint64_t prevClass = qosClass; if (auto jClass = jQos.get_ptr("class")) { if (jClass->isInt() && isQosClassValid(jClass->getInt())) { qosClass = jClass->getInt(); } else { MC_LOG_FAILURE(opts_, memcache::failure::Category::kInvalidConfig, "{}: qos.class must be an integer in the range [0, 4]", parentName); } } if (auto jPath = jQos.get_ptr("path")) { if (jPath->isInt() && isQosPathValid(jPath->getInt())) { qosPath = jPath->getInt(); } else { MC_LOG_FAILURE(opts_, memcache::failure::Category::kInvalidConfig, "{}: qos.path must be an integer in the range [0, 3]", parentName); qosClass = prevClass; } } }
ShardSplitter::ShardSplitter(const folly::dynamic& json) { if (!json.isObject()) { return; } for (const auto& it : json.items()) { if (!it.second.isInt()) { LOG(ERROR) << "ShardSplitter: shard_splits value is not an int for " << it.first.asString(); continue; } auto splitCnt = it.second.asInt(); if (splitCnt <= 0) { LOG(ERROR) << "ShardSplitter: shard_splits value <= 0 '" << it.first.asString() << "': " << splitCnt; } else if (static_cast<size_t>(splitCnt) > kMaxSplits) { LOG(ERROR) << "ShardSplitter: shard_splits value > " << kMaxSplits << " '" << it.first.asString() << "': " << splitCnt; shardSplits_.emplace(it.first.c_str(), kMaxSplits); } else { shardSplits_.emplace(it.first.c_str(), splitCnt); } } }
std::vector<double> WeightedChHashFuncBase::parseWeights( const folly::dynamic& json, size_t n) { std::vector<double> weights; checkLogic( json.isObject() && json.count("weights"), "WeightedChHashFunc: not an object or no weights"); checkLogic( json["weights"].isArray(), "WeightedChHashFunc: weights is not array"); const auto& jWeights = json["weights"]; LOG_IF(ERROR, jWeights.size() < n) << "WeightedChHashFunc: CONFIG IS BROKEN!!! number of weights (" << jWeights.size() << ") is smaller than number of servers (" << n << "). Missing weights are set to 0.5"; for (size_t i = 0; i < std::min(n, jWeights.size()); ++i) { const auto& weight = jWeights[i]; checkLogic(weight.isNumber(), "WeightedChHashFunc: weight is not number"); const auto weightNum = weight.asDouble(); checkLogic( 0 <= weightNum && weightNum <= 1.0, "WeightedChHashFunc: weight must be in range [0, 1.0]"); weights.push_back(weightNum); } weights.resize(n, 0.5); return weights; }
McrouterRouteHandlePtr makeFailoverWithExptimeRoute( RouteHandleFactory<McrouterRouteHandleIf>& factory, const folly::dynamic& json) { checkLogic(json.isObject(), "FailoverWithExptimeRoute is not an object"); McrouterRouteHandlePtr normal; if (auto jnormal = json.get_ptr("normal")) { normal = factory.create(*jnormal); } std::vector<McrouterRouteHandlePtr> failoverTargets; if (auto jfailover = json.get_ptr("failover")) { failoverTargets = factory.createList(*jfailover); } int32_t failoverExptime = 60; if (auto jexptime = json.get_ptr("failover_exptime")) { checkLogic(jexptime->isInt(), "FailoverWithExptimeRoute: " "failover_exptime is not an integer"); failoverExptime = jexptime->getInt(); } // Check if only one format is being used checkLogic(!(json.count("settings") && // old (json.count("failover_errors") || json.count("failover_tag"))), // new "Use either 'settings' (old format) or 'failover_errors' / 'failover_tag'" ); // new format FailoverErrorsSettings failoverErrors; bool failoverTagging = false; if (auto jfailoverTag = json.get_ptr("failover_tag")) { checkLogic(jfailoverTag->isBool(), "FailoverWithExptime: failover_tag is not bool"); failoverTagging = jfailoverTag->getBool(); } if (auto jfailoverErrors = json.get_ptr("failover_errors")) { failoverErrors = FailoverErrorsSettings(*jfailoverErrors); } // old format if (auto jsettings = json.get_ptr("settings")) { VLOG(1) << "FailoverWithExptime: This config format is deprecated. " "Use 'failover_errors' instead of 'settings'."; auto oldSettings = FailoverWithExptimeSettings(*jsettings); failoverTagging = oldSettings.failoverTagging; failoverErrors = oldSettings.getFailoverErrors(); } return makeFailoverWithExptimeRoute( std::move(normal), std::move(failoverTargets), failoverExptime, std::move(failoverErrors), failoverTagging); }
FailoverErrorsSettings::FailoverErrorsSettings(const folly::dynamic& json) { checkLogic(json.isObject() || json.isArray(), "Failover errors must be either an array or an object."); if (json.isObject()) { if (auto jsonGets = json.get_ptr("gets")) { gets_ = FailoverErrorsSettings::List(*jsonGets); } if (auto jsonUpdates = json.get_ptr("updates")) { updates_ = FailoverErrorsSettings::List(*jsonUpdates); } if (auto jsonDeletes = json.get_ptr("deletes")) { deletes_ = FailoverErrorsSettings::List(*jsonDeletes); } } else if (json.isArray()) { gets_ = FailoverErrorsSettings::List(json); updates_ = FailoverErrorsSettings::List(json); deletes_ = FailoverErrorsSettings::List(json); } }
McrouterRouteHandlePtr makeRateLimitRoute( RouteHandleFactory<McrouterRouteHandleIf>& factory, const folly::dynamic& json) { checkLogic(json.isObject(), "RateLimitRoute is not an object"); auto jtarget = json.get_ptr("target"); checkLogic(jtarget, "RateLimitRoute: target not found"); auto target = factory.create(*jtarget); auto jrates = json.get_ptr("rates"); checkLogic(jrates, "RateLimitRoute: rates not found"); return makeRateLimitRoute(std::move(target), RateLimiter(*jrates)); }
PoolFactory::PoolJson PoolFactory::parsePool(const folly::dynamic& json) { checkLogic(json.isString() || json.isObject(), "Pool should be a string (name of pool) or an object"); if (json.isString()) { return parseNamedPool(json.stringPiece()); } auto jname = json.get_ptr("name"); checkLogic(jname && jname->isString(), "Pool should have string 'name'"); pools_.emplace(jname->stringPiece(), std::make_pair(json, PoolState::NEW)); return parseNamedPool(jname->stringPiece()); }
fbstring phpSerialize(const folly::dynamic& d) { if (d.isNull()) { return "N;"; } if (d.isBool()) { return d.asBool() ? "b:1;" : "b:0;"; } if (d.isInt()) { return "i:" + d.asString() + ";"; } if (d.isDouble()) { return "d:" + d.asString() + ";"; } if (d.isString()) { auto str = d.asString(); return folly::to<fbstring>("s:", str.size(), ":\"", str, "\";"); } if (d.isArray()) { fbstring ret = folly::to<fbstring>("a:", d.size(), ":{"); int i = 0; for (auto &v : d) { ret += folly::to<fbstring>("i:", i, ";", phpSerialize(v)); } return ret + "};"; } if (d.isObject()) { fbstring ret = folly::to<fbstring>("a:", d.size(), ":{"); int nextindex = 0; for (auto &k : d.keys()) { if (k.isNull()) { ret += "i:0;"; if (nextindex <= 0) { nextindex = 1; } } else if (k.isInt() || k.isDouble()) { int i = k.asInt(); ret += folly::to<fbstring>("i:", i, ";"); if (nextindex <= i) { nextindex = i + 1; } } else if (k.isString()) { ret += folly::to<fbstring>("s:", k.size(), ":\"", escapeCpp(k.asString()), "\";"); } else { /* Should never be reached, but cover it to be safe */ ret += folly::to<fbstring>("i:", nextindex++, ";"); } ret += phpSerialize(d[k]); } return ret + "};"; } throw std::logic_error("Unhandled dynamic type in php serialization"); return "N;"; }
PoolFactory::PoolFactory(const folly::dynamic& config, ConfigApiIf& configApi) : configApi_(configApi) { checkLogic(config.isObject(), "config is not an object"); if (auto jpools = config.get_ptr("pools")) { checkLogic(jpools->isObject(), "config: 'pools' is not an object"); for (const auto& it : jpools->items()) { pools_.emplace( it.first.stringPiece(), std::make_pair(it.second, PoolState::NEW)); } } }
std::shared_ptr<ClientPool> PoolFactory::parsePool(const folly::dynamic& json) { checkLogic(json.isString() || json.isObject(), "Pool should be a string (name of pool) or an object"); if (json.isString()) { return parsePool(json.stringPiece().str(), json); } else { auto name = json.get_ptr("name"); checkLogic(name && name->isString(), "Pool should have string 'name'"); return parsePool(name->stringPiece().str(), json); } }
McrouterRouteHandlePtr makeLatestRoute( RouteHandleFactory<McrouterRouteHandleIf>& factory, const folly::dynamic& json) { std::vector<McrouterRouteHandlePtr> children; if (json.isObject()) { if (auto jchildren = json.get_ptr("children")) { children = factory.createList(*jchildren); } } else { children = factory.createList(json); } return makeLatestRoute(json, std::move(children)); }
std::pair<std::shared_ptr<ClientPool>, std::vector<McrouterRouteHandlePtr>> McRouteHandleProvider::makePool(const folly::dynamic& json) { checkLogic(json.isString() || json.isObject(), "Pool should be a string (name of pool) or an object"); auto pool = poolFactory_.parsePool(json); std::vector<McrouterRouteHandlePtr> destinations; for (const auto& client : pool->getClients()) { auto pdstn = destinationMap_.fetch(*client); auto route = makeDestinationRoute(client, std::move(pdstn)); destinations.push_back(std::move(route)); } return std::make_pair(std::move(pool), std::move(destinations)); }
std::vector<McrouterRouteHandlePtr> makeShadowRoutes( RouteHandleFactory<McrouterRouteHandleIf>& factory, const folly::dynamic& json, proxy_t& proxy, ExtraRouteHandleProviderIf& extraProvider) { checkLogic(json.isObject(), "ShadowRoute should be an object"); const auto jchildren = json.get_ptr("children"); checkLogic(jchildren, "ShadowRoute: children not found"); auto children = factory.createList(*jchildren); if (json.count("shadows")) { children = makeShadowRoutes( factory, json, std::move(children), proxy, extraProvider); } return children; }
PoolFactory::PoolFactory(const folly::dynamic& config, ConfigApi& configApi, const McrouterOptions& opts) : configApi_(configApi), opts_(opts) { checkLogic(config.isObject(), "config is not an object"); if (auto jpools = config.get_ptr("pools")) { checkLogic(jpools->isObject(), "config: 'pools' is not an object"); for (const auto& it : jpools->items()) { parsePool(it.first.stringPiece().str(), it.second); } } }
WeightedCh3HashFunc::WeightedCh3HashFunc(const folly::dynamic& json, size_t n) { checkLogic(json.isObject() && json.count("weights"), "WeightedCh3HashFunc: not an object or no weights"); checkLogic(json["weights"].isArray(), "WeightedCh3HashFunc: weights is not array"); const auto& jWeights = json["weights"]; LOG_IF(ERROR, jWeights.size() < n) << "WeightedCh3HashFunc: CONFIG IS BROKEN!!! number of weights (" << jWeights.size() << ") is smaller than number of servers (" << n << "). Missing weights are set to 0.5"; for (size_t i = 0; i < std::min(n, jWeights.size()); ++i) { const auto& weight = jWeights[i]; checkLogic(weight.isNumber(), "WeightedCh3HashFunc: weight is not number"); weights_.push_back(weight.asDouble()); } weights_.resize(n, 0.5); }
ProxyConfig::ProxyConfig(proxy_t* proxy, const folly::dynamic& json, std::string configMd5Digest, std::shared_ptr<PoolFactory> poolFactory) : poolFactory_(std::move(poolFactory)), configMd5Digest_(std::move(configMd5Digest)) { McRouteHandleProvider provider(proxy, *proxy->destinationMap, *poolFactory_); RouteHandleFactory<McrouterRouteHandleIf> factory(provider); checkLogic(json.isObject(), "Config is not an object"); if (json.count("named_handles")) { checkLogic(json["named_handles"].isArray(), "named_handles is not array"); for (const auto& it : json["named_handles"]) { factory.create(it); } } checkLogic(!json.count("route") || !json.count("routes"), "Config ambiguous, has both route and routes"); RouteSelectorMap routeSelectors; if (json.count("route")) { addRouteSelector({ proxy->opts.default_route.str() }, json["route"], factory, routeSelectors); } else if (json.count("routes")) { checkLogic(json["routes"].isArray(), "Config: routes is not array"); for (const auto& it : json["routes"]) { checkLogic(it.isObject(), "RoutePolicy is not object"); checkLogic(it.count("route"), "RoutePolicy has no route"); checkLogic(it.count("aliases"), "RoutePolicy has no aliases"); const auto& aliases = it["aliases"]; checkLogic(aliases.isArray(), "RoutePolicy aliases is not array"); addRouteSelector(aliases, it["route"], factory, routeSelectors); } } else { throw std::logic_error("No route/routes in config"); } asyncLogRoutes_ = provider.releaseAsyncLogRoutes(); proxyRoute_ = std::make_shared<ProxyRoute>(proxy, routeSelectors); serviceInfo_ = std::make_shared<ServiceInfo>(proxy, *this); }
McrouterRouteHandlePtr makeLatestRoute( const folly::dynamic& json, std::vector<McrouterRouteHandlePtr> targets) { size_t failoverCount = 5; FailoverErrorsSettings failoverErrors; if (json.isObject()) { if (auto jfailoverCount = json.get_ptr("failover_count")) { checkLogic(jfailoverCount->isInt(), "LatestRoute: failover_count is not an integer"); failoverCount = jfailoverCount->getInt(); } if (auto jFailoverErrors = json.get_ptr("failover_errors")) { failoverErrors = FailoverErrorsSettings(*jFailoverErrors); } } return makeLatestRoute(std::move(targets), failoverCount, std::move(failoverErrors)); }
/** * @return target and asynclogName * Caller may call makeAsynclogRoute afterwards. */ std::pair<McrouterRouteHandlePtr, std::string> parseAsynclogRoute( RouteHandleFactory<McrouterRouteHandleIf>& factory, const folly::dynamic& json) { std::string asynclogName; McrouterRouteHandlePtr target; checkLogic(json.isObject() || json.isString(), "AsynclogRoute should be object or string"); if (json.isString()) { asynclogName = json.stringPiece().str(); target = factory.create(json); } else { // object auto jname = json.get_ptr("name"); checkLogic(jname && jname->isString(), "AsynclogRoute: required string name"); auto jtarget = json.get_ptr("target"); checkLogic(jtarget, "AsynclogRoute: target not found"); asynclogName = jname->stringPiece().str(); target = factory.create(*jtarget); } return { std::move(target), std::move(asynclogName) }; }
std::shared_ptr<ShadowSettings> ShadowSettings::create(const folly::dynamic& json, McrouterInstance& router) { auto result = std::shared_ptr<ShadowSettings>(new ShadowSettings()); try { checkLogic(json.isObject(), "json is not an object"); if (auto jKeyFractionRange = json.get_ptr("key_fraction_range")) { checkLogic(jKeyFractionRange->isArray(), "key_fraction_range is not an array"); auto ar = folly::convertTo<std::vector<double>>(*jKeyFractionRange); checkLogic(ar.size() == 2, "key_fraction_range size is not 2"); result->setKeyRange(ar[0], ar[1]); } if (auto jIndexRange = json.get_ptr("index_range")) { checkLogic(jIndexRange->isArray(), "index_range is not an array"); auto ar = folly::convertTo<std::vector<size_t>>(*jIndexRange); checkLogic(ar.size() == 2, "index_range size is not 2"); checkLogic(ar[0] <= ar[1], "index_range start > end"); result->startIndex_ = ar[0]; result->endIndex_ = ar[1]; } if (auto jKeyFractionRangeRv = json.get_ptr("key_fraction_range_rv")) { checkLogic(jKeyFractionRangeRv->isString(), "key_fraction_range_rv is not a string"); result->keyFractionRangeRv_ = jKeyFractionRangeRv->stringPiece().str(); } if (auto jValidateReplies = json.get_ptr("validate_replies")) { checkLogic(jValidateReplies->isBool(), "validate_replies is not a bool"); result->validateReplies_ = jValidateReplies->getBool(); } } catch (const std::logic_error& e) { MC_LOG_FAILURE(router.opts(), failure::Category::kInvalidConfig, "ShadowSettings: {}", e.what()); return nullptr; } result->registerOnUpdateCallback(router); return result; }
McrouterRouteHandlePtr makeOperationSelectorRoute( RouteHandleFactory<McrouterRouteHandleIf>& factory, const folly::dynamic& json) { if (!json.isObject()) { return factory.create(json); } McrouterRouteHandlePtr defaultPolicy; if (json.count("default_policy")) { defaultPolicy = factory.create(json["default_policy"]); } std::vector<McrouterRouteHandlePtr> operationPolicies{mc_nops}; if (auto jOpPolicies = json.get_ptr("operation_policies")) { checkLogic(jOpPolicies->isObject(), "OperationSelectorRoute: operation_policies is not an object"); std::map<std::string, const folly::dynamic*> orderedPolicies; for (auto& it : jOpPolicies->items()) { checkLogic(it.first.isString(), "OperationSelectorRoute: operation_policies' " "key is not a string"); auto key = it.first.stringPiece().str(); orderedPolicies.emplace(std::move(key), &it.second); } // order is important here: named handles may not be resolved if we parse // policies in random order for (const auto& it : orderedPolicies) { auto opId = mc_op_from_string(it.first.data()); checkLogic(opId != mc_op_unknown, "Unknown mc operation: {}", it.first); operationPolicies[opId] = factory.create(*it.second); } return makeOperationSelectorRoute(std::move(operationPolicies), std::move(defaultPolicy)); } return defaultPolicy; }
McrouterRouteHandlePtr makeFailoverRoute( const folly::dynamic& json, std::vector<McrouterRouteHandlePtr> children) { FailoverErrorsSettings failoverErrors; std::unique_ptr<FailoverRateLimiter> rateLimiter; bool failoverTagging = false; if (json.isObject()) { if (auto jFailoverErrors = json.get_ptr("failover_errors")) { failoverErrors = FailoverErrorsSettings(*jFailoverErrors); } if (auto jFailoverTag = json.get_ptr("failover_tag")) { checkLogic(jFailoverTag->isBool(), "Failover: failover_tag is not bool"); failoverTagging = jFailoverTag->getBool(); } if (auto jFailoverLimit = json.get_ptr("failover_limit")) { rateLimiter = folly::make_unique<FailoverRateLimiter>(*jFailoverLimit); } } return makeFailoverRoute(std::move(children), std::move(failoverErrors), std::move(rateLimiter), failoverTagging); }
RateLimiter::RateLimiter(const folly::dynamic& json) { checkLogic(json.isObject(), "RateLimiter settings json is not an object"); auto now = TokenBucket::defaultClockNow(); if (json.count("gets_rate")) { double rate = asPositiveDouble(json, "gets_rate"); double burst = asPositiveDoubleDefault(json, "gets_burst", rate); getsTb_ = TokenBucket(rate, burst, now); } if (json.count("sets_rate")) { double rate = asPositiveDouble(json, "sets_rate"); double burst = asPositiveDoubleDefault(json, "sets_burst", rate); setsTb_ = TokenBucket(rate, burst, now); } if (json.count("deletes_rate")) { double rate = asPositiveDouble(json, "deletes_rate"); double burst = asPositiveDoubleDefault(json, "deletes_burst", rate); deletesTb_ = TokenBucket(rate, burst, now); } }
// Infer type from an actual value, e.g. 123, "foo", null, true, etc... static DataType kindOfFromValue(const folly::dynamic& v) { if (v.isNull()) { return KindOfNull; } if (v.isBool()) { return KindOfBoolean; } if (v.isInt()) { return KindOfInt64; } if (v.isDouble()) { return KindOfDouble; } if (v.isString()) { return KindOfString; } if (v.isArray()) { return KindOfArray; } if (v.isObject()) { return KindOfObject; } return KindOfInvalid; }
OperationSelectorRoute::OperationSelectorRoute( RouteHandleFactory<McrouterRouteHandleIf>& factory, const folly::dynamic& json) { if (!json.isObject()) { defaultPolicy_ = factory.create(json); return; } if (json.count("default_policy")) { defaultPolicy_ = factory.create(json["default_policy"]); } operationPolicies_.resize(mc_nops); if (json.count("operation_policies")) { const auto& policies = json["operation_policies"]; checkLogic(policies.isObject(), "OperationSelectorRoute: operation_policies is not object"); std::map<std::string, folly::dynamic> orderedPolicies; for (const auto& it : policies.items()) { checkLogic(it.first.isString(), "OperationSelectorRoute: operation_policies " "key is not a string"); auto key = it.first.asString().toStdString(); orderedPolicies.insert({ key, it.second }); } // order is important here: named handles may not be resolved if we parse // policies in random order for (const auto& it : orderedPolicies) { auto opId = mc_op_from_string(it.first.data()); checkLogic(opId != mc_op_unknown, "Unknown mc operation: {}", it.first); operationPolicies_[opId] = factory.create(it.second); } } }
ProxyConfig::ProxyConfig(proxy_t& proxy, const folly::dynamic& json, std::string configMd5Digest, PoolFactory& poolFactory) : configMd5Digest_(std::move(configMd5Digest)) { McRouteHandleProvider provider(proxy, poolFactory); RouteHandleFactory<McrouterRouteHandleIf> factory(provider); checkLogic(json.isObject(), "Config is not an object"); if (auto jNamedHandles = json.get_ptr("named_handles")) { if (jNamedHandles->isArray()) { for (const auto& it : *jNamedHandles) { factory.create(it); } } else if (jNamedHandles->isObject()) { for (const auto& it : jNamedHandles->items()) { factory.addNamed(it.first.stringPiece(), it.second); } } else { throwLogic("named_handles is {} expected array/object", jNamedHandles->typeName()); } } RouteSelectorMap routeSelectors; auto jRoute = json.get_ptr("route"); auto jRoutes = json.get_ptr("routes"); checkLogic(!jRoute || !jRoutes, "Invalid config: both 'route' and 'routes' are specified"); if (jRoute) { routeSelectors[proxy.getRouterOptions().default_route] = std::make_shared<PrefixSelectorRoute>(factory, *jRoute); } else if (jRoutes) { // jRoutes checkLogic(jRoutes->isArray() || jRoutes->isObject(), "Config: routes is not array/object"); if (jRoutes->isArray()) { for (const auto& it : *jRoutes) { checkLogic(it.isObject(), "RoutePolicy is not an object"); auto jCurRoute = it.get_ptr("route"); auto jAliases = it.get_ptr("aliases"); checkLogic(jCurRoute, "RoutePolicy: no route"); checkLogic(jAliases, "RoutePolicy: no aliases"); checkLogic(jAliases->isArray(), "RoutePolicy: aliases is not an array"); auto routeSelector = std::make_shared<PrefixSelectorRoute>(factory, *jCurRoute); for (const auto& alias : *jAliases) { checkLogic(alias.isString(), "RoutePolicy: alias is not a string"); routeSelectors[alias.stringPiece()] = routeSelector; } } } else { // object for (const auto& it : jRoutes->items()) { checkLogic(it.first.isString(), "RoutePolicy: alias is not a string"); routeSelectors[it.first.stringPiece()] = std::make_shared<PrefixSelectorRoute>(factory, it.second); } } } else { throwLogic("No route/routes in config"); } asyncLogRoutes_ = provider.releaseAsyncLogRoutes(); pools_ = provider.releasePools(); accessPoints_ = provider.releaseAccessPoints(); proxyRoute_ = std::make_shared<ProxyRoute>(&proxy, routeSelectors); serviceInfo_ = std::make_shared<ServiceInfo>(&proxy, *this); }