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 }