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 |
