diff mercurial/revlog.py @ 50348:f952be90b051 stable 6.4.2

revlog-split: make sure the self._indexfile attribut is reset (issue6811) Before this change, after a transaction committing a file split, a revlog object would have its `self._indexfile` attribute desynchronised from the actual file storing the data. If that same object is reused (as we do for the manifest during clone bundles), this lead to the data being writting in the wrong location and the repository to go corrupt. We not properly reset the attribut when applicable and everything is back in working order.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Tue, 18 Apr 2023 01:23:27 +0200
parents 87f0155d68aa
children 814f55775b21 978ffa09910b
line wrap: on
line diff
--- a/mercurial/revlog.py	Tue Apr 18 00:07:52 2023 +0200
+++ b/mercurial/revlog.py	Tue Apr 18 01:23:27 2023 +0200
@@ -19,6 +19,7 @@
 import io
 import os
 import struct
+import weakref
 import zlib
 
 # import stuff from node for others to import from revlog
@@ -2057,6 +2058,7 @@
             old_index_file_path = self._indexfile
             new_index_file_path = self._indexfile + b'.s'
             opener = self.opener
+            weak_self = weakref.ref(self)
 
             fncache = getattr(opener, 'fncache', None)
             if fncache is not None:
@@ -2069,13 +2071,22 @@
                     old_index_file_path,
                     checkambig=True,
                 )
+                maybe_self = weak_self()
+                if maybe_self is not None:
+                    maybe_self._indexfile = old_index_file_path
+
+            def abort_callback(tr):
+                maybe_self = weak_self()
+                if maybe_self is not None:
+                    maybe_self._indexfile = old_index_file_path
 
             tr.registertmp(new_index_file_path)
             if self.target[1] is not None:
-                finalize_id = b'000-revlog-split-%d-%s' % self.target
+                callback_id = b'000-revlog-split-%d-%s' % self.target
             else:
-                finalize_id = b'000-revlog-split-%d' % self.target[0]
-            tr.addfinalize(finalize_id, finalize_callback)
+                callback_id = b'000-revlog-split-%d' % self.target[0]
+            tr.addfinalize(callback_id, finalize_callback)
+            tr.addabort(callback_id, abort_callback)
 
         new_dfh = self._datafp(b'w+')
         new_dfh.truncate(0)  # drop any potentially existing data