Mercurial > jhg
comparison src/org/tmatesoft/hg/internal/FileRenameHistory.java @ 694:7efabe0cddcf
Speed up (a) file rename history to minimize file reads; (b) file.isCopy(int) to read metadata for few revisions at once (use pattern assumes earlier revisions are likely to be queried, too); (c) HgIgnore.isIgnored by caching matched initial fragments (to substitute more expensive Matcher.matches with cheaper HashMap.contains)
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Mon, 05 Aug 2013 17:42:10 +0200 |
parents | 72fc7774b87e |
children |
comparison
equal
deleted
inserted
replaced
693:32b0d19e8aba | 694:7efabe0cddcf |
---|---|
14 * the terms of a license other than GNU General Public License | 14 * the terms of a license other than GNU General Public License |
15 * contact TMate Software at support@hg4j.com | 15 * contact TMate Software at support@hg4j.com |
16 */ | 16 */ |
17 package org.tmatesoft.hg.internal; | 17 package org.tmatesoft.hg.internal; |
18 | 18 |
19 import static org.tmatesoft.hg.repo.HgRepository.BAD_REVISION; | |
20 | |
19 import java.util.ArrayList; | 21 import java.util.ArrayList; |
22 import java.util.Arrays; | |
20 import java.util.Collections; | 23 import java.util.Collections; |
21 import java.util.LinkedList; | 24 import java.util.LinkedList; |
22 import java.util.List; | 25 import java.util.List; |
23 | 26 |
24 import org.tmatesoft.hg.core.HgFileRevision; | 27 import org.tmatesoft.hg.core.HgFileRevision; |
25 import org.tmatesoft.hg.core.HgIterateDirection; | 28 import org.tmatesoft.hg.core.HgIterateDirection; |
26 import org.tmatesoft.hg.repo.HgDataFile; | 29 import org.tmatesoft.hg.repo.HgDataFile; |
30 import org.tmatesoft.hg.repo.HgRepository; | |
31 import org.tmatesoft.hg.repo.HgRuntimeException; | |
27 | 32 |
28 /** | 33 /** |
29 * Traces file renames. Quite similar to HgChangesetFileSneaker, although the latter tries different paths | 34 * Traces file renames. Quite similar to HgChangesetFileSneaker, although the latter tries different paths |
30 * to find origin names, while this class traces first renames found only. | 35 * to find origin names, while this class traces first renames found only. |
31 * | 36 * |
59 public void build(HgDataFile df, int fileRev) { | 64 public void build(HgDataFile df, int fileRev) { |
60 assert !isOutOfRange(df, fileRev); | 65 assert !isOutOfRange(df, fileRev); |
61 LinkedList<Chunk> chunks = new LinkedList<Chunk>(); | 66 LinkedList<Chunk> chunks = new LinkedList<Chunk>(); |
62 int chunkStart = 0, chunkEnd = fileRev; | 67 int chunkStart = 0, chunkEnd = fileRev; |
63 int csetChunkEnd = -1, csetChunkStart = -1; | 68 int csetChunkEnd = -1, csetChunkStart = -1; |
69 BasicRevMap csetMap = new BasicRevMap(0, fileRev).collect(df); | |
64 while (fileRev >= 0) { | 70 while (fileRev >= 0) { |
65 int cset = df.getChangesetRevisionIndex(fileRev); | 71 int cset = csetMap.changesetAt(fileRev); |
66 if (csetChunkEnd == -1) { | 72 if (csetChunkEnd == -1) { |
67 csetChunkEnd = cset; | 73 csetChunkEnd = cset; |
68 } | 74 } |
69 if (cset <= csetFrom) { | 75 if (cset <= csetFrom) { |
70 chunkStart = fileRev; | 76 chunkStart = fileRev; |
80 if (df.isCopy(fileRev)) { | 86 if (df.isCopy(fileRev)) { |
81 chunks.addFirst(new Chunk(df, fileRev, chunkEnd, csetChunkStart, csetChunkEnd)); | 87 chunks.addFirst(new Chunk(df, fileRev, chunkEnd, csetChunkStart, csetChunkEnd)); |
82 HgFileRevision origin = df.getCopySource(fileRev); | 88 HgFileRevision origin = df.getCopySource(fileRev); |
83 df = df.getRepo().getFileNode(origin.getPath()); | 89 df = df.getRepo().getFileNode(origin.getPath()); |
84 fileRev = chunkEnd = df.getRevisionIndex(origin.getRevision()); | 90 fileRev = chunkEnd = df.getRevisionIndex(origin.getRevision()); |
91 csetMap = new BasicRevMap(0, fileRev).collect(df); | |
85 chunkStart = 0; | 92 chunkStart = 0; |
86 csetChunkEnd = cset - 1; // if df is copy, cset can't be 0 | 93 csetChunkEnd = cset - 1; // if df is copy, cset can't be 0 |
87 csetChunkStart = -1; | 94 csetChunkStart = -1; |
88 } else { | 95 } else { |
89 fileRev--; | 96 fileRev--; |
128 | 135 |
129 | 136 |
130 /** | 137 /** |
131 * file has changes [firstFileRev..lastFileRev] that have occurred somewhere in [firstCset..lastCset] | 138 * file has changes [firstFileRev..lastFileRev] that have occurred somewhere in [firstCset..lastCset] |
132 */ | 139 */ |
133 public static class Chunk { | 140 public static final class Chunk { |
134 private final HgDataFile df; | 141 private final HgDataFile df; |
135 private final int fileRevFrom; | 142 private final int fileRevFrom; |
136 private final int fileRevTo; | 143 private final int fileRevTo; |
137 private final int csetFrom; | 144 private final int csetFrom; |
138 private final int csetTo; | 145 private final int csetTo; |
157 } | 164 } |
158 public int lastCset() { | 165 public int lastCset() { |
159 return csetTo; | 166 return csetTo; |
160 } | 167 } |
161 } | 168 } |
169 | |
170 private static final class BasicRevMap implements HgDataFile.LinkRevisionInspector { | |
171 private final int[] revs; | |
172 private final int fromRev; | |
173 private final int toRev; | |
174 public BasicRevMap(int startRev, int endRev) { | |
175 revs = new int[endRev+1]; // for simplicity, just ignore startRev now (it's 0 in local use anyway) | |
176 fromRev = startRev; | |
177 toRev = endRev; | |
178 Arrays.fill(revs, BAD_REVISION); | |
179 } | |
180 | |
181 public BasicRevMap collect(HgDataFile df) { | |
182 df.indexWalk(fromRev, toRev, this); | |
183 return this; | |
184 } | |
185 | |
186 public void next(int revisionIndex, int linkedRevisionIndex) throws HgRuntimeException { | |
187 revs[revisionIndex] = linkedRevisionIndex; | |
188 } | |
189 | |
190 /** | |
191 * @return {@link HgRepository#BAD_REVISION} if there's no mapping | |
192 */ | |
193 public int changesetAt(int rev) { | |
194 return revs[rev]; | |
195 } | |
196 } | |
162 } | 197 } |