# HG changeset patch # User Benoit Boissinot # Date 2013-02-11 00:21:24 # Node ID 1701421616726a052055472321c1269f90277d8d # Parent a5e94bee77eded5b7c3f2e5ba3fddf309472352a # Parent e556659340f09d504756de42f99c4ff71b2b063a merge crew and main diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py --- a/mercurial/dirstate.py +++ b/mercurial/dirstate.py @@ -9,7 +9,7 @@ import errno from node import nullid from i18n import _ import scmutil, util, ignore, osutil, parsers, encoding -import os, stat, errno +import os, stat, errno, gc propertycache = util.propertycache filecache = scmutil.filecache @@ -285,7 +285,23 @@ class dirstate(object): if not st: return - p = parsers.parse_dirstate(self._map, self._copymap, st) + # Python's garbage collector triggers a GC each time a certain number + # of container objects (the number being defined by + # gc.get_threshold()) are allocated. parse_dirstate creates a tuple + # for each file in the dirstate. The C version then immediately marks + # them as not to be tracked by the collector. However, this has no + # effect on when GCs are triggered, only on what objects the GC looks + # into. This means that O(number of files) GCs are unavoidable. + # Depending on when in the process's lifetime the dirstate is parsed, + # this can get very expensive. As a workaround, disable GC while + # parsing the dirstate. + gcenabled = gc.isenabled() + gc.disable() + try: + p = parsers.parse_dirstate(self._map, self._copymap, st) + finally: + if gcenabled: + gc.enable() if not self._dirtypl: self._pl = p diff --git a/mercurial/merge.py b/mercurial/merge.py --- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -196,6 +196,7 @@ def manifestmerge(repo, wctx, p2, pa, br overwrite = force and not branchmerge actions, copy, movewithdir = [], {}, {} + followcopies = False if overwrite: pa = wctx elif pa == p2: # backwards @@ -203,6 +204,13 @@ def manifestmerge(repo, wctx, p2, pa, br elif not branchmerge and not wctx.dirty(missing=True): pass elif pa and repo.ui.configbool("merge", "followcopies", True): + followcopies = True + + # manifests fetched in order are going to be faster, so prime the caches + [x.manifest() for x in + sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())] + + if followcopies: ret = copies.mergecopies(repo, wctx, p2, pa) copy, movewithdir, diverge, renamedelete = ret for of, fl in diverge.iteritems(): @@ -515,12 +523,12 @@ def calculateupdates(repo, tctx, mctx, a _checkcollision(mctx, None) else: _checkcollision(mctx, (tctx, ancestor)) - if tctx.rev() is None: - actions += _forgetremoved(tctx, mctx, branchmerge) actions += manifestmerge(repo, tctx, mctx, ancestor, branchmerge, force, partial) + if tctx.rev() is None: + actions += _forgetremoved(tctx, mctx, branchmerge) return actions def recordupdates(repo, actions, branchmerge):