comparison src/org/tmatesoft/hg/repo/HgDataFile.java @ 242:ad6a046943be

Improved reading of sparse revisions from a revlog
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Thu, 23 Jun 2011 15:19:07 +0200
parents 29231022fec8
children 2fb439375ddc
comparison
equal deleted inserted replaced
241:d3ab16739736 242:ad6a046943be
222 end = last; 222 end = last;
223 } else if (end < start || end > last) { 223 } else if (end < start || end > last) {
224 throw new IllegalArgumentException(); 224 throw new IllegalArgumentException();
225 } 225 }
226 final int[] commitRevisions = new int[end - start + 1]; 226 final int[] commitRevisions = new int[end - start + 1];
227 final boolean[] needsSorting = { false };
227 RevlogStream.Inspector insp = new RevlogStream.Inspector() { 228 RevlogStream.Inspector insp = new RevlogStream.Inspector() {
228 int count = 0; 229 int count = 0;
229
230 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { 230 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) {
231 if (count > 0) {
232 if (commitRevisions[count -1] > linkRevision) {
233 needsSorting[0] = true;
234 }
235 }
231 commitRevisions[count++] = linkRevision; 236 commitRevisions[count++] = linkRevision;
232 } 237 }
233 }; 238 };
234 content.iterate(start, end, false, insp); 239 content.iterate(start, end, false, insp);
235 final HgChangelog changelog = getRepo().getChangelog(); 240 final HgChangelog changelog = getRepo().getChangelog();
236 /* 241 if (needsSorting[0]) {
237 * changelog.range(inspector, commitRevisions); 242 // automatic tools (svnmerge?) produce unnatural file history
238 * Not effective when changes are sparse and far from each other. 243 // (e.g. cpython/Lib/doctest.py, revision 164 points to cset 63509, 165 - to 38453)
239 * However, it's only single file read, unlike code below (few reads of sequential blocks) 244 Arrays.sort(commitRevisions);
240 * Need to weight tradeoffs of file read and iteration of sparse files. 245 }
241 */ 246 changelog.range(inspector, commitRevisions);
242
243 //
244 final int HistoricallyCloseCommits = 50; // XXX perhaps, shall increase/decrease based on changelog.revisionCount()
245 // (huge changelog => memory mapped files, each file re-read is more expensive than iterating over records in one read?
246 //
247 // try short sequences on neighboring revisions.
248 Arrays.sort(commitRevisions); // automatic tools (svnmerge?) produce unnatural file history
249 // (e.g. cpython/Lib/doctest.py, revision 164 points to 63509, 165 - to 38453)
250 for (int i = 0; i < commitRevisions.length; ) {
251 int x = i;
252 i++;
253 boolean sequential = true;
254 while (i < commitRevisions.length) {
255 if (commitRevisions[i] == commitRevisions[i-1] + 1) {
256 i++;
257 } else if (commitRevisions[i] - commitRevisions[i-1] < HistoricallyCloseCommits) {
258 // close enough, but not sequential
259 sequential = false;
260 i++;
261 } else {
262 break;
263 }
264 }
265 if (sequential) {
266 // commitRevisions[x..i-1] are sequential
267 changelog.range(commitRevisions[x], commitRevisions[i-1], inspector);
268 } else {
269 int[] revs = new int[i-x];
270 System.arraycopy(commitRevisions, x, revs, 0, i-x);
271 changelog.range(inspector, revs);
272 }
273 }
274 } 247 }
275 248
276 // for a given local revision of the file, find out local revision in the changelog 249 // for a given local revision of the file, find out local revision in the changelog
277 public int getChangesetLocalRevision(int revision) { 250 public int getChangesetLocalRevision(int revision) {
278 return content.linkRevision(revision); 251 return content.linkRevision(revision);