Merge lp:~jameinel/bzr/2.5-unending-sendall-1047309 into lp:bzr/2.5
| Status: | Merged |
|---|---|
| Approved by: | John A Meinel on 2012-09-11 |
| Approved revision: | 6510 |
| Merged at revision: | 6510 |
| Proposed branch: | lp:~jameinel/bzr/2.5-unending-sendall-1047309 |
| Merge into: | lp:bzr/2.5 |
| Diff against target: |
68 lines (+34/-1) 3 files modified
bzrlib/osutils.py (+5/-1) bzrlib/tests/test_osutils.py (+22/-0) doc/en/release-notes/bzr-2.5.txt (+7/-0) |
| To merge this branch: | bzr merge lp:~jameinel/bzr/2.5-unending-sendall-1047309 |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Richard Wilbur | Needs Fixing on 2012-09-10 | ||
| Martin Packman (community) | 2012-09-07 | Approve on 2012-09-10 | |
|
Review via email:
|
|||
Commit Message
Detect if we are not progressing during osutils.send_all() and fail rather than hang. (bug #1047309)
Description of the Change
See the associated bug #1047309.
Basically, with the new ConnectionReset code coming into bzr-2.5, it seems that if Paramiko gets disconnected, it is unable to send any content, but doesn't raise an error. (it returns 0 bytes sent, but no exception is raised.)
As a conservative fix, this allows us to get a series of up to 5 0-bytes-sent, but any more than that in a row, and we just treat it as a ECONNRESET. Looking at the man pages, it seems send in non-blocking socket shouldn't ever give 0 bytes sent, but I preferred to be a little cautious.
If this causes fallout, we could tweak the retries, or even do sleep-based backoff.
| John A Meinel (jameinel) wrote : | # |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 9/7/2012 7:54 PM, Martin Packman wrote:
> Review: Needs Information
>
> Did you find any answer on if it's valid for send() to return 0? As
> far as I'm aware it's not, it's either EINTR or a partial write of
> more than one byte, though I can't find anything explicit either.
>
> For implementations like paramiko that just emulate the interface,
> coping with this is I guess required, though it would be nice to
> fix upstream to do something more sane. I'd prefer raising an error
> straight off, but understand the motivation behind retying several
> times, as that would previously have worked and regressions are
> bad. I'd much prefer not to use this heuristic if at possible
> though, instead quirking on the socket type or something that makes
> it explict this is a paramiko issue only.
>
Well, we could go with immediately erroring, and see how bad the
fallout is...
I think this is a reasonable compromise which means we won't have to
think about it again.
John
=:->
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://
iEYEARECAAYFAlB
1NIAnjiQ3YrIyh7
=zHgy
-----END PGP SIGNATURE-----
| Martin Packman (gz) wrote : | # |
Won't have to think about, apart from when someone writing code wants to know if they should use socket.sendall or osutils.sendall and what the hell is going on... So, I don't really like the code but am somewhat sold on it being the least risky option for fixing this bug.
Suggested tweaks before landing:
* Remove note about making _max_no_
* Add comment/docstring to osutils.sendall about why it's checking for 0 from send
* Maybe add mutter if we get 0 returned from send which is probably the only way we'll find out if it gets hit in the wild
* Make test_send_
| Richard Wilbur (richard-wilbur) wrote : | # |
The documentation for paramiko.
Python 2.7 socket library documentation for socket.send: "Returns the number of bytes sent. Applications are responsible for checking that all data has been sent; if only some of the data was transmitted, the application needs to attempt delivery of the remaining data. For further information on this concept, consult the Socket Programming HOWTO."[2]
Interestingly the Socket Programming HOWTO (referenced above) has an example which suggests you might get a 0 return value[3], but only if the connection is broken:
sent = self.sock.
if sent == 0:
Linux documentation for socket send[4]:
RETURN VALUE
On success, these calls return the number of characters sent. On
error, -1 is returned, and errno is set appropriately.
The consensus seems to be that a socket send should never return 0 unless there is an error. Paramiko looks like it thinks that is a normal way to signal a closed connection. The python socket programming HOWTO implies that the only reason for a 0 return value is also a closed connection.
@John, I agree with your proposition that we should throw an exception immediately when send returns 0.
@Martin, this would alleviate the need for _max_no_
1. I am in favour of removing _max_no_
2. Comment/docstring for osutils.sendall would be fine if it isn't obvious from the exception we throw
3.,4. Agree
References:
[1] http://
[2] http://
[3] http://
[4] info send
- 6511. By John A Meinel on 2012-09-11
-
simplify the fix. Sending 0 bytes seems to always indicate that we have a closed connection.
| John A Meinel (jameinel) wrote : | # |
Code has been simplified to just treat 0 bytes as closed connection.
| John A Meinel (jameinel) wrote : | # |
sent to pqm by email

Did you find any answer on if it's valid for send() to return 0? As far as I'm aware it's not, it's either EINTR or a partial write of more than one byte, though I can't find anything explicit either.
For implementations like paramiko that just emulate the interface, coping with this is I guess required, though it would be nice to fix upstream to do something more sane. I'd prefer raising an error straight off, but understand the motivation behind retying several times, as that would previously have worked and regressions are bad. I'd much prefer not to use this heuristic if at possible though, instead quirking on the socket type or something that makes it explict this is a paramiko issue only.