##// END OF EJS Templates
transaction: actually delete file created during the transaction on rollback...
transaction: actually delete file created during the transaction on rollback Transaction currently has two modes: - one where file created during the transaction are deleted on rollback, - one where file created during the transaction are truncated to 0 on rollback. Before this change, `hg rollback` and `hg recover` are using the "delete" mode and transaction abort is using the "truncate" option. This difference is never really explained. A long time ago, there was two code paths, with this divergence existing for unclear reasons. When the two code paths got merged into a single one, a boolean argument have been added to preserve this divergence, mostly probably as a cargo cult. The divergence is weird and induce bad surprises, and the truncate behavior is a bit odds, introducing other bad surprises (e.g. 08ecbdba186f) So solve this, we stop using the "truncate" behavior and unify on the "delete" behavior. Despite being currently more "common", the truncate behavior seems less natural, resulting in the transaction leaving empty file around. This is landed on default, early in the cycle, to help us catch problems that could emerge.

File last commit:

r50527:048f829a default
r51703:5c3d0795 default
Show More
nodemap_docket.rs
108 lines | 3.6 KiB | application/rls-services+xml | RustLexer
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 use crate::errors::{HgError, HgResultExt};
Simon Sapin
rust: use the bytes-cast crate to parse persistent nodemaps...
r47119 use bytes_cast::{unaligned, BytesCast};
Simon Sapin
rust: Switch to the memmap2-rs crate...
r48767 use memmap2::Mmap;
Simon Sapin
rhg: use persistent nodemap when available...
r46706 use std::path::{Path, PathBuf};
Martin von Zweigbergk
rust-nodemap-docket: make unaware of `Repo`...
r49977 use crate::vfs::Vfs;
Simon Sapin
rhg: use persistent nodemap when available...
r46706
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(
Martin von Zweigbergk
rust-nodemap-docket: make unaware of `Repo`...
r49977 store_vfs: &Vfs,
Simon Sapin
rhg: use persistent nodemap when available...
r46706 index_path: &Path,
Simon Sapin
rust: Return HgError instead of RevlogError in revlog constructors...
r48777 ) -> Result<Option<(Self, Mmap)>, HgError> {
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) =
Martin von Zweigbergk
rust-nodemap-docket: make unaware of `Repo`...
r49977 store_vfs.read(&docket_path).io_not_found_as_none()?
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 {
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
Simon Sapin
rust: Return HgError instead of RevlogError in revlog constructors...
r48777 fn parse<T, E>(result: Result<T, E>) -> Result<T, HgError> {
result
.map_err(|_| HgError::corrupted("nodemap docket parse error"))
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 }
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?
Martin von Zweigbergk
rust-nodemap-docket: make unaware of `Repo`...
r49977 if let Some(mmap) =
store_vfs.mmap_open(&data_path).io_not_found_as_none()?
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 {
if mmap.len() >= data_length {
Ok(Some((docket, mmap)))
} else {
Simon Sapin
rust: Return HgError instead of RevlogError in revlog constructors...
r48777 Err(HgError::corrupted("persistent nodemap too short"))
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");
Raphaël Gomès
hg-core: remove unneeded util now that we support Rust 1.42+
r50527 let prefix = docket_name
.strip_suffix(".n.a")
.or_else(|| docket_name.strip_suffix(".n"))
Simon Sapin
rhg: use persistent nodemap when available...
r46706 .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)
}