comparison src/org/tmatesoft/hg/internal/DataAccessProvider.java @ 338:3cfa4d908fc9

Add options to control DataAccessProvider, allow to turn off use of file memory mapping in particular to solve potential sharing violation (os file handle gets released on MappedByteByffer being GC'd, not on FileChannel.close())
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Tue, 15 Nov 2011 04:47:03 +0100
parents 981f9f50bb6c
children 0ae53c32ecef 31a719b9f95e
comparison
equal deleted inserted replaced
337:f377f833b780 338:3cfa4d908fc9
30 * 30 *
31 * @author Artem Tikhomirov 31 * @author Artem Tikhomirov
32 * @author TMate Software Ltd. 32 * @author TMate Software Ltd.
33 */ 33 */
34 public class DataAccessProvider { 34 public class DataAccessProvider {
35 /**
36 * Boundary to start using file memory mapping instead of regular file access, in bytes.
37 * Set to 0 to indicate mapping files into memory shall not be used.
38 * If set to -1, file of any size would be mapped in memory.
39 */
40 public static final String CFG_PROPERTY_MAPIO_LIMIT = "hg4j.dap.mapio_limit";
41 public static final String CFG_PROPERTY_MAPIO_BUFFER_SIZE = "hg4j.dap.mapio_buffer";
42 public static final String CFG_PROPERTY_FILE_BUFFER_SIZE = "hg4j.dap.file_buffer";
35 43
36 private final int mapioMagicBoundary; 44 private final int mapioMagicBoundary;
37 private final int bufferSize; 45 private final int bufferSize;
38 private final SessionContext context; 46 private final SessionContext context;
39 47
40 public DataAccessProvider(SessionContext ctx) { 48 public DataAccessProvider(SessionContext ctx) {
41 this(ctx, 100 * 1024, 8 * 1024); 49 this(ctx, getConfigOption(ctx, CFG_PROPERTY_MAPIO_LIMIT, 100 * 1024), getConfigOption(ctx, CFG_PROPERTY_FILE_BUFFER_SIZE, 8 * 1024));
50 }
51
52 private static int getConfigOption(SessionContext ctx, String optName, int defaultValue) {
53 Object v = ctx.getProperty(optName, defaultValue);
54 if (false == v instanceof Number) {
55 v = Integer.parseInt(v.toString());
56 }
57 return ((Number) v).intValue();
42 } 58 }
43 59
44 public DataAccessProvider(SessionContext ctx, int mapioBoundary, int regularBufferSize) { 60 public DataAccessProvider(SessionContext ctx, int mapioBoundary, int regularBufferSize) {
45 context = ctx; 61 context = ctx;
46 mapioMagicBoundary = mapioBoundary; 62 mapioMagicBoundary = mapioBoundary == 0 ? Integer.MAX_VALUE : mapioBoundary;
47 bufferSize = regularBufferSize; 63 bufferSize = regularBufferSize;
48 } 64 }
49 65
50 public DataAccess create(File f) { 66 public DataAccess create(File f) {
51 if (!f.exists()) { 67 if (!f.exists()) {
57 if (fc.size() - flen != 0) { 73 if (fc.size() - flen != 0) {
58 throw new HgBadStateException("Files greater than 2Gb are not yet supported"); 74 throw new HgBadStateException("Files greater than 2Gb are not yet supported");
59 } 75 }
60 if (flen > mapioMagicBoundary) { 76 if (flen > mapioMagicBoundary) {
61 // TESTS: bufLen of 1024 was used to test MemMapFileAccess 77 // TESTS: bufLen of 1024 was used to test MemMapFileAccess
62 return new MemoryMapFileAccess(fc, flen, mapioMagicBoundary); 78 return new MemoryMapFileAccess(fc, flen, getConfigOption(context, CFG_PROPERTY_MAPIO_BUFFER_SIZE, 100*1024 /*same as default boundary*/));
63 } else { 79 } else {
64 // XXX once implementation is more or less stable, 80 // XXX once implementation is more or less stable,
65 // may want to try ByteBuffer.allocateDirect() to see 81 // may want to try ByteBuffer.allocateDirect() to see
66 // if there's any performance gain. 82 // if there's any performance gain.
67 boolean useDirectBuffer = false; 83 boolean useDirectBuffer = false; // XXX might be another config option
68 // TESTS: bufferSize of 100 was used to check buffer underflow states when readBytes reads chunks bigger than bufSize 84 // TESTS: bufferSize of 100 was used to check buffer underflow states when readBytes reads chunks bigger than bufSize
69 return new FileAccess(fc, flen, bufferSize, useDirectBuffer); 85 return new FileAccess(fc, flen, bufferSize, useDirectBuffer);
70 } 86 }
71 } catch (IOException ex) { 87 } catch (IOException ex) {
72 // unlikely to happen, we've made sure file exists. 88 // unlikely to happen, we've made sure file exists.
81 private final int size; 97 private final int size;
82 private long position = 0; // always points to buffer's absolute position in the file 98 private long position = 0; // always points to buffer's absolute position in the file
83 private final int memBufferSize; 99 private final int memBufferSize;
84 private MappedByteBuffer buffer; 100 private MappedByteBuffer buffer;
85 101
86 public MemoryMapFileAccess(FileChannel fc, int channelSize, int /*long?*/ bufferSize) { 102 public MemoryMapFileAccess(FileChannel fc, int channelSize, int bufferSize) {
87 fileChannel = fc; 103 fileChannel = fc;
88 size = channelSize; 104 size = channelSize;
89 memBufferSize = bufferSize; 105 memBufferSize = bufferSize > channelSize ? channelSize : bufferSize; // no reason to waste memory more than there's data
90 } 106 }
91 107
92 @Override 108 @Override
93 public boolean isEmpty() { 109 public boolean isEmpty() {
94 return position + (buffer == null ? 0 : buffer.position()) >= size; 110 return position + (buffer == null ? 0 : buffer.position()) >= size;