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 }