comparison src/org/tmatesoft/hg/internal/RevlogStream.java @ 158:b413b16d10a5

Integer offsets and file length explictly, rather than casts throughout code. Inflater may benefit from total length hint, but shall calculate it by its own if needed
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 09 Mar 2011 13:16:37 +0100
parents d5268ca7715b
children 71ddbf8603e8
comparison
equal deleted inserted replaced
157:d5268ca7715b 158:b413b16d10a5
24 import java.util.ArrayList; 24 import java.util.ArrayList;
25 import java.util.Collections; 25 import java.util.Collections;
26 import java.util.LinkedList; 26 import java.util.LinkedList;
27 import java.util.List; 27 import java.util.List;
28 28
29 import org.tmatesoft.hg.core.HgBadStateException;
29 import org.tmatesoft.hg.core.Nodeid; 30 import org.tmatesoft.hg.core.Nodeid;
30 import org.tmatesoft.hg.repo.HgRepository; 31 import org.tmatesoft.hg.repo.HgRepository;
31 32
32 33
33 /** 34 /**
75 DataAccess daIndex = getIndexStream(); // XXX may supply a hint that I'll need really few bytes of data (although at some offset) 76 DataAccess daIndex = getIndexStream(); // XXX may supply a hint that I'll need really few bytes of data (although at some offset)
76 if (revision == TIP) { 77 if (revision == TIP) {
77 revision = indexSize - 1; 78 revision = indexSize - 1;
78 } 79 }
79 try { 80 try {
80 int recordOffset = inline ? (int) index.get(revision).offset : revision * REVLOGV1_RECORD_SIZE; 81 int recordOffset = inline ? index.get(revision).getIntOffset() : revision * REVLOGV1_RECORD_SIZE;
81 daIndex.seek(recordOffset + 12); // 6+2+4 82 daIndex.seek(recordOffset + 12); // 6+2+4
82 int actualLen = daIndex.readInt(); 83 int actualLen = daIndex.readInt();
83 return actualLen; 84 return actualLen;
84 } catch (IOException ex) { 85 } catch (IOException ex) {
85 ex.printStackTrace(); // log error. FIXME better handling 86 ex.printStackTrace(); // log error. FIXME better handling
97 if (revision < 0 || revision >= indexSize) { 98 if (revision < 0 || revision >= indexSize) {
98 throw new IllegalArgumentException(Integer.toString(revision)); 99 throw new IllegalArgumentException(Integer.toString(revision));
99 } 100 }
100 DataAccess daIndex = getIndexStream(); 101 DataAccess daIndex = getIndexStream();
101 try { 102 try {
102 int recordOffset = inline ? (int) index.get(revision).offset : revision * REVLOGV1_RECORD_SIZE; 103 int recordOffset = inline ? index.get(revision).getIntOffset() : revision * REVLOGV1_RECORD_SIZE;
103 daIndex.seek(recordOffset + 32); 104 daIndex.seek(recordOffset + 32);
104 byte[] rv = new byte[20]; 105 byte[] rv = new byte[20];
105 daIndex.readBytes(rv, 0, 20); 106 daIndex.readBytes(rv, 0, 20);
106 return rv; 107 return rv;
107 } catch (IOException ex) { 108 } catch (IOException ex) {
120 if (revision < 0 || revision > last) { 121 if (revision < 0 || revision > last) {
121 throw new IllegalArgumentException(Integer.toString(revision)); 122 throw new IllegalArgumentException(Integer.toString(revision));
122 } 123 }
123 DataAccess daIndex = getIndexStream(); 124 DataAccess daIndex = getIndexStream();
124 try { 125 try {
125 int recordOffset = inline ? (int) index.get(revision).offset : revision * REVLOGV1_RECORD_SIZE; 126 int recordOffset = inline ? index.get(revision).getIntOffset() : revision * REVLOGV1_RECORD_SIZE;
126 daIndex.seek(recordOffset + 20); 127 daIndex.seek(recordOffset + 20);
127 int linkRev = daIndex.readInt(); 128 int linkRev = daIndex.readInt();
128 return linkRev; 129 return linkRev;
129 } catch (IOException ex) { 130 } catch (IOException ex) {
130 ex.printStackTrace(); 131 ex.printStackTrace();
206 extraReadsToBaseRev = true; 207 extraReadsToBaseRev = true;
207 } else { 208 } else {
208 i = start; 209 i = start;
209 } 210 }
210 211
211 daIndex.seek(inline ? index.get(i).offset : i * REVLOGV1_RECORD_SIZE); 212 daIndex.seek(inline ? index.get(i).getIntOffset() : i * REVLOGV1_RECORD_SIZE);
212 for (; i <= end; i++ ) { 213 for (; i <= end; i++ ) {
213 if (inline && needData) { 214 if (inline && needData) {
214 // inspector reading data (though FilterDataAccess) may have affected index position 215 // inspector reading data (though FilterDataAccess) may have affected index position
215 daIndex.seek(index.get(i).offset); 216 daIndex.seek(index.get(i).getIntOffset());
216 } 217 }
217 long l = daIndex.readLong(); // 0 218 long l = daIndex.readLong(); // 0
218 @SuppressWarnings("unused") 219 @SuppressWarnings("unused")
219 long offset = l >>> 16; 220 long offset = l >>> 16;
220 @SuppressWarnings("unused") 221 @SuppressWarnings("unused")
229 daIndex.readBytes(nodeidBuf, 0, 20); // +32 230 daIndex.readBytes(nodeidBuf, 0, 20); // +32
230 daIndex.skip(12); 231 daIndex.skip(12);
231 DataAccess userDataAccess = null; 232 DataAccess userDataAccess = null;
232 if (needData) { 233 if (needData) {
233 final byte firstByte; 234 final byte firstByte;
234 long streamOffset = index.get(i).offset; 235 int streamOffset = index.get(i).getIntOffset();
235 DataAccess streamDataAccess; 236 DataAccess streamDataAccess;
236 if (inline) { 237 if (inline) {
237 streamDataAccess = daIndex; 238 streamDataAccess = daIndex;
238 streamOffset += REVLOGV1_RECORD_SIZE; // don't need to do seek as it's actual position in the index stream 239 streamOffset += REVLOGV1_RECORD_SIZE; // don't need to do seek as it's actual position in the index stream
239 } else { 240 } else {
240 streamDataAccess = daData; 241 streamDataAccess = daData;
241 daData.seek(streamOffset); 242 daData.seek(streamOffset);
242 } 243 }
244 final boolean patchToPrevious = baseRevision != i; // XXX not sure if this is the right way to detect a patch
243 firstByte = streamDataAccess.readByte(); 245 firstByte = streamDataAccess.readByte();
244 if (firstByte == 0x78 /* 'x' */) { 246 if (firstByte == 0x78 /* 'x' */) {
245 userDataAccess = new InflaterDataAccess(streamDataAccess, streamOffset, compressedLen); 247 userDataAccess = new InflaterDataAccess(streamDataAccess, streamOffset, compressedLen, patchToPrevious ? -1 : actualLen);
246 } else if (firstByte == 0x75 /* 'u' */) { 248 } else if (firstByte == 0x75 /* 'u' */) {
247 userDataAccess = new FilterDataAccess(streamDataAccess, streamOffset+1, compressedLen-1); 249 userDataAccess = new FilterDataAccess(streamDataAccess, streamOffset+1, compressedLen-1);
248 } else { 250 } else {
249 // XXX Python impl in fact throws exception when there's not 'x', 'u' or '0' 251 // XXX Python impl in fact throws exception when there's not 'x', 'u' or '0'
250 // but I don't see reason not to return data as is 252 // but I don't see reason not to return data as is
251 userDataAccess = new FilterDataAccess(streamDataAccess, streamOffset, compressedLen); 253 userDataAccess = new FilterDataAccess(streamDataAccess, streamOffset, compressedLen);
252 } 254 }
253 // XXX 255 // XXX
254 if (baseRevision != i) { // XXX not sure if this is the right way to detect a patch 256 if (patchToPrevious) {
255 // this is a patch 257 // this is a patch
256 LinkedList<PatchRecord> patches = new LinkedList<PatchRecord>(); 258 LinkedList<PatchRecord> patches = new LinkedList<PatchRecord>();
257 while (!userDataAccess.isEmpty()) { 259 while (!userDataAccess.isEmpty()) {
258 PatchRecord pr = PatchRecord.read(userDataAccess); 260 PatchRecord pr = PatchRecord.read(userDataAccess);
259 // System.out.printf("PatchRecord:%d %d %d\n", pr.start, pr.end, pr.len); 261 // System.out.printf("PatchRecord:%d %d %d\n", pr.start, pr.end, pr.len);
279 } 281 }
280 lastUserData = userDataAccess; 282 lastUserData = userDataAccess;
281 } 283 }
282 } 284 }
283 } catch (IOException ex) { 285 } catch (IOException ex) {
284 throw new IllegalStateException(ex); // FIXME need better handling 286 throw new HgBadStateException(ex); // FIXME need better handling
285 } finally { 287 } finally {
286 daIndex.done(); 288 daIndex.done();
287 if (daData != null) { 289 if (daData != null) {
288 daData.done(); 290 daData.done();
289 } 291 }
343 345
344 346
345 // perhaps, package-local or protected, if anyone else from low-level needs them 347 // perhaps, package-local or protected, if anyone else from low-level needs them
346 // XXX think over if we should keep offset in case of separate data file - we read the field anyway. Perhaps, distinct entry classes for Inline and non-inline indexes? 348 // XXX think over if we should keep offset in case of separate data file - we read the field anyway. Perhaps, distinct entry classes for Inline and non-inline indexes?
347 private static class IndexEntry { 349 private static class IndexEntry {
348 public final long offset; // for separate .i and .d - copy of index record entry, for inline index - actual offset of the record in the .i file (record entry + revision * record size)) 350 private final int/*long*/ offset; // for separate .i and .d - copy of index record entry, for inline index - actual offset of the record in the .i file (record entry + revision * record size))
349 //public final int length; // data past fixed record (need to decide whether including header size or not), and whether length is of compressed data or not 351 //public final int length; // data past fixed record (need to decide whether including header size or not), and whether length is of compressed data or not
350 public final int baseRevision; 352 public final int baseRevision;
351 353
352 public IndexEntry(long o, int baseRev) { 354 public IndexEntry(long o, int baseRev) {
353 offset = o; 355 offset = (int) o;
356 // Index file stores offsets as long, but since DataAccess doesn't support long length() and others yet,
357 // no reason to operate with long offsets
358 if (o != offset) {
359 throw new HgBadStateException("Data too big, offset didn't fit to sizeof(int)");
360 }
354 baseRevision = baseRev; 361 baseRevision = baseRev;
362 }
363
364 public int getIntOffset() {
365 return offset;
355 } 366 }
356 } 367 }
357 368
358 // mpatch.c : apply() 369 // mpatch.c : apply()
359 // FIXME need to implement patch merge (fold, combine, gather and discard from aforementioned mpatch.[c|py]), also see Revlog and Mercurial PDF 370 // FIXME need to implement patch merge (fold, combine, gather and discard from aforementioned mpatch.[c|py]), also see Revlog and Mercurial PDF
360 public/*for HgBundle; until moved to better place*/static byte[] apply(DataAccess baseRevisionContent, int outcomeLen, List<PatchRecord> patch) throws IOException { 371 public/*for HgBundle; until moved to better place*/static byte[] apply(DataAccess baseRevisionContent, int outcomeLen, List<PatchRecord> patch) throws IOException {
361 int last = 0, destIndex = 0; 372 int last = 0, destIndex = 0;
362 if (outcomeLen == -1) { 373 if (outcomeLen == -1) {
363 outcomeLen = (int) baseRevisionContent.length(); 374 outcomeLen = baseRevisionContent.length();
364 for (PatchRecord pr : patch) { 375 for (PatchRecord pr : patch) {
365 outcomeLen += pr.start - last + pr.len; 376 outcomeLen += pr.start - last + pr.len;
366 last = pr.end; 377 last = pr.end;
367 } 378 }
368 outcomeLen -= last; 379 outcomeLen -= last;