Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: use rayon to parallelize directory operations #1941

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.

1 change: 1 addition & 0 deletions yazi-fs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ futures = { workspace = true }
regex = { workspace = true }
serde = { workspace = true }
tokio = { workspace = true }
rayon = "1.10.0"

[target."cfg(unix)".dependencies]
libc = { workspace = true }
Expand Down
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
Loading