Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/Revlog.java @ 425:48f993aa2f41
FIXMEs: exceptions, javadoc
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Wed, 28 Mar 2012 18:39:29 +0200 |
parents | 6437d261048a |
children | 12f668401613 |
comparison
equal
deleted
inserted
replaced
424:6437d261048a | 425:48f993aa2f41 |
---|---|
14 * the terms of a license other than GNU General Public License | 14 * the terms of a license other than GNU General Public License |
15 * contact TMate Software at support@hg4j.com | 15 * contact TMate Software at support@hg4j.com |
16 */ | 16 */ |
17 package org.tmatesoft.hg.repo; | 17 package org.tmatesoft.hg.repo; |
18 | 18 |
19 import static org.tmatesoft.hg.repo.HgRepository.BAD_REVISION; | 19 import static org.tmatesoft.hg.repo.HgRepository.*; |
20 import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION; | |
21 import static org.tmatesoft.hg.repo.HgRepository.TIP; | |
22 | 20 |
23 import java.io.IOException; | 21 import java.io.IOException; |
24 import java.nio.ByteBuffer; | 22 import java.nio.ByteBuffer; |
25 import java.util.ArrayList; | 23 import java.util.ArrayList; |
26 import java.util.Arrays; | 24 import java.util.Arrays; |
27 import java.util.Collection; | 25 import java.util.Collection; |
28 import java.util.HashSet; | 26 import java.util.HashSet; |
29 import java.util.LinkedList; | 27 import java.util.LinkedList; |
30 import java.util.List; | 28 import java.util.List; |
31 | 29 |
32 import org.tmatesoft.hg.core.HgException; | |
33 import org.tmatesoft.hg.core.Nodeid; | 30 import org.tmatesoft.hg.core.Nodeid; |
34 import org.tmatesoft.hg.internal.ArrayHelper; | 31 import org.tmatesoft.hg.internal.ArrayHelper; |
35 import org.tmatesoft.hg.internal.DataAccess; | 32 import org.tmatesoft.hg.internal.DataAccess; |
36 import org.tmatesoft.hg.internal.Experimental; | 33 import org.tmatesoft.hg.internal.Experimental; |
37 import org.tmatesoft.hg.internal.Preview; | 34 import org.tmatesoft.hg.internal.Preview; |
78 | 75 |
79 public final HgRepository getRepo() { | 76 public final HgRepository getRepo() { |
80 return repo; | 77 return repo; |
81 } | 78 } |
82 | 79 |
83 public final int getRevisionCount() { | 80 /** |
81 * @return total number of revisions kept in this revlog | |
82 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> | |
83 */ | |
84 public final int getRevisionCount() throws HgRuntimeException { | |
84 return content.revisionCount(); | 85 return content.revisionCount(); |
85 } | 86 } |
86 | 87 |
87 public final int getLastRevision() { | 88 /** |
89 * @return index of last known revision, a.k.a. {@link HgRepository#TIP} | |
90 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> | |
91 */ | |
92 public final int getLastRevision() throws HgRuntimeException { | |
88 return content.revisionCount() - 1; | 93 return content.revisionCount() - 1; |
89 } | 94 } |
90 | 95 |
91 /** | 96 /** |
92 * Map revision index to unique revision identifier (nodeid). | 97 * Map revision index to unique revision identifier (nodeid). |
93 * | 98 * |
94 * @param revision index of the entry in this revlog, may be {@link HgRepository#TIP} | 99 * @param revision index of the entry in this revlog, may be {@link HgRepository#TIP} |
95 * @return revision nodeid of the entry | 100 * @return revision nodeid of the entry |
96 * | 101 * |
97 * @throws HgInvalidRevisionException if supplied argument doesn't represent revision index in this revlog | 102 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> |
98 * @throws HgInvalidControlFileException if access to revlog index/data entry failed | 103 */ |
99 */ | 104 public final Nodeid getRevision(int revision) throws HgRuntimeException { |
100 public final Nodeid getRevision(int revision) throws HgInvalidRevisionException, HgInvalidControlFileException { | |
101 // XXX cache nodeids? Rather, if context.getCache(this).getRevisionMap(create == false) != null, use it | 105 // XXX cache nodeids? Rather, if context.getCache(this).getRevisionMap(create == false) != null, use it |
102 return Nodeid.fromBinary(content.nodeid(revision), 0); | 106 return Nodeid.fromBinary(content.nodeid(revision), 0); |
103 } | 107 } |
104 | 108 |
105 /** | 109 /** |
106 * FIXME need to be careful about (1) ordering of the revisions in the return list; (2) modifications (sorting) of the argument array | 110 * Effective alternative to map few revision indexes to corresponding nodeids at once. |
107 */ | 111 * <p>Note, there are few aspects to be careful about when using this method<ul> |
108 public final List<Nodeid> getRevisions(int... revisions) throws HgInvalidRevisionException, HgInvalidControlFileException { | 112 * <li>ordering of the revisions in the return list is unspecified, it's likely won't match that of the method argument |
113 * <li>supplied array get modified (sorted)</ul> | |
114 * @return list of mapped revisions in no particular order | |
115 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> | |
116 */ | |
117 public final List<Nodeid> getRevisions(int... revisions) throws HgRuntimeException { | |
109 ArrayList<Nodeid> rv = new ArrayList<Nodeid>(revisions.length); | 118 ArrayList<Nodeid> rv = new ArrayList<Nodeid>(revisions.length); |
110 Arrays.sort(revisions); | 119 Arrays.sort(revisions); |
111 getRevisionsInternal(rv, revisions); | 120 getRevisionsInternal(rv, revisions); |
112 return rv; | 121 return rv; |
113 } | 122 } |
130 * For occasional queries, this method works with decent performance, despite its O(n/2) approach. | 139 * For occasional queries, this method works with decent performance, despite its O(n/2) approach. |
131 * Alternatively, if you need to perform multiple queries (e.g. at least 15-20), {@link Revlog.RevisionMap} may come handy. | 140 * Alternatively, if you need to perform multiple queries (e.g. at least 15-20), {@link Revlog.RevisionMap} may come handy. |
132 * | 141 * |
133 * @param nid revision to look up | 142 * @param nid revision to look up |
134 * @return revision local index in this revlog | 143 * @return revision local index in this revlog |
135 * @throws HgInvalidRevisionException if supplied nodeid doesn't identify any revision from this revlog | 144 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> |
136 * @throws HgInvalidControlFileException if access to revlog index/data entry failed | 145 */ |
137 */ | 146 public final int getRevisionIndex(Nodeid nid) throws HgRuntimeException { |
138 public final int getRevisionIndex(Nodeid nid) throws HgInvalidControlFileException, HgInvalidRevisionException { | |
139 int revision = content.findRevisionIndex(nid); | 147 int revision = content.findRevisionIndex(nid); |
140 if (revision == BAD_REVISION) { | 148 if (revision == BAD_REVISION) { |
141 // using toString() to identify revlog. HgDataFile.toString includes path, HgManifest and HgChangelog instances | 149 // using toString() to identify revlog. HgDataFile.toString includes path, HgManifest and HgChangelog instances |
142 // are fine with default (class name) | 150 // are fine with default (class name) |
143 // Perhaps, more tailored description method would be suitable here | 151 // Perhaps, more tailored description method would be suitable here |
149 /** | 157 /** |
150 * Note, {@link Nodeid#NULL} nodeid is not reported as known in any revlog. | 158 * Note, {@link Nodeid#NULL} nodeid is not reported as known in any revlog. |
151 * | 159 * |
152 * @param nodeid | 160 * @param nodeid |
153 * @return <code>true</code> if revision is part of this revlog | 161 * @return <code>true</code> if revision is part of this revlog |
154 * @throws HgInvalidControlFileException if access to revlog index/data entry failed | 162 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> |
155 */ | 163 */ |
156 public final boolean isKnown(Nodeid nodeid) throws HgInvalidControlFileException { | 164 public final boolean isKnown(Nodeid nodeid) throws HgRuntimeException { |
157 final int rn = content.findRevisionIndex(nodeid); | 165 final int rn = content.findRevisionIndex(nodeid); |
158 if (BAD_REVISION == rn) { | 166 if (BAD_REVISION == rn) { |
159 return false; | 167 return false; |
160 } | 168 } |
161 if (rn < 0 || rn >= content.revisionCount()) { | 169 if (rn < 0 || rn >= content.revisionCount()) { |
206 // TODO post 1.0 e.setFileName(content.getIndexFile() or this.getHumanFriendlyPath()) - shall decide whether | 214 // TODO post 1.0 e.setFileName(content.getIndexFile() or this.getHumanFriendlyPath()) - shall decide whether |
207 // protected abstract getHFPath() with impl in HgDataFile, HgManifest and HgChangelog or path is data of either Revlog or RevlogStream | 215 // protected abstract getHFPath() with impl in HgDataFile, HgManifest and HgChangelog or path is data of either Revlog or RevlogStream |
208 // Do the same (add file name) below | 216 // Do the same (add file name) below |
209 throw e; | 217 throw e; |
210 } catch (HgInvalidControlFileException ex) { | 218 } catch (HgInvalidControlFileException ex) { |
211 throw ex; | 219 throw ex.isRevisionIndexSet() ? ex : ex.setRevisionIndex(revisionIndex); |
212 } catch (HgException ex) { | |
213 HgInvalidControlFileException e = new HgInvalidControlFileException(ex.getClass().getSimpleName(), ex, null); | |
214 e.setRevisionIndex(revisionIndex); | |
215 throw e; | |
216 } | 220 } |
217 } | 221 } |
218 | 222 |
219 /** | 223 /** |
220 * Fills supplied arguments with information about revision parents. | 224 * Fills supplied arguments with information about revision parents. |
221 * | 225 * |
222 * @param revision - revision to query parents, or {@link HgRepository#TIP} | 226 * @param revision - revision to query parents, or {@link HgRepository#TIP} |
223 * @param parentRevisions - int[2] to get local revision numbers of parents (e.g. {6, -1}), {@link HgRepository#NO_REVISION} indicates parent not set | 227 * @param parentRevisions - int[2] to get local revision numbers of parents (e.g. {6, -1}), {@link HgRepository#NO_REVISION} indicates parent not set |
224 * @param parent1 - byte[20] or null, if parent's nodeid is not needed | 228 * @param parent1 - byte[20] or null, if parent's nodeid is not needed |
225 * @param parent2 - byte[20] or null, if second parent's nodeid is not needed | 229 * @param parent2 - byte[20] or null, if second parent's nodeid is not needed |
226 * @throws HgInvalidRevisionException | 230 * @throws IllegalArgumentException if passed arrays can't fit requested data |
227 * @throws HgInvalidControlFileException FIXME EXCEPTIONS | 231 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> |
228 * @throws IllegalArgumentException | 232 */ |
229 */ | 233 public void parents(int revision, int[] parentRevisions, byte[] parent1, byte[] parent2) throws HgRuntimeException, IllegalArgumentException { |
230 public void parents(int revision, int[] parentRevisions, byte[] parent1, byte[] parent2) throws HgInvalidRevisionException, HgInvalidControlFileException { | |
231 if (revision != TIP && !(revision >= 0 && revision < content.revisionCount())) { | 234 if (revision != TIP && !(revision >= 0 && revision < content.revisionCount())) { |
232 throw new HgInvalidRevisionException(revision); | 235 throw new HgInvalidRevisionException(revision); |
233 } | 236 } |
234 if (parentRevisions == null || parentRevisions.length < 2) { | 237 if (parentRevisions == null || parentRevisions.length < 2) { |
235 throw new IllegalArgumentException(String.valueOf(parentRevisions)); | 238 throw new IllegalArgumentException(String.valueOf(parentRevisions)); |
273 content.iterate(parentRevisions[1], parentRevisions[1], false, pc); | 276 content.iterate(parentRevisions[1], parentRevisions[1], false, pc); |
274 System.arraycopy(pc.nodeid, 0, parent2, 0, 20); | 277 System.arraycopy(pc.nodeid, 0, parent2, 0, 20); |
275 } | 278 } |
276 } | 279 } |
277 } | 280 } |
278 | 281 |
282 /** | |
283 * EXPERIMENTAL CODE, DO NOT USE | |
284 * | |
285 * Alternative revlog iteration | |
286 * | |
287 * @param start | |
288 * @param end | |
289 * @param inspector | |
290 * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> | |
291 */ | |
279 @Experimental | 292 @Experimental |
280 public void walk(int start, int end, final Revlog.Inspector inspector) throws HgInvalidRevisionException, HgInvalidControlFileException { | 293 public void walk(int start, int end, final Revlog.Inspector inspector) throws HgRuntimeException { |
281 int lastRev = getLastRevision(); | 294 int lastRev = getLastRevision(); |
282 if (start == TIP) { | 295 if (start == TIP) { |
283 start = lastRev; | 296 start = lastRev; |
284 } | 297 } |
285 if (end == TIP) { | 298 if (end == TIP) { |
323 // XXX document whether parentX is -1 or a constant (BAD_REVISION? or dedicated?) | 336 // XXX document whether parentX is -1 or a constant (BAD_REVISION? or dedicated?) |
324 void next(int revisionIndex, Nodeid revision, int parent1, int parent2, Nodeid nidParent1, Nodeid nidParent2); | 337 void next(int revisionIndex, Nodeid revision, int parent1, int parent2, Nodeid nidParent1, Nodeid nidParent2); |
325 } | 338 } |
326 | 339 |
327 /* | 340 /* |
328 * XXX think over if it's better to do either: | 341 * FIXME think over if it's better to do either: |
329 * pw = getChangelog().new ParentWalker(); pw.init() and pass pw instance around as needed | 342 * pw = getChangelog().new ParentWalker(); pw.init() and pass pw instance around as needed |
330 * or | 343 * or |
331 * add Revlog#getParentWalker(), static class, make cons() and #init package-local, and keep SoftReference to allow walker reuse. | 344 * add Revlog#getParentWalker(), static class, make cons() and #init package-local, and keep SoftReference to allow walker reuse. |
332 * | 345 * |
333 * and yes, walker is not a proper name | 346 * and yes, walker is not a proper name |
596 protected void recordFailure(Exception ex) { | 609 protected void recordFailure(Exception ex) { |
597 assert failure == null; | 610 assert failure == null; |
598 failure = ex; | 611 failure = ex; |
599 } | 612 } |
600 | 613 |
601 // FIXME is HgException of any use here now? | 614 public void checkFailed() throws HgRuntimeException, IOException, CancelledException { |
602 // TODO consider if IOException in addition to HgException is of any real utility | |
603 public void checkFailed() throws HgException, IOException, CancelledException { | |
604 if (failure == null) { | 615 if (failure == null) { |
605 return; | 616 return; |
606 } | 617 } |
607 if (failure instanceof IOException) { | 618 if (failure instanceof IOException) { |
608 throw (IOException) failure; | 619 throw (IOException) failure; |
609 } | 620 } |
610 if (failure instanceof CancelledException) { | 621 if (failure instanceof CancelledException) { |
611 throw (CancelledException) failure; | 622 throw (CancelledException) failure; |
612 } | 623 } |
613 if (failure instanceof HgException) { | 624 if (failure instanceof HgRuntimeException) { |
614 throw (HgException) failure; | 625 throw (HgRuntimeException) failure; |
615 } | 626 } |
616 throw new HgInvalidStateException(failure.toString()); | 627 throw new HgInvalidStateException(failure.toString()); |
617 } | 628 } |
618 | 629 |
619 public void checkCancelled() throws CancelledException { | 630 public void checkCancelled() throws CancelledException { |
639 setCancelSupport(CancelSupport.Factory.get(_sink)); | 650 setCancelSupport(CancelSupport.Factory.get(_sink)); |
640 offset = seekOffset; | 651 offset = seekOffset; |
641 logFacility = log; | 652 logFacility = log; |
642 } | 653 } |
643 | 654 |
644 protected void prepare(int revisionNumber, DataAccess da) throws HgException, IOException { | 655 protected void prepare(int revisionNumber, DataAccess da) throws IOException { |
645 if (offset > 0) { // save few useless reset/rewind operations | 656 if (offset > 0) { // save few useless reset/rewind operations |
646 da.seek(offset); | 657 da.seek(offset); |
647 } | 658 } |
648 } | 659 } |
649 | 660 |
687 progressSupport.done(); // XXX shall specify whether #done() is invoked always or only if completed successfully. | 698 progressSupport.done(); // XXX shall specify whether #done() is invoked always or only if completed successfully. |
688 } catch (IOException ex) { | 699 } catch (IOException ex) { |
689 recordFailure(ex); | 700 recordFailure(ex); |
690 } catch (CancelledException ex) { | 701 } catch (CancelledException ex) { |
691 recordFailure(ex); | 702 recordFailure(ex); |
692 } catch (HgException ex) { | |
693 recordFailure(ex); | |
694 } | 703 } |
695 } | 704 } |
696 } | 705 } |
697 } | 706 } |