Mercurial > hg4j
comparison test/org/tmatesoft/hg/test/MapTagsToFileRevisions.java @ 326:d42a45a2c9d6
Alternative tag collection approach for a file history
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Tue, 04 Oct 2011 06:28:01 +0200 |
parents | 283b294d1079 |
children | 694ebabb5cb3 |
comparison
equal
deleted
inserted
replaced
325:f05c8b1f08c4 | 326:d42a45a2c9d6 |
---|---|
15 import org.tmatesoft.hg.core.HgChangeset; | 15 import org.tmatesoft.hg.core.HgChangeset; |
16 import org.tmatesoft.hg.core.HgChangesetHandler; | 16 import org.tmatesoft.hg.core.HgChangesetHandler; |
17 import org.tmatesoft.hg.core.HgException; | 17 import org.tmatesoft.hg.core.HgException; |
18 import org.tmatesoft.hg.core.HgLogCommand; | 18 import org.tmatesoft.hg.core.HgLogCommand; |
19 import org.tmatesoft.hg.core.Nodeid; | 19 import org.tmatesoft.hg.core.Nodeid; |
20 import org.tmatesoft.hg.internal.ArrayHelper; | 20 import org.tmatesoft.hg.internal.IntMap; |
21 import org.tmatesoft.hg.repo.HgChangelog; | 21 import org.tmatesoft.hg.repo.HgChangelog; |
22 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; | |
22 import org.tmatesoft.hg.repo.HgDataFile; | 23 import org.tmatesoft.hg.repo.HgDataFile; |
23 import org.tmatesoft.hg.repo.HgLookup; | 24 import org.tmatesoft.hg.repo.HgLookup; |
24 import org.tmatesoft.hg.repo.HgManifest; | 25 import org.tmatesoft.hg.repo.HgManifest; |
26 import org.tmatesoft.hg.repo.HgManifest.Flags; | |
25 import org.tmatesoft.hg.repo.HgRepository; | 27 import org.tmatesoft.hg.repo.HgRepository; |
26 import org.tmatesoft.hg.repo.HgTags; | 28 import org.tmatesoft.hg.repo.HgTags; |
27 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; | |
28 import org.tmatesoft.hg.repo.HgManifest.Flags; | |
29 import org.tmatesoft.hg.repo.HgTags.TagInfo; | 29 import org.tmatesoft.hg.repo.HgTags.TagInfo; |
30 import org.tmatesoft.hg.util.CancelledException; | 30 import org.tmatesoft.hg.util.CancelledException; |
31 import org.tmatesoft.hg.util.Path; | 31 import org.tmatesoft.hg.util.Path; |
32 | 32 |
33 /** | 33 /** |
38 // Static ================================================================= | 38 // Static ================================================================= |
39 | 39 |
40 public static void main(String[] args) throws Exception { | 40 public static void main(String[] args) throws Exception { |
41 MapTagsToFileRevisions m = new MapTagsToFileRevisions(); | 41 MapTagsToFileRevisions m = new MapTagsToFileRevisions(); |
42 System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); | 42 System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); |
43 // m.collectTagsPerFile(); | 43 m.collectTagsPerFile(); |
44 // m.manifestWalk(); | 44 // m.manifestWalk(); |
45 // m.changelogWalk(); | 45 // m.changelogWalk(); |
46 // m.revisionMap(); | 46 // m.revisionMap(); |
47 m.buildFile2ChangelogRevisionMap(); | 47 // m.buildFile2ChangelogRevisionMap(); |
48 m = null; | 48 m = null; |
49 System.gc(); | 49 System.gc(); |
50 System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); | 50 System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); |
51 } | 51 } |
52 | 52 |
198 // 0..10k is 34 seconds now | 198 // 0..10k is 34 seconds now |
199 // Another run, 23 seconds now, seems nothing has been changed. Switched to Pool2 with DirectHashSet: 22,5 seconds | 199 // Another run, 23 seconds now, seems nothing has been changed. Switched to Pool2 with DirectHashSet: 22,5 seconds |
200 System.out.printf("Total time: %d ms\n", System.currentTimeMillis() - start); | 200 System.out.printf("Total time: %d ms\n", System.currentTimeMillis() - start); |
201 System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); | 201 System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); |
202 } | 202 } |
203 | 203 |
204 private void collectTagsPerFile() throws HgException, CancelledException { | 204 private int[] collectLocalTagRevisions(HgChangelog.RevisionMap clogrmap, TagInfo[] allTags, IntMap<List<TagInfo>> tagLocalRev2TagInfo) { |
205 final long start = System.currentTimeMillis(); | |
206 final HgRepository repository = new HgLookup().detect(new File("/temp/hg/cpython")); | |
207 final HgTags tags = repository.getTags(); | |
208 // | |
209 // build cache | |
210 // | |
211 final TagInfo[] allTags = new TagInfo[tags.getTags().size()]; | |
212 tags.getTags().values().toArray(allTags); | |
213 // file2rev2tag value is array of revisions, always of allTags.length. Revision index in the array | |
214 // is index of corresponding TagInfo in allTags; | |
215 final Map<Path, Nodeid[]> file2rev2tag = new HashMap<Path, Nodeid[]>(); | |
216 System.out.printf("Collecting manifests for %d tags\n", allTags.length); | |
217 // effective translation of changeset revisions to their local indexes | |
218 final HgChangelog.RevisionMap clogrmap = repository.getChangelog().new RevisionMap().init(); | |
219 int[] tagLocalRevs = new int[allTags.length]; | 205 int[] tagLocalRevs = new int[allTags.length]; |
220 int x = 0; | 206 int x = 0; |
221 for (int i = 0; i < allTags.length; i++) { | 207 for (int i = 0; i < allTags.length; i++) { |
222 final Nodeid tagRevision = allTags[i].revision(); | 208 final Nodeid tagRevision = allTags[i].revision(); |
223 final int tagLocalRev = clogrmap.localRevision(tagRevision); | 209 final int tagLocalRev = clogrmap.localRevision(tagRevision); |
224 if (tagLocalRev != HgRepository.BAD_REVISION) { | 210 if (tagLocalRev != HgRepository.BAD_REVISION) { |
225 tagLocalRevs[x++] = tagLocalRev; | 211 tagLocalRevs[x++] = tagLocalRev; |
212 List<TagInfo> tagsAssociatedWithRevision = tagLocalRev2TagInfo.get(tagLocalRev); | |
213 if (tagsAssociatedWithRevision == null) { | |
214 tagLocalRev2TagInfo.put(tagLocalRev, tagsAssociatedWithRevision = new LinkedList<TagInfo>()); | |
215 } | |
216 tagsAssociatedWithRevision.add(allTags[i]); | |
226 } | 217 } |
227 } | 218 } |
228 if (x != allTags.length) { | 219 if (x != allTags.length) { |
229 // some tags were removed (recorded Nodeid.NULL tagname) | 220 // some tags were removed (recorded Nodeid.NULL tagname) |
230 int[] copy = new int[x]; | 221 int[] copy = new int[x]; |
231 System.arraycopy(tagLocalRevs, 0, copy, 0, x); | 222 System.arraycopy(tagLocalRevs, 0, copy, 0, x); |
232 tagLocalRevs = copy; | 223 tagLocalRevs = copy; |
233 } | 224 } |
225 return tagLocalRevs; | |
226 } | |
227 | |
228 private void collectTagsPerFile() throws HgException, CancelledException { | |
229 final long start = System.currentTimeMillis(); | |
230 final HgRepository repository = new HgLookup().detect(new File("/temp/hg/cpython")); | |
231 final HgTags tags = repository.getTags(); | |
232 // | |
233 // build cache | |
234 // | |
235 final TagInfo[] allTags = new TagInfo[tags.getTags().size()]; | |
236 tags.getTags().values().toArray(allTags); | |
237 // effective translation of changeset revisions to their local indexes | |
238 final HgChangelog.RevisionMap clogrmap = repository.getChangelog().new RevisionMap().init(); | |
239 // map to look up tag by changeset local number | |
240 final IntMap<List<TagInfo>> tagLocalRev2TagInfo = new IntMap<List<TagInfo>>(allTags.length); | |
241 System.out.printf("Collecting manifests for %d tags\n", allTags.length); | |
242 final int[] tagLocalRevs = collectLocalTagRevisions(clogrmap, allTags, tagLocalRev2TagInfo); | |
234 System.out.printf("Prepared tag revisions to analyze: %d ms\n", System.currentTimeMillis() - start); | 243 System.out.printf("Prepared tag revisions to analyze: %d ms\n", System.currentTimeMillis() - start); |
235 // | 244 |
245 final Path targetPath = Path.create("README"); | |
246 // | |
247 collectTagsPerFile_Approach_1(clogrmap, tagLocalRevs, allTags, targetPath); | |
248 System.out.printf("Total time: %d ms\n", System.currentTimeMillis() - start); | |
249 | |
250 System.out.println("\nApproach 2"); | |
251 collectTagsPerFile_Approach_2(repository, tagLocalRevs, tagLocalRev2TagInfo, allTags, targetPath); | |
252 } | |
253 | |
254 // Approach 1. Build map with all files, their revisions and corresponding tags | |
255 // | |
256 private void collectTagsPerFile_Approach_1(final HgChangelog.RevisionMap clogrmap, final int[] tagLocalRevs, final TagInfo[] allTags, Path targetPath) { | |
257 HgRepository repository = clogrmap.getRepo(); | |
258 final long start = System.currentTimeMillis(); | |
259 // file2rev2tag value is array of revisions, always of allTags.length. Revision index in the array | |
260 // is index of corresponding TagInfo in allTags; | |
261 final Map<Path, Nodeid[]> file2rev2tag = new HashMap<Path, Nodeid[]>(); | |
236 repository.getManifest().walk(new HgManifest.Inspector2() { | 262 repository.getManifest().walk(new HgManifest.Inspector2() { |
237 private int[] tagIndexAtRev = new int[4]; // it's unlikely there would be a lot of tags associated with a given cset | 263 private int[] tagIndexAtRev = new int[4]; // it's unlikely there would be a lot of tags associated with a given cset |
238 | 264 |
239 public boolean begin(int mainfestRevision, Nodeid nid, int changelogRevision) { | 265 public boolean begin(int mainfestRevision, Nodeid nid, int changelogRevision) { |
266 // may do better here using tagLocalRev2TagInfo, but need to change a lot, too lazy now | |
240 Nodeid cset = clogrmap.revision(changelogRevision); | 267 Nodeid cset = clogrmap.revision(changelogRevision); |
241 Arrays.fill(tagIndexAtRev, -1); | 268 Arrays.fill(tagIndexAtRev, -1); |
242 for (int i = 0, x = 0; i < allTags.length; i++) { | 269 for (int i = 0, x = 0; i < allTags.length; i++) { |
243 if (cset.equals(allTags[i].revision())) { | 270 if (cset.equals(allTags[i].revision())) { |
244 tagIndexAtRev[x++] = i; | 271 tagIndexAtRev[x++] = i; |
284 | 311 |
285 }, tagLocalRevs); | 312 }, tagLocalRevs); |
286 System.out.printf("Cache built: %d ms\n", System.currentTimeMillis() - start); | 313 System.out.printf("Cache built: %d ms\n", System.currentTimeMillis() - start); |
287 // | 314 // |
288 // look up specific file. This part is fast. | 315 // look up specific file. This part is fast. |
289 final Path targetPath = Path.create("README"); | |
290 HgDataFile fileNode = repository.getFileNode(targetPath); | 316 HgDataFile fileNode = repository.getFileNode(targetPath); |
291 final Nodeid[] allTagsOfTheFile = file2rev2tag.get(targetPath); | 317 final Nodeid[] allTagsOfTheFile = file2rev2tag.get(targetPath); |
292 // TODO if fileNode.isCopy, repeat for each getCopySourceName() | 318 // TODO if fileNode.isCopy, repeat for each getCopySourceName() |
293 for (int localFileRev = 0; localFileRev < fileNode.getRevisionCount(); localFileRev++) { | 319 for (int localFileRev = 0; localFileRev < fileNode.getRevisionCount(); localFileRev++) { |
294 Nodeid fileRev = fileNode.getRevision(localFileRev); | 320 Nodeid fileRev = fileNode.getRevision(localFileRev); |
299 associatedTags.add(allTags[i].name()); | 325 associatedTags.add(allTags[i].name()); |
300 } | 326 } |
301 } | 327 } |
302 System.out.printf("%3d%7d%s\n", localFileRev, changesetLocalRev, associatedTags); | 328 System.out.printf("%3d%7d%s\n", localFileRev, changesetLocalRev, associatedTags); |
303 } | 329 } |
304 System.out.printf("Total time: %d ms\n", System.currentTimeMillis() - start); | 330 } |
331 | |
332 private void collectTagsPerFile_Approach_2(HgRepository repository, final int[] tagLocalRevs, final IntMap<List<TagInfo>> tagLocalRev2TagInfo, TagInfo[] allTags, Path targetPath) { | |
333 // | |
334 // Approach 2. No all-file map. Collect file revisions recorded at the time of tagging, | |
335 // then for each file revision check if it is among those above, and if yes, take corresponding tags | |
336 HgDataFile fileNode = repository.getFileNode(targetPath); | |
337 final long start2 = System.nanoTime(); | |
338 final int lastRev = fileNode.getLastRevision(); | |
339 final Map<Integer, Nodeid> fileRevisionAtTagRevision = repository.getManifest().getFileRevisions(targetPath, tagLocalRevs); | |
340 final long start2a = System.nanoTime(); | |
341 fileNode.walk(0, lastRev, new HgDataFile.RevisionInspector() { | |
342 | |
343 public void next(int localFileRev, Nodeid fileRevision, int linkedRevision) { | |
344 int changesetLocalRev = linkedRevision; | |
345 List<String> associatedTags = new LinkedList<String>(); | |
346 for (int taggetRevision : tagLocalRevs) { | |
347 // current file revision can't appear in tags that point to earlier changelog revisions (they got own file revision) | |
348 if (taggetRevision >= changesetLocalRev) { | |
349 // z points to some changeset with tag | |
350 Nodeid wasKnownAs = fileRevisionAtTagRevision.get(taggetRevision); | |
351 if (wasKnownAs.equals(fileRevision)) { | |
352 // has tag associated with changeset at index z | |
353 List<TagInfo> tagsAtRev = tagLocalRev2TagInfo.get(taggetRevision); | |
354 assert tagsAtRev != null; | |
355 for (TagInfo ti : tagsAtRev) { | |
356 associatedTags.add(ti.name()); | |
357 } | |
358 } | |
359 } | |
360 } | |
361 System.out.printf("%3d%7d%s\n", localFileRev, changesetLocalRev, associatedTags); | |
362 } | |
363 }); | |
364 System.out.printf("Alternative total time: %d ms, of that init: %d ms\n", (System.nanoTime() - start2)/1000000, (start2a-start2)/1000000); | |
305 System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); | 365 System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); |
306 } | 366 } |
307 | 367 |
308 public static void main2(String[] args) throws HgException, CancelledException { | 368 public static void main2(String[] args) throws HgException, CancelledException { |
309 final HgRepository repository = new HgLookup().detect(new File("/temp/hg/cpython")); | 369 final HgRepository repository = new HgLookup().detect(new File("/temp/hg/cpython")); |