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