Mercurial > hg4j
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 |