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;