| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
| * agreements. See the NOTICE file distributed with this work for additional information regarding |
| * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the License. You may obtain a |
| * copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package org.apache.geode.internal.cache.persistence; |
| |
| import java.io.File; |
| import java.io.FileDescriptor; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.RandomAccessFile; |
| import java.nio.ByteBuffer; |
| import java.nio.channels.ClosedByInterruptException; |
| import java.nio.channels.FileChannel; |
| import java.nio.channels.SeekableByteChannel; |
| |
| public class UninterruptibleRandomAccessFile { |
| private RandomAccessFile raf; |
| private final UninterruptibleFileChannelImpl channel; |
| private final File file; |
| private final String mode; |
| private boolean isClosed; |
| |
| public UninterruptibleRandomAccessFile(File file, String mode) throws FileNotFoundException { |
| this.file = file; |
| this.mode = mode; |
| raf = new RandomAccessFile(file, mode); |
| channel = new UninterruptibleFileChannelImpl(); |
| } |
| |
| public UninterruptibleFileChannel getChannel() { |
| return channel; |
| } |
| |
| public synchronized void reopen(long lastPosition) throws IOException { |
| if (isClosed) { |
| throw new IOException("Random Access File is closed"); |
| } |
| try { |
| raf.close(); |
| } catch (IOException e) { |
| // ignore |
| } |
| raf = new RandomAccessFile(file, mode); |
| raf.seek(lastPosition); |
| } |
| |
| public synchronized void close() throws IOException { |
| isClosed = true; |
| raf.close(); |
| } |
| |
| public synchronized void setLength(long newLength) throws IOException { |
| raf.setLength(newLength); |
| |
| } |
| |
| public synchronized FileDescriptor getFD() throws IOException { |
| return raf.getFD(); |
| } |
| |
| public synchronized long getFilePointer() throws IOException { |
| return raf.getFilePointer(); |
| } |
| |
| public synchronized void seek(long readPosition) throws IOException { |
| raf.seek(readPosition); |
| |
| } |
| |
| public synchronized void readFully(byte[] valueBytes) throws IOException { |
| raf.readFully(valueBytes); |
| |
| } |
| |
| public synchronized void readFully(byte[] valueBytes, int i, int valueLength) throws IOException { |
| raf.readFully(valueBytes, i, valueLength); |
| |
| } |
| |
| public synchronized long length() throws IOException { |
| return raf.length(); |
| } |
| |
| private interface FileOperation { |
| long doOp(FileChannel channel) throws IOException; |
| } |
| |
| private class UninterruptibleFileChannelImpl implements UninterruptibleFileChannel { |
| |
| private FileChannel delegate() { |
| return raf.getChannel(); |
| } |
| |
| /** |
| * Perform an operation on the file, reopening the file and redoing the operation if necessary |
| * if we are interrupted in the middle of the operation |
| */ |
| private long doUninterruptibly(FileOperation op) throws IOException { |
| boolean interrupted = false; |
| try { |
| synchronized (UninterruptibleRandomAccessFile.this) { |
| while (true) { |
| interrupted |= Thread.interrupted(); |
| FileChannel d = delegate(); |
| long lastPosition = getFilePointer(); |
| try { |
| return op.doOp(d); |
| } catch (ClosedByInterruptException e) { |
| interrupted = true; |
| reopen(lastPosition); |
| } |
| } |
| } |
| } finally { |
| if (interrupted) { |
| Thread.currentThread().interrupt(); |
| } |
| } |
| } |
| |
| @Override |
| public long read(final ByteBuffer[] dsts, final int offset, final int length) |
| throws IOException { |
| return doUninterruptibly(channel -> channel.read(dsts, offset, length)); |
| } |
| |
| @Override |
| public long read(final ByteBuffer[] dsts) throws IOException { |
| return doUninterruptibly(channel -> channel.read(dsts)); |
| } |
| |
| @Override |
| public long write(final ByteBuffer[] srcs, final int offset, final int length) |
| throws IOException { |
| return doUninterruptibly(channel -> channel.write(srcs, offset, length)); |
| } |
| |
| @Override |
| public long write(final ByteBuffer[] srcs) throws IOException { |
| return doUninterruptibly(channel -> channel.write(srcs)); |
| } |
| |
| @Override |
| public int read(final ByteBuffer dst) throws IOException { |
| return (int) doUninterruptibly(channel -> channel.read(dst)); |
| } |
| |
| @Override |
| public int write(final ByteBuffer src) throws IOException { |
| return (int) doUninterruptibly(channel -> channel.write(src)); |
| } |
| |
| @Override |
| public long position() throws IOException { |
| return doUninterruptibly(FileChannel::position); |
| } |
| |
| @Override |
| public SeekableByteChannel position(final long newPosition) throws IOException { |
| doUninterruptibly(channel -> { |
| channel.position(newPosition); |
| return 0; |
| }); |
| return this; |
| } |
| |
| @Override |
| public long size() throws IOException { |
| return doUninterruptibly(FileChannel::size); |
| } |
| |
| @Override |
| public SeekableByteChannel truncate(final long size) throws IOException { |
| doUninterruptibly(channel -> { |
| channel.truncate(size); |
| return 0; |
| }); |
| return this; |
| } |
| |
| @Override |
| public boolean isOpen() { |
| return delegate().isOpen(); |
| } |
| |
| @Override |
| public void close() throws IOException { |
| UninterruptibleRandomAccessFile.this.close(); |
| } |
| |
| @Override |
| public void force(final boolean b) throws IOException { |
| doUninterruptibly(channel -> { |
| channel.force(b); |
| return 0; |
| }); |
| } |
| |
| } |
| } |