rust/hg-core/src/update.rs
author Rapha?l Gom?s <rgomes@octobus.net>
Thu, 26 Sep 2024 14:26:24 +0200
changeset 52178 bd8081e9fd62
parent 52156 039b7caeb4d9
child 52251 65d516db7309
permissions -rw-r--r--
rust: don't star export from the `revlog` module This made a lot of the imports confusing because they didn't make sense at the top level (so, outside of `revlog`), and they hide the more common types when autocompleting.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
52056
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
     1
//! Tools for moving the repository to a given revision
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
     2
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
     3
use std::{
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
     4
    fs::Permissions,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
     5
    io::Write,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
     6
    os::unix::fs::{MetadataExt, PermissionsExt},
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
     7
    path::Path,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
     8
    time::Duration,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
     9
};
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    10
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    11
use crate::{
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    12
    dirstate::{ParentFileData, TruncatedTimestamp},
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    13
    dirstate_tree::{
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    14
        dirstate_map::DirstateEntryReset, on_disk::write_tracked_key,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    15
    },
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    16
    errors::{HgError, IoResultExt},
52178
bd8081e9fd62 rust: don't star export from the `revlog` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52156
diff changeset
    17
    exit_codes, narrow,
52056
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    18
    operations::{list_rev_tracked_files, ExpandedManifestEntry},
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    19
    progress::Progress,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    20
    repo::Repo,
52178
bd8081e9fd62 rust: don't star export from the `revlog` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52156
diff changeset
    21
    revlog::filelog::Filelog,
bd8081e9fd62 rust: don't star export from the `revlog` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52156
diff changeset
    22
    revlog::node::NULL_NODE,
bd8081e9fd62 rust: don't star export from the `revlog` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52156
diff changeset
    23
    revlog::options::{default_revlog_options, RevlogOpenOptions},
bd8081e9fd62 rust: don't star export from the `revlog` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52156
diff changeset
    24
    revlog::RevlogError,
52056
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    25
    sparse,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    26
    utils::{
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    27
        files::{filesystem_now, get_path_from_bytes},
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    28
        hg_path::{hg_path_to_path_buf, HgPath, HgPathError},
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    29
        path_auditor::PathAuditor,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    30
    },
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    31
    vfs::{is_on_nfs_mount, VfsImpl},
52178
bd8081e9fd62 rust: don't star export from the `revlog` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52156
diff changeset
    32
    DirstateParents, UncheckedRevision,
52056
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    33
};
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    34
use crossbeam_channel::{Receiver, Sender};
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    35
use rayon::prelude::*;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    36
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    37
fn write_dirstate(repo: &Repo) -> Result<(), HgError> {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    38
    repo.write_dirstate()
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    39
        .map_err(|e| HgError::abort(e.to_string(), exit_codes::ABORT, None))?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    40
    write_tracked_key(repo)
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    41
}
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    42
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    43
/// Update the current working copy of `repo` to the given revision `to`, from
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    44
/// the null revision and set + write out the dirstate to reflect that.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    45
///
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    46
/// Do not call this outside of a Python context. This does *not* handle any
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    47
/// of the checks, hooks, lock taking needed to setup and get out of this
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    48
/// update from the null revision.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    49
pub fn update_from_null(
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    50
    repo: &Repo,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    51
    to: UncheckedRevision,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    52
    progress: &dyn Progress,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    53
) -> Result<usize, HgError> {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    54
    // Ignore the warnings, they've been displayed by Python already
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    55
    // TODO non-Python clients: display narrow warnings
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    56
    let (narrow_matcher, _) = narrow::matcher(repo)?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    57
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    58
    let files_for_rev = list_rev_tracked_files(repo, to, narrow_matcher)
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    59
        .map_err(handle_revlog_error)?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    60
    repo.manually_set_parents(DirstateParents {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    61
        p1: repo.node(to).expect("update target should exist"),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    62
        p2: NULL_NODE,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    63
    })?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    64
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    65
    // Filter the working copy according to the sparse spec
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    66
    let tracked_files: Result<Vec<_>, _> = if !repo.has_sparse() {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    67
        files_for_rev.iter().collect()
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    68
    } else {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    69
        // Ignore the warnings, they've been displayed by Python already
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    70
        // TODO non-Python clients: display sparse warnings
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    71
        let (sparse_matcher, _) = sparse::matcher(repo)?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    72
        files_for_rev
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    73
            .iter()
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    74
            .filter(|f| {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    75
                match f {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    76
                    Ok(f) => sparse_matcher.matches(f.0),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    77
                    Err(_) => true, // Errors stop the update, include them
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    78
                }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    79
            })
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    80
            .collect()
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    81
    };
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    82
    let tracked_files = tracked_files?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    83
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    84
    if tracked_files.is_empty() {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    85
        // Still write the dirstate because we might not be in the null
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    86
        // revision.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    87
        // This can happen in narrow repos where all paths are excluded in
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    88
        // this revision.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    89
        write_dirstate(repo)?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    90
        return Ok(0);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    91
    }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    92
    let store_vfs = &repo.store_vfs();
52156
039b7caeb4d9 rust-revlog: introduce an `options` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52056
diff changeset
    93
    let options = default_revlog_options(
039b7caeb4d9 rust-revlog: introduce an `options` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52056
diff changeset
    94
        repo.config(),
039b7caeb4d9 rust-revlog: introduce an `options` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52056
diff changeset
    95
        repo.requirements(),
52178
bd8081e9fd62 rust: don't star export from the `revlog` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52156
diff changeset
    96
        crate::revlog::RevlogType::Filelog,
52156
039b7caeb4d9 rust-revlog: introduce an `options` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52056
diff changeset
    97
    )?;
52056
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    98
    let (errors_sender, errors_receiver) = crossbeam_channel::unbounded();
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    99
    let (files_sender, files_receiver) = crossbeam_channel::unbounded();
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   100
    let working_directory_path = &repo.working_directory_path();
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   101
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   102
    let files_count = tracked_files.len();
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   103
    let chunks = chunk_tracked_files(tracked_files);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   104
    progress.update(0, Some(files_count as u64));
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   105
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   106
    create_working_copy(
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   107
        chunks,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   108
        working_directory_path,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   109
        store_vfs,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   110
        options,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   111
        files_sender,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   112
        errors_sender,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   113
        progress,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   114
    );
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   115
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   116
    let errors: Vec<HgError> = errors_receiver.iter().collect();
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   117
    if !errors.is_empty() {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   118
        log::debug!("{} errors during update (see trace logs)", errors.len());
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   119
        for error in errors.iter() {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   120
            log::trace!("{}", error);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   121
        }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   122
        // Best we can do is raise the first error (in order of the channel)
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   123
        return Err(errors.into_iter().next().expect("can never be empty"));
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   124
    }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   125
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   126
    // TODO try to run this concurrently to update the dirstate while we're
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   127
    // still writing out the working copy to see if that improves performance.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   128
    let total = update_dirstate(repo, files_receiver)?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   129
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   130
    write_dirstate(repo)?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   131
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   132
    Ok(total)
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   133
}
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   134
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   135
fn handle_revlog_error(e: RevlogError) -> HgError {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   136
    match e {
52178
bd8081e9fd62 rust: don't star export from the `revlog` module
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52156
diff changeset
   137
        crate::revlog::RevlogError::Other(hg_error) => hg_error,
52056
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   138
        e => HgError::abort(
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   139
            format!("revlog error: {}", e),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   140
            exit_codes::ABORT,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   141
            None,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   142
        ),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   143
    }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   144
}
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   145
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   146
/// Preallocated size of Vec holding directory contents. This aims at
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   147
/// preventing the need for re-allocating the Vec in most cases.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   148
///
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   149
/// The value is arbitrarily picked as a little over an average number of files
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   150
/// per directory done by looking at a few larger open-source repos.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   151
/// Most of the runtime is IO anyway, so this doesn't matter too much.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   152
const FILES_PER_DIRECTORY: usize = 16;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   153
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   154
/// Chunk files per directory prefix, so almost every directory is handled
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   155
/// in a separate thread, which works around the FS inode mutex.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   156
/// Chunking less (and doing approximately `files_count`/`threads`) actually
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   157
/// ends up being less performant: my hypothesis is `rayon`'s work stealing
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   158
/// being more efficient with tasks of varying lengths.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   159
#[logging_timer::time("trace")]
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   160
fn chunk_tracked_files(
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   161
    tracked_files: Vec<ExpandedManifestEntry>,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   162
) -> Vec<(&HgPath, Vec<ExpandedManifestEntry>)> {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   163
    let files_count = tracked_files.len();
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   164
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   165
    let mut chunks = Vec::with_capacity(files_count / FILES_PER_DIRECTORY);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   166
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   167
    let mut current_chunk = Vec::with_capacity(FILES_PER_DIRECTORY);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   168
    let mut last_directory = tracked_files[0].0.parent();
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   169
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   170
    for file_info in tracked_files {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   171
        let current_directory = file_info.0.parent();
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   172
        let different_directory = current_directory != last_directory;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   173
        if different_directory {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   174
            chunks.push((last_directory, current_chunk));
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   175
            current_chunk = Vec::with_capacity(FILES_PER_DIRECTORY);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   176
        }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   177
        current_chunk.push(file_info);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   178
        last_directory = current_directory;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   179
    }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   180
    chunks.push((last_directory, current_chunk));
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   181
    chunks
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   182
}
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   183
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   184
#[logging_timer::time("trace")]
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   185
fn create_working_copy<'a: 'b, 'b>(
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   186
    chunks: Vec<(&HgPath, Vec<ExpandedManifestEntry<'a>>)>,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   187
    working_directory_path: &Path,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   188
    store_vfs: &VfsImpl,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   189
    options: RevlogOpenOptions,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   190
    files_sender: Sender<(&'b HgPath, u32, usize, TruncatedTimestamp)>,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   191
    error_sender: Sender<HgError>,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   192
    progress: &dyn Progress,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   193
) {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   194
    let auditor = PathAuditor::new(working_directory_path);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   195
    chunks.into_par_iter().for_each(|(dir_path, chunk)| {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   196
        if let Err(e) = working_copy_worker(
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   197
            dir_path,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   198
            chunk,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   199
            working_directory_path,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   200
            store_vfs,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   201
            options,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   202
            &files_sender,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   203
            progress,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   204
            &auditor,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   205
        ) {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   206
            error_sender
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   207
                .send(e)
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   208
                .expect("channel should not be disconnected")
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   209
        }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   210
    });
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   211
}
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   212
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   213
/// Represents a work unit for a single thread, responsible for this set of
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   214
/// files and restoring them to the working copy.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   215
#[allow(clippy::too_many_arguments)]
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   216
fn working_copy_worker<'a: 'b, 'b>(
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   217
    dir_path: &HgPath,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   218
    chunk: Vec<ExpandedManifestEntry<'a>>,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   219
    working_directory_path: &Path,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   220
    store_vfs: &VfsImpl,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   221
    options: RevlogOpenOptions,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   222
    files_sender: &Sender<(&'b HgPath, u32, usize, TruncatedTimestamp)>,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   223
    progress: &dyn Progress,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   224
    auditor: &PathAuditor,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   225
) -> Result<(), HgError> {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   226
    let dir_path =
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   227
        hg_path_to_path_buf(dir_path).expect("invalid path in manifest");
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   228
    let dir_path = working_directory_path.join(dir_path);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   229
    std::fs::create_dir_all(&dir_path).when_writing_file(&dir_path)?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   230
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   231
    for (file, file_node, flags) in chunk {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   232
        auditor.audit_path(file)?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   233
        let flags = flags.map(|f| f.into());
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   234
        let path =
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   235
            working_directory_path.join(get_path_from_bytes(file.as_bytes()));
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   236
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   237
        // Treemanifest is not supported
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   238
        assert!(flags != Some(b't'));
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   239
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   240
        let filelog = Filelog::open_vfs(store_vfs, file, options)?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   241
        let filelog_revision_data = &filelog
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   242
            .data_for_node(file_node)
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   243
            .map_err(handle_revlog_error)?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   244
        let file_data = filelog_revision_data.file_data()?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   245
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   246
        if flags == Some(b'l') {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   247
            let target = get_path_from_bytes(file_data);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   248
            if let Err(e) = std::os::unix::fs::symlink(target, &path) {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   249
                // If the path already exists either:
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   250
                //   - another process created this file while ignoring the
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   251
                //     lock => error
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   252
                //   - our check for the fast path is incorrect => error
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   253
                //   - this is a malicious repo/bundle and this is symlink that
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   254
                //     tries to write things where it shouldn't be able to.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   255
                match e.kind() {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   256
                    std::io::ErrorKind::AlreadyExists => {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   257
                        let metadata = std::fs::symlink_metadata(&path)
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   258
                            .when_reading_file(&path)?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   259
                        if metadata.is_dir() {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   260
                            return Err(HgError::Path(
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   261
                                HgPathError::TraversesSymbolicLink {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   262
                                    // Technically it should be one of the
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   263
                                    // children, but good enough
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   264
                                    path: file
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   265
                                        .join(HgPath::new(b"*"))
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   266
                                        .to_owned(),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   267
                                    symlink: file.to_owned(),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   268
                                },
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   269
                            ));
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   270
                        }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   271
                        return Err(e).when_writing_file(&path);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   272
                    }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   273
                    _ => return Err(e).when_writing_file(&path),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   274
                }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   275
            }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   276
        } else {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   277
            let mut f =
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   278
                std::fs::File::create(&path).when_writing_file(&path)?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   279
            f.write_all(file_data).when_writing_file(&path)?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   280
        }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   281
        if flags == Some(b'x') {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   282
            std::fs::set_permissions(&path, Permissions::from_mode(0o755))
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   283
                .when_writing_file(&path)?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   284
        }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   285
        let metadata =
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   286
            std::fs::symlink_metadata(&path).when_reading_file(&path)?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   287
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   288
        let mode = metadata.mode();
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   289
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   290
        files_sender
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   291
            .send((
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   292
                file,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   293
                mode,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   294
                file_data.len(),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   295
                TruncatedTimestamp::for_mtime_of(&metadata)
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   296
                    .when_reading_file(&path)?,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   297
            ))
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   298
            .expect("channel should not be closed");
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   299
        progress.increment(1, None);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   300
    }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   301
    Ok(())
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   302
}
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   303
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   304
#[logging_timer::time("trace")]
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   305
fn update_dirstate(
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   306
    repo: &Repo,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   307
    files_receiver: Receiver<(&HgPath, u32, usize, TruncatedTimestamp)>,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   308
) -> Result<usize, HgError> {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   309
    let mut dirstate = repo
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   310
        .dirstate_map_mut()
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   311
        .map_err(|e| HgError::abort(e.to_string(), exit_codes::ABORT, None))?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   312
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   313
    // (see the comments in `filter_ambiguous_files` in `merge.py` for more)
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   314
    // It turns out that (on Linux at least) the filesystem resolution time
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   315
    // for most filesystems is based on the HZ kernel config. Their internal
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   316
    // clocks do return nanoseconds if the hardware clock is precise enough,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   317
    // which should be the case on most recent computers but are only updated
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   318
    // every few milliseconds at best (every "jiffy").
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   319
    //
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   320
    // We are still not concerned with fixing the race with other
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   321
    // processes that might modify the working copy right after it was created
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   322
    // within the same tick, because it is impossible to catch.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   323
    // However, we might as well not race with operations that could run right
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   324
    // after this one, especially other Mercurial operations that could be
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   325
    // waiting for the wlock to change file contents and the dirstate.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   326
    //
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   327
    // Thus: wait until the filesystem clock has ticked to filter ambiguous
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   328
    // entries and write the dirstate, but only for dirstate-v2, since v1 only
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   329
    // has second-level granularity and waiting for a whole second is too much
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   330
    // of a penalty in the general case.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   331
    // Although we're assuming that people running dirstate-v2 on Linux
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   332
    // don't have a second-granularity FS (with the exclusion of NFS), users
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   333
    // can be surprising, and at some point in the future dirstate-v2 will
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   334
    // become the default. To that end, we limit the wait time to 100ms and
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   335
    // fall back to the filter method in case of a timeout.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   336
    //
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   337
    // +------------+------+--------------+
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   338
    // |   version  | wait | filter level |
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   339
    // +------------+------+--------------+
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   340
    // |     V1     | No   | Second       |
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   341
    // |     V2     | Yes  | Nanosecond   |
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   342
    // | V2-slow-fs | No   | Second       |
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   343
    // +------------+------+--------------+
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   344
    let dirstate_v2 = repo.use_dirstate_v2();
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   345
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   346
    // Let's ignore NFS right off the bat
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   347
    let mut fast_enough_fs = !is_on_nfs_mount(repo.working_directory_path());
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   348
    let fs_time_now = if dirstate_v2 && fast_enough_fs {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   349
        match wait_until_fs_tick(repo.working_directory_path()) {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   350
            None => None,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   351
            Some(Ok(time)) => Some(time),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   352
            Some(Err(time)) => {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   353
                fast_enough_fs = false;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   354
                Some(time)
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   355
            }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   356
        }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   357
    } else {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   358
        filesystem_now(repo.working_directory_path())
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   359
            .ok()
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   360
            .map(TruncatedTimestamp::from)
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   361
    };
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   362
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   363
    let mut total = 0;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   364
    for (filename, mode, size, mtime) in files_receiver.into_iter() {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   365
        total += 1;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   366
        // When using dirstate-v2 on a filesystem with reasonable performance
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   367
        // this is basically always true unless you get a mtime from the
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   368
        // far future.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   369
        let has_meaningful_mtime = if let Some(fs_time) = fs_time_now {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   370
            mtime.for_reliable_mtime_of_self(&fs_time).is_some_and(|t| {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   371
                // Dirstate-v1 only has second-level information
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   372
                !t.second_ambiguous || dirstate_v2 && fast_enough_fs
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   373
            })
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   374
        } else {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   375
            // We somehow failed to write to the filesystem, so don't store
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   376
            // the cache information.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   377
            false
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   378
        };
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   379
        let reset = DirstateEntryReset {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   380
            filename,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   381
            wc_tracked: true,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   382
            p1_tracked: true,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   383
            p2_info: false,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   384
            has_meaningful_mtime,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   385
            parent_file_data_opt: Some(ParentFileData {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   386
                mode_size: Some((
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   387
                    mode,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   388
                    size.try_into().expect("invalid file size in manifest"),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   389
                )),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   390
                mtime: Some(mtime),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   391
            }),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   392
            from_empty: true,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   393
        };
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   394
        dirstate.reset_state(reset).map_err(|e| {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   395
            HgError::abort(e.to_string(), exit_codes::ABORT, None)
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   396
        })?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   397
    }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   398
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   399
    Ok(total)
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   400
}
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   401
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   402
/// Wait until the next update from the filesystem time by writing in a loop
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   403
/// a new temporary file inside the working directory and checking if its time
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   404
/// differs from the first one observed.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   405
///
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   406
/// Returns `None` if we are unable to get the filesystem time,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   407
/// `Some(Err(timestamp))` if we've timed out waiting for the filesystem clock
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   408
/// to tick, and `Some(Ok(timestamp))` if we've waited successfully.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   409
///
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   410
/// On Linux, your average tick is going to be a "jiffy", or 1/HZ.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   411
/// HZ is your kernel's tick rate (if it has one configured) and the value
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   412
/// is the one returned by `grep 'CONFIG_HZ=' /boot/config-$(uname -r)`,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   413
/// again assuming a normal setup.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   414
///
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   415
/// In my case (Alphare) at the time of writing, I get `CONFIG_HZ=250`,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   416
/// which equates to 4ms.
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   417
///
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   418
/// This might change with a series that could make it to Linux 6.12:
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   419
/// https://lore.kernel.org/all/20241002-mgtime-v10-8-d1c4717f5284@kernel.org
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   420
fn wait_until_fs_tick(
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   421
    working_directory_path: &Path,
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   422
) -> Option<Result<TruncatedTimestamp, TruncatedTimestamp>> {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   423
    let start = std::time::Instant::now();
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   424
    let old_fs_time = filesystem_now(working_directory_path).ok()?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   425
    let mut fs_time = filesystem_now(working_directory_path).ok()?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   426
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   427
    const FS_TICK_WAIT_TIMEOUT: Duration = Duration::from_millis(100);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   428
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   429
    while fs_time == old_fs_time {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   430
        if std::time::Instant::now() - start > FS_TICK_WAIT_TIMEOUT {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   431
            log::trace!(
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   432
                "timed out waiting for the fs clock to tick after {:?}",
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   433
                FS_TICK_WAIT_TIMEOUT
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   434
            );
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   435
            return Some(Err(TruncatedTimestamp::from(old_fs_time)));
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   436
        }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   437
        fs_time = filesystem_now(working_directory_path).ok()?;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   438
    }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   439
    log::trace!(
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   440
        "waited for {:?} before writing the dirstate",
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   441
        fs_time.duration_since(old_fs_time)
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   442
    );
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   443
    Some(Ok(TruncatedTimestamp::from(fs_time)))
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   444
}
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   445
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   446
#[cfg(test)]
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   447
mod test {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   448
    use super::*;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   449
    use pretty_assertions::assert_eq;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   450
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   451
    #[test]
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   452
    fn test_chunk_tracked_files() {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   453
        fn chunk(v: Vec<&'static str>) -> Vec<ExpandedManifestEntry> {
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   454
            v.into_iter()
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   455
                .map(|f| (HgPath::new(f.as_bytes()), NULL_NODE, None))
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   456
                .collect()
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   457
        }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   458
        let p = HgPath::new;
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   459
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   460
        let files = chunk(vec!["a"]);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   461
        let expected = vec![(p(""), chunk(vec!["a"]))];
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   462
        assert_eq!(chunk_tracked_files(files), expected);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   463
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   464
        let files = chunk(vec!["a", "b", "c"]);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   465
        let expected = vec![(p(""), chunk(vec!["a", "b", "c"]))];
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   466
        assert_eq!(chunk_tracked_files(files), expected);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   467
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   468
        let files = chunk(vec![
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   469
            "dir/a-new",
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   470
            "dir/a/mut",
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   471
            "dir/a/mut-mut",
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   472
            "dir/albert",
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   473
            "dir/b",
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   474
            "dir/subdir/c",
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   475
            "dir/subdir/d",
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   476
            "file",
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   477
        ]);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   478
        let expected = vec![
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   479
            (p("dir"), chunk(vec!["dir/a-new"])),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   480
            (p("dir/a"), chunk(vec!["dir/a/mut", "dir/a/mut-mut"])),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   481
            (p("dir"), chunk(vec!["dir/albert", "dir/b"])),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   482
            (p("dir/subdir"), chunk(vec!["dir/subdir/c", "dir/subdir/d"])),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   483
            (p(""), chunk(vec!["file"])),
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   484
        ];
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   485
        assert_eq!(chunk_tracked_files(files), expected);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   486
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   487
        // Doesn't get split
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   488
        let large_dir = vec![
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   489
            "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   490
            "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23",
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   491
        ];
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   492
        let files = chunk(large_dir.clone());
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   493
        let expected = vec![(p(""), chunk(large_dir))];
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   494
        assert_eq!(chunk_tracked_files(files), expected);
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   495
    }
8b7123c8947b update: add a Rust fast-path when updating from null (and clean)
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
   496
}