Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/StatusCollector.java @ 89:42bcb4bffd17
Refactored to simplify manifest collector
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Wed, 26 Jan 2011 06:18:31 +0100 |
parents | 61eedab3eb3e |
children | a95c700408a9 |
comparison
equal
deleted
inserted
replaced
88:61eedab3eb3e | 89:42bcb4bffd17 |
---|---|
24 import java.util.HashMap; | 24 import java.util.HashMap; |
25 import java.util.LinkedHashMap; | 25 import java.util.LinkedHashMap; |
26 import java.util.LinkedList; | 26 import java.util.LinkedList; |
27 import java.util.List; | 27 import java.util.List; |
28 import java.util.Map; | 28 import java.util.Map; |
29 import java.util.TreeMap; | |
29 import java.util.TreeSet; | 30 import java.util.TreeSet; |
30 | 31 |
31 import org.tmatesoft.hg.core.Nodeid; | 32 import org.tmatesoft.hg.core.Nodeid; |
32 import org.tmatesoft.hg.core.Path; | 33 import org.tmatesoft.hg.core.Path; |
33 | 34 |
44 private final Map<Integer, ManifestRevisionInspector> cache; // sparse array, in fact | 45 private final Map<Integer, ManifestRevisionInspector> cache; // sparse array, in fact |
45 | 46 |
46 public StatusCollector(HgRepository hgRepo) { | 47 public StatusCollector(HgRepository hgRepo) { |
47 this.repo = hgRepo; | 48 this.repo = hgRepo; |
48 cache = new HashMap<Integer, ManifestRevisionInspector>(); | 49 cache = new HashMap<Integer, ManifestRevisionInspector>(); |
49 ManifestRevisionInspector emptyFakeState = new ManifestRevisionInspector(-1, -1); | 50 ManifestRevisionInspector emptyFakeState = new ManifestRevisionInspector(); |
50 emptyFakeState.begin(-1, null); | 51 emptyFakeState.begin(-1, null); |
51 emptyFakeState.end(-1); // FIXME HgRepo.TIP == -1 as well, need to distinguish fake "prior to first" revision from "the very last" | 52 emptyFakeState.end(-1); // FIXME HgRepo.TIP == -1 as well, need to distinguish fake "prior to first" revision from "the very last" |
52 cache.put(-1, emptyFakeState); | 53 cache.put(-1, emptyFakeState); |
53 } | 54 } |
54 | 55 |
57 } | 58 } |
58 | 59 |
59 private ManifestRevisionInspector get(int rev) { | 60 private ManifestRevisionInspector get(int rev) { |
60 ManifestRevisionInspector i = cache.get(rev); | 61 ManifestRevisionInspector i = cache.get(rev); |
61 if (i == null) { | 62 if (i == null) { |
62 i = new ManifestRevisionInspector(rev, rev); | 63 i = new ManifestRevisionInspector(); |
63 cache.put(rev, i); | 64 cache.put(rev, i); |
64 repo.getManifest().walk(rev, rev, i); | 65 repo.getManifest().walk(rev, rev, i); |
65 } | 66 } |
66 return i; | 67 return i; |
67 } | 68 } |
96 if (rev2 == TIP) { | 97 if (rev2 == TIP) { |
97 rev2 = repo.getManifest().getRevisionCount() - 1; // XXX add Revlog.tip() func ? | 98 rev2 = repo.getManifest().getRevisionCount() - 1; // XXX add Revlog.tip() func ? |
98 } | 99 } |
99 // in fact, rev1 and rev2 are often next (or close) to each other, | 100 // in fact, rev1 and rev2 are often next (or close) to each other, |
100 // thus, we can optimize Manifest reads here (manifest.walk(rev1, rev2)) | 101 // thus, we can optimize Manifest reads here (manifest.walk(rev1, rev2)) |
101 ManifestRevisionInspector r1, r2; | 102 ManifestRevisionInspector r1, r2 ; |
102 if (!cache.containsKey(rev1) && !cache.containsKey(rev2) && Math.abs(rev1 - rev2) < 5 /*subjective equivalent of 'close enough'*/) { | 103 if (!cache.containsKey(rev1) && !cache.containsKey(rev2) && Math.abs(rev1 - rev2) < 5 /*subjective equivalent of 'close enough'*/) { |
103 int minRev = rev1 < rev2 ? rev1 : rev2; | 104 int minRev = rev1 < rev2 ? rev1 : rev2; |
104 int maxRev = minRev == rev1 ? rev2 : rev1; | 105 int maxRev = minRev == rev1 ? rev2 : rev1; |
105 r1 = r2 = new ManifestRevisionInspector(minRev, maxRev); | 106 if (minRev > 0) { |
106 for (int i = minRev; i <= maxRev; i++) { | 107 minRev--; // expand range a bit |
107 cache.put(i, r1); | 108 // XXX perhaps, if revlog.baseRevision is cheap, shall expand minRev up to baseRevision |
108 } | 109 // which gonna be read anyway |
109 repo.getManifest().walk(minRev, maxRev, r1); | 110 } |
110 } else { | 111 |
111 r1 = get(rev1); | 112 repo.getManifest().walk(minRev, maxRev, new HgManifest.Inspector() { |
112 r2 = get(rev2); | 113 private ManifestRevisionInspector delegate; |
113 } | 114 |
114 | 115 public boolean begin(int revision, Nodeid nid) { |
115 TreeSet<String> r1Files = new TreeSet<String>(r1.files(rev1)); | 116 cache.put(revision, delegate = new ManifestRevisionInspector()); |
116 for (String fname : r2.files(rev2)) { | 117 delegate.begin(revision, nid); |
118 return true; | |
119 } | |
120 | |
121 public boolean next(Nodeid nid, String fname, String flags) { | |
122 delegate.next(nid, fname, flags); | |
123 return true; | |
124 } | |
125 | |
126 public boolean end(int revision) { | |
127 delegate.end(revision); | |
128 delegate = null; | |
129 return true; | |
130 } | |
131 }); | |
132 } | |
133 r1 = get(rev1); | |
134 r2 = get(rev2); | |
135 | |
136 | |
137 TreeSet<String> r1Files = new TreeSet<String>(r1.files()); | |
138 for (String fname : r2.files()) { | |
117 if (r1Files.remove(fname)) { | 139 if (r1Files.remove(fname)) { |
118 Nodeid nidR1 = r1.nodeid(rev1, fname); | 140 Nodeid nidR1 = r1.nodeid(fname); |
119 Nodeid nidR2 = r2.nodeid(rev2, fname); | 141 Nodeid nidR2 = r2.nodeid(fname); |
120 String flagsR1 = r1.flags(rev1, fname); | 142 String flagsR1 = r1.flags(fname); |
121 String flagsR2 = r2.flags(rev2, fname); | 143 String flagsR2 = r2.flags(fname); |
122 if (nidR1.equals(nidR2) && ((flagsR2 == null && flagsR1 == null) || flagsR2.equals(flagsR1))) { | 144 if (nidR1.equals(nidR2) && ((flagsR2 == null && flagsR1 == null) || flagsR2.equals(flagsR1))) { |
123 inspector.clean(fname); | 145 inspector.clean(fname); |
124 } else { | 146 } else { |
125 inspector.modified(fname); | 147 inspector.modified(fname); |
126 } | 148 } |
200 return null; | 222 return null; |
201 } | 223 } |
202 if ((modified == null || !modified.contains(fname)) && (removed == null || !removed.contains(fname))) { | 224 if ((modified == null || !modified.contains(fname)) && (removed == null || !removed.contains(fname))) { |
203 return null; | 225 return null; |
204 } | 226 } |
205 return statusHelper.raw(startRev).nodeid(startRev, fname); | 227 return statusHelper.raw(startRev).nodeid(fname); |
206 } | 228 } |
207 public Nodeid nodeidAfterChange(String fname) { | 229 public Nodeid nodeidAfterChange(String fname) { |
208 if (statusHelper == null || endRev == BAD_REVISION) { | 230 if (statusHelper == null || endRev == BAD_REVISION) { |
209 return null; | 231 return null; |
210 } | 232 } |
211 if ((modified == null || !modified.contains(fname)) && (added == null || !added.contains(fname))) { | 233 if ((modified == null || !modified.contains(fname)) && (added == null || !added.contains(fname))) { |
212 return null; | 234 return null; |
213 } | 235 } |
214 return statusHelper.raw(endRev).nodeid(endRev, fname); | 236 return statusHelper.raw(endRev).nodeid(fname); |
215 } | 237 } |
216 | 238 |
217 public List<String> getModified() { | 239 public List<String> getModified() { |
218 return proper(modified); | 240 return proper(modified); |
219 } | 241 } |
302 l.add(s); | 324 l.add(s); |
303 return l; | 325 return l; |
304 } | 326 } |
305 } | 327 } |
306 | 328 |
307 // XXX in fact, indexed access brings more trouble than benefits, get rid of it? Distinct instance per revision is good enough | 329 /*package-local*/ static final class ManifestRevisionInspector implements HgManifest.Inspector { |
308 public /*XXX private, actually. Made public unless repo.statusLocal finds better place*/ static final class ManifestRevisionInspector implements HgManifest.Inspector { | 330 private final TreeMap<String, Nodeid> idsMap; |
309 private final HashMap<String, Nodeid>[] idsMap; | 331 private final TreeMap<String, String> flagsMap; |
310 private final HashMap<String, String>[] flagsMap; | 332 |
311 private final int baseRevision; | 333 public ManifestRevisionInspector() { |
312 private int r = -1; // cursor | 334 idsMap = new TreeMap<String, Nodeid>(); |
313 | 335 flagsMap = new TreeMap<String, String>(); |
314 /** | 336 } |
315 * [minRev, maxRev] | 337 |
316 * [-1,-1] also accepted (for fake empty instance) | 338 public Collection<String> files() { |
317 * @param minRev - inclusive | 339 return idsMap.keySet(); |
318 * @param maxRev - inclusive | 340 } |
319 */ | 341 |
320 @SuppressWarnings("unchecked") | 342 public Nodeid nodeid(String fname) { |
321 public ManifestRevisionInspector(int minRev, int maxRev) { | 343 return idsMap.get(fname); |
322 baseRevision = minRev; | 344 } |
323 int range = maxRev - minRev + 1; | 345 |
324 idsMap = new HashMap[range]; | 346 public String flags(String fname) { |
325 flagsMap = new HashMap[range]; | 347 return flagsMap.get(fname); |
326 } | |
327 | |
328 public Collection<String> files(int rev) { | |
329 if (rev < baseRevision || rev >= baseRevision + idsMap.length) { | |
330 throw new IllegalArgumentException(); | |
331 } | |
332 return idsMap[rev - baseRevision].keySet(); | |
333 } | |
334 | |
335 public Nodeid nodeid(int rev, String fname) { | |
336 if (rev < baseRevision || rev >= baseRevision + idsMap.length) { | |
337 throw new IllegalArgumentException(); | |
338 } | |
339 return idsMap[rev - baseRevision].get(fname); | |
340 } | |
341 | |
342 public String flags(int rev, String fname) { | |
343 if (rev < baseRevision || rev >= baseRevision + idsMap.length) { | |
344 throw new IllegalArgumentException(); | |
345 } | |
346 return flagsMap[rev - baseRevision].get(fname); | |
347 } | 348 } |
348 | 349 |
349 // | 350 // |
350 | 351 |
351 public boolean next(Nodeid nid, String fname, String flags) { | 352 public boolean next(Nodeid nid, String fname, String flags) { |
352 idsMap[r].put(fname, nid); | 353 idsMap.put(fname, nid); |
353 flagsMap[r].put(fname, flags); | 354 flagsMap.put(fname, flags); |
354 return true; | 355 return true; |
355 } | 356 } |
356 | 357 |
357 public boolean end(int revision) { | 358 public boolean end(int revision) { |
358 assert revision == r + baseRevision; | 359 // in fact, this class cares about single revision |
359 r = -1; | 360 return false; |
360 return revision+1 < baseRevision + idsMap.length; | |
361 } | 361 } |
362 | 362 |
363 public boolean begin(int revision, Nodeid nid) { | 363 public boolean begin(int revision, Nodeid nid) { |
364 if (revision < baseRevision || revision >= baseRevision + idsMap.length) { | |
365 throw new IllegalArgumentException(); | |
366 } | |
367 r = revision - baseRevision; | |
368 idsMap[r] = new HashMap<String, Nodeid>(); | |
369 flagsMap[r] = new HashMap<String, String>(); | |
370 return true; | 364 return true; |
371 } | 365 } |
372 } | 366 } |
373 | 367 |
374 } | 368 } |