Skip to content

Commit ce5dd76

Browse files
committed
Adjust nofile limit recommendations
1 parent a5e845c commit ce5dd76

File tree

8 files changed

+59
-42
lines changed

8 files changed

+59
-42
lines changed

Diff for: nativelink-config/examples/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ The `private` server consists of a `listener` object and a `services` object. Th
386386

387387
```json5
388388
"global": {
389-
"max_open_files": 512
389+
"max_open_files": 24576
390390
}
391391
```
392392

@@ -562,7 +562,7 @@ Below, you will find a fully tested example that you can also find in [basic_cas
562562
}
563563
}],
564564
"global": {
565-
"max_open_files": 512
565+
"max_open_files": 24576
566566
}
567567
}
568568
```

Diff for: nativelink-config/examples/basic_cas.json5

+1-1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,6 @@
157157
}
158158
}],
159159
"global": {
160-
"max_open_files": 512
160+
"max_open_files": 24576
161161
}
162162
}
File renamed without changes.

Diff for: nativelink-config/src/cas_server.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -707,12 +707,12 @@ pub struct GlobalConfig {
707707
/// This value is not strictly enforced, it is a best effort. Some internal libraries
708708
/// open files or read metadata from a files which do not obey this limit, however
709709
/// the vast majority of cases will have this limit be honored.
710-
/// As a rule of thumb this value should be less than half the value of `ulimit -n`.
710+
/// This value must be larger than `ulimit -n` to have any effect.
711711
/// Any network open file descriptors is not counted in this limit, but is counted
712712
/// in the kernel limit. It is a good idea to set a very large `ulimit -n`.
713713
/// Note: This value must be greater than 10.
714714
///
715-
/// Default: 512
715+
/// Default: 24576 (= 24 * 1024)
716716
#[serde(deserialize_with = "convert_numeric_with_shellexpand")]
717717
pub max_open_files: usize,
718718

Diff for: nativelink-util/src/fs.rs

+48-32
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,9 @@ impl AsyncWrite for FileSlot {
114114

115115
// Note: If the default changes make sure you update the documentation in
116116
// `config/cas_server.rs`.
117-
pub const DEFAULT_OPEN_FILE_PERMITS: usize = 24 * 1024; // 24k.
118-
static TOTAL_FILE_SEMAPHORES: AtomicUsize = AtomicUsize::new(DEFAULT_OPEN_FILE_PERMITS);
119-
pub static OPEN_FILE_SEMAPHORE: Semaphore = Semaphore::const_new(DEFAULT_OPEN_FILE_PERMITS);
117+
pub const DEFAULT_OPEN_FILE_LIMIT: usize = 24 * 1024; // 24k.
118+
static OPEN_FILE_LIMIT: AtomicUsize = AtomicUsize::new(DEFAULT_OPEN_FILE_LIMIT);
119+
pub static OPEN_FILE_SEMAPHORE: Semaphore = Semaphore::const_new(DEFAULT_OPEN_FILE_LIMIT);
120120

121121
/// Try to acquire a permit from the open file semaphore.
122122
#[inline]
@@ -139,59 +139,75 @@ where
139139
.unwrap_or_else(|e| Err(make_err!(Code::Internal, "background task failed: {e:?}")))
140140
}
141141

142-
pub fn set_open_file_limit(limit: usize) {
143-
let new_limit = {
144-
// We increase the limit by 20% to give extra
145-
// room for other file descriptors like sockets,
146-
// pipes, and other things.
147-
let fs_ulimit =
148-
u64::try_from(limit.saturating_add(limit / 5)).expect("set_open_file_limit too large");
149-
match increase_nofile_limit(fs_ulimit) {
150-
Ok(new_fs_ulimit) => {
142+
/// Sets the soft nofile limit to `desired_open_file_limit` and adjusts
143+
/// `OPEN_FILE_SEMAPHORE` accorgingly.
144+
///
145+
/// # Panics
146+
///
147+
/// If any type conversion fails. This can't happen if `usize` is smaller than
148+
/// `u64`.
149+
pub fn set_open_file_limit(desired_open_file_limit: usize) {
150+
let new_open_file_limit = {
151+
match increase_nofile_limit(
152+
u64::try_from(desired_open_file_limit)
153+
.expect("desired_open_file_limit is too large to convert to u64."),
154+
) {
155+
Ok(open_file_limit) => {
151156
event!(
152157
Level::INFO,
153-
"set_open_file_limit({limit})::ulimit success. New fs.ulimit: {fs_ulimit} (20% increase of {limit}).",
158+
"set_open_file_limit() assigns new open file limit {open_file_limit}.",
154159
);
155-
usize::try_from(new_fs_ulimit).expect("new_fs_ulimit too large")
160+
usize::try_from(open_file_limit)
161+
.expect("open_file_limit is too large to convert to usize.")
156162
}
157163
Err(e) => {
158164
event!(
159165
Level::ERROR,
160-
"set_open_file_limit({limit})::ulimit failed. Maybe system does not have ulimits, continuing anyway. - {e:?}",
166+
"set_open_file_limit() failed to assign open file limit. Maybe system does not have ulimits, continuing anyway. - {e:?}",
161167
);
162-
limit
168+
DEFAULT_OPEN_FILE_LIMIT
163169
}
164170
}
165171
};
166-
if new_limit < DEFAULT_OPEN_FILE_PERMITS {
172+
// Can we give a better estimate?
173+
if new_open_file_limit < DEFAULT_OPEN_FILE_LIMIT {
167174
event!(
168175
Level::WARN,
169-
"set_open_file_limit({limit}) succeeded, but this is below the default limit of {DEFAULT_OPEN_FILE_PERMITS}. Will continue, but we recommend increasing the limit to at least the default.",
176+
"The new open file limit ({new_open_file_limit}) is below the recommended value of {DEFAULT_OPEN_FILE_LIMIT}. Consider raising max_open_files.",
170177
);
171178
}
172-
if new_limit < limit {
179+
180+
// Use only 80% of the open file limit for permits from OPEN_FILE_SEMAPHORE
181+
// to give extra room for other file descriptors like sockets, pipes, and
182+
// other things.
183+
let reduced_open_file_limit = new_open_file_limit.saturating_sub(new_open_file_limit / 5);
184+
let previous_open_file_limit = OPEN_FILE_LIMIT.load(Ordering::Acquire);
185+
// No permit should be aquired yet, so this warning should not occur.
186+
if (OPEN_FILE_SEMAPHORE.available_permits() + reduced_open_file_limit)
187+
< previous_open_file_limit
188+
{
173189
event!(
174190
Level::WARN,
175-
"set_open_file_limit({limit}) succeeded, but new open file limit is {new_limit}. Will continue, but likely a config or system options (ie: ulimit) needs updated.",
191+
"There are not enough available permits to remove {previous_open_file_limit} - {reduced_open_file_limit} permits.",
176192
);
177193
}
178-
179-
let current_total = TOTAL_FILE_SEMAPHORES.load(Ordering::Acquire);
180-
if limit < current_total {
181-
event!(
182-
Level::ERROR,
183-
"set_open_file_limit({}) must be greater than {}",
184-
limit,
185-
current_total
194+
if previous_open_file_limit <= reduced_open_file_limit {
195+
OPEN_FILE_LIMIT.fetch_add(
196+
reduced_open_file_limit - previous_open_file_limit,
197+
Ordering::Release,
198+
);
199+
OPEN_FILE_SEMAPHORE.add_permits(reduced_open_file_limit - previous_open_file_limit);
200+
} else {
201+
OPEN_FILE_LIMIT.fetch_sub(
202+
previous_open_file_limit - reduced_open_file_limit,
203+
Ordering::Release,
186204
);
187-
return;
205+
OPEN_FILE_SEMAPHORE.forget_permits(previous_open_file_limit - reduced_open_file_limit);
188206
}
189-
TOTAL_FILE_SEMAPHORES.fetch_add(limit - current_total, Ordering::Release);
190-
OPEN_FILE_SEMAPHORE.add_permits(limit - current_total);
191207
}
192208

193209
pub fn get_open_files_for_test() -> usize {
194-
TOTAL_FILE_SEMAPHORES.load(Ordering::Acquire) - OPEN_FILE_SEMAPHORE.available_permits()
210+
OPEN_FILE_LIMIT.load(Ordering::Acquire) - OPEN_FILE_SEMAPHORE.available_permits()
195211
}
196212

197213
pub async fn open_file(

Diff for: src/bin/nativelink.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1012,7 +1012,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
10121012
let mut metrics_enabled = {
10131013
let global_cfg = if let Some(global_cfg) = &mut cfg.global {
10141014
if global_cfg.max_open_files == 0 {
1015-
global_cfg.max_open_files = fs::DEFAULT_OPEN_FILE_PERMITS;
1015+
global_cfg.max_open_files = fs::DEFAULT_OPEN_FILE_LIMIT;
10161016
}
10171017
if global_cfg.default_digest_size_health_check == 0 {
10181018
global_cfg.default_digest_size_health_check = DEFAULT_DIGEST_SIZE_HEALTH_CHECK_CFG;
@@ -1021,7 +1021,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
10211021
*global_cfg
10221022
} else {
10231023
GlobalConfig {
1024-
max_open_files: fs::DEFAULT_OPEN_FILE_PERMITS,
1024+
max_open_files: fs::DEFAULT_OPEN_FILE_LIMIT,
10251025
disable_metrics: cfg.servers.iter().all(|v| {
10261026
let Some(service) = &v.services else {
10271027
return true;

Diff for: toolchain-examples/nativelink-config.json renamed to toolchain-examples/nativelink-config.json5

+2-1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@
141141
}
142142
}],
143143
"global": {
144-
"max_open_files": 512
144+
// Defaults to 24576 = 24 * 1024.
145+
"max_open_files": 24576
145146
}
146147
}

Diff for: web/platform/src/content/docs/docs/config/basic-configs.mdx

+2-2
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ memory and filesystem stores instead of S3 and Redis.
181181
}
182182
}],
183183
"global": {
184-
"max_open_files": 512
184+
"max_open_files": 24576
185185
}
186186
}
187187

@@ -360,7 +360,7 @@ memory and filesystem stores instead of S3 and Redis.
360360
}
361361
}],
362362
"global": {
363-
"max_open_files": 512
363+
"max_open_files": 24576
364364
}
365365
}
366366
```

0 commit comments

Comments
 (0)