Skip to content

Commit 8cef669

Browse files
authored
Fix/buck2 isolation dir name (#1913)
* fix(orion): pass buck2 isolation dir as name instead of path Signed-off-by: jerry <1772030600@qq.com> * perf(orion,scorpio): reduce cold FUSE metadata latency for buck2 Signed-off-by: jerry <1772030600@qq.com> * chore: add in-code TODOs for remaining FUSE metadata work Signed-off-by: jerry <1772030600@qq.com> --------- Signed-off-by: jerry <1772030600@qq.com>
1 parent cf8fe42 commit 8cef669

10 files changed

Lines changed: 52 additions & 94 deletions

File tree

common/src/config/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -647,8 +647,6 @@ pub struct BuildConfig {
647647
pub orion_server: String,
648648
#[serde(default)]
649649
pub orion_preheat_shallow_depth: usize,
650-
#[serde(default)]
651-
pub orion_buck2_isolation_dir_base: Option<String>,
652650
}
653651

654652
/// Orion Server configuration (flat structure)

config/config-test.toml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,7 @@ orion_server = "https://orion.gitmega.com"
8787

8888
# Orion worker: shallow preheat depth before buck2 cells/audit.
8989
# 0 means disabled.
90-
orion_preheat_shallow_depth = 0
91-
92-
# Orion worker: base directory for buck2 --isolation-dir.
93-
# Empty means use the system temp directory.
94-
orion_buck2_isolation_dir_base = ""
90+
orion_preheat_shallow_depth = 3
9591

9692

9793
[pack]

config/config-workflow.toml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,7 @@ orion_server = "https://orion.gitmega.com"
8383

8484
# Orion worker: shallow preheat depth before buck2 cells/audit.
8585
# 0 means disabled.
86-
orion_preheat_shallow_depth = 0
87-
88-
# Orion worker: base directory for buck2 --isolation-dir.
89-
# Empty means use the system temp directory.
90-
orion_buck2_isolation_dir_base = ""
86+
orion_preheat_shallow_depth = 3
9187

9288

9389
[pack]

config/config.toml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,7 @@ orion_server = "https://orion.gitmega.com"
8888

8989
# Orion worker: shallow preheat depth before buck2 cells/audit.
9090
# 0 means disabled.
91-
orion_preheat_shallow_depth = 0
92-
93-
# Orion worker: base directory for buck2 --isolation-dir.
94-
# Empty means use the system temp directory.
95-
orion_buck2_isolation_dir_base = ""
91+
orion_preheat_shallow_depth = 3
9692

9793

9894
[pack]

orion/.env.example

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,5 +68,4 @@ ORION_WORKER_START_SCORPIO=true
6868
# ---------------------------------------------------------------------------
6969
# Buck2 Configuration
7070
# ---------------------------------------------------------------------------
71-
BUCK2_ISOLATION_DIR=/tmp/buck2-isolation
7271

orion/Dockerfile

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,7 @@ ENV PATH="/app/bin:/usr/local/bin:${PATH}" \
171171
RUST_LOG=info \
172172
# Scorpio defaults
173173
SCORPIO_STORE_PATH=/data/scorpio/store \
174-
SCORPIO_WORKSPACE=/workspace/mount \
175-
# Buck2 defaults
176-
BUCK2_ISOLATION_DIR=/tmp/buck2-isolation
174+
SCORPIO_WORKSPACE=/workspace/mount
177175

178176
WORKDIR /workspace
179177

orion/src/buck_controller.rs

Lines changed: 14 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ static PROJECT_ROOT: Lazy<String> =
3535
Lazy::new(|| std::env::var("BUCK_PROJECT_ROOT").expect("BUCK_PROJECT_ROOT must be set"));
3636

3737
const MOUNT_TIMEOUT_SECS: u64 = 7200;
38+
const DEFAULT_PREHEAT_SHALLOW_DEPTH: usize = 3;
3839
static BUILD_CONFIG: Lazy<Option<BuildConfig>> = Lazy::new(load_build_config);
3940

4041
/// Mounts filesystem via remote API for repository access.
@@ -411,6 +412,9 @@ async fn unmount_fs(repo: &str, cl: Option<&str>) -> Result<bool, Box<dyn Error
411412

412413
/// Buck2 targets stats every directory, which is slow on FUSE.
413414
/// We pre-warm metadata with `ls -lR` to reduce statx latency.
415+
/// TODO(perf): Replace this full-tree walk with a targeted preheat plan that
416+
/// only touches changed paths + ancestors and buck-critical files
417+
/// (PACKAGE/BUCK/.buckconfig) to avoid duplicated tree scans.
414418
/// TODO: Rewrite the targets logic in the monolith.
415419
fn preheat(repo_path: &Path) -> anyhow::Result<()> {
416420
let preheat_status = std::process::Command::new("ls")
@@ -485,7 +489,7 @@ fn preheat_shallow_depth() -> usize {
485489

486490
build_config()
487491
.map(|config| config.orion_preheat_shallow_depth)
488-
.unwrap_or(0)
492+
.unwrap_or(DEFAULT_PREHEAT_SHALLOW_DEPTH)
489493
}
490494

491495
fn parse_env_usize(key: &str) -> Option<usize> {
@@ -501,21 +505,6 @@ fn parse_env_usize(key: &str) -> Option<usize> {
501505
}
502506
}
503507

504-
fn parse_env_path(key: &str) -> Option<PathBuf> {
505-
match std::env::var(key) {
506-
Ok(value) => {
507-
let trimmed = value.trim();
508-
if trimmed.is_empty() {
509-
tracing::warn!("Empty {key} provided, ignoring.");
510-
None
511-
} else {
512-
Some(PathBuf::from(trimmed))
513-
}
514-
}
515-
Err(_) => None,
516-
}
517-
}
518-
519508
fn build_config() -> Option<&'static BuildConfig> {
520509
BUILD_CONFIG.as_ref()
521510
}
@@ -558,63 +547,26 @@ fn resolve_config_path() -> Option<PathBuf> {
558547
None
559548
}
560549

561-
fn buck2_isolation_dir_base() -> (PathBuf, bool) {
562-
if let Some(path) = parse_env_path("ORION_BUCK2_ISOLATION_DIR_BASE") {
563-
return (path, true);
564-
}
565-
566-
if let Some(path) = parse_env_path("MEGA_BUILD__ORION_BUCK2_ISOLATION_DIR_BASE") {
567-
return (path, true);
568-
}
569-
570-
if let Some(config) = build_config()
571-
&& let Some(path) = config.orion_buck2_isolation_dir_base.as_ref()
572-
{
573-
let trimmed = path.trim();
574-
if !trimmed.is_empty() {
575-
return (PathBuf::from(trimmed), true);
576-
}
577-
}
578-
579-
(std::env::temp_dir(), false)
580-
}
581-
582-
/// Derive a stable per-mount buck2 isolation directory and ensure it exists.
583-
fn buck2_isolation_dir(repo_path: &Path) -> anyhow::Result<PathBuf> {
550+
/// Derive a stable per-mount buck2 isolation directory name.
551+
///
552+
/// Buck2 `--isolation-dir` expects a plain directory **name** (no path
553+
/// separators). Buck2 itself stores daemon state under
554+
/// `<project_root>/.buck2/<isolation_dir>/`, so we only need to return a
555+
/// unique name – not a full path.
556+
fn buck2_isolation_dir(repo_path: &Path) -> anyhow::Result<String> {
584557
let digest = ring::digest::digest(
585558
&ring::digest::SHA256,
586559
repo_path.to_string_lossy().as_bytes(),
587560
);
588561
let suffix = &hex::encode(digest.as_ref())[..16];
589-
let (base, from_env) = buck2_isolation_dir_base();
590-
let mut path = base.join(format!("buck2-isolation-{suffix}"));
591-
if let Err(err) = std::fs::create_dir_all(&path) {
592-
if from_env {
593-
tracing::warn!(
594-
"Failed to create buck2 isolation dir {path:?} from ORION_BUCK2_ISOLATION_DIR_BASE: {err}. Falling back to temp dir."
595-
);
596-
let fallback = std::env::temp_dir();
597-
path = fallback.join(format!("buck2-isolation-{suffix}"));
598-
std::fs::create_dir_all(&path)
599-
.map_err(|err| anyhow!("Failed to create buck2 isolation dir {path:?}: {err}"))?;
600-
} else {
601-
return Err(anyhow!(
602-
"Failed to create buck2 isolation dir {path:?}: {err}"
603-
));
604-
}
605-
}
606-
Ok(path)
562+
Ok(format!("buck2-isolation-{suffix}"))
607563
}
608564

609565
/// Get target of a specific repo under tmp directory.
610566
fn get_repo_targets(file_name: &str, repo_path: &Path) -> anyhow::Result<Targets> {
611567
const MAX_ATTEMPTS: usize = 2;
612568
let jsonl_path = PathBuf::from(repo_path).join(file_name);
613569
let isolation_dir = buck2_isolation_dir(repo_path)?;
614-
let isolation_dir = isolation_dir
615-
.to_str()
616-
.ok_or_else(|| anyhow!("Invalid isolation dir path: {isolation_dir:?}"))?
617-
.to_string();
618570

619571
preheat(repo_path)?;
620572

@@ -669,12 +621,7 @@ async fn get_build_targets(
669621

670622
preheat_shallow(&mount_path, preheat_shallow_depth())?;
671623
let mut buck2 = Buck2::with_root("buck2".to_string(), mount_path.clone());
672-
buck2.set_isolation_dir(
673-
buck2_isolation_dir(&mount_path)?
674-
.to_str()
675-
.ok_or_else(|| anyhow!("Invalid isolation dir path: {mount_path:?}"))?
676-
.to_string(),
677-
);
624+
buck2.set_isolation_dir(buck2_isolation_dir(&mount_path)?);
678625
let mut cells = CellInfo::parse(
679626
&buck2
680627
.cells()
@@ -894,10 +841,6 @@ pub async fn build(
894841
// This ensures buck2 uses the sub-project's .buckconfig and PACKAGE files.
895842
let project_root = PathBuf::from(&mount_point).join(repo_prefix);
896843
let isolation_dir = buck2_isolation_dir(&project_root)?;
897-
let isolation_dir = isolation_dir
898-
.to_str()
899-
.ok_or_else(|| anyhow!("Invalid isolation dir path: {isolation_dir:?}"))?
900-
.to_string();
901844
let mut cmd = Command::new("buck2");
902845
cmd.args(["--isolation-dir", &isolation_dir]);
903846
let cmd = cmd

scorpio/src/antares/fuse.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use libfuse_fs::{
66
};
77
use tokio::task::JoinHandle;
88

9-
use crate::server::mount_filesystem;
9+
use crate::server::{mount_filesystem, mount_filesystem_with_antares_cache};
1010

1111
/// Antares union-fs wrapper: dicfuse lower + passthrough upper/CL.
1212
pub struct AntaresFuse {
@@ -94,7 +94,8 @@ impl AntaresFuse {
9494

9595
let overlay = self.build_overlay().await?;
9696
let logfs = LoggingFileSystem::new(overlay);
97-
let handle = mount_filesystem(logfs, self.mountpoint.as_os_str()).await;
97+
let handle =
98+
mount_filesystem_with_antares_cache(logfs, self.mountpoint.as_os_str(), true).await;
9899

99100
// Spawn background task to run the FUSE session
100101
let fuse_task = tokio::spawn(async move {

scorpio/src/dicfuse/async_io.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ impl Filesystem for Dicfuse {
174174
let child = match child {
175175
Some(v) => v,
176176
None => {
177+
// TODO(perf): add short-lived negative lookup cache for ENOENT
178+
// to avoid repeated misses for Buck2 probe paths.
177179
return Err(std::io::Error::from_raw_os_error(libc::ENOENT).into());
178180
}
179181
};

scorpio/src/server/mod.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,36 @@ use rfuse3::{
5959
MountOptions,
6060
};
6161

62+
#[cfg(target_os = "linux")]
63+
// TODO(perf): tune these values with production lookup metrics and make them
64+
// configurable per mount role (interactive vs build-heavy workers).
65+
const ANTARES_FUSE_CACHE_MOUNT_OPTIONS: &str =
66+
"kernel_cache,auto_cache,entry_timeout=60,attr_timeout=60,negative_timeout=10";
67+
68+
#[cfg(not(target_os = "linux"))]
69+
const ANTARES_FUSE_CACHE_MOUNT_OPTIONS: &str = "";
70+
71+
fn apply_antares_cache_mount_options(options: &mut MountOptions) {
72+
if !ANTARES_FUSE_CACHE_MOUNT_OPTIONS.is_empty() {
73+
options.custom_options(ANTARES_FUSE_CACHE_MOUNT_OPTIONS);
74+
}
75+
}
76+
6277
#[allow(unused)]
6378
pub async fn mount_filesystem<F: Filesystem + std::marker::Sync + Send + 'static>(
6479
fs: F,
6580
mountpoint: &OsStr,
81+
) -> MountHandle {
82+
mount_filesystem_with_antares_cache(fs, mountpoint, false).await
83+
}
84+
85+
#[allow(unused)]
86+
pub async fn mount_filesystem_with_antares_cache<
87+
F: Filesystem + std::marker::Sync + Send + 'static,
88+
>(
89+
fs: F,
90+
mountpoint: &OsStr,
91+
enable_antares_cache: bool,
6692
) -> MountHandle {
6793
if let Err(e) = env_logger::try_init() {
6894
if !e.to_string().contains("initialized") {
@@ -96,6 +122,9 @@ pub async fn mount_filesystem<F: Filesystem + std::marker::Sync + Send + 'static
96122
let mut mount_options = MountOptions::default();
97123
// .allow_other(true)
98124
mount_options.force_readdir_plus(true).uid(uid).gid(gid);
125+
if enable_antares_cache {
126+
apply_antares_cache_mount_options(&mut mount_options);
127+
}
99128

100129
let session = Session::<F>::new(mount_options);
101130
session.mount(fs, mount_path).await.unwrap()

0 commit comments

Comments
 (0)