merge: check created file dirs for path conflicts only once (issue5716)

In large repositories, updates involving the creation of many files check the
same directories repeatedly in the wctx manifest.  Move these checks out to a
separate loop to avoid repeated checks hitting the manifest.

Differential Revision: https://phab.mercurial-scm.org/D1226
This commit is contained in:
Mark Thomas 2017-11-24 12:53:58 -08:00
parent 2f4962c2a4
commit 107956c510

View File

@ -915,34 +915,21 @@ def checkpathconflicts(repo, wctx, mctx, actions):
# can't be updated to cleanly.
invalidconflicts = set()
# The set of directories that contain files that are being created.
createdfiledirs = set()
# The set of files deleted by all the actions.
deletedfiles = set()
for f, (m, args, msg) in actions.items():
if m in ('c', 'dc', 'm', 'cm'):
# This action may create a new local file.
createdfiledirs.update(util.finddirs(f))
if mf.hasdir(f):
# The file aliases a local directory. This might be ok if all
# the files in the local directory are being deleted. This
# will be checked once we know what all the deleted files are.
remoteconflicts.add(f)
for p in util.finddirs(f):
if p in mf:
if p in mctx:
# The file is in a directory which aliases both a local
# and a remote file. This is an internal inconsistency
# within the remote manifest.
invalidconflicts.add(p)
else:
# The file is in a directory which aliases a local file.
# We will need to rename the local file.
localconflicts.add(p)
if p in actions and actions[p][0] in ('c', 'dc', 'm', 'cm'):
# The file is in a directory which aliases a remote file.
# This is an internal inconsistency within the remote
# manifest.
invalidconflicts.add(p)
# Track the names of all deleted files.
if m == 'r':
deletedfiles.add(f)
@ -954,6 +941,24 @@ def checkpathconflicts(repo, wctx, mctx, actions):
f2, flags = args
deletedfiles.add(f2)
# Check all directories that contain created files for path conflicts.
for p in createdfiledirs:
if p in mf:
if p in mctx:
# A file is in a directory which aliases both a local
# and a remote file. This is an internal inconsistency
# within the remote manifest.
invalidconflicts.add(p)
else:
# A file is in a directory which aliases a local file.
# We will need to rename the local file.
localconflicts.add(p)
if p in actions and actions[p][0] in ('c', 'dc', 'm', 'cm'):
# The file is in a directory which aliases a remote file.
# This is an internal inconsistency within the remote
# manifest.
invalidconflicts.add(p)
# Rename all local conflicting files that have not been deleted.
for p in localconflicts:
if p not in deletedfiles: