Mercurial > hg4j
comparison src/org/tmatesoft/hg/internal/DataAccessProvider.java @ 425:48f993aa2f41
FIXMEs: exceptions, javadoc
| author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
|---|---|
| date | Wed, 28 Mar 2012 18:39:29 +0200 |
| parents | 6c22bdc0bdfd |
| children | 299870249a28 |
comparison
equal
deleted
inserted
replaced
| 424:6437d261048a | 425:48f993aa2f41 |
|---|---|
| 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.SessionContext; | 26 import org.tmatesoft.hg.core.SessionContext; |
| 27 import org.tmatesoft.hg.util.LogFacility; | |
| 27 | 28 |
| 28 /** | 29 /** |
| 29 * | 30 * |
| 30 * @author Artem Tikhomirov | 31 * @author Artem Tikhomirov |
| 31 * @author TMate Software Ltd. | 32 * @author TMate Software Ltd. |
| 37 * If set to -1, file of any size would be mapped in memory. | 38 * If set to -1, file of any size would be mapped in memory. |
| 38 */ | 39 */ |
| 39 public static final String CFG_PROPERTY_MAPIO_LIMIT = "hg4j.dap.mapio_limit"; | 40 public static final String CFG_PROPERTY_MAPIO_LIMIT = "hg4j.dap.mapio_limit"; |
| 40 public static final String CFG_PROPERTY_MAPIO_BUFFER_SIZE = "hg4j.dap.mapio_buffer"; | 41 public static final String CFG_PROPERTY_MAPIO_BUFFER_SIZE = "hg4j.dap.mapio_buffer"; |
| 41 public static final String CFG_PROPERTY_FILE_BUFFER_SIZE = "hg4j.dap.file_buffer"; | 42 public static final String CFG_PROPERTY_FILE_BUFFER_SIZE = "hg4j.dap.file_buffer"; |
| 43 | |
| 44 private static final int DEFAULT_MAPIO_LIMIT = 100 * 1024; // 100 kB | |
| 45 private static final int DEFAULT_FILE_BUFFER = 8 * 1024; // 8 kB | |
| 46 private static final int DEFAULT_MAPIO_BUFFER = DEFAULT_MAPIO_LIMIT; // same as default boundary | |
| 42 | 47 |
| 43 private final int mapioMagicBoundary; | 48 private final int mapioMagicBoundary; |
| 44 private final int bufferSize; | 49 private final int bufferSize; |
| 45 private final SessionContext context; | 50 private final SessionContext context; |
| 46 | 51 |
| 47 public DataAccessProvider(SessionContext ctx) { | 52 public DataAccessProvider(SessionContext ctx) { |
| 48 this(ctx, getConfigOption(ctx, CFG_PROPERTY_MAPIO_LIMIT, 100 * 1024), getConfigOption(ctx, CFG_PROPERTY_FILE_BUFFER_SIZE, 8 * 1024)); | 53 this(ctx, getConfigOption(ctx, CFG_PROPERTY_MAPIO_LIMIT, DEFAULT_MAPIO_LIMIT), getConfigOption(ctx, CFG_PROPERTY_FILE_BUFFER_SIZE, DEFAULT_FILE_BUFFER)); |
| 49 } | 54 } |
| 50 | 55 |
| 51 private static int getConfigOption(SessionContext ctx, String optName, int defaultValue) { | 56 private static int getConfigOption(SessionContext ctx, String optName, int defaultValue) { |
| 52 Object v = ctx.getProperty(optName, defaultValue); | 57 Object v = ctx.getProperty(optName, defaultValue); |
| 53 if (false == v instanceof Number) { | 58 if (false == v instanceof Number) { |
| 69 try { | 74 try { |
| 70 FileChannel fc = new FileInputStream(f).getChannel(); | 75 FileChannel fc = new FileInputStream(f).getChannel(); |
| 71 long flen = fc.size(); | 76 long flen = fc.size(); |
| 72 if (flen > mapioMagicBoundary) { | 77 if (flen > mapioMagicBoundary) { |
| 73 // TESTS: bufLen of 1024 was used to test MemMapFileAccess | 78 // TESTS: bufLen of 1024 was used to test MemMapFileAccess |
| 74 return new MemoryMapFileAccess(fc, flen, getConfigOption(context, CFG_PROPERTY_MAPIO_BUFFER_SIZE, 100*1024 /*same as default boundary*/)); | 79 int mapioBufSize = getConfigOption(context, CFG_PROPERTY_MAPIO_BUFFER_SIZE, DEFAULT_MAPIO_BUFFER); |
| 80 return new MemoryMapFileAccess(fc, flen, mapioBufSize, context.getLog()); | |
| 75 } else { | 81 } else { |
| 76 // XXX once implementation is more or less stable, | 82 // XXX once implementation is more or less stable, |
| 77 // may want to try ByteBuffer.allocateDirect() to see | 83 // may want to try ByteBuffer.allocateDirect() to see |
| 78 // if there's any performance gain. | 84 // if there's any performance gain. |
| 79 boolean useDirectBuffer = false; // XXX might be another config option | 85 boolean useDirectBuffer = false; // XXX might be another config option |
| 80 // TESTS: bufferSize of 100 was used to check buffer underflow states when readBytes reads chunks bigger than bufSize | 86 // TESTS: bufferSize of 100 was used to check buffer underflow states when readBytes reads chunks bigger than bufSize |
| 81 return new FileAccess(fc, flen, bufferSize, useDirectBuffer); | 87 return new FileAccess(fc, flen, bufferSize, useDirectBuffer, context.getLog()); |
| 82 } | 88 } |
| 83 } catch (IOException ex) { | 89 } catch (IOException ex) { |
| 84 // unlikely to happen, we've made sure file exists. | 90 // unlikely to happen, we've made sure file exists. |
| 85 context.getLog().error(getClass(), ex, null); | 91 context.getLog().error(getClass(), ex, null); |
| 86 } | 92 } |
| 87 return new DataAccess(); // non-null, empty. | 93 return new DataAccess(); // non-null, empty. |
| 88 } | 94 } |
| 89 | 95 |
| 90 private static class MemoryMapFileAccess extends DataAccess { | 96 private static class MemoryMapFileAccess extends DataAccess { |
| 91 private FileChannel fileChannel; | 97 private FileChannel fileChannel; |
| 98 private long position = 0; // always points to buffer's absolute position in the file | |
| 99 private MappedByteBuffer buffer; | |
| 92 private final long size; | 100 private final long size; |
| 93 private long position = 0; // always points to buffer's absolute position in the file | |
| 94 private final int memBufferSize; | 101 private final int memBufferSize; |
| 95 private MappedByteBuffer buffer; | 102 private final LogFacility logFacility; |
| 96 | 103 |
| 97 public MemoryMapFileAccess(FileChannel fc, long channelSize, int bufferSize) { | 104 public MemoryMapFileAccess(FileChannel fc, long channelSize, int bufferSize, LogFacility log) { |
| 98 fileChannel = fc; | 105 fileChannel = fc; |
| 99 size = channelSize; | 106 size = channelSize; |
| 107 logFacility = log; | |
| 100 memBufferSize = bufferSize > channelSize ? (int) channelSize : bufferSize; // no reason to waste memory more than there's data | 108 memBufferSize = bufferSize > channelSize ? (int) channelSize : bufferSize; // no reason to waste memory more than there's data |
| 101 } | 109 } |
| 102 | 110 |
| 103 @Override | 111 @Override |
| 104 public boolean isEmpty() { | 112 public boolean isEmpty() { |
| 200 buffer = null; | 208 buffer = null; |
| 201 if (fileChannel != null) { | 209 if (fileChannel != null) { |
| 202 try { | 210 try { |
| 203 fileChannel.close(); | 211 fileChannel.close(); |
| 204 } catch (IOException ex) { | 212 } catch (IOException ex) { |
| 205 StreamLogFacility.newDefault().debug(getClass(), ex, null); | 213 logFacility.debug(getClass(), ex, null); |
| 206 } | 214 } |
| 207 fileChannel = null; | 215 fileChannel = null; |
| 208 } | 216 } |
| 209 } | 217 } |
| 210 } | 218 } |
| 211 | 219 |
| 212 // (almost) regular file access - FileChannel and buffers. | 220 // (almost) regular file access - FileChannel and buffers. |
| 213 private static class FileAccess extends DataAccess { | 221 private static class FileAccess extends DataAccess { |
| 214 private FileChannel fileChannel; | 222 private FileChannel fileChannel; |
| 215 private final long size; | |
| 216 private ByteBuffer buffer; | 223 private ByteBuffer buffer; |
| 217 private long bufferStartInFile = 0; // offset of this.buffer in the file. | 224 private long bufferStartInFile = 0; // offset of this.buffer in the file. |
| 218 | 225 private final long size; |
| 219 public FileAccess(FileChannel fc, long channelSize, int bufferSizeHint, boolean useDirect) { | 226 private final LogFacility logFacility; |
| 227 | |
| 228 public FileAccess(FileChannel fc, long channelSize, int bufferSizeHint, boolean useDirect, LogFacility log) { | |
| 220 fileChannel = fc; | 229 fileChannel = fc; |
| 221 size = channelSize; | 230 size = channelSize; |
| 231 logFacility = log; | |
| 222 final int capacity = size < bufferSizeHint ? (int) size : bufferSizeHint; | 232 final int capacity = size < bufferSizeHint ? (int) size : bufferSizeHint; |
| 223 buffer = useDirect ? ByteBuffer.allocateDirect(capacity) : ByteBuffer.allocate(capacity); | 233 buffer = useDirect ? ByteBuffer.allocateDirect(capacity) : ByteBuffer.allocate(capacity); |
| 224 buffer.flip(); // or .limit(0) to indicate it's empty | 234 buffer.flip(); // or .limit(0) to indicate it's empty |
| 225 } | 235 } |
| 226 | 236 |
| 332 } | 342 } |
| 333 if (fileChannel != null) { | 343 if (fileChannel != null) { |
| 334 try { | 344 try { |
| 335 fileChannel.close(); | 345 fileChannel.close(); |
| 336 } catch (IOException ex) { | 346 } catch (IOException ex) { |
| 337 // FIXME/TODO log facility can be obtained from session context | 347 logFacility.debug(getClass(), ex, null); |
| 338 StreamLogFacility.newDefault().debug(getClass(), ex, null); | |
| 339 } | 348 } |
| 340 fileChannel = null; | 349 fileChannel = null; |
| 341 } | 350 } |
| 342 } | 351 } |
| 343 } | 352 } |
