Mercurial > jhg
comparison src/org/tmatesoft/hg/internal/DataAccessProvider.java @ 420:6c22bdc0bdfd
Respect long offsets in revlogs
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Thu, 22 Mar 2012 22:56:01 +0100 |
| parents | bb278ccf9866 |
| children | 48f993aa2f41 |
comparison
equal
deleted
inserted
replaced
| 419:7f136a3fa671 | 420:6c22bdc0bdfd |
|---|---|
| 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 import org.tmatesoft.hg.core.SessionContext; | 26 import org.tmatesoft.hg.core.SessionContext; |
| 28 | 27 |
| 29 /** | 28 /** |
| 30 * | 29 * |
| 31 * @author Artem Tikhomirov | 30 * @author Artem Tikhomirov |
| 67 if (!f.exists()) { | 66 if (!f.exists()) { |
| 68 return new DataAccess(); | 67 return new DataAccess(); |
| 69 } | 68 } |
| 70 try { | 69 try { |
| 71 FileChannel fc = new FileInputStream(f).getChannel(); | 70 FileChannel fc = new FileInputStream(f).getChannel(); |
| 72 int flen = (int) fc.size(); | 71 long flen = fc.size(); |
| 73 if (fc.size() - flen != 0) { | |
| 74 throw new HgBadStateException("Files greater than 2Gb are not yet supported"); | |
| 75 } | |
| 76 if (flen > mapioMagicBoundary) { | 72 if (flen > mapioMagicBoundary) { |
| 77 // TESTS: bufLen of 1024 was used to test MemMapFileAccess | 73 // TESTS: bufLen of 1024 was used to test MemMapFileAccess |
| 78 return new MemoryMapFileAccess(fc, flen, getConfigOption(context, CFG_PROPERTY_MAPIO_BUFFER_SIZE, 100*1024 /*same as default boundary*/)); | 74 return new MemoryMapFileAccess(fc, flen, getConfigOption(context, CFG_PROPERTY_MAPIO_BUFFER_SIZE, 100*1024 /*same as default boundary*/)); |
| 79 } else { | 75 } else { |
| 80 // XXX once implementation is more or less stable, | 76 // XXX once implementation is more or less stable, |
| 89 context.getLog().error(getClass(), ex, null); | 85 context.getLog().error(getClass(), ex, null); |
| 90 } | 86 } |
| 91 return new DataAccess(); // non-null, empty. | 87 return new DataAccess(); // non-null, empty. |
| 92 } | 88 } |
| 93 | 89 |
| 94 // DOESN'T WORK YET | |
| 95 private static class MemoryMapFileAccess extends DataAccess { | 90 private static class MemoryMapFileAccess extends DataAccess { |
| 96 private FileChannel fileChannel; | 91 private FileChannel fileChannel; |
| 97 private final int size; | 92 private final long size; |
| 98 private long position = 0; // always points to buffer's absolute position in the file | 93 private long position = 0; // always points to buffer's absolute position in the file |
| 99 private final int memBufferSize; | 94 private final int memBufferSize; |
| 100 private MappedByteBuffer buffer; | 95 private MappedByteBuffer buffer; |
| 101 | 96 |
| 102 public MemoryMapFileAccess(FileChannel fc, int channelSize, int bufferSize) { | 97 public MemoryMapFileAccess(FileChannel fc, long channelSize, int bufferSize) { |
| 103 fileChannel = fc; | 98 fileChannel = fc; |
| 104 size = channelSize; | 99 size = channelSize; |
| 105 memBufferSize = bufferSize > channelSize ? channelSize : bufferSize; // no reason to waste memory more than there's data | 100 memBufferSize = bufferSize > channelSize ? (int) channelSize : bufferSize; // no reason to waste memory more than there's data |
| 106 } | 101 } |
| 107 | 102 |
| 108 @Override | 103 @Override |
| 109 public boolean isEmpty() { | 104 public boolean isEmpty() { |
| 110 return position + (buffer == null ? 0 : buffer.position()) >= size; | 105 return position + (buffer == null ? 0 : buffer.position()) >= size; |
| 111 } | 106 } |
| 112 | 107 |
| 113 @Override | 108 @Override |
| 109 public DataAccess reset() throws IOException { | |
| 110 longSeek(0); | |
| 111 return this; | |
| 112 } | |
| 113 | |
| 114 @Override | |
| 114 public int length() { | 115 public int length() { |
| 116 return Internals.ltoi(longLength()); | |
| 117 } | |
| 118 | |
| 119 @Override | |
| 120 public long longLength() { | |
| 115 return size; | 121 return size; |
| 116 } | 122 } |
| 117 | 123 |
| 118 @Override | 124 @Override |
| 119 public DataAccess reset() throws IOException { | 125 public void longSeek(long offset) { |
| 120 seek(0); | |
| 121 return this; | |
| 122 } | |
| 123 | |
| 124 @Override | |
| 125 public void seek(int offset) { | |
| 126 assert offset >= 0; | 126 assert offset >= 0; |
| 127 // offset may not necessarily be further than current position in the file (e.g. rewind) | 127 // offset may not necessarily be further than current position in the file (e.g. rewind) |
| 128 if (buffer != null && /*offset is within buffer*/ offset >= position && (offset - position) < buffer.limit()) { | 128 if (buffer != null && /*offset is within buffer*/ offset >= position && (offset - position) < buffer.limit()) { |
| 129 buffer.position((int) (offset - position)); | 129 // cast is ok according to check above |
| 130 buffer.position(Internals.ltoi(offset - position)); | |
| 130 } else { | 131 } else { |
| 131 position = offset; | 132 position = offset; |
| 132 buffer = null; | 133 buffer = null; |
| 133 } | 134 } |
| 135 } | |
| 136 | |
| 137 @Override | |
| 138 public void seek(int offset) { | |
| 139 longSeek(offset); | |
| 134 } | 140 } |
| 135 | 141 |
| 136 @Override | 142 @Override |
| 137 public void skip(int bytes) throws IOException { | 143 public void skip(int bytes) throws IOException { |
| 138 assert bytes >= 0; | 144 assert bytes >= 0; |
| 204 } | 210 } |
| 205 | 211 |
| 206 // (almost) regular file access - FileChannel and buffers. | 212 // (almost) regular file access - FileChannel and buffers. |
| 207 private static class FileAccess extends DataAccess { | 213 private static class FileAccess extends DataAccess { |
| 208 private FileChannel fileChannel; | 214 private FileChannel fileChannel; |
| 209 private final int size; | 215 private final long size; |
| 210 private ByteBuffer buffer; | 216 private ByteBuffer buffer; |
| 211 private int bufferStartInFile = 0; // offset of this.buffer in the file. | 217 private long bufferStartInFile = 0; // offset of this.buffer in the file. |
| 212 | 218 |
| 213 public FileAccess(FileChannel fc, int channelSize, int bufferSizeHint, boolean useDirect) { | 219 public FileAccess(FileChannel fc, long channelSize, int bufferSizeHint, boolean useDirect) { |
| 214 fileChannel = fc; | 220 fileChannel = fc; |
| 215 size = channelSize; | 221 size = channelSize; |
| 216 final int capacity = size < bufferSizeHint ? size : bufferSizeHint; | 222 final int capacity = size < bufferSizeHint ? (int) size : bufferSizeHint; |
| 217 buffer = useDirect ? ByteBuffer.allocateDirect(capacity) : ByteBuffer.allocate(capacity); | 223 buffer = useDirect ? ByteBuffer.allocateDirect(capacity) : ByteBuffer.allocate(capacity); |
| 218 buffer.flip(); // or .limit(0) to indicate it's empty | 224 buffer.flip(); // or .limit(0) to indicate it's empty |
| 219 } | 225 } |
| 220 | 226 |
| 221 @Override | 227 @Override |
| 222 public boolean isEmpty() { | 228 public boolean isEmpty() { |
| 223 return bufferStartInFile + buffer.position() >= size; | 229 return bufferStartInFile + buffer.position() >= size; |
| 224 } | 230 } |
| 225 | 231 |
| 226 @Override | 232 @Override |
| 233 public DataAccess reset() throws IOException { | |
| 234 longSeek(0); | |
| 235 return this; | |
| 236 } | |
| 237 | |
| 238 @Override | |
| 227 public int length() { | 239 public int length() { |
| 240 return Internals.ltoi(longLength()); | |
| 241 } | |
| 242 | |
| 243 @Override | |
| 244 public long longLength() { | |
| 228 return size; | 245 return size; |
| 229 } | 246 } |
| 230 | 247 |
| 231 @Override | 248 @Override |
| 232 public DataAccess reset() throws IOException { | 249 public void longSeek(long offset) throws IOException { |
| 233 seek(0); | |
| 234 return this; | |
| 235 } | |
| 236 | |
| 237 @Override | |
| 238 public void seek(int offset) throws IOException { | |
| 239 if (offset > size) { | 250 if (offset > size) { |
| 240 throw new IllegalArgumentException(String.format("Can't seek to %d for the file of size %d (buffer start:%d)", offset, size, bufferStartInFile)); | 251 throw new IllegalArgumentException(String.format("Can't seek to %d for the file of size %d (buffer start:%d)", offset, size, bufferStartInFile)); |
| 241 } | 252 } |
| 242 if (offset < bufferStartInFile + buffer.limit() && offset >= bufferStartInFile) { | 253 if (offset < bufferStartInFile + buffer.limit() && offset >= bufferStartInFile) { |
| 243 buffer.position((int) (offset - bufferStartInFile)); | 254 // cast to int is safe, we've checked we fit into buffer |
| 255 buffer.position(Internals.ltoi(offset - bufferStartInFile)); | |
| 244 } else { | 256 } else { |
| 245 // out of current buffer, invalidate it (force re-read) | 257 // out of current buffer, invalidate it (force re-read) |
| 246 // XXX or ever re-read it right away? | 258 // XXX or ever re-read it right away? |
| 247 bufferStartInFile = offset; | 259 bufferStartInFile = offset; |
| 248 buffer.clear(); | 260 buffer.clear(); |
| 250 fileChannel.position(offset); | 262 fileChannel.position(offset); |
| 251 } | 263 } |
| 252 } | 264 } |
| 253 | 265 |
| 254 @Override | 266 @Override |
| 267 public void seek(int offset) throws IOException { | |
| 268 longSeek(offset); | |
| 269 } | |
| 270 | |
| 271 @Override | |
| 255 public void skip(int bytes) throws IOException { | 272 public void skip(int bytes) throws IOException { |
| 256 final int newPos = buffer.position() + bytes; | 273 final int newPos = buffer.position() + bytes; |
| 257 if (newPos >= 0 && newPos < buffer.limit()) { | 274 if (newPos >= 0 && newPos < buffer.limit()) { |
| 258 // no need to move file pointer, just rewind/seek buffer | 275 // no need to move file pointer, just rewind/seek buffer |
| 259 buffer.position(newPos); | 276 buffer.position(newPos); |
| 260 } else { | 277 } else { |
| 261 // | 278 // |
| 262 seek(bufferStartInFile + newPos); | 279 longSeek(bufferStartInFile + newPos); |
| 263 } | 280 } |
| 264 } | 281 } |
| 265 | 282 |
| 266 private boolean fill() throws IOException { | 283 private boolean fill() throws IOException { |
| 267 if (!buffer.hasRemaining()) { | 284 if (!buffer.hasRemaining()) { |
