comparison mercurial/manifest.py @ 41153:2c3f69855ce8

manifest: convert a recursive function to iterative one using stacks I am debugging a memory issue from yesterday where `hg update` goes upto taking 22GB of memory on our internal treemanifest repository. This is an interesting function and I saw memory consumption increasing while this function was running. It's sometimes hard to understand a recursive function and also the profile won't show you actual operations which took time, rather it will show you the function again and again in profile. I am yet to notice any memory consumption decrease with this patch, but I believe this will help like in making this a generator. Differential Revision: https://phab.mercurial-scm.org/D5413
author Pulkit Goyal <pulkit@yandex-team.ru>
date Wed, 12 Dec 2018 16:26:58 +0300
parents 3913223417ea
children 876494fd967d
comparison
equal deleted inserted replaced
41152:191fac9ff9d3 41153:2c3f69855ce8
1133 m1 = self.matches(match) 1133 m1 = self.matches(match)
1134 m2 = m2.matches(match) 1134 m2 = m2.matches(match)
1135 return m1.diff(m2, clean=clean) 1135 return m1.diff(m2, clean=clean)
1136 result = {} 1136 result = {}
1137 emptytree = treemanifest() 1137 emptytree = treemanifest()
1138 def _diff(t1, t2): 1138
1139 def _iterativediff(t1, t2, stack):
1140 """compares two tree manifests and append new tree-manifests which
1141 needs to be compared to stack"""
1139 if t1._node == t2._node and not t1._dirty and not t2._dirty: 1142 if t1._node == t2._node and not t1._dirty and not t2._dirty:
1140 return 1143 return
1141 t1._load() 1144 t1._load()
1142 t2._load() 1145 t2._load()
1143 self._loaddifflazy(t1, t2) 1146 self._loaddifflazy(t1, t2)
1144 1147
1145 for d, m1 in t1._dirs.iteritems(): 1148 for d, m1 in t1._dirs.iteritems():
1146 m2 = t2._dirs.get(d, emptytree) 1149 m2 = t2._dirs.get(d, emptytree)
1147 _diff(m1, m2) 1150 stack.append((m1, m2))
1148 1151
1149 for d, m2 in t2._dirs.iteritems(): 1152 for d, m2 in t2._dirs.iteritems():
1150 if d not in t1._dirs: 1153 if d not in t1._dirs:
1151 _diff(emptytree, m2) 1154 stack.append((emptytree, m2))
1152 1155
1153 for fn, n1 in t1._files.iteritems(): 1156 for fn, n1 in t1._files.iteritems():
1154 fl1 = t1._flags.get(fn, '') 1157 fl1 = t1._flags.get(fn, '')
1155 n2 = t2._files.get(fn, None) 1158 n2 = t2._files.get(fn, None)
1156 fl2 = t2._flags.get(fn, '') 1159 fl2 = t2._flags.get(fn, '')
1162 for fn, n2 in t2._files.iteritems(): 1165 for fn, n2 in t2._files.iteritems():
1163 if fn not in t1._files: 1166 if fn not in t1._files:
1164 fl2 = t2._flags.get(fn, '') 1167 fl2 = t2._flags.get(fn, '')
1165 result[t2._subpath(fn)] = ((None, ''), (n2, fl2)) 1168 result[t2._subpath(fn)] = ((None, ''), (n2, fl2))
1166 1169
1167 _diff(self, m2) 1170 stackls = []
1171 _iterativediff(self, m2, stackls)
1172 while stackls:
1173 t1, t2 = stackls.pop()
1174 # stackls is populated in the function call
1175 _iterativediff(t1, t2, stackls)
1168 return result 1176 return result
1169 1177
1170 def unmodifiedsince(self, m2): 1178 def unmodifiedsince(self, m2):
1171 return not self._dirty and not m2._dirty and self._node == m2._node 1179 return not self._dirty and not m2._dirty and self._node == m2._node
1172 1180