Patchwork D11236: streamclone: ensure the server sends the right amount of data

login
register
mail settings
Submitter phabricator
Date Aug. 1, 2021, 2:59 p.m.
Message ID <differential-rev-PHID-DREV-m53sm72una3yho4ql77e-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/49551/
State Superseded
Headers show

Comments

phabricator - Aug. 1, 2021, 2:59 p.m.
valentin.gatienbaron created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  Otherwise, the client would fail with some confusing error. I have
  seen an error which I think is this, perhaps due to a concurrent
  revlog split, which streamclones do not handle correctly and would
  result in a short read of the index of the revlog being split.

REPOSITORY
  rHG Mercurial

BRANCH
  default

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

AFFECTED FILES
  mercurial/streamclone.py

CHANGE DETAILS




To: valentin.gatienbaron, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/mercurial/streamclone.py b/mercurial/streamclone.py
--- a/mercurial/streamclone.py
+++ b/mercurial/streamclone.py
@@ -573,7 +573,7 @@ 
         # copy is delayed until we are in the try
         entries = [_filterfull(e, copy, vfsmap) for e in entries]
         yield None  # this release the lock on the repository
-        seen = 0
+        totalbytecount = 0
 
         for src, name, ftype, data in entries:
             vfs = vfsmap[src]
@@ -585,6 +585,7 @@ 
             elif ftype == _filefull:
                 fp = open(data, b'rb')
                 size = util.fstat(fp).st_size
+            bytecount = 0
             try:
                 yield util.uvarintencode(size)
                 yield name
@@ -593,9 +594,20 @@ 
                 else:
                     chunks = util.filechunkiter(fp, limit=size)
                 for chunk in chunks:
-                    seen += len(chunk)
-                    progress.update(seen)
+                    bytecount += len(chunk)
+                    totalbytecount += len(chunk)
+                    progress.update(totalbytecount)
                     yield chunk
+                if bytecount != size:
+                    # Would most likely be caused by a race due to `hg strip` or
+                    # a revlog split
+                    raise error.Abort(
+                        _(
+                            b'clone could only read %d bytes from %s, but '
+                            b'expected %d bytes'
+                        )
+                        % (bytecount, name, size)
+                    )
             finally:
                 fp.close()