comparison mercurial/copies.py @ 46011:b9588ff9b66a

copies: avoid materializing a full directory map during copy tracing Materializing a full copy of every directory in a treemanifest repo can be quite expensive, even with a narrow matcher. For flat manifest repos, this should be equivalent - it will still materialize (and cache) a dict of all of the dirs inside of the manifest object, we just don't get a copy of it. In a repo I have here, this brings the time for a simple rebase from 11.197s to 4.609s. Differential Revision: https://phab.mercurial-scm.org/D9503
author Kyle Lippincott <spectral@google.com>
date Wed, 02 Dec 2020 11:05:53 -0800
parents f9f8d8aa9a92
children 8d54944eaeb0
comparison
equal deleted inserted replaced
46010:61c1f29e7f4f 46011:b9588ff9b66a
928 fullcopy: files copied on the same side (as ctx), including those that 928 fullcopy: files copied on the same side (as ctx), including those that
929 merge.manifestmerge() won't care about 929 merge.manifestmerge() won't care about
930 addedfiles: added files on the other side (compared to ctx) 930 addedfiles: added files on the other side (compared to ctx)
931 """ 931 """
932 # generate a directory move map 932 # generate a directory move map
933 d = ctx.dirs()
934 invalid = set() 933 invalid = set()
935 dirmove = {} 934 dirmove = {}
936 935
937 # examine each file copy for a potential directory move, which is 936 # examine each file copy for a potential directory move, which is
938 # when all the files in a directory are moved to a new directory 937 # when all the files in a directory are moved to a new directory
939 for dst, src in pycompat.iteritems(fullcopy): 938 for dst, src in pycompat.iteritems(fullcopy):
940 dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst) 939 dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst)
941 if dsrc in invalid: 940 if dsrc in invalid:
942 # already seen to be uninteresting 941 # already seen to be uninteresting
943 continue 942 continue
944 elif dsrc in d and ddst in d: 943 elif ctx.hasdir(dsrc) and ctx.hasdir(ddst):
945 # directory wasn't entirely moved locally 944 # directory wasn't entirely moved locally
946 invalid.add(dsrc) 945 invalid.add(dsrc)
947 elif dsrc in dirmove and dirmove[dsrc] != ddst: 946 elif dsrc in dirmove and dirmove[dsrc] != ddst:
948 # files from the same directory moved to two different places 947 # files from the same directory moved to two different places
949 invalid.add(dsrc) 948 invalid.add(dsrc)
952 dirmove[dsrc] = ddst 951 dirmove[dsrc] = ddst
953 952
954 for i in invalid: 953 for i in invalid:
955 if i in dirmove: 954 if i in dirmove:
956 del dirmove[i] 955 del dirmove[i]
957 del d, invalid 956 del invalid
958 957
959 if not dirmove: 958 if not dirmove:
960 return {}, {} 959 return {}, {}
961 960
962 dirmove = {k + b"/": v + b"/" for k, v in pycompat.iteritems(dirmove)} 961 dirmove = {k + b"/": v + b"/" for k, v in pycompat.iteritems(dirmove)}