##// END OF EJS Templates
recover: only apply last journal record per file (issue6423)...
recover: only apply last journal record per file (issue6423) This got broken in 2019 when the size check was introduced. It is most noticable when dealing with transactions that involve an inline to non-inline revlog storage transaction. It wasn't seen as much at the time because the in-memory journal actually de-duplicated the entry implicity, but since 63edc384d3b7 the on-disk journal is used for rollback as well as recover. Differential Revision: https://phab.mercurial-scm.org/D10726

File last commit:

r47894:cd8ca38f default
r48061:672f48cf default
Show More
dirstate.rs
133 lines | 3.5 KiB | application/rls-services+xml | RustLexer
// dirstate module
//
// Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
//
// This software may be used and distributed according to the terms of the
// GNU General Public License version 2 or any later version.
use crate::errors::HgError;
use crate::revlog::Node;
use crate::utils::hg_path::{HgPath, HgPathBuf};
use crate::FastHashMap;
use bytes_cast::{unaligned, BytesCast};
use std::convert::TryFrom;
pub mod dirs_multiset;
pub mod dirstate_map;
pub mod parsers;
pub mod status;
#[derive(Debug, PartialEq, Clone, BytesCast)]
#[repr(C)]
pub struct DirstateParents {
pub p1: Node,
pub p2: Node,
}
/// The C implementation uses all signed types. This will be an issue
/// either when 4GB+ source files are commonplace or in 2038, whichever
/// comes first.
#[derive(Debug, PartialEq, Copy, Clone)]
pub struct DirstateEntry {
pub state: EntryState,
pub mode: i32,
pub mtime: i32,
pub size: i32,
}
impl DirstateEntry {
pub fn is_non_normal(&self) -> bool {
self.state != EntryState::Normal || self.mtime == MTIME_UNSET
}
pub fn is_from_other_parent(&self) -> bool {
self.state == EntryState::Normal && self.size == SIZE_FROM_OTHER_PARENT
}
// TODO: other platforms
#[cfg(unix)]
pub fn mode_changed(
&self,
filesystem_metadata: &std::fs::Metadata,
) -> bool {
use std::os::unix::fs::MetadataExt;
const EXEC_BIT_MASK: u32 = 0o100;
let dirstate_exec_bit = (self.mode as u32) & EXEC_BIT_MASK;
let fs_exec_bit = filesystem_metadata.mode() & EXEC_BIT_MASK;
dirstate_exec_bit != fs_exec_bit
}
}
#[derive(BytesCast)]
#[repr(C)]
struct RawEntry {
state: u8,
mode: unaligned::I32Be,
size: unaligned::I32Be,
mtime: unaligned::I32Be,
length: unaligned::I32Be,
}
const MTIME_UNSET: i32 = -1;
/// A `DirstateEntry` with a size of `-2` means that it was merged from the
/// other parent. This allows revert to pick the right status back during a
/// merge.
pub const SIZE_FROM_OTHER_PARENT: i32 = -2;
pub type StateMap = FastHashMap<HgPathBuf, DirstateEntry>;
pub type StateMapIter<'a> =
Box<dyn Iterator<Item = (&'a HgPath, &'a DirstateEntry)> + Send + 'a>;
pub type CopyMap = FastHashMap<HgPathBuf, HgPathBuf>;
pub type CopyMapIter<'a> =
Box<dyn Iterator<Item = (&'a HgPath, &'a HgPath)> + Send + 'a>;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum EntryState {
Normal,
Added,
Removed,
Merged,
Unknown,
}
impl EntryState {
pub fn is_tracked(self) -> bool {
use EntryState::*;
match self {
Normal | Added | Merged => true,
Removed | Unknown => false,
}
}
}
impl TryFrom<u8> for EntryState {
type Error = HgError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
b'n' => Ok(EntryState::Normal),
b'a' => Ok(EntryState::Added),
b'r' => Ok(EntryState::Removed),
b'm' => Ok(EntryState::Merged),
b'?' => Ok(EntryState::Unknown),
_ => Err(HgError::CorruptedRepository(format!(
"Incorrect dirstate entry state {}",
value
))),
}
}
}
impl Into<u8> for EntryState {
fn into(self) -> u8 {
match self {
EntryState::Normal => b'n',
EntryState::Added => b'a',
EntryState::Removed => b'r',
EntryState::Merged => b'm',
EntryState::Unknown => b'?',
}
}
}