Mercurial > hg4j
diff src/org/tmatesoft/hg/repo/Revlog.java @ 243:0e01f9182e16
External cache Nodeid<->int added, Revlog.RevisionMap
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 23 Jun 2011 16:58:38 +0200 |
parents | 047b1dec7a04 |
children | 9fb50c04f03c |
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/repo/Revlog.java Thu Jun 23 15:19:07 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/Revlog.java Thu Jun 23 16:58:38 2011 +0200 @@ -16,6 +16,7 @@ */ package org.tmatesoft.hg.repo; +import static org.tmatesoft.hg.core.Nodeid.NULL; import static org.tmatesoft.hg.repo.HgRepository.BAD_REVISION; import static org.tmatesoft.hg.repo.HgRepository.TIP; @@ -87,6 +88,15 @@ return Nodeid.fromBinary(content.nodeid(revision), 0); } + /** + * Get local revision number (index) of the specified revision. + * + * For occasional queries, this method works with decent performance, despite its O(n/2) approach. + * Alternatively, if you need to perform multiple queries (e.g. at least 15-20), {@link RevisionMap} may come handy. + * + * @param nid revision to look up + * @return revision index, or {@link HgRepository#BAD_REVISION} if specified revision not found. + */ public final int getLocalRevision(Nodeid nid) { int revision = content.findLocalRevisionNumber(nid); if (revision == BAD_REVISION) { @@ -229,6 +239,7 @@ public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) { if (ix != revisionNumber) { // XXX temp code, just to make sure I understand what's going on here + // FIXME check against cpython or another tool-mangled repository throw new IllegalStateException(); } if (parent1Revision >= revisionNumber || parent2Revision >= revisionNumber) { @@ -370,6 +381,76 @@ } } + /** + * Effective int to Nodeid and vice versa translation. It's advised to use this class instead of + * multiple {@link Revlog#getLocalRevision(Nodeid)} calls. + * + * getLocalRevision(Nodeid) with straightforward lookup approach performs O(n/2) + * #localRevision() is log(n), plus initialization is O(n) + */ + public final class RevisionMap { + /* + * in fact, initialization is much slower as it instantiates Nodeids, while #getLocalRevision + * compares directly against byte buffer. Measuring cpython with 70k+ gives 3 times difference (47 vs 171) + * for complete changelog iteration. + */ + + /* + * XXX 3 * (x * 4) bytes. Can I do better? + */ + private Nodeid[] sequential; // natural repository order, childrenOf rely on ordering + private Nodeid[] sorted; // for binary search + private int[] sorted2natural; + + public RevisionMap() { + } + + public HgRepository getRepo() { + return Revlog.this.getRepo(); + } + + /** + * @return <code>this</code> for convenience. + */ + public RevisionMap init(/*XXX Pool<Nodeid> to reuse nodeids, if possible. */) { + // XXX HgRepository.register((RepoChangeListener) this); // listen to changes in repo, re-init if needed? + final int revisionCount = Revlog.this.content.revisionCount(); + sequential = new Nodeid[revisionCount]; + sorted = new Nodeid[revisionCount]; + sorted2natural = new int[revisionCount]; + RevlogStream.Inspector insp = new RevlogStream.Inspector() { + + public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { + final Nodeid nid = new Nodeid(nodeid, true); + sequential[revisionNumber] = sorted[revisionNumber] = nid; + } + }; + Revlog.this.content.iterate(0, TIP, false, insp); + Arrays.sort(sorted); + for (int i = 0; i < revisionCount; i++) { + Nodeid n = sequential[i]; + int x = Arrays.binarySearch(sorted, n); + sorted2natural[x] = i; + } + return this; + } + + public Nodeid revision(int localRevision) { + return sequential[localRevision]; + } + public int localRevision(Nodeid revision) { + if (revision == null || NULL.equals(revision)) { + return BAD_REVISION; + } + int x = Arrays.binarySearch(sorted, revision); + if (x < 0) { + return BAD_REVISION; + } + return sorted2natural[x]; + } + } + + protected static class ContentPipe implements RevlogStream.Inspector, CancelSupport { private final ByteChannel sink; private final CancelSupport cancelSupport;