Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/Revlog.java @ 347:8da7ade36c57
Add specific IAE subclass to handle wrong (e.g. outdated after rollback) revisions
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> | 
|---|---|
| date | Tue, 22 Nov 2011 05:25:57 +0100 | 
| parents | a674b8590362 | 
| children | 5f9073eabf06 | 
   comparison
  equal
  deleted
  inserted
  replaced
| 346:6d2c6b2469fc | 347:8da7ade36c57 | 
|---|---|
| 28 import java.util.LinkedList; | 28 import java.util.LinkedList; | 
| 29 import java.util.List; | 29 import java.util.List; | 
| 30 | 30 | 
| 31 import org.tmatesoft.hg.core.HgBadStateException; | 31 import org.tmatesoft.hg.core.HgBadStateException; | 
| 32 import org.tmatesoft.hg.core.HgException; | 32 import org.tmatesoft.hg.core.HgException; | 
| 33 import org.tmatesoft.hg.core.HgInvalidRevisionException; | |
| 33 import org.tmatesoft.hg.core.Nodeid; | 34 import org.tmatesoft.hg.core.Nodeid; | 
| 34 import org.tmatesoft.hg.internal.ArrayHelper; | 35 import org.tmatesoft.hg.internal.ArrayHelper; | 
| 35 import org.tmatesoft.hg.internal.DataAccess; | 36 import org.tmatesoft.hg.internal.DataAccess; | 
| 36 import org.tmatesoft.hg.internal.Experimental; | 37 import org.tmatesoft.hg.internal.Experimental; | 
| 37 import org.tmatesoft.hg.internal.RevlogStream; | 38 import org.tmatesoft.hg.internal.RevlogStream; | 
| 84 | 85 | 
| 85 public final int getLastRevision() { | 86 public final int getLastRevision() { | 
| 86 return content.revisionCount() - 1; | 87 return content.revisionCount() - 1; | 
| 87 } | 88 } | 
| 88 | 89 | 
| 89 public final Nodeid getRevision(int revision) { | 90 public final Nodeid getRevision(int revision) throws HgInvalidRevisionException { | 
| 90 // XXX cache nodeids? Rather, if context.getCache(this).getRevisionMap(create == false) != null, use it | 91 // XXX cache nodeids? Rather, if context.getCache(this).getRevisionMap(create == false) != null, use it | 
| 91 return Nodeid.fromBinary(content.nodeid(revision), 0); | 92 return Nodeid.fromBinary(content.nodeid(revision), 0); | 
| 92 } | 93 } | 
| 93 | 94 | 
| 94 /** | 95 /** | 
| 95 * FIXME need to be careful about (1) ordering of the revisions in the return list; (2) modifications (sorting) of the argument array | 96 * FIXME need to be careful about (1) ordering of the revisions in the return list; (2) modifications (sorting) of the argument array | 
| 96 */ | 97 */ | 
| 97 public final List<Nodeid> getRevisions(int... revisions) { | 98 public final List<Nodeid> getRevisions(int... revisions) throws HgInvalidRevisionException { | 
| 98 ArrayList<Nodeid> rv = new ArrayList<Nodeid>(revisions.length); | 99 ArrayList<Nodeid> rv = new ArrayList<Nodeid>(revisions.length); | 
| 99 Arrays.sort(revisions); | 100 Arrays.sort(revisions); | 
| 100 getRevisionsInternal(rv, revisions); | 101 getRevisionsInternal(rv, revisions); | 
| 101 return rv; | 102 return rv; | 
| 102 } | 103 } | 
| 103 | 104 | 
| 104 /*package-local*/ void getRevisionsInternal(final List<Nodeid> retVal, int[] sortedRevs) { | 105 /*package-local*/ void getRevisionsInternal(final List<Nodeid> retVal, int[] sortedRevs) throws HgInvalidRevisionException { | 
| 105 // once I have getRevisionMap and may find out whether it is avalable from cache, | 106 // once I have getRevisionMap and may find out whether it is avalable from cache, | 
| 106 // may use it, perhaps only for small number of revisions | 107 // may use it, perhaps only for small number of revisions | 
| 107 content.iterate(sortedRevs, false, new RevlogStream.Inspector() { | 108 content.iterate(sortedRevs, false, new RevlogStream.Inspector() { | 
| 108 | 109 | 
| 109 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { | 110 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { | 
| 112 }); | 113 }); | 
| 113 } | 114 } | 
| 114 | 115 | 
| 115 /** | 116 /** | 
| 116 * Get local revision number (index) of the specified revision. | 117 * Get local revision number (index) of the specified revision. | 
| 118 * If unsure, use {@link #isKnown(Nodeid)} to find out whether nodeid belongs to this revlog. | |
| 117 * | 119 * | 
| 118 * For occasional queries, this method works with decent performance, despite its O(n/2) approach. | 120 * For occasional queries, this method works with decent performance, despite its O(n/2) approach. | 
| 119 * Alternatively, if you need to perform multiple queries (e.g. at least 15-20), {@link RevisionMap} may come handy. | 121 * Alternatively, if you need to perform multiple queries (e.g. at least 15-20), {@link RevisionMap} may come handy. | 
| 120 * | 122 * | 
| 121 * @param nid revision to look up | 123 * @param nid revision to look up | 
| 122 * @return revision index, or {@link HgRepository#BAD_REVISION} if specified revision not found. | 124 * @return revision local index in this revlog | 
| 123 */ | 125 * @throws HgInvalidRevisionException if supplied nodeid doesn't identify any revision from this revlog | 
| 124 public final int getLocalRevision(Nodeid nid) { | 126 */ | 
| 127 public final int getLocalRevision(Nodeid nid) throws HgInvalidRevisionException { | |
| 125 int revision = content.findLocalRevisionNumber(nid); | 128 int revision = content.findLocalRevisionNumber(nid); | 
| 126 if (revision == BAD_REVISION) { | 129 if (revision == BAD_REVISION) { | 
| 127 throw new IllegalArgumentException(String.format("%s doesn't represent a revision of %s", nid.toString(), this /*XXX HgDataFile.getPath might be more suitable here*/)); | 130 throw new HgInvalidRevisionException(String.format("Bad revision of %s", this /*XXX HgDataFile.getPath might be more suitable here*/), nid, null); | 
| 128 } | 131 } | 
| 129 return revision; | 132 return revision; | 
| 130 } | 133 } | 
| 131 | 134 | 
| 132 // Till now, i follow approach that NULL nodeid is never part of revlog | 135 // Till now, i follow approach that NULL nodeid is never part of revlog | 
| 144 | 147 | 
| 145 /** | 148 /** | 
| 146 * Access to revision data as is (decompressed, but otherwise unprocessed, i.e. not parsed for e.g. changeset or manifest entries) | 149 * Access to revision data as is (decompressed, but otherwise unprocessed, i.e. not parsed for e.g. changeset or manifest entries) | 
| 147 * @param nodeid | 150 * @param nodeid | 
| 148 */ | 151 */ | 
| 149 protected void rawContent(Nodeid nodeid, ByteChannel sink) throws HgException, IOException, CancelledException { | 152 protected void rawContent(Nodeid nodeid, ByteChannel sink) throws HgException, IOException, CancelledException, HgInvalidRevisionException { | 
| 150 rawContent(getLocalRevision(nodeid), sink); | 153 rawContent(getLocalRevision(nodeid), sink); | 
| 151 } | 154 } | 
| 152 | 155 | 
| 153 /** | 156 /** | 
| 154 * @param revision - repo-local index of this file change (not a changelog revision number!) | 157 * @param revision - repo-local index of this file change (not a changelog revision number!) | 
| 155 */ | 158 */ | 
| 156 protected void rawContent(int revision, ByteChannel sink) throws HgException, IOException, CancelledException { | 159 protected void rawContent(int revision, ByteChannel sink) throws HgException, IOException, CancelledException, HgInvalidRevisionException { | 
| 157 if (sink == null) { | 160 if (sink == null) { | 
| 158 throw new IllegalArgumentException(); | 161 throw new IllegalArgumentException(); | 
| 159 } | 162 } | 
| 160 ContentPipe insp = new ContentPipe(sink, 0); | 163 ContentPipe insp = new ContentPipe(sink, 0); | 
| 161 insp.checkCancelled(); | 164 insp.checkCancelled(); | 
| 168 * | 171 * | 
| 169 * @param revision - revision to query parents, or {@link HgRepository#TIP} | 172 * @param revision - revision to query parents, or {@link HgRepository#TIP} | 
| 170 * @param parentRevisions - int[2] to get local revision numbers of parents (e.g. {6, -1}) | 173 * @param parentRevisions - int[2] to get local revision numbers of parents (e.g. {6, -1}) | 
| 171 * @param parent1 - byte[20] or null, if parent's nodeid is not needed | 174 * @param parent1 - byte[20] or null, if parent's nodeid is not needed | 
| 172 * @param parent2 - byte[20] or null, if second parent's nodeid is not needed | 175 * @param parent2 - byte[20] or null, if second parent's nodeid is not needed | 
| 173 * @return | 176 * @throws HgInvalidRevisionException | 
| 174 */ | 177 * @throws IllegalArgumentException | 
| 175 public void parents(int revision, int[] parentRevisions, byte[] parent1, byte[] parent2) { | 178 */ | 
| 179 public void parents(int revision, int[] parentRevisions, byte[] parent1, byte[] parent2) throws HgInvalidRevisionException { | |
| 176 if (revision != TIP && !(revision >= 0 && revision < content.revisionCount())) { | 180 if (revision != TIP && !(revision >= 0 && revision < content.revisionCount())) { | 
| 177 throw new IllegalArgumentException(String.valueOf(revision)); | 181 throw new HgInvalidRevisionException(revision); | 
| 178 } | 182 } | 
| 179 if (parentRevisions == null || parentRevisions.length < 2) { | 183 if (parentRevisions == null || parentRevisions.length < 2) { | 
| 180 throw new IllegalArgumentException(String.valueOf(parentRevisions)); | 184 throw new IllegalArgumentException(String.valueOf(parentRevisions)); | 
| 181 } | 185 } | 
| 182 if (parent1 != null && parent1.length < 20) { | 186 if (parent1 != null && parent1.length < 20) { | 
| 219 } | 223 } | 
| 220 } | 224 } | 
| 221 } | 225 } | 
| 222 | 226 | 
| 223 @Experimental | 227 @Experimental | 
| 224 public void walk(int start, int end, final Revlog.Inspector inspector) { | 228 public void walk(int start, int end, final Revlog.Inspector inspector) throws HgInvalidRevisionException { | 
| 225 int lastRev = getLastRevision(); | 229 int lastRev = getLastRevision(); | 
| 226 if (start == TIP) { | 230 if (start == TIP) { | 
| 227 start = lastRev; | 231 start = lastRev; | 
| 228 } | 232 } | 
| 229 if (end == TIP) { | 233 if (end == TIP) { | 
