Mercurial > public > mercurial-scm > hg-stable
diff mercurial/dirstateutils/docket.py @ 47674:ff97e793ed36
dirstate-v2: Introduce a docket file
.hg/dirstate now only contains some metadata to point to a separate data file
named .hg/dirstate.{}.d with a random hexadecimal identifier. For now every
update creates a new data file and removes the old one, but later we?ll
(usually) append to an existing file.
Separating into two files allows doing the "write to a temporary file then
atomically rename into destination" dance with only a small docket file,
without always rewriting a lot of data.
Differential Revision: https://phab.mercurial-scm.org/D11088
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Thu, 08 Jul 2021 12:18:21 +0200 |
parents | |
children | 78f7f0d490ee |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial/dirstateutils/docket.py Thu Jul 08 12:18:21 2021 +0200 @@ -0,0 +1,62 @@ +# dirstatedocket.py - docket file for dirstate-v2 +# +# Copyright Mercurial Contributors +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +from __future__ import absolute_import + +import struct + +from ..revlogutils import docket as docket_mod + + +V2_FORMAT_MARKER = b"dirstate-v2\n" + +# * 12 bytes: format marker +# * 32 bytes: node ID of the working directory's first parent +# * 32 bytes: node ID of the working directory's second parent +# * 4 bytes: big-endian used size of the data file +# * 1 byte: length of the data file's UUID +# * variable: data file's UUID +# +# Node IDs are null-padded if shorter than 32 bytes. +# A data file shorter than the specified used size is corrupted (truncated) +HEADER = struct.Struct(">{}s32s32sLB".format(len(V2_FORMAT_MARKER))) + + +class DirstateDocket(object): + data_filename_pattern = b'dirstate.%s.d' + + def __init__(self, parents, data_size, uuid): + self.parents = parents + self.data_size = data_size + self.uuid = uuid + + @classmethod + def with_new_uuid(cls, parents, data): + return cls(parents, data, docket_mod.make_uid()) + + @classmethod + def parse(cls, data, nodeconstants): + if not data: + parents = (nodeconstants.nullid, nodeconstants.nullid) + return cls(parents, 0, None) + marker, p1, p2, data_size, uuid_size = HEADER.unpack_from(data) + if marker != V2_FORMAT_MARKER: + raise ValueError("expected dirstate-v2 marker") + uuid = data[HEADER.size : HEADER.size + uuid_size] + p1 = p1[: nodeconstants.nodelen] + p2 = p2[: nodeconstants.nodelen] + return cls((p1, p2), data_size, uuid) + + def serialize(self): + p1, p2 = self.parents + header = HEADER.pack( + V2_FORMAT_MARKER, p1, p2, self.data_size, len(self.uuid) + ) + return header + self.uuid + + def data_filename(self): + return self.data_filename_pattern % self.uuid