Remove atomix.storage.buffer
[controller.git] / third-party / atomix / utils / src / main / java / io / atomix / utils / memory / MappedMemoryAllocator.java
1 /*
2  * Copyright 2017-present Open Networking Foundation
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package io.atomix.utils.memory;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.io.RandomAccessFile;
21 import java.nio.channels.FileChannel;
22 import java.util.concurrent.atomic.AtomicInteger;
23
24 /**
25  * Mapped memory allocator.
26  * <p>
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}.
31  *
32  * @author <a href="http://github.com/kuujo">Jordan Halterman</a>
33  */
34 public class MappedMemoryAllocator implements MemoryAllocator<MappedMemory> {
35   public static final FileChannel.MapMode DEFAULT_MAP_MODE = FileChannel.MapMode.READ_WRITE;
36
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;
42
43   public MappedMemoryAllocator(File file) {
44     this(file, DEFAULT_MAP_MODE, 0);
45   }
46
47   public MappedMemoryAllocator(File file, FileChannel.MapMode mode) {
48     this(file, mode, 0);
49   }
50
51   public MappedMemoryAllocator(File file, FileChannel.MapMode mode, long offset) {
52     this(createFile(file, mode), mode, offset);
53   }
54
55   public MappedMemoryAllocator(RandomAccessFile file, FileChannel.MapMode mode, long offset) {
56     if (file == null) {
57       throw new NullPointerException("file cannot be null");
58     }
59     if (mode == null) {
60       throw new NullPointerException("mode cannot be null");
61     }
62     if (offset < 0) {
63       throw new IllegalArgumentException("offset cannot be negative");
64     }
65     this.file = file;
66     this.channel = this.file.getChannel();
67     this.mode = mode;
68     this.offset = offset;
69   }
70
71   private static RandomAccessFile createFile(File file, FileChannel.MapMode mode) {
72     if (file == null) {
73       throw new NullPointerException("file cannot be null");
74     }
75     if (mode == null) {
76       mode = DEFAULT_MAP_MODE;
77     }
78     try {
79       return new RandomAccessFile(file, parseMode(mode));
80     } catch (IOException e) {
81       throw new RuntimeException(e);
82     }
83   }
84
85   private static String parseMode(FileChannel.MapMode mode) {
86     if (mode == FileChannel.MapMode.READ_ONLY) {
87       return "r";
88     } else if (mode == FileChannel.MapMode.READ_WRITE) {
89       return "rw";
90     }
91     throw new IllegalArgumentException("unsupported map mode");
92   }
93
94   @Override
95   public MappedMemory allocate(int size) {
96     try {
97       if (file.length() < size) {
98         file.setLength(size);
99       }
100       referenceCount.incrementAndGet();
101       return new MappedMemory(channel.map(mode, offset, size), this);
102     } catch (IOException e) {
103       throw new RuntimeException(e);
104     }
105   }
106
107   @Override
108   public MappedMemory reallocate(MappedMemory memory, int size) {
109     MappedMemory newMemory = allocate(size);
110     memory.free();
111     return newMemory;
112   }
113
114   public void close() {
115     try {
116       file.close();
117     } catch (IOException e) {
118       throw new RuntimeException(e);
119     }
120   }
121
122   /**
123    * Releases a reference from the allocator.
124    */
125   void release() {
126     if (referenceCount.decrementAndGet() == 0) {
127       close();
128     }
129   }
130
131 }