##// END OF EJS Templates
worker: use os._exit for posix worker in all cases...
worker: use os._exit for posix worker in all cases Like commandserver, the worker should never run other resource cleanup logic. Previously this is not true for workers if they have exceptions other than KeyboardInterrupt. This actually caused a real-world deadlock with remotefilelog: 1. remotefilelog/fileserverclient creates a sshpeer. pipei/o/e get created. 2. worker inherits that sshpeer's pipei/o/e. 3. worker runs sshpeer.cleanup (only happens without os._exit) 4. worker closes pipeo/i, which will normally make the sshpeer read EOF from its stdin and exit. But the master process still have pipeo, so no EOF. 5. worker reads pipee (stderr of sshpeer), which never completes because the ssh process does not exit, does not close its stderr. 6. master waits for all workers, which never completes because they never complete sshpeer.cleanup. This could also be addressed by closing these fds after fork, which is not easy because Python 2.x does not have an official "afterfork" hook. Hacking os.fork is also ugly. Besides, sshpeer is probably not the only troublemarker. The patch changes _posixworker so all its code paths will use os._exit to avoid running unwanted resource clean-ups.

File last commit:

r30466:2add671b default
r30521:86cd09bc default
Show More
proto.py
189 lines | 7.0 KiB | text/x-python | PythonLexer
various
hgext: add largefiles extension...
r15168 # Copyright 2011 Fog Creek Software
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
liscju
py3: make largefiles/proto.py use absolute_import
r29312 from __future__ import absolute_import
various
hgext: add largefiles extension...
r15168
import os
Mads Kiilerich
largefiles: make the protocol hack for replacing heads with lheads more precise...
r19917 import re
various
hgext: add largefiles extension...
r15168
from mercurial.i18n import _
liscju
py3: make largefiles/proto.py use absolute_import
r29312 from mercurial import (
error,
httppeer,
util,
wireproto,
)
from . import (
lfutil,
)
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 urlerr = util.urlerr
urlreq = util.urlreq
Greg Ward
largefiles: cosmetics, whitespace, code style...
r15255 LARGEFILES_REQUIRED_MSG = ('\nThis repository uses the largefiles extension.'
'\n\nPlease enable it in your Mercurial config '
'file.\n')
various
hgext: add largefiles extension...
r15168
Bryan O'Sullivan
largefiles: quiet (and document) undefined name errors (issue3886)...
r18922 # these will all be replaced by largefiles.uisetup
capabilitiesorig = None
ssholdcallstream = None
httpoldcallstream = None
various
hgext: add largefiles extension...
r15168 def putlfile(repo, proto, sha):
Mads Kiilerich
largefiles: add some docstrings
r28576 '''Server command for putting a largefile into a repository's local store
and into the user cache.'''
various
hgext: add largefiles extension...
r15168 proto.redirect()
Hao Lian
largefiles: replace tempfile.NamedTemporaryFile with tempfile.mkstemp...
r15391
hlian
largefiles: in putlfile, ensure tempfile's directory exists prior to creation...
r16594 path = lfutil.storepath(repo, sha)
util.makedirs(os.path.dirname(path))
tmpfp = util.atomictempfile(path, createmode=repo.store.createmode)
various
hgext: add largefiles extension...
r15168 try:
Matt Mackall
largefiles: use try/except/finally
r25079 proto.getfile(tmpfp)
tmpfp._fp.seek(0)
if sha != lfutil.hexsha1(tmpfp._fp):
raise IOError(0, _('largefile contents do not match hash'))
tmpfp.close()
lfutil.linktousercache(repo, sha)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as e:
Matt Mackall
largefiles: use try/except/finally
r25079 repo.ui.warn(_('largefiles: failed to put %s into store: %s\n') %
(sha, e.strerror))
return wireproto.pushres(1)
various
hgext: add largefiles extension...
r15168 finally:
Martin Geisler
largefiles: respect store.createmode and avoid extra file copy...
r16155 tmpfp.discard()
various
hgext: add largefiles extension...
r15168
return wireproto.pushres(0)
def getlfile(repo, proto, sha):
Mads Kiilerich
largefiles: add some docstrings
r28576 '''Server command for retrieving a largefile from the repository-local
cache or user cache.'''
various
hgext: add largefiles extension...
r15168 filename = lfutil.findfile(repo, sha)
if not filename:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('requested largefile %s not present in cache')
% sha)
various
hgext: add largefiles extension...
r15168 f = open(filename, 'rb')
length = os.fstat(f.fileno())[6]
Greg Ward
largefiles: improve comments, internal docstrings...
r15252
# Since we can't set an HTTP content-length header here, and
# Mercurial core provides no way to give the length of a streamres
# (and reading the entire file into RAM would be ill-advised), we
# just send the length on the first line of the response, like the
# ssh proto does for string responses.
various
hgext: add largefiles extension...
r15168 def generator():
yield '%d\n' % length
Mads Kiilerich
largefiles: use filechunkiter for iterating largefile when serving getlfile...
r19009 for chunk in util.filechunkiter(f):
various
hgext: add largefiles extension...
r15168 yield chunk
Gregory Szorc
wireproto: perform chunking and compression at protocol layer (API)...
r30466 return wireproto.streamres(gen=generator())
various
hgext: add largefiles extension...
r15168
def statlfile(repo, proto, sha):
Mads Kiilerich
largefiles: add some docstrings
r28576 '''Server command for checking if a largefile is present - returns '2\n' if
the largefile is missing, '0\n' if it seems to be in good condition.
Mads Kiilerich
largefiles: don't verify largefile hashes on servers when processing statlfile...
r18488
The value 1 is reserved for mismatched checksum, but that is too expensive
to be verified on every stat and must be caught be running 'hg verify'
server side.'''
various
hgext: add largefiles extension...
r15168 filename = lfutil.findfile(repo, sha)
if not filename:
return '2\n'
Mads Kiilerich
largefiles: don't verify largefile hashes on servers when processing statlfile...
r18488 return '0\n'
various
hgext: add largefiles extension...
r15168
def wirereposetup(ui, repo):
class lfileswirerepository(repo.__class__):
def putlfile(self, sha, fd):
# unfortunately, httprepository._callpush tries to convert its
# input file-like into a bundle before sending it, so we can't use
# it ...
Peter Arrenbrecht
peer: introduce real peer classes...
r17192 if issubclass(self.__class__, httppeer.httppeer):
Mads Kiilerich
largefiles: don't mute and obfuscate http errors when putlfile fails...
r26825 res = self._call('putlfile', data=fd, sha=sha,
headers={'content-type':'application/mercurial-0.1'})
various
hgext: add largefiles extension...
r15168 try:
Kevin Gessner
largefiles: display remote errors from putlfile (issue3123) (issue3149)
r15778 d, output = res.split('\n', 1)
for l in output.splitlines(True):
Mads Kiilerich
largefiles: don't add extra \n when displaying remote messages in putlfile
r19949 self.ui.warn(_('remote: '), l) # assume l ends with \n
Kevin Gessner
largefiles: display remote errors from putlfile (issue3123) (issue3149)
r15778 return int(d)
Mads Kiilerich
largefiles: don't mute and obfuscate http errors when putlfile fails...
r26825 except ValueError:
Mads Kiilerich
largefiles: fix 'unexpected response' warning newlines...
r19947 self.ui.warn(_('unexpected putlfile response: %r\n') % res)
various
hgext: add largefiles extension...
r15168 return 1
# ... but we can't use sshrepository._call because the data=
# argument won't get sent, and _callpush does exactly what we want
# in this case: send the data straight through
else:
try:
ret, output = self._callpush("putlfile", fd, sha=sha)
if ret == "":
raise error.ResponseError(_('putlfile failed:'),
output)
return int(ret)
except IOError:
return 1
except ValueError:
raise error.ResponseError(
_('putlfile failed (unexpected response):'), ret)
def getlfile(self, sha):
Mads Kiilerich
largefiles: move protocol conversion into getlfile and make it an iterable...
r19004 """returns an iterable with the chunks of the file with sha sha"""
various
hgext: add largefiles extension...
r15168 stream = self._callstream("getlfile", sha=sha)
length = stream.readline()
try:
length = int(length)
except ValueError:
Matt Mackall
largefiles: fix over-long lines
r15170 self._abort(error.ResponseError(_("unexpected response:"),
length))
Mads Kiilerich
largefiles: move protocol conversion into getlfile and make it an iterable...
r19004
Mads Kiilerich
largefiles: drop limitreader, use filechunkiter limit...
r19005 # SSH streams will block if reading more than length
Mads Kiilerich
util: increase filechunkiter size to 128k...
r30181 for chunk in util.filechunkiter(stream, limit=length):
Mads Kiilerich
largefiles: move protocol conversion into getlfile and make it an iterable...
r19004 yield chunk
Mads Kiilerich
largefiles: getlfile must hit end of HTTP chunked streams to reuse connections...
r19006 # HTTP streams must hit the end to process the last empty
# chunk of Chunked-Encoding so the connection can be reused.
if issubclass(self.__class__, httppeer.httppeer):
chunk = stream.read(1)
if chunk:
self._abort(error.ResponseError(_("unexpected response:"),
chunk))
various
hgext: add largefiles extension...
r15168
Mads Kiilerich
largefiles: import whole modules instead of importing parts of them...
r21084 @wireproto.batchable
various
hgext: add largefiles extension...
r15168 def statlfile(self, sha):
Mads Kiilerich
largefiles: import whole modules instead of importing parts of them...
r21084 f = wireproto.future()
Na'Tosha Bard
largefiles: batch statlfile requests when pushing a largefiles repo (issue3386)...
r17127 result = {'sha': sha}
yield result, f
various
hgext: add largefiles extension...
r15168 try:
Na'Tosha Bard
largefiles: batch statlfile requests when pushing a largefiles repo (issue3386)...
r17127 yield int(f.value)
timeless
pycompat: switch to util.urlreq/util.urlerr for py3 compat
r28883 except (ValueError, urlerr.httperror):
Greg Ward
largefiles: improve comments, internal docstrings...
r15252 # If the server returns anything but an integer followed by a
various
hgext: add largefiles extension...
r15168 # newline, newline, it's not speaking our language; if we get
# an HTTP error, we can't be sure the largefile is present;
Greg Ward
largefiles: improve comments, internal docstrings...
r15252 # either way, consider it missing.
Na'Tosha Bard
largefiles: batch statlfile requests when pushing a largefiles repo (issue3386)...
r17127 yield 2
various
hgext: add largefiles extension...
r15168
repo.__class__ = lfileswirerepository
# advertise the largefiles=serve capability
def capabilities(repo, proto):
Mads Kiilerich
largefiles: add some docstrings
r28576 '''Wrap server command to announce largefile server capability'''
Na'Tosha Bard
largefiles: remove use of underscores that breaks coding convention
r16247 return capabilitiesorig(repo, proto) + ' largefiles=serve'
various
hgext: add largefiles extension...
r15168
def heads(repo, proto):
Mads Kiilerich
largefiles: add some docstrings
r28576 '''Wrap server command - largefile capable clients will know to call
lheads instead'''
various
hgext: add largefiles extension...
r15168 if lfutil.islfilesrepo(repo):
Na'Tosha Bard
largefiles: remove pre-1.9 code from extension first bundled with 1.9
r15224 return wireproto.ooberror(LARGEFILES_REQUIRED_MSG)
various
hgext: add largefiles extension...
r15168 return wireproto.heads(repo, proto)
Na'Tosha Bard
largefiles: remove use of underscores that breaks coding convention
r16247 def sshrepocallstream(self, cmd, **args):
various
hgext: add largefiles extension...
r15168 if cmd == 'heads' and self.capable('largefiles'):
cmd = 'lheads'
if cmd == 'batch' and self.capable('largefiles'):
args['cmds'] = args['cmds'].replace('heads ', 'lheads ')
Na'Tosha Bard
largefiles: remove use of underscores that breaks coding convention
r16247 return ssholdcallstream(self, cmd, **args)
various
hgext: add largefiles extension...
r15168
Mads Kiilerich
largefiles: make the protocol hack for replacing heads with lheads more precise...
r19917 headsre = re.compile(r'(^|;)heads\b')
Na'Tosha Bard
largefiles: remove use of underscores that breaks coding convention
r16247 def httprepocallstream(self, cmd, **args):
various
hgext: add largefiles extension...
r15168 if cmd == 'heads' and self.capable('largefiles'):
cmd = 'lheads'
if cmd == 'batch' and self.capable('largefiles'):
Mads Kiilerich
largefiles: make the protocol hack for replacing heads with lheads more precise...
r19917 args['cmds'] = headsre.sub('lheads', args['cmds'])
Na'Tosha Bard
largefiles: remove use of underscores that breaks coding convention
r16247 return httpoldcallstream(self, cmd, **args)