Ejemplo n.º 1
0
void CheckVersionFeature::validateOptions(
    std::shared_ptr<ProgramOptions> options) {
  if (!_checkVersion) {
    return;
  }

  ApplicationServer::forceDisableFeatures(_nonServerFeatures);

  LoggerFeature* logger =
      ApplicationServer::getFeature<LoggerFeature>("Logger");
  logger->disableThreaded();

  DatabaseFeature* databaseFeature =
      ApplicationServer::getFeature<DatabaseFeature>("Database");
  databaseFeature->disableReplicationApplier();
  databaseFeature->enableCheckVersion();

  V8DealerFeature* v8dealer =
      ApplicationServer::getFeature<V8DealerFeature>("V8Dealer");
  v8dealer->setNumberContexts(1);
}
Ejemplo n.º 2
0
void SupervisorFeature::daemonize() {
  static time_t const MIN_TIME_ALIVE_IN_SEC = 30;

  if (!_supervisor) {
    return;
  }

  time_t startTime = time(0);
  time_t t;
  bool done = false;
  int result = EXIT_SUCCESS;

  std::vector<ApplicationFeature*> supervisorFeatures(_supervisorStart.size());

  std::transform(_supervisorStart.begin(), _supervisorStart.end(),
                 supervisorFeatures.begin(), [](std::string const& name) {
                  try {
                    return ApplicationServer::getFeature<ApplicationFeature>(name);
                  } catch (...) { 
                    LOG_TOPIC(FATAL, Logger::STARTUP)
                        << "unknown feature '" << name << "', giving up";
                    FATAL_ERROR_EXIT();
                  }
                 });

  while (!done) {
    // fork of the server
    _clientPid = fork();

    if (_clientPid < 0) {
      LOG_TOPIC(FATAL, Logger::STARTUP) << "fork failed, giving up";
      FATAL_ERROR_EXIT();
    }

    // parent (supervisor)
    if (0 < _clientPid) {
      TRI_SetProcessTitle("arangodb [supervisor]");

      std::for_each(supervisorFeatures.begin(), supervisorFeatures.end(),
                    [](ApplicationFeature* feature) {
                      LoggerFeature* logger =
                          dynamic_cast<LoggerFeature*>(feature);

                      if (logger != nullptr) {
                        logger->setSupervisor(true);
                        logger->disableThreaded();
                      }
                    });

      std::for_each(supervisorFeatures.begin(), supervisorFeatures.end(),
                    [](ApplicationFeature* feature) { feature->prepare(); });

      std::for_each(supervisorFeatures.begin(), supervisorFeatures.end(),
                    [](ApplicationFeature* feature) { feature->start(); });

      LOG_TOPIC(DEBUG, Logger::STARTUP) << "supervisor mode: within parent";

      ArangoGlobalContext::CONTEXT->unmaskStandardSignals();
      signal(SIGINT, StopHandler);
      signal(SIGTERM, StopHandler);

      CLIENT_PID = _clientPid;
      DONE = false;

      int status;
      int res = waitpid(_clientPid, &status, 0);
      bool horrible = true;

      if (!DONE) {
        done = true;
        horrible = false;
      }
      else {
        LOG_TOPIC(DEBUG, Logger::STARTUP) << "waitpid woke up with return value "
                                          << res << " and status " << status;

        if (WIFEXITED(status)) {
          // give information about cause of death
          if (WEXITSTATUS(status) == 0) {
            LOG_TOPIC(INFO, Logger::STARTUP) << "child " << _clientPid
                                             << " died of natural causes";
            done = true;
            horrible = false;
          } else {
            t = time(0) - startTime;

            LOG_TOPIC(ERR, Logger::STARTUP)
                << "child " << _clientPid
                << " died a horrible death, exit status " << WEXITSTATUS(status);

            if (t < MIN_TIME_ALIVE_IN_SEC) {
              LOG_TOPIC(ERR, Logger::STARTUP)
                  << "child only survived for " << t
                  << " seconds, this will not work - please fix the error "
                     "first";
              done = true;
            } else {
              done = false;
            }
          }
        } else if (WIFSIGNALED(status)) {
          switch (WTERMSIG(status)) {
            case 2:
            case 9:
            case 15:
              LOG_TOPIC(INFO, Logger::STARTUP)
                  << "child " << _clientPid
                  << " died of natural causes, exit status " << WTERMSIG(status);
              done = true;
              horrible = false;
              break;

            default:
              t = time(0) - startTime;

              LOG_TOPIC(ERR, Logger::STARTUP) << "child " << _clientPid
                                              << " died a horrible death, signal "
                                              << WTERMSIG(status);

              if (t < MIN_TIME_ALIVE_IN_SEC) {
                LOG_TOPIC(ERR, Logger::STARTUP)
                    << "child only survived for " << t
                    << " seconds, this will not work - please fix the "
                       "error first";
                done = true;

#ifdef WCOREDUMP
                if (WCOREDUMP(status)) {
                  LOG_TOPIC(WARN, Logger::STARTUP) << "child process "
                                                   << _clientPid
                                                   << " produced a core dump";
                }
#endif
              } else {
                done = false;
              }

              break;
          }
        } else {
          LOG_TOPIC(ERR, Logger::STARTUP)
              << "child " << _clientPid
              << " died a horrible death, unknown cause";
          done = false;
        }
      }

      if (horrible) {
        result = EXIT_FAILURE;
      }
    }

    // child - run the normal boot sequence
    else {
      LOG_TOPIC(DEBUG, Logger::STARTUP) << "supervisor mode: within child";
      TRI_SetProcessTitle("arangodb [server]");

#ifdef TRI_HAVE_PRCTL
      // force child to stop if supervisor dies
      prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
#endif

      try {
        DaemonFeature* daemon = ApplicationServer::getFeature<DaemonFeature>("Daemon");

        // disable daemon mode
        daemon->setDaemon(false);
      } catch (...) {
      }

      return;
    }
  }

  std::for_each(supervisorFeatures.rbegin(), supervisorFeatures.rend(),
                [](ApplicationFeature* feature) { feature->stop(); });

  std::for_each(supervisorFeatures.rbegin(), supervisorFeatures.rend(),
                [](ApplicationFeature* feature) { feature->unprepare(); });

  exit(result);
}