From d4deebc4f7da506cb9128dacabd4a0894456b01e Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Mon, 26 Nov 2012 13:44:11 -0600 Subject: [PATCH 1/5] revset: backed out changeset 7a8dc9a35aa2 This was causing clones of the hg repo to go from 12.4s to 14.7s. --- mercurial/revset.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/mercurial/revset.py b/mercurial/revset.py index 94e120547f..c78ea53ea1 100644 --- a/mercurial/revset.py +++ b/mercurial/revset.py @@ -571,14 +571,6 @@ def _descendants(repo, subset, x, followfirst=False): if not args: return [] s = set(_revdescendants(repo, args, followfirst)) | set(args) - - if len(subset) == len(repo): - # the passed in revisions may not exist, -1 for example - for arg in args: - if arg not in subset: - s.remove(arg) - return list(s) - return [r for r in subset if r in s] def descendants(repo, subset, x): @@ -1336,10 +1328,7 @@ def roots(repo, subset, x): Changesets in set with no parent changeset in set. """ s = set(getset(repo, repo.changelog, x)) - if len(subset) == len(repo): - subset = s - else: - subset = [r for r in subset if r in s] + subset = [r for r in subset if r in s] cs = _children(repo, subset, s) return [r for r in subset if r not in cs] From af5b4b62cf891217e302129e8fa58867b90e8c64 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Mon, 26 Nov 2012 15:42:52 -0600 Subject: [PATCH 2/5] util: make chunkbuffer non-quadratic on Windows The old str-based += collector performed very nicely on Linux, but turns out to be quadratically expensive on Windows, causing chunkbuffer to dominate in profiles. This list-based version has been measured to significantly improve performance with large chunks on Windows, with negligible overall overhead on Linux (though microbenchmarks show it to be about 50% slower). This may increase memory overhead where += didn't behave quadratically. If we want to gather up 1G of data to join, we temporarily have 1G in our list and 1G in our string. --- mercurial/util.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mercurial/util.py b/mercurial/util.py index 7f0e707df4..52d577098c 100644 --- a/mercurial/util.py +++ b/mercurial/util.py @@ -899,7 +899,7 @@ class chunkbuffer(object): """Read L bytes of data from the iterator of chunks of data. Returns less than L bytes if the iterator runs dry.""" left = l - buf = '' + buf = [] queue = self._queue while left > 0: # refill the queue @@ -917,11 +917,11 @@ class chunkbuffer(object): left -= len(chunk) if left < 0: queue.appendleft(chunk[left:]) - buf += chunk[:left] + buf.append(chunk[:left]) else: - buf += chunk + buf.append(chunk) - return buf + return ''.join(buf) def filechunkiter(f, size=65536, limit=None): """Create a generator that produces the data in the file size From c6fe65e9e2214fef08c479d66a82e0a4c0ac301f Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Mon, 26 Nov 2012 16:14:22 -0600 Subject: [PATCH 3/5] hooks: delay I/O redirection until we actually run a hook (issue3711) We were attempting to redirect I/O even if no hook was actually getting called. This defers redirection until we've found something to do. --- mercurial/hook.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/mercurial/hook.py b/mercurial/hook.py index 743519f525..fd98733804 100644 --- a/mercurial/hook.py +++ b/mercurial/hook.py @@ -142,25 +142,26 @@ def hook(ui, repo, name, throw=False, **args): return False r = False - oldstdout = -1 - if _redirect: - try: - stdoutno = sys.__stdout__.fileno() - stderrno = sys.__stderr__.fileno() - # temporarily redirect stdout to stderr, if possible - if stdoutno >= 0 and stderrno >= 0: - sys.__stdout__.flush() - oldstdout = os.dup(stdoutno) - os.dup2(stderrno, stdoutno) - except AttributeError: - # __stdout__/__stderr__ doesn't have fileno(), it's not a real file - pass try: for hname, cmd in _allhooks(ui): if hname.split('.')[0] != name or not cmd: continue + + if oldstdout == -1 and _redirect: + try: + stdoutno = sys.__stdout__.fileno() + stderrno = sys.__stderr__.fileno() + # temporarily redirect stdout to stderr, if possible + if stdoutno >= 0 and stderrno >= 0: + sys.__stdout__.flush() + oldstdout = os.dup(stdoutno) + os.dup2(stderrno, stdoutno) + except AttributeError: + # __stdout__/__stderr__ has no fileno(), not a real file + pass + if util.safehasattr(cmd, '__call__'): r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r elif cmd.startswith('python:'): From 1c34c93b250e7c150f55fcfadad54cb05cfbbae6 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Mon, 26 Nov 2012 17:48:39 -0600 Subject: [PATCH 4/5] hooks: be even more forgiven of non-fd descriptors (issue3711) Looks like there are instances where sys.stdout/stderr contain file handles that are invalid. We should be tolerant of this for hook I/O redirection, as our primary concern is not garbling our own output stream. --- mercurial/hook.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mercurial/hook.py b/mercurial/hook.py index fd98733804..0a4cf21259 100644 --- a/mercurial/hook.py +++ b/mercurial/hook.py @@ -158,8 +158,8 @@ def hook(ui, repo, name, throw=False, **args): sys.__stdout__.flush() oldstdout = os.dup(stdoutno) os.dup2(stderrno, stdoutno) - except AttributeError: - # __stdout__/__stderr__ has no fileno(), not a real file + except (OSError, AttributeError): + # files seem to be bogus, give up on redirecting (WSGI, etc) pass if util.safehasattr(cmd, '__call__'): From 94ef5e50d62cbae83a026938389d27591369c474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Sintzoff?= Date: Sun, 25 Nov 2012 20:39:37 +0100 Subject: [PATCH 5/5] phases: fix missing "error" module import (issue3707) --- mercurial/phases.py | 2 +- tests/test-phases.t | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/mercurial/phases.py b/mercurial/phases.py index 2ed98fd1cb..130069b4b3 100644 --- a/mercurial/phases.py +++ b/mercurial/phases.py @@ -103,7 +103,7 @@ Note: old client behave as a publishing server with draft only content import errno from node import nullid, nullrev, bin, hex, short from i18n import _ -import util +import util, error import obsolete allphases = public, draft, secret = range(3) diff --git a/tests/test-phases.t b/tests/test-phases.t index 28e7dab198..d057eef5ca 100644 --- a/tests/test-phases.t +++ b/tests/test-phases.t @@ -337,8 +337,17 @@ test that phase are displayed in log at debug level description: A - + +(Issue3707) +test invalid phase name + + $ mkcommit I --config phases.new-commit='babar' + transaction abort! + rollback completed + abort: phases.new-commit: not a valid phase name ('babar') + [255] + Test phase command ===================