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 } |
