// Copyright © 2011-2013, Esko Luontola <www.orfjackal.net>
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0
package fi.jumi.core.ipc.buffer;
import fi.jumi.core.util.Resilient;
import javax.annotation.concurrent.NotThreadSafe;
import java.io.IOException;
import java.nio.*;
import java.nio.channels.FileChannel;
import java.nio.file.*;
import static java.nio.file.StandardOpenOption.*;
@NotThreadSafe
public class MappedByteBufferSequence implements ByteBufferSequence {
private final FileSegmenter segmenter;
private final boolean readOnly;
public static MappedByteBufferSequence readWrite(FileSegmenter segmenter) {
return new MappedByteBufferSequence(segmenter, false);
}
public static MappedByteBufferSequence readOnly(FileSegmenter segmenter) {
return new MappedByteBufferSequence(segmenter, true);
}
private MappedByteBufferSequence(FileSegmenter segmenter, boolean readOnly) {
this.segmenter = segmenter;
this.readOnly = readOnly;
}
@Override
public ByteBuffer get(int index) {
Path path = segmenter.pathOf(index);
long size = segmenter.sizeOf(index);
try {
return Resilient.tryRepeatedly(() -> tryMapFile(path, size));
} catch (IOException e) {
throw new RuntimeException("failed to map " + path, e);
}
}
private MappedByteBuffer tryMapFile(Path path, long size) throws IOException {
OpenOption[] options;
if (Files.exists(path)) {
size = Files.size(path);
if (size <= 0) {
throw new IOException("file size was " + size + " bytes");
}
options = new OpenOption[]{READ, WRITE};
} else {
// To avoid a race condition if two processes open the file concurrently,
// we use here CREATE_NEW instead of CREATE
options = new OpenOption[]{READ, WRITE, CREATE_NEW};
}
try (FileChannel fc = FileChannel.open(path, options)) {
return fc.map(mapMode(), 0, size);
}
}
private FileChannel.MapMode mapMode() {
return readOnly ? FileChannel.MapMode.READ_ONLY : FileChannel.MapMode.READ_WRITE;
}
// TODO: should read-only MappedByteBufferSequence not be able to create new segments?
}