1
0
Fork 0
arangodb/arangod/RestServer/FileDescriptorsFeature.cpp

174 lines
5.2 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////
#include "FileDescriptorsFeature.h"
#include "Logger/Logger.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
#include "Scheduler/SchedulerFeature.h"
#ifdef TRI_HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
using namespace arangodb::application_features;
using namespace arangodb::basics;
using namespace arangodb::options;
namespace arangodb {
uint64_t const FileDescriptorsFeature::RECOMMENDED = 8192;
FileDescriptorsFeature::FileDescriptorsFeature(application_features::ApplicationServer& server)
: ApplicationFeature(server, "FileDescriptors"), _descriptorsMinimum(0) {
setOptional(false);
startsAfter("GreetingsPhase");
}
void FileDescriptorsFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
#ifdef TRI_HAVE_GETRLIMIT
options->addSection("server", "Server features");
options->addOption("--server.descriptors-minimum",
"minimum number of file descriptors needed to start",
new UInt64Parameter(&_descriptorsMinimum));
#endif
}
void FileDescriptorsFeature::prepare() { adjustFileDescriptors(); }
#ifdef TRI_HAVE_GETRLIMIT
template <typename T>
static bool isUnlimited(T value) {
auto max = std::numeric_limits<decltype(value)>::max();
if (value == max || value == max / 2) {
return true;
}
return false;
}
template <typename T>
static std::string StringifyLimitValue(T value) {
if (isUnlimited(value)) {
return "unlimited";
}
return std::to_string(value);
}
#endif
void FileDescriptorsFeature::start() {
#ifdef TRI_HAVE_GETRLIMIT
struct rlimit rlim;
int res = getrlimit(RLIMIT_NOFILE, &rlim);
if (res == 0) {
LOG_TOPIC("a1c60", INFO, arangodb::Logger::SYSCALL)
<< "file-descriptors (nofiles) hard limit is "
<< StringifyLimitValue(rlim.rlim_max) << ", soft limit is "
<< StringifyLimitValue(rlim.rlim_cur);
}
if (rlim.rlim_cur < RECOMMENDED) {
LOG_TOPIC("8c771", WARN, arangodb::Logger::SYSCALL)
<< "file-descriptors limit is too low, currently "
<< StringifyLimitValue(rlim.rlim_cur) << ", please raise to at least "
<< RECOMMENDED << " (e.g. ulimit -n " << RECOMMENDED << ")";
}
#endif
}
void FileDescriptorsFeature::adjustFileDescriptors() {
#ifdef TRI_HAVE_GETRLIMIT
struct rlimit rlim;
int res = getrlimit(RLIMIT_NOFILE, &rlim);
if (res != 0) {
LOG_TOPIC("17d7b", FATAL, arangodb::Logger::SYSCALL)
<< "cannot get the file descriptor limit: " << strerror(errno);
FATAL_ERROR_EXIT();
}
LOG_TOPIC("6762c", DEBUG, arangodb::Logger::SYSCALL)
<< "file-descriptors (nofiles) hard limit is " << StringifyLimitValue(rlim.rlim_max)
<< ", soft limit is " << StringifyLimitValue(rlim.rlim_cur);
uint64_t recommended = RECOMMENDED;
uint64_t minimum = _descriptorsMinimum;
if (minimum < recommended && 0 < minimum) {
recommended = minimum;
}
if (rlim.rlim_max < recommended) {
LOG_TOPIC("0835c", DEBUG, arangodb::Logger::SYSCALL)
<< "hard limit " << rlim.rlim_max << " is too small, trying to raise";
rlim.rlim_max = recommended;
rlim.rlim_cur = recommended;
res = setrlimit(RLIMIT_NOFILE, &rlim);
if (0 < minimum && minimum < recommended && res < 0) {
rlim.rlim_max = minimum;
rlim.rlim_cur = minimum;
res = setrlimit(RLIMIT_NOFILE, &rlim);
}
if (0 < minimum && res < 0) {
LOG_TOPIC("ba733", FATAL, arangodb::Logger::SYSCALL)
<< "cannot raise the file descriptor limit to " << minimum << ": "
<< strerror(errno);
FATAL_ERROR_EXIT();
}
} else if (rlim.rlim_cur < recommended) {
LOG_TOPIC("2940e", DEBUG, arangodb::Logger::SYSCALL)
<< "soft limit " << rlim.rlim_cur << " is too small, trying to raise";
if (!isUnlimited(rlim.rlim_max) && recommended < rlim.rlim_max) {
recommended = rlim.rlim_max;
}
rlim.rlim_cur = recommended;
res = setrlimit(RLIMIT_NOFILE, &rlim);
if (0 < minimum && minimum < recommended && res < 0) {
rlim.rlim_cur = minimum;
res = setrlimit(RLIMIT_NOFILE, &rlim);
}
if (0 < minimum && res < 0) {
LOG_TOPIC("dd521", FATAL, arangodb::Logger::SYSCALL)
<< "cannot raise the file descriptor limit to " << minimum << ": "
<< strerror(errno);
FATAL_ERROR_EXIT();
}
}
#endif
}
} // namespace arangodb