clone: only use stream when we understand the revlog format
authorSune Foldager <cryo@cyanite.org>
Wed, 15 Sep 2010 11:06:22 +0200
changeset 12296 d7fff529d85d
parent 12295 3388ab21d768
child 12297 a424fa60e742
child 12308 2ae4d6c31dcc
clone: only use stream when we understand the revlog format This patch fixes issues with stream cloning in the presense of parentdelta, lwcopy and similar additions that change the interpretation of the revlog format, or the format itself. Currently, the stream capability is sent like this: stream=<version of changelog> But the client doesn't actually check the version number; also, it only checks the changelog and it doesn't capture the interpretation-changes and flag-changes in parentdelta and lwcopy. This patch removes the 'stream' capability whenever we use a non-basic revlog format, to prevent old clients from receiving incorrect data. In those cases, a new capability called 'streamreqs' is added instead. Instead of a revlog version, it comes with a list of revlog-format relevant requirements, which are a subset of the repository requirements, excluding things that are not relevant for stream. New clients use this to determine whether or not they can stream. Old clients only look for the 'stream' capability, as always. New servers will still send this when serving old repositories.
mercurial/localrepo.py
mercurial/wireproto.py
--- a/mercurial/localrepo.py	Wed Sep 15 10:44:10 2010 +0200
+++ b/mercurial/localrepo.py	Wed Sep 15 11:06:22 2010 +0200
@@ -1784,7 +1784,7 @@
             return newheads - oldheads + 1
 
 
-    def stream_in(self, remote):
+    def stream_in(self, remote, requirements):
         fp = remote.stream_out()
         l = fp.readline()
         try:
@@ -1829,6 +1829,13 @@
         self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
                        (util.bytecount(total_bytes), elapsed,
                         util.bytecount(total_bytes / elapsed)))
+
+        # new requirements = old non-format requirements + new format-related
+        # requirements from the streamed-in repository
+        requirements.update(set(self.requirements) - self.supportedformats)
+        self._applyrequirements(requirements)
+        self._writerequirements()
+
         self.invalidate()
         return len(self.heads()) + 1
 
@@ -1847,8 +1854,17 @@
         # and format flags on "stream" capability, and use
         # uncompressed only if compatible.
 
-        if stream and not heads and remote.capable('stream'):
-            return self.stream_in(remote)
+        if stream and not heads:
+            # 'stream' means remote revlog format is revlogv1 only
+            if remote.capable('stream'):
+                return self.stream_in(remote, set(('revlogv1',)))
+            # otherwise, 'streamreqs' contains the remote revlog format
+            streamreqs = remote.capable('streamreqs')
+            if streamreqs:
+                streamreqs = set(streamreqs.split(','))
+                # if we support it, stream in and adjust our requirements
+                if not streamreqs - self.supportedformats:
+                    return self.stream_in(remote, streamreqs)
         return self.pull(remote, heads)
 
     def pushkey(self, namespace, key, old, new):
--- a/mercurial/wireproto.py	Wed Sep 15 10:44:10 2010 +0200
+++ b/mercurial/wireproto.py	Wed Sep 15 11:06:22 2010 +0200
@@ -172,7 +172,13 @@
 def capabilities(repo, proto):
     caps = 'lookup changegroupsubset branchmap pushkey'.split()
     if _allowstream(repo.ui):
-        caps.append('stream=%d' % repo.changelog.version)
+        requiredformats = repo.requirements & repo.supportedformats
+        # if our local revlogs are just revlogv1, add 'stream' cap
+        if not requiredformats - set(('revlogv1',)):
+            caps.append('stream')
+        # otherwise, add 'streamreqs' detailing our local revlog format
+        else:
+            caps.append('streamreqs=%s' % ','.join(requiredformats))
     caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
     return ' '.join(caps)