comparison src/org/tmatesoft/hg/repo/HgManifest.java @ 598:d29d9dc6c128

Utilize the fact nodeids are very different and are read anyway to speed up reverse lookup
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 03 May 2013 15:19:18 +0200
parents c895b5556937
children 46f29b73e51e
comparison
equal deleted inserted replaced
597:c895b5556937 598:d29d9dc6c128
575 private static class RevisionMapper implements RevlogStream.Inspector, Lifecycle { 575 private static class RevisionMapper implements RevlogStream.Inspector, Lifecycle {
576 576
577 private final int changelogRevisionCount; 577 private final int changelogRevisionCount;
578 private int[] changelog2manifest; 578 private int[] changelog2manifest;
579 private final HgRepository repo; 579 private final HgRepository repo;
580 private int[] manifestNodeidHashes; // first 4 bytes of manifest nodeid at corresponding index
580 581
581 public RevisionMapper(HgRepository hgRepo) { 582 public RevisionMapper(HgRepository hgRepo) {
582 repo = hgRepo; 583 repo = hgRepo;
583 changelogRevisionCount = repo.getChangelog().getRevisionCount(); 584 changelogRevisionCount = repo.getChangelog().getRevisionCount();
584 } 585 }
617 for (int i = 0; i < revisionNumber; changelog2manifest[i] = i, i++) 618 for (int i = 0; i < revisionNumber; changelog2manifest[i] = i, i++)
618 ; 619 ;
619 changelog2manifest[linkRevision] = revisionNumber; 620 changelog2manifest[linkRevision] = revisionNumber;
620 } 621 }
621 } 622 }
623 manifestNodeidHashes[revisionNumber] = Nodeid.hashCode(nodeid);
622 } 624 }
623 625
624 public void start(int count, Callback callback, Object token) { 626 public void start(int count, Callback callback, Object token) {
625 if (count != changelogRevisionCount) { 627 if (count != changelogRevisionCount) {
626 assert count < changelogRevisionCount; // no idea what to do if manifest has more revisions than changelog 628 assert count < changelogRevisionCount; // no idea what to do if manifest has more revisions than changelog
629 // Note, it's pure guess, I didn't see such repository yet (although the way manifest revisions 631 // Note, it's pure guess, I didn't see such repository yet (although the way manifest revisions
630 // in cpython repo are numbered makes me think aforementioned way) 632 // in cpython repo are numbered makes me think aforementioned way)
631 changelog2manifest = new int[changelogRevisionCount]; 633 changelog2manifest = new int[changelogRevisionCount];
632 Arrays.fill(changelog2manifest, BAD_REVISION); 634 Arrays.fill(changelog2manifest, BAD_REVISION);
633 } 635 }
636 manifestNodeidHashes = new int[count];
634 } 637 }
635 638
636 public void finish(Object token) { 639 public void finish(Object token) {
637 if (changelog2manifest == null) { 640 if (changelog2manifest == null) {
638 return; 641 return;
643 if (changelog2manifest[i] == BAD_REVISION) { 646 if (changelog2manifest[i] == BAD_REVISION) {
644 undefinedChangelogRevision.add(i); 647 undefinedChangelogRevision.add(i);
645 } 648 }
646 } 649 }
647 if (undefinedChangelogRevision.size() > 0) { 650 if (undefinedChangelogRevision.size() > 0) {
651 final long t1 = System.nanoTime();
648 final IntMap<Nodeid> missingCsetToManifest = new IntMap<Nodeid>(undefinedChangelogRevision.size()); 652 final IntMap<Nodeid> missingCsetToManifest = new IntMap<Nodeid>(undefinedChangelogRevision.size());
649 int[] undefinedClogRevs = undefinedChangelogRevision.toArray(); 653 int[] undefinedClogRevs = undefinedChangelogRevision.toArray();
650 // undefinedChangelogRevision is sorted by the nature it's created 654 // undefinedChangelogRevision is sorted by the nature it's created
651 repo.getChangelog().rangeInternal(new HgChangelog.Inspector() { 655 repo.getChangelog().rangeInternal(new HgChangelog.Inspector() {
652 656
653 public void next(int revisionIndex, Nodeid nodeid, RawChangeset cset) { 657 public void next(int revisionIndex, Nodeid nodeid, RawChangeset cset) {
654 missingCsetToManifest.put(revisionIndex, cset.manifest()); 658 missingCsetToManifest.put(revisionIndex, cset.manifest());
655 } 659 }
656 }, undefinedClogRevs); 660 }, undefinedClogRevs);
657 assert missingCsetToManifest.size() == undefinedChangelogRevision.size(); 661 assert missingCsetToManifest.size() == undefinedChangelogRevision.size();
662 final long t2 = System.nanoTime();
658 for (int u : undefinedClogRevs) { 663 for (int u : undefinedClogRevs) {
659 Nodeid manifest = missingCsetToManifest.get(u); 664 Nodeid manifest = missingCsetToManifest.get(u);
660 // TODO calculate those missing effectively (e.g. cache and sort nodeids to speed lookup
661 // right away in the #next (may refactor ParentWalker's sequential and sorted into dedicated helper and reuse here)
662 if (manifest == null || manifest.isNull()) { 665 if (manifest == null || manifest.isNull()) {
663 repo.getSessionContext().getLog().dump(getClass(), Severity.Warn, "Changeset %d has no associated manifest entry", u); 666 repo.getSessionContext().getLog().dump(getClass(), Severity.Warn, "Changeset %d has no associated manifest entry", u);
664 // keep -1 in the changelog2manifest map. 667 // keep -1 in the changelog2manifest map.
665 } else { 668 continue;
666 changelog2manifest[u] = repo.getManifest().getRevisionIndex(manifest);
667 } 669 }
668 } 670 int hash = manifest.hashCode();
669 } 671 for (int i = 0; i < manifestNodeidHashes.length; i++) {
672 if (manifestNodeidHashes[i] == hash) {
673 if (manifest.equals(repo.getManifest().getRevision(i))) {
674 changelog2manifest[u] = i;
675 break;
676 }
677 // else false match (only 4 head bytes matched, continue loop
678 }
679 }
680 }
681 final long t3 = System.nanoTime();
682 System.out.printf("\tRevisionMapper#finish(), %d missing revs: %d + %d us\n", undefinedChangelogRevision.size(), (t2-t1) / 1000, (t3-t2) / 1000);
683 }
684 manifestNodeidHashes = null;
670 } 685 }
671 } 686 }
672 687
673 /** 688 /**
674 * Look up specified file in possibly multiple manifest revisions, collect file revision and flags. 689 * Look up specified file in possibly multiple manifest revisions, collect file revision and flags.