diff mercurial/revlog.py @ 50638:5460424092e2

stream-clone: smoothly detect and handle a case were a revlog is split This detect and handle the most common case for a race condition around stream and revlog splitting. The one were the revlog is split between the initial collection of data and the time were we start considering stream that data. In such case, we repatch an inlined version of that revlog together when this happens. This is necessary as stream-v2 promised a specific number of bytes and a specific number of files to the client. In stream-v3, we will have the opportunity to just send a split revlog instead. Getting a better version of the protocol for stream-v3 is still useful, but it is no longer a blocket to fix that race condition. Note that another, rarer race condition exist, were the revlog is split while we creating the revlog and extracing content from it. This can be dealt with later.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Mon, 29 May 2023 18:41:58 +0200
parents 9caa860dcbec
children 3b56395404a1
line wrap: on
line diff
--- a/mercurial/revlog.py	Mon May 29 14:07:58 2023 +0200
+++ b/mercurial/revlog.py	Mon May 29 18:41:58 2023 +0200
@@ -506,7 +506,7 @@
         except FileNotFoundError:
             return b''
 
-    def get_streams(self, max_linkrev):
+    def get_streams(self, max_linkrev, force_inline=False):
         n = len(self)
         index = self.index
         while n > 0:
@@ -547,6 +547,29 @@
             return [
                 (self._indexfile, inline_stream, index_size + data_size),
             ]
+        elif force_inline:
+
+            def get_stream():
+                with self._datafp() as fp_d:
+                    yield None
+
+                    for rev in range(n):
+                        idx = self.index.entry_binary(rev)
+                        if rev == 0 and self._docket is None:
+                            # re-inject the inline flag
+                            header = self._format_flags
+                            header |= self._format_version
+                            header |= FLAG_INLINE_DATA
+                            header = self.index.pack_header(header)
+                            idx = header + idx
+                        yield idx
+                        yield self._getsegmentforrevs(rev, rev, df=fp_d)[1]
+
+            inline_stream = get_stream()
+            next(inline_stream)
+            return [
+                (self._indexfile, inline_stream, index_size + data_size),
+            ]
         else:
 
             def get_index_stream():