Patchwork D12009: revlog: fix a bug where transaction can be aborted partially

login
register
mail settings
Submitter phabricator
Date Jan. 20, 2022, 2:10 p.m.
Message ID <differential-rev-PHID-DREV-5d6iyfjkodslu6avvkfe-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/50335/
State New
Headers show

Comments

phabricator - Jan. 20, 2022, 2:10 p.m.
aalekseyev created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  Fix a repo corruption bug caused by a partial transaction rollback.

REPOSITORY
  rHG Mercurial

BRANCH
  stable

REVISION DETAIL
  https://phab.mercurial-scm.org/D12009

AFFECTED FILES
  mercurial/revlog.py
  tests/test-transaction-rollback-on-revlog-split.t

CHANGE DETAILS




To: aalekseyev, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

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 @@ 
   [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 @@ 
   $ 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 @@ 
   
   $ 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 @@ 
   $ 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 @@ 
   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 @@ 
   
   $ 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 ..
 
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -2006,7 +2006,7 @@ 
             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 @@ 
             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