Mercurial > public > mercurial-scm > hg-stable
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 |