Mercurial > hg4j
comparison src/org/tmatesoft/hg/internal/RevlogStream.java @ 354:5f9073eabf06
Propagate errors with exceptions up to a end client
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 01 Dec 2011 05:21:40 +0100 |
parents | 8da7ade36c57 |
children | 189dc6dc1c3e |
comparison
equal
deleted
inserted
replaced
353:0f3687e79f5a | 354:5f9073eabf06 |
---|---|
22 import java.io.File; | 22 import java.io.File; |
23 import java.io.IOException; | 23 import java.io.IOException; |
24 import java.util.zip.Inflater; | 24 import java.util.zip.Inflater; |
25 | 25 |
26 import org.tmatesoft.hg.core.HgBadStateException; | 26 import org.tmatesoft.hg.core.HgBadStateException; |
27 import org.tmatesoft.hg.core.HgInvalidControlFileException; | |
27 import org.tmatesoft.hg.core.HgInvalidRevisionException; | 28 import org.tmatesoft.hg.core.HgInvalidRevisionException; |
28 import org.tmatesoft.hg.core.Nodeid; | 29 import org.tmatesoft.hg.core.Nodeid; |
29 import org.tmatesoft.hg.repo.HgInternals; | 30 import org.tmatesoft.hg.repo.HgInternals; |
30 import org.tmatesoft.hg.repo.HgRepository; | 31 import org.tmatesoft.hg.repo.HgRepository; |
31 | 32 |
78 initOutline(); | 79 initOutline(); |
79 return baseRevisions.length; | 80 return baseRevisions.length; |
80 } | 81 } |
81 | 82 |
82 /** | 83 /** |
83 * @throws HgBadStateException if internal read operation failed | 84 * @throws HgInvalidControlFileException if attempt to read index file failed |
84 */ | 85 * @throws HgInvalidRevisionException if revisionIndex argument doesn't represent a valid record in the revlog |
85 public int dataLength(int revision) { | 86 */ |
87 public int dataLength(int revisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException { | |
86 // XXX in fact, use of iterate() instead of this implementation may be quite reasonable. | 88 // XXX in fact, use of iterate() instead of this implementation may be quite reasonable. |
87 // | 89 // |
88 final int indexSize = revisionCount(); | 90 revisionIndex = checkRevisionIndex(revisionIndex); |
89 DataAccess daIndex = getIndexStream(); | 91 DataAccess daIndex = getIndexStream(); |
90 if (revision == TIP) { | 92 try { |
91 revision = indexSize - 1; | 93 int recordOffset = getIndexOffsetInt(revisionIndex); |
92 } | |
93 try { | |
94 int recordOffset = getIndexOffsetInt(revision); | |
95 daIndex.seek(recordOffset + 12); // 6+2+4 | 94 daIndex.seek(recordOffset + 12); // 6+2+4 |
96 int actualLen = daIndex.readInt(); | 95 int actualLen = daIndex.readInt(); |
97 return actualLen; | 96 return actualLen; |
98 } catch (IOException ex) { | 97 } catch (IOException ex) { |
99 ex.printStackTrace(); // log error. FIXME better handling | 98 throw new HgInvalidControlFileException(null, ex, indexFile); |
100 throw new HgBadStateException(ex); | |
101 } finally { | 99 } finally { |
102 daIndex.done(); | 100 daIndex.done(); |
103 } | 101 } |
104 } | 102 } |
105 | 103 |
106 /** | 104 /** |
107 * @throws HgBadStateException if internal read operation failed | 105 * Read nodeid at given index |
108 */ | 106 * |
109 public byte[] nodeid(int revision) throws HgInvalidRevisionException { | 107 * @throws HgInvalidControlFileException if attempt to read index file failed |
110 final int indexSize = revisionCount(); | 108 * @throws HgInvalidRevisionException if revisionIndex argument doesn't represent a valid record in the revlog |
111 if (revision == TIP) { | 109 */ |
112 revision = indexSize - 1; | 110 public byte[] nodeid(int revisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException { |
113 } | 111 revisionIndex = checkRevisionIndex(revisionIndex); |
114 if (revision < 0 || revision >= indexSize) { | |
115 throw new HgInvalidRevisionException(revision).setRevisionIndex(revision, 0, indexSize); | |
116 } | |
117 DataAccess daIndex = getIndexStream(); | 112 DataAccess daIndex = getIndexStream(); |
118 try { | 113 try { |
119 int recordOffset = getIndexOffsetInt(revision); | 114 int recordOffset = getIndexOffsetInt(revisionIndex); |
120 daIndex.seek(recordOffset + 32); | 115 daIndex.seek(recordOffset + 32); |
121 byte[] rv = new byte[20]; | 116 byte[] rv = new byte[20]; |
122 daIndex.readBytes(rv, 0, 20); | 117 daIndex.readBytes(rv, 0, 20); |
123 return rv; | 118 return rv; |
124 } catch (IOException ex) { | 119 } catch (IOException ex) { |
125 ex.printStackTrace(); | 120 throw new HgInvalidControlFileException(null, ex, indexFile); |
126 throw new HgBadStateException(); | |
127 } finally { | 121 } finally { |
128 daIndex.done(); | 122 daIndex.done(); |
129 } | 123 } |
130 } | 124 } |
131 | 125 |
132 /** | 126 /** |
133 * Get link field from the index record. | 127 * Get link field from the index record. |
134 * @throws HgBadStateException if internal read operation failed | 128 * |
135 */ | 129 * @throws HgInvalidControlFileException if attempt to read index file failed |
136 public int linkRevision(int revision) { | 130 * @throws HgInvalidRevisionException if revisionIndex argument doesn't represent a valid record in the revlog |
137 final int last = revisionCount() - 1; | 131 */ |
138 if (revision == TIP) { | 132 public int linkRevision(int revisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException { |
139 revision = last; | 133 revisionIndex = checkRevisionIndex(revisionIndex); |
140 } | |
141 if (revision < 0 || revision > last) { | |
142 throw new IllegalArgumentException(Integer.toString(revision)); | |
143 } | |
144 DataAccess daIndex = getIndexStream(); | 134 DataAccess daIndex = getIndexStream(); |
145 try { | 135 try { |
146 int recordOffset = getIndexOffsetInt(revision); | 136 int recordOffset = getIndexOffsetInt(revisionIndex); |
147 daIndex.seek(recordOffset + 20); | 137 daIndex.seek(recordOffset + 20); |
148 int linkRev = daIndex.readInt(); | 138 int linkRev = daIndex.readInt(); |
149 return linkRev; | 139 return linkRev; |
150 } catch (IOException ex) { | 140 } catch (IOException ex) { |
151 ex.printStackTrace(); | 141 throw new HgInvalidControlFileException(null, ex, indexFile); |
152 throw new HgBadStateException(); | |
153 } finally { | 142 } finally { |
154 daIndex.done(); | 143 daIndex.done(); |
155 } | 144 } |
156 } | 145 } |
157 | 146 |
159 // while Nodeids should be kept on the level up, in Revlog. Guess, Revlog better keep | 148 // while Nodeids should be kept on the level up, in Revlog. Guess, Revlog better keep |
160 // map of nodeids, and once this comes true, we may get rid of this method. | 149 // map of nodeids, and once this comes true, we may get rid of this method. |
161 // Unlike its counterpart, {@link Revlog#getLocalRevisionNumber()}, doesn't fail with exception if node not found, | 150 // Unlike its counterpart, {@link Revlog#getLocalRevisionNumber()}, doesn't fail with exception if node not found, |
162 /** | 151 /** |
163 * @return integer in [0..revisionCount()) or {@link HgRepository#BAD_REVISION} if not found | 152 * @return integer in [0..revisionCount()) or {@link HgRepository#BAD_REVISION} if not found |
164 */ | 153 * @throws HgInvalidControlFileException if attempt to read index file failed |
165 public int findLocalRevisionNumber(Nodeid nodeid) { | 154 */ |
155 public int findLocalRevisionNumber(Nodeid nodeid) throws HgInvalidControlFileException { | |
166 // XXX this one may be implemented with iterate() once there's mechanism to stop iterations | 156 // XXX this one may be implemented with iterate() once there's mechanism to stop iterations |
167 final int indexSize = revisionCount(); | 157 final int indexSize = revisionCount(); |
168 DataAccess daIndex = getIndexStream(); | 158 DataAccess daIndex = getIndexStream(); |
169 try { | 159 try { |
170 byte[] nodeidBuf = new byte[20]; | 160 byte[] nodeidBuf = new byte[20]; |
177 return i; | 167 return i; |
178 } | 168 } |
179 daIndex.skip(inline ? 12 + compressedLen : 12); | 169 daIndex.skip(inline ? 12 + compressedLen : 12); |
180 } | 170 } |
181 } catch (IOException ex) { | 171 } catch (IOException ex) { |
182 ex.printStackTrace(); // log error. FIXME better handling. Perhaps, shall return BAD_REVISION here as well? | 172 throw new HgInvalidControlFileException("Failed", ex, indexFile).setRevision(nodeid); |
183 throw new IllegalStateException(ex); | |
184 } finally { | 173 } finally { |
185 daIndex.done(); | 174 daIndex.done(); |
186 } | 175 } |
187 return BAD_REVISION; | 176 return BAD_REVISION; |
188 } | 177 } |
265 private int getBaseRevision(int revision) { | 254 private int getBaseRevision(int revision) { |
266 return baseRevisions[revision]; | 255 return baseRevisions[revision]; |
267 } | 256 } |
268 | 257 |
269 /** | 258 /** |
259 * @param revisionIndex shall be valid index, [0..baseRevisions.length-1]. | |
260 * It's advised to use {@link #checkRevisionIndex(int)} to ensure argument is correct. | |
270 * @return offset of the revision's record in the index (.i) stream | 261 * @return offset of the revision's record in the index (.i) stream |
271 */ | 262 */ |
272 private int getIndexOffsetInt(int revision) { | 263 private int getIndexOffsetInt(int revisionIndex) { |
273 return inline ? indexRecordOffset[revision] : revision * REVLOGV1_RECORD_SIZE; | 264 return inline ? indexRecordOffset[revisionIndex] : revisionIndex * REVLOGV1_RECORD_SIZE; |
265 } | |
266 | |
267 private int checkRevisionIndex(int revisionIndex) throws HgInvalidRevisionException { | |
268 final int last = revisionCount() - 1; | |
269 if (revisionIndex == TIP) { | |
270 revisionIndex = last; | |
271 } | |
272 if (revisionIndex < 0 || revisionIndex > last) { | |
273 throw new HgInvalidRevisionException(revisionIndex).setRevisionIndex(revisionIndex, 0, last); | |
274 } | |
275 return revisionIndex; | |
274 } | 276 } |
275 | 277 |
276 private void initOutline() { | 278 private void initOutline() { |
277 if (baseRevisions != null && baseRevisions.length > 0) { | 279 if (baseRevisions != null && baseRevisions.length > 0) { |
278 return; | 280 return; |