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()); }
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 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)); }
YGDisplay yogaStyleDisplayFromDynamic(const folly::dynamic &value) { assert(value.isString()); auto stringValue = value.asString(); if (stringValue == "flex") { return YGDisplayFlex; } if (stringValue == "none") { return YGDisplayNone; } abort(); }
YGPositionType yogaStylePositionTypeFromDynamic(const folly::dynamic &value) { assert(value.isString()); auto stringValue = value.asString(); if (stringValue == "relative") { return YGPositionTypeRelative; } if (stringValue == "absolute") { return YGPositionTypeAbsolute; } abort(); }
YGDirection yogaStyleDirectionFromDynamic(const folly::dynamic &value) { assert(value.isString()); auto stringValue = value.asString(); if (stringValue == "inherit") { return YGDirectionInherit; } if (stringValue == "ltr") { return YGDirectionLTR; } if (stringValue == "rtl") { return YGDirectionRTL; } abort(); }
YGOverflow yogaStyleOverflowFromDynamic(const folly::dynamic &value) { assert(value.isString()); auto stringValue = value.asString(); if (stringValue == "visible") { return YGOverflowVisible; } if (stringValue == "hidden") { return YGOverflowHidden; } if (stringValue == "scroll") { return YGOverflowScroll; } abort(); }
YGWrap yogaStyleWrapFromDynamic(const folly::dynamic &value) { assert(value.isString()); auto stringValue = value.asString(); if (stringValue == "no-wrap") { return YGWrapNoWrap; } if (stringValue == "wrap") { return YGWrapWrap; } if (stringValue == "wrap-reverse") { return YGWrapWrapReverse; } abort(); }
YGFlexDirection yogaStyleFlexDirectionFromDynamic(const folly::dynamic &value) { assert(value.isString()); auto stringValue = value.asString(); if (stringValue == "column") { return YGFlexDirectionColumn; } if (stringValue == "column-reverse") { return YGFlexDirectionColumnReverse; } if (stringValue == "row") { return YGFlexDirectionRow; } if (stringValue == "row-reverse") { return YGFlexDirectionRowReverse; } abort(); }
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;"; }
/** * @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) }; }
YGFloatOptional yogaStyleOptionalFloatFromDynamic(const folly::dynamic &value) { if (value.isNumber()) { return YGFloatOptional(value.asDouble()); } else if (value.isString()) { const auto stringValue = value.asString(); if (stringValue == "auto") { return YGFloatOptional(); } } abort(); }
YGJustify yogaStyleJustifyFromDynamic(const folly::dynamic &value) { assert(value.isString()); auto stringValue = value.asString(); if (stringValue == "flex-start") { return YGJustifyFlexStart; } if (stringValue == "center") { return YGJustifyCenter; } if (stringValue == "flex-end") { return YGJustifyFlexEnd; } if (stringValue == "space-between") { return YGJustifySpaceBetween; } if (stringValue == "space-around") { return YGJustifySpaceAround; } if (stringValue == "space-evenly") { return YGJustifySpaceEvenly; } abort(); }
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)); }
YGAlign yogaStyleAlignFromDynamic(const folly::dynamic &value) { assert(value.isString()); auto stringValue = value.asString(); if (stringValue == "auto") { return YGAlignAuto; } if (stringValue == "flex-start") { return YGAlignFlexStart; } if (stringValue == "center") { return YGAlignCenter; } if (stringValue == "flex-end") { return YGAlignFlexEnd; } if (stringValue == "stretch") { return YGAlignStretch; } if (stringValue == "baseline") { return YGAlignBaseline; } if (stringValue == "between") { return YGAlignSpaceBetween; } if (stringValue == "space-around") { return YGAlignSpaceAround; } abort(); }
fbstring typeString(const folly::dynamic& typeNode, bool isReturnType) { if (!typeNode.isString()) { return "void"; } auto typeIt = g_typeMap.find(typeNode.asString()); if (typeIt == g_typeMap.end()) { return (isReturnType ? "HPHP::Object" : "HPHP::Object const&"); } auto& type = typeIt->second; if (!isReturnType && isTypeCppIndirectPass(type)) { return type + " const&"; } else { return type; } }
// Parse type from a descriptive string, e.g. "int", "bool", etc... static DataType kindOfFromDynamic(const folly::dynamic& t) { if (!t.isString()) { return KindOfInvalid; } // If you hit this assert, the IDL contains "type": "Array"; you need to // use one of {Int64,String,Variant}{Vec,Map} instead. // // These are still KindOfArray, not the HH types. assert(t.asString() != "Array"); auto it = g_kindOfMap.find(t.asString()); if (it == g_kindOfMap.end()) { return KindOfObject; } return it->second; }
YGValue yogaStyleValueFromDynamic(const folly::dynamic &value) { if (value.isNumber()) { float x = value.asDouble(); return { x, YGUnitPoint }; } else if (value.isString()) { const auto stringValue = value.asString(); if (stringValue == "auto") { return { YGUndefined, YGUnitAuto }; } else { if (stringValue.back() == '%') { return { folly::to<float>(stringValue.substr(stringValue.length() - 1)), YGUnitPercent }; } else { return { folly::to<float>(stringValue), YGUnitPoint }; } } } return YGValueUndefined; }
// 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; }
std::shared_ptr<ClientPool> PoolFactory::parsePool(const std::string& name, const folly::dynamic& json) { auto seenPoolIt = pools_.find(name); if (seenPoolIt != pools_.end()) { return seenPoolIt->second; } if (json.isString()) { // get the pool from ConfigApi std::string jsonStr; checkLogic(configApi_.get(ConfigType::Pool, name, jsonStr), "Can not read pool: {}", name); return parsePool(name, parseJsonString(jsonStr)); } else { // one day we may add inheriting from local pool if (auto jinherit = json.get_ptr("inherit")) { checkLogic(jinherit->isString(), "Pool {}: inherit is not a string", name); auto path = jinherit->stringPiece().str(); std::string jsonStr; checkLogic(configApi_.get(ConfigType::Pool, path, jsonStr), "Can not read pool from: {}", path); auto newJson = parseJsonString(jsonStr); for (auto& it : json.items()) { newJson.insert(it.first, it.second); } newJson.erase("inherit"); return parsePool(name, newJson); } } // pool_locality std::chrono::milliseconds timeout{opts_.server_timeout_ms}; if (auto jlocality = json.get_ptr("pool_locality")) { if (!jlocality->isString()) { MC_LOG_FAILURE(opts_, memcache::failure::Category::kInvalidConfig, "Pool {}: pool_locality is not a string", name); } else { auto str = jlocality->stringPiece(); if (str == "cluster") { if (opts_.cluster_pools_timeout_ms != 0) { timeout = std::chrono::milliseconds(opts_.cluster_pools_timeout_ms); } } else if (str == "region") { if (opts_.regional_pools_timeout_ms != 0) { timeout = std::chrono::milliseconds(opts_.regional_pools_timeout_ms); } } else { MC_LOG_FAILURE(opts_, memcache::failure::Category::kInvalidConfig, "Pool {}: '{}' pool locality is not supported", name, str); } } } // region & cluster std::string region, cluster; if (auto jregion = json.get_ptr("region")) { if (!jregion->isString()) { MC_LOG_FAILURE(opts_, memcache::failure::Category::kInvalidConfig, "Pool {}: pool_region is not a string", name); } else { region = jregion->stringPiece().str(); } } if (auto jcluster = json.get_ptr("cluster")) { if (!jcluster->isString()) { MC_LOG_FAILURE(opts_, memcache::failure::Category::kInvalidConfig, "Pool {}: pool_cluster is not a string", name); } else { cluster = jcluster->stringPiece().str(); } } if (auto jtimeout = json.get_ptr("server_timeout")) { if (!jtimeout->isInt()) { MC_LOG_FAILURE(opts_, memcache::failure::Category::kInvalidConfig, "Pool {}: server_timeout is not an int", name); } else { timeout = std::chrono::milliseconds(jtimeout->getInt()); } } if (!region.empty() && !cluster.empty()) { auto& route = opts_.default_route; if (region == route.getRegion() && cluster == route.getCluster()) { if (opts_.within_cluster_timeout_ms != 0) { timeout = std::chrono::milliseconds(opts_.within_cluster_timeout_ms); } } else if (region == route.getRegion()) { if (opts_.cross_cluster_timeout_ms != 0) { timeout = std::chrono::milliseconds(opts_.cross_cluster_timeout_ms); } } else { if (opts_.cross_region_timeout_ms != 0) { timeout = std::chrono::milliseconds(opts_.cross_region_timeout_ms); } } } auto protocol = parseProtocol(json, mc_ascii_protocol); bool keep_routing_prefix = false; if (auto jkeep_routing_prefix = json.get_ptr("keep_routing_prefix")) { checkLogic(jkeep_routing_prefix->isBool(), "Pool {}: keep_routing_prefix is not a bool"); keep_routing_prefix = jkeep_routing_prefix->getBool(); } uint64_t qosClass = opts_.default_qos_class; uint64_t qosPath = opts_.default_qos_path; if (auto jqos = json.get_ptr("qos")) { parseQos(folly::sformat("Pool {}", name), *jqos, qosClass, qosPath); } bool useSsl = false; if (auto juseSsl = json.get_ptr("use_ssl")) { checkLogic(juseSsl->isBool(), "Pool {}: use_ssl is not a bool", name); useSsl = juseSsl->getBool(); } // servers auto jservers = json.get_ptr("servers"); checkLogic(jservers, "Pool {}: servers not found", name); checkLogic(jservers->isArray(), "Pool {}: servers is not an array", name); auto clientPool = std::make_shared<ClientPool>(name); for (size_t i = 0; i < jservers->size(); ++i) { const auto& server = jservers->at(i); std::shared_ptr<AccessPoint> ap; bool serverUseSsl = useSsl; uint64_t serverQosClass = qosClass; uint64_t serverQosPath = qosPath; checkLogic(server.isString() || server.isObject(), "Pool {}: server #{} is not a string/object", name, i); if (server.isString()) { // we support both host:port and host:port:protocol ap = AccessPoint::create(server.stringPiece(), protocol); checkLogic(ap != nullptr, "Pool {}: invalid server {}", name, server.stringPiece()); } else { // object auto jhostname = server.get_ptr("hostname"); checkLogic(jhostname, "Pool {}: hostname not found for server #{}", name, i); checkLogic(jhostname->isString(), "Pool {}: hostname is not a string for server #{}", name, i); if (auto jqos = server.get_ptr("qos")) { parseQos(folly::sformat("Pool {}, server #{}", name, i), *jqos, qosClass, qosPath); } if (auto juseSsl = server.get_ptr("use_ssl")) { checkLogic(juseSsl->isBool(), "Pool {}: use_ssl is not a bool for server #{}", name, i); serverUseSsl = juseSsl->getBool(); } ap = AccessPoint::create(jhostname->stringPiece(), parseProtocol(server, protocol)); checkLogic(ap != nullptr, "Pool {}: invalid server #{}", name, i); } auto client = clientPool->emplaceClient( timeout, std::move(ap), keep_routing_prefix, serverUseSsl, serverQosClass, serverQosPath); clients_.push_back(std::move(client)); } // servers // weights if (auto jweights = json.get_ptr("weights")) { clientPool->setWeights(*jweights); } pools_.emplace(name, clientPool); return clientPool; }
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; }
AccessibilityTraits accessibilityTraitsFromDynamic(const folly::dynamic &value) { assert(value.isString()); // FIXME: Not clear yet. abort(); }