##// END OF EJS Templates
revlogv2: track pending write in the docket and expose it to hooks...
marmoute -
r48015:2219853a default
parent child Browse files
Show More
@@ -395,7 +395,6 b' class changelog(revlog.revlog):'
395 395 ``concurrencychecker`` will be passed to the revlog init function, see
396 396 the documentation there.
397 397 """
398
399 398 revlog.revlog.__init__(
400 399 self,
401 400 opener,
@@ -484,6 +483,8 b' class changelog(revlog.revlog):'
484 483 def _writepending(self, tr):
485 484 """create a file containing the unfinalized state for
486 485 pretxnchangegroup"""
486 if self._docket:
487 return self._docket.write(tr, pending=True)
487 488 if self._delaybuf:
488 489 # make a temporary copy of the index
489 490 fp1 = self._realopener(self._indexfile)
@@ -1150,7 +1150,6 b' coreconfigitem('
1150 1150 )
1151 1151 # "out of experimental" todo list.
1152 1152 #
1153 # * expose transaction content hooks during pre-commit validation
1154 1153 # * include management of a persistent nodemap in the main docket
1155 1154 # * enforce a "no-truncate" policy for mmap safety
1156 1155 # - for censoring operation
@@ -529,7 +529,9 b' class revlog(object):'
529 529 if self._initempty:
530 530 self._docket = docketutil.default_docket(self, header)
531 531 else:
532 self._docket = docketutil.parse_docket(self, entry_data)
532 self._docket = docketutil.parse_docket(
533 self, entry_data, use_pending=self._trypending
534 )
533 535 self._indexfile = self._docket.index_filepath()
534 536 index_data = b''
535 537 index_size = self._docket.index_end
@@ -19,6 +19,10 b' from __future__ import absolute_import'
19 19
20 20 import struct
21 21
22 from .. import (
23 error,
24 )
25
22 26 from . import (
23 27 constants,
24 28 )
@@ -29,19 +33,35 b' from . import ('
29 33 # | This is mandatory as docket must be compatible with the previous
30 34 # | revlog index header.
31 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 40 class RevlogDocket(object):
36 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 51 self._version_header = version_header
52 self._read_only = bool(use_pending)
40 53 self._dirty = False
41 54 self._radix = revlog.radix
42 55 self._path = revlog._docket_file
43 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 66 def index_filepath(self):
47 67 """file path to the current index file associated to this docket"""
@@ -58,22 +78,38 b' class RevlogDocket(object):'
58 78 self._index_end = new_size
59 79 self._dirty = True
60 80
61 def write(self, transaction, stripping=False):
81 def write(self, transaction, pending=False, stripping=False):
62 82 """write the modification of disk if any
63 83
64 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 92 if not stripping:
67 93 # XXX we could, leverage the docket while stripping. However it
68 94 # is not powerfull enough at the time of this comment
69 95 transaction.addbackup(self._path, location=b'store')
70 96 with self._opener(self._path, mode=b'w', atomictemp=True) as f:
71 f.write(self._serialize())
72 self._dirty = False
97 f.write(self._serialize(pending=pending))
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 110 data = (
76 111 self._version_header,
112 official_index_end,
77 113 self._index_end,
78 114 )
79 115 return S_HEADER.pack(*data)
@@ -88,13 +124,15 b' def default_docket(revlog, version_heade'
88 124 return docket
89 125
90 126
91 def parse_docket(revlog, data):
127 def parse_docket(revlog, data, use_pending=False):
92 128 """given some docket data return a docket object for the given revlog"""
93 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 131 docket = RevlogDocket(
96 132 revlog,
133 use_pending=use_pending,
97 134 version_header=version_header,
98 135 index_end=index_size,
136 pending_index_end=pending_index_size,
99 137 )
100 138 return docket
@@ -46,13 +46,13 b' synchronisation+output script:'
46 46 $ cat << EOF > script/external.sh
47 47 > #!/bin/sh
48 48 > $RUNTESTDIR/testlib/wait-on-file 5 $HG_TEST_FILE_EXT_UNLOCK $HG_TEST_FILE_EXT_WAITING
49 > hg log --rev 'tip' -T 'external: {rev} {desc}\n' > $TESTTMP/output/external.out 2>/dev/null
49 > hg log --rev 'tip' -T 'external: {rev} {desc}\n' > $TESTTMP/output/external.out
50 50 > touch $HG_TEST_FILE_EXT_DONE
51 51 > EOF
52 52 $ chmod +x script/external.sh
53 53 $ cat << EOF > script/internal.sh
54 54 > #!/bin/sh
55 > hg log --rev 'tip' -T 'internal: {rev} {desc}\n' > $TESTTMP/output/internal.out 2>/dev/null
55 > hg log --rev 'tip' -T 'internal: {rev} {desc}\n' > $TESTTMP/output/internal.out
56 56 > $RUNTESTDIR/testlib/wait-on-file 5 $HG_TEST_FILE_EXT_DONE $HG_TEST_FILE_EXT_UNLOCK
57 57 > EOF
58 58 $ chmod +x script/internal.sh
@@ -124,8 +124,7 b' the repository should still be inline (f'
124 124 $ make_one_commit first
125 125 pre-commit: -1
126 126 external: -1
127 internal: 0 first (revlogv1 !)
128 internal: -1 (revlogv2 known-bad-output !)
127 internal: 0 first
129 128 post-tr: 0 first
130 129
131 130 #if revlogv1
@@ -150,8 +149,7 b' the repository should still be inline (f'
150 149 $ make_one_commit second
151 150 pre-commit: 0 first
152 151 external: 0 first
153 internal: 1 second (revlogv1 !)
154 internal: 0 first (revlogv2 known-bad-output !)
152 internal: 1 second
155 153 post-tr: 1 second
156 154
157 155 #if revlogv1
@@ -177,8 +175,7 b' the repository should still be inline (f'
177 175 pre-commit: 1 second
178 176 warning: repository is unrelated
179 177 external: 1 second
180 internal: 5 r3 (revlogv1 !)
181 internal: 1 second (revlogv2 known-bad-output !)
178 internal: 5 r3
182 179 post-tr: 5 r3
183 180
184 181 #if revlogv1
@@ -203,8 +200,7 b' the repository should no longer be inlin'
203 200 $ make_one_pull 400
204 201 pre-commit: 5 r3
205 202 external: 5 r3
206 internal: 402 r400 (revlogv1 !)
207 internal: 5 r3 (revlogv2 known-bad-output !)
203 internal: 402 r400
208 204 post-tr: 402 r400
209 205
210 206 #if revlogv1
@@ -229,8 +225,7 b' the repository should no longer be inlin'
229 225 $ make_one_commit third
230 226 pre-commit: 402 r400
231 227 external: 402 r400
232 internal: 403 third (revlogv1 !)
233 internal: 402 r400 (revlogv2 known-bad-output !)
228 internal: 403 third
234 229 post-tr: 403 third
235 230
236 231 #if revlogv1
@@ -256,8 +251,7 b' the repository should no longer be inlin'
256 251 $ make_one_pull tip
257 252 pre-commit: 403 third
258 253 external: 403 third
259 internal: 503 r500 (revlogv1 !)
260 internal: 403 third (revlogv2 known-bad-output !)
254 internal: 503 r500
261 255 post-tr: 503 r500
262 256
263 257 #if revlogv1
General Comments 0
You need to be logged in to leave comments. Login now