further speed up creation of Files

This commit is contained in:
rabite 2020-01-27 17:39:42 +01:00
parent 5899ee9b65
commit c8e6ea51bb
3 changed files with 63 additions and 219 deletions

View File

@ -476,23 +476,21 @@ impl FileBrowser {
self.prev_cwd = Some(self.cwd.clone()); self.prev_cwd = Some(self.cwd.clone());
self.cwd = dir.clone(); self.cwd = dir.clone();
let file_source = FileSource::Path(self.cwd.clone());
let main_async_widget = self.main_async_widget_mut()?; let main_async_widget = self.main_async_widget_mut()?;
main_async_widget.change_to(move |stale: &Stale, core| { main_async_widget.change_to(move |stale: &Stale, core| {
let (selected_file, files) = cache.get_files(&dir, stale.clone())?; let view = ListView::builder(core, file_source)
let files = files.run_sync()?; .meta_all()
.prerender()
.with_cache(cache)
.with_stale(stale.clone())
.build()?;
let mut list = ListView::new(&core, files); Ok(view)
list.content.meta_set_fresh().log();
list.content.meta_all();
if let Some(file) = selected_file {
list.select_file(&file);
}
Ok(list)
}).log(); }).log();
if let Ok(grand_parent) = self.cwd()?.parent_as_file() { if let Ok(grand_parent) = self.cwd()?.parent_as_file() {
self.left_widget_goto(&grand_parent).log(); self.left_widget_goto(&grand_parent).log();
} else { } else {
@ -513,18 +511,19 @@ impl FileBrowser {
} }
let cache = self.fs_cache.clone(); let cache = self.fs_cache.clone();
let dir = dir.clone(); let file_source = FileSource::Path(dir.clone());
let left_async_widget = self.left_async_widget_mut()?; let left_async_widget = self.left_async_widget_mut()?;
left_async_widget.change_to(move |stale, core| { left_async_widget.change_to(move |stale, core| {
let cached_files = cache.get_files(&dir, stale.clone())?; let view = ListView::builder(core, file_source)
let (_, files) = cached_files; .meta_all()
.prerender()
.with_cache(cache)
.with_stale(stale.clone())
.build()?;
let files = files.run_sync()?; Ok(view)
}).log();
let list = ListView::new(&core, files);
Ok(list)
})?;
Ok(()) Ok(())
} }

View File

@ -344,8 +344,7 @@ impl Files {
None None
} else { } else {
let file = File::new_from_direntry(file, let file = File::new_from_direntry(file,
Some(dirty_meta.clone()), Some(dirty_meta.clone()));
stale.clone());
Some(file) Some(file)
} }
}) })
@ -470,7 +469,7 @@ impl Files {
} }
match (a.meta(), b.meta()) { match (a.meta(), b.meta()) {
(Ok(a_meta), Ok(b_meta)) => { (Some(a_meta), Some(b_meta)) => {
match a_meta.size() == b_meta.size() { match a_meta.size() == b_meta.size() {
true => compare_str(&b.name, &a.name), true => compare_str(&b.name, &a.name),
false => b_meta.size() false => b_meta.size()
@ -496,7 +495,7 @@ impl Files {
} }
match (a.meta(), b.meta()) { match (a.meta(), b.meta()) {
(Ok(a_meta), Ok(b_meta)) => { (Some(a_meta), Some(b_meta)) => {
match a_meta.mtime() == b_meta.mtime() { match a_meta.mtime() == b_meta.mtime() {
true => compare_str(&b.name, &a.name), true => compare_str(&b.name, &a.name),
false => b_meta.mtime() false => b_meta.mtime()
@ -621,59 +620,22 @@ impl Files {
} }
pub fn meta_all_sync(&mut self) -> HResult<()> { pub fn meta_all_sync(&mut self) -> HResult<()> {
let mut same = true;
for file in self.iter_files_mut() { for file in self.iter_files_mut() {
if !file.meta_processed { if !file.meta_processed {
file.meta_sync().log(); file.meta_sync().log();
same = false;
} }
} }
if !same {
self.set_dirty(); self.set_dirty();
}
Ok(()) Ok(())
} }
pub fn meta_all(&mut self) {
let len = self.len();
self.meta_upto(len, None);
self.dirty_meta.set_dirty();
self.meta_set_fresh().log();
}
pub fn meta_upto(&mut self, to: usize, sender: Option<Sender<Events>>) {
let meta_files = if self.meta_upto > Some(to) {
self.meta_upto.unwrap()
} else {
if to > self.len() {
self.len()
} else {
to
}
};
if self.meta_upto >= Some(meta_files) && !self.dirty_meta.is_dirty() { return }
self.set_dirty();
self.dirty_meta.set_clean();
let meta_pool = make_pool(sender.clone());
for file in self.iter_files_mut()
.take(meta_files) {
if !file.meta_processed {
file.take_meta(&meta_pool).ok();
}
if file.is_dir() {
file.take_dirsize(&meta_pool).ok();
}
}
self.meta_upto = Some(meta_files);
}
pub fn meta_set_fresh(&self) -> HResult<()> {
self.iter_files().nth(0)?.meta.set_fresh()?;
Ok(())
}
pub fn set_filter(&mut self, filter: Option<String>) { pub fn set_filter(&mut self, filter: Option<String>) {
self.filter = filter; self.filter = filter;
@ -771,10 +733,10 @@ pub struct File {
pub path: PathBuf, pub path: PathBuf,
pub hidden: bool, pub hidden: bool,
pub kind: Kind, pub kind: Kind,
pub dirsize: Option<Async<usize>>, pub dirsize: Option<usize>,
pub target: Option<PathBuf>, pub target: Option<PathBuf>,
pub color: Option<lscolors::Color>, pub color: Option<lscolors::Color>,
pub meta: Async<Metadata>, pub meta: Option<Metadata>,
pub dirty_meta: Option<AsyncDirtyBit>, pub dirty_meta: Option<AsyncDirtyBit>,
pub meta_processed: bool, pub meta_processed: bool,
pub selected: bool, pub selected: bool,
@ -787,19 +749,15 @@ impl File {
path: PathBuf, path: PathBuf,
dirty_meta: Option<AsyncDirtyBit>) -> File { dirty_meta: Option<AsyncDirtyBit>) -> File {
let hidden = name.starts_with("."); let hidden = name.starts_with(".");
let meta = File::make_async_meta(&path, dirty_meta.clone(), None);
let dirsize = if path.is_dir() {
Some(File::make_async_dirsize(&path, dirty_meta.clone(), None))
} else { None };
File { File {
name: name.to_string(), name: name.to_string(),
hidden: hidden, hidden: hidden,
kind: if path.is_dir() { Kind::Directory } else { Kind::File }, kind: if path.is_dir() { Kind::Directory } else { Kind::File },
path: path, path: path,
dirsize: dirsize, dirsize: None,
target: None, target: None,
meta: meta, meta: None,
meta_processed: false, meta_processed: false,
dirty_meta: dirty_meta, dirty_meta: dirty_meta,
color: None, color: None,
@ -810,26 +768,17 @@ impl File {
pub fn new_with_stale(name: &str, pub fn new_with_stale(name: &str,
path: PathBuf, path: PathBuf,
dirty_meta: Option<AsyncDirtyBit>, dirty_meta: Option<AsyncDirtyBit>) -> File {
stale: Stale) -> File {
let hidden = name.starts_with("."); let hidden = name.starts_with(".");
let meta = File::make_async_meta(&path,
dirty_meta.clone(),
Some(stale.clone()));
let dirsize = if path.is_dir() {
Some(File::make_async_dirsize(&path,
dirty_meta.clone(),
Some(stale)))
} else { None };
File { File {
name: name.to_string(), name: name.to_string(),
hidden: hidden, hidden: hidden,
kind: if path.is_dir() { Kind::Directory } else { Kind::File }, kind: if path.is_dir() { Kind::Directory } else { Kind::File },
path: path, path: path,
dirsize: dirsize, dirsize: None,
target: None, target: None,
meta: meta, meta: None,
meta_processed: false, meta_processed: false,
dirty_meta: dirty_meta, dirty_meta: dirty_meta,
color: None, color: None,
@ -839,8 +788,7 @@ impl File {
} }
pub fn new_from_direntry(direntry: std::fs::DirEntry, pub fn new_from_direntry(direntry: std::fs::DirEntry,
dirty_meta: Option<AsyncDirtyBit>, dirty_meta: Option<AsyncDirtyBit>) -> File {
stale: Stale) -> File {
let path = direntry.path(); let path = direntry.path();
let name = direntry.file_name() let name = direntry.file_name()
.to_string_lossy() .to_string_lossy()
@ -855,25 +803,14 @@ impl File {
_ => Kind::Placeholder _ => Kind::Placeholder
}; };
let meta = File::make_async_meta(&path,
dirty_meta.clone(),
Some(stale.clone()));
let dirsize = match kind {
Kind::Directory => Some(File::make_async_dirsize(&path,
dirty_meta.clone(),
Some(stale.clone()))),
_ => None
};
File { File {
name: name, name: name,
hidden: hidden, hidden: hidden,
kind: kind, kind: kind,
path: path, path: path,
dirsize: dirsize, dirsize: None,
target: None, target: None,
meta: meta, meta: None,
meta_processed: false, meta_processed: false,
dirty_meta: dirty_meta, dirty_meta: dirty_meta,
color: None, color: None,
@ -907,104 +844,24 @@ impl File {
} }
pub fn meta_sync(&mut self) -> HResult<()> { pub fn meta_sync(&mut self) -> HResult<()> {
let stale = self.meta.get_stale(); let meta = std::fs::symlink_metadata(&self.path)?;
let meta = std::fs::metadata(&self.path)?; self.meta = Some(meta);
self.meta = Async::new_with_value(meta);
self.meta.put_stale(stale);
self.process_meta().log(); self.process_meta().log();
if self.is_dir() { if self.is_dir() {
let dirsize = self.dirsize let dirsize = std::fs::read_dir(&self.path)?.count();
.take() self.dirsize = Some(dirsize);
.map(|s| s.run_sync())??;
self.dirsize = Some(Async::new_with_value(dirsize));
} }
Ok(()) Ok(())
} }
pub fn make_async_meta(path: &PathBuf, pub fn meta(&self) -> Option<&Metadata> {
dirty_meta: Option<AsyncDirtyBit>, self.meta.as_ref()
stale_preview: Option<Stale>) -> Async<Metadata> {
let path = path.clone();
let mut meta = Async::new(move |stale: &Stale| {
if stale.is_stale()? { HError::stale()? }
Ok(std::fs::symlink_metadata(&path)?)
});
stale_preview.map(|s| meta.put_stale(s));
dirty_meta.map(|mut d|
meta.on_ready(move |_,_| {
d.set_dirty();
Ok(())
}).log()
);
meta
}
pub fn make_async_dirsize(path: &PathBuf,
dirty_meta: Option<AsyncDirtyBit>,
stale_preview: Option<Stale>) -> Async<usize> {
let path = path.clone();
let mut dirsize = Async::new(move |stale: &Stale| {
if stale.is_stale()? { HError::stale()? }
Ok(std::fs::read_dir(&path)?.count())
});
stale_preview.map(|s| dirsize.put_stale(s));
dirty_meta.map(|mut d|
dirsize.on_ready(move |_,_| {
d.set_dirty();
Ok(())
}).log()
);
dirsize
}
pub fn meta(&self) -> HResult<&Metadata> {
Ok(self.meta.get()?)
}
fn take_dirsize(&mut self,
pool: &ThreadPool) -> HResult<()> {
let dirsize = self.dirsize.as_mut()?;
if let Ok(_) = dirsize.value { return Ok(()) }
if !dirsize.is_running() && !dirsize.is_ready() {
dirsize.run_pooled(Some(&*pool))?;
}
if dirsize.is_ready() {
dirsize.pull_async()?;
}
Ok(())
}
pub fn take_meta(&mut self,
pool: &ThreadPool) -> HResult<()> {
if self.meta_processed { return Ok(()) }
if !self.meta.is_running() && !self.meta.is_ready() {
self.meta.run_pooled(Some(&*pool))?;
}
if self.meta.is_ready() {
self.meta.pull_async()?;
self.process_meta()?;
}
Ok(())
} }
pub fn process_meta(&mut self) -> HResult<()> { pub fn process_meta(&mut self) -> HResult<()> {
if let Ok(meta) = self.meta.get() { if let Some(ref meta) = self.meta {
let color = self.get_color(&meta); let color = self.get_color(&meta);
let target = if meta.file_type().is_symlink() { let target = if meta.file_type().is_symlink() {
self.path.read_link().ok() self.path.read_link().ok()
@ -1019,18 +876,7 @@ impl File {
pub fn reload_meta(&mut self) -> HResult<()> { pub fn reload_meta(&mut self) -> HResult<()> {
self.meta_processed = false; self.meta_processed = false;
self.meta = File::make_async_meta(&self.path, self.meta_sync()
self.dirty_meta.clone(),
None);
self.meta.run()?;
if self.dirsize.is_some() {
self.dirsize = Some(File::make_async_dirsize(&self.path,
self.dirty_meta.clone(),
None));
self.dirsize.as_mut()?.run()?;
}
Ok(())
} }
fn get_color(&self, meta: &std::fs::Metadata) -> Option<lscolors::Color> { fn get_color(&self, meta: &std::fs::Metadata) -> Option<lscolors::Color> {
@ -1042,7 +888,7 @@ impl File {
pub fn calculate_size(&self) -> HResult<(u32, &str)> { pub fn calculate_size(&self) -> HResult<(u32, &str)> {
if let Some(ref dirsize) = self.dirsize { if let Some(ref dirsize) = self.dirsize {
return Ok((*dirsize.value.as_ref().unwrap_or(&0) as u32, "")) return Ok((*dirsize as u32, ""))
} }
@ -1073,7 +919,6 @@ impl File {
// Fix crash in tree_magic when called on non-regular file // Fix crash in tree_magic when called on non-regular file
// Also fix crash when a file doesn't exist any more // Also fix crash when a file doesn't exist any more
self.meta() self.meta()
.ok()
.and_then(|meta| { .and_then(|meta| {
if meta.is_file() && self.path.exists() { if meta.is_file() && self.path.exists() {
let mime = tree_magic::from_filepath(&self.path); let mime = tree_magic::from_filepath(&self.path);
@ -1239,7 +1084,7 @@ impl File {
} }
pub fn pretty_user(&self) -> Option<String> { pub fn pretty_user(&self) -> Option<String> {
if self.meta().is_err() { return None } if self.meta().is_none() { return None }
let uid = self.meta().unwrap().uid(); let uid = self.meta().unwrap().uid();
let file_user = users::get_user_by_uid(uid)?; let file_user = users::get_user_by_uid(uid)?;
let cur_user = users::get_current_username()?; let cur_user = users::get_current_username()?;
@ -1252,7 +1097,7 @@ impl File {
} }
pub fn pretty_group(&self) -> Option<String> { pub fn pretty_group(&self) -> Option<String> {
if self.meta().is_err() { return None } if self.meta().is_none() { return None }
let gid = self.meta().unwrap().gid(); let gid = self.meta().unwrap().gid();
let file_group = users::get_group_by_gid(gid)?; let file_group = users::get_group_by_gid(gid)?;
let cur_group = users::get_current_groupname()?; let cur_group = users::get_current_groupname()?;
@ -1265,7 +1110,7 @@ impl File {
} }
pub fn pretty_mtime(&self) -> Option<String> { pub fn pretty_mtime(&self) -> Option<String> {
if self.meta().is_err() { return None } if self.meta().is_none() { return None }
let time: chrono::DateTime<chrono::Local> let time: chrono::DateTime<chrono::Local>
= chrono::Local.timestamp(self.meta().unwrap().mtime(), 0); = chrono::Local.timestamp(self.meta().unwrap().mtime(), 0);
Some(time.format("%F %R").to_string()) Some(time.format("%F %R").to_string())

View File

@ -108,7 +108,7 @@ impl Listable for ListView<Files> {
.cloned() .cloned()
.unwrap_or_default(); .unwrap_or_default();
if !file.meta.value.is_ok() { if file.meta.is_none() {
file.meta_sync().log(); file.meta_sync().log();
} }
@ -311,7 +311,7 @@ impl FileListBuilder {
pub fn build(self) -> HResult<ListView<Files>> { pub fn build(self) -> HResult<ListView<Files>> {
let c = &self.cache; let c = &self.cache;
let s = self.stale.clone(); let s = self.stale.clone();
let mut files = match self.source { let files = match self.source {
FileSource::Files(f) => Ok(f), FileSource::Files(f) => Ok(f),
FileSource::Path(f) => { FileSource::Path(f) => {
c.as_ref() c.as_ref()