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 }