/* * Copyright 2015-present Open Networking Foundation * * 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 io.atomix.storage.buffer; import io.atomix.utils.memory.BufferCleaner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Files; /** * {@link ByteBuffer} based mapped bytes. */ public class MappedBytes extends ByteBufferBytes { private static final Logger LOGGER = LoggerFactory.getLogger(MappedBytes.class); /** * Allocates a mapped buffer in {@link FileChannel.MapMode#READ_WRITE} mode. *

* Memory will be mapped by opening and expanding the given {@link File} to the desired {@code count} and mapping the * file contents into memory via {@link FileChannel#map(FileChannel.MapMode, long, long)}. * * @param file The file to map into memory. If the file doesn't exist it will be automatically created. * @param size The count of the buffer to allocate (in bytes). * @return The mapped buffer. * @throws NullPointerException If {@code file} is {@code null} * @throws IllegalArgumentException If {@code count} is greater than {@link MappedBytes#MAX_SIZE} * @see #allocate(File, FileChannel.MapMode, int) */ public static MappedBytes allocate(File file, int size) { return allocate(file, FileChannel.MapMode.READ_WRITE, size); } /** * Allocates a mapped buffer. *

* Memory will be mapped by opening and expanding the given {@link File} to the desired {@code count} and mapping the * file contents into memory via {@link FileChannel#map(FileChannel.MapMode, long, long)}. * * @param file The file to map into memory. If the file doesn't exist it will be automatically created. * @param mode The mode with which to map the file. * @param size The count of the buffer to allocate (in bytes). * @return The mapped buffer. * @throws NullPointerException If {@code file} is {@code null} * @throws IllegalArgumentException If {@code count} is greater than {@link Integer#MAX_VALUE} * @see #allocate(File, int) */ public static MappedBytes allocate(File file, FileChannel.MapMode mode, int size) { return FileBytes.allocate(file, size).map(0, size, mode); } private final File file; private final RandomAccessFile randomAccessFile; private final FileChannel.MapMode mode; protected MappedBytes(File file, RandomAccessFile randomAccessFile, MappedByteBuffer buffer, FileChannel.MapMode mode) { super(buffer); this.file = file; this.randomAccessFile = randomAccessFile; this.mode = mode; } @Override protected ByteBuffer newByteBuffer(int size) { try { return randomAccessFile.getChannel().map(mode, 0, size); } catch (IOException e) { throw new RuntimeException(e); } } @Override public boolean isDirect() { return true; } @Override public Bytes flush() { ((MappedByteBuffer) buffer).force(); return this; } @Override public void close() { try { BufferCleaner.freeBuffer(buffer); } catch (Exception e) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Failed to unmap direct buffer", e); } } try { randomAccessFile.close(); } catch (IOException e) { throw new RuntimeException(e); } super.close(); } /** * Deletes the underlying file. */ public void delete() { try { close(); Files.delete(file.toPath()); } catch (IOException e) { throw new RuntimeException(e); } } private static String parseMode(FileChannel.MapMode mode) { if (mode == FileChannel.MapMode.READ_ONLY) { return "r"; } else if (mode == FileChannel.MapMode.READ_WRITE) { return "rw"; } throw new IllegalArgumentException("unsupported map mode"); } }