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 } |