Commit 906b9677 authored by Simon Sapin's avatar Simon Sapin
Browse files

dirstate-v2: Extend node flags to 16 bits

Only 7 out of 8 available bits are used right now. Reserve some more.

Future versions of Mercurial may assign meaning to some of these bits,
with the limitation that then-older versions will always reset those bits to
unset when writing nodes.
(A new node is written for any mutation in its subtree, leaving the bytes of
the old node unreachable until the data file is rewritten entirely.)

Differential Revision: https://phab.mercurial-scm.org/D11661
parent 7ed0fc687220
......@@ -18,7 +18,7 @@ parsers = policy.importmod('parsers')
# Must match the constant of the same name in
# `rust/hg-core/src/dirstate_tree/on_disk.rs`
TREE_METADATA_SIZE = 44
NODE_SIZE = 43
NODE_SIZE = 44
# Must match the `TreeMetadata` Rust struct in
......@@ -50,7 +50,7 @@ TREE_METADATA = struct.Struct('>LLLLL4s20s')
# * 4 bytes: expected size
# * 4 bytes: mtime seconds
# * 4 bytes: mtime nanoseconds
NODE = struct.Struct('>LHHLHLLLLBlll')
NODE = struct.Struct('>LHHLHLLLLHlll')
assert TREE_METADATA_SIZE == TREE_METADATA.size
......
......@@ -372,7 +372,7 @@ Node components are:
This counter is used to implement `has_tracked_dir`.
* Offset 30:
A single `flags` byte that packs some boolean values as bits.
A `flags` fields that packs some boolean values as bits of a 16-bit integer.
Starting from least-significant, bit masks are::
WDIR_TRACKED = 1 << 0
......@@ -384,22 +384,29 @@ Node components are:
MODE_IS_SYMLINK = 1 << 6
The meaning of each bit is described below.
Other bits are unset.
* Offset 31:
Other bits are unset.
They may be assigned meaning if the future,
with the limitation that Mercurial versions that pre-date such meaning
will always reset those bits to unset when writing nodes.
(A new node is written for any mutation in its subtree,
leaving the bytes of the old node unreachable
until the data file is rewritten entirely.)
* Offset 32:
A `size` field described below, as a 32-bit integer.
Unlike in dirstate-v1, negative values are not used.
* Offset 35:
* Offset 36:
The seconds component of an `mtime` field described below,
as a 32-bit integer.
Unlike in dirstate-v1, negative values are not used.
* Offset 39:
* Offset 40:
The nanoseconds component of an `mtime` field described below,
as a 32-bit integer.
* (Offset 43: end of this node)
* (Offset 44: end of this node)
The meaning of the boolean values packed in `flags` is:
......
......@@ -33,7 +33,7 @@ pub(super) type IgnorePatternsHash = [u8; IGNORE_PATTERNS_HASH_LEN];
/// Must match constants of the same names in `mercurial/dirstateutils/v2.py`
const TREE_METADATA_SIZE: usize = 44;
const NODE_SIZE: usize = 43;
const NODE_SIZE: usize = 44;
/// Make sure that size-affecting changes are made knowingly
#[allow(unused)]
......@@ -94,15 +94,14 @@ pub(super) struct Node {
children: ChildNodes,
pub(super) descendants_with_entry_count: Size,
pub(super) tracked_descendants_count: Size,
flags: Flags,
flags: U16Be,
size: U32Be,
mtime: PackedTruncatedTimestamp,
}
bitflags! {
#[derive(BytesCast)]
#[repr(C)]
struct Flags: u8 {
struct Flags: u16 {
const WDIR_TRACKED = 1 << 0;
const P1_TRACKED = 1 << 1;
const P2_INFO = 1 << 2;
......@@ -296,8 +295,12 @@ impl Node {
})
}
fn flags(&self) -> Flags {
Flags::from_bits_truncate(self.flags.get())
}
fn has_entry(&self) -> bool {
self.flags.intersects(
self.flags().intersects(
Flags::WDIR_TRACKED | Flags::P1_TRACKED | Flags::P2_INFO,
)
}
......@@ -318,7 +321,7 @@ impl Node {
&self,
) -> Result<Option<TruncatedTimestamp>, DirstateV2ParseError> {
Ok(
if self.flags.contains(Flags::HAS_MTIME) && !self.has_entry() {
if self.flags().contains(Flags::HAS_MTIME) && !self.has_entry() {
Some(self.mtime.try_into()?)
} else {
None
......@@ -327,12 +330,12 @@ impl Node {
}
fn synthesize_unix_mode(&self) -> u32 {
let file_type = if self.flags.contains(Flags::MODE_IS_SYMLINK) {
let file_type = if self.flags().contains(Flags::MODE_IS_SYMLINK) {
libc::S_IFLNK
} else {
libc::S_IFREG
};
let permisions = if self.flags.contains(Flags::MODE_EXEC_PERM) {
let permisions = if self.flags().contains(Flags::MODE_EXEC_PERM) {
0o755
} else {
0o644
......@@ -342,15 +345,15 @@ impl Node {
fn assume_entry(&self) -> DirstateEntry {
// TODO: convert through raw bits instead?
let wdir_tracked = self.flags.contains(Flags::WDIR_TRACKED);
let p1_tracked = self.flags.contains(Flags::P1_TRACKED);
let p2_info = self.flags.contains(Flags::P2_INFO);
let mode_size = if self.flags.contains(Flags::HAS_MODE_AND_SIZE) {
let wdir_tracked = self.flags().contains(Flags::WDIR_TRACKED);
let p1_tracked = self.flags().contains(Flags::P1_TRACKED);
let p2_info = self.flags().contains(Flags::P2_INFO);
let mode_size = if self.flags().contains(Flags::HAS_MODE_AND_SIZE) {
Some((self.synthesize_unix_mode(), self.size.into()))
} else {
None
};
let mtime = if self.flags.contains(Flags::HAS_MTIME) {
let mtime = if self.flags().contains(Flags::HAS_MTIME) {
Some(self.mtime.truncated_seconds.into())
} else {
None
......@@ -600,7 +603,7 @@ impl Writer<'_, '_> {
tracked_descendants_count: node
.tracked_descendants_count
.into(),
flags,
flags: flags.bits().into(),
size,
mtime,
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment