bool AsyncLog::openFile()

in mcrouter/AsyncLog.cpp [60:209]


bool AsyncLog::openFile() {
  char path[PATH_MAX + 1];
  time_t now = time(nullptr);
  pid_t tid = syscall(SYS_gettid);
  struct tm date;
  struct stat st;

  if (file_ && now - spoolTime_ <= DEFAULT_ASYNCLOG_LIFETIME) {
    return true;
  }

  if (file_) {
    file_.reset();
  }

  localtime_r(&now, &date);
  char hour_path[PATH_MAX + 1];
  time_t hour_time = now - (now % 3600);
  if (snprintf(
          hour_path,
          PATH_MAX,
          "%s/%04d%02d%02dT%02d-%lld",
          options_.async_spool.c_str(),
          date.tm_year + 1900,
          date.tm_mon + 1,
          date.tm_mday,
          date.tm_hour,
          (long long)hour_time) > PATH_MAX) {
    hour_path[PATH_MAX] = '\0';
    MC_LOG_FAILURE(
        options_,
        failure::Category::kSystemError,
        "async log hourly spool path is too long: {}",
        hour_path);
    return false;
  }

  if (stat(hour_path, &st) != 0) {
    mode_t old_umask = umask(0);
    int ret = mkdir(hour_path, 0777);
    int mkdir_errno = 0;
    if (ret != 0) {
      mkdir_errno = errno;
    }
    if (old_umask != 0) {
      umask(old_umask);
    }
    /* EEXIST is possible due to a race. We don't care. */
    if (ret != 0 && mkdir_errno != EEXIST) {
      MC_LOG_FAILURE(
          options_,
          failure::Category::kSystemError,
          "couldn't create async log hour spool path: {}. Reason: {}",
          hour_path,
          folly::errnoStr(mkdir_errno));
      return false;
    }
  }

  if (snprintf(
          path,
          PATH_MAX,
          "%s/%04d%02d%02dT%02d%02d%02d-%lld-%s-%s-t%d-%p",
          hour_path,
          date.tm_year + 1900,
          date.tm_mon + 1,
          date.tm_mday,
          date.tm_hour,
          date.tm_min,
          date.tm_sec,
          (long long)now,
          options_.service_name.c_str(),
          options_.router_name.c_str(),
          tid,
          this) > PATH_MAX) {
    path[PATH_MAX] = '\0';
    MC_LOG_FAILURE(
        options_,
        failure::Category::kSystemError,
        "async log path is too long: {}",
        path);
    return false;
  }

  int fd = -1;
  /*
   * Just in case, append to the log if it exists
   */
  if (stat(path, &st) != 0) {
    fd = open(path, O_WRONLY | O_CREAT, 0666);
    if (fd < 0) {
      MC_LOG_FAILURE(
          options_,
          failure::Category::kSystemError,
          "Can't create and open async store {}: {}",
          path,
          folly::errnoStr(errno));
      return false;
    }
  } else {
    fd = open(path, O_WRONLY | O_APPEND, 0666);
    if (fd < 0) {
      MC_LOG_FAILURE(
          options_,
          failure::Category::kSystemError,
          "Can't re-open async store {}: {}",
          path,
          folly::errnoStr(errno));
      return false;
    }
  }

  if (fstat(fd, &st)) {
    MC_LOG_FAILURE(
        options_,
        failure::Category::kSystemError,
        "Can't stat async store {}: {}",
        path,
        folly::errnoStr(errno));
    closeFd(fd);
    return false;
  }
  if (!S_ISREG(st.st_mode)) {
    MC_LOG_FAILURE(
        options_,
        failure::Category::kSystemError,
        "Async store exists but is not a file: {}: {}",
        path,
        folly::errnoStr(errno));
    closeFd(fd);
    return false;
  }

  file_ = createFile(fd);
  if (!file_) {
    MC_LOG_FAILURE(
        options_,
        failure::Category::kSystemError,
        "Unable to allocate memory for file_: {}",
        folly::errnoStr(errno));
    closeFd(fd);
    return false;
  }

  spoolTime_ = now;

  VLOG(1) << "Opened async store for " << path;

  return true;
}