typename RouterInfo::RouteHandlePtr createCarbonLookasideRoute()

in mcrouter/routes/CarbonLookasideRoute.h [412:525]


typename RouterInfo::RouteHandlePtr createCarbonLookasideRoute(
    RouteHandleFactory<typename RouterInfo::RouteHandleIf>& factory,
    const folly::dynamic& json) {
  checkLogic(json.isObject(), "CarbonLookasideRoute is not an object");

  auto jChild = json.get_ptr("child");
  checkLogic(
      jChild != nullptr, "CarbonLookasideRoute: 'child' property is missing");

  auto child = factory.create(*jChild);
  checkLogic(
      child != nullptr,
      "CarbonLookasideRoute: cannot create route handle from 'child'");

  bool subSecTTL = false;
  if (auto jTtlUnit = json.get_ptr("ttl_unit_ms")) {
    checkLogic(
        jTtlUnit->isBool(),
        "CarbonLookasideRoute: 'ttl_unit_ms' is not a bool");
    if (jTtlUnit->getBool()) {
      subSecTTL = true;
    }
  }

  auto jTtl = json.get_ptr("ttl");
  checkLogic(
      jTtl != nullptr, "CarbonLookasideRoute: 'ttl' property is missing");
  checkLogic(jTtl->isInt(), "CarbonLookasideRoute: 'ttl' is not an integer");
  int32_t ttl = jTtl->getInt();

  if (subSecTTL) {
    checkLogic(
        ttl >= 10 && ttl < 1000 && (1000 % ttl == 0),
        "CarbonLookasideRoute: for sub-second ttl, you must use a number "
        "that is >= 10, < 1000, and 1000 must be a multiple of ttl.");
  }

  std::string prefix = ""; // Defaults to no prefix.
  if (auto jPrefix = json.get_ptr("prefix")) {
    checkLogic(
        jPrefix->isString(), "CarbonLookasideRoute: 'prefix' is not a string");
    prefix = jPrefix->getString();
  }

  std::string flavor = "web"; // Defaults to web flavor.
  if (auto jFlavor = json.get_ptr("flavor")) {
    checkLogic(
        jFlavor->isString(), "CarbonLookasideRoute: 'flavor' is not a string");
    flavor = jFlavor->getString();
  }

  std::unordered_map<std::string, std::string> flavorOverrides;
  if (json.get_ptr("flavor_overrides")) {
    checkLogic(
        parse_json_options(json, "flavor_overrides", flavorOverrides),
        "CarbonLookasideRoute: error parsing 'flavor_overrides'");
  }

  size_t keySplitSize = 1;
  if (auto jKeySplitSize = json.get_ptr("key_split_size")) {
    checkLogic(
        jKeySplitSize->isInt() && jKeySplitSize->getInt() > 0,
        "CarbonLookasideRoute: 'key_split_size' must be a positive integer");
    keySplitSize = jKeySplitSize->getInt();
  }

  LeaseSettings leaseSettings = parseLeaseSettings(json);

  auto helperConfig = json.get_ptr("helper_config");
  if (helperConfig) {
    checkLogic(
        helperConfig->isObject(),
        "CarbonLookasideRoute: 'helper_config' is not an object");
  }
  CarbonLookasideHelper helper(helperConfig);

  // Creates a McRouter client to communicate with memcache using the
  // specified flavor information. The route handle owns the router resource
  // via a shared_ptr. The router will survive reconfigurations given that
  // at least one route handle will maintain a reference to it at any one time.
  // It will be cleaned up automatically whenever the last route handle using it
  // is removed.
  auto persistenceId = folly::to<std::string>("CarbonLookasideClient:", flavor);
  auto router =
      createCarbonLookasideRouter(persistenceId, flavor, flavorOverrides);
  if (!router) {
    LOG(ERROR) << "Failed to create router from flavor '" << flavor
               << "' for CarbonLookasideRouter.";
    return child;
  }

  CarbonRouterClient<MemcacheRouterInfo>::Pointer client{nullptr};
  try {
    client = router->createClient(0 /* max_outstanding_requests */);
  } catch (const std::runtime_error& e) {
    LOG(ERROR)
        << "Failed to create client for CarbonLookasideRouter. Exception: "
        << e.what();
    return child;
  }
  return makeRouteHandleWithInfo<
      RouterInfo,
      CarbonLookasideRoute,
      CarbonLookasideHelper>(
      std::move(child),
      std::move(router),
      std::move(client),
      std::move(prefix),
      keySplitSize,
      ttl,
      subSecTTL,
      std::move(helper),
      std::move(leaseSettings));
}