Skip to content

Commit b4982ad

Browse files
committed
Add a new package cache locking system.
This introduces a new `CacheLocker` which manages locks on the package cache. Instead of either being "locked" or "not locked", the new locker supports multiple modes: - Shared lock: Cargo can read from the package sources, along with any other cargos reading at the same time. - Download exclusive lock: Only one cargo can perform downloads. Download locks do not interfere with Shared locks, since it is expected that downloading does not modify existing files (only adds new ones). - Mutate exclusive lock: Only one cargo can have this lock, and it also prevents shared locks. This is so that the cargo can modify the package cache (such as deleting files) without breaking concurrent processes.
1 parent b37c8f3 commit b4982ad

File tree

25 files changed

+1007
-205
lines changed

25 files changed

+1007
-205
lines changed

crates/cargo-test-support/src/compare.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ fn substitute_macros(input: &str) -> String {
236236
("[SKIPPING]", " Skipping"),
237237
("[WAITING]", " Waiting"),
238238
("[PUBLISHED]", " Published"),
239+
("[BLOCKING]", " Blocking"),
239240
];
240241
let mut result = input.to_owned();
241242
for &(pat, subst) in &macros {

crates/xtask-bump-check/src/xtask.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use cargo::core::Registry;
2222
use cargo::core::SourceId;
2323
use cargo::core::Workspace;
2424
use cargo::sources::source::QueryKind;
25+
use cargo::util::cache_lock::CacheLockMode;
2526
use cargo::util::command_prelude::*;
2627
use cargo::util::ToSemver;
2728
use cargo::CargoResult;
@@ -361,7 +362,7 @@ fn check_crates_io<'a>(
361362
) -> CargoResult<()> {
362363
let source_id = SourceId::crates_io(config)?;
363364
let mut registry = PackageRegistry::new(config)?;
364-
let _lock = config.acquire_package_cache_lock()?;
365+
let _lock = config.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
365366
registry.lock_patches();
366367
config.shell().status(
367368
STATUS,

src/cargo/core/compiler/context/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::sync::{Arc, Mutex};
77
use crate::core::compiler::compilation::{self, UnitOutput};
88
use crate::core::compiler::{self, artifact, Unit};
99
use crate::core::PackageId;
10+
use crate::util::cache_lock::CacheLockMode;
1011
use crate::util::errors::CargoResult;
1112
use crate::util::profile;
1213
use anyhow::{bail, Context as _};
@@ -132,6 +133,13 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
132133
///
133134
/// [`ops::cargo_compile`]: ../../../ops/cargo_compile/index.html
134135
pub fn compile(mut self, exec: &Arc<dyn Executor>) -> CargoResult<Compilation<'cfg>> {
136+
// A shared lock is held during the duration of the build since rustc
137+
// needs to read from the `src` cache, and we don't want other
138+
// commands modifying the `src` cache while it is running.
139+
let _lock = self
140+
.bcx
141+
.config
142+
.acquire_package_cache_lock(CacheLockMode::Shared)?;
135143
let mut queue = JobQueue::new(self.bcx);
136144
let mut plan = BuildPlan::new();
137145
let build_plan = self.bcx.build_config.build_plan;

src/cargo/core/compiler/future_incompat.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use crate::core::compiler::BuildContext;
3737
use crate::core::{Dependency, PackageId, Workspace};
3838
use crate::sources::source::QueryKind;
3939
use crate::sources::SourceConfigMap;
40+
use crate::util::cache_lock::CacheLockMode;
4041
use crate::util::{iter_join, CargoResult};
4142
use anyhow::{bail, format_err, Context};
4243
use serde::{Deserialize, Serialize};
@@ -297,7 +298,10 @@ fn render_report(per_package_reports: &[FutureIncompatReportPackage]) -> BTreeMa
297298
/// This is best-effort - if an error occurs, `None` will be returned.
298299
fn get_updates(ws: &Workspace<'_>, package_ids: &BTreeSet<PackageId>) -> Option<String> {
299300
// This in general ignores all errors since this is opportunistic.
300-
let _lock = ws.config().acquire_package_cache_lock().ok()?;
301+
let _lock = ws
302+
.config()
303+
.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)
304+
.ok()?;
301305
// Create a set of updated registry sources.
302306
let map = SourceConfigMap::new(ws.config()).ok()?;
303307
let mut package_ids: BTreeSet<_> = package_ids

src/cargo/core/package.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::core::resolver::{HasDevUnits, Resolve};
2424
use crate::core::{Dependency, Manifest, PackageId, SourceId, Target};
2525
use crate::core::{Summary, Workspace};
2626
use crate::sources::source::{MaybePackage, SourceMap};
27-
use crate::util::config::PackageCacheLock;
27+
use crate::util::cache_lock::{CacheLock, CacheLockMode};
2828
use crate::util::errors::{CargoResult, HttpNotSuccessful};
2929
use crate::util::interning::InternedString;
3030
use crate::util::network::http::http_handle_and_timeout;
@@ -367,7 +367,7 @@ pub struct Downloads<'a, 'cfg> {
367367
next_speed_check_bytes_threshold: Cell<u64>,
368368
/// Global filesystem lock to ensure only one Cargo is downloading at a
369369
/// time.
370-
_lock: PackageCacheLock<'cfg>,
370+
_lock: CacheLock<'cfg>,
371371
}
372372

373373
struct Download<'cfg> {
@@ -465,7 +465,9 @@ impl<'cfg> PackageSet<'cfg> {
465465
timeout,
466466
next_speed_check: Cell::new(Instant::now()),
467467
next_speed_check_bytes_threshold: Cell::new(0),
468-
_lock: self.config.acquire_package_cache_lock()?,
468+
_lock: self
469+
.config
470+
.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?,
469471
})
470472
}
471473

@@ -478,6 +480,9 @@ impl<'cfg> PackageSet<'cfg> {
478480

479481
pub fn get_many(&self, ids: impl IntoIterator<Item = PackageId>) -> CargoResult<Vec<&Package>> {
480482
let mut pkgs = Vec::new();
483+
let _lock = self
484+
.config
485+
.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
481486
let mut downloads = self.enable_download()?;
482487
for id in ids {
483488
pkgs.extend(downloads.start(id)?);

src/cargo/ops/cargo_add/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::core::Shell;
2323
use crate::core::Summary;
2424
use crate::core::Workspace;
2525
use crate::sources::source::QueryKind;
26+
use crate::util::cache_lock::CacheLockMode;
2627
use crate::util::style;
2728
use crate::util::toml_mut::dependency::Dependency;
2829
use crate::util::toml_mut::dependency::GitSource;
@@ -77,7 +78,9 @@ pub fn add(workspace: &Workspace<'_>, options: &AddOptions<'_>) -> CargoResult<(
7778
let mut registry = PackageRegistry::new(options.config)?;
7879

7980
let deps = {
80-
let _lock = options.config.acquire_package_cache_lock()?;
81+
let _lock = options
82+
.config
83+
.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
8184
registry.lock_patches();
8285
options
8386
.dependencies

src/cargo/ops/cargo_generate_lockfile.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::core::resolver::features::{CliFeatures, HasDevUnits};
33
use crate::core::{PackageId, PackageIdSpec};
44
use crate::core::{Resolve, SourceId, Workspace};
55
use crate::ops;
6+
use crate::util::cache_lock::CacheLockMode;
67
use crate::util::config::Config;
78
use crate::util::style;
89
use crate::util::CargoResult;
@@ -48,7 +49,9 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes
4849

4950
// Updates often require a lot of modifications to the registry, so ensure
5051
// that we're synchronized against other Cargos.
51-
let _lock = ws.config().acquire_package_cache_lock()?;
52+
let _lock = ws
53+
.config()
54+
.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
5255

5356
let max_rust_version = ws.rust_version();
5457

src/cargo/ops/cargo_package.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::core::{registry::PackageRegistry, resolver::HasDevUnits};
1313
use crate::core::{Feature, Shell, Verbosity, Workspace};
1414
use crate::core::{Package, PackageId, PackageSet, Resolve, SourceId};
1515
use crate::sources::PathSource;
16+
use crate::util::cache_lock::CacheLockMode;
1617
use crate::util::config::JobsConfig;
1718
use crate::util::errors::CargoResult;
1819
use crate::util::toml::TomlManifest;
@@ -806,7 +807,7 @@ pub fn check_yanked(
806807
) -> CargoResult<()> {
807808
// Checking the yanked status involves taking a look at the registry and
808809
// maybe updating files, so be sure to lock it here.
809-
let _lock = config.acquire_package_cache_lock()?;
810+
let _lock = config.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
810811

811812
let mut sources = pkg_set.sources_mut();
812813
let mut pending: Vec<PackageId> = resolve.iter().collect();

src/cargo/ops/common_for_install_and_uninstall.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::ops::{self, CompileFilter, CompileOptions};
1717
use crate::sources::source::QueryKind;
1818
use crate::sources::source::Source;
1919
use crate::sources::PathSource;
20+
use crate::util::cache_lock::CacheLockMode;
2021
use crate::util::errors::CargoResult;
2122
use crate::util::Config;
2223
use crate::util::{FileLock, Filesystem};
@@ -536,7 +537,7 @@ where
536537
// This operation may involve updating some sources or making a few queries
537538
// which may involve frobbing caches, as a result make sure we synchronize
538539
// with other global Cargos
539-
let _lock = config.acquire_package_cache_lock()?;
540+
let _lock = config.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
540541

541542
if needs_update {
542543
source.invalidate_cache();
@@ -604,7 +605,7 @@ where
604605
// This operation may involve updating some sources or making a few queries
605606
// which may involve frobbing caches, as a result make sure we synchronize
606607
// with other global Cargos
607-
let _lock = config.acquire_package_cache_lock()?;
608+
let _lock = config.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
608609

609610
source.invalidate_cache();
610611

src/cargo/ops/registry/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use crate::core::SourceId;
2222
use crate::sources::source::Source;
2323
use crate::sources::{RegistrySource, SourceConfigMap};
2424
use crate::util::auth;
25+
use crate::util::cache_lock::CacheLockMode;
2526
use crate::util::config::{Config, PathAndArgs};
2627
use crate::util::errors::CargoResult;
2728
use crate::util::network::http::http_handle;
@@ -131,7 +132,7 @@ fn registry(
131132
}
132133

133134
let cfg = {
134-
let _lock = config.acquire_package_cache_lock()?;
135+
let _lock = config.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
135136
let mut src = RegistrySource::remote(source_ids.replacement, &HashSet::new(), config)?;
136137
// Only update the index if `force_update` is set.
137138
if force_update {

0 commit comments

Comments
 (0)