Exemple #1
0
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;
}