From 1c9a1ea9e690c46be1b2430e859b1d2f3bb28bad Mon Sep 17 00:00:00 2001 From: Han Xiaoyang Date: Sun, 13 Jul 2025 11:00:39 +0800 Subject: [PATCH] [scorpio]:mr layer fetch. Signed-off-by: Han Xiaoyang --- scorpio/src/daemon/mod.rs | 16 +++++++-- scorpio/src/fuse/mod.rs | 12 +++++-- scorpio/src/manager/mod.rs | 2 ++ scorpio/src/manager/mr.rs | 71 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 scorpio/src/manager/mr.rs diff --git a/scorpio/src/daemon/mod.rs b/scorpio/src/daemon/mod.rs index 5daa603e1..a3144dc31 100644 --- a/scorpio/src/daemon/mod.rs +++ b/scorpio/src/daemon/mod.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use crate::fuse::MegaFuse; use crate::manager::fetch::fetch; -use crate::manager::{ScorpioManager, WorkDir}; +use crate::manager::{mr, ScorpioManager, WorkDir}; use crate::util::{config, GPath}; use axum::extract::State; use axum::routing::{get, post}; @@ -18,6 +18,7 @@ const FAIL: &str = "Fail"; #[derive(Debug, Deserialize, Serialize)] struct MountRequest { path: String, + mr: Option, // mr is the mount request, used for buck2 temp mount. } #[derive(Debug, Deserialize, Serialize)] @@ -153,7 +154,7 @@ async fn mount_handler( }; let store_path = PathBuf::from(store_path).join(&temp_hash); - let _ = state.fuse.overlay_mount(inode, store_path).await; + let _ = state.fuse.overlay_mount(inode, store_path,false).await; let mount_info = MountInfo { hash: temp_hash.clone(), path: mono_path.clone(), @@ -171,12 +172,21 @@ async fn mount_handler( message: "Directory mounted successfully".to_string(), }); } + + if let Some(m) = &req.mr { + + // if mr is provided, we need to fetch the mr info from mono. + mr::build_mr_layer(m, store_path.into()).await.unwrap(); + + } + // fetch the dionary node info from mono. let work_dir = fetch(&mut ml, inode, mono_path).await.unwrap(); + let store_path = PathBuf::from(store_path).join(&work_dir.hash); // checkout / mount this dictionary. - let _ = state.fuse.overlay_mount(inode, store_path).await; + let _ = state.fuse.overlay_mount(inode, store_path,false).await; let mount_info = MountInfo { hash: work_dir.hash, diff --git a/scorpio/src/fuse/mod.rs b/scorpio/src/fuse/mod.rs index 8b24905d2..9c3112b80 100644 --- a/scorpio/src/fuse/mod.rs +++ b/scorpio/src/fuse/mod.rs @@ -70,7 +70,7 @@ impl MegaFuse { // mount user works. for dir in &manager.works { let _lower = PathBuf::from(store_path).join(&dir.hash); - megafuse.overlay_mount(dir.node, &_lower).await.unwrap(); + megafuse.overlay_mount(dir.node, &_lower,false).await.unwrap(); } megafuse @@ -92,10 +92,16 @@ impl MegaFuse { &self, inode: u64, store_path: P, + need_mr:bool, // if need mr, then create mr layer. ) -> std::io::Result<()> { let lower = store_path.as_ref().join("lower"); let upper = store_path.as_ref().join("upper"); - let lowerdir = vec![lower]; + let mut lowerdir = vec![lower]; + if need_mr { + let mr_path = store_path.as_ref().join("mr"); + let _ = std::fs::create_dir_all(&mr_path); + lowerdir.push(mr_path); + } let upperdir = upper; let config = config::Config { @@ -145,6 +151,8 @@ impl MegaFuse { Ok(()) } + + /// Unmounts the overlay filesystem associated with a given inode asynchronously. /// /// This function removes the overlay filesystem mapped to the specified inode from diff --git a/scorpio/src/manager/mod.rs b/scorpio/src/manager/mod.rs index 47a4bdf31..ca11a40e5 100644 --- a/scorpio/src/manager/mod.rs +++ b/scorpio/src/manager/mod.rs @@ -23,6 +23,8 @@ pub mod push; pub mod reset; pub mod status; pub mod store; +pub mod mr; + #[derive(Serialize, Deserialize)] pub struct ScorpioManager { // pub url:String, diff --git a/scorpio/src/manager/mr.rs b/scorpio/src/manager/mr.rs new file mode 100644 index 000000000..18278ecaa --- /dev/null +++ b/scorpio/src/manager/mr.rs @@ -0,0 +1,71 @@ +use std::path::PathBuf; + +use reqwest::Client; +use serde::Deserialize; + +use crate::util::config; + +/// Single file record +#[derive(Debug, Deserialize)] +struct FileInfo { + action: String, + path: String, + _sha: String, +} + +/// Response body for /files-list endpoint +#[derive(Debug, Deserialize)] +struct FilesListResp { + data: Vec, + err_message: String, + req_result: bool, +} + +pub async fn build_mr_layer( + link: &str, + _mr_path:PathBuf +) -> Result<(), reqwest::Error> { + let files_list = fetch_files_list(link).await?; + + if !files_list.req_result { + println!("{}", files_list.err_message); + return Ok(()); + } + + for file in files_list.data { + if file.action == "remove" { + // ! ! ! Attention: + // As for deleted files, the path should create a `whiteout file`, refer to create_whiteout in other files . + println!("{}", file.path); + } + } + //TODO: Implement the logic to build the MR layer + // This could involve checking out the MR branch, applying changes, etc. + // such as fetch::fetch_by_hashs(&files_list.data, &mr_path) + + println!("MR layer built for link: {link}"); + Ok(()) +} + +/// Fetch the list of files for a Merge Request (MR) +/// +/// - `link`: unique identifier for the MR (used in the path) +/// +/// Returns `FilesListResp` on success, or `reqwest::Error` on failure. +async fn fetch_files_list( + link: &str, +) -> Result { + let url = format!( + "{}/api/v1/mr/{}/files-list", + config::base_url(), + link + ); + + Client::new() + .get(&url) + .send() + .await? + .error_for_status()? + .json::() + .await +}