comparison src/org/tmatesoft/hg/internal/DataAccessProvider.java @ 619:868b2ffdcd5c

Close FIS, not FileChannel, to clear both references to FileDescriptor right away
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 17 May 2013 22:04:23 +0200
parents 7c0d2ce340b8
children 12a4f60ea972
comparison
equal deleted inserted replaced
618:7c0d2ce340b8 619:868b2ffdcd5c
77 public DataAccess createReader(File f, boolean shortRead) { 77 public DataAccess createReader(File f, boolean shortRead) {
78 if (!f.exists()) { 78 if (!f.exists()) {
79 return new DataAccess(); 79 return new DataAccess();
80 } 80 }
81 try { 81 try {
82 FileChannel fc = new FileInputStream(f).getChannel(); // FIXME SHALL CLOSE FIS, not only channel 82 FileInputStream fis = new FileInputStream(f);
83 long flen = fc.size(); 83 long flen = f.length();
84 if (!shortRead && flen > mapioMagicBoundary) { 84 if (!shortRead && flen > mapioMagicBoundary) {
85 // TESTS: bufLen of 1024 was used to test MemMapFileAccess 85 // TESTS: bufLen of 1024 was used to test MemMapFileAccess
86 return new MemoryMapFileAccess(fc, flen, mapioBufSize, context.getLog()); 86 return new MemoryMapFileAccess(fis, flen, mapioBufSize, context.getLog());
87 } else { 87 } else {
88 // XXX once implementation is more or less stable, 88 // XXX once implementation is more or less stable,
89 // may want to try ByteBuffer.allocateDirect() to see 89 // may want to try ByteBuffer.allocateDirect() to see
90 // if there's any performance gain. 90 // if there's any performance gain.
91 boolean useDirectBuffer = false; // XXX might be another config option 91 boolean useDirectBuffer = false; // XXX might be another config option
92 // TESTS: bufferSize of 100 was used to check buffer underflow states when readBytes reads chunks bigger than bufSize 92 // TESTS: bufferSize of 100 was used to check buffer underflow states when readBytes reads chunks bigger than bufSize
93 return new FileAccess(fc, flen, bufferSize, useDirectBuffer, context.getLog()); 93 return new FileAccess(fis, flen, bufferSize, useDirectBuffer, context.getLog());
94 } 94 }
95 } catch (IOException ex) { 95 } catch (IOException ex) {
96 // unlikely to happen, we've made sure file exists. 96 // unlikely to happen, we've made sure file exists.
97 context.getLog().dump(getClass(), Error, ex, null); 97 context.getLog().dump(getClass(), Error, ex, null);
98 } 98 }
107 // to control the moment transaction gets into play and whether it fails or not 107 // to control the moment transaction gets into play and whether it fails or not
108 return new TransactionAwareFileSerializer(tr, f); 108 return new TransactionAwareFileSerializer(tr, f);
109 } 109 }
110 110
111 private static class MemoryMapFileAccess extends DataAccess { 111 private static class MemoryMapFileAccess extends DataAccess {
112 private FileInputStream fileStream;
112 private FileChannel fileChannel; 113 private FileChannel fileChannel;
113 private long position = 0; // always points to buffer's absolute position in the file 114 private long position = 0; // always points to buffer's absolute position in the file
114 private MappedByteBuffer buffer; 115 private MappedByteBuffer buffer;
115 private final long size; 116 private final long size;
116 private final int memBufferSize; 117 private final int memBufferSize;
117 private final LogFacility logFacility; 118 private final LogFacility logFacility;
118 119
119 public MemoryMapFileAccess(FileChannel fc, long channelSize, int bufferSize, LogFacility log) { 120 public MemoryMapFileAccess(FileInputStream fis, long channelSize, int bufferSize, LogFacility log) {
120 fileChannel = fc; 121 fileStream = fis;
122 fileChannel = fis.getChannel();
121 size = channelSize; 123 size = channelSize;
122 logFacility = log; 124 logFacility = log;
123 memBufferSize = bufferSize > channelSize ? (int) channelSize : bufferSize; // no reason to waste memory more than there's data 125 memBufferSize = bufferSize > channelSize ? (int) channelSize : bufferSize; // no reason to waste memory more than there's data
124 } 126 }
125 127
239 } 241 }
240 242
241 @Override 243 @Override
242 public void done() { 244 public void done() {
243 buffer = null; 245 buffer = null;
244 if (fileChannel != null) { 246 if (fileStream != null) {
245 try { 247 new FileUtils(logFacility).closeQuietly(fileStream);
246 fileChannel.close(); 248 fileStream = null;
247 } catch (IOException ex) { 249 fileChannel = null; // channel is closed together with stream
248 logFacility.dump(getClass(), Warn, ex, null);
249 }
250 fileChannel = null;
251 } 250 }
252 } 251 }
253 } 252 }
254 253
255 // (almost) regular file access - FileChannel and buffers. 254 // (almost) regular file access - FileChannel and buffers.
256 private static class FileAccess extends DataAccess { 255 private static class FileAccess extends DataAccess {
256 private FileInputStream fileStream;
257 private FileChannel fileChannel; 257 private FileChannel fileChannel;
258 private ByteBuffer buffer; 258 private ByteBuffer buffer;
259 private long bufferStartInFile = 0; // offset of this.buffer in the file. 259 private long bufferStartInFile = 0; // offset of this.buffer in the file.
260 private final long size; 260 private final long size;
261 private final LogFacility logFacility; 261 private final LogFacility logFacility;
262 262
263 public FileAccess(FileChannel fc, long channelSize, int bufferSizeHint, boolean useDirect, LogFacility log) { 263 public FileAccess(FileInputStream fis, long channelSize, int bufferSizeHint, boolean useDirect, LogFacility log) {
264 fileChannel = fc; 264 fileStream = fis;
265 fileChannel = fis.getChannel();
265 size = channelSize; 266 size = channelSize;
266 logFacility = log; 267 logFacility = log;
267 final int capacity = size < bufferSizeHint ? (int) size : bufferSizeHint; 268 final int capacity = size < bufferSizeHint ? (int) size : bufferSizeHint;
268 buffer = useDirect ? ByteBuffer.allocateDirect(capacity) : ByteBuffer.allocate(capacity); 269 buffer = useDirect ? ByteBuffer.allocateDirect(capacity) : ByteBuffer.allocate(capacity);
269 buffer.flip(); // or .limit(0) to indicate it's empty 270 buffer.flip(); // or .limit(0) to indicate it's empty
370 throw new IOException(); 371 throw new IOException();
371 } 372 }
372 373
373 @Override 374 @Override
374 public void done() { 375 public void done() {
375 if (buffer != null) { 376 buffer = null;
376 buffer = null; 377 if (fileStream != null) {
377 } 378 new FileUtils(logFacility).closeQuietly(fileStream);
378 if (fileChannel != null) { 379 fileStream = null;
379 try {
380 fileChannel.close();
381 } catch (IOException ex) {
382 logFacility.dump(getClass(), Warn, ex, null);
383 }
384 fileChannel = null; 380 fileChannel = null;
385 } 381 }
386 } 382 }
387 } 383 }
388 384