Mercurial > hg
comparison mercurial/revlogutils/docket.py @ 47241:2219853a1503
revlogv2: track pending write in the docket and expose it to hooks
The docket is now able to write pending data. We could have used a distinct
intermediate files, however keeping everything in the same file will make it
simpler to keep track of the various involved files if necessary.
However it might prove more complicated for streaming clone. This will be dealt
with later.
Note that we lifted the stderr redirection in the test since we no longer suffer
from "unkown working directory parent" message.
Differential Revision: https://phab.mercurial-scm.org/D10631
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Mon, 03 May 2021 12:35:25 +0200 |
parents | 6597255a4f94 |
children | 4abd474a10af |
comparison
equal
deleted
inserted
replaced
47240:4f38ada3fc26 | 47241:2219853a1503 |
---|---|
17 | 17 |
18 from __future__ import absolute_import | 18 from __future__ import absolute_import |
19 | 19 |
20 import struct | 20 import struct |
21 | 21 |
22 from .. import ( | |
23 error, | |
24 ) | |
25 | |
22 from . import ( | 26 from . import ( |
23 constants, | 27 constants, |
24 ) | 28 ) |
25 | 29 |
26 # Docket format | 30 # Docket format |
27 # | 31 # |
28 # * 4 bytes: revlog version | 32 # * 4 bytes: revlog version |
29 # | This is mandatory as docket must be compatible with the previous | 33 # | This is mandatory as docket must be compatible with the previous |
30 # | revlog index header. | 34 # | revlog index header. |
31 # * 8 bytes: size of index data | 35 # * 8 bytes: size of index data |
32 S_HEADER = struct.Struct(constants.INDEX_HEADER.format + 'L') | 36 # * 8 bytes: pending size of index data |
37 S_HEADER = struct.Struct(constants.INDEX_HEADER.format + 'LL') | |
33 | 38 |
34 | 39 |
35 class RevlogDocket(object): | 40 class RevlogDocket(object): |
36 """metadata associated with revlog""" | 41 """metadata associated with revlog""" |
37 | 42 |
38 def __init__(self, revlog, version_header=None, index_end=0): | 43 def __init__( |
44 self, | |
45 revlog, | |
46 use_pending=False, | |
47 version_header=None, | |
48 index_end=0, | |
49 pending_index_end=0, | |
50 ): | |
39 self._version_header = version_header | 51 self._version_header = version_header |
52 self._read_only = bool(use_pending) | |
40 self._dirty = False | 53 self._dirty = False |
41 self._radix = revlog.radix | 54 self._radix = revlog.radix |
42 self._path = revlog._docket_file | 55 self._path = revlog._docket_file |
43 self._opener = revlog.opener | 56 self._opener = revlog.opener |
44 self._index_end = index_end | 57 # this assert should be True as long as we have a single index filename |
58 assert index_end <= pending_index_end | |
59 self._initial_index_end = index_end | |
60 self._pending_index_end = pending_index_end | |
61 if use_pending: | |
62 self._index_end = self._pending_index_end | |
63 else: | |
64 self._index_end = self._initial_index_end | |
45 | 65 |
46 def index_filepath(self): | 66 def index_filepath(self): |
47 """file path to the current index file associated to this docket""" | 67 """file path to the current index file associated to this docket""" |
48 # very simplistic version at first | 68 # very simplistic version at first |
49 return b"%s.idx" % self._radix | 69 return b"%s.idx" % self._radix |
56 def index_end(self, new_size): | 76 def index_end(self, new_size): |
57 if new_size != self._index_end: | 77 if new_size != self._index_end: |
58 self._index_end = new_size | 78 self._index_end = new_size |
59 self._dirty = True | 79 self._dirty = True |
60 | 80 |
61 def write(self, transaction, stripping=False): | 81 def write(self, transaction, pending=False, stripping=False): |
62 """write the modification of disk if any | 82 """write the modification of disk if any |
63 | 83 |
64 This make the new content visible to all process""" | 84 This make the new content visible to all process""" |
65 if self._dirty: | 85 if not self._dirty: |
86 return False | |
87 else: | |
88 if self._read_only: | |
89 msg = b'writing read-only docket: %s' | |
90 msg %= self._path | |
91 raise error.ProgrammingError(msg) | |
66 if not stripping: | 92 if not stripping: |
67 # XXX we could, leverage the docket while stripping. However it | 93 # XXX we could, leverage the docket while stripping. However it |
68 # is not powerfull enough at the time of this comment | 94 # is not powerfull enough at the time of this comment |
69 transaction.addbackup(self._path, location=b'store') | 95 transaction.addbackup(self._path, location=b'store') |
70 with self._opener(self._path, mode=b'w', atomictemp=True) as f: | 96 with self._opener(self._path, mode=b'w', atomictemp=True) as f: |
71 f.write(self._serialize()) | 97 f.write(self._serialize(pending=pending)) |
72 self._dirty = False | 98 # if pending we still need to the write final data eventually |
99 self._dirty = pending | |
100 return True | |
73 | 101 |
74 def _serialize(self): | 102 def _serialize(self, pending=False): |
103 if pending: | |
104 official_index_end = self._initial_index_end | |
105 else: | |
106 official_index_end = self._index_end | |
107 | |
108 # this assert should be True as long as we have a single index filename | |
109 assert official_index_end <= self._index_end | |
75 data = ( | 110 data = ( |
76 self._version_header, | 111 self._version_header, |
112 official_index_end, | |
77 self._index_end, | 113 self._index_end, |
78 ) | 114 ) |
79 return S_HEADER.pack(*data) | 115 return S_HEADER.pack(*data) |
80 | 116 |
81 | 117 |
86 docket = RevlogDocket(revlog, version_header=version_header) | 122 docket = RevlogDocket(revlog, version_header=version_header) |
87 docket._dirty = True | 123 docket._dirty = True |
88 return docket | 124 return docket |
89 | 125 |
90 | 126 |
91 def parse_docket(revlog, data): | 127 def parse_docket(revlog, data, use_pending=False): |
92 """given some docket data return a docket object for the given revlog""" | 128 """given some docket data return a docket object for the given revlog""" |
93 header = S_HEADER.unpack(data[: S_HEADER.size]) | 129 header = S_HEADER.unpack(data[: S_HEADER.size]) |
94 version_header, index_size = header | 130 version_header, index_size, pending_index_size = header |
95 docket = RevlogDocket( | 131 docket = RevlogDocket( |
96 revlog, | 132 revlog, |
133 use_pending=use_pending, | |
97 version_header=version_header, | 134 version_header=version_header, |
98 index_end=index_size, | 135 index_end=index_size, |
136 pending_index_end=pending_index_size, | |
99 ) | 137 ) |
100 return docket | 138 return docket |