# HG changeset patch # User Arseniy Alekseyev # Date 2022-01-20 14:06:36 # Node ID ccd9cb73125cf096a1af26bda689399a190179b2 # Parent f38ae2d7390e23d56e01cd01ca911beab55dccfa revlog: fix a bug where transaction can be aborted partially Fix a repo corruption bug caused by a partial transaction rollback. Differential Revision: https://phab.mercurial-scm.org/D12009 diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -2006,7 +2006,7 @@ class revlog(object): raise error.RevlogError( _(b"%s not found in the transaction") % self._indexfile ) - trindex = 0 + trindex = None tr.add(self._datafile, 0) existing_handles = False @@ -2029,10 +2029,17 @@ class revlog(object): with self._indexfp() as read_ifh: for r in self: new_dfh.write(self._getsegmentforrevs(r, r, df=read_ifh)[1]) - if troffset <= self.start(r) + r * self.index.entry_size: + if ( + trindex is None + and troffset + <= self.start(r) + r * self.index.entry_size + ): trindex = r new_dfh.flush() + if trindex is None: + trindex = 0 + with self.__index_new_fp() as fp: self._format_flags &= ~FLAG_INLINE_DATA self._inline = False diff --git a/tests/test-transaction-rollback-on-revlog-split.t b/tests/test-transaction-rollback-on-revlog-split.t --- a/tests/test-transaction-rollback-on-revlog-split.t +++ b/tests/test-transaction-rollback-on-revlog-split.t @@ -63,7 +63,7 @@ Reference size: [80] #endif $ cat .hg/store/journal | tr -s '\000' ' ' | grep data/file | tail -1 - data/file.i 192 + data/file.i 128 The first file.i entry should match the "Reference size" above. The first file.d entry is the temporary record during the split, @@ -73,14 +73,14 @@ and the second file.i entry should match $ cat .hg/store/journal | tr -s '\000' ' ' | grep data/file data/file.i 1174 data/file.d 0 - data/file.d 1067 - data/file.i 192 + data/file.d 1046 + data/file.i 128 $ hg recover rolling back interrupted transaction (verify step skipped, run `hg verify` to check your repository content) $ f -s .hg/store/data/file* - .hg/store/data/file.d: size=1067 - .hg/store/data/file.i: size=192 + .hg/store/data/file.d: size=1046 + .hg/store/data/file.i: size=128 $ hg tip changeset: 1:cfa8d6e60429 tag: tip @@ -90,23 +90,12 @@ and the second file.i entry should match $ hg verify -q warning: revlog 'data/file.d' not in fncache! - file@?: rev 2 points to nonexistent changeset 2 - (expected ) - file@?: fa1120531cc1 not in manifests - 2 warnings encountered! + 1 warnings encountered! hint: run "hg debugrebuildfncache" to recover from corrupt fncache - 2 integrity errors encountered! - [1] $ hg debugrebuildfncache --only-data adding data/file.d 1 items added, 0 removed from fncache $ hg verify -q - file@?: rev 2 points to nonexistent changeset 2 - (expected ) - file@?: fa1120531cc1 not in manifests - 1 warnings encountered! - 2 integrity errors encountered! - [1] $ cd .. @@ -134,13 +123,13 @@ where the data file is left as garbage. $ cat .hg/store/journal | tr -s '\000' ' ' | grep data/file data/file.i 1174 data/file.d 0 - data/file.d 1067 + data/file.d 1046 $ hg recover rolling back interrupted transaction (verify step skipped, run `hg verify` to check your repository content) $ f -s .hg/store/data/file* - .hg/store/data/file.d: size=1067 + .hg/store/data/file.d: size=1046 .hg/store/data/file.i: size=1174 $ hg tip changeset: 1:cfa8d6e60429 @@ -172,8 +161,8 @@ Repeat the original test but let hg roll abort: pretxnchangegroup hook exited with status 1 [40] $ f -s .hg/store/data/file* - .hg/store/data/file.d: size=1067 - .hg/store/data/file.i: size=192 + .hg/store/data/file.d: size=1046 + .hg/store/data/file.i: size=128 $ hg tip changeset: 1:cfa8d6e60429 tag: tip @@ -183,12 +172,7 @@ Repeat the original test but let hg roll $ hg verify -q warning: revlog 'data/file.d' not in fncache! - file@?: rev 2 points to nonexistent changeset 2 - (expected ) - file@?: fa1120531cc1 not in manifests - 2 warnings encountered! + 1 warnings encountered! hint: run "hg debugrebuildfncache" to recover from corrupt fncache - 2 integrity errors encountered! - [1] $ cd ..