tikhomirov@254: package org.tmatesoft.hg.test; tikhomirov@254: tikhomirov@324: import static org.tmatesoft.hg.repo.HgRepository.TIP; tikhomirov@324: tikhomirov@255: import java.io.File; tikhomirov@255: import java.util.ArrayList; tikhomirov@256: import java.util.Arrays; tikhomirov@255: import java.util.HashMap; tikhomirov@255: import java.util.LinkedList; tikhomirov@255: import java.util.List; tikhomirov@255: import java.util.Map; tikhomirov@254: tikhomirov@324: import org.junit.Assert; tikhomirov@423: import org.tmatesoft.hg.core.HgCallbackTargetException; tikhomirov@255: import org.tmatesoft.hg.core.HgChangeset; tikhomirov@255: import org.tmatesoft.hg.core.HgChangesetHandler; tikhomirov@255: import org.tmatesoft.hg.core.HgException; tikhomirov@255: import org.tmatesoft.hg.core.HgLogCommand; tikhomirov@255: import org.tmatesoft.hg.core.Nodeid; tikhomirov@326: import org.tmatesoft.hg.internal.IntMap; tikhomirov@255: import org.tmatesoft.hg.repo.HgChangelog; tikhomirov@326: import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; tikhomirov@255: import org.tmatesoft.hg.repo.HgDataFile; tikhomirov@255: import org.tmatesoft.hg.repo.HgLookup; tikhomirov@255: import org.tmatesoft.hg.repo.HgManifest; tikhomirov@326: import org.tmatesoft.hg.repo.HgManifest.Flags; tikhomirov@255: import org.tmatesoft.hg.repo.HgRepository; tikhomirov@255: import org.tmatesoft.hg.repo.HgTags; tikhomirov@254: import org.tmatesoft.hg.repo.HgTags.TagInfo; tikhomirov@255: import org.tmatesoft.hg.util.CancelledException; tikhomirov@255: import org.tmatesoft.hg.util.Path; tikhomirov@254: tikhomirov@254: /** tikhomirov@254: * @author Marc Strapetz tikhomirov@254: */ tikhomirov@254: public class MapTagsToFileRevisions { tikhomirov@254: tikhomirov@254: // Static ================================================================= tikhomirov@254: tikhomirov@255: public static void main(String[] args) throws Exception { tikhomirov@255: MapTagsToFileRevisions m = new MapTagsToFileRevisions(); tikhomirov@255: System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); tikhomirov@329: m.measurePatchAffectsArbitraryRevisionRead(); tikhomirov@329: // m.collectTagsPerFile(); tikhomirov@307: // m.manifestWalk(); tikhomirov@307: // m.changelogWalk(); tikhomirov@324: // m.revisionMap(); tikhomirov@326: // m.buildFile2ChangelogRevisionMap(); tikhomirov@255: m = null; tikhomirov@255: System.gc(); tikhomirov@255: System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); tikhomirov@255: } tikhomirov@324: tikhomirov@329: tikhomirov@329: // revision == 2406 - 5 ms per run (baseRevision == 2406) tikhomirov@329: // revision == 2405 - 69 ms per run (baseRevision == 1403) tikhomirov@329: private void measurePatchAffectsArbitraryRevisionRead() throws Exception { tikhomirov@329: final HgRepository repository = new HgLookup().detect(new File("/temp/hg/cpython")); tikhomirov@329: final DoNothingManifestInspector insp = new DoNothingManifestInspector(); tikhomirov@329: final int revision = 2405; tikhomirov@329: // warm-up. tikhomirov@329: repository.getManifest().walk(revision, revision, insp); tikhomirov@329: final int runs = 10; tikhomirov@329: final long start = System.nanoTime(); tikhomirov@329: for (int i = 0; i < runs; i++) { tikhomirov@329: repository.getManifest().walk(revision, revision, insp); tikhomirov@329: } tikhomirov@329: final long end = System.nanoTime(); tikhomirov@329: System.out.printf("%d ms per run\n", (end - start)/ (runs*1000000)); tikhomirov@329: } tikhomirov@329: tikhomirov@324: /* tikhomirov@324: * .hgtags, 261 revisions tikhomirov@324: * Approach 1: total 83, init: 0, iteration: 82 tikhomirov@324: * Approach 2: total 225, init: 206, iteration: 19 tikhomirov@324: * README, 465 revisions tikhomirov@324: * Approach 1: total 162, init: 0, iteration: 161 tikhomirov@324: * Approach 2: total 231, init: 198, iteration: 32 tikhomirov@324: * configure.in, 1109 revisions tikhomirov@324: * Approach 1: total 409, init: 1, iteration: 407 tikhomirov@324: * Approach 2: total 277, init: 203, iteration: 74 tikhomirov@324: */ tikhomirov@324: private void buildFile2ChangelogRevisionMap() throws Exception { tikhomirov@324: final HgRepository repository = new HgLookup().detect(new File("/temp/hg/cpython")); tikhomirov@324: final HgChangelog clog = repository.getChangelog(); tikhomirov@324: final HgDataFile fileNode = repository.getFileNode("configure.in"); tikhomirov@324: // warm-up tikhomirov@324: HgChangelog.RevisionMap clogMap = clog.new RevisionMap().init(); tikhomirov@324: HgDataFile.RevisionMap fileMap = fileNode.new RevisionMap().init(); tikhomirov@324: // tikhomirov@324: final int latestRevision = fileNode.getLastRevision(); tikhomirov@324: // tikhomirov@324: final long start_1 = System.nanoTime(); tikhomirov@324: fileMap = fileNode.new RevisionMap().init(); tikhomirov@324: final long start_1a = System.nanoTime(); tikhomirov@324: final Map changesetToNodeid_1 = new HashMap(); tikhomirov@324: for (int revision = 0; revision <= latestRevision; revision++) { tikhomirov@324: final Nodeid nodeId = fileMap.revision(revision); tikhomirov@324: // final Nodeid changesetId = fileNode.getChangesetRevision(nodeId); tikhomirov@367: int localCset = fileNode.getChangesetRevisionIndex(revision); tikhomirov@324: final Nodeid changesetId = clog.getRevision(localCset); tikhomirov@324: changesetToNodeid_1.put(changesetId, nodeId); tikhomirov@324: } tikhomirov@324: final long end_1 = System.nanoTime(); tikhomirov@324: // tikhomirov@324: final long start_2 = System.nanoTime(); tikhomirov@324: clogMap = clog.new RevisionMap().init(); tikhomirov@324: fileMap = fileNode.new RevisionMap().init(); tikhomirov@324: final Map changesetToNodeid_2 = new HashMap(); tikhomirov@324: final long start_2a = System.nanoTime(); tikhomirov@324: for (int revision = 0; revision <= latestRevision; revision++) { tikhomirov@324: Nodeid nidFile = fileMap.revision(revision); tikhomirov@367: int localCset = fileNode.getChangesetRevisionIndex(revision); tikhomirov@324: Nodeid nidCset = clogMap.revision(localCset); tikhomirov@324: changesetToNodeid_2.put(nidCset, nidFile); tikhomirov@324: } tikhomirov@324: final long end_2 = System.nanoTime(); tikhomirov@324: Assert.assertEquals(changesetToNodeid_1, changesetToNodeid_2); tikhomirov@324: // tikhomirov@324: final long start_3 = System.nanoTime(); tikhomirov@324: final Map changesetToNodeid_3 = new HashMap(); tikhomirov@324: fileNode.walk(0, TIP, new HgDataFile.RevisionInspector() { tikhomirov@324: tikhomirov@368: public void next(int fileRevisionIndex, Nodeid revision, int linkedRevisionIndex) { tikhomirov@423: changesetToNodeid_3.put(clog.getRevision(linkedRevisionIndex), revision); tikhomirov@324: } tikhomirov@324: }); tikhomirov@324: final long end_3 = System.nanoTime(); tikhomirov@324: Assert.assertEquals(changesetToNodeid_1, changesetToNodeid_3); tikhomirov@324: System.out.printf("Approach 1: total %d, init: %d, iteration: %d\n", (end_1 - start_1)/1000000, (start_1a - start_1)/1000000, (end_1 - start_1a)/1000000); tikhomirov@324: System.out.printf("Approach 2: total %d, init: %d, iteration: %d\n", (end_2 - start_2)/1000000, (start_2a - start_2)/1000000, (end_2 - start_2a)/1000000); tikhomirov@324: System.out.printf("Approach 3: total %d\n", (end_3 - start_3)/1000000); tikhomirov@324: } tikhomirov@263: tikhomirov@307: /* tikhomirov@307: * Each 5000 revisions from cpython, total 15 revisions tikhomirov@367: * Direct clog.getRevisionIndex: ~260 ms tikhomirov@367: * RevisionMap.revisionIndex: ~265 ms (almost 100% in #init()) tikhomirov@307: * each 1000'th revision, total 71 revision: 1 230 vs 270 tikhomirov@307: * each 2000'th revision, total 36 revision: 620 vs 270 tikhomirov@307: * each 3000'th revision, total 24 revision: 410 vs 275 tikhomirov@307: */ tikhomirov@307: private void revisionMap() throws Exception { tikhomirov@307: final HgRepository repository = new HgLookup().detect(new File("/temp/hg/cpython")); tikhomirov@307: final HgChangelog clog = repository.getChangelog(); tikhomirov@307: ArrayList revisions = new ArrayList(); tikhomirov@307: final int step = 5000; tikhomirov@307: for (int i = 0, top = clog.getLastRevision(); i < top; i += step) { tikhomirov@307: revisions.add(clog.getRevision(i)); tikhomirov@307: } tikhomirov@307: final long s1 = System.nanoTime(); tikhomirov@307: for (Nodeid n : revisions) { tikhomirov@367: int r = clog.getRevisionIndex(n); tikhomirov@307: if (r % step != 0) { tikhomirov@307: throw new IllegalStateException(Integer.toString(r)); tikhomirov@307: } tikhomirov@307: } tikhomirov@307: System.out.printf("Direct lookup of %d revisions took %,d ns\n", revisions.size(), System.nanoTime() - s1); tikhomirov@307: HgChangelog.RevisionMap rmap = clog.new RevisionMap(); tikhomirov@307: final long s2 = System.nanoTime(); tikhomirov@307: rmap.init(); tikhomirov@307: final long s3 = System.nanoTime(); tikhomirov@307: for (Nodeid n : revisions) { tikhomirov@367: int r = rmap.revisionIndex(n); tikhomirov@307: if (r % step != 0) { tikhomirov@307: throw new IllegalStateException(Integer.toString(r)); tikhomirov@307: } tikhomirov@307: } tikhomirov@307: System.out.printf("RevisionMap time: %d ms, of that init() %,d ns\n", (System.nanoTime() - s2) / 1000000, s3 - s2); tikhomirov@307: } tikhomirov@307: tikhomirov@263: private void changelogWalk() throws Exception { tikhomirov@307: final HgRepository repository = new HgLookup().detect(new File("/temp/hg/cpython")); tikhomirov@263: final long start = System.currentTimeMillis(); tikhomirov@263: repository.getChangelog().all(new HgChangelog.Inspector() { tikhomirov@263: public int xx = 0; tikhomirov@263: tikhomirov@263: public void next(int revisionNumber, Nodeid nodeid, RawChangeset cset) { tikhomirov@263: if (xx+revisionNumber < 0) { tikhomirov@263: System.out.println(xx); tikhomirov@263: System.out.println(revisionNumber); tikhomirov@263: } tikhomirov@263: xx += revisionNumber; tikhomirov@263: } tikhomirov@263: }); tikhomirov@263: // cpython: 17 seconds, mem 132,9 -> 129,0 -> 131,7 tikhomirov@263: // cpyhton: 13 seconds. Of that, cumulative Patch.apply takes 8.8 seconds, RevlogStream.Inspector.next - 1.8 tikhomirov@263: System.out.printf("Total time: %d ms\n", System.currentTimeMillis() - start); tikhomirov@263: System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); tikhomirov@263: } tikhomirov@263: tikhomirov@263: private void manifestWalk() throws Exception { tikhomirov@268: System.out.println(System.getProperty("java.version")); tikhomirov@263: final long start = System.currentTimeMillis(); tikhomirov@263: final HgRepository repository = new HgLookup().detect(new File("/temp/hg/cpython")); tikhomirov@329: repository.getManifest().walk(0, 10000, new DoNothingManifestInspector()); tikhomirov@263: // cpython: 1,1 sec for 0..1000, 43 sec for 0..10000, 115 sec for 0..20000 (Pool with HashMap) tikhomirov@263: // 2,4 sec for 1000..2000 tikhomirov@263: // cpython -r 1000: 484 files, -r 2000: 1015 files. Iteration 1000..2000; fnamePool.size:1019 nodeidPool.size:2989 tikhomirov@263: // nodeidPool for two subsequent revisions only: 840. 37 sec for 0..10000. 99 sec for 0..20k tikhomirov@263: // 0..10000 fnamePool: hits:15989152, misses:3020 tikhomirov@268: // tikhomirov@268: // With Pool for fname and flags, Nodeid's ascii2bin through local array, overall byte[] iteration, tikhomirov@268: // 0..10k is 34 seconds now tikhomirov@304: // Another run, 23 seconds now, seems nothing has been changed. Switched to Pool2 with DirectHashSet: 22,5 seconds tikhomirov@263: System.out.printf("Total time: %d ms\n", System.currentTimeMillis() - start); tikhomirov@263: System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); tikhomirov@263: } tikhomirov@326: tikhomirov@326: private int[] collectLocalTagRevisions(HgChangelog.RevisionMap clogrmap, TagInfo[] allTags, IntMap> tagLocalRev2TagInfo) { tikhomirov@326: int[] tagLocalRevs = new int[allTags.length]; tikhomirov@326: int x = 0; tikhomirov@326: for (int i = 0; i < allTags.length; i++) { tikhomirov@326: final Nodeid tagRevision = allTags[i].revision(); tikhomirov@368: final int tagRevisionIndex = clogrmap.revisionIndex(tagRevision); tikhomirov@368: if (tagRevisionIndex != HgRepository.BAD_REVISION) { tikhomirov@368: tagLocalRevs[x++] = tagRevisionIndex; tikhomirov@368: List tagsAssociatedWithRevision = tagLocalRev2TagInfo.get(tagRevisionIndex); tikhomirov@326: if (tagsAssociatedWithRevision == null) { tikhomirov@368: tagLocalRev2TagInfo.put(tagRevisionIndex, tagsAssociatedWithRevision = new LinkedList()); tikhomirov@326: } tikhomirov@326: tagsAssociatedWithRevision.add(allTags[i]); tikhomirov@326: } tikhomirov@326: } tikhomirov@326: if (x != allTags.length) { tikhomirov@326: // some tags were removed (recorded Nodeid.NULL tagname) tikhomirov@326: int[] copy = new int[x]; tikhomirov@326: System.arraycopy(tagLocalRevs, 0, copy, 0, x); tikhomirov@326: tagLocalRevs = copy; tikhomirov@326: } tikhomirov@326: return tagLocalRevs; tikhomirov@326: } tikhomirov@263: tikhomirov@263: private void collectTagsPerFile() throws HgException, CancelledException { tikhomirov@254: final long start = System.currentTimeMillis(); tikhomirov@254: final HgRepository repository = new HgLookup().detect(new File("/temp/hg/cpython")); tikhomirov@254: final HgTags tags = repository.getTags(); tikhomirov@254: // tikhomirov@254: // build cache tikhomirov@255: // tikhomirov@423: final TagInfo[] allTags = new TagInfo[tags.getAllTags().size()]; tikhomirov@423: tags.getAllTags().values().toArray(allTags); tikhomirov@326: // effective translation of changeset revisions to their local indexes tikhomirov@326: final HgChangelog.RevisionMap clogrmap = repository.getChangelog().new RevisionMap().init(); tikhomirov@326: // map to look up tag by changeset local number tikhomirov@326: final IntMap> tagLocalRev2TagInfo = new IntMap>(allTags.length); tikhomirov@326: System.out.printf("Collecting manifests for %d tags\n", allTags.length); tikhomirov@326: final int[] tagLocalRevs = collectLocalTagRevisions(clogrmap, allTags, tagLocalRev2TagInfo); tikhomirov@329: System.out.printf("Prepared %d tag revisions to analyze: %d ms\n", tagLocalRevs.length, System.currentTimeMillis() - start); tikhomirov@326: tikhomirov@326: final Path targetPath = Path.create("README"); tikhomirov@326: // tikhomirov@326: collectTagsPerFile_Approach_1(clogrmap, tagLocalRevs, allTags, targetPath); tikhomirov@326: System.out.printf("Total time: %d ms\n", System.currentTimeMillis() - start); tikhomirov@326: tikhomirov@326: System.out.println("\nApproach 2"); tikhomirov@326: collectTagsPerFile_Approach_2(repository, tagLocalRevs, tagLocalRev2TagInfo, allTags, targetPath); tikhomirov@326: } tikhomirov@326: tikhomirov@326: // Approach 1. Build map with all files, their revisions and corresponding tags tikhomirov@326: // tikhomirov@354: private void collectTagsPerFile_Approach_1(final HgChangelog.RevisionMap clogrmap, final int[] tagLocalRevs, final TagInfo[] allTags, Path targetPath) throws HgException { tikhomirov@326: HgRepository repository = clogrmap.getRepo(); tikhomirov@326: final long start = System.currentTimeMillis(); tikhomirov@255: // file2rev2tag value is array of revisions, always of allTags.length. Revision index in the array tikhomirov@255: // is index of corresponding TagInfo in allTags; tikhomirov@285: final Map file2rev2tag = new HashMap(); tikhomirov@424: repository.getManifest().walk(new HgManifest.Inspector() { tikhomirov@256: private int[] tagIndexAtRev = new int[4]; // it's unlikely there would be a lot of tags associated with a given cset tikhomirov@254: tikhomirov@254: public boolean begin(int mainfestRevision, Nodeid nid, int changelogRevision) { tikhomirov@326: // may do better here using tagLocalRev2TagInfo, but need to change a lot, too lazy now tikhomirov@254: Nodeid cset = clogrmap.revision(changelogRevision); tikhomirov@256: Arrays.fill(tagIndexAtRev, -1); tikhomirov@256: for (int i = 0, x = 0; i < allTags.length; i++) { tikhomirov@255: if (cset.equals(allTags[i].revision())) { tikhomirov@256: tagIndexAtRev[x++] = i; tikhomirov@256: if (x == tagIndexAtRev.length) { tikhomirov@256: // expand twice as much tikhomirov@256: int[] expanded = new int[x << 1]; tikhomirov@256: System.arraycopy(tagIndexAtRev, 0, expanded, 0, x); tikhomirov@256: expanded[x] = -1; // just in case there'd be no more tags associated with this cset tikhomirov@256: tagIndexAtRev = expanded; tikhomirov@256: } tikhomirov@255: } tikhomirov@255: } tikhomirov@256: if (tagIndexAtRev[0] == -1) { tikhomirov@254: System.out.println("Can't happen, provided we iterate over revisions with tags only"); tikhomirov@254: } tikhomirov@254: return true; tikhomirov@254: } tikhomirov@285: tikhomirov@285: public boolean next(Nodeid nid, Path fname, HgManifest.Flags flags) { tikhomirov@255: Nodeid[] m = file2rev2tag.get(fname); tikhomirov@254: if (m == null) { tikhomirov@255: file2rev2tag.put(fname, m = new Nodeid[allTags.length]); tikhomirov@254: } tikhomirov@255: for (int tagIndex : tagIndexAtRev) { tikhomirov@256: if (tagIndex == -1) { tikhomirov@256: break; tikhomirov@256: } tikhomirov@255: if (m[tagIndex] != null) { tikhomirov@255: System.out.printf("There's another revision (%s) associated with tag %s already while we try to associate %s\n", m[tagIndex].shortNotation(), allTags[tagIndex].name(), nid.shortNotation()); tikhomirov@255: } tikhomirov@255: m[tagIndex] = nid; tikhomirov@254: } tikhomirov@254: return true; tikhomirov@254: } tikhomirov@254: tikhomirov@254: public boolean end(int manifestRevision) { tikhomirov@254: return true; tikhomirov@254: } tikhomirov@254: tikhomirov@254: }, tagLocalRevs); tikhomirov@255: System.out.printf("Cache built: %d ms\n", System.currentTimeMillis() - start); tikhomirov@254: // tikhomirov@254: // look up specific file. This part is fast. tikhomirov@254: HgDataFile fileNode = repository.getFileNode(targetPath); tikhomirov@285: final Nodeid[] allTagsOfTheFile = file2rev2tag.get(targetPath); tikhomirov@254: // TODO if fileNode.isCopy, repeat for each getCopySourceName() tikhomirov@368: for (int fileRevIndex = 0; fileRevIndex < fileNode.getRevisionCount(); fileRevIndex++) { tikhomirov@368: Nodeid fileRev = fileNode.getRevision(fileRevIndex); tikhomirov@368: int changesetRevIndex = fileNode.getChangesetRevisionIndex(fileRevIndex); tikhomirov@254: List associatedTags = new LinkedList(); tikhomirov@255: for (int i = 0; i < allTagsOfTheFile.length; i++) { tikhomirov@255: if (fileRev.equals(allTagsOfTheFile[i])) { tikhomirov@255: associatedTags.add(allTags[i].name()); tikhomirov@254: } tikhomirov@254: } tikhomirov@368: System.out.printf("%3d%7d%s\n", fileRevIndex, changesetRevIndex, associatedTags); tikhomirov@254: } tikhomirov@326: } tikhomirov@326: tikhomirov@366: private void collectTagsPerFile_Approach_2(HgRepository repository, final int[] tagLocalRevs, final IntMap> tagLocalRev2TagInfo, TagInfo[] allTags, Path targetPath) throws HgException { tikhomirov@326: // tikhomirov@326: // Approach 2. No all-file map. Collect file revisions recorded at the time of tagging, tikhomirov@326: // then for each file revision check if it is among those above, and if yes, take corresponding tags tikhomirov@326: HgDataFile fileNode = repository.getFileNode(targetPath); tikhomirov@326: final long start2 = System.nanoTime(); tikhomirov@326: final int lastRev = fileNode.getLastRevision(); tikhomirov@426: final Map fileRevisionAtTagRevision = new HashMap(); tikhomirov@426: HgManifest.Inspector collectFileRevAtCset = new HgManifest.Inspector() { tikhomirov@426: tikhomirov@426: private int csetRevIndex; tikhomirov@426: tikhomirov@426: public boolean next(Nodeid nid, Path fname, Flags flags) { tikhomirov@426: fileRevisionAtTagRevision.put(csetRevIndex, nid); tikhomirov@426: return true; tikhomirov@426: } tikhomirov@426: tikhomirov@426: public boolean end(int manifestRevision) { tikhomirov@426: return true; tikhomirov@426: } tikhomirov@426: tikhomirov@426: public boolean begin(int mainfestRevision, Nodeid nid, int changelogRevision) { tikhomirov@426: csetRevIndex = changelogRevision; tikhomirov@426: return true; tikhomirov@426: } tikhomirov@426: }; tikhomirov@426: repository.getManifest().walkFileRevisions(targetPath, collectFileRevAtCset,tagLocalRevs); tikhomirov@426: tikhomirov@326: final long start2a = System.nanoTime(); tikhomirov@326: fileNode.walk(0, lastRev, new HgDataFile.RevisionInspector() { tikhomirov@326: tikhomirov@368: public void next(int fileRevisionIndex, Nodeid fileRevision, int changesetRevisionIndex) { tikhomirov@326: List associatedTags = new LinkedList(); tikhomirov@326: for (int taggetRevision : tagLocalRevs) { tikhomirov@326: // current file revision can't appear in tags that point to earlier changelog revisions (they got own file revision) tikhomirov@368: if (taggetRevision >= changesetRevisionIndex) { tikhomirov@326: // z points to some changeset with tag tikhomirov@326: Nodeid wasKnownAs = fileRevisionAtTagRevision.get(taggetRevision); tikhomirov@326: if (wasKnownAs.equals(fileRevision)) { tikhomirov@326: // has tag associated with changeset at index z tikhomirov@326: List tagsAtRev = tagLocalRev2TagInfo.get(taggetRevision); tikhomirov@326: assert tagsAtRev != null; tikhomirov@326: for (TagInfo ti : tagsAtRev) { tikhomirov@326: associatedTags.add(ti.name()); tikhomirov@326: } tikhomirov@326: } tikhomirov@326: } tikhomirov@326: } tikhomirov@368: System.out.printf("%3d%7d%s\n", fileRevisionIndex, changesetRevisionIndex, associatedTags); tikhomirov@326: } tikhomirov@326: }); tikhomirov@326: System.out.printf("Alternative total time: %d ms, of that init: %d ms\n", (System.nanoTime() - start2)/1000000, (start2a-start2)/1000000); tikhomirov@255: System.out.printf("Free mem: %,d\n", Runtime.getRuntime().freeMemory()); tikhomirov@254: } tikhomirov@254: tikhomirov@424: static class DoNothingManifestInspector implements HgManifest.Inspector { tikhomirov@329: public boolean begin(int mainfestRevision, Nodeid nid, int changelogRevision) { tikhomirov@329: return true; tikhomirov@329: } tikhomirov@329: public boolean next(Nodeid nid, Path fname, Flags flags) { tikhomirov@329: return true; tikhomirov@329: } tikhomirov@329: public boolean end(int manifestRevision) { tikhomirov@329: return true; tikhomirov@329: } tikhomirov@329: } tikhomirov@329: tikhomirov@423: public static void main2(String[] args) throws HgCallbackTargetException, HgException, CancelledException { tikhomirov@254: final HgRepository repository = new HgLookup().detect(new File("/temp/hg/cpython")); tikhomirov@254: final Path targetPath = Path.create("README"); tikhomirov@254: final HgTags tags = repository.getTags(); tikhomirov@423: final Map tagToInfo = tags.getAllTags(); tikhomirov@254: final HgManifest manifest = repository.getManifest(); tikhomirov@254: final Map> changeSetRevisionToTags = new HashMap>(); tikhomirov@254: final HgDataFile fileNode = repository.getFileNode(targetPath); tikhomirov@254: for (String tagName : tagToInfo.keySet()) { tikhomirov@254: final HgTags.TagInfo info = tagToInfo.get(tagName); tikhomirov@254: final Nodeid nodeId = info.revision(); tikhomirov@254: // TODO: This is not correct as we can't be sure that file at the corresponding revision is actually our target file (which may have been renamed, etc.) tikhomirov@367: final Nodeid fileRevision = manifest.getFileRevision(repository.getChangelog().getRevisionIndex(nodeId), targetPath); tikhomirov@254: if (fileRevision == null) { tikhomirov@254: continue; tikhomirov@254: } tikhomirov@254: tikhomirov@254: final Nodeid changeSetRevision = fileNode.getChangesetRevision(fileRevision); tikhomirov@254: List revisionTags = changeSetRevisionToTags.get(changeSetRevision); tikhomirov@254: if (revisionTags == null) { tikhomirov@254: revisionTags = new ArrayList(); tikhomirov@254: changeSetRevisionToTags.put(changeSetRevision, revisionTags); tikhomirov@254: } tikhomirov@254: revisionTags.add(tagName); tikhomirov@254: } tikhomirov@254: tikhomirov@254: final HgLogCommand logCommand = new HgLogCommand(repository); tikhomirov@254: logCommand.file(targetPath, true); tikhomirov@254: logCommand.execute(new HgChangesetHandler() { tikhomirov@254: public void next(HgChangeset changeset) { tikhomirov@254: if (changeset.getAffectedFiles().contains(targetPath)) { tikhomirov@423: System.out.println(changeset.getRevisionIndex() + " " + changeSetRevisionToTags.get(changeset.getNodeid())); tikhomirov@254: } tikhomirov@254: } tikhomirov@254: }); tikhomirov@254: } tikhomirov@254: }