2 * Copyright 2017-present Open Networking Foundation
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package io.atomix.utils.memory;
19 import java.io.IOException;
20 import java.io.RandomAccessFile;
21 import java.nio.channels.FileChannel;
22 import java.util.concurrent.atomic.AtomicInteger;
25 * Mapped memory allocator.
27 * The mapped memory allocator provides direct memory access to memory mapped from a file on disk. The mapped allocator
28 * supports allocating memory in any {@link FileChannel.MapMode}. Once the file is mapped and the
29 * memory has been allocated, the mapped allocator provides the memory address of the underlying
30 * {@link java.nio.MappedByteBuffer} for access via {@link sun.misc.Unsafe}.
32 * @author <a href="http://github.com/kuujo">Jordan Halterman</a>
34 public class MappedMemoryAllocator implements MemoryAllocator<MappedMemory> {
35 public static final FileChannel.MapMode DEFAULT_MAP_MODE = FileChannel.MapMode.READ_WRITE;
37 private final AtomicInteger referenceCount = new AtomicInteger();
38 private final RandomAccessFile file;
39 private final FileChannel channel;
40 private final FileChannel.MapMode mode;
41 private final long offset;
43 public MappedMemoryAllocator(File file) {
44 this(file, DEFAULT_MAP_MODE, 0);
47 public MappedMemoryAllocator(File file, FileChannel.MapMode mode) {
51 public MappedMemoryAllocator(File file, FileChannel.MapMode mode, long offset) {
52 this(createFile(file, mode), mode, offset);
55 public MappedMemoryAllocator(RandomAccessFile file, FileChannel.MapMode mode, long offset) {
57 throw new NullPointerException("file cannot be null");
60 throw new NullPointerException("mode cannot be null");
63 throw new IllegalArgumentException("offset cannot be negative");
66 this.channel = this.file.getChannel();
71 private static RandomAccessFile createFile(File file, FileChannel.MapMode mode) {
73 throw new NullPointerException("file cannot be null");
76 mode = DEFAULT_MAP_MODE;
79 return new RandomAccessFile(file, parseMode(mode));
80 } catch (IOException e) {
81 throw new RuntimeException(e);
85 private static String parseMode(FileChannel.MapMode mode) {
86 if (mode == FileChannel.MapMode.READ_ONLY) {
88 } else if (mode == FileChannel.MapMode.READ_WRITE) {
91 throw new IllegalArgumentException("unsupported map mode");
95 public MappedMemory allocate(int size) {
97 if (file.length() < size) {
100 referenceCount.incrementAndGet();
101 return new MappedMemory(channel.map(mode, offset, size), this);
102 } catch (IOException e) {
103 throw new RuntimeException(e);
108 public MappedMemory reallocate(MappedMemory memory, int size) {
109 MappedMemory newMemory = allocate(size);
114 public void close() {
117 } catch (IOException e) {
118 throw new RuntimeException(e);
123 * Releases a reference from the allocator.
126 if (referenceCount.decrementAndGet() == 0) {