Performance improvements

This commit is contained in:
Ajeet D'Souza 2020-04-05 20:44:23 +05:30
parent 4414898a06
commit 342954cda0
8 changed files with 68 additions and 60 deletions

14
Cargo.lock generated
View File

@ -49,7 +49,7 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -295,15 +295,15 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.105" version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.105" version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
@ -432,7 +432,7 @@ dependencies = [
"bstr 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "bstr 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -475,8 +475,8 @@ dependencies = [
"checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" "checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
"checksum regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" "checksum regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
"checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" "checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
"checksum serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" "checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399"
"checksum serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" "checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum structopt 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "c8faa2719539bbe9d77869bfb15d4ee769f99525e707931452c97b693b3f159d" "checksum structopt 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "c8faa2719539bbe9d77869bfb15d4ee769f99525e707931452c97b693b3f159d"
"checksum structopt-derive 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f88b8e18c69496aad6f9ddf4630dd7d585bcaf765786cb415b9aec2fe5a0430" "checksum structopt-derive 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f88b8e18c69496aad6f9ddf4630dd7d585bcaf765786cb415b9aec2fe5a0430"

View File

@ -17,7 +17,7 @@ anyhow = "1.0.28"
bincode = "1.2.1" bincode = "1.2.1"
clap = "2.33.0" clap = "2.33.0"
dirs = "2.0.2" dirs = "2.0.2"
serde = { version = "1.0.105", features = ["derive"] } serde = { version = "1.0.106", features = ["derive"] }
structopt = "0.3.12" structopt = "0.3.12"
uuid = { version = "0.8.1", features = ["v4"] } uuid = { version = "0.8.1", features = ["v4"] }

View File

@ -121,7 +121,7 @@ impl DB {
continue; continue;
}; };
let split_line = line.rsplitn(3, '|').collect::<Vec<&str>>(); let split_line = line.rsplitn(3, '|').collect::<Vec<_>>();
match split_line.as_slice() { match split_line.as_slice() {
[epoch_str, rank_str, path_str] => { [epoch_str, rank_str, path_str] => {
@ -215,7 +215,7 @@ impl DB {
Ok(()) Ok(())
} }
pub fn query(&mut self, keywords: &[String], now: Epoch) -> Option<Dir> { pub fn query(&mut self, keywords: &[String], now: Epoch) -> Option<&Dir> {
let (idx, dir, _) = self let (idx, dir, _) = self
.data .data
.dirs .dirs
@ -228,7 +228,8 @@ impl DB {
})?; })?;
if dir.is_dir() { if dir.is_dir() {
Some(dir.to_owned()) // FIXME: change this to Some(dir) once the MIR borrow checker comes to stable Rust
Some(&self.data.dirs[idx])
} else { } else {
self.data.dirs.swap_remove(idx); self.data.dirs.swap_remove(idx);
self.modified = true; self.modified = true;
@ -236,7 +237,7 @@ impl DB {
} }
} }
pub fn query_all(&mut self, keywords: &[String]) -> Vec<Dir> { pub fn query_all<'a>(&'a mut self, keywords: &'a [String]) -> impl Iterator<Item = &'a Dir> {
let orig_len = self.data.dirs.len(); let orig_len = self.data.dirs.len();
self.data.dirs.retain(Dir::is_dir); self.data.dirs.retain(Dir::is_dir);
@ -247,15 +248,17 @@ impl DB {
self.data self.data
.dirs .dirs
.iter() .iter()
.filter(|dir| dir.is_match(&keywords)) .filter(move |dir| dir.is_match(keywords))
.cloned()
.collect()
} }
pub fn remove<P: AsRef<Path>>(&mut self, path: P) -> Result<()> { pub fn remove<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
let path_canonicalized;
let path_abs = match path.as_ref().canonicalize() { let path_abs = match path.as_ref().canonicalize() {
Ok(path_abs) => path_abs, Ok(path_abs) => {
Err(_) => path.as_ref().to_path_buf(), path_canonicalized = path_abs;
&path_canonicalized
}
Err(_) => path.as_ref(),
}; };
if let Some(idx) = self.data.dirs.iter().position(|dir| dir.path == path_abs) { if let Some(idx) = self.data.dirs.iter().position(|dir| dir.path == path_abs) {

View File

@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
pub use f64 as Rank; pub use f64 as Rank;
pub use i64 as Epoch; // use a signed integer so subtraction can be performed on it pub use i64 as Epoch; // use a signed integer so subtraction can be performed on it
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Debug, Default, Deserialize, Serialize)]
pub struct Dir { pub struct Dir {
pub path: PathBuf, pub path: PathBuf,
pub rank: Rank, pub rank: Rank,

View File

@ -15,20 +15,25 @@ pub struct Add {
impl Add { impl Add {
pub fn run(&self) -> Result<()> { pub fn run(&self) -> Result<()> {
let mut db = util::get_db()?; let current_dir;
let now = util::get_current_time()?;
let maxage = config::zo_maxage()?;
let excluded_dirs = config::zo_exclude_dirs();
let path = match &self.path { let path = match &self.path {
Some(path) => path.clone(), Some(path) => path,
None => env::current_dir().context("unable to fetch current directory")?, None => {
current_dir = env::current_dir().context("unable to fetch current directory")?;
&current_dir
}
}; };
if excluded_dirs.contains(&path) { let excluded_dirs = config::zo_exclude_dirs();
if excluded_dirs.contains(path) {
return Ok(()); return Ok(());
} }
let mut db = util::get_db()?;
let maxage = config::zo_maxage()?;
let now = util::get_current_time()?;
db.add(path, maxage, now) db.add(path, maxage, now)
} }
} }

View File

@ -45,8 +45,6 @@ impl Init {
let stdout = io::stdout(); let stdout = io::stdout();
let mut handle = stdout.lock(); let mut handle = stdout.lock();
// If any `writeln!` call fails to write to stdout, we assume the user's
// computer is on fire and panic.
let z = config.z; let z = config.z;
writeln!(handle, "{}", z(&self.z_cmd)).unwrap(); writeln!(handle, "{}", z(&self.z_cmd)).unwrap();

View File

@ -15,7 +15,7 @@ pub struct Query {
} }
impl Query { impl Query {
pub fn run(mut self) -> Result<()> { pub fn run(&self) -> Result<()> {
let path_opt = if self.interactive { let path_opt = if self.interactive {
self.query_interactive()? self.query_interactive()?
} else { } else {
@ -35,7 +35,7 @@ impl Query {
Ok(()) Ok(())
} }
fn query(&mut self) -> Result<Option<Vec<u8>>> { fn query(&self) -> Result<Option<Vec<u8>>> {
if let [path] = self.keywords.as_slice() { if let [path] = self.keywords.as_slice() {
if Path::new(path).is_dir() { if Path::new(path).is_dir() {
return Ok(Some(path.as_bytes().to_vec())); return Ok(Some(path.as_bytes().to_vec()));
@ -44,11 +44,13 @@ impl Query {
let now = util::get_current_time()?; let now = util::get_current_time()?;
for keyword in &mut self.keywords { let keywords = self
*keyword = keyword.to_lowercase(); .keywords
} .iter()
.map(|keyword| keyword.to_lowercase())
.collect::<Vec<_>>();
let path_opt = util::get_db()?.query(&self.keywords, now).map(|dir| { let path_opt = util::get_db()?.query(&keywords, now).map(|dir| {
// `path_to_bytes` is guaranteed to succeed here since // `path_to_bytes` is guaranteed to succeed here since
// the path has already been queried successfully // the path has already been queried successfully
let path_bytes = util::path_to_bytes(&dir.path).unwrap(); let path_bytes = util::path_to_bytes(&dir.path).unwrap();
@ -58,14 +60,17 @@ impl Query {
Ok(path_opt) Ok(path_opt)
} }
fn query_interactive(&mut self) -> Result<Option<Vec<u8>>> { fn query_interactive(&self) -> Result<Option<Vec<u8>>> {
let now = util::get_current_time()?; let now = util::get_current_time()?;
for keyword in &mut self.keywords { let keywords = self
*keyword = keyword.to_lowercase(); .keywords
} .iter()
.map(|keyword| keyword.to_lowercase())
.collect::<Vec<_>>();
let dirs = util::get_db()?.query_all(&self.keywords); let mut db = util::get_db()?;
let dirs = db.query_all(&keywords);
util::fzf_helper(now, dirs) util::fzf_helper(now, dirs)
} }
} }

View File

@ -4,7 +4,7 @@ use crate::dir::{Dir, Epoch};
use anyhow::{anyhow, bail, Context, Result}; use anyhow::{anyhow, bail, Context, Result};
use std::cmp::{Ordering, PartialOrd}; use std::cmp::Reverse;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::path::Path; use std::path::Path;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
@ -49,9 +49,12 @@ pub fn get_current_time() -> Result<Epoch> {
Ok(current_time as Epoch) Ok(current_time as Epoch)
} }
pub fn fzf_helper(now: Epoch, mut dirs: Vec<Dir>) -> Result<Option<Vec<u8>>> { pub fn fzf_helper<'a, I>(now: Epoch, dirs: I) -> Result<Option<Vec<u8>>>
where
I: IntoIterator<Item = &'a Dir>,
{
let mut fzf = Command::new("fzf") let mut fzf = Command::new("fzf")
.arg("-n2..") .args(&["-n2..", "--no-sort"])
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn() .spawn()
@ -62,26 +65,20 @@ pub fn fzf_helper(now: Epoch, mut dirs: Vec<Dir>) -> Result<Option<Vec<u8>>> {
.as_mut() .as_mut()
.ok_or_else(|| anyhow!("could not connect to fzf stdin"))?; .ok_or_else(|| anyhow!("could not connect to fzf stdin"))?;
for dir in dirs.iter_mut() { let mut dir_frecencies = dirs
dir.rank = dir.get_frecency(now); .into_iter()
} .map(|dir| (dir, clamp(dir.get_frecency(now), 0.0, 9999.0) as i32))
.collect::<Vec<_>>();
dirs.sort_unstable_by(|dir1, dir2| { dir_frecencies.sort_unstable_by_key(|&(dir, frecency)| Reverse((frecency, &dir.path)));
dir1.rank
.partial_cmp(&dir2.rank)
.unwrap_or(Ordering::Equal)
.reverse()
});
for dir in dirs.iter() { for &(dir, frecency) in dir_frecencies.iter() {
// ensure that frecency fits in 4 characters // ensure that frecency fits in 4 characters
let frecency = clamp(dir.rank, 0.0, 9999.0);
if let Some(path_bytes) = path_to_bytes(&dir.path) { if let Some(path_bytes) = path_to_bytes(&dir.path) {
(|| { (|| {
write!(fzf_stdin, "{:>4.0} ", frecency)?; write!(fzf_stdin, "{:>4} ", frecency)?;
fzf_stdin.write_all(path_bytes)?; fzf_stdin.write_all(path_bytes)?;
fzf_stdin.write_all(b"\n") writeln!(fzf_stdin)
})() })()
.context("could not write into fzf stdin")?; .context("could not write into fzf stdin")?;
} }
@ -125,11 +122,11 @@ pub fn fzf_helper(now: Epoch, mut dirs: Vec<Dir>) -> Result<Option<Vec<u8>>> {
pub fn clamp(val: f64, min: f64, max: f64) -> f64 { pub fn clamp(val: f64, min: f64, max: f64) -> f64 {
assert!(min <= max); assert!(min <= max);
if val < min { if val > max {
min
} else if val > max {
max max
} else { } else if val > min {
val val
} else {
min
} }
} }