2 * Copyright 2015-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.storage.buffer;
18 import io.atomix.utils.memory.Memory;
21 import java.nio.channels.FileChannel;
23 import static com.google.common.base.Preconditions.checkArgument;
28 * File buffers wrap a simple {@link java.io.RandomAccessFile} instance to provide random access to a file on local disk. All
29 * operations are delegated directly to the {@link java.io.RandomAccessFile} interface, and limitations are dependent on the
30 * semantics of the underlying file.
32 * @author <a href="http://github.com/kuujo">Jordan Halterman</a>
34 public class FileBuffer extends AbstractBuffer {
37 * Allocates a file buffer of unlimited capacity.
39 * The buffer will initially be allocated with {@code 4096} bytes. As bytes are written to the resulting buffer and
40 * the original capacity is reached, the buffer's capacity will double.
42 * @param file The file to allocate.
43 * @return The allocated buffer.
44 * @see FileBuffer#allocate(File, int)
45 * @see FileBuffer#allocate(File, int, int)
46 * @see FileBuffer#allocate(File, String, int, int)
48 public static FileBuffer allocate(File file) {
49 return allocate(file, FileBytes.DEFAULT_MODE, DEFAULT_INITIAL_CAPACITY, Integer.MAX_VALUE);
53 * Allocates a file buffer with the given initial capacity.
55 * If the underlying file is empty, the file count will expand dynamically as bytes are written to the file.
56 * The underlying {@link FileBytes} will be initialized to the nearest power of {@code 2}.
58 * @param file The file to allocate.
59 * @param initialCapacity The initial capacity of the bytes to allocate.
60 * @return The allocated buffer.
61 * @see FileBuffer#allocate(File)
62 * @see FileBuffer#allocate(File, int, int)
63 * @see FileBuffer#allocate(File, String, int, int)
65 public static FileBuffer allocate(File file, int initialCapacity) {
66 return allocate(file, FileBytes.DEFAULT_MODE, initialCapacity, Integer.MAX_VALUE);
70 * Allocates a file buffer.
72 * The underlying {@link java.io.RandomAccessFile} will be created in {@code rw} mode by default.
73 * The resulting buffer will be initialized with a capacity of {@code initialCapacity}. The underlying {@link FileBytes}
74 * will be initialized to the nearest power of {@code 2}. As bytes are written to the file the buffer's capacity will
75 * double up to {@code maxCapacity}.
77 * @param file The file to allocate.
78 * @param initialCapacity The initial capacity of the buffer.
79 * @param maxCapacity The maximum allowed capacity of the buffer.
80 * @return The allocated buffer.
81 * @see FileBuffer#allocate(File)
82 * @see FileBuffer#allocate(File, int)
83 * @see FileBuffer#allocate(File, String, int, int)
85 public static FileBuffer allocate(File file, int initialCapacity, int maxCapacity) {
86 return allocate(file, FileBytes.DEFAULT_MODE, initialCapacity, maxCapacity);
90 * Allocates a file buffer.
92 * The resulting buffer will be initialized with a capacity of {@code initialCapacity}. The underlying {@link FileBytes}
93 * will be initialized to the nearest power of {@code 2}. As bytes are written to the file the buffer's capacity will
94 * double up to {@code maxCapacity}.
96 * @param file The file to allocate.
97 * @param mode The mode in which to open the underlying {@link java.io.RandomAccessFile}.
98 * @param initialCapacity The initial capacity of the buffer.
99 * @param maxCapacity The maximum allowed capacity of the buffer.
100 * @return The allocated buffer.
101 * @see FileBuffer#allocate(File)
102 * @see FileBuffer#allocate(File, int)
103 * @see FileBuffer#allocate(File, int, int)
105 public static FileBuffer allocate(File file, String mode, int initialCapacity, int maxCapacity) {
106 checkArgument(initialCapacity <= maxCapacity, "initial capacity cannot be greater than maximum capacity");
107 return new FileBuffer(new FileBytes(file, mode, (int) Math.min(Memory.Util.toPow2(initialCapacity), maxCapacity)), 0, initialCapacity, maxCapacity);
110 private final FileBytes bytes;
112 private FileBuffer(FileBytes bytes, int offset, int initialCapacity, int maxCapacity) {
113 super(bytes, offset, initialCapacity, maxCapacity, null);
118 * Returns the underlying file object.
120 * @return The underlying file.
123 return ((FileBytes) bytes).file();
127 * Maps a portion of the underlying file into memory in {@link FileChannel.MapMode#READ_WRITE} mode
128 * starting at the current position up to the given {@code count}.
130 * @param size The count of the bytes to map into memory.
131 * @return The mapped buffer.
132 * @throws IllegalArgumentException If {@code count} is greater than the maximum allowed
133 * {@link java.nio.MappedByteBuffer} count: {@link Integer#MAX_VALUE}
135 public MappedBuffer map(int size) {
136 return map(position(), size, FileChannel.MapMode.READ_WRITE);
140 * Maps a portion of the underlying file into memory starting at the current position up to the given {@code count}.
142 * @param size The count of the bytes to map into memory.
143 * @param mode The mode in which to map the bytes into memory.
144 * @return The mapped buffer.
145 * @throws IllegalArgumentException If {@code count} is greater than the maximum allowed
146 * {@link java.nio.MappedByteBuffer} count: {@link Integer#MAX_VALUE}
148 public MappedBuffer map(int size, FileChannel.MapMode mode) {
149 return map(position(), size, mode);
153 * Maps a portion of the underlying file into memory in {@link FileChannel.MapMode#READ_WRITE} mode
154 * starting at the given {@code offset} up to the given {@code count}.
156 * @param offset The offset from which to map bytes into memory.
157 * @param size The count of the bytes to map into memory.
158 * @return The mapped buffer.
159 * @throws IllegalArgumentException If {@code count} is greater than the maximum allowed
160 * {@link java.nio.MappedByteBuffer} count: {@link Integer#MAX_VALUE}
162 public MappedBuffer map(int offset, int size) {
163 return map(offset, size, FileChannel.MapMode.READ_WRITE);
167 * Maps a portion of the underlying file into memory starting at the given {@code offset} up to the given {@code count}.
169 * @param offset The offset from which to map bytes into memory.
170 * @param size The count of the bytes to map into memory.
171 * @param mode The mode in which to map the bytes into memory.
172 * @return The mapped buffer.
173 * @throws IllegalArgumentException If {@code count} is greater than the maximum allowed
174 * {@link java.nio.MappedByteBuffer} count: {@link Integer#MAX_VALUE}
176 public MappedBuffer map(int offset, int size, FileChannel.MapMode mode) {
177 return new MappedBuffer(((FileBytes) bytes).map(offset, size, mode), 0, size, size);
181 protected void compact(int from, int to, int length) {
182 byte[] bytes = new byte[1024];
184 while (position < from + length) {
185 int size = Math.min((from + length) - position, 1024);
186 this.bytes.read(position, bytes, 0, size);
187 this.bytes.write(0, bytes, 0, size);
193 public FileBuffer duplicate() {
194 return new FileBuffer(new FileBytes(bytes.file(), bytes.mode(), bytes.size()), offset(), capacity(), maxCapacity());
198 * Duplicates the buffer using the given mode.
200 * @return The mode with which to open the duplicate buffer.
202 public FileBuffer duplicate(String mode) {
203 return new FileBuffer(new FileBytes(bytes.file(), mode, bytes.size()), offset(), capacity(), maxCapacity());
207 * Deletes the underlying file.
209 public void delete() {