Skip to content

Commit 7553c1f

Browse files
Raise process FD limit and use RocksDB default max_open_files
Remove the hardcoded OPEN_FILE_LIMIT=750 and state_snapshot's max_open_files=1024 overrides. With multiple RocksDB databases open simultaneously (comments archive + account history + snapshot manifest), the combined table cache reservation of 1500+ FDs exceeds the process soft limit on many systems, causing "Too many open files" crashes during replay. Instead, raise the process soft FD limit toward the hard limit at startup (capped at 65536) and let RocksDB use its recommended default of max_open_files=-1 (keep all SST files open). This is simpler, more performant (no table cache eviction), and aligned with RocksDB's own design recommendations. Fixes #851
1 parent 817c37b commit 7553c1f

6 files changed

Lines changed: 91 additions & 9 deletions

File tree

libraries/chain/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ set( SOURCES
9292
external_storage/rocksdb_comment_archive.cpp
9393
external_storage/rocksdb_snapshot.cpp
9494
external_storage/types.cpp
95+
external_storage/fd_budget.cpp
9596

9697
${HEADERS}
9798
)
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#include <hive/chain/external_storage/fd_budget.hpp>
2+
3+
#include <sys/resource.h>
4+
#include <algorithm>
5+
#include <cerrno>
6+
#include <cstdint>
7+
#include <mutex>
8+
9+
#include <fc/log/logger.hpp>
10+
11+
namespace hive { namespace chain {
12+
13+
namespace {
14+
15+
constexpr rlim_t MAX_FD_CAP = 65536;
16+
constexpr rlim_t FD_WARN_THRESHOLD = 8192;
17+
18+
std::once_flag raise_flag;
19+
20+
void do_raise_fd_limit()
21+
{
22+
struct rlimit rl;
23+
if( getrlimit( RLIMIT_NOFILE, &rl ) != 0 )
24+
{
25+
wlog( "Failed to read file descriptor limit (errno=${e}). "
26+
"RocksDB will use max_open_files=-1 with current system defaults.",
27+
("e", errno) );
28+
return;
29+
}
30+
31+
rlim_t old_soft = rl.rlim_cur;
32+
rlim_t hard = rl.rlim_max;
33+
rlim_t target = std::min( hard, MAX_FD_CAP );
34+
35+
if( old_soft < target )
36+
{
37+
rl.rlim_cur = target;
38+
if( setrlimit( RLIMIT_NOFILE, &rl ) != 0 )
39+
{
40+
wlog( "Failed to raise file descriptor soft limit from ${old} to ${target} (errno=${e}). "
41+
"Keeping current soft limit. Consider raising ulimit -n manually.",
42+
("old", static_cast<uint64_t>( old_soft ))
43+
("target", static_cast<uint64_t>( target ))
44+
("e", errno) );
45+
rl.rlim_cur = old_soft;
46+
}
47+
}
48+
49+
ilog( "File descriptor limits: soft ${old} -> ${cur}, hard ${hard}",
50+
("old", static_cast<uint64_t>( old_soft ))
51+
("cur", static_cast<uint64_t>( rl.rlim_cur ))
52+
("hard", static_cast<uint64_t>( hard )) );
53+
54+
if( rl.rlim_cur < FD_WARN_THRESHOLD )
55+
{
56+
wlog( "File descriptor limit is low (${cur}). "
57+
"This may cause RocksDB errors under heavy load. "
58+
"Consider raising the limit: ulimit -n ${recommended} or adjust system configuration.",
59+
("cur", static_cast<uint64_t>( rl.rlim_cur ))
60+
("recommended", static_cast<uint64_t>( FD_WARN_THRESHOLD )) );
61+
}
62+
}
63+
64+
} // anonymous namespace
65+
66+
void raise_fd_limit()
67+
{
68+
std::call_once( raise_flag, do_raise_fd_limit );
69+
}
70+
71+
} } // hive::chain

libraries/chain/external_storage/rocksdb_storage_provider.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <hive/chain/external_storage/rocksdb_storage_provider.hpp>
33

44
#include <hive/chain/external_storage/comment_rocksdb_objects.hpp>
5+
#include <hive/chain/external_storage/fd_budget.hpp>
56
#include <hive/chain/external_storage/utilities.hpp>
67
#include <hive/chain/external_storage/types.hpp>
78

@@ -45,7 +46,7 @@ void rocksdb_storage_provider::openDb( uint32_t expected_lib )
4546
/// Optimize RocksDB. This is the easiest way to get RocksDB to perform well
4647
options.IncreaseParallelism();
4748
options.OptimizeLevelStyleCompaction();
48-
options.max_open_files = OPEN_FILE_LIMIT;
49+
raise_fd_limit();
4950

5051
auto status = DB::Open( DBOptions( options ), strPath, columnDefs, &_columnHandles, &_db );
5152
ilog( "Database is ${status}.", ("status", status.ok() ? "opened" : "not opened") );
@@ -123,7 +124,7 @@ std::tuple<bool, bool> rocksdb_storage_provider::createDbSchema( const bfs::path
123124
/// Optimize RocksDB. This is the easiest way to get RocksDB to perform well
124125
options.IncreaseParallelism();
125126
options.OptimizeLevelStyleCompaction();
126-
options.max_open_files = OPEN_FILE_LIMIT;
127+
raise_fd_limit();
127128

128129
std::tuple<bool, bool> _result{ false, false };
129130

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#pragma once
2+
3+
namespace hive { namespace chain {
4+
5+
/// Raises the process soft file descriptor limit toward the hard limit.
6+
/// Called before opening RocksDB databases so they can use max_open_files = -1
7+
/// (RocksDB's recommended default) without hitting OS limits.
8+
/// Thread-safe and idempotent (uses std::call_once internally).
9+
void raise_fd_limit();
10+
11+
} } // hive::chain

libraries/chain/include/hive/chain/external_storage/types.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ using ::rocksdb::Comparator;
2121
#define STORE_MAJOR_VERSION 1
2222
#define STORE_MINOR_VERSION 1
2323

24-
#define OPEN_FILE_LIMIT 750
25-
2624
#define checkStatus(s) FC_ASSERT((s).ok(), "Data access failed: ${m}", ("m", (s).ToString()))
2725

2826
/** Because localtion_id_pair stores block_number paired with operation_id_vop_pair, which stores operation id on 63 bits,

libraries/plugins/state_snapshot/state_snapshot_plugin.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <hive/chain/util/decoded_types_data_storage.hpp>
1616
#include <hive/chain/util/state_checker_tools.hpp>
1717

18+
#include <hive/chain/external_storage/fd_budget.hpp>
1819
#include <hive/chain/external_storage/state_snapshot_provider.hpp>
1920
#include <hive/chain/external_storage/types.hpp>
2021

@@ -292,8 +293,7 @@ class snapshot_processor_data : public BaseClass
292293
{
293294
::rocksdb::Options opts;
294295
opts.comparator = &_size_t_comparator;
295-
296-
opts.max_open_files = 1024;
296+
hive::chain::raise_fd_limit();
297297

298298
return opts;
299299
}
@@ -1022,9 +1022,9 @@ void state_snapshot_plugin::impl::store_snapshot_manifest(const bfs::path& actua
10221022
if(bfs::exists(manifestDbPath) == false)
10231023
bfs::create_directories(manifestDbPath);
10241024

1025+
hive::chain::raise_fd_limit();
10251026
::rocksdb::Options dbOptions;
10261027
dbOptions.create_if_missing = true;
1027-
dbOptions.max_open_files = 1024;
10281028

10291029
rocksdb_cleanup_helper db = rocksdb_cleanup_helper::open(dbOptions, manifestDbPath);
10301030
::rocksdb::ColumnFamilyHandle* manifestCF = db.create_column_family("INDEX_MANIFEST");
@@ -1174,10 +1174,10 @@ state_snapshot_plugin::impl::load_snapshot_manifest(const bfs::path& actualStora
11741174
bfs::path manifestDbPath(actualStoragePath);
11751175
manifestDbPath /= "snapshot-manifest";
11761176

1177+
hive::chain::raise_fd_limit();
11771178
::rocksdb::Options dbOptions;
11781179
dbOptions.create_if_missing = false;
1179-
dbOptions.max_open_files = 1024;
1180-
1180+
11811181
::rocksdb::ColumnFamilyDescriptor cfDescriptor;
11821182
cfDescriptor.name = "INDEX_MANIFEST";
11831183

0 commit comments

Comments
 (0)