view rust/hg-core/src/lib.rs @ 48750:94e36b230990

status: prefer relative paths in Rust code ? when the repository root is under the current directory, so the kernel needs to traverse fewer directory in every call to `read_dir` or `symlink_metadata`. Better yet would be to use libc functions like `openat` and `fstatat` to remove such repeated traversals entirely, but the standard library does not provide APIs based on those. Maybe with a crate like https://crates.io/crates/openat instead? Benchmarks of `rhg status` show that this patch is neutral in some configurations, and makes the command up to ~20% faster in others. Below is semi-arbitrary subset of results. The four numeric columns are: time (in seconds) with this changeset?s parent, time with this changeset, time difference (negative is better), time ratio (less than 1?is better). ``` mercurial-dirstate-v1 | default-plain-clean.no-iu.pbr | 0.0061 -> 0.0059: -0.0002 (0.97) mercurial-dirstate-v2 | default-plain-clean.no-iu.pbr | 0.0029 -> 0.0028: -0.0001 (0.97) mozilla-dirstate-v1 | default-plain-clean.no-iu.pbr | 0.2110 -> 0.2102: -0.0007 (1.00) mozilla-dirstate-v2 | default-copies-clean.ignored.pbr | 0.0489 -> 0.0401: -0.0088 (0.82) mozilla-dirstate-v2 | default-copies-clean.no-iu.pbr | 0.0479 -> 0.0393: -0.0085 (0.82) mozilla-dirstate-v2 | default-copies-large.all.pbr | 0.1262 -> 0.1210: -0.0051 (0.96) mozilla-dirstate-v2 | default-copies-small.ignored-unknown.pbr | 0.1262 -> 0.1200: -0.0062 (0.95) mozilla-dirstate-v2 | default-copies-small.ignored.pbr | 0.0536 -> 0.0417: -0.0119 (0.78) mozilla-dirstate-v2 | default-copies-small.no-iu.pbr | 0.0482 -> 0.0393: -0.0089 (0.81) mozilla-dirstate-v2 | default-plain-clean.ignored.pbr | 0.0518 -> 0.0402: -0.0116 (0.78) mozilla-dirstate-v2 | default-plain-clean.no-iu.pbr | 0.0481 -> 0.0392: -0.0088 (0.82) mozilla-dirstate-v2 | default-plain-large.all.pbr | 0.1271 -> 0.1218: -0.0052 (0.96) mozilla-dirstate-v2 | default-plain-small.ignored-unknown.pbr | 0.1225 -> 0.1202: -0.0022 (0.98) mozilla-dirstate-v2 | default-plain-small.ignored.pbr | 0.0510 -> 0.0418: -0.0092 (0.82) mozilla-dirstate-v2 | default-plain-small.no-iu.pbr | 0.0480 -> 0.0394: -0.0086 (0.82) netbeans-dirstate-v1 | default-plain-clean.no-iu.pbr | 0.1442 -> 0.1422: -0.0020 (0.99) netbeans-dirstate-v2 | default-plain-clean.no-iu.pbr | 0.0325 -> 0.0282: -0.0043 (0.87) ``` Differential Revision: https://phab.mercurial-scm.org/D12175
author Simon Sapin <simon.sapin@octobus.net>
date Fri, 21 Jan 2022 17:54:03 +0100
parents 791f5d5f7a96
children 11c0411bf4e2
line wrap: on
line source

// Copyright 2018-2020 Georges Racinet <georges.racinet@octobus.net>
//           and Mercurial contributors
//
// This software may be used and distributed according to the terms of the
// GNU General Public License version 2 or any later version.

mod ancestors;
pub mod dagops;
pub mod errors;
pub use ancestors::{AncestorsIterator, MissingAncestors};
pub mod dirstate;
pub mod dirstate_tree;
pub mod discovery;
pub mod exit_codes;
pub mod requirements;
pub mod testing; // unconditionally built, for use from integration tests
pub use dirstate::{
    dirs_multiset::{DirsMultiset, DirsMultisetIter},
    status::{
        BadMatch, BadType, DirstateStatus, HgPathCow, StatusError,
        StatusOptions,
    },
    DirstateEntry, DirstateParents, EntryState,
};
pub mod copy_tracing;
mod filepatterns;
pub mod matchers;
pub mod repo;
pub mod revlog;
pub use revlog::*;
pub mod config;
pub mod lock;
pub mod logging;
pub mod operations;
pub mod revset;
pub mod utils;
pub mod vfs;

use crate::utils::hg_path::{HgPathBuf, HgPathError};
pub use filepatterns::{
    parse_pattern_syntax, read_pattern_file, IgnorePattern,
    PatternFileWarning, PatternSyntax,
};
use std::collections::HashMap;
use std::fmt;
use twox_hash::RandomXxHashBuilder64;

/// This is a contract between the `micro-timer` crate and us, to expose
/// the `log` crate as `crate::log`.
use log;

pub type LineNumber = usize;

/// Rust's default hasher is too slow because it tries to prevent collision
/// attacks. We are not concerned about those: if an ill-minded person has
/// write access to your repository, you have other issues.
pub type FastHashMap<K, V> = HashMap<K, V, RandomXxHashBuilder64>;

#[derive(Debug, PartialEq)]
pub enum DirstateMapError {
    PathNotFound(HgPathBuf),
    EmptyPath,
    InvalidPath(HgPathError),
}

impl fmt::Display for DirstateMapError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            DirstateMapError::PathNotFound(_) => {
                f.write_str("expected a value, found none")
            }
            DirstateMapError::EmptyPath => {
                f.write_str("Overflow in dirstate.")
            }
            DirstateMapError::InvalidPath(path_error) => path_error.fmt(f),
        }
    }
}

#[derive(Debug, derive_more::From)]
pub enum DirstateError {
    Map(DirstateMapError),
    Common(errors::HgError),
}

impl fmt::Display for DirstateError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            DirstateError::Map(error) => error.fmt(f),
            DirstateError::Common(error) => error.fmt(f),
        }
    }
}

#[derive(Debug, derive_more::From)]
pub enum PatternError {
    #[from]
    Path(HgPathError),
    UnsupportedSyntax(String),
    UnsupportedSyntaxInFile(String, String, usize),
    TooLong(usize),
    #[from]
    IO(std::io::Error),
    /// Needed a pattern that can be turned into a regex but got one that
    /// can't. This should only happen through programmer error.
    NonRegexPattern(IgnorePattern),
}

impl fmt::Display for PatternError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            PatternError::UnsupportedSyntax(syntax) => {
                write!(f, "Unsupported syntax {}", syntax)
            }
            PatternError::UnsupportedSyntaxInFile(syntax, file_path, line) => {
                write!(
                    f,
                    "{}:{}: unsupported syntax {}",
                    file_path, line, syntax
                )
            }
            PatternError::TooLong(size) => {
                write!(f, "matcher pattern is too long ({} bytes)", size)
            }
            PatternError::IO(error) => error.fmt(f),
            PatternError::Path(error) => error.fmt(f),
            PatternError::NonRegexPattern(pattern) => {
                write!(f, "'{:?}' cannot be turned into a regex", pattern)
            }
        }
    }
}