Mercurial > public > mercurial-scm > hg-stable
view rust/hg-core/src/revlog/nodemap_docket.rs @ 46606:c692384bb559
copies: rearrange all value comparison conditional
To properly handle the newly tested case (chaining of merges) we will need to
detect more accurately when an actualy merging of the copy information (and
superseed the two existing data). Before starting to do so, we need to
reorganise the values comparison to introduce different conditional branches
when such actual merging is needed/detected.
To avoid mixing too many change in this complicated code, we do the
reorganisation before adding the "overwrite detection" logic in the next
changesets.
Differential Revision: https://phab.mercurial-scm.org/D9612
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Mon, 14 Dec 2020 19:26:33 +0100 |
parents | 43d63979a75e |
children | 842f2372ced6 |
line wrap: on
line source
use crate::errors::{HgError, HgResultExt}; use bytes_cast::{unaligned, BytesCast}; use memmap::Mmap; use std::path::{Path, PathBuf}; use super::revlog::RevlogError; use crate::repo::Repo; use crate::utils::strip_suffix; const ONDISK_VERSION: u8 = 1; pub(super) struct NodeMapDocket { pub data_length: usize, // TODO: keep here more of the data from `parse()` when we need it } #[derive(BytesCast)] #[repr(C)] struct DocketHeader { uid_size: u8, _tip_rev: unaligned::U64Be, data_length: unaligned::U64Be, _data_unused: unaligned::U64Be, tip_node_size: unaligned::U64Be, } impl NodeMapDocket { /// Return `Ok(None)` when the caller should proceed without a persistent /// nodemap: /// /// * This revlog does not have a `.n` docket file (it is not generated for /// small revlogs), or /// * The docket has an unsupported version number (repositories created by /// later hg, maybe that should be a requirement instead?), or /// * The docket file points to a missing (likely deleted) data file (this /// can happen in a rare race condition). pub fn read_from_file( repo: &Repo, index_path: &Path, ) -> Result<Option<(Self, Mmap)>, RevlogError> { let docket_path = index_path.with_extension("n"); let docket_bytes = if let Some(bytes) = repo.store_vfs().read(&docket_path).io_not_found_as_none()? { bytes } else { return Ok(None); }; let input = if let Some((&ONDISK_VERSION, rest)) = docket_bytes.split_first() { rest } else { return Ok(None); }; /// Treat any error as a parse error fn parse<T, E>(result: Result<T, E>) -> Result<T, RevlogError> { result.map_err(|_| { HgError::corrupted("nodemap docket parse error").into() }) } let (header, rest) = parse(DocketHeader::from_bytes(input))?; let uid_size = header.uid_size as usize; // TODO: do we care about overflow for 4 GB+ nodemap files on 32-bit // systems? let tip_node_size = header.tip_node_size.get() as usize; let data_length = header.data_length.get() as usize; let (uid, rest) = parse(u8::slice_from_bytes(rest, uid_size))?; let (_tip_node, _rest) = parse(u8::slice_from_bytes(rest, tip_node_size))?; let uid = parse(std::str::from_utf8(uid))?; let docket = NodeMapDocket { data_length }; let data_path = rawdata_path(&docket_path, uid); // TODO: use `vfs.read()` here when the `persistent-nodemap.mmap` // config is false? if let Some(mmap) = repo .store_vfs() .mmap_open(&data_path) .io_not_found_as_none()? { if mmap.len() >= data_length { Ok(Some((docket, mmap))) } else { Err(HgError::corrupted("persistent nodemap too short").into()) } } else { Ok(None) } } } fn rawdata_path(docket_path: &Path, uid: &str) -> PathBuf { let docket_name = docket_path .file_name() .expect("expected a base name") .to_str() .expect("expected an ASCII file name in the store"); let prefix = strip_suffix(docket_name, ".n.a") .or_else(|| strip_suffix(docket_name, ".n")) .expect("expected docket path in .n or .n.a"); let name = format!("{}-{}.nd", prefix, uid); docket_path .parent() .expect("expected a non-root path") .join(name) }