Skip to content

Commit 7fb9d3f

Browse files
committed
Fix #2229 detect available memory
This doesn't implement streaming IO for low memory situations - we still have the situation that low footprint situations will fail to install, but while it is the case that rustc's memory footprint is lower than our unpack footprint this is probably not urgent to fix, though I will get around to it. Being less aggressive about unpack buffer size though should reduce the number of support tickets from folk in these cases, I hope. We may end up getting tickets from folk with broken ulimit syscalls though, who knows.
1 parent bd2d51e commit 7fb9d3f

File tree

10 files changed

+153
-57
lines changed

10 files changed

+153
-57
lines changed

Cargo.lock

Lines changed: 64 additions & 35 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ chrono = "0.4"
2525
clap = "2"
2626
download = { path = "download" }
2727
error-chain = "0.12"
28+
effective-limits = "0.3"
2829
flate2 = "1"
2930
git-testament = "0.1.4"
3031
home = "0.5"

src/cli/common.rs

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use crate::self_update;
55
use crate::term2;
66
use git_testament::{git_testament, render_testament};
77
use lazy_static::lazy_static;
8+
use rustup::dist::notifications as dist_notifications;
9+
use rustup::utils::notifications as util_notifications;
810
use rustup::utils::notify::NotificationLevel;
911
use rustup::utils::utils;
1012
use rustup::{Cfg, Notification, Toolchain, UpdateStatus};
@@ -104,21 +106,29 @@ pub fn read_line() -> Result<String> {
104106
.ok_or_else(|| "unable to read from stdin for confirmation".into())
105107
}
106108

107-
pub fn set_globals(verbose: bool, quiet: bool) -> Result<Cfg> {
108-
use crate::download_tracker::DownloadTracker;
109-
use std::cell::RefCell;
110-
111-
let download_tracker = RefCell::new(DownloadTracker::new().with_display_progress(!quiet));
109+
#[derive(Default)]
110+
struct NotifyOnConsole {
111+
ram_notice_shown: bool,
112+
verbose: bool,
113+
}
112114

113-
Ok(Cfg::from_env(Arc::new(move |n: Notification<'_>| {
114-
if download_tracker.borrow_mut().handle_notification(&n) {
115-
return;
116-
}
115+
impl NotifyOnConsole {
116+
fn handle(&mut self, n: Notification<'_>) {
117+
if let Notification::Install(dist_notifications::Notification::Utils(
118+
util_notifications::Notification::SetDefaultBufferSize(_),
119+
)) = &n
120+
{
121+
if self.ram_notice_shown {
122+
return;
123+
} else {
124+
self.ram_notice_shown = true;
125+
}
126+
};
117127
let level = n.level();
118128
for n in format!("{}", n).lines() {
119129
match level {
120130
NotificationLevel::Verbose => {
121-
if verbose {
131+
if self.verbose {
122132
verbose!("{}", n);
123133
}
124134
}
@@ -133,6 +143,24 @@ pub fn set_globals(verbose: bool, quiet: bool) -> Result<Cfg> {
133143
}
134144
}
135145
}
146+
}
147+
}
148+
149+
pub fn set_globals(verbose: bool, quiet: bool) -> Result<Cfg> {
150+
use crate::download_tracker::DownloadTracker;
151+
use std::cell::RefCell;
152+
153+
let download_tracker = RefCell::new(DownloadTracker::new().with_display_progress(!quiet));
154+
let console_notifier = RefCell::new(NotifyOnConsole {
155+
verbose,
156+
..Default::default()
157+
});
158+
159+
Ok(Cfg::from_env(Arc::new(move |n: Notification<'_>| {
160+
if download_tracker.borrow_mut().handle_notification(&n) {
161+
return;
162+
}
163+
console_notifier.borrow_mut().handle(n);
136164
}))?)
137165
}
138166

src/dist/component/package.rs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -165,17 +165,30 @@ struct MemoryBudget {
165165

166166
// Probably this should live in diskio but ¯\_(ツ)_/¯
167167
impl MemoryBudget {
168-
fn new(max_file_size: usize) -> Self {
169-
const DEFAULT_UNPACK_RAM: usize = 400 * 1024 * 1024;
170-
let unpack_ram = if let Ok(budget_str) = env::var("RUSTUP_UNPACK_RAM") {
171-
if let Ok(budget) = budget_str.parse::<usize>() {
172-
budget
173-
} else {
174-
DEFAULT_UNPACK_RAM
168+
fn new(
169+
max_file_size: usize,
170+
effective_max_ram: usize,
171+
notify_handler: Option<&dyn Fn(Notification<'_>)>,
172+
) -> Self {
173+
const DEFAULT_UNPACK_RAM_MAX: usize = 500 * 1024 * 1024;
174+
const RAM_ALLOWANCE_FOR_RUSTUP_AND_BUFFERS: usize = 100 * 1024 * 1024;
175+
let ram_for_unpacking = effective_max_ram - RAM_ALLOWANCE_FOR_RUSTUP_AND_BUFFERS;
176+
let default_max_unpack_ram = std::cmp::min(DEFAULT_UNPACK_RAM_MAX, ram_for_unpacking);
177+
let unpack_ram = match env::var("RUSTUP_UNPACK_RAM")
178+
.ok()
179+
.and_then(|budget_str| budget_str.parse::<usize>().ok())
180+
{
181+
// Note: In future we may want to add a warning or even an override if a user
182+
// supplied budget is larger than effective_max_ram.
183+
Some(budget) => budget,
184+
None => {
185+
if let Some(h) = notify_handler {
186+
h(Notification::SetDefaultBufferSize(default_max_unpack_ram))
187+
}
188+
default_max_unpack_ram
175189
}
176-
} else {
177-
DEFAULT_UNPACK_RAM
178190
};
191+
179192
if max_file_size > unpack_ram {
180193
panic!("RUSTUP_UNPACK_RAM must be larger than {}", max_file_size);
181194
}
@@ -278,7 +291,12 @@ fn unpack_without_first_dir<'a, R: Read>(
278291
.entries()
279292
.chain_err(|| ErrorKind::ExtractingPackage)?;
280293
const MAX_FILE_SIZE: u64 = 200_000_000;
281-
let mut budget = MemoryBudget::new(MAX_FILE_SIZE as usize);
294+
let effective_max_ram = effective_limits::memory_limit()?;
295+
let mut budget = MemoryBudget::new(
296+
MAX_FILE_SIZE as usize,
297+
effective_max_ram as usize,
298+
notify_handler,
299+
);
282300

283301
let mut directories: HashMap<PathBuf, DirStatus> = HashMap::new();
284302
// Path is presumed to exist. Call it a precondition.

src/errors.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub const TOOLSTATE_MSG: &str =
2222
error_chain! {
2323
links {
2424
Download(download::Error, download::ErrorKind);
25+
Limits(effective_limits::Error, effective_limits::ErrorKind);
2526
}
2627

2728
foreign_links {

src/utils/notifications.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::path::Path;
44
use url::Url;
55

66
use crate::utils::notify::NotificationLevel;
7-
use crate::utils::units::Unit;
7+
use crate::utils::units::{self, Unit};
88

99
#[derive(Debug)]
1010
pub enum Notification<'a> {
@@ -27,6 +27,10 @@ pub enum Notification<'a> {
2727
DownloadPopUnit,
2828
NoCanonicalPath(&'a Path),
2929
ResumingPartialDownload,
30+
/// This would make more sense as a crate::notifications::Notification
31+
/// member, but the notification callback is already narrowed to
32+
/// utils::notifications by the time tar unpacking is called.
33+
SetDefaultBufferSize(usize),
3034
UsingCurl,
3135
UsingReqwest,
3236
/// Renaming encountered a file in use error and is retrying.
@@ -54,7 +58,7 @@ impl<'a> Notification<'a> {
5458
| ResumingPartialDownload
5559
| UsingCurl
5660
| UsingReqwest => NotificationLevel::Verbose,
57-
RenameInUse(_, _) => NotificationLevel::Info,
61+
RenameInUse(_, _) | SetDefaultBufferSize(_) => NotificationLevel::Info,
5862
NoCanonicalPath(_) => NotificationLevel::Warn,
5963
}
6064
}
@@ -78,6 +82,11 @@ impl<'a> Display for Notification<'a> {
7882
src.display(),
7983
dest.display()
8084
),
85+
SetDefaultBufferSize(size) => write!(
86+
f,
87+
"Defaulting to {} unpack ram",
88+
units::Size::new(*size, units::Unit::B, units::UnitMode::Norm)
89+
),
8190
DownloadingFile(url, _) => write!(f, "downloading file from: '{}'", url),
8291
DownloadContentLengthReceived(len) => write!(f, "download size is: '{}'", len),
8392
DownloadDataReceived(data) => write!(f, "received some data of size {}", data.len()),

tests/cli-exact.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ info: downloading component 'rust-docs'
3838
info: downloading component 'rust-std'
3939
info: downloading component 'rustc'
4040
info: installing component 'cargo'
41+
info: Defaulting to 500.0 MiB unpack ram
4142
info: installing component 'rust-docs'
4243
info: installing component 'rust-std'
4344
info: installing component 'rustc'
@@ -172,6 +173,7 @@ info: downloading component 'rust-docs'
172173
info: downloading component 'rust-std'
173174
info: downloading component 'rustc'
174175
info: installing component 'cargo'
176+
info: Defaulting to 500.0 MiB unpack ram
175177
info: installing component 'rust-docs'
176178
info: installing component 'rust-std'
177179
info: installing component 'rustc'
@@ -504,6 +506,7 @@ fn cross_install_indicates_target() {
504506
&format!(
505507
r"info: downloading component 'rust-std' for '{0}'
506508
info: installing component 'rust-std' for '{0}'
509+
info: Defaulting to 500.0 MiB unpack ram
507510
",
508511
clitools::CROSS_ARCH1
509512
),

tests/cli-rustup.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ info: removing previous version of component 'rust-docs'
5656
info: removing previous version of component 'rust-std'
5757
info: removing previous version of component 'rustc'
5858
info: installing component 'cargo'
59+
info: Defaulting to 500.0 MiB unpack ram
5960
info: installing component 'rust-docs'
6061
info: installing component 'rust-std'
6162
info: installing component 'rustc'
@@ -96,6 +97,7 @@ info: removing previous version of component 'rust-docs'
9697
info: removing previous version of component 'rust-std'
9798
info: removing previous version of component 'rustc'
9899
info: installing component 'cargo'
100+
info: Defaulting to 500.0 MiB unpack ram
99101
info: installing component 'rust-docs'
100102
info: installing component 'rust-std'
101103
info: installing component 'rustc'
@@ -160,6 +162,7 @@ info: removing previous version of component 'rust-docs'
160162
info: removing previous version of component 'rust-std'
161163
info: removing previous version of component 'rustc'
162164
info: installing component 'cargo'
165+
info: Defaulting to 500.0 MiB unpack ram
163166
info: installing component 'rust-docs'
164167
info: installing component 'rust-std'
165168
info: installing component 'rustc'
@@ -230,6 +233,7 @@ info: removing previous version of component 'rust-docs'
230233
info: removing previous version of component 'rust-std'
231234
info: removing previous version of component 'rustc'
232235
info: installing component 'cargo'
236+
info: Defaulting to 500.0 MiB unpack ram
233237
info: installing component 'rust-docs'
234238
info: installing component 'rust-std'
235239
info: installing component 'rustc'
@@ -291,6 +295,7 @@ info: downloading component 'rust-docs'
291295
info: downloading component 'rust-std'
292296
info: downloading component 'rustc'
293297
info: installing component 'cargo'
298+
info: Defaulting to 500.0 MiB unpack ram
294299
info: installing component 'rust-docs'
295300
info: installing component 'rust-std'
296301
info: installing component 'rustc'

tests/cli-self-upd.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,7 @@ info: downloading component 'rust-docs'
883883
info: downloading component 'rust-std'
884884
info: downloading component 'rustc'
885885
info: installing component 'cargo'
886+
info: Defaulting to 500.0 MiB unpack ram
886887
info: installing component 'rust-docs'
887888
info: installing component 'rust-std'
888889
info: installing component 'rustc'

tests/cli-v2.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,6 +1342,7 @@ info: downloading component 'cargo'
13421342
info: downloading component 'rust-docs'
13431343
info: downloading component 'rustc'
13441344
info: installing component 'cargo'
1345+
info: Defaulting to 500.0 MiB unpack ram
13451346
info: installing component 'rust-docs'
13461347
info: installing component 'rustc'
13471348
"

0 commit comments

Comments
 (0)