##// END OF EJS Templates
server: add an error feedback mechanism for when the daemon fails to launch...
server: add an error feedback mechanism for when the daemon fails to launch There's a recurring problem on Windows where `hg serve -d` will randomly fail to spawn a detached process. The reason for the failure is completely hidden, and it takes hours to get a single failure on my laptop. All this does is redirect stdout/stderr of the child to a file until the lock file is freed, and then the parent dumps it out if it fails to spawn. I chose to put the output into the lock file because that is always cleaned up. There's no way to report errors after that anyway. On Windows, killdaemons.py is roughly `kill -9`, so this ensures that junk won't pile up. This may end up being a case of EADDRINUSE. At least that's what I saw spit out a few times (among other odd errors and missing output on Windows). But I also managed to get the same thing on Fedora 26 by running test-hgwebdir.t with --loop -j10 for several hours. Running `netstat` immediately after killing that run printed a wall of sockets in the TIME_WAIT state, which were gone a couple seconds later. I couldn't match up ports that failed, because --loop doesn't print out the message about the port that was used. So maybe the fix is to rotate the use of HGPORT[12] in the tests. But, let's collect some more data first.

File last commit:

r36114:66b4ffe9 default
r37229:f09a2eab default
Show More
narrowrevlog.py
187 lines | 7.2 KiB | text/x-python | PythonLexer
# narrowrevlog.py - revlog storing irrelevant nodes as "ellipsis" nodes
#
# Copyright 2017 Google, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
from mercurial import (
error,
manifest,
revlog,
util,
)
def readtransform(self, text):
return text, False
def writetransform(self, text):
return text, False
def rawtransform(self, text):
return False
revlog.addflagprocessor(revlog.REVIDX_ELLIPSIS,
(readtransform, writetransform, rawtransform))
def setup():
# We just wanted to add the flag processor, which is done at module
# load time.
pass
class excludeddir(manifest.treemanifest):
"""Stand-in for a directory that is excluded from the repository.
With narrowing active on a repository that uses treemanifests,
some of the directory revlogs will be excluded from the resulting
clone. This is a huge storage win for clients, but means we need
some sort of pseudo-manifest to surface to internals so we can
detect a merge conflict outside the narrowspec. That's what this
class is: it stands in for a directory whose node is known, but
whose contents are unknown.
"""
def __init__(self, dir, node):
super(excludeddir, self).__init__(dir)
self._node = node
# Add an empty file, which will be included by iterators and such,
# appearing as the directory itself (i.e. something like "dir/")
self._files[''] = node
self._flags[''] = 't'
# Manifests outside the narrowspec should never be modified, so avoid
# copying. This makes a noticeable difference when there are very many
# directories outside the narrowspec. Also, it makes sense for the copy to
# be of the same type as the original, which would not happen with the
# super type's copy().
def copy(self):
return self
class excludeddirmanifestctx(manifest.treemanifestctx):
"""context wrapper for excludeddir - see that docstring for rationale"""
def __init__(self, dir, node):
self._dir = dir
self._node = node
def read(self):
return excludeddir(self._dir, self._node)
def write(self, *args):
raise error.ProgrammingError(
'attempt to write manifest from excluded dir %s' % self._dir)
class excludedmanifestrevlog(manifest.manifestrevlog):
"""Stand-in for excluded treemanifest revlogs.
When narrowing is active on a treemanifest repository, we'll have
references to directories we can't see due to the revlog being
skipped. This class exists to conform to the manifestrevlog
interface for those directories and proactively prevent writes to
outside the narrowspec.
"""
def __init__(self, dir):
self._dir = dir
def __len__(self):
raise error.ProgrammingError(
'attempt to get length of excluded dir %s' % self._dir)
def rev(self, node):
raise error.ProgrammingError(
'attempt to get rev from excluded dir %s' % self._dir)
def linkrev(self, node):
raise error.ProgrammingError(
'attempt to get linkrev from excluded dir %s' % self._dir)
def node(self, rev):
raise error.ProgrammingError(
'attempt to get node from excluded dir %s' % self._dir)
def add(self, *args, **kwargs):
# We should never write entries in dirlogs outside the narrow clone.
# However, the method still gets called from writesubtree() in
# _addtree(), so we need to handle it. We should possibly make that
# avoid calling add() with a clean manifest (_dirty is always False
# in excludeddir instances).
pass
def makenarrowmanifestrevlog(mfrevlog, repo):
if util.safehasattr(mfrevlog, '_narrowed'):
return
class narrowmanifestrevlog(mfrevlog.__class__):
# This function is called via debug{revlog,index,data}, but also during
# at least some push operations. This will be used to wrap/exclude the
# child directories when using treemanifests.
def dirlog(self, d):
if d and not d.endswith('/'):
d = d + '/'
if not repo.narrowmatch().visitdir(d[:-1] or '.'):
return excludedmanifestrevlog(d)
result = super(narrowmanifestrevlog, self).dirlog(d)
makenarrowmanifestrevlog(result, repo)
return result
mfrevlog.__class__ = narrowmanifestrevlog
mfrevlog._narrowed = True
def makenarrowmanifestlog(mfl, repo):
class narrowmanifestlog(mfl.__class__):
def get(self, dir, node, verify=True):
if not repo.narrowmatch().visitdir(dir[:-1] or '.'):
return excludeddirmanifestctx(dir, node)
return super(narrowmanifestlog, self).get(dir, node, verify=verify)
mfl.__class__ = narrowmanifestlog
def makenarrowfilelog(fl, narrowmatch):
class narrowfilelog(fl.__class__):
def renamed(self, node):
# Renames that come from outside the narrowspec are
# problematic at least for git-diffs, because we lack the
# base text for the rename. This logic was introduced in
# 3cd72b1 of narrowhg (authored by martinvonz, reviewed by
# adgar), but that revision doesn't have any additional
# commentary on what problems we can encounter.
m = super(narrowfilelog, self).renamed(node)
if m and not narrowmatch(m[0]):
return None
return m
def size(self, rev):
# We take advantage of the fact that remotefilelog
# lacks a node() method to just skip the
# rename-checking logic when on remotefilelog. This
# might be incorrect on other non-revlog-based storage
# engines, but for now this seems to be fine.
#
# TODO: when remotefilelog is in core, improve this to
# explicitly look for remotefilelog instead of cheating
# with a hasattr check.
if util.safehasattr(self, 'node'):
node = self.node(rev)
# Because renamed() is overridden above to
# sometimes return None even if there is metadata
# in the revlog, size can be incorrect for
# copies/renames, so we need to make sure we call
# the super class's implementation of renamed()
# for the purpose of size calculation.
if super(narrowfilelog, self).renamed(node):
return len(self.read(node))
return super(narrowfilelog, self).size(rev)
def cmp(self, node, text):
different = super(narrowfilelog, self).cmp(node, text)
if different:
# Similar to size() above, if the file was copied from
# a file outside the narrowspec, the super class's
# would have returned True because we tricked it into
# thinking that the file was not renamed.
if super(narrowfilelog, self).renamed(node):
t2 = self.read(node)
return t2 != text
return different
fl.__class__ = narrowfilelog