001/*
002 * Copyright 2013 Alex Kasko (alexkasko.com)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.alexkasko.unsafe.offheap;
018
019import com.alexkasko.unsafe.bytearray.ByteArrayTool;
020
021import java.lang.reflect.InvocationTargetException;
022
023/**
024 * <p>Allocates an area of off-heap memory that is not a subject to GC.
025 * Default implementation uses {@code sun.misc.Unsafe}, with all operations guarded with {@code assert}
026 * boundary checks.
027 * With assert enabled in runtime ({@code -ea} java switch) {@link AssertionError}
028 * will be thrown on illegal input. Without assertions illegal input will crash JVM.
029 *
030 * <p>Fallback implementation uses {@link java.nio.ByteBuffer#allocateDirect(int)} that may (OpenJDK)
031 * or may not (Dalvik) use {@code sun.misc.Unsafe} under the hood.
032 * Note: only unsafe implementation ({@link #allocateMemoryUnsafe(long)}) may use memory areas longer than {@code Integer.MAX_VALUE}
033 *
034 * <p>Unsafe implementation uses native endianness (LE on most platforms). Fallback implementation uses Little Endian byte order.
035 *
036 * <p>Provides methods to access allocated memory. More complex data structures (off-heap quasi-objects) may be
037 * constructed wrapping this class, see {@link com.alexkasko.unsafe.offheaplong.OffHeapLongArray}.
038 *
039 * <p>Memory may be freed manually calling {@link #free()} (thread-safe and may be called safely more than one time),
040 * or it will be freed when {@link OffHeapMemory} instance itself will be garbage collected.
041 *
042 * @author alexkasko
043 * Date: 1/14/13
044 */
045public abstract class OffHeapMemory {
046    /**
047     * Allocates memory using {@code sun.misc.Unsafe} if it's proper implementation is available.
048     * Allocates using {@link java.nio.ByteBuffer#allocateDirect(int)} otherwise.
049     *
050     * @param bytes amount of memory to allocate
051     * @return {@code OffHeapMemory} instance
052     */
053    public static OffHeapMemory allocateMemory(long bytes) {
054        try {
055            return allocateMemoryUnsafe(bytes);
056        } catch (Exception e) {
057            // check OOM Error and rethrow it
058            if(e instanceof InvocationTargetException &&
059                    null != e.getCause() &&
060                    e.getCause() instanceof OutOfMemoryError) {
061                throw new RuntimeException(e);
062            }
063            return allocateMemoryDirect(bytes);
064        }
065    }
066
067    /**
068     * Allocates memory using {@code sun.misc.Unsafe}
069     *
070     * @param bytes amount of memory to allocate
071     * @return {@code OffHeapMemory} instance
072     * @throws Exception if proper {@code sun.misc.Unsafe} not available
073     */
074    public static OffHeapMemory allocateMemoryUnsafe(long bytes) throws Exception {
075        try {
076            Class<? extends OffHeapMemory> unsafeMaClass = OffHeapMemory.class
077                    .getClassLoader()
078                    .loadClass(OffHeapMemory.class.getPackage().getName() + ".UnsafeOffHeapMemory")
079                    .asSubclass(OffHeapMemory.class);
080            return unsafeMaClass.getDeclaredConstructor(long.class).newInstance(bytes);
081        } catch (Throwable t) {
082            throw t instanceof Exception ? (Exception) t : new RuntimeException(t);
083        }
084    }
085
086    /**
087     * Allocates memory using {@link java.nio.ByteBuffer#allocateDirect(int)}
088     *
089     * @param bytes amount of memory to allocate
090     * @return {@code OffHeapMemory} instance
091     */
092    public static OffHeapMemory allocateMemoryDirect(long bytes) {
093        return new DirectOffHeapMemory(bytes);
094    }
095
096    /**
097     * Allocates memory using byte array
098     *
099     * @param bytes amount of memory to allocate
100     * @param bt byte array tool to use for on-heap memory management
101     * @return {@code OffHeapMemory} instance
102     */
103    public static OffHeapMemory allocateMemoryOnHeap(ByteArrayTool bt, long bytes) {
104        return new OnHeapMemory(bt, bytes);
105    }
106
107    /**
108     * Whether current implementation uses {@code sun.misc.Unsafe}
109     *
110     * @return whether unsafe
111     */
112    public abstract boolean isUnsafe();
113
114    /**
115     * Returns length of allocated memory area
116     *
117     * @return length of allocated memory area
118     */
119    public abstract long length();
120
121    /**
122     * Frees allocated memory, may be called multiple times from any thread
123     */
124    public abstract void free();
125
126    /**
127     * Copies byte array contents into memory area
128     *
129     * @param offset memory area offset
130     * @param buffer source byte array
131     * @param bufferOffset position in byte array
132     * @param bytes bytes length to copy
133     */
134    public abstract void put(long offset, byte[] buffer, int bufferOffset, int bytes);
135
136    /**
137     * Copies byte array contents into memory area
138     *
139     * @param offset memory area offset
140     * @param buffer source byte array
141     */
142    public abstract void put(long offset, byte[] buffer);
143
144    /**
145     * Copies part of memory area into byte array
146     *
147     * @param offset memory area offset
148     * @param buffer destination byte array
149     * @param bufferOffset position in byte array
150     * @param bytes bytes length to copy
151     */
152    public abstract void get(long offset, byte[] buffer, int bufferOffset, int bytes);
153
154    /**
155     * Copies part of memory area into byte array
156     *
157     * @param offset memory area offset
158     * @param buffer destination byte array
159     */
160    public abstract void get(long offset, byte[] buffer);
161
162    /**
163     * Gets byte from memory area
164     *
165     * @param offset memory area offset
166     * @return byte value
167     */
168    public abstract byte getByte(long offset);
169
170    /**
171     * Puts byte into memory area
172     *
173     * @param offset memory area offset
174     * @param value byte value
175     */
176    public abstract void putByte(long offset, byte value);
177
178    /**
179     * Gets one byte (stored as one signed byte), converts it to unsigned
180     * and returns it as short
181     *
182     * @param offset memory area offset
183     * @return unsigned byte as short
184     */
185    public abstract short getUnsignedByte(long offset);
186
187    /**
188     * Puts short with value from 0 to 255 inclusive into memory area as one
189     * signed byte
190     *
191     * @param offset memory area offset
192     * @param value unsigned byte as short
193     */
194    public abstract void putUnsignedByte(long offset, short value);
195
196    /**
197     * Gets two bytes from memory area as short
198     *
199     * @param offset memory area offset
200     * @return short value
201     */
202    public abstract short getShort(long offset);
203
204    /**
205     * Puts short into memory area as two bytes
206     *
207     * @param offset memory area offset
208     * @param value short value
209     */
210    public abstract void putShort(long offset, short value);
211
212    /**
213     * Gets unsigned short from memory area (stored as two bytes) and returns it as int
214     *
215     * @param offset memory area offset
216     * @return unsigned short as int
217     */
218    public abstract int getUnsignedShort(long offset);
219
220    /**
221     * Puts int with value from 0 to 65535 inclusive into memory are as two bytes
222     *
223     * @param offset memory area offset
224     * @param value unsigned short as int
225     */
226    public abstract void putUnsignedShort(long offset, int value);
227
228    /**
229     * Gets four bytes from memory area as int
230     *
231     * @param offset memory area offset
232     * @return int value
233     */
234    public abstract int getInt(long offset);
235
236    /**
237     * Puts int into memory area as four bytes
238     *
239     * @param offset memory area offset
240     * @param value int value
241     */
242    public abstract void putInt(long offset, int value);
243
244    /**
245     * Gets unsigned int (stored as 4 bytes) and returns it as long
246     *
247     * @param offset memory area offset
248     * @return unsigned int as long
249     */
250    public abstract long getUnsignedInt(long offset);
251
252    /**
253     * Puts long value from 0 to 4294967295 inclusive into memory area as four bytes
254     *
255     * @param offset memory area offset
256     * @param value unsigned int as long
257     */
258    public abstract void putUnsignedInt(long offset, long value);
259
260    /**
261     * Gets eight bytes from memory area as long
262     *
263     * @param offset memory area offset
264     * @return long value
265     */
266    public abstract long getLong(long offset);
267
268    /**
269     * Puts long into memory area as eight bytes
270     *
271     * @param offset memory area offset
272     * @param value long value
273     */
274    public abstract void putLong(long offset, long value);
275
276    /**
277     * Copies memory from this instance's area into another instance's area
278     *
279     * @param offset this memory area offset
280     * @param destination destination memory area
281     * @param destOffset destination memory area offset
282     * @param bytes memory length in bytes to copy
283     */
284    public abstract void copy(long offset, OffHeapMemory destination, long destOffset, long bytes);
285
286    /**
287     * Creates new instance of {@link OffHeapMemory}
288     * and copies there current instance contents
289     *
290     * @return new instance of {@link OffHeapMemory}
291     */
292    @Override
293    public abstract OffHeapMemory clone();
294}