/* * Copyright 2014 Ruediger Moeller. * * 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 org.nustaq.offheap.structs; import org.nustaq.offheap.bytez.Bytez; import org.nustaq.offheap.bytez.BytezAllocator; import org.nustaq.offheap.bytez.malloc.MallocBytezAllocator; import org.nustaq.offheap.bytez.onheap.HeapBytezAllocator; import org.nustaq.offheap.structs.structtypes.StructArray; import org.nustaq.offheap.structs.unsafeimpl.FSTStructFactory; import org.nustaq.serialization.util.FSTUtil; /** * Date: 04.10.13 * Time: 20:51 * implemenst struct instances. By default heap is used to obtain underlying byte arrays. * By supplementing a BytezAllocator, structs can also be created offheap. */ public class FSTStructAllocator { public static boolean DUMP_ALLOC = false; protected int chunkSize; protected Bytez chunk; protected int chunkIndex; BytezAllocator alloc = new HeapBytezAllocator(); int chunkObjCount = 0; // BytezAllocator alloc = new MallocBytezAllocator(); protected FSTStructAllocator() { } /** * @param b * @param index * @return a new allocated pointer matching struct type stored in b[] */ public static FSTStruct createStructPointer(Bytez b, int index) { return FSTStructFactory.getInstance().getStructPointerByOffset(b, index).detach(); } /** * @param onHeapTemplate * @param <T> * @return return a byte array based struct instance for given on-heap template. Allocates a new byte[] with each call */ public static <T extends FSTStruct> T toStruct(T onHeapTemplate) { return FSTStructFactory.getInstance().toStruct(onHeapTemplate); } /** * @param b * @param index * @return a pointer matching struct type stored in b[] from the thread local cache */ public static FSTStruct getVolatileStructPointer(Bytez b, int index) { return (FSTStruct) FSTStructFactory.getInstance().getStructPointerByOffset(b, index); } /** * @param clazz * @param <C> * @return a newly allocated pointer matching. use baseOn to point it to a meaningful location */ public static <C extends FSTStruct> C newPointer(Class<C> clazz) { try { return (C) allocInstance(clazz); } catch (Exception e) { throw new RuntimeException(e); } } protected static <C extends FSTStruct> Object allocInstance(Class<C> clazz) throws Exception { return FSTUtil.getUnsafe().allocateInstance(FSTStructFactory.getInstance().getProxyClass(clazz)); // return FSTStructFactory.getInstance().getProxyClass(clazz).newInstance(); } /** * Create a Heap-Byte Array Structallocator with given chunk size in bytes. If allocated structs are larger than the given size, a new bytearray is * created for the allocation. * @param chunkSizeBytes */ public FSTStructAllocator(int chunkSizeBytes) { this.chunkSize = chunkSizeBytes; } /** * optionally uses another allocator (e.g. for Real Off Heap with MallocBytez) * * Warning: Currently there is not automatic free for OffHeap Bytez, so only use for * statically allocated structures. You can call free() to release all offheap structures * allocated by this instance, however you'll get crashes if there are still references * from y<our application to the free'd memory. * A good approach is to keep only large static structures OffHeap (refdata, buffers) so there is no need for freeing. * Also IO related single big blobs apply for Off Heap. * * This does not apply for HeapBytez, which are handled by GC as usual. Here a chunk is freed, if there is no Struct * Object in the Heap referencing the unerlying byte array. If you use large chunk sizes, this can be a problem * because a single stuct can prevent a large chunk from being freed. So in general for On-Heap use as small * as possible chunks, off heap use large chunk sizes and free manually. * * @param chunkSizeBytes - set to a reasonable size, memory is allocated in thes chunk sizes. If very small, each * struct alloc will result in its individual chunk being allocated. * @param allocator */ public FSTStructAllocator(int chunkSizeBytes, BytezAllocator allocator ) { this.chunkSize = chunkSizeBytes; alloc = allocator; } /** * create a new struct array of same type as template * @param size * @return */ public <X extends FSTStruct> StructArray<X> newArray(int size, X templ) { return newArray(size,templ,alloc); } /** * create a new struct array of same type as template * @param size * @return */ public <X extends FSTStruct> StructArray<X> newArray(int size, X templ, BytezAllocator alloc) { StructArray<X> aTemplate = new StructArray<X>(size, templ); int siz = getFactory().calcStructSize(aTemplate); try { if ( siz < chunkSize ) return newStruct(aTemplate); else { return getFactory().toStruct(aTemplate,alloc); } } catch (Throwable e) { throw new RuntimeException(e); } } /** * frees associated offheap memory, in case making objects created INVALID (Access violation!). * is a noop for on heap byte array allocator */ public void free() { alloc.freeAll(); } /** * allocate a Struct instance from an arbitrary template instance. * * @param aTemplate * @param <S> * @return */ public <S extends FSTStruct> S newStruct(S aTemplate) { return newStruct(aTemplate,alloc); } public <S extends FSTStruct> S newStruct(S aTemplate, BytezAllocator alloc) { aTemplate = getFactory().toStruct(aTemplate); if (aTemplate.getByteSize()>=chunkSize) return (S)aTemplate.createCopy(); int byteSize = aTemplate.getByteSize(); synchronized (this) { if (chunk == null || chunkIndex+byteSize >= chunk.length()) { chunk = alloc.alloc(chunkSize); if ( DUMP_ALLOC ) System.out.println("[Allocator] sum allocated "+MallocBytezAllocator.alloced.get()/1024/1024+" MB"); chunkIndex = 0; chunkObjCount = 0; } // FSTStruct.unsafe.copyMemory(aTemplate.___bytes, aTemplate.___offset, chunk, FSTStruct.bufoff + chunkIndex, byteSize); aTemplate.___bytes.copyTo(chunk, chunkIndex, aTemplate.___offset, byteSize); S res = (S) getFactory().createStructWrapper(chunk, chunkIndex ); chunkIndex+=byteSize; chunkObjCount++; return res; } } protected FSTStructFactory getFactory() { return FSTStructFactory.getInstance(); } }