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) {