-
-
Notifications
You must be signed in to change notification settings - Fork 306
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
feat/issue-306-pr #965
base: master
Are you sure you want to change the base?
feat/issue-306-pr #965
Conversation
`src/listing.rs` === * Add `EntrySize` struct * Impl Display for EntrySize * Change `Option<bytesize::ByteSize>` to `EntrySize` in `Entry` * Add Entry::Directory size calculation utilizing WalkDir * Sort directory listings by always putting directories at the top and sorting files and directories based on their own semantics (ie. entry counts for directories and bytes for files) `src/renderer.rs` === * Change `entry_raw` from using `if-let` to just operating on `entry.size`
One thing I didn't look into was setting these behind CLI flags and this probably needs some memoization as it can be just slightly noticeable when looking at parents with a lot of children (or maybe just limiting it down to direct children). |
I think this should probably be behind CLI flags as the performance hit can be severe and we don't want that by default. I will do a proper review a little later. |
Cool stuff! As you already said, a memoization technique would be neat. I think a |
// @if let size = entry.size { | ||
// span.mobile-info.size { | ||
// (maud::display(size)) | ||
// } | ||
// } | ||
} | ||
} | ||
} | ||
} | ||
td.size-cell { | ||
@if let Some(size) = entry.size { | ||
(maud::display(size)) | ||
} | ||
(maud::display(&entry.size)) | ||
// @if let size = entry.size { | ||
// (maud::display(size)) | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's with the commented code here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I didn't remove that since it was the code that would need to be switched on if we were going to throw everything behind a feature flag.
// e2.size | ||
// .unwrap_or_else(|| ByteSize::b(0)) | ||
// .cmp(&e1.size.unwrap_or_else(|| ByteSize::b(0))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also this.
src/listing.rs
Outdated
#[derive(Clone, Copy, PartialEq, Eq)] | ||
/// Possible entry size types | ||
pub enum EntrySize { | ||
/// EntryCount is number of entries in a directory | ||
EntryCount(usize), | ||
/// Bytes is number of bytes in a file | ||
Bytes(bytesize::ByteSize), | ||
} | ||
|
||
impl Display for EntrySize { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
match self { | ||
EntrySize::EntryCount(count) => write!(f, "{}", count), | ||
EntrySize::Bytes(bytes) => write!(f, "{}", bytes), | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be cool to also show the combined directory file size?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what you are referring to by "combined directory file size". Are you referring to the total size in bytes of a directory? That might be a bit expensive and probably would require a persistent cache to be anywhere near fast.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the byte sizes. I recognize it might be too slow. Hm. If you like to, you could try to experiment with this.
A
Definitely. We might be able to shortcut a lot of the issues by just counting direct children by changing the size calculation to call |
src/listing.rs
Outdated
@@ -256,12 +276,14 @@ pub fn directory_listing( | |||
Err(_) => None, | |||
}; | |||
|
|||
let size = WalkDir::new(entry.path()).into_iter().count(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking about it, we might be able to just do .take(UPPER_LIMIT).count()
instead of .count()
to shortcut execution time. So, we might have UPPER_LIMIT
be something like 10001 and if it's more than 10000 we have the Impl Display for EntrySize print >10000
or something along those lines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other option would have been to add an actual timeout, but I'm not really sure how to best do that in a non-async context.
You're going to need a
How about walking through the tree in threads using rayon? Should be fairly easy and it might also allow you to cancel/timeout threads. |
`Cargo.lock` & `Cargo.toml` === * Remove `WalkDir` * Add `fs_extra` * Add `OnceCell` `src/listing.rs` === * remove `use walkdir::WalkDir` * add HashMap, Arc, Mutex, OnceCell, log::warn, and `FILE_SIZE_CACHE` * Cargo fmt
`src/listing.rs` === * Cargo fmt * Replace `WalkDir::new(entry.path()).into_iter().count()` with calculating directory size using `fs_extra::dir::get_size` * If `get_size` fails, fall back to `std::fs::read_dir` counting
Yep, worked like a charm. Thanks for the hint.
Tried rayon and then encountered BurntSushi/walkdir#21. This lead me to look for something other than WalkDir and found fs_extra. I just wanted to get this to a MVP and figure out what flags we want to incorporate (and how to wire them from the config/cli to the call site). So for now I left off the parallel scanning. Looking at That said another option is to spawn a thread that listens for file system notifications and updates the cache on writes, but I'm only aware of Linux's inotify so I'm not sure if it's really cross-platform. Let me know if you have any questions or concerns. |
This would resolve issue #306 with entry counts for directories.
This also resolves issue #964 as I had to define how to compare
EntrySize::EntryCount
andEntrySize::Bytes
.This adds a single dependency
walkdir
to handle counting the number of items in a directory cross-platform. Also, by default it doesn't follow symbolic links which seems fine.