comparison mercurial/cmdutil.py @ 20553:86cefb15e7b5

cmdutil: implemented new lazy increasingwindows Now log can work in a lazy way and get results as soon as they are processed. Performance Benchmarking: $ time hg log -l1 -qr "branch(default)" 0:9117c6561b0b real 0m2.303s user 0m2.252s sys 0m0.048s $ time ./hg log -l1 -qr "branch(default)" 0:9117c6561b0b real 0m0.238s user 0m0.199s sys 0m0.037s
author Lucas Moscovicz <lmoscovicz@fb.com>
date Thu, 13 Feb 2014 14:27:12 -0800
parents ce3f3082ec45
children d4893e64f300
comparison
equal deleted inserted replaced
20552:0e99a66eb7bc 20553:86cefb15e7b5
1131 (rev, util.datestr(results[rev]))) 1131 (rev, util.datestr(results[rev])))
1132 return str(rev) 1132 return str(rev)
1133 1133
1134 raise util.Abort(_("revision matching date not found")) 1134 raise util.Abort(_("revision matching date not found"))
1135 1135
1136 def increasingwindows(start, end, windowsize=8, sizelimit=512): 1136 def increasingwindows(windowsize=8, sizelimit=512):
1137 if start < end: 1137 while True:
1138 while start < end: 1138 yield windowsize
1139 yield start, min(windowsize, end - start) 1139 if windowsize < sizelimit:
1140 start += windowsize 1140 windowsize *= 2
1141 if windowsize < sizelimit:
1142 windowsize *= 2
1143 else:
1144 while start > end:
1145 yield start, min(windowsize, start - end - 1)
1146 start -= windowsize
1147 if windowsize < sizelimit:
1148 windowsize *= 2
1149 1141
1150 class FileWalkError(Exception): 1142 class FileWalkError(Exception):
1151 pass 1143 pass
1152 1144
1153 def walkfilerevs(repo, match, follow, revs, fncache): 1145 def walkfilerevs(repo, match, follow, revs, fncache):
1276 return [] 1268 return []
1277 wanted = set() 1269 wanted = set()
1278 slowpath = match.anypats() or (match.files() and opts.get('removed')) 1270 slowpath = match.anypats() or (match.files() and opts.get('removed'))
1279 fncache = {} 1271 fncache = {}
1280 change = repo.changectx 1272 change = repo.changectx
1281 revs = revset.baseset(revs)
1282 1273
1283 # First step is to fill wanted, the set of revisions that we want to yield. 1274 # First step is to fill wanted, the set of revisions that we want to yield.
1284 # When it does not induce extra cost, we also fill fncache for revisions in 1275 # When it does not induce extra cost, we also fill fncache for revisions in
1285 # wanted: a cache of filenames that were changed (ctx.files()) and that 1276 # wanted: a cache of filenames that were changed (ctx.files()) and that
1286 # match the file filtering conditions. 1277 # match the file filtering conditions.
1287 1278
1288 if not slowpath and not match.files(): 1279 if not slowpath and not match.files():
1289 # No files, no patterns. Display all revs. 1280 # No files, no patterns. Display all revs.
1290 wanted = set(revs) 1281 wanted = revs
1291 1282
1292 if not slowpath and match.files(): 1283 if not slowpath and match.files():
1293 # We only have to read through the filelog to find wanted revisions 1284 # We only have to read through the filelog to find wanted revisions
1294 1285
1295 try: 1286 try:
1387 rev = repo[rev].rev() 1378 rev = repo[rev].rev()
1388 ff = followfilter() 1379 ff = followfilter()
1389 stop = min(revs[0], revs[-1]) 1380 stop = min(revs[0], revs[-1])
1390 for x in xrange(rev, stop - 1, -1): 1381 for x in xrange(rev, stop - 1, -1):
1391 if ff.match(x): 1382 if ff.match(x):
1392 wanted.discard(x) 1383 wanted = wanted - [x]
1393
1394 # Choose a small initial window if we will probably only visit a
1395 # few commits.
1396 limit = loglimit(opts)
1397 windowsize = 8
1398 if limit:
1399 windowsize = min(limit, windowsize)
1400 1384
1401 # Now that wanted is correctly initialized, we can iterate over the 1385 # Now that wanted is correctly initialized, we can iterate over the
1402 # revision range, yielding only revisions in wanted. 1386 # revision range, yielding only revisions in wanted.
1403 def iterate(): 1387 def iterate():
1404 if follow and not match.files(): 1388 if follow and not match.files():
1407 return ff.match(rev) and rev in wanted 1391 return ff.match(rev) and rev in wanted
1408 else: 1392 else:
1409 def want(rev): 1393 def want(rev):
1410 return rev in wanted 1394 return rev in wanted
1411 1395
1412 for i, window in increasingwindows(0, len(revs), windowsize): 1396 it = iter(revs)
1413 nrevs = [rev for rev in revs[i:i + window] if want(rev)] 1397 stopiteration = False
1398 for windowsize in increasingwindows():
1399 nrevs = []
1400 for i in xrange(windowsize):
1401 try:
1402 rev = it.next()
1403 if want(rev):
1404 nrevs.append(rev)
1405 except (StopIteration):
1406 stopiteration = True
1407 break
1414 for rev in sorted(nrevs): 1408 for rev in sorted(nrevs):
1415 fns = fncache.get(rev) 1409 fns = fncache.get(rev)
1416 ctx = change(rev) 1410 ctx = change(rev)
1417 if not fns: 1411 if not fns:
1418 def fns_generator(): 1412 def fns_generator():
1421 yield f 1415 yield f
1422 fns = fns_generator() 1416 fns = fns_generator()
1423 prepare(ctx, fns) 1417 prepare(ctx, fns)
1424 for rev in nrevs: 1418 for rev in nrevs:
1425 yield change(rev) 1419 yield change(rev)
1420
1421 if stopiteration:
1422 break
1423
1426 return iterate() 1424 return iterate()
1427 1425
1428 def _makegraphfilematcher(repo, pats, followfirst): 1426 def _makegraphfilematcher(repo, pats, followfirst):
1429 # When displaying a revision with --patch --follow FILE, we have 1427 # When displaying a revision with --patch --follow FILE, we have
1430 # to know which file of the revision must be diffed. With 1428 # to know which file of the revision must be diffed. With