Add shared cache with file lock to prevent redundant parallel downloads.

This commit is contained in:
Alejandro Cabeza Romero 2026-05-14 13:50:20 +02:00
parent 9d6ab94d5f
commit ca118adbfe
No known key found for this signature in database
GPG Key ID: DA3D14AE478030FD
4 changed files with 38 additions and 6 deletions

14
rust/Cargo.lock generated
View File

@ -79,6 +79,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.61.2",
]
[[package]]
name = "fd-lock"
version = "4.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78"
dependencies = [
"cfg-if",
"rustix",
"windows-sys 0.52.0",
]
@ -177,6 +188,7 @@ name = "logos-blockchain-circuits-build"
version = "0.5.0"
dependencies = [
"dirs",
"fd-lock",
"flate2",
"tar",
"ureq",
@ -329,7 +341,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
"windows-sys 0.61.2",
]
[[package]]

View File

@ -32,6 +32,7 @@ lbc-types = { default-features = false, package = "logos-blockchain-circuits-typ
# External
dirs = "^6"
fd-lock = "^4"
flate2 = "^1.1"
libc = "^0.2"
tar = "^0.4"

View File

@ -10,13 +10,14 @@ repository.workspace = true
version.workspace = true
[features]
prebuilt = ["dep:dirs", "dep:flate2", "dep:tar", "dep:ureq"]
prebuilt = ["dep:dirs", "dep:fd-lock", "dep:flate2", "dep:tar", "dep:ureq"]
[lints]
workspace = true
[dependencies]
dirs = { workspace = true, optional = true }
fd-lock = { workspace = true, optional = true }
flate2 = { workspace = true, optional = true }
tar = { workspace = true, optional = true }
ureq = { workspace = true, optional = true }

View File

@ -59,7 +59,18 @@ mod prebuilt {
unpacked_library_directory
}
fn cache_dir() -> PathBuf {
/// Produce a lockfile for the given directory
fn get_lockfile(directory: &Path) -> fd_lock::RwLock<std::fs::File> {
let file = std::fs::OpenOptions::new()
.create(true)
.truncate(false)
.write(true)
.open(directory.join(".lock"))
.expect("Failed to open cache lock file.");
fd_lock::RwLock::new(file)
}
fn get_cache_dir() -> PathBuf {
dirs::cache_dir()
.expect("Could not determine the cache directory for this platform.")
.join("logos")
@ -71,13 +82,22 @@ mod prebuilt {
let os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
let cache = cache_dir();
let cache = get_cache_dir();
// The tarball unpacks to a top-level `{artifact_name}/` dir, so the circuit lives at
// `cache/{artifact_name}/{circuit_name}/`.
let circuit_dir = cache
.join(build_artifact_name(version, &os, &arch))
.join(circuit_name);
std::fs::create_dir_all(&cache).expect("Failed to create the cache directory.");
// Since the circuits' libraries are all contained in the same single artifact, each crate
// will try to download the same circuits.
// To avoid redundant downloads, we use a lock to ensure that only one process fetches the
// circuits while the others wait for it to complete and then re-check the cache.
let mut lock = get_lockfile(&cache);
let _guard = lock.write().expect("Failed to acquire cache lock.");
if circuit_dir.is_dir() {
println!(
"Found a cached {circuit_name} library at {}, reusing.",
@ -86,8 +106,6 @@ mod prebuilt {
return circuit_dir;
}
std::fs::create_dir_all(&cache).expect("Failed to create cache directory.");
println!(
"No cached download found, downloading {circuit_name} v{version} for {os}-{arch}..."
);