/* * Copyright 2016 higherfrequencytrading.com * * 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 net.openhft.lang.io; import net.openhft.lang.io.FileLifecycleListener.EventType; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.lang.reflect.InvocationTargetException; import java.nio.ByteOrder; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; /* * Merge memory mapped files: * - net.openhft.lang.io.MappedFile * - net.openhft.lang.io.MappedStore * - net.openhft.chronicle.VanillaFile */ public class VanillaMappedFile implements VanillaMappedResource { private final File path; private final FileChannel fileChannel; private final VanillaMappedMode mode; private final long size; private final FileLifecycleListener fileLifecycleListener; public VanillaMappedFile(final File path, VanillaMappedMode mode) throws IOException { this(path, mode, -1, FileLifecycleListener.FileLifecycleListeners.IGNORE); } public VanillaMappedFile(final File path, VanillaMappedMode mode, long size, FileLifecycleListener fileLifecycleListener) throws IOException { this.path = path; this.mode = mode; this.size = size; this.fileChannel = fileChannel(path, mode, this.size, fileLifecycleListener); this.fileLifecycleListener = fileLifecycleListener; } private static FileChannel fileChannel(final File path, VanillaMappedMode mapMode, long size, FileLifecycleListener fileLifecycleListener) throws IOException { long start = System.nanoTime(); FileChannel fileChannel = null; try { final RandomAccessFile raf = new RandomAccessFile(path, mapMode.stringValue()); if (size > 0 && raf.length() != size) { if (mapMode.mapValue() != FileChannel.MapMode.READ_WRITE) { throw new IOException("Cannot resize file to " + size + " as mode is not READ_WRITE"); } raf.setLength(size); } fileChannel = raf.getChannel(); } catch (Exception e) { throw wrap(e); } fileLifecycleListener.onEvent(EventType.NEW, path, System.nanoTime() - start); return fileChannel; } private static IOException wrap(Throwable throwable) { if(throwable instanceof InvocationTargetException) { throwable = throwable.getCause(); } else if(throwable instanceof IOException) { return (IOException)throwable; } return new IOException(throwable); } public static VanillaMappedFile readWrite(final File path) throws IOException { return new VanillaMappedFile(path,VanillaMappedMode.RW); } public static VanillaMappedFile readWrite(final File path, long size) throws IOException { return new VanillaMappedFile(path, VanillaMappedMode.RW, size, FileLifecycleListener.FileLifecycleListeners.IGNORE); } public static VanillaMappedFile readOnly(final File path) throws IOException { return new VanillaMappedFile(path,VanillaMappedMode.RO); } // ************************************************************************* // Helpers // ************************************************************************* public static VanillaMappedFile readOnly(final File path, long size) throws IOException { return new VanillaMappedFile(path, VanillaMappedMode.RO, size, FileLifecycleListener.FileLifecycleListeners.IGNORE); } public static VanillaMappedBytes readWriteBytes(final File path, long size) throws IOException { return readWriteBytes(path, size, -1); } public static VanillaMappedBytes readWriteBytes(final File path, long size, long index) throws IOException { return readWriteBytes(path, size, index, FileLifecycleListener.FileLifecycleListeners.IGNORE); } public static VanillaMappedBytes readWriteBytes(final File path, long size, long index, FileLifecycleListener fileLifecycleListener) throws IOException { VanillaMappedFile vmf = new VanillaMappedFile(path, VanillaMappedMode.RW, -1, fileLifecycleListener); return new VanillaMappedBytes(path, vmf.map(0,size), index, vmf.fileChannel, fileLifecycleListener); } public VanillaMappedBytes bytes(long address, long size) throws IOException { return new VanillaMappedBytes(this.path, map(address, size), -1, null, this.fileLifecycleListener); } public VanillaMappedBytes bytes(long address, long size, long index) throws IOException { return new VanillaMappedBytes(this.path, map(address, size), index, null, this.fileLifecycleListener); } @Override public String path() { return this.path.getAbsolutePath(); } @Override public long size() { try { return this.fileChannel.size(); } catch (IOException e) { return 0; } } @Override public synchronized void close() throws IOException { if (this.fileChannel.isOpen()) { long start = System.nanoTime(); this.fileChannel.close(); this.fileLifecycleListener.onEvent(EventType.CLOSE, this.path, System.nanoTime() - start); } } private synchronized MappedByteBuffer map(long address, long size) throws IOException { long start = System.nanoTime(); MappedByteBuffer buffer = this.fileChannel.map(this.mode.mapValue(), address, size); buffer.order(ByteOrder.nativeOrder()); fileLifecycleListener.onEvent(EventType.MMAP, path, System.nanoTime() - start); return buffer; } }