##// END OF EJS Templates
dirstate-tree: Remove DirstateMap::iter_node_data_mut...
dirstate-tree: Remove DirstateMap::iter_node_data_mut In an upcoming changeset we want DirstateMap to be able to work directly with nodes in their "on disk" representation, without always allocating corresponding in-memory data structures. Nodes would have two possible representations: one immutable "on disk" refering to the bytes buffer of the contents of the .hg/dirstate file, and one mutable with HashMap like the curren data structure. These nodes would have copy-on-write semantics: when an immutable node would need to be mutated, instead we allocate new mutable node for it and its ancestors. A mutable iterator of the entire tree would still be possible, but it would become much more expensive since we’d need to allocate mutable nodes for everything. Instead, remove this iterator. It was only used to clear ambiguous mtimes while serializing the `DirstateMap`. Instead clearing and serialization are now two separate passes. Clearing first uses an immutable iterator to collect the paths of nodes that need to be cleared, then accesses only those nodes mutably. Differential Revision: https://phab.mercurial-scm.org/D10744

File last commit:

r47375:842f2372 default
r48121:73f23e76 default
Show More
nodemap_docket.rs
121 lines | 3.9 KiB | application/rls-services+xml | RustLexer
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 use crate::errors::{HgError, HgResultExt};
Simon Sapin
rhg: Don’t attempt to read persistent nodemap without .hg/requires opt-in...
r47375 use crate::requirements;
Simon Sapin
rust: use the bytes-cast crate to parse persistent nodemaps...
r47119 use bytes_cast::{unaligned, BytesCast};
Simon Sapin
rhg: use persistent nodemap when available...
r46706 use memmap::Mmap;
use std::path::{Path, PathBuf};
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 use super::revlog::RevlogError;
use crate::repo::Repo;
Simon Sapin
rhg: use persistent nodemap when available...
r46706 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
}
Simon Sapin
rust: use the bytes-cast crate to parse persistent nodemaps...
r47119 #[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,
}
Simon Sapin
rhg: use persistent nodemap when available...
r46706 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(
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 repo: &Repo,
Simon Sapin
rhg: use persistent nodemap when available...
r46706 index_path: &Path,
) -> Result<Option<(Self, Mmap)>, RevlogError> {
Simon Sapin
rhg: Don’t attempt to read persistent nodemap without .hg/requires opt-in...
r47375 if !repo
.requirements()
.contains(requirements::NODEMAP_REQUIREMENT)
{
// If .hg/requires does not opt it, don’t try to open a nodemap
return Ok(None);
}
Simon Sapin
rhg: use persistent nodemap when available...
r46706 let docket_path = index_path.with_extension("n");
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 let docket_bytes = if let Some(bytes) =
repo.store_vfs().read(&docket_path).io_not_found_as_none()?
{
bytes
} else {
return Ok(None);
Simon Sapin
rhg: use persistent nodemap when available...
r46706 };
Simon Sapin
rust: use the bytes-cast crate to parse persistent nodemaps...
r47119 let input = if let Some((&ONDISK_VERSION, rest)) =
Simon Sapin
rhg: use persistent nodemap when available...
r46706 docket_bytes.split_first()
{
rest
} else {
return Ok(None);
};
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 /// 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))?;
Simon Sapin
rust: use the bytes-cast crate to parse persistent nodemaps...
r47119 let uid_size = header.uid_size as usize;
Simon Sapin
rhg: use persistent nodemap when available...
r46706 // TODO: do we care about overflow for 4 GB+ nodemap files on 32-bit
// systems?
Simon Sapin
rust: use the bytes-cast crate to parse persistent nodemaps...
r47119 let tip_node_size = header.tip_node_size.get() as usize;
let data_length = header.data_length.get() as usize;
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 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))?;
Simon Sapin
rhg: use persistent nodemap when available...
r46706 let docket = NodeMapDocket { data_length };
let data_path = rawdata_path(&docket_path, uid);
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 // TODO: use `vfs.read()` here when the `persistent-nodemap.mmap`
Simon Sapin
rhg: use persistent nodemap when available...
r46706 // config is false?
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 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())
Simon Sapin
rhg: use persistent nodemap when available...
r46706 }
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 } else {
Simon Sapin
rhg: Don’t attempt to read persistent nodemap without .hg/requires opt-in...
r47375 // Even if .hg/requires opted in, some revlogs are deemed small
// enough to not need a persistent nodemap.
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 Ok(None)
Simon Sapin
rhg: use persistent nodemap when available...
r46706 }
}
}
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)
}