Skip to content

Commit a44a7d6

Browse files
committed
infoLoggerD fix handling of large number of connections
1 parent b61c868 commit a44a7d6

File tree

2 files changed

+67
-4
lines changed

2 files changed

+67
-4
lines changed

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ endif()
2222
# global compilation options
2323
enable_language(C)
2424
enable_language(CXX)
25-
set(CMAKE_CXX_STANDARD 14)
25+
set(CMAKE_CXX_STANDARD 17)
2626
set(CMAKE_CXX_STANDARD_REQUIRED ON)
2727
set(CMAKE_CXX_EXTENSIONS OFF)
2828
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
@@ -65,7 +65,7 @@ endif()
6565
include(ExternalProject)
6666
externalproject_add (Common-standalone
6767
GIT_REPOSITORY "https://github.com/AliceO2Group/Common.git"
68-
GIT_TAG "v1.6.1"
68+
GIT_TAG "v1.6.3"
6969
LOG_DOWNLOAD 1
7070
UPDATE_COMMAND ""
7171
PATCH_COMMAND ""

src/infoLoggerD.cxx

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
#include <limits.h>
4141

4242
#include <list>
43+
#include <filesystem>
44+
#include <sys/resource.h>
4345

4446
#include <Common/Daemon.h>
4547
#include <Common/SimpleLog.h>
@@ -67,7 +69,7 @@ class ConfigInfoLoggerD
6769
std::string localLogDirectory = "/tmp/infoLoggerD"; // local directory to be used for log storage, whenever necessary
6870
std::string rxSocketPath = INFOLOGGER_DEFAULT_LOCAL_SOCKET; // name of socket used to receive log messages from clients
6971
int rxSocketInBufferSize = -1; // size of socket receiving buffer. -1 will leave to sys default.
70-
int rxMaxConnections = 1024; // maximum number of incoming connections
72+
int rxMaxConnections = 2048; // maximum number of incoming connections
7173

7274
// settings for remote infoLoggerServer access
7375
std::string serverHost = "localhost"; // IP name to connect infoLoggerServer
@@ -217,6 +219,8 @@ class InfoLoggerD : public Daemon
217219
TR_client_handle hCx = nullptr; // handle to server transport
218220

219221
FILE* logOutput = nullptr; // handle to local log file where to copy incoming messages, if configured to do so
222+
223+
bool stateAcceptFailed = 0; // flag to keep track accept() failing, and avoid flooding log output with errors in case of e.g. reaching max number of open files
220224
};
221225

222226
// list of extra keys accepted on the command line (-o key=value entries)
@@ -373,6 +377,58 @@ InfoLoggerD::InfoLoggerD(int argc, char* argv[]) : Daemon(argc, argv, nullptr, E
373377
// todo: open a log file!
374378
}
375379

380+
// check consistency of settings for max number of incoming connections
381+
if (1) {
382+
log.info("Checking resources for rxMaxConnections = %d", configInfoLoggerD.rxMaxConnections);
383+
long fileDescriptorCount = 0;
384+
long fileDescriptorMax = 0;
385+
struct rlimit rlim;
386+
bool limitOk = 0;
387+
try {
388+
fileDescriptorCount = std::distance(std::filesystem::directory_iterator("/proc/self/fd"), std::filesystem::directory_iterator{});
389+
log.info("At the moment, having %ld files opened", fileDescriptorCount);
390+
}
391+
catch(...) {
392+
}
393+
// iterate a couple of time to get/set rlimit if needed
394+
for (int i=0; i<2; i++) {
395+
int err = getrlimit(RLIMIT_NOFILE, &rlim);
396+
if (err) {
397+
log.error("getrlimit() failed: %s", strerror(errno));
398+
break;
399+
}
400+
fileDescriptorMax = (long) rlim.rlim_cur;
401+
log.info("getrlimit(): soft = %lu, hard = %lu", (unsigned long)rlim.rlim_cur, (unsigned long)rlim.rlim_max);
402+
if (fileDescriptorCount + configInfoLoggerD.rxMaxConnections > (long)rlim.rlim_cur) {
403+
log.info("Current limits are not compatible with rxMaxConnections = %d", configInfoLoggerD.rxMaxConnections);
404+
405+
// trying to increase limits once
406+
if (i) break;
407+
rlim.rlim_cur = (unsigned long)(fileDescriptorCount + configInfoLoggerD.rxMaxConnections + 1);
408+
log.info("Trying to increase limit to %ld", (long)rlim.rlim_cur);
409+
if (rlim.rlim_cur > rlim.rlim_max) {
410+
rlim.rlim_cur = rlim.rlim_max;
411+
}
412+
err = setrlimit(RLIMIT_NOFILE, &rlim);
413+
if (err) {
414+
log.error("setrlimit() failed: %s", strerror(errno));
415+
break;
416+
}
417+
} else {
418+
log.info("Limits ok, should be able to cope with %d max connections", configInfoLoggerD.rxMaxConnections);
419+
limitOk = 1;
420+
break;
421+
}
422+
}
423+
if (!limitOk) {
424+
configInfoLoggerD.rxMaxConnections = fileDescriptorMax - fileDescriptorCount - 1;
425+
if (configInfoLoggerD.rxMaxConnections <= 0) {
426+
configInfoLoggerD.rxMaxConnections = 1;
427+
}
428+
log.info("Reducing rxMaxConnections to %d", configInfoLoggerD.rxMaxConnections);
429+
}
430+
}
431+
376432
isInitialized = 1;
377433
log.info("infoLoggerD started");
378434
}
@@ -496,8 +552,15 @@ Daemon::LoopStatus InfoLoggerD::doLoop()
496552
socklen_t socketAddressLen = sizeof(socketAddress);
497553
int tmpSocket = accept(rxSocket, (struct sockaddr*)&socketAddress, &socketAddressLen);
498554
if (tmpSocket == -1) {
499-
log.error("accept() failed: %s", strerror(errno));
555+
if (!stateAcceptFailed) {
556+
stateAcceptFailed = 1;
557+
log.error("accept() failed: %s", strerror(errno));
558+
}
500559
} else {
560+
if (stateAcceptFailed) {
561+
log.info("accept() failure now recovered");
562+
stateAcceptFailed = 0;
563+
}
501564
if (((int)clients.size() >= configInfoLoggerD.rxMaxConnections) && (configInfoLoggerD.rxMaxConnections > 0)) {
502565
log.warning("Closing new client, maximum number of connections reached (%d)", configInfoLoggerD.rxMaxConnections);
503566
close(tmpSocket);

0 commit comments

Comments
 (0)