comparison src/org/tmatesoft/hg/repo/HgStatusCollector.java @ 195:c9b305df0b89

Optimization: use ParentWalker to get changeset's parents, if possible. Do not keep duplicating nodeids and strings in manifest revisions
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 15 Apr 2011 05:17:44 +0200
parents d5268ca7715b
children 3a7696fb457c
comparison
equal deleted inserted replaced
194:344e8d7e4d6e 195:c9b305df0b89
23 import java.util.Collections; 23 import java.util.Collections;
24 import java.util.LinkedHashMap; 24 import java.util.LinkedHashMap;
25 import java.util.LinkedList; 25 import java.util.LinkedList;
26 import java.util.List; 26 import java.util.List;
27 import java.util.Map; 27 import java.util.Map;
28 import java.util.SortedMap;
28 import java.util.TreeMap; 29 import java.util.TreeMap;
29 import java.util.TreeSet; 30 import java.util.TreeSet;
30 31
31 import org.tmatesoft.hg.core.HgDataStreamException; 32 import org.tmatesoft.hg.core.HgDataStreamException;
32 import org.tmatesoft.hg.core.Nodeid; 33 import org.tmatesoft.hg.core.Nodeid;
34 import org.tmatesoft.hg.internal.Pool;
33 import org.tmatesoft.hg.util.Path; 35 import org.tmatesoft.hg.util.Path;
34 import org.tmatesoft.hg.util.PathPool; 36 import org.tmatesoft.hg.util.PathPool;
35 import org.tmatesoft.hg.util.PathRewrite; 37 import org.tmatesoft.hg.util.PathRewrite;
36 38
37 39
42 * @author TMate Software Ltd. 44 * @author TMate Software Ltd.
43 */ 45 */
44 public class HgStatusCollector { 46 public class HgStatusCollector {
45 47
46 private final HgRepository repo; 48 private final HgRepository repo;
47 private final Map<Integer, ManifestRevisionInspector> cache; // sparse array, in fact 49 private final SortedMap<Integer, ManifestRevisionInspector> cache; // sparse array, in fact
50 // with cpython repository, ~70 000 changes, complete Log (direct out, no reverse) output
51 // no cache limit, no nodeids and fname caching - OOME on changeset 1035
52 // no cache limit, but with cached nodeids and filenames - 1730+
53 // cache limit 100 - 19+ minutes to process 10000, and still working (too long, stopped)
54 private final int cacheMaxSize = 100; // do not keep too much manifest revisions
48 private PathPool pathPool; 55 private PathPool pathPool;
56 private final Pool<Nodeid> cacheNodes;
57 private final Pool<String> cacheFilenames; // XXX in fact, need to think if use of PathPool directly instead is better solution
58
49 59
50 public HgStatusCollector(HgRepository hgRepo) { 60 public HgStatusCollector(HgRepository hgRepo) {
51 this.repo = hgRepo; 61 this.repo = hgRepo;
52 cache = new TreeMap<Integer, ManifestRevisionInspector>(); 62 cache = new TreeMap<Integer, ManifestRevisionInspector>();
53 ManifestRevisionInspector emptyFakeState = new ManifestRevisionInspector(); 63 cacheNodes = new Pool<Nodeid>();
64 cacheFilenames = new Pool<String>();
65 ManifestRevisionInspector emptyFakeState = new ManifestRevisionInspector(null, null);
54 emptyFakeState.begin(-1, null); 66 emptyFakeState.begin(-1, null);
55 emptyFakeState.end(-1); // FIXME HgRepo.TIP == -1 as well, need to distinguish fake "prior to first" revision from "the very last" 67 emptyFakeState.end(-1); // FIXME HgRepo.TIP == -1 as well, need to distinguish fake "prior to first" revision from "the very last"
56 cache.put(-1, emptyFakeState); 68 cache.put(-1, emptyFakeState);
57 } 69 }
58 70
61 } 73 }
62 74
63 private ManifestRevisionInspector get(int rev) { 75 private ManifestRevisionInspector get(int rev) {
64 ManifestRevisionInspector i = cache.get(rev); 76 ManifestRevisionInspector i = cache.get(rev);
65 if (i == null) { 77 if (i == null) {
66 i = new ManifestRevisionInspector(); 78 if (cache.size() > cacheMaxSize) {
79 // assume usually we go from oldest to newest, hence remove oldest as most likely to be no longer necessary
80 cache.remove(cache.firstKey());
81 }
82 i = new ManifestRevisionInspector(cacheNodes, cacheFilenames);
67 cache.put(rev, i); 83 cache.put(rev, i);
68 repo.getManifest().walk(rev, rev, i); 84 repo.getManifest().walk(rev, rev, i);
69 } 85 }
70 return i; 86 return i;
71 } 87 }
128 144
129 repo.getManifest().walk(minRev, maxRev, new HgManifest.Inspector() { 145 repo.getManifest().walk(minRev, maxRev, new HgManifest.Inspector() {
130 private ManifestRevisionInspector delegate; 146 private ManifestRevisionInspector delegate;
131 147
132 public boolean begin(int revision, Nodeid nid) { 148 public boolean begin(int revision, Nodeid nid) {
133 cache.put(revision, delegate = new ManifestRevisionInspector()); 149 cache.put(revision, delegate = new ManifestRevisionInspector(cacheNodes, cacheFilenames));
134 delegate.begin(revision, nid); 150 delegate.begin(revision, nid);
135 return true; 151 return true;
136 } 152 }
137 153
138 public boolean next(Nodeid nid, String fname, String flags) { 154 public boolean next(Nodeid nid, String fname, String flags) {
340 } 356 }
341 l.add(p); 357 l.add(p);
342 return l; 358 return l;
343 } 359 }
344 } 360 }
345 361
346 /*package-local*/ static final class ManifestRevisionInspector implements HgManifest.Inspector { 362 /*package-local*/ static final class ManifestRevisionInspector implements HgManifest.Inspector {
347 private final TreeMap<String, Nodeid> idsMap; 363 private final TreeMap<String, Nodeid> idsMap;
348 private final TreeMap<String, String> flagsMap; 364 private final TreeMap<String, String> flagsMap;
349 365 private final Pool<Nodeid> idsPool;
350 public ManifestRevisionInspector() { 366 private final Pool<String> namesPool;
367
368 // optional pools for effective management of nodeids and filenames (they are likely
369 // to be duplicated among different manifest revisions
370 public ManifestRevisionInspector(Pool<Nodeid> nodeidPool, Pool<String> filenamePool) {
371 idsPool = nodeidPool;
372 namesPool = filenamePool;
351 idsMap = new TreeMap<String, Nodeid>(); 373 idsMap = new TreeMap<String, Nodeid>();
352 flagsMap = new TreeMap<String, String>(); 374 flagsMap = new TreeMap<String, String>();
353 } 375 }
354 376
355 public Collection<String> files() { 377 public Collection<String> files() {
365 } 387 }
366 388
367 // 389 //
368 390
369 public boolean next(Nodeid nid, String fname, String flags) { 391 public boolean next(Nodeid nid, String fname, String flags) {
392 if (namesPool != null) {
393 fname = namesPool.unify(fname);
394 }
395 if (idsPool != null) {
396 nid = idsPool.unify(nid);
397 }
370 idsMap.put(fname, nid); 398 idsMap.put(fname, nid);
371 flagsMap.put(fname, flags); 399 flagsMap.put(fname, flags);
372 return true; 400 return true;
373 } 401 }
374 402