Skip to content

Commit

Permalink
perf: use rayon to parallelize directory operations
Browse files Browse the repository at this point in the history
  • Loading branch information
Integral-Tech committed Dec 21, 2024
1 parent 5bd71bf commit 9d4057a
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 33 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 37 additions & 29 deletions yazi-fs/src/fns.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::{borrow::Cow, collections::{HashMap, HashSet, VecDeque}, ffi::{OsStr, OsString}, path::{Path, PathBuf}};
use std::{borrow::Cow, collections::{HashMap, HashSet}, ffi::{OsStr, OsString}, path::{Path, PathBuf}};

use anyhow::{Result, bail};
use tokio::{fs, io, select, sync::{mpsc, oneshot}, time};
use rayon::prelude::*;

use super::Cha;

Expand Down Expand Up @@ -155,28 +156,28 @@ pub async fn realname_unchecked<'a>(
}
}

pub async fn calculate_size(path: &Path) -> u64 {
let mut total = 0;
let mut stack = VecDeque::from([path.to_path_buf()]);
while let Some(path) = stack.pop_front() {
let Ok(meta) = fs::symlink_metadata(&path).await else { continue };
if !meta.is_dir() {
total += meta.len();
continue;
}
pub async fn calculate_size(path: &Path) -> io::Result<u64> {
let path = path.to_path_buf();
tokio::task::spawn_blocking(move || _calculate_size(&path)).await?
}

let Ok(mut it) = fs::read_dir(path).await else { continue };
while let Ok(Some(entry)) = it.next_entry().await {
let Ok(meta) = entry.metadata().await else { continue };
fn _calculate_size(path: &Path) -> io::Result<u64> {
let entries: Vec<_> = std::fs::read_dir(&path)?.collect();

if meta.is_dir() {
stack.push_back(entry.path());
} else {
total += meta.len();
}
let total = entries.par_iter().filter_map(|entry| {
match entry {
Ok(entry) => {
match entry.metadata() {
Ok(meta) if meta.is_file() => Some(meta.len()),
Ok(meta) if meta.is_dir() => _calculate_size(&entry.path()).ok(),
_ => None,
}
},
_ => None,
}
}
total
}).sum();

Ok(total)
}

pub fn copy_with_progress(
Expand Down Expand Up @@ -284,18 +285,25 @@ async fn _copy_with_progress(from: PathBuf, to: PathBuf, cha: Cha) -> io::Result
}
}

pub async fn remove_dir_clean(dir: &Path) {
let Ok(mut it) = fs::read_dir(dir).await else { return };
pub async fn remove_dir_clean(dir: &Path) -> io::Result<()> {
let dir = dir.to_path_buf();
tokio::task::spawn_blocking(move || _remove_dir_clean(&dir)).await?
}

fn _remove_dir_clean(dir: &Path) -> io::Result<()> {
let entries: Vec<_> = std::fs::read_dir(&dir)?.collect();

while let Ok(Some(entry)) = it.next_entry().await {
if entry.file_type().await.is_ok_and(|t| t.is_dir()) {
let path = entry.path();
Box::pin(remove_dir_clean(&path)).await;
fs::remove_dir(path).await.ok();
entries.par_iter().for_each(|entry| {
match entry {
Ok(entry) if entry.file_type().is_ok_and(|t| t.is_dir()) => {
let _ = _remove_dir_clean(&entry.path());
let _ = std::fs::remove_dir(&entry.path());
}
_ => (),
}
}
});

fs::remove_dir(dir).await.ok();
std::fs::remove_dir(&dir)
}

// Convert a file mode to a string representation
Expand Down
2 changes: 1 addition & 1 deletion yazi-plugin/src/fs/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ fn remove(lua: &Lua) -> mlua::Result<Function> {
b"file" => fs::remove_file(&*url).await,
b"dir" => fs::remove_dir(&*url).await,
b"dir_all" => fs::remove_dir_all(&*url).await,
b"dir_clean" => Ok(remove_dir_clean(&url).await),
b"dir_clean" => Ok(remove_dir_clean(&url).await?),
_ => Err("Removal type must be 'file', 'dir', 'dir_all', or 'dir_clean'".into_lua_err())?,
};

Expand Down
2 changes: 1 addition & 1 deletion yazi-scheduler/src/file/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ impl File {

pub async fn trash(&self, mut task: FileOpTrash) -> Result<()> {
let id = task.id;
task.length = calculate_size(&task.target).await;
task.length = calculate_size(&task.target).await?;

self.prog.send(TaskProg::New(id, task.length))?;
self.queue(FileOp::Trash(task), LOW).await?;
Expand Down
2 changes: 1 addition & 1 deletion yazi-scheduler/src/prework/prework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl Prework {
self.prog.send(TaskProg::Adv(task.id, 1, 0))?;
}
PreworkOp::Size(task) => {
let length = calculate_size(&task.target).await;
let length = calculate_size(&task.target).await?;
task.throttle.done((task.target, length), |buf| {
{
let mut loading = self.size_loading.write();
Expand Down
2 changes: 1 addition & 1 deletion yazi-scheduler/src/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl Scheduler {
Box::new(move |canceled: bool| {
async move {
if !canceled {
remove_dir_clean(&from).await;
let _ = remove_dir_clean(&from).await;
Pump::push_move(from, to);
}
ongoing.lock().try_remove(id, TaskStage::Hooked);
Expand Down
1 change: 1 addition & 0 deletions yazi-shared/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ ratatui = { workspace = true }
serde = { workspace = true }
shell-words = { workspace = true }
tokio = { workspace = true }
rayon = "1.10.0"

[target."cfg(unix)".dependencies]
libc = { workspace = true }
Expand Down

0 comments on commit 9d4057a

Please sign in to comment.