Fixing log -- filters, along with performance improvements

pmeunier
Dec 7, 2021, 2:05 PM
6U42MTEZTINWUU2KLJLQW33ZBZXKTHPTF6TMEG56TO642CQDZQMQC

Dependencies

  • [2] 6F6AAHK4 Simplifying pijul::commands::log, and fixing Broken Pipe errors
  • [3] L4JXJHWX pijul/*: reorganize imports and remove extern crate
  • [4] F2S6XETO Fixing log --hash-only
  • [5] SXEYMYF7 Fixing the bad changes in history (unfortunately, by rebooting).
  • [6] OU6JOR3C Add path filtering for log, add json output for log
  • [7] SMMBFECL Converting to the new patch format "online"

Change contents

  • replacement in pijul/src/commands/log.rs at line 2
    [3.694][3.0:42]()
    use std::collections::{HashMap, HashSet};
    [3.694]
    [3.42]
    use std::collections::HashMap;
  • replacement in pijul/src/commands/log.rs at line 128
    [3.1009][2.2805:2851]()
    ) -> Result<Vec<libpijul::Inode>, Error<E>> {
    [3.1009]
    [3.1060]
    ) -> Result<
    Vec<(
    libpijul::Inode,
    Option<libpijul::pristine::Position<libpijul::ChangeId>>,
    )>,
    Error<E>,
    > {
  • replacement in pijul/src/commands/log.rs at line 158
    [2.3222][2.3222:3297]()
    Ok(Some(s)) => inodes.push(libpijul::fs::find_inode(txn, s)?),
    [2.3222]
    [3.2759]
    Ok(Some(s)) => {
    let inode = libpijul::fs::find_inode(txn, s)?;
    let inode_position = txn.get_inodes(&inode, None)?;
    inodes.push((inode, inode_position.cloned()))
    }
  • edit in pijul/src/commands/log.rs at line 169
    [3.2841][3.2841:3001](),[3.3001][2.3298:3355](),[2.3355][3.3070:3111](),[3.3070][3.3070:3111](),[3.3111][2.3356:3405](),[2.3405][3.3165:3417](),[3.3165][3.3165:3417](),[3.3417][2.3406:3436](),[2.3436][3.3489:3787](),[3.3489][3.3489:3787](),[3.3787][2.3437:3573](),[2.3573][3.4336:4511](),[3.4336][3.4336:4511]()
    /// Given a list of path filters which represent the files/directories for which
    /// the user wants to see the logs, find the subset of relevant change hashes.
    fn filtered_hashes<E: std::error::Error>(
    txn: &Txn,
    path: &Path,
    filters: &[String],
    ) -> Result<HashSet<libpijul::Hash>, Error<E>> {
    let inodes = get_inodes(txn, path, filters)?;
    let mut hashes = HashSet::<libpijul::Hash>::new();
    for inode in inodes {
    // The Position<ChangeId> for the file Inode.
    let inode_position = match txn.get_inodes(&inode, None)? {
    None => continue,
    Some(p) => p,
    };
    for pair in txn.iter_touched(inode_position)? {
    let (position, touched_change_id) = pair?;
    // Push iff the file ChangeId for this element matches that of the file Inode
    if &position.change == &inode_position.change {
    let ser_h = txn.get_external(touched_change_id)?.unwrap();
    hashes.insert(libpijul::Hash::from(*ser_h));
    } else {
    // We've gone past the relevant subset of changes in the iterator.
    break;
    }
    }
    }
    Ok(hashes)
    }
  • edit in pijul/src/commands/log.rs at line 312
    [3.10433][3.10433:10702]()
    // If the user applied path filters, figure out what change hashes
    // are to be logged.
    let mut requested_hashes = filtered_hashes(
    &self.txn,
    self.repo_path.as_ref(),
    self.cmd.filters.as_slice(),
    )?;
  • replacement in pijul/src/commands/log.rs at line 313
    [3.10703][3.10703:11547](),[3.11547][2.3650:3695](),[2.3695][3.11678:12071](),[3.11678][3.11678:12071]()
    // Get the (Hash, Merkle) pairs for the portion of reverse_log
    // that are between offset and limit.
    let hs = self
    .txn
    .reverse_log(&*self.channel_ref.read(), None)?
    .skip(self.offset)
    .take(self.limit)
    .map(|res| {
    res.map(|(_, (ser_h, ser_m))| {
    (libpijul::Hash::from(ser_h), libpijul::Merkle::from(ser_m))
    })
    });
    for pr in hs {
    let (h, mrk) = pr?;
    if (self.cmd.filters.is_empty()) || requested_hashes.remove(&h) {
    // If there were no path filters applied, OR is this was one of the hashes
    // marked by the file filters that were applied
    let entry = self.mk_log_entry(&mut authors, &mut id_path, h, Some(mrk))?;
    f(entry).map_err(Error::E)?;
    } else if requested_hashes.is_empty() {
    // If the user applied path filters, but the relevant change hashes
    // have been exhausted, we can break early.
    break;
    } else {
    // The user applied path filters; this wasn't a hit, but
    // there are still hits to be logged.
    continue;
    [3.10703]
    [3.135674]
    let inodes = get_inodes(&self.txn, &self.repo_path, &self.cmd.filters)?;
    let mut offset = self.offset;
    let mut limit = self.limit;
    for pr in self.txn.reverse_log(&*self.channel_ref.read(), None)? {
    let (_, (h, mrk)) = pr?;
    let cid = self.txn.get_internal(h)?.unwrap();
    let mut is_in_filters = inodes.is_empty();
    for (_, position) in inodes.iter() {
    if let Some(position) = position {
    is_in_filters = self.txn.get_touched_files(position, Some(cid))?.is_some();
    if is_in_filters {
    break;
    }
    }
    }
    if is_in_filters {
    if offset == 0 && limit > 0 {
    // If there were no path filters applied, OR is this was one of the hashes
    // marked by the file filters that were applied
    let entry =
    self.mk_log_entry(&mut authors, &mut id_path, h.into(), Some(mrk.into()))?;
    f(entry).map_err(Error::E)?;
    limit -= 1
    } else if limit > 0 {
    offset -= 1
    } else {
    break;
    }