eu.stratosphere.nephele.io.channels.LocalChannelWithAccessInfo Maven / Gradle / Ivy
/***********************************************************************************************************************
* Copyright (C) 2010-2013 by the Stratosphere project (http://stratosphere.eu)
*
* Licensed 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 eu.stratosphere.nephele.io.channels;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
final class LocalChannelWithAccessInfo implements ChannelWithAccessInfo {
/**
* The logging object.
*/
private static final Log LOG = LogFactory.getLog(LocalChannelWithAccessInfo.class);
private final File file;
private final FileChannel channel;
private final AtomicLong reservedWritePosition;
private final AtomicInteger referenceCounter;
private final AtomicBoolean deleteOnClose;
LocalChannelWithAccessInfo(final File file, final boolean deleteOnClose) throws IOException {
this.file = file;
this.channel = new RandomAccessFile(file, "rw").getChannel();
this.reservedWritePosition = new AtomicLong(0L);
this.referenceCounter = new AtomicInteger(0);
this.deleteOnClose = new AtomicBoolean(deleteOnClose);
}
@Override
public FileChannel getChannel() {
return this.channel;
}
@Override
public FileChannel getAndIncrementReferences() {
if (incrementReferences()) {
return this.channel;
} else {
return null;
}
}
@Override
public ChannelWithPosition reserveWriteSpaceAndIncrementReferences(final int spaceToReserve) {
if (incrementReferences()) {
return new ChannelWithPosition(this.channel, this.reservedWritePosition.getAndAdd(spaceToReserve));
} else {
return null;
}
}
@Override
public int decrementReferences() {
int current = this.referenceCounter.get();
while (true) {
if (current <= 0) {
// this is actually an error case, because the channel was deleted before
throw new IllegalStateException("The references to the file were already at zero.");
}
if (current == 1) {
// this call decrements to zero, so mark it as deleted
if (this.referenceCounter.compareAndSet(current, Integer.MIN_VALUE)) {
current = 0;
break;
}
} else if (this.referenceCounter.compareAndSet(current, current - 1)) {
current = current - 1;
break;
}
current = this.referenceCounter.get();
}
if (current > 0) {
return current;
} else if (current == 0) {
// delete the channel
this.referenceCounter.set(Integer.MIN_VALUE);
this.reservedWritePosition.set(Long.MIN_VALUE);
try {
this.channel.close();
} catch (IOException ioex) {
if (LOG.isErrorEnabled()) {
LOG.error("Error while closing spill file for file buffers: " + ioex.getMessage(), ioex);
}
}
if (this.deleteOnClose.get()) {
this.file.delete();
}
return current;
} else {
throw new IllegalStateException("The references to the file were already at zero.");
}
}
@Override
public boolean incrementReferences() {
int current = this.referenceCounter.get();
while (true) {
// check whether it was disposed in the meantime
if (current < 0) {
return false;
}
// atomically check and increment
if (this.referenceCounter.compareAndSet(current, current + 1)) {
return true;
}
current = this.referenceCounter.get();
}
}
@Override
public void disposeSilently() {
this.referenceCounter.set(Integer.MIN_VALUE);
this.reservedWritePosition.set(Long.MIN_VALUE);
if (this.channel.isOpen()) {
try {
this.channel.close();
} catch (Throwable t) {
}
}
if (this.deleteOnClose.get()) {
this.file.delete();
}
}
@Override
public void updateDeleteOnCloseFlag(final boolean deleteOnClose) {
this.deleteOnClose.compareAndSet(true, deleteOnClose);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy