Mercurial > hg4j
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 } |
