comparison mercurial/ui.py @ 33755:cde4cfeb6e3e stable

ui: restore behavior to ignore some I/O errors (issue5658) e9646ff34d55 and 1bfb9a63b98e refactored ui methods to no longer silently swallow some IOError instances. This is arguably the correct thing to do. However, it had the unfortunate side-effect of causing StdioError to bubble up to sensitive code like transaction aborts, leading to an uncaught exceptions and failures to e.g. roll back a transaction. This could occur when a remote HTTP or SSH client connection dropped. The new behavior is resulting in semi-frequent "abandonded transaction" errors on multiple high-volume repositories at Mozilla. This commit effectively reverts e9646ff34d55 and 1bfb9a63b98e to restore the old behavior. I agree with the principle that I/O errors shouldn't be ignored. That makes this change... unfortunate. However, our hands are tied for what to do on stable. I think the proper solution is for the ui's behavior to be configurable (possibly via a context manager). During critical sections like transaction rollback and abort, it should be possible to suppress errors. But this feature would not be appropriate on stable.
author Gregory Szorc <gregory.szorc@gmail.com>
date Tue, 15 Aug 2017 13:04:31 -0700
parents c2c6a0f7408b
children af20468eb0a4 0e4bed5c5c38
comparison
equal deleted inserted replaced
33754:2debf1e3cfa4 33755:cde4cfeb6e3e
902 # stderr may be buffered under win32 when redirected to files, 902 # stderr may be buffered under win32 when redirected to files,
903 # including stdout. 903 # including stdout.
904 if not getattr(self.ferr, 'closed', False): 904 if not getattr(self.ferr, 'closed', False):
905 self.ferr.flush() 905 self.ferr.flush()
906 except IOError as inst: 906 except IOError as inst:
907 raise error.StdioError(inst) 907 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
908 raise error.StdioError(inst)
908 909
909 def flush(self): 910 def flush(self):
910 # opencode timeblockedsection because this is a critical path 911 # opencode timeblockedsection because this is a critical path
911 starttime = util.timer() 912 starttime = util.timer()
912 try: 913 try:
913 try: 914 try:
914 self.fout.flush() 915 self.fout.flush()
915 except IOError as err: 916 except IOError as err:
916 raise error.StdioError(err) 917 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
918 raise error.StdioError(err)
917 finally: 919 finally:
918 try: 920 try:
919 self.ferr.flush() 921 self.ferr.flush()
920 except IOError as err: 922 except IOError as err:
921 raise error.StdioError(err) 923 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
924 raise error.StdioError(err)
922 finally: 925 finally:
923 self._blockedtimes['stdio_blocked'] += \ 926 self._blockedtimes['stdio_blocked'] += \
924 (util.timer() - starttime) * 1000 927 (util.timer() - starttime) * 1000
925 928
926 def _isatty(self, fh): 929 def _isatty(self, fh):