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);
}
void TestClient::sendGet(std::string key, mc_res_t expectedResult,
                         uint32_t timeoutMs) {
  inflight_++;
  fm_.addTask([key, expectedResult, this, timeoutMs]() {
      auto msg = createMcMsgRef(key.c_str());
      msg->op = mc_op_get;
      McRequestWithMcOp<mc_op_get> req{std::move(msg)};
      try {
        auto reply = client_->sendSync(req,
                                       std::chrono::milliseconds(timeoutMs));
        if (reply.result() == mc_res_found) {
          auto value = getRange(reply.value());
          if (req.fullKey() == "empty") {
            checkLogic(reply.hasValue(), "Reply has no value");
            checkLogic(value.empty(), "Expected empty value, got {}", value);
          } else {
            checkLogic(value == req.fullKey(),
                       "Expected {}, got {}", req.fullKey(), value);
          }
        }
        checkLogic(expectedResult == reply.result(), "Expected {}, got {}",
                   mc_res_to_string(expectedResult),
                   mc_res_to_string(reply.result()));
      } catch (const std::exception& e) {
        CHECK(false) << "Failed: " << e.what();
      }
      inflight_--;
    });
}
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));
}
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"]);
  }
}
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;
}
Exemple #6
0
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);
}
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);
}
Exemple #8
0
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());
}
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));
}
Exemple #10
0
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);
  }
}
FailoverErrorsSettings::List::List(const folly::dynamic& json) {
  checkLogic(json.isArray(), "List of failover errors is not an array.");

  std::vector<std::string> errors;
  errors.reserve(json.size());
  for (const auto& elem : json) {
    checkLogic(elem.isString(), "Failover error {} is not a string", elem);
    errors.push_back(elem.getString());
  }

  init(std::move(errors));
}
Exemple #12
0
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));
    }
  }
}
Exemple #13
0
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);
    }
  }
}
Exemple #14
0
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;
}
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));
}
Exemple #16
0
void ShadowSettings::setKeyRange(double start, double end) {
  checkLogic(0 <= start && start <= end && end <= 1,
             "invalid key_fraction_range [{}, {}]", start, end);
  uint64_t keyStart = start * std::numeric_limits<uint32_t>::max();
  uint64_t keyEnd = end * std::numeric_limits<uint32_t>::max();
  keyRange_ = (keyStart << 32UL) | keyEnd;
}
size_t WeightedCh3HashFunc::operator()(folly::StringPiece key) const {
  auto n = weights_.size();
  checkLogic(n && n <= furc_maximum_pool_size(), "Invalid pool size: {}", n);
  size_t salt = 0;
  size_t index = 0;
  std::string saltedKey;
  auto originalKey = key;
  for (size_t i = 0; i < kNumTries; ++i) {
    index = furc_hash(key.data(), key.size(), n);

    /* Use 32-bit hash, but store in 64-bit ints so that
       we don't have to deal with overflows */
    uint64_t p = folly::hash::SpookyHashV2::Hash32(key.data(), key.size(),
                                                   kHashSeed);
    assert(0 <= weights_[index] && weights_[index] <= 1.0);
    uint64_t w = weights_[index] * std::numeric_limits<uint32_t>::max();

    /* Rehash only if p is out of range */
    if (LIKELY(p < w)) {
      return index;
    }

    /* Change the key to rehash */
    auto s = salt++;
    saltedKey = originalKey.str();
    do {
      saltedKey.push_back(char(s % 10) + '0');
      s /= 10;
    } while (s > 0);

    key = saltedKey;
  }

  return index;
}
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);
}
void DestinationClient::initializeAsyncMcClient() {
  FBI_ASSERT(proxy_->eventBase);

  auto pdstn = pdstn_.lock();
  assert(pdstn != nullptr);

  ConnectionOptions options(pdstn->accessPoint);
  options.noNetwork = proxy_->opts.no_network;
  options.tcpKeepAliveCount = proxy_->opts.keepalive_cnt;
  options.tcpKeepAliveIdle = proxy_->opts.keepalive_idle_s;
  options.tcpKeepAliveInterval = proxy_->opts.keepalive_interval_s;
  options.timeout = std::chrono::duration_cast<std::chrono::milliseconds>(
    std::chrono::seconds(pdstn->server_timeout.tv_sec) +
    std::chrono::microseconds(pdstn->server_timeout.tv_usec));
  if (proxy_->opts.enable_qos) {
    options.enableQoS = true;
    options.qos = pdstn->qos;
  }

  if (pdstn->use_ssl) {
    auto& opts = proxy_->opts;
    checkLogic(!opts.pem_cert_path.empty() &&
               !opts.pem_key_path.empty() &&
               !opts.pem_ca_path.empty(),
               "Some of ssl key paths are not set!");
    options.sslContextProvider = [&opts] {
      return getSSLContext(opts.pem_cert_path, opts.pem_key_path,
                           opts.pem_ca_path);
    };
  }

  asyncMcClient_ = folly::make_unique<AsyncMcClient>(*proxy_->eventBase,
                                                     std::move(options));

  auto pdstnWeakPtr = pdstn_;
  asyncMcClient_->setStatusCallbacks(
    [pdstnWeakPtr] () {
      auto pdstnPtr = pdstnWeakPtr.lock();
      if (!pdstnPtr) {
        return;
      }
      pdstnPtr->on_up();
    },
    [pdstnWeakPtr] (const apache::thrift::transport::TTransportException&) {
      auto pdstnPtr = pdstnWeakPtr.lock();
      if (!pdstnPtr) {
        return;
      }
      pdstnPtr->on_down();
    });

  if (proxy_->opts.target_max_inflight_requests > 0) {
    asyncMcClient_->setThrottle(proxy_->opts.target_max_inflight_requests,
                                proxy_->opts.target_max_pending_requests);
  }
}
Exemple #20
0
void ShadowSettings::registerOnUpdateCallback(McrouterInstance& router) {
  handle_ = router.rtVarsData().subscribeAndCall(
    [this](std::shared_ptr<const RuntimeVarsData> oldVars,
           std::shared_ptr<const RuntimeVarsData> newVars) {
      if (!newVars || keyFractionRangeRv_.empty()) {
        return;
      }
      auto val = newVars->getVariableByName(keyFractionRangeRv_);
      if (val != nullptr) {
        checkLogic(val.isArray(),
                   "runtime vars: {} is not an array", keyFractionRangeRv_);
        checkLogic(val.size() == 2,
                   "runtime vars: size of {} is not 2", keyFractionRangeRv_);
        checkLogic(val[0].isNumber(),
                   "runtime vars: {}#0 is not a number", keyFractionRangeRv_);
        checkLogic(val[1].isNumber(),
                   "runtime vars: {}#1 is not a number", keyFractionRangeRv_);
        setKeyRange(val[0].asDouble(), val[1].asDouble());
      }
    });
}
/**
 * @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) };
}
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;
}
Exemple #23
0
RouteHandleMap::RouteHandleMap(
  const RouteSelectorMap& routeSelectors,
  const RoutingPrefix& defaultRoute,
  bool sendInvalidRouteToDefault)
    : defaultRoute_(defaultRoute),
      sendInvalidRouteToDefault_(sendInvalidRouteToDefault) {

  checkLogic(routeSelectors.find(defaultRoute_) != routeSelectors.end(),
             "invalid default route: {}", defaultRoute_.str());

  RouteSelectorVector allRoutes;
  std::unordered_map<std::string, RouteSelectorVector> byRegion;
  std::unordered_map<std::string, RouteSelectorVector> byRoute;
  // add defaults first
  for (const auto& it : routeSelectors) {
    RoutingPrefix prefix(it.first);
    if (prefix.str() == defaultRoute_.str()) {
      allRoutes.push_back(it.second);
    }

    if (prefix.getRegion() == defaultRoute_.getRegion()) {
      byRegion[prefix.getRegion().str()].push_back(it.second);
    }
  }

  // then add rest
  for (const auto& it : routeSelectors) {
    RoutingPrefix prefix(it.first);
    if (prefix.str() != defaultRoute_.str()) {
      allRoutes.push_back(it.second);
    }

    if (prefix.getRegion() != defaultRoute_.getRegion()) {
      byRegion[prefix.getRegion().str()].push_back(it.second);
    }

    byRoute[it.first].push_back(it.second);
  }

  // create corresponding RoutePolicyMaps
  UniqueVectorMap uniqueVectors;
  allRoutes_ = makePolicyMap(uniqueVectors, allRoutes);
  for (const auto& it : byRegion) {
    byRegion_.emplace(it.first, makePolicyMap(uniqueVectors, it.second));
  }
  for (const auto& it : byRoute) {
    byRoute_.emplace(it.first, makePolicyMap(uniqueVectors, it.second));
  }

  assert(byRoute_.find(defaultRoute_) != byRoute_.end());
  defaultRouteMap_ = byRoute_[defaultRoute_];
}
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));
}
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);
    }
  }
}
Exemple #26
0
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);
}
Exemple #27
0
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));
}
Exemple #28
0
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;
}
void FailoverErrorsSettings::List::init(std::vector<std::string> errors) {
  failover_ = folly::make_unique<std::array<bool, mc_nres>>();

  for (const auto& error : errors) {
    int i;
    for (i = 0; i < mc_nres; ++i) {
      mc_res_t errorType = static_cast<mc_res_t>(i);
      folly::StringPiece errorName(mc_res_to_string(errorType));
      errorName.removePrefix("mc_res_");

      if (mc_res_is_err(errorType) && error == errorName) {
        (*failover_)[i] = true;
        break;
      }
    }

    checkLogic(i < mc_nres,
        "Failover error '{}' is not a valid error type.", error);
  }
}
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);
  }
}