Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/HgDataFile.java @ 317:09628675bcee
Rework file history build approach to match rest of the API
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 29 Sep 2011 03:20:28 +0200 |
parents | 971baa95fb07 |
children | d68dcb3b5f49 |
comparison
equal
deleted
inserted
replaced
316:ee6b467c1a5f | 317:09628675bcee |
---|---|
28 import java.util.ArrayList; | 28 import java.util.ArrayList; |
29 import java.util.Arrays; | 29 import java.util.Arrays; |
30 import java.util.Collection; | 30 import java.util.Collection; |
31 import java.util.Collections; | 31 import java.util.Collections; |
32 import java.util.List; | 32 import java.util.List; |
33 import java.util.NoSuchElementException; | |
34 | 33 |
35 import org.tmatesoft.hg.core.HgDataStreamException; | 34 import org.tmatesoft.hg.core.HgDataStreamException; |
36 import org.tmatesoft.hg.core.HgException; | 35 import org.tmatesoft.hg.core.HgException; |
37 import org.tmatesoft.hg.core.Nodeid; | 36 import org.tmatesoft.hg.core.Nodeid; |
38 import org.tmatesoft.hg.internal.DataAccess; | 37 import org.tmatesoft.hg.internal.DataAccess; |
39 import org.tmatesoft.hg.internal.Experimental; | |
40 import org.tmatesoft.hg.internal.FilterByteChannel; | 38 import org.tmatesoft.hg.internal.FilterByteChannel; |
41 import org.tmatesoft.hg.internal.FilterDataAccess; | 39 import org.tmatesoft.hg.internal.FilterDataAccess; |
42 import org.tmatesoft.hg.internal.IntMap; | 40 import org.tmatesoft.hg.internal.IntMap; |
43 import org.tmatesoft.hg.internal.RevlogStream; | 41 import org.tmatesoft.hg.internal.RevlogStream; |
44 import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; | |
45 import org.tmatesoft.hg.util.ByteChannel; | 42 import org.tmatesoft.hg.util.ByteChannel; |
46 import org.tmatesoft.hg.util.CancelSupport; | 43 import org.tmatesoft.hg.util.CancelSupport; |
47 import org.tmatesoft.hg.util.CancelledException; | 44 import org.tmatesoft.hg.util.CancelledException; |
48 import org.tmatesoft.hg.util.Pair; | 45 import org.tmatesoft.hg.util.Pair; |
49 import org.tmatesoft.hg.util.Path; | 46 import org.tmatesoft.hg.util.Path; |
229 // shall not happen, unless we changed ContentPipe or its subclass | 226 // shall not happen, unless we changed ContentPipe or its subclass |
230 throw new HgDataStreamException(getPath(), ex.getClass().getName(), ex); | 227 throw new HgDataStreamException(getPath(), ex.getClass().getName(), ex); |
231 } | 228 } |
232 } | 229 } |
233 | 230 |
234 @Experimental(reason="Investigate approaches to build complete file history log") | 231 private static class HistoryNode { |
235 public interface HistoryWalker { | 232 int changeset; |
236 void next(); | 233 Nodeid cset; |
237 boolean hasNext(); | 234 HistoryNode parent1, parent2; |
238 Nodeid changesetRevision(); | 235 List<HistoryNode> children; |
239 RawChangeset changeset(); | 236 |
240 boolean isFork(); | 237 HistoryNode(int cs, HistoryNode p1, HistoryNode p2) { |
241 boolean isJoin(); | 238 changeset = cs; |
242 Pair<Nodeid, Nodeid> parentChangesets(); | 239 parent1 = p1; |
243 Collection<Nodeid> childChangesets(); | 240 parent2 = p2; |
244 } | 241 if (p1 != null) { |
245 | 242 p1.addChild(this); |
246 public HistoryWalker history() { | 243 } |
247 final boolean[] needsSorting = { false }; | 244 if (p2 != null) { |
248 class HistoryNode { | 245 p2.addChild(this); |
249 int changeset; | 246 } |
250 Nodeid cset; | 247 } |
251 HistoryNode parent1, parent2; | 248 |
252 List<HistoryNode> children; | 249 Nodeid changesetRevision() { |
253 | 250 assert cset != null : "we initialize all csets prior to use"; |
254 public HistoryNode(int cs, HistoryNode p1, HistoryNode p2) { | 251 return cset; |
255 changeset = cs; | 252 } |
256 parent1 = p1; | 253 |
257 parent2 = p2; | 254 void addChild(HistoryNode child) { |
258 if (p1 != null) { | 255 if (children == null) { |
259 p1.addChild(this); | 256 children = new ArrayList<HistoryNode>(2); |
260 } | 257 } |
261 if (p2 != null) { | 258 children.add(child); |
262 p2.addChild(this); | 259 } |
263 } | 260 } |
264 } | 261 |
265 | 262 public void history(HgChangelog.TreeInspector inspector) { |
266 public Nodeid changesetRevision() { | 263 final CancelSupport cancelSupport = CancelSupport.Factory.get(inspector); |
267 if (cset == null) { | 264 try { |
268 cset = getRepo().getChangelog().getRevision(changeset); | 265 final boolean[] needsSorting = { false }; |
269 } | 266 final HistoryNode[] completeHistory = new HistoryNode[getRevisionCount()]; |
270 return cset; | 267 final int[] commitRevisions = new int[completeHistory.length]; |
271 } | 268 RevlogStream.Inspector insp = new RevlogStream.Inspector() { |
272 | 269 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { |
273 public void addChild(HistoryNode child) { | 270 if (revisionNumber > 0) { |
274 if (children == null) { | 271 if (commitRevisions[revisionNumber-1] > linkRevision) { |
275 children = new ArrayList<HistoryNode>(2); | 272 needsSorting[0] = true; |
276 } | 273 } |
277 children.add(child); | 274 } |
278 } | 275 commitRevisions[revisionNumber] = linkRevision; |
279 } | 276 HistoryNode p1 = null, p2 = null; |
280 final HistoryNode[] completeHistory = new HistoryNode[getRevisionCount()]; | 277 if (parent1Revision != -1) { |
281 final int[] commitRevisions = new int[completeHistory.length]; | 278 p1 = completeHistory[parent1Revision]; |
282 RevlogStream.Inspector insp = new RevlogStream.Inspector() { | 279 } |
283 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { | 280 if (parent2Revision != -1) { |
284 if (revisionNumber > 0) { | 281 p2 = completeHistory[parent2Revision]; |
285 if (commitRevisions[revisionNumber-1] > linkRevision) { | 282 } |
286 needsSorting[0] = true; | 283 completeHistory[revisionNumber] = new HistoryNode(linkRevision, p1, p2); |
287 } | 284 } |
288 } | 285 }; |
289 HistoryNode p1 = null, p2 = null; | 286 content.iterate(0, getLastRevision(), false, insp); |
290 if (parent1Revision != -1) { | 287 cancelSupport.checkCancelled(); |
291 p1 = completeHistory[parent1Revision]; | 288 if (needsSorting[0]) { |
292 } | 289 Arrays.sort(commitRevisions); |
293 if (parent2Revision != -1) { | 290 } |
294 p2 = completeHistory[parent2Revision]; | 291 // read changeset revisions at once (to avoid numerous changelog.getRevision reads) |
295 } | 292 // but just nodeids, not RawChangeset (changelog.iterate(data=false) |
296 completeHistory[revisionNumber] = new HistoryNode(linkRevision, p1, p2); | 293 ArrayList<Nodeid> changesetRevisions = new ArrayList<Nodeid>(commitRevisions.length); |
297 } | 294 getRepo().getChangelog().getRevisionsInternal(changesetRevisions, commitRevisions); |
298 }; | 295 cancelSupport.checkCancelled(); |
299 content.iterate(0, getLastRevision(), false, insp); | 296 // assign them to corresponding HistoryNodes |
300 // XXX may read changeset revisions at once (to avoid numerous changelog.getRevision reads) | 297 for (int i = 0; i < completeHistory.length; i++ ) { |
301 // but perhaps just nodeids, not RawChangeset (changelog.iterate(data=false) | 298 final HistoryNode n = completeHistory[i]; |
302 // XXX sort completeHistory according to changeset numbers? | 299 if (needsSorting[0]) { |
303 return new HistoryWalker() { | 300 int x = Arrays.binarySearch(commitRevisions, n.changeset); |
304 private int index = -1; | 301 assert x >= 0; |
305 | 302 n.cset = changesetRevisions.get(x); |
306 public void next() { | 303 } else { |
307 if (!hasNext()) { | 304 // commit revisions were not sorted, may use original index directly |
308 throw new NoSuchElementException(); | 305 n.cset = changesetRevisions.get(i); |
309 } | 306 } |
310 index++; | 307 } |
311 } | 308 cancelSupport.checkCancelled(); |
312 | 309 // XXX shall sort completeHistory according to changeset numbers? |
313 public boolean hasNext() { | 310 for (int i = 0; i < completeHistory.length; i++ ) { |
314 return index+1 < completeHistory.length; | 311 final HistoryNode n = completeHistory[i]; |
315 } | |
316 | |
317 public Pair<Nodeid, Nodeid> parentChangesets() { | |
318 HistoryNode p; | 312 HistoryNode p; |
319 Nodeid p1, p2; | 313 Nodeid p1, p2; |
320 if ((p = completeHistory[index].parent1) != null) { | 314 if ((p = n.parent1) != null) { |
321 p1 = p.changesetRevision(); | 315 p1 = p.changesetRevision(); |
322 } else { | 316 } else { |
323 p1 = Nodeid.NULL; | 317 p1 = Nodeid.NULL; |
324 } | 318 } |
325 if ((p = completeHistory[index].parent2) != null) { | 319 if ((p= n.parent2) != null) { |
326 p2 = p.changesetRevision(); | 320 p2 = p.changesetRevision(); |
327 } else { | 321 } else { |
328 p2 = Nodeid.NULL; | 322 p2 = Nodeid.NULL; |
329 } | 323 } |
330 return new Pair<Nodeid, Nodeid>(p1, p2); | 324 final Pair<Nodeid, Nodeid> parentChangesets = new Pair<Nodeid, Nodeid>(p1, p2); |
331 } | 325 final List<Nodeid> childChangesets; |
332 | |
333 public boolean isJoin() { | |
334 return completeHistory[index].parent1 != null && completeHistory[index].parent2 != null; | |
335 } | |
336 | |
337 public boolean isFork() { | |
338 HistoryNode n = completeHistory[index]; | |
339 return n.children != null && n.children.size() > 1; | |
340 } | |
341 | |
342 public Collection<Nodeid> childChangesets() { | |
343 HistoryNode n = completeHistory[index]; | |
344 if (n.children == null) { | 326 if (n.children == null) { |
345 return Collections.emptyList(); | 327 childChangesets = Collections.emptyList(); |
346 } | 328 } else { |
347 ArrayList<Nodeid> rv = new ArrayList<Nodeid>(n.children.size()); | 329 Nodeid[] revisions = new Nodeid[n.children.size()]; |
348 for (HistoryNode hn : n.children) { | 330 int j = 0; |
349 rv.add(hn.changesetRevision()); | 331 for (HistoryNode hn : n.children) { |
350 } | 332 revisions[j++] = hn.changesetRevision(); |
351 return rv; | 333 } |
352 } | 334 childChangesets = Arrays.asList(revisions); |
353 | 335 } |
354 public Nodeid changesetRevision() { | 336 inspector.next(n.changesetRevision(), parentChangesets, childChangesets); |
355 return completeHistory[index].changesetRevision(); | 337 cancelSupport.checkCancelled(); |
356 } | 338 } |
357 | 339 } catch (CancelledException ex) { |
358 public RawChangeset changeset() { | 340 return; |
359 final int cs = completeHistory[index].changeset; | 341 } |
360 return getRepo().getChangelog().range(cs, cs).get(0); | |
361 } | |
362 }; | |
363 } | 342 } |
364 | 343 |
365 public void history(HgChangelog.Inspector inspector) { | 344 public void history(HgChangelog.Inspector inspector) { |
366 history(0, getLastRevision(), inspector); | 345 history(0, getLastRevision(), inspector); |
367 } | 346 } |