From ba29a5590bc4479d74454f0b9fdaf007d9d80221 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 26 Apr 2013 00:46:47 +0200 Subject: [PATCH] Try to increase file descriptor rlimit if necessary As the default can be too low, especially on OSX. --- src/init.cpp | 20 ++++++++++++++++++++ src/net.cpp | 5 +++-- src/net.h | 1 + src/util.cpp | 23 +++++++++++++++++++++++ src/util.h | 1 + 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 7024f3f78..8efe6dfdc 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -28,6 +28,15 @@ using namespace boost; CWallet* pwalletMain; CClientUIInterface uiInterface; +#ifdef WIN32 +// Win32 LevelDB doesn't use filedescriptors, and the ones used for +// accessing block files, don't count towards to fd_set size limit +// anyway. +#define MIN_CORE_FILEDESCRIPTORS 0 +#else +#define MIN_CORE_FILEDESCRIPTORS 150 +#endif + // Used to pass flags to the Bind() function enum BindFlags { BF_NONE = 0, @@ -518,6 +527,16 @@ bool AppInit2(boost::thread_group& threadGroup) SoftSetBoolArg("-rescan", true); } + // Make sure enough file descriptors are available + int nBind = std::max((int)mapArgs.count("-bind"), 1); + nMaxConnections = GetArg("-maxconnections", 125); + nMaxConnections = std::max(std::min(nMaxConnections, FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS), 0); + int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS); + if (nFD < MIN_CORE_FILEDESCRIPTORS) + return InitError(_("Not enough file descriptors available.")); + if (nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections) + nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS; + // ********************************************************* Step 3: parameter-to-internal-flags fDebug = GetBoolArg("-debug"); @@ -594,6 +613,7 @@ bool AppInit2(boost::thread_group& threadGroup) printf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str()); printf("Default data directory %s\n", GetDefaultDataDir().string().c_str()); printf("Used data directory %s\n", strDataDir.c_str()); + printf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD); std::ostringstream strErrors; if (fDaemon) diff --git a/src/net.cpp b/src/net.cpp index 031126180..3fa48ae48 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -48,6 +48,7 @@ static CNode* pnodeSync = NULL; uint64 nLocalHostNonce = 0; static std::vector vhListenSocket; CAddrMan addrman; +int nMaxConnections = 125; vector vNodes; CCriticalSection cs_vNodes; @@ -908,7 +909,7 @@ void ThreadSocketHandler() if (nErr != WSAEWOULDBLOCK) printf("socket error accept failed: %d\n", nErr); } - else if (nInbound >= GetArg("-maxconnections", 125) - MAX_OUTBOUND_CONNECTIONS) + else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS) { { LOCK(cs_setservAddNodeAddresses); @@ -1803,7 +1804,7 @@ void StartNode(boost::thread_group& threadGroup) { if (semOutbound == NULL) { // initialize semaphore - int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, (int)GetArg("-maxconnections", 125)); + int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); semOutbound = new CSemaphore(nMaxOutbound); } diff --git a/src/net.h b/src/net.h index 32bbbca6d..df34f5a88 100644 --- a/src/net.h +++ b/src/net.h @@ -74,6 +74,7 @@ extern bool fDiscover; extern uint64 nLocalServices; extern uint64 nLocalHostNonce; extern CAddrMan addrman; +extern int nMaxConnections; extern std::vector vNodes; extern CCriticalSection cs_vNodes; diff --git a/src/util.cpp b/src/util.cpp index 3fd624c42..8b6d8b32c 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -10,6 +10,7 @@ #endif #include #include +#include #endif #include "util.h" @@ -1167,6 +1168,28 @@ bool TruncateFile(FILE *file, unsigned int length) { #endif } + +// this function tries to raise the file descriptor limit to the requested number. +// It returns the actual file descriptor limit (which may be more or less than nMinFD) +int RaiseFileDescriptorLimit(int nMinFD) { +#if defined(WIN32) + return 2048; +#else + struct rlimit limitFD; + if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) { + if (limitFD.rlim_cur < (rlim_t)nMinFD) { + limitFD.rlim_cur = nMinFD; + if (limitFD.rlim_cur > limitFD.rlim_max) + limitFD.rlim_cur = limitFD.rlim_max; + setrlimit(RLIMIT_NOFILE, &limitFD); + getrlimit(RLIMIT_NOFILE, &limitFD); + } + return limitFD.rlim_cur; + } + return nMinFD; // getrlimit failed, assume it's fine +#endif +} + // this function tries to make a particular range of a file allocated (corresponding to disk space) // it is advisory, and the range specified in the arguments will never contain live data void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) { diff --git a/src/util.h b/src/util.h index 0641c4be7..3d2536450 100644 --- a/src/util.h +++ b/src/util.h @@ -197,6 +197,7 @@ bool WildcardMatch(const std::string& str, const std::string& mask); void FileCommit(FILE *fileout); int GetFilesize(FILE* file); bool TruncateFile(FILE *file, unsigned int length); +int RaiseFileDescriptorLimit(int nMinFD); void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length); bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest); boost::filesystem::path GetDefaultDataDir();