summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCanop <cano.petrole@gmail.com>2019-01-11 17:58:08 +0100
committerCanop <cano.petrole@gmail.com>2019-01-11 17:58:08 +0100
commit8fff2e2c890fd9b1e1ea26071111af3c5b5654a6 (patch)
treebdcd046c7febb130d83a9c5d0ef5fc6e1f725a31
parentd856a79d9492f171d84ab2193226c7a96e3ab0bb (diff)
search speed up (very notable in case of rare matches)v0.4.5
Some long searches's duration can be divided by 3. This is obtained by - never fetching a path's metadata during the search - less frequently checking the file type Even checking whether a path is of a dir or a file is a very slow operation that we must make as rare as possible.
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--src/file_sizes.rs12
-rw-r--r--src/main.rs2
-rw-r--r--src/tree_build.rs112
5 files changed, 63 insertions, 67 deletions
diff --git a/Cargo.lock b/Cargo.lock
index fcdd340..5af61fe 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -31,7 +31,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "broot"
-version = "0.4.4"
+version = "0.4.5"
dependencies = [
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"custom_error 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/Cargo.toml b/Cargo.toml
index 63003f0..d720002 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "broot"
-version = "0.4.4"
+version = "0.4.5"
authors = ["dystroy <denys.seguret@gmail.com>"]
repository = "https://github.com/Canop/broot"
description = "Fuzzy Search + tree + cd"
diff --git a/src/file_sizes.rs b/src/file_sizes.rs
index 5440c29..e3dd92c 100644
--- a/src/file_sizes.rs
+++ b/src/file_sizes.rs
@@ -46,12 +46,10 @@ impl Size {
if let Ok(md) = e.metadata() {
if md.is_dir() {
dirs.push(e.path());
- } else if md.nlink() > 1 {
- if !inodes.insert(md.ino()) {
- // it was already in the set
- nb_duplicate_inodes += 1;
- continue; // let's not add the size
- }
+ } else if md.nlink() > 1 && !inodes.insert(md.ino()) {
+ // it was already in the set
+ nb_duplicate_inodes += 1;
+ continue; // let's not add the size
}
s += Size::from(md.len());
}
@@ -84,7 +82,7 @@ impl Size {
}
format!("{}{}", v, &SIZE_NAMES[i])
}
- pub fn discreet_ratio(&self, max: Size, r: u64) -> u64 {
+ pub fn discreet_ratio(self, max: Size, r: u64) -> u64 {
if max.0 == 0 || self.0 == 0 {
0
} else {
diff --git a/src/main.rs b/src/main.rs
index 11de12f..18a069b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -45,7 +45,7 @@ use crate::task_sync::TaskLifetime;
use crate::tree_options::TreeOptions;
use crate::verbs::VerbStore;
-const VERSION: &'static str = "0.4.4";
+const VERSION: &str = "0.4.5";
fn get_cli_args<'a>() -> clap::ArgMatches<'a> {
clap::App::new("broot")
diff --git a/src/tree_build.rs b/src/tree_build.rs
index 005acc0..749f017 100644
--- a/src/tree_build.rs
+++ b/src/tree_build.rs
@@ -1,14 +1,12 @@
use std::cmp::{self, Ordering};
use std::collections::{BinaryHeap, VecDeque};
-use std::ffi::OsString;
-use std::fs::{self, Metadata};
+use std::fs;
use std::os::unix::fs::MetadataExt;
use std::path::PathBuf;
use std::time::{Duration, Instant};
use crate::flat_tree::{LineType, Tree, TreeLine};
use crate::git_ignore::GitIgnoreFilter;
-use crate::patterns::Pattern;
use crate::task_sync::TaskLifetime;
use crate::tree_options::{OptionBool, TreeOptions};
@@ -19,8 +17,8 @@ struct BLine {
path: PathBuf,
depth: u16,
name: String,
- children_loaded: bool, // true when load_children has been called already
- children: Vec<usize>, // sorted and filtered (indexes of the children in tree.blines)
+ children_loaded: bool, // true when load_children has been called already
+ children: Vec<usize>, // sorted and filtered (indexes of the children in tree.blines)
next_child_idx: usize, // index for iteration, among the children
line_type: LineType,
has_error: bool,
@@ -37,6 +35,7 @@ enum BLineResult {
FilteredOutByPattern,
FilteredOutAsNonFolder,
GitIgnored,
+ Invalid,
}
impl BLine {
@@ -51,7 +50,7 @@ impl BLine {
} else {
let gif = GitIgnoreFilter::applicable_to(&path);
// if auto, we don't look for other gif if we're not in a git dir
- if respect_ignore == OptionBool::Auto && gif.files.len() == 0 {
+ if respect_ignore == OptionBool::Auto && gif.files.is_empty() {
None
} else {
Some(gif)
@@ -73,35 +72,41 @@ impl BLine {
nb_kept_children: 0,
}
}
- // return a bline if the path directly matches the conditions
- // (pattern, no_hidden, only_folders)
+ // return a bline if the direntry directly matches the options and there's no error
fn from(
parent_idx: usize,
- metadata: Metadata,
- name: OsString,
- path: PathBuf,
+ e: fs::DirEntry,
depth: u16,
- no_hidden: bool,
- only_folders: bool,
- pattern: &Option<Pattern>,
+ options: &TreeOptions,
parent_ignore_filter: &Option<GitIgnoreFilter>,
) -> BLineResult {
- let mut has_match = true;
- let mut score = 0;
- let name = name.to_string_lossy();
- if no_hidden && name.starts_with('.') {
+ let name = e.file_name();
+ let name = match name.to_str() {
+ Some(name) => name,
+ None => {
+ return BLineResult::Invalid;
+ }
+ };
+ if !options.show_hidden && name.starts_with('.') {
return BLineResult::FilteredOutAsHidden;
}
- if let Some(pattern) = pattern {
+ let mut has_match = true;
+ let mut score = 0;
+ if let Some(pattern) = &options.pattern {
if let Some(m) = pattern.test(&name) {
score = m.score;
} else {
has_match = false;
}
}
+ let ft = match e.file_type() {
+ Ok(ft) => ft,
+ Err(_) => {
+ return BLineResult::Invalid;
+ }
+ };
let mut is_dir = false;
let line_type = {
- let ft = metadata.file_type();
if ft.is_dir() {
is_dir = true;
LineType::Dir
@@ -109,10 +114,10 @@ impl BLine {
if !has_match {
return BLineResult::FilteredOutByPattern;
}
- if only_folders {
+ if options.only_folders {
return BLineResult::FilteredOutAsNonFolder;
}
- LineType::SymLink(match fs::read_link(&path) {
+ LineType::SymLink(match fs::read_link(&e.path()) {
Ok(target) => target.to_string_lossy().into_owned(),
Err(_) => String::from("???"),
})
@@ -120,12 +125,13 @@ impl BLine {
if !has_match {
return BLineResult::FilteredOutByPattern;
}
- if only_folders {
+ if options.only_folders {
return BLineResult::FilteredOutAsNonFolder;
}
LineType::File
}
};
+ let path = e.path();
let mut ignore_filter = None;
if let Some(gif) = parent_ignore_filter {
if !gif.accepts(&path, &name, is_dir) {
@@ -244,33 +250,27 @@ impl TreeBuilder {
let mut children: Vec<usize> = Vec::new();
for e in entries {
if let Ok(e) = e {
- if let Ok(metadata) = e.metadata() {
- let bl = BLine::from(
- bline_idx,
- metadata,
- e.file_name(),
- e.path(),
- self.blines[bline_idx].depth + 1,
- !self.options.show_hidden,
- self.options.only_folders,
- &self.options.pattern,
- &self.blines[bline_idx].ignore_filter,
- );
- match bl {
- BLineResult::Some(bl) => {
- if bl.has_match {
- // direct match
- self.blines[bline_idx].has_match = true;
- has_child_match = true;
- }
- children.push(self.store(bl));
- }
- BLineResult::GitIgnored => {
- self.nb_gitignored += 1;
- }
- _ => {
- // other reason, we don't care
+ let bl = BLine::from(
+ bline_idx,
+ e,
+ self.blines[bline_idx].depth + 1,
+ &self.options,
+ &self.blines[bline_idx].ignore_filter,
+ );
+ match bl {
+ BLineResult::Some(bl) => {
+ if bl.has_match {
+ // direct match
+ self.blines[bline_idx].has_match = true;
+ has_child_match = true;
}
+ children.push(self.store(bl));
+ }
+ BLineResult::GitIgnored => {
+ self.nb_gitignored += 1;
+ }
+ _ => {
+ // other reason, we don't care
}
}
}
@@ -324,7 +324,8 @@ impl TreeBuilder {
open_dirs.push_back(0);
loop {
if self.options.pattern.is_some() {
- if (nb_lines_ok > 20 * self.targeted_size)
+ if
+ (nb_lines_ok > 20 * self.targeted_size)
|| (nb_lines_ok >= self.targeted_size && start.elapsed() > not_long)
{
//debug!("break {} {}", nb_lines_ok, 10 * self.targeted_size);
@@ -334,10 +335,8 @@ impl TreeBuilder {
info!("task expired (core build)");
return None;
}
- } else {
- if nb_lines_ok >= self.targeted_size {
- break;
- }
+ } else if nb_lines_ok >= self.targeted_size {
+ break;
}
if let Some(open_dir_idx) = open_dirs.pop_front() {
if let Some(child_idx) = self.next_child(open_dir_idx) {
@@ -396,7 +395,6 @@ impl TreeBuilder {
// removing a parent before its children.
fn trim_excess(&mut self, out_blines: &[usize]) {
let mut count = 1;
- // To start with, we get a better count of what we have:
for idx in out_blines[1..].iter() {
if self.blines[*idx].has_match {
count += 1;
@@ -410,7 +408,7 @@ impl TreeBuilder {
if
bline.has_match
&& bline.nb_kept_children == 0
- && (bline.depth>1 || !self.options.show_sizes) // we keep the complete first level when showing sizes
+ && (bline.depth > 1 || !self.options.show_sizes) // we keep the complete first level when showing sizes
{
remove_queue.push(SortableBLineIdx {
idx: *idx,
@@ -468,7 +466,7 @@ impl TreeBuilder {
tree.after_lines_changed();
if self.options.show_sizes {
- tree.fetch_file_sizes();
+ tree.fetch_file_sizes(); // not the dirs, only simple files
}
tree
}