Explorar o código

fix: only store top-level recursive dir size

xempt %!s(int64=2) %!d(string=hai) anos
pai
achega
51097ca495
Modificáronse 7 ficheiros con 40 adicións e 27 borrados
  1. 10 9
      src/fs/file.rs
  2. 19 12
      src/fs/filter.rs
  3. 3 1
      src/main.rs
  4. 1 1
      src/output/details.rs
  5. 1 1
      src/output/grid.rs
  6. 1 1
      src/output/lines.rs
  7. 5 2
      src/output/table.rs

+ 10 - 9
src/fs/file.rs

@@ -516,30 +516,31 @@ impl<'dir> File<'dir> {
 
 
     /// Recursive folder size
     /// Recursive folder size
     #[cfg(unix)]
     #[cfg(unix)]
-    pub fn recursive_size(&self) -> f::Size {
+    pub fn recursive_size(&self, toplevel: bool) -> f::Size {
         use crate::fs::RECURSIVE_SIZE_HASHMAP;
         use crate::fs::RECURSIVE_SIZE_HASHMAP;
         if self.is_directory() {
         if self.is_directory() {
+            let mut recursive_size: u64 = 0;
             let Ok(dir) = Dir::read_dir(self.path.clone()) else {
             let Ok(dir) = Dir::read_dir(self.path.clone()) else {
                 return f::Size::None;
                 return f::Size::None;
             };
             };
             let files = dir.files(super::DotFilter::Dotfiles, None, false, false);
             let files = dir.files(super::DotFilter::Dotfiles, None, false, false);
 
 
-            let mut recursive_size: u64 = 0;
-            for fileresult in files {
-                let Ok(file) = fileresult else { continue };
+            for file in files.flatten() {
                 if file.is_file() {
                 if file.is_file() {
                     recursive_size += file.metadata.size();
                     recursive_size += file.metadata.size();
                 } else {
                 } else {
-                    recursive_size += match file.recursive_size() {
+                    recursive_size += match file.recursive_size(false) {
                         f::Size::Some(s) => s,
                         f::Size::Some(s) => s,
                         _ => file.metadata.size(),
                         _ => file.metadata.size(),
                     };
                     };
                 }
                 }
             }
             }
-            RECURSIVE_SIZE_HASHMAP
-                .lock()
-                .unwrap()
-                .insert(self.metadata.ino(), recursive_size);
+            if toplevel {
+                RECURSIVE_SIZE_HASHMAP
+                    .lock()
+                    .unwrap()
+                    .insert(self.metadata.ino(), recursive_size);
+            }
             f::Size::Some(recursive_size)
             f::Size::Some(recursive_size)
         } else if self.is_char_device() || self.is_block_device() {
         } else if self.is_char_device() || self.is_block_device() {
             let device_id = self.metadata.rdev();
             let device_id = self.metadata.rdev();

+ 19 - 12
src/fs/filter.rs

@@ -108,11 +108,14 @@ impl FileFilter {
     }
     }
 
 
     /// Sort the files in the given vector based on the sort field option.
     /// Sort the files in the given vector based on the sort field option.
-    pub fn sort_files<'a, F>(&self, files: &mut [F])
+    pub fn sort_files<'a, F>(&self, files: &mut [F], total_size: bool)
     where
     where
         F: AsRef<File<'a>>,
         F: AsRef<File<'a>>,
     {
     {
-        files.sort_by(|a, b| self.sort_field.compare_files(a.as_ref(), b.as_ref()));
+        files.sort_by(|a, b| {
+            self.sort_field
+                .compare_files(a.as_ref(), b.as_ref(), total_size)
+        });
 
 
         if self.flags.contains(&FileFilterFlags::Reverse) {
         if self.flags.contains(&FileFilterFlags::Reverse) {
             files.reverse();
             files.reverse();
@@ -231,7 +234,7 @@ impl SortField {
     /// together, so `file10` will sort after `file9`, instead of before it
     /// together, so `file10` will sort after `file9`, instead of before it
     /// because of the `1`.
     /// because of the `1`.
     #[cfg(unix)]
     #[cfg(unix)]
-    pub fn compare_files(self, a: &File<'_>, b: &File<'_>) -> Ordering {
+    pub fn compare_files(self, a: &File<'_>, b: &File<'_>, recursive: bool) -> Ordering {
         use self::SortCase::{ABCabc, AaBbCc};
         use self::SortCase::{ABCabc, AaBbCc};
         use crate::fs::RECURSIVE_SIZE_HASHMAP;
         use crate::fs::RECURSIVE_SIZE_HASHMAP;
 
 
@@ -243,16 +246,20 @@ impl SortField {
             Self::Name(AaBbCc)  => natord::compare_ignore_case(&a.name, &b.name),
             Self::Name(AaBbCc)  => natord::compare_ignore_case(&a.name, &b.name),
 
 
             Self::Size => {
             Self::Size => {
-                let recursive_map = RECURSIVE_SIZE_HASHMAP.lock().unwrap();
-                match recursive_map.get(&a.metadata.ino()) {
-                    Some(s) => *s,
-                    _ => a.metadata.len()
-                }.cmp(
-                    &match recursive_map.get(&b.metadata.ino()) {
+                if recursive {
+                    let recursive_map = RECURSIVE_SIZE_HASHMAP.lock().unwrap();
+                    match recursive_map.get(&a.metadata.ino()) {
                         Some(s) => *s,
                         Some(s) => *s,
-                        _ => b.metadata.len()
-                    }
-                )
+                        _ => a.metadata.len()
+                    }.cmp(
+                        &match recursive_map.get(&b.metadata.ino()) {
+                            Some(s) => *s,
+                            _ => b.metadata.len()
+                        }
+                    )
+                } else {
+                    a.metadata.len().cmp(&b.metadata.len())
+                }
             }
             }
 
 
             #[cfg(unix)]
             #[cfg(unix)]

+ 3 - 1
src/main.rs

@@ -271,7 +271,9 @@ impl<'args> Exa<'args> {
             }
             }
 
 
             self.options.filter.filter_child_files(&mut children);
             self.options.filter.filter_child_files(&mut children);
-            self.options.filter.sort_files(&mut children);
+            self.options
+                .filter
+                .sort_files(&mut children, self.options.view.total_size);
 
 
             if let Some(recurse_opts) = self.options.dir_action.recurse_options() {
             if let Some(recurse_opts) = self.options.dir_action.recurse_options() {
                 let depth = dir
                 let depth = dir

+ 1 - 1
src/output/details.rs

@@ -317,7 +317,7 @@ impl<'a> Render<'a> {
 
 
         // this is safe because all entries have been initialized above
         // this is safe because all entries have been initialized above
         let mut file_eggs = unsafe { std::mem::transmute::<_, Vec<Egg<'_>>>(file_eggs) };
         let mut file_eggs = unsafe { std::mem::transmute::<_, Vec<Egg<'_>>>(file_eggs) };
-        self.filter.sort_files(&mut file_eggs);
+        self.filter.sort_files(&mut file_eggs, self.total_size);
 
 
         for (tree_params, egg) in depth.iterate_over(file_eggs.into_iter()) {
         for (tree_params, egg) in depth.iterate_over(file_eggs.into_iter()) {
             let mut files = Vec::new();
             let mut files = Vec::new();

+ 1 - 1
src/output/grid.rs

@@ -41,7 +41,7 @@ impl<'a> Render<'a> {
 
 
         grid.reserve(self.files.len());
         grid.reserve(self.files.len());
 
 
-        self.filter.sort_files(&mut self.files);
+        self.filter.sort_files(&mut self.files, false);
         for file in &self.files {
         for file in &self.files {
             let filename = self.file_style.for_file(file, self.theme);
             let filename = self.file_style.for_file(file, self.theme);
 
 

+ 1 - 1
src/output/lines.rs

@@ -18,7 +18,7 @@ pub struct Render<'a> {
 
 
 impl<'a> Render<'a> {
 impl<'a> Render<'a> {
     pub fn render<W: Write>(mut self, w: &mut W) -> io::Result<()> {
     pub fn render<W: Write>(mut self, w: &mut W) -> io::Result<()> {
-        self.filter.sort_files(&mut self.files);
+        self.filter.sort_files(&mut self.files, false);
         for file in &self.files {
         for file in &self.files {
             let name_cell = self.render_file(file);
             let name_cell = self.render_file(file);
             writeln!(w, "{}", ANSIStrings(&name_cell))?;
             writeln!(w, "{}", ANSIStrings(&name_cell))?;

+ 5 - 2
src/output/table.rs

@@ -455,8 +455,11 @@ impl<'a> Table<'a> {
             Column::Permissions => self.permissions_plus(file, xattrs).render(self.theme),
             Column::Permissions => self.permissions_plus(file, xattrs).render(self.theme),
             Column::FileSize => {
             Column::FileSize => {
                 if total_size {
                 if total_size {
-                    file.recursive_size()
-                        .render(self.theme, self.size_format, &self.env.numeric)
+                    file.recursive_size(true).render(
+                        self.theme,
+                        self.size_format,
+                        &self.env.numeric,
+                    )
                 } else {
                 } else {
                     file.size()
                     file.size()
                         .render(self.theme, self.size_format, &self.env.numeric)
                         .render(self.theme, self.size_format, &self.env.numeric)