/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.flink.core.memory; import org.apache.flink.annotation.Internal; import java.nio.ByteBuffer; import static org.apache.flink.util.Preconditions.checkNotNull; /** * A factory for memory segments. The purpose of this factory is to make sure that all memory segments * for heap data are of the same type. That way, the runtime does not mix the various specializations * of the {@link org.apache.flink.core.memory.MemorySegment}. Not mixing them has shown to be beneficial * to method specialization by the JIT and to overall performance. * * <p>Note that this factory auto-initialized to use {@link org.apache.flink.core.memory.HeapMemorySegment}, * if a request to create a segment comes before the initialization. */ @Internal public class MemorySegmentFactory { /** The factory to use */ private static volatile Factory factory; /** * Creates a new memory segment that targets the given heap memory region. * This method should be used to turn short lived byte arrays into memory segments. * * @param buffer The heap memory region. * @return A new memory segment that targets the given heap memory region. */ public static MemorySegment wrap(byte[] buffer) { ensureInitialized(); return factory.wrap(buffer); } /** * Allocates some unpooled memory and creates a new memory segment that represents * that memory. * <p> * This method is similar to {@link #allocateUnpooledSegment(int, Object)}, but the * memory segment will have null as the owner. * * @param size The size of the memory segment to allocate. * @return A new memory segment, backed by unpooled heap memory. */ public static MemorySegment allocateUnpooledSegment(int size) { return allocateUnpooledSegment(size, null); } /** * Allocates some unpooled memory and creates a new memory segment that represents * that memory. * <p> * This method is similar to {@link #allocateUnpooledSegment(int)}, but additionally sets * the owner of the memory segment. * * @param size The size of the memory segment to allocate. * @param owner The owner to associate with the memory segment. * @return A new memory segment, backed by unpooled heap memory. */ public static MemorySegment allocateUnpooledSegment(int size, Object owner) { ensureInitialized(); return factory.allocateUnpooledSegment(size, owner); } /** * Creates a memory segment that wraps the given byte array. * <p> * This method is intended to be used for components which pool memory and create * memory segments around long-lived memory regions. * * * @param memory The heap memory to be represented by the memory segment. * @param owner The owner to associate with the memory segment. * @return A new memory segment representing the given heap memory. */ public static MemorySegment wrapPooledHeapMemory(byte[] memory, Object owner) { ensureInitialized(); return factory.wrapPooledHeapMemory(memory, owner); } /** * Creates a memory segment that wraps the off-heap memory backing the given ByteBuffer. * Note that the ByteBuffer needs to be a <i>direct ByteBuffer</i>. * <p> * This method is intended to be used for components which pool memory and create * memory segments around long-lived memory regions. * * @param memory The byte buffer with the off-heap memory to be represented by the memory segment. * @param owner The owner to associate with the memory segment. * @return A new memory segment representing the given off-heap memory. */ public static MemorySegment wrapPooledOffHeapMemory(ByteBuffer memory, Object owner) { ensureInitialized(); return factory.wrapPooledOffHeapMemory(memory, owner); } // ------------------------------------------------------------------------ /** * Initializes this factory with the given concrete factory, iff it is not yet initialized. * This also checks if the factory is already initialized to the exact same concrete factory * as given. * * @param f The concrete factory to use. * @return True, if the factory is initialized with the given concrete factory, or if it was already * initialized with the exact same concrete factory. False, if it is already initialized with * a different concrete factory. */ public static boolean initializeIfNotInitialized(Factory f) { checkNotNull(f); synchronized (MemorySegmentFactory.class) { if (factory == null) { factory = f; return true; } else { return factory == f; } } } /** * Checks whether this memory segment factory has been initialized (with a type to produce). * * @return True, if the factory has been initialized, false otherwise. */ public static boolean isInitialized() { return factory != null; } /** * Gets the factory. May return null, if the factory has not been initialized. * * @return The factory, or null, if the factory has not been initialized. */ public static Factory getFactory() { return factory; } /** * Sets the factory to the {@link HeapMemorySegment#FACTORY} is no factory has been initialized, yet. */ private static void ensureInitialized() { if (factory == null) { synchronized (MemorySegmentFactory.class) { if (factory == null) { factory = HeapMemorySegment.FACTORY; } } } } // ------------------------------------------------------------------------ // Internal factory // ------------------------------------------------------------------------ /** * A concrete factory for memory segments. */ public interface Factory { /** * Creates a new memory segment that targets the given heap memory region. * * @param memory The heap memory region. * @return A new memory segment that targets the given heap memory region. */ MemorySegment wrap(byte[] memory); /** * Allocates some unpooled memory and creates a new memory segment that represents * that memory. * * @param size The size of the memory segment to allocate. * @param owner The owner to associate with the memory segment. * @return A new memory segment, backed by unpooled heap memory. */ MemorySegment allocateUnpooledSegment(int size, Object owner); /** * Creates a memory segment that wraps the given byte array. * <p> * This method is intended to be used for components which pool memory and create * memory segments around long-lived memory regions. * * * @param memory The heap memory to be represented by the memory segment. * @param owner The owner to associate with the memory segment. * @return A new memory segment representing the given heap memory. */ MemorySegment wrapPooledHeapMemory(byte[] memory, Object owner); /** * Creates a memory segment that wraps the off-heap memory backing the given ByteBuffer. * Note that the ByteBuffer needs to be a <i>direct ByteBuffer</i>. * <p> * This method is intended to be used for components which pool memory and create * memory segments around long-lived memory regions. * * @param memory The byte buffer with the off-heap memory to be represented by the memory segment. * @param owner The owner to associate with the memory segment. * @return A new memory segment representing the given off-heap memory. */ MemorySegment wrapPooledOffHeapMemory(ByteBuffer memory, Object owner); } }