Mercurial > jhg
comparison src/org/tmatesoft/hg/repo/Revlog.java @ 695:053bb4397bf9
Refactoring: nice Revlog.indexWalk() implementation
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Mon, 05 Aug 2013 18:45:16 +0200 |
| parents | 7efabe0cddcf |
| children |
comparison
equal
deleted
inserted
replaced
| 694:7efabe0cddcf | 695:053bb4397bf9 |
|---|---|
| 29 import org.tmatesoft.hg.internal.DataAccess; | 29 import org.tmatesoft.hg.internal.DataAccess; |
| 30 import org.tmatesoft.hg.internal.Experimental; | 30 import org.tmatesoft.hg.internal.Experimental; |
| 31 import org.tmatesoft.hg.internal.IntMap; | 31 import org.tmatesoft.hg.internal.IntMap; |
| 32 import org.tmatesoft.hg.internal.Preview; | 32 import org.tmatesoft.hg.internal.Preview; |
| 33 import org.tmatesoft.hg.internal.RevisionLookup; | 33 import org.tmatesoft.hg.internal.RevisionLookup; |
| 34 import org.tmatesoft.hg.internal.RevlogDelegate; | |
| 34 import org.tmatesoft.hg.internal.RevlogStream; | 35 import org.tmatesoft.hg.internal.RevlogStream; |
| 35 import org.tmatesoft.hg.util.Adaptable; | 36 import org.tmatesoft.hg.util.Adaptable; |
| 36 import org.tmatesoft.hg.util.ByteChannel; | 37 import org.tmatesoft.hg.util.ByteChannel; |
| 37 import org.tmatesoft.hg.util.CancelSupport; | 38 import org.tmatesoft.hg.util.CancelSupport; |
| 38 import org.tmatesoft.hg.util.CancelledException; | 39 import org.tmatesoft.hg.util.CancelledException; |
| 350 end = lastRev; | 351 end = lastRev; |
| 351 } | 352 } |
| 352 final RevisionInspector revisionInsp = Adaptable.Factory.getAdapter(inspector, RevisionInspector.class, null); | 353 final RevisionInspector revisionInsp = Adaptable.Factory.getAdapter(inspector, RevisionInspector.class, null); |
| 353 final ParentInspector parentInsp = Adaptable.Factory.getAdapter(inspector, ParentInspector.class, null); | 354 final ParentInspector parentInsp = Adaptable.Factory.getAdapter(inspector, ParentInspector.class, null); |
| 354 final LinkRevisionInspector linkRevInspector = Adaptable.Factory.getAdapter(inspector, LinkRevisionInspector.class, null); | 355 final LinkRevisionInspector linkRevInspector = Adaptable.Factory.getAdapter(inspector, LinkRevisionInspector.class, null); |
| 355 final Nodeid[] allRevisions = parentInsp == null ? null : new Nodeid[end - _start + 1]; | 356 |
| 356 // next are to build set of parent indexes that are not part of the range iteration | 357 // instantiate implementors in reverse order |
| 357 // i.e. those parents we need to read separately. See Issue 31 for details. | 358 RevlogDelegate head = parentInsp == null ? null : new ParentDelegate(parentInsp, null, _start, end); |
| 358 final int[] firstParentIndexes = parentInsp == null || _start == 0 ? null : new int[allRevisions.length]; | 359 if (revisionInsp != null) { |
| 359 final int[] secondParentIndexes = parentInsp == null || _start == 0 ? null : new int[allRevisions.length]; | 360 head = new RevisionDelegate(revisionInsp, head); |
| 360 final IntMap<Nodeid> missingParents = parentInsp == null || _start == 0 ? null : new IntMap<Nodeid>(16); | 361 } |
| 361 | 362 if (linkRevInspector != null) { |
| 362 content.iterate(_start, end, false, new RevlogStream.Inspector() { | 363 head = new LinkRevDelegate(linkRevInspector, head); |
| 363 private int i = 0; | 364 } |
| 364 | 365 // first to get notified is created last |
| 365 public void next(int revisionIndex, int actualLen, int baseRevIndex, int linkRevIndex, int parent1RevIndex, int parent2RevIndex, byte[] nodeid, DataAccess data) throws HgRuntimeException { | 366 |
| 366 // FIXME refactor either as chain of RevlogStream.Inspector or an external AnyOf() runner not to keep everything | 367 assert head != null; // we know all subclasses of Revlog.Inspector |
| 367 // in a single method | 368 head.walk(getRepo(), content, _start, end); |
| 368 if (linkRevInspector != null) { | 369 } |
| 369 linkRevInspector.next(revisionIndex, linkRevIndex); | 370 |
| 370 if (parentInsp == null && revisionInsp == null) { | |
| 371 return; | |
| 372 } | |
| 373 } | |
| 374 Nodeid nid = Nodeid.fromBinary(nodeid, 0); | |
| 375 if (revisionInsp != null) { | |
| 376 revisionInsp.next(revisionIndex, nid, linkRevIndex); | |
| 377 } | |
| 378 if (parentInsp != null) { | |
| 379 allRevisions[i] = nid; | |
| 380 if (_start > 0) { | |
| 381 // there are chances we don't know parents here, | |
| 382 // postpone parent dispatching for later, now just collect what's missing | |
| 383 firstParentIndexes[i] = parent1RevIndex; | |
| 384 secondParentIndexes[i] = parent2RevIndex; | |
| 385 if (parent1RevIndex < _start && parent1RevIndex >= 0) { | |
| 386 missingParents.put(parent1RevIndex, null); | |
| 387 } | |
| 388 if (parent2RevIndex < _start && parent2RevIndex >= 0) { | |
| 389 missingParents.put(parent2RevIndex, null); | |
| 390 } | |
| 391 } else { | |
| 392 // we iterate from the very beginning, got every index we'll need | |
| 393 Nodeid p1 = parent1RevIndex == -1 ? Nodeid.NULL : allRevisions[parent1RevIndex]; | |
| 394 Nodeid p2 = parent2RevIndex == -1 ? Nodeid.NULL : allRevisions[parent2RevIndex]; | |
| 395 parentInsp.next(revisionIndex, allRevisions[i], parent1RevIndex, parent2RevIndex, p1, p2); | |
| 396 } | |
| 397 i++; | |
| 398 } | |
| 399 } | |
| 400 }); | |
| 401 if (parentInsp != null && _start > 0 ) { | |
| 402 if (missingParents.size() > 0) { | |
| 403 // it's possible to get empty missingParents when _start > 0 e.g. when n-th file revision | |
| 404 // is a copy of another file and hence got -1,-1 parents in this revlog, and we indexWalk(n,n) | |
| 405 for (int k = missingParents.firstKey(), l = missingParents.lastKey(); k <= l; k++) { | |
| 406 // TODO [post-1.1] int[] IntMap#keys() or even sort of iterator that can modify values | |
| 407 if (missingParents.containsKey(k)) { | |
| 408 Nodeid nid = getRepo().getChangelog().getRevision(k); | |
| 409 missingParents.put(k, nid); | |
| 410 } | |
| 411 } | |
| 412 } | |
| 413 | |
| 414 for (int i = 0, revNum = _start; i < allRevisions.length; i++, revNum++) { | |
| 415 int riP1 = firstParentIndexes[i]; | |
| 416 int riP2 = secondParentIndexes[i]; | |
| 417 Nodeid p1, p2; | |
| 418 p1 = p2 = Nodeid.NULL; | |
| 419 if (riP1 >= _start) { | |
| 420 // p1 of revNum's revision is out of iterated range | |
| 421 // (don't check for riP1<end as I assume parents come prior to children in the changelog) | |
| 422 p1 = allRevisions[riP1 - start]; | |
| 423 } else if (riP1 != -1) { | |
| 424 assert riP1 >=0 && riP1 < _start; | |
| 425 p1 = missingParents.get(riP1); | |
| 426 assert p1 != null; | |
| 427 } | |
| 428 // same for Pp2 | |
| 429 if (riP2 >= _start) { | |
| 430 p2 = allRevisions[riP2 - start]; | |
| 431 } else if (riP2 != -1) { | |
| 432 assert riP2 >= 0 && riP2 < _start; | |
| 433 p2 = missingParents.get(riP2); | |
| 434 assert p2 != null; | |
| 435 } | |
| 436 parentInsp.next(revNum, allRevisions[i], riP1, riP2, p1, p2); | |
| 437 } | |
| 438 } | |
| 439 } | |
| 440 | |
| 441 /** | 371 /** |
| 442 * MARKER | 372 * MARKER |
| 443 */ | 373 */ |
| 444 @Experimental | 374 @Experimental |
| 445 public interface Inspector { | 375 public interface Inspector { |
| 575 } catch (CancelledException ex) { | 505 } catch (CancelledException ex) { |
| 576 recordFailure(ex); | 506 recordFailure(ex); |
| 577 } | 507 } |
| 578 } | 508 } |
| 579 } | 509 } |
| 510 | |
| 511 | |
| 512 private static final class LinkRevDelegate extends RevlogDelegate { | |
| 513 private final LinkRevisionInspector insp; | |
| 514 | |
| 515 public LinkRevDelegate(LinkRevisionInspector inspector, RevlogDelegate next) { | |
| 516 super(next); | |
| 517 assert inspector != null; | |
| 518 insp = inspector; | |
| 519 } | |
| 520 @Override | |
| 521 public void next(int revisionIndex, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) throws HgRuntimeException { | |
| 522 insp.next(revisionIndex, linkRevision); | |
| 523 super.next(revisionIndex, actualLen, baseRevision, linkRevision, parent1Revision, parent2Revision, nodeid, data); | |
| 524 } | |
| 525 } | |
| 526 | |
| 527 private static final class RevisionDelegate extends RevlogDelegate { | |
| 528 private final RevisionInspector insp; | |
| 529 public RevisionDelegate(RevisionInspector inspector, RevlogDelegate next) { | |
| 530 super(next); | |
| 531 assert inspector != null; | |
| 532 insp = inspector; | |
| 533 } | |
| 534 @Override | |
| 535 public void next(int revisionIndex, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) throws HgRuntimeException { | |
| 536 Nodeid nid = getRevision(nodeid); | |
| 537 insp.next(revisionIndex, nid, linkRevision); | |
| 538 super.next(revisionIndex, actualLen, baseRevision, linkRevision, parent1Revision, parent2Revision, nodeid, data); | |
| 539 } | |
| 540 } | |
| 541 | |
| 542 private static class ParentDelegate extends RevlogDelegate { | |
| 543 private final ParentInspector insp; | |
| 544 private int i = 0; | |
| 545 private final Nodeid[] allRevisions; | |
| 546 // next are to build set of parent indexes that are not part of the range iteration | |
| 547 // i.e. those parents we need to read separately. See Issue 31 for details. | |
| 548 private final int[] firstParentIndexes; | |
| 549 private final int[] secondParentIndexes; | |
| 550 private final IntMap<Nodeid> missingParents; | |
| 551 private final int start; | |
| 552 | |
| 553 public ParentDelegate(ParentInspector inspector, RevlogDelegate next, int _start, int end) { | |
| 554 super(next); | |
| 555 insp = inspector; | |
| 556 start = _start; | |
| 557 allRevisions = new Nodeid[end - _start + 1]; | |
| 558 firstParentIndexes = _start == 0 ? null : new int[allRevisions.length]; | |
| 559 secondParentIndexes = _start == 0 ? null : new int[allRevisions.length]; | |
| 560 missingParents = _start == 0 ? null : new IntMap<Nodeid>(16); | |
| 561 } | |
| 562 @Override | |
| 563 public void next(int revisionIndex, int actualLen, int baseRevision, int linkRevision, int parent1RevIndex, int parent2RevIndex, byte[] nodeid, DataAccess data) throws HgRuntimeException { | |
| 564 allRevisions[i] = getRevision(nodeid); | |
| 565 if (start > 0) { | |
| 566 // there are chances we don't know parents here, | |
| 567 // postpone parent dispatching for later, now just collect what's missing | |
| 568 firstParentIndexes[i] = parent1RevIndex; | |
| 569 secondParentIndexes[i] = parent2RevIndex; | |
| 570 if (parent1RevIndex < start && parent1RevIndex >= 0) { | |
| 571 missingParents.put(parent1RevIndex, null); | |
| 572 } | |
| 573 if (parent2RevIndex < start && parent2RevIndex >= 0) { | |
| 574 missingParents.put(parent2RevIndex, null); | |
| 575 } | |
| 576 } else { | |
| 577 // we iterate from the very beginning, got every index we'll need | |
| 578 Nodeid p1 = parent1RevIndex == -1 ? Nodeid.NULL : allRevisions[parent1RevIndex]; | |
| 579 Nodeid p2 = parent2RevIndex == -1 ? Nodeid.NULL : allRevisions[parent2RevIndex]; | |
| 580 insp.next(revisionIndex, allRevisions[i], parent1RevIndex, parent2RevIndex, p1, p2); | |
| 581 } | |
| 582 i++; | |
| 583 super.next(revisionIndex, actualLen, baseRevision, linkRevision, parent1RevIndex, parent2RevIndex, nodeid, data); | |
| 584 } | |
| 585 | |
| 586 @Override | |
| 587 protected void postWalk(HgRepository hgRepo) { | |
| 588 if (start > 0) { | |
| 589 complete(hgRepo); | |
| 590 } | |
| 591 super.postWalk(hgRepo); | |
| 592 } | |
| 593 | |
| 594 private void complete(HgRepository repo) { | |
| 595 if (missingParents.size() > 0) { | |
| 596 // it's possible to get empty missingParents when _start > 0 e.g. when n-th file revision | |
| 597 // is a copy of another file and hence got -1,-1 parents in this revlog, and we indexWalk(n,n) | |
| 598 for (int k = missingParents.firstKey(), l = missingParents.lastKey(); k <= l; k++) { | |
| 599 // TODO [post-1.1] int[] IntMap#keys() or even sort of iterator that can modify values | |
| 600 if (missingParents.containsKey(k)) { | |
| 601 Nodeid nid = repo.getChangelog().getRevision(k); | |
| 602 missingParents.put(k, nid); | |
| 603 } | |
| 604 } | |
| 605 } | |
| 606 | |
| 607 for (int i = 0, revNum = start; i < allRevisions.length; i++, revNum++) { | |
| 608 int riP1 = firstParentIndexes[i]; | |
| 609 int riP2 = secondParentIndexes[i]; | |
| 610 Nodeid p1, p2; | |
| 611 p1 = p2 = Nodeid.NULL; | |
| 612 if (riP1 >= start) { | |
| 613 // p1 of revNum's revision is out of iterated range | |
| 614 // (don't check for riP1<end as I assume parents come prior to children in the changelog) | |
| 615 p1 = allRevisions[riP1 - start]; | |
| 616 } else if (riP1 != -1) { | |
| 617 assert riP1 >=0 && riP1 < start; | |
| 618 p1 = missingParents.get(riP1); | |
| 619 assert p1 != null; | |
| 620 } | |
| 621 // same for Pp2 | |
| 622 if (riP2 >= start) { | |
| 623 p2 = allRevisions[riP2 - start]; | |
| 624 } else if (riP2 != -1) { | |
| 625 assert riP2 >= 0 && riP2 < start; | |
| 626 p2 = missingParents.get(riP2); | |
| 627 assert p2 != null; | |
| 628 } | |
| 629 insp.next(revNum, allRevisions[i], riP1, riP2, p1, p2); | |
| 630 } | |
| 631 } | |
| 632 } | |
| 580 } | 633 } |
