[PATCH STABLE] changegroup: retry read() when partial data returned
Yuya Nishihara
yuya at tcha.org
Mon Mar 27 11:59:27 EDT 2017
On Mon, 27 Mar 2017 08:25:41 -0700, Gregory Szorc wrote:
> > On Mar 27, 2017, at 08:13, Yuya Nishihara <yuya at tcha.org> wrote:
> >> On Sun, 26 Mar 2017 11:56:59 -0700, Gregory Szorc wrote:
> >> # HG changeset patch
> >> # User Gregory Szorc <gregory.szorc at gmail.com>
> >> # Date 1490554582 25200
> >> # Sun Mar 26 11:56:22 2017 -0700
> >> # Branch stable
> >> # Node ID 414128ddd876eb33f70b0dd95d110e29a9308c93
> >> # Parent ed5b25874d998ababb181a939dd37a16ea644435
> >> changegroup: retry read() when partial data returned
[...]
> >> def readexactly(stream, n):
> >> '''read n bytes from stream.read and abort if less was available'''
> >> - s = stream.read(n)
> >> - if len(s) < n:
> >> + # Most of the time, stream.read() returns exactly the number of bytes
> >> + # requested. Various Python APIs will perform multiple system calls
> >> + # to retrieve more bytes if the first call did not return enough. This
> >> + # includes cases where the system call is interrupted.
> >> + #
> >> + # Even with this retry logic in the Python APIs, we still see failure
> >> + # to retrieve the requested number of bytes. So, we build in our own
> >> + # retry layer here.
> >> + left = n
> >> + chunk = stream.read(n)
> >> + left -= len(chunk)
> >> + assert left >= 0
> >> +
> >> + # Common case is it just works.
> >> + if not left:
> >> + return chunk
> >> +
> >> + chunks = [chunk]
> >> + # Retry to get remaining data. In cases where the stream has errored or
> >> + # is at EOF, this will do a bit of redundant work. But it helps prevent
> >> + # intermittent failures and isn't common. So the overhead is acceptable.
> >> + for i in range(3):
> >> + chunk = stream.read(left)
> >> + chunks.append(chunk)
> >> + left -= len(chunk)
> >> + assert left >= 0
> >> +
> >> + if not left:
> >> + break
> >
> > Do you have some number that supports this change actually mitigates the
> > problem?
>
> No. I could try to get that this week.
Many thanks.
> > Suppose underlying functions have bugs, I don't think we can always get
> > contiguous chunks with no data loss. If a few bytes lost for example, we
> > could read arbitrary part as a length field, and call readexactly() with
> > that invalid length value.
>
> Hmm. My assumption is that any error that would result in data loss effectively poisons the stream and prevents future reads.
I was thinking e.g. some intermediate layer might not handle EINTR
appropriately and EINTR might be caught by some upper layer. If it had
a temporary buffer, its content would be lost.
More information about the Mercurial-devel
mailing list