Enhance OSDK performance by using hard link instead of copy

This commit is contained in:
Ruize Tang
2024-12-09 17:03:58 +08:00
committed by Tate, Hongliang Tian
parent 7601509e6e
commit 9d82ac8958
6 changed files with 37 additions and 19 deletions

View File

@ -1,12 +1,9 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
use std::{ use std::path::{Path, PathBuf};
fs,
path::{Path, PathBuf},
};
use super::file::BundleFile; use super::file::BundleFile;
use crate::arch::Arch; use crate::{arch::Arch, util::hard_link_or_copy};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AsterBin { pub struct AsterBin {
@ -87,7 +84,7 @@ impl AsterBin {
pub fn copy_to(self, base: impl AsRef<Path>) -> Self { pub fn copy_to(self, base: impl AsRef<Path>) -> Self {
let file_name = self.path.file_name().unwrap(); let file_name = self.path.file_name().unwrap();
let copied_path = base.as_ref().join(file_name); let copied_path = base.as_ref().join(file_name);
fs::copy(&self.path, copied_path).unwrap(); hard_link_or_copy(&self.path, copied_path).unwrap();
Self { Self {
path: PathBuf::from(file_name), path: PathBuf::from(file_name),
arch: self.arch, arch: self.arch,

View File

@ -7,6 +7,8 @@ use std::{
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use crate::util::hard_link_or_copy;
/// A trait for files in a bundle. The file in a bundle should have it's digest and be validatable. /// A trait for files in a bundle. The file in a bundle should have it's digest and be validatable.
pub trait BundleFile { pub trait BundleFile {
fn path(&self) -> &PathBuf; fn path(&self) -> &PathBuf;
@ -57,7 +59,7 @@ impl Initramfs {
pub fn copy_to(self, base: impl AsRef<Path>) -> Self { pub fn copy_to(self, base: impl AsRef<Path>) -> Self {
let name = self.path.file_name().unwrap(); let name = self.path.file_name().unwrap();
let dest = base.as_ref().join(name); let dest = base.as_ref().join(name);
fs::copy(&self.path, dest).unwrap(); hard_link_or_copy(&self.path, dest).unwrap();
Self { Self {
path: PathBuf::from(name), path: PathBuf::from(name),
..self ..self

View File

@ -1,9 +1,8 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
use std::{ use std::path::{Path, PathBuf};
fs,
path::{Path, PathBuf}, use crate::util::hard_link_or_copy;
};
use super::file::BundleFile; use super::file::BundleFile;
@ -63,8 +62,7 @@ impl AsterVmImage {
pub fn copy_to(self, base: impl AsRef<Path>) -> Self { pub fn copy_to(self, base: impl AsRef<Path>) -> Self {
let file_name = self.path.file_name().unwrap(); let file_name = self.path.file_name().unwrap();
let copied_path = base.as_ref().join(file_name); let copied_path = base.as_ref().join(file_name);
fs::copy(&self.path, copied_path).unwrap(); hard_link_or_copy(&self.path, copied_path).unwrap();
fs::remove_file(&self.path).unwrap();
Self { Self {
path: PathBuf::from(file_name), path: PathBuf::from(file_name),
typ: self.typ, typ: self.typ,

View File

@ -17,7 +17,7 @@ use crate::{
bin::{AsterBin, AsterBinType, AsterBzImageMeta, AsterElfMeta}, bin::{AsterBin, AsterBinType, AsterBzImageMeta, AsterElfMeta},
file::BundleFile, file::BundleFile,
}, },
util::get_current_crate_info, util::{get_current_crate_info, hard_link_or_copy},
}; };
pub fn make_install_bzimage( pub fn make_install_bzimage(
@ -115,7 +115,7 @@ pub fn make_elf_for_qemu(install_dir: impl AsRef<Path>, elf: &AsterBin, strip: b
} }
} else { } else {
// Copy the ELF file. // Copy the ELF file.
std::fs::copy(elf.path(), &result_elf_path).unwrap(); hard_link_or_copy(elf.path(), &result_elf_path).unwrap();
} }
if elf.arch() == Arch::X86_64 { if elf.arch() == Arch::X86_64 {

View File

@ -16,7 +16,7 @@ use crate::{
scheme::{ActionChoice, BootProtocol}, scheme::{ActionChoice, BootProtocol},
Config, Config,
}, },
util::get_current_crate_info, util::{get_current_crate_info, hard_link_or_copy},
}; };
pub fn create_bootdev_image( pub fn create_bootdev_image(
@ -42,7 +42,7 @@ pub fn create_bootdev_image(
// Copy the initramfs to the boot directory. // Copy the initramfs to the boot directory.
if let Some(init_path) = &initramfs_path { if let Some(init_path) = &initramfs_path {
fs::copy( hard_link_or_copy(
init_path.as_ref().to_str().unwrap(), init_path.as_ref().to_str().unwrap(),
iso_root.join("boot").join("initramfs.cpio.gz"), iso_root.join("boot").join("initramfs.cpio.gz"),
) )
@ -63,7 +63,7 @@ pub fn create_bootdev_image(
_ => { _ => {
// Copy the kernel image to the boot directory. // Copy the kernel image to the boot directory.
let target_path = iso_root.join("boot").join(&target_name); let target_path = iso_root.join("boot").join(&target_name);
fs::copy(aster_bin.path(), target_path).unwrap(); hard_link_or_copy(aster_bin.path(), target_path).unwrap();
} }
}; };

View File

@ -3,7 +3,7 @@
use std::{ use std::{
ffi::OsStr, ffi::OsStr,
fs::{self, File}, fs::{self, File},
io::{BufRead, BufReader, Write}, io::{BufRead, BufReader, Result, Write},
path::{Path, PathBuf}, path::{Path, PathBuf},
process::Command, process::Command,
}; };
@ -290,3 +290,24 @@ impl Drop for DirGuard {
std::env::set_current_dir(&self.0).unwrap(); std::env::set_current_dir(&self.0).unwrap();
} }
} }
/// Attempts to create a hard link from `from` to `to`.
/// If the hard link operation fails (e.g., due to crossing file systems),
/// it falls back to performing a file copy.
///
/// # Arguments
/// - `from`: The source file path.
/// - `to`: The destination file path.
///
/// # Returns
/// - `Ok(0)` if the hard link is successfully created (no data was copied).
/// - `Ok(size)` where `size` is the number of bytes copied if the hard link failed and a copy was performed.
/// - `Err(error)` if an error occurred during the copy operation.
pub fn hard_link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<u64> {
if fs::hard_link(&from, &to).is_err() {
info!("Copying {:?} -> {:?}", from.as_ref(), to.as_ref());
return fs::copy(from, to);
}
info!("Linking {:?} -> {:?}", from.as_ref(), to.as_ref());
Ok(0)
}