Ejemplo n.º 1
0
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;
    }
  }
}
Ejemplo n.º 2
0
bool McrouterLogger::start() {
  if (running_ || router_.opts().stats_logging_interval == 0) {
    return false;
  }

  if (!ensureDirExistsAndWritable(router_.opts().stats_root)) {
    LOG(ERROR) << "Can't create or chmod " << router_.opts().stats_root <<
                  ", disabling stats logging";
    return false;
  }

  auto path = stats_file_path(router_.opts(), kStatsStartupOptionsSfx);
  if (std::find(touchStatsFilepaths_.begin(), touchStatsFilepaths_.end(), path)
      == touchStatsFilepaths_.end()) {
    touchStatsFilepaths_.push_back(std::move(path));
  }

  running_ = true;
  const std::string threadName = "mcrtr-stats-logger";
  try {
    loggerThread_ = std::thread(
        std::bind(&McrouterLogger::loggerThreadRun, this));
    folly::setThreadName(loggerThread_.native_handle(), threadName);
  } catch (const std::system_error& e) {
    running_ = false;
    MC_LOG_FAILURE(router_.opts(), memcache::failure::Category::kSystemError,
                   "Can not start McrouterLogger thread {}: {}",
                   threadName, e.what());
  }

  return running_;
}
Ejemplo n.º 3
0
void ProxyDestinationMap::scheduleTimer(bool initialAttempt) {
  if (!resetTimer_->scheduleTimeout(inactivityTimeout_)) {
    MC_LOG_FAILURE(
        proxy_->router().opts(),
        memcache::failure::Category::kSystemError,
        "failed to {}schedule inactivity timer",
        initialAttempt ? "" : "re-");
  }
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
0
/** Adds an asynchronous request to the event log. */
void asynclog_delete(proxy_t* proxy,
                     const ProxyClientCommon& pclient,
                     folly::StringPiece key,
                     folly::StringPiece poolName) {
  dynamic json = {};
  const auto& host = pclient.ap->getHost();
  const auto& port = proxy->router().opts().asynclog_port_override == 0
    ? pclient.ap->getPort()
    : proxy->router().opts().asynclog_port_override;

  if (proxy->router().opts().use_asynclog_version2) {
    json = dynamic::object;
    json["f"] = proxy->router().opts().flavor_name;
    json["h"] = folly::sformat("[{}]:{}", host, port);
    json["p"] = poolName.str();
    json["k"] = key.str();
  } else {
    /* ["host", port, escaped_command] */
    json.push_back(host);
    json.push_back(port);
    json.push_back(folly::sformat("delete {}\r\n", key));
  }

  auto fd = asynclog_open(proxy);
  if (!fd) {
    MC_LOG_FAILURE(proxy->router().opts(),
                   memcache::failure::Category::kSystemError,
                   "asynclog_open() failed (key {}, pool {})",
                   key, poolName);
    return;
  }

  // ["AS1.0", 1289416829.836, "C", ["10.0.0.1", 11302, "delete foo\r\n"]]
  // OR ["AS2.0", 1289416829.836, "C", {"f":"flavor","h":"[10.0.0.1]:11302",
  //                                    "p":"pool_name","k":"foo\r\n"}]
  dynamic jsonOut = {};
  if (proxy->router().opts().use_asynclog_version2) {
    jsonOut.push_back(ASYNCLOG_MAGIC2);
  } else {
    jsonOut.push_back(ASYNCLOG_MAGIC);
  }

  struct timeval timestamp;
  CHECK(gettimeofday(&timestamp, nullptr) == 0);

  auto timestamp_ms =
    facebook::memcache::to<std::chrono::milliseconds>(timestamp).count();

  jsonOut.push_back(1e-3 * timestamp_ms);
  jsonOut.push_back(std::string("C"));

  jsonOut.push_back(json);

  auto jstr = folly::toJson(jsonOut) + "\n";

  ssize_t size = folly::writeFull(fd->fd(), jstr.data(), jstr.size());
  if (size == -1 || size_t(size) < jstr.size()) {
    MC_LOG_FAILURE(proxy->router().opts(),
                   memcache::failure::Category::kSystemError,
                   "Error fully writing asynclog request (key {}, pool {})",
                   key, poolName);
  }
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
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;
}