##// END OF EJS Templates
chg: handle EOF reading data block...
chg: handle EOF reading data block We recently discovered a case in production that chg uses 100% CPU and is trying to read data forever: recvfrom(4, "", 1814012019, 0, NULL, NULL) = 0 Using gdb, apparently readchannel() got wrong data. It was reading in an infinite loop because rsize == 0 does not exit the loop, while the server process had ended. (gdb) bt #0 ... in recv () at /lib64/libc.so.6 #1 ... in readchannel (...) at /usr/include/bits/socket2.h:45 #2 ... in readchannel (hgc=...) at hgclient.c:129 #3 ... in handleresponse (hgc=...) at hgclient.c:255 #4 ... in hgc_runcommand (hgc=..., args=<optimized>, argsize=<optimized>) #5 ... in main (argc=...486922636, argv=..., envp=...) at chg.c:661 (gdb) frame 2 (gdb) p *hgc $1 = {sockfd = 4, pid = 381152, ctx = {ch = 108 'l', data = 0x7fb05164f010 "st):\nTraceback (most recent call last):\n" "Traceback (most recent call last):\ne", maxdatasize = 1814065152," " datasize = 1814064225}, capflags = 16131} This patch addresses the infinite loop issue by detecting continuously empty responses and abort in that case. Note that datasize can be translated to ['l', ' ', 'l', 'a']. Concatenate datasize and data, it forms part of "Traceback (most recent call last):". This may indicate a server-side channeledoutput issue. If it is a race condition, we may want to use flock to protect the channels.

File last commit:

r29205:a0939666 default
r29602:4fc4b8cc default
Show More
schemes.py
132 lines | 4.0 KiB | text/x-python | PythonLexer
# Copyright 2009, Alexander Solovyov <piranha@piranha.org.ua>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
"""extend schemes with shortcuts to repository swarms
This extension allows you to specify shortcuts for parent URLs with a
lot of repositories to act like a scheme, for example::
[schemes]
py = http://code.python.org/hg/
After that you can use it like::
hg clone py://trunk/
Additionally there is support for some more complex schemas, for
example used by Google Code::
[schemes]
gcode = http://{1}.googlecode.com/hg/
The syntax is taken from Mercurial templates, and you have unlimited
number of variables, starting with ``{1}`` and continuing with
``{2}``, ``{3}`` and so on. This variables will receive parts of URL
supplied, split by ``/``. Anything not specified as ``{part}`` will be
just appended to an URL.
For convenience, the extension adds these schemes by default::
[schemes]
py = http://hg.python.org/
bb = https://bitbucket.org/
bb+ssh = ssh://hg@bitbucket.org/
gcode = https://{1}.googlecode.com/hg/
kiln = https://{1}.kilnhg.com/Repo/
You can override a predefined scheme by defining a new scheme with the
same name.
"""
from __future__ import absolute_import
import os
import re
from mercurial.i18n import _
from mercurial import (
cmdutil,
error,
extensions,
hg,
templater,
util,
)
cmdtable = {}
command = cmdutil.command(cmdtable)
# Note for extension authors: ONLY specify testedwith = 'internal' for
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
# be specifying the version(s) of Mercurial they are tested with, or
# leave the attribute unspecified.
testedwith = 'internal'
class ShortRepository(object):
def __init__(self, url, scheme, templater):
self.scheme = scheme
self.templater = templater
self.url = url
try:
self.parts = max(map(int, re.findall(r'\{(\d+)\}', self.url)))
except ValueError:
self.parts = 0
def __repr__(self):
return '<ShortRepository: %s>' % self.scheme
def instance(self, ui, url, create):
url = self.resolve(url)
return hg._peerlookup(url).instance(ui, url, create)
def resolve(self, url):
# Should this use the util.url class, or is manual parsing better?
try:
url = url.split('://', 1)[1]
except IndexError:
raise error.Abort(_("no '://' in scheme url '%s'") % url)
parts = url.split('/', self.parts)
if len(parts) > self.parts:
tail = parts[-1]
parts = parts[:-1]
else:
tail = ''
context = dict((str(i + 1), v) for i, v in enumerate(parts))
return ''.join(self.templater.process(self.url, context)) + tail
def hasdriveletter(orig, path):
if path:
for scheme in schemes:
if path.startswith(scheme + ':'):
return False
return orig(path)
schemes = {
'py': 'http://hg.python.org/',
'bb': 'https://bitbucket.org/',
'bb+ssh': 'ssh://hg@bitbucket.org/',
'gcode': 'https://{1}.googlecode.com/hg/',
'kiln': 'https://{1}.kilnhg.com/Repo/'
}
def extsetup(ui):
schemes.update(dict(ui.configitems('schemes')))
t = templater.engine(lambda x: x)
for scheme, url in schemes.items():
if (os.name == 'nt' and len(scheme) == 1 and scheme.isalpha()
and os.path.exists('%s:\\' % scheme)):
raise error.Abort(_('custom scheme %s:// conflicts with drive '
'letter %s:\\\n') % (scheme, scheme.upper()))
hg.schemes[scheme] = ShortRepository(url, scheme, t)
extensions.wrapfunction(util, 'hasdriveletter', hasdriveletter)
@command('debugexpandscheme', norepo=True)
def expandscheme(ui, url, **opts):
"""given a repo path, provide the scheme-expanded path
"""
repo = hg._peerlookup(url)
if isinstance(repo, ShortRepository):
url = repo.resolve(url)
ui.write(url + '\n')