PoolFactory::PoolJson PoolFactory::parseNamedPool(folly::StringPiece name) { auto existingIt = pools_.find(name); if (existingIt == pools_.end()) { // get the pool from ConfigApi std::string jsonStr; checkLogic(configApi_.get(ConfigType::Pool, name.str(), jsonStr), "Can not read pool: {}", name); existingIt = pools_.emplace( name, std::make_pair(parseJsonString(jsonStr), PoolState::PARSED) ).first; return PoolJson(existingIt->first, existingIt->second.first); } name = existingIt->first; auto& json = existingIt->second.first; auto& state = existingIt->second.second; switch (state) { case PoolState::PARSED: return PoolJson(name, json); case PoolState::PARSING: throwLogic("Cycle in pool inheritance"); case PoolState::NEW: state = PoolState::PARSING; break; } if (auto jInherit = json.get_ptr("inherit")) { checkLogic(jInherit->isString(), "Pool {}: inherit is not a string", name); auto& newJson = parseNamedPool(jInherit->stringPiece()).json; json.update_missing(newJson); json.erase("inherit"); } state = PoolState::PARSED; return PoolJson(name, json); }
Entity* Parser::parseRight(const std::string & str, size_t & pos) { Entity* value = 0; if ( str[ pos ] == '{' ) { // next one is an object DEBUG("We read an object.") Object* obj = new Object; pos += 1; while( pos < str.size() && str[ pos ] != '}' ) { parseLeft( str, pos, obj ); ignoreChars( str, pos ); } DEBUG("We just finished to read an object ! ") pos += 1; // we're on the }, go to the next char value = obj; } else if ( str[ pos ] == '"' ) { // next one is a string DEBUG("We read a string") value = parseJsonString( str, pos ); } else if ( str[ pos ] == '[' ) { // next one is an array DEBUG("We read an array") Array* array = new Array; pos += 1; while( pos < str.size() && str[ pos ] != ']' ) { Entity* child = parseRight( str, pos ); if ( child ) array->push_back( child ); } DEBUG("We've finished to read our array.") pos += 1; // we're on the ], go to the next char value = array; } ignoreChars( str, pos ); return value; }
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; }