Mercurial > hg4j
comparison src/org/tmatesoft/hg/internal/DataAccessProvider.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 | 981f9f50bb6c |
comparison
equal
deleted
inserted
replaced
157:d5268ca7715b | 158:b413b16d10a5 |
---|---|
21 import java.io.IOException; | 21 import java.io.IOException; |
22 import java.nio.ByteBuffer; | 22 import java.nio.ByteBuffer; |
23 import java.nio.MappedByteBuffer; | 23 import java.nio.MappedByteBuffer; |
24 import java.nio.channels.FileChannel; | 24 import java.nio.channels.FileChannel; |
25 | 25 |
26 import org.tmatesoft.hg.core.HgBadStateException; | |
27 | |
26 /** | 28 /** |
27 * | 29 * |
28 * @author Artem Tikhomirov | 30 * @author Artem Tikhomirov |
29 * @author TMate Software Ltd. | 31 * @author TMate Software Ltd. |
30 */ | 32 */ |
46 if (!f.exists()) { | 48 if (!f.exists()) { |
47 return new DataAccess(); | 49 return new DataAccess(); |
48 } | 50 } |
49 try { | 51 try { |
50 FileChannel fc = new FileInputStream(f).getChannel(); | 52 FileChannel fc = new FileInputStream(f).getChannel(); |
51 if (fc.size() > mapioMagicBoundary) { | 53 int flen = (int) fc.size(); |
54 if (fc.size() - flen != 0) { | |
55 throw new HgBadStateException("Files greater than 2Gb are not yet supported"); | |
56 } | |
57 if (flen > mapioMagicBoundary) { | |
52 // TESTS: bufLen of 1024 was used to test MemMapFileAccess | 58 // TESTS: bufLen of 1024 was used to test MemMapFileAccess |
53 return new MemoryMapFileAccess(fc, fc.size(), mapioMagicBoundary); | 59 return new MemoryMapFileAccess(fc, flen, mapioMagicBoundary); |
54 } else { | 60 } else { |
55 // XXX once implementation is more or less stable, | 61 // XXX once implementation is more or less stable, |
56 // may want to try ByteBuffer.allocateDirect() to see | 62 // may want to try ByteBuffer.allocateDirect() to see |
57 // if there's any performance gain. | 63 // if there's any performance gain. |
58 boolean useDirectBuffer = false; | 64 boolean useDirectBuffer = false; |
59 // TESTS: bufferSize of 100 was used to check buffer underflow states when readBytes reads chunks bigger than bufSize | 65 // TESTS: bufferSize of 100 was used to check buffer underflow states when readBytes reads chunks bigger than bufSize |
60 return new FileAccess(fc, fc.size(), bufferSize, useDirectBuffer); | 66 return new FileAccess(fc, flen, bufferSize, useDirectBuffer); |
61 } | 67 } |
62 } catch (IOException ex) { | 68 } catch (IOException ex) { |
63 // unlikely to happen, we've made sure file exists. | 69 // unlikely to happen, we've made sure file exists. |
64 ex.printStackTrace(); // FIXME log error | 70 ex.printStackTrace(); // FIXME log error |
65 } | 71 } |
67 } | 73 } |
68 | 74 |
69 // DOESN'T WORK YET | 75 // DOESN'T WORK YET |
70 private static class MemoryMapFileAccess extends DataAccess { | 76 private static class MemoryMapFileAccess extends DataAccess { |
71 private FileChannel fileChannel; | 77 private FileChannel fileChannel; |
72 private final long size; | 78 private final int size; |
73 private long position = 0; // always points to buffer's absolute position in the file | 79 private long position = 0; // always points to buffer's absolute position in the file |
74 private final int memBufferSize; | 80 private final int memBufferSize; |
75 private MappedByteBuffer buffer; | 81 private MappedByteBuffer buffer; |
76 | 82 |
77 public MemoryMapFileAccess(FileChannel fc, long channelSize, int /*long?*/ bufferSize) { | 83 public MemoryMapFileAccess(FileChannel fc, int channelSize, int /*long?*/ bufferSize) { |
78 fileChannel = fc; | 84 fileChannel = fc; |
79 size = channelSize; | 85 size = channelSize; |
80 memBufferSize = bufferSize; | 86 memBufferSize = bufferSize; |
81 } | 87 } |
82 | 88 |
84 public boolean isEmpty() { | 90 public boolean isEmpty() { |
85 return position + (buffer == null ? 0 : buffer.position()) >= size; | 91 return position + (buffer == null ? 0 : buffer.position()) >= size; |
86 } | 92 } |
87 | 93 |
88 @Override | 94 @Override |
89 public long length() { | 95 public int length() { |
90 return size; | 96 return size; |
91 } | 97 } |
92 | 98 |
93 @Override | 99 @Override |
94 public DataAccess reset() throws IOException { | 100 public DataAccess reset() throws IOException { |
95 seek(0); | 101 seek(0); |
96 return this; | 102 return this; |
97 } | 103 } |
98 | 104 |
99 @Override | 105 @Override |
100 public void seek(long offset) { | 106 public void seek(int offset) { |
101 assert offset >= 0; | 107 assert offset >= 0; |
102 // offset may not necessarily be further than current position in the file (e.g. rewind) | 108 // offset may not necessarily be further than current position in the file (e.g. rewind) |
103 if (buffer != null && /*offset is within buffer*/ offset >= position && (offset - position) < buffer.limit()) { | 109 if (buffer != null && /*offset is within buffer*/ offset >= position && (offset - position) < buffer.limit()) { |
104 buffer.position((int) (offset - position)); | 110 buffer.position((int) (offset - position)); |
105 } else { | 111 } else { |
179 } | 185 } |
180 | 186 |
181 // (almost) regular file access - FileChannel and buffers. | 187 // (almost) regular file access - FileChannel and buffers. |
182 private static class FileAccess extends DataAccess { | 188 private static class FileAccess extends DataAccess { |
183 private FileChannel fileChannel; | 189 private FileChannel fileChannel; |
184 private final long size; | 190 private final int size; |
185 private ByteBuffer buffer; | 191 private ByteBuffer buffer; |
186 private long bufferStartInFile = 0; // offset of this.buffer in the file. | 192 private int bufferStartInFile = 0; // offset of this.buffer in the file. |
187 | 193 |
188 public FileAccess(FileChannel fc, long channelSize, int bufferSizeHint, boolean useDirect) { | 194 public FileAccess(FileChannel fc, int channelSize, int bufferSizeHint, boolean useDirect) { |
189 fileChannel = fc; | 195 fileChannel = fc; |
190 size = channelSize; | 196 size = channelSize; |
191 final int capacity = size < bufferSizeHint ? (int) size : bufferSizeHint; | 197 final int capacity = size < bufferSizeHint ? size : bufferSizeHint; |
192 buffer = useDirect ? ByteBuffer.allocateDirect(capacity) : ByteBuffer.allocate(capacity); | 198 buffer = useDirect ? ByteBuffer.allocateDirect(capacity) : ByteBuffer.allocate(capacity); |
193 buffer.flip(); // or .limit(0) to indicate it's empty | 199 buffer.flip(); // or .limit(0) to indicate it's empty |
194 } | 200 } |
195 | 201 |
196 @Override | 202 @Override |
197 public boolean isEmpty() { | 203 public boolean isEmpty() { |
198 return bufferStartInFile + buffer.position() >= size; | 204 return bufferStartInFile + buffer.position() >= size; |
199 } | 205 } |
200 | 206 |
201 @Override | 207 @Override |
202 public long length() { | 208 public int length() { |
203 return size; | 209 return size; |
204 } | 210 } |
205 | 211 |
206 @Override | 212 @Override |
207 public DataAccess reset() throws IOException { | 213 public DataAccess reset() throws IOException { |
208 seek(0); | 214 seek(0); |
209 return this; | 215 return this; |
210 } | 216 } |
211 | 217 |
212 @Override | 218 @Override |
213 public void seek(long offset) throws IOException { | 219 public void seek(int offset) throws IOException { |
214 if (offset > size) { | 220 if (offset > size) { |
215 throw new IllegalArgumentException(); | 221 throw new IllegalArgumentException(); |
216 } | 222 } |
217 if (offset < bufferStartInFile + buffer.limit() && offset >= bufferStartInFile) { | 223 if (offset < bufferStartInFile + buffer.limit() && offset >= bufferStartInFile) { |
218 buffer.position((int) (offset - bufferStartInFile)); | 224 buffer.position((int) (offset - bufferStartInFile)); |