##// END OF EJS Templates
revlog: test that pending hooks properly see the repository on split...
marmoute -
r51240:6487737e stable
parent child Browse files
Show More
@@ -1,394 +1,433 b''
1 1 Test correctness of revlog inline -> non-inline transition
2 2 ----------------------------------------------------------
3 3
4 4 Helper extension to intercept renames and kill process
5 5
6 6 $ cat > $TESTTMP/intercept_before_rename.py << EOF
7 7 > import os
8 8 > import signal
9 9 > from mercurial import extensions, util
10 10 >
11 11 > def extsetup(ui):
12 12 > def close(orig, *args, **kwargs):
13 13 > path = util.normpath(args[0]._atomictempfile__name)
14 14 > if path.endswith(b'/.hg/store/data/file.i'):
15 15 > os.kill(os.getpid(), signal.SIGKILL)
16 16 > return orig(*args, **kwargs)
17 17 > extensions.wrapfunction(util.atomictempfile, 'close', close)
18 18 > EOF
19 19
20 20 $ cat > $TESTTMP/intercept_after_rename.py << EOF
21 21 > import os
22 22 > import signal
23 23 > from mercurial import extensions, util
24 24 >
25 25 > def extsetup(ui):
26 26 > def close(orig, *args, **kwargs):
27 27 > path = util.normpath(args[0]._atomictempfile__name)
28 28 > r = orig(*args, **kwargs)
29 29 > if path.endswith(b'/.hg/store/data/file.i'):
30 30 > os.kill(os.getpid(), signal.SIGKILL)
31 31 > return r
32 32 > extensions.wrapfunction(util.atomictempfile, 'close', close)
33 33 > EOF
34 34
35 35 $ cat > $TESTTMP/killme.py << EOF
36 36 > import os
37 37 > import signal
38 38 >
39 39 > def killme(ui, repo, hooktype, **kwargs):
40 40 > os.kill(os.getpid(), signal.SIGKILL)
41 41 > EOF
42 42
43 43 $ cat > $TESTTMP/reader_wait_split.py << EOF
44 44 > import os
45 45 > import signal
46 46 > from mercurial import extensions, revlog, testing
47 47 > def _wait_post_load(orig, self, *args, **kwargs):
48 48 > wait = b'data/file' in self.radix
49 49 > if wait:
50 50 > testing.wait_file(b"$TESTTMP/writer-revlog-split")
51 51 > r = orig(self, *args, **kwargs)
52 52 > if wait:
53 53 > testing.write_file(b"$TESTTMP/reader-index-read")
54 54 > testing.wait_file(b"$TESTTMP/writer-revlog-unsplit")
55 55 > return r
56 56 >
57 57 > def extsetup(ui):
58 58 > extensions.wrapfunction(revlog.revlog, '_loadindex', _wait_post_load)
59 59 > EOF
60 60
61 61 setup a repository for tests
62 62 ----------------------------
63 63
64 64 $ cat >> $HGRCPATH << EOF
65 65 > [format]
66 66 > revlog-compression=none
67 67 > EOF
68 68
69 69 $ hg init troffset-computation
70 70 $ cd troffset-computation
71 71 $ printf '%20d' '1' > file
72 72 $ hg commit -Aqma
73 73 $ printf '%1024d' '1' > file
74 74 $ hg commit -Aqmb
75 75 $ printf '%20d' '1' > file
76 76 $ hg commit -Aqmc
77 77 $ dd if=/dev/zero of=file bs=1k count=128 > /dev/null 2>&1
78 78 $ hg commit -AqmD
79 79
80 80 Reference size:
81 81 $ f -s file
82 82 file: size=131072
83 83 $ f -s .hg/store/data/file*
84 84 .hg/store/data/file.d: size=132139
85 85 .hg/store/data/file.i: size=256
86 86
87 87 $ cd ..
88 88
89 89
90 90 Test a hard crash after the file was split but before the transaction was committed
91 91 ===================================================================================
92 92
93 93 Test offset computation to correctly factor in the index entries themselves.
94 94 Also test that the new data size has the correct size if the transaction is aborted
95 95 after the index has been replaced.
96 96
97 97 Test repo has commits a, b, c, D, where D is large (grows the revlog enough that it
98 98 transitions to non-inline storage). The clone initially has changes a, b
99 99 and will transition to non-inline storage when adding c, D.
100 100
101 101 If the transaction adding c, D is rolled back, then we don't undo the revlog split,
102 102 but truncate the index and the data to remove both c and D.
103 103
104 104
105 105 $ hg clone --quiet --rev 1 troffset-computation troffset-computation-copy
106 106 $ cd troffset-computation-copy
107 107
108 108 Reference size:
109 109 $ f -s file
110 110 file: size=1024
111 111 $ f -s .hg/store/data/file*
112 112 .hg/store/data/file.i: size=1174
113 113
114 114 $ cat > .hg/hgrc <<EOF
115 115 > [hooks]
116 116 > pretxnchangegroup = python:$TESTTMP/killme.py:killme
117 117 > EOF
118 118 #if chg
119 119 $ hg pull ../troffset-computation
120 120 pulling from ../troffset-computation
121 121 [255]
122 122 #else
123 123 $ hg pull ../troffset-computation
124 124 pulling from ../troffset-computation
125 125 Killed
126 126 [137]
127 127 #endif
128 128
129 129
130 130 The revlog have been split on disk
131 131
132 132 $ f -s .hg/store/data/file*
133 133 .hg/store/data/file.d: size=132139
134 134 .hg/store/data/file.i: size=256
135 135
136 136 $ cat .hg/store/journal | tr -s '\000' ' ' | grep data/file | tail -1
137 137 data/file.i 128
138 138
139 139 The first file.i entry should match the "Reference size" above.
140 140 The first file.d entry is the temporary record during the split,
141 141
142 142 The second entry after the split happened. The sum of the second file.d
143 143 and the second file.i entry should match the first file.i entry.
144 144
145 145 $ cat .hg/store/journal | tr -s '\000' ' ' | grep data/file
146 146 data/file.i 1174
147 147 data/file.d 0
148 148 data/file.d 1046
149 149 data/file.i 128
150 150 $ hg recover
151 151 rolling back interrupted transaction
152 152 (verify step skipped, run `hg verify` to check your repository content)
153 153 $ f -s .hg/store/data/file*
154 154 .hg/store/data/file.d: size=1046
155 155 .hg/store/data/file.i: size=128
156 156 $ hg tip
157 157 changeset: 1:cfa8d6e60429
158 158 tag: tip
159 159 user: test
160 160 date: Thu Jan 01 00:00:00 1970 +0000
161 161 summary: b
162 162
163 163 $ hg verify -q
164 164 warning: revlog 'data/file.d' not in fncache!
165 165 1 warnings encountered!
166 166 hint: run "hg debugrebuildfncache" to recover from corrupt fncache
167 167 $ hg debugrebuildfncache --only-data
168 168 adding data/file.d
169 169 1 items added, 0 removed from fncache
170 170 $ hg verify -q
171 171 $ cd ..
172 172
173 173 Test a hard crash right before the index is move into place
174 174 ===========================================================
175 175
176 176 Now retry the procedure but intercept the rename of the index and check that
177 177 the journal does not contain the new index size. This demonstrates the edge case
178 178 where the data file is left as garbage.
179 179
180 180 $ hg clone --quiet --rev 1 troffset-computation troffset-computation-copy2
181 181 $ cd troffset-computation-copy2
182 182
183 183 Reference size:
184 184 $ f -s file
185 185 file: size=1024
186 186 $ f -s .hg/store/data/file*
187 187 .hg/store/data/file.i: size=1174
188 188
189 189 $ cat > .hg/hgrc <<EOF
190 190 > [extensions]
191 191 > intercept_rename = $TESTTMP/intercept_before_rename.py
192 192 > [hooks]
193 193 > pretxnchangegroup = python:$TESTTMP/killme.py:killme
194 194 > EOF
195 195 #if chg
196 196 $ hg pull ../troffset-computation
197 197 pulling from ../troffset-computation
198 198 [255]
199 199 #else
200 200 $ hg pull ../troffset-computation
201 201 pulling from ../troffset-computation
202 202 Killed
203 203 [137]
204 204 #endif
205 205
206 206 The data file is created, but the revlog is still inline
207 207
208 208 $ f -s .hg/store/data/file*
209 209 .hg/store/data/file.d: size=132139
210 210 .hg/store/data/file.i: size=132395
211 211
212 212 $ cat .hg/store/journal | tr -s '\000' ' ' | grep data/file
213 213 data/file.i 1174
214 214 data/file.d 0
215 215 data/file.d 1046
216 216
217 217 $ hg recover
218 218 rolling back interrupted transaction
219 219 (verify step skipped, run `hg verify` to check your repository content)
220 220 $ f -s .hg/store/data/file*
221 221 .hg/store/data/file.d: size=1046
222 222 .hg/store/data/file.i: size=1174
223 223 $ hg tip
224 224 changeset: 1:cfa8d6e60429
225 225 tag: tip
226 226 user: test
227 227 date: Thu Jan 01 00:00:00 1970 +0000
228 228 summary: b
229 229
230 230 $ hg verify -q
231 231 $ cd ..
232 232
233 233 Test a hard crash right after the index is move into place
234 234 ===========================================================
235 235
236 236 Now retry the procedure but intercept the rename of the index.
237 237
238 238 Things get corrupted /o\
239 239
240 240 $ hg clone --quiet --rev 1 troffset-computation troffset-computation-crash-after-rename
241 241 $ cd troffset-computation-crash-after-rename
242 242
243 243 Reference size:
244 244 $ f -s file
245 245 file: size=1024
246 246 $ f -s .hg/store/data/file*
247 247 .hg/store/data/file.i: size=1174
248 248
249 249 $ cat > .hg/hgrc <<EOF
250 250 > [extensions]
251 251 > intercept_rename = $TESTTMP/intercept_after_rename.py
252 252 > [hooks]
253 253 > pretxnchangegroup = python:$TESTTMP/killme.py:killme
254 254 > EOF
255 255 #if chg
256 256 $ hg pull ../troffset-computation
257 257 pulling from ../troffset-computation
258 258 [255]
259 259 #else
260 260 $ hg pull ../troffset-computation
261 261 pulling from ../troffset-computation
262 262 Killed
263 263 [137]
264 264 #endif
265 265
266 266 the revlog has been split on disk
267 267
268 268 $ f -s .hg/store/data/file*
269 269 .hg/store/data/file.d: size=132139
270 270 .hg/store/data/file.i: size=256
271 271
272 272 $ cat .hg/store/journal | tr -s '\000' ' ' | grep data/file
273 273 data/file.i 1174
274 274 data/file.d 0
275 275 data/file.d 1046
276 276
277 277 $ hg recover
278 278 rolling back interrupted transaction
279 279 abort: attempted to truncate data/file.i to 1174 bytes, but it was already 256 bytes
280 280
281 281 [255]
282 282 $ f -s .hg/store/data/file*
283 283 .hg/store/data/file.d: size=1046
284 284 .hg/store/data/file.i: size=256
285 285 $ hg tip
286 286 changeset: 1:cfa8d6e60429
287 287 tag: tip
288 288 user: test
289 289 date: Thu Jan 01 00:00:00 1970 +0000
290 290 summary: b
291 291
292 292 $ hg verify -q
293 293 abandoned transaction found - run hg recover
294 294 warning: revlog 'data/file.d' not in fncache!
295 295 file@0: data length off by -131093 bytes
296 296 file@2: unpacking fa1120531cc1: partial read of revlog data/file.d; expected 21 bytes from offset 1046, got 0
297 297 file@3: unpacking a631378adaa3: partial read of revlog data/file.d; expected 131072 bytes from offset 1067, got -21
298 298 file@?: rev 2 points to nonexistent changeset 2
299 299 (expected )
300 300 file@?: fa1120531cc1 not in manifests
301 301 file@?: rev 3 points to nonexistent changeset 3
302 302 (expected )
303 303 file@?: a631378adaa3 not in manifests
304 304 not checking dirstate because of previous errors
305 305 3 warnings encountered!
306 306 hint: run "hg debugrebuildfncache" to recover from corrupt fncache
307 307 7 integrity errors encountered!
308 308 (first damaged changeset appears to be 0)
309 309 [1]
310 310 $ cd ..
311 311
312 312 Have the transaction rollback itself without any hard crash
313 313 ===========================================================
314 314
315 315
316 316 Repeat the original test but let hg rollback the transaction.
317 317
318 318 $ hg clone --quiet --rev 1 troffset-computation troffset-computation-copy-rb
319 319 $ cd troffset-computation-copy-rb
320 320 $ cat > .hg/hgrc <<EOF
321 321 > [hooks]
322 322 > pretxnchangegroup = false
323 323 > EOF
324 324 $ hg pull ../troffset-computation
325 325 pulling from ../troffset-computation
326 326 searching for changes
327 327 adding changesets
328 328 adding manifests
329 329 adding file changes
330 330 transaction abort!
331 331 rollback completed
332 332 abort: pretxnchangegroup hook exited with status 1
333 333 [40]
334 334
335 335 File are still split on disk, with the expected size.
336 336
337 337 $ f -s .hg/store/data/file*
338 338 .hg/store/data/file.d: size=1046
339 339 .hg/store/data/file.i: size=128
340 340
341 341 $ hg tip
342 342 changeset: 1:cfa8d6e60429
343 343 tag: tip
344 344 user: test
345 345 date: Thu Jan 01 00:00:00 1970 +0000
346 346 summary: b
347 347
348 348 $ hg verify -q
349 349 warning: revlog 'data/file.d' not in fncache!
350 350 1 warnings encountered!
351 351 hint: run "hg debugrebuildfncache" to recover from corrupt fncache
352 352 $ cd ..
353 353
354 354 Read race
355 355 =========
356 356
357 357 We check that a client that started reading a revlog (its index) after the
358 358 split and end reading (the data) after the rollback should be fine
359 359
360 360 $ hg clone --quiet --rev 1 troffset-computation troffset-computation-race
361 361 $ cd troffset-computation-race
362 362 $ cat > .hg/hgrc <<EOF
363 363 > [hooks]
364 364 > pretxnchangegroup=$RUNTESTDIR/testlib/wait-on-file 5 $TESTTMP/reader-index-read $TESTTMP/writer-revlog-split
365 365 > pretxnclose = false
366 366 > EOF
367 367
368 368 start a reader
369 369
370 370 $ hg cat --rev 0 file \
371 371 > --config "extensions.wait_read=$TESTTMP/reader_wait_split.py" \
372 372 > 2> $TESTTMP/reader.stderr \
373 373 > > $TESTTMP/reader.stdout &
374 374
375 375 Do a failed pull in //
376 376
377 377 $ hg pull ../troffset-computation
378 378 pulling from ../troffset-computation
379 379 searching for changes
380 380 adding changesets
381 381 adding manifests
382 382 adding file changes
383 383 transaction abort!
384 384 rollback completed
385 385 abort: pretxnclose hook exited with status 1
386 386 [40]
387 387 $ touch $TESTTMP/writer-revlog-unsplit
388 388 $ wait
389 389
390 390 The reader should be fine
391 391 $ cat $TESTTMP/reader.stderr
392 392 $ cat $TESTTMP/reader.stdout
393 393 1 (no-eol)
394 394 $ cd ..
395
396 pending hooks
397 =============
398
399 We checks that hooks properly see the inside of the transaction, while other process don't.
400
401 $ hg clone --quiet --rev 1 troffset-computation troffset-computation-hooks
402 $ cd troffset-computation-hooks
403 $ cat > .hg/hgrc <<EOF
404 > [hooks]
405 > pretxnclose.01-echo = hg cat -r 'max(all())' file | f --size
406 > pretxnclose.02-echo = $RUNTESTDIR/testlib/wait-on-file 5 $TESTTMP/hook-done $TESTTMP/hook-tr-ready
407 > pretxnclose.03-abort = false
408 > EOF
409
410 $ (
411 > $RUNTESTDIR/testlib/wait-on-file 5 $TESTTMP/hook-tr-ready;\
412 > hg cat -r 'max(all())' file | f --size;\
413 > touch $TESTTMP/hook-done
414 > ) >stdout 2>stderr &
415
416 $ hg pull ../troffset-computation
417 pulling from ../troffset-computation
418 searching for changes
419 adding changesets
420 adding manifests
421 adding file changes
422 size=131072
423 transaction abort!
424 rollback completed
425 abort: pretxnclose.03-abort hook exited with status 1
426 [40]
427
428 $ cat stdout
429 size=1024
430 $ cat stderr
431
432
433 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now