/* * Copyright 2021 The Netty Project * * The Netty Project 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: * * https://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 io.netty5.buffer.api; import io.netty5.buffer.api.internal.MemoryManagerLoader; import io.netty5.buffer.api.internal.MemoryManagerOverride; import io.netty5.util.internal.UnstableApi; import io.netty5.util.internal.logging.InternalLogger; import io.netty5.util.internal.logging.InternalLoggerFactory; import java.lang.ref.Cleaner; import java.util.Optional; import java.util.ServiceConfigurationError; import java.util.ServiceLoader.Provider; import java.util.function.Supplier; import java.util.stream.Stream; /** * The choice of {@code MemoryManager} implementation also determines the choice of {@link Buffer} implementation. * It is the MemoryManager that implement memory allocation, and how to wrap the allocated memory in a {@link Buffer} * interface. * * @apiNote This is a low-level, {@linkplain UnstableApi unstable}, API that is used for * {@link BufferAllocator BufferAllocator} implementations to build upon. * The methods in this interface are unsafe, because they can be used to violate the safety guarantees of the * {@link Buffer} API, and potentially also the safety guarantees of the JVM. */ @UnstableApi public interface MemoryManager { /** * Get the default, or currently configured, memory managers instance. * @return A MemoryManagers instance. */ static MemoryManager instance() { return MemoryManagerOverride.configuredOrDefaultManager(); } /** * Temporarily override the default configured memory managers instance. *

* Calls to {@link #instance()} from within the given supplier will get the given managers instance. * * @param managers Override the default configured managers instance with this instance. * @param supplier The supplier function to be called while the override is in place. * @param The result type from the supplier. * @return The result from the supplier. */ static T using(MemoryManager managers, Supplier supplier) { return MemoryManagerOverride.using(managers, supplier); } /** * Get a lazy-loading stream of all available memory managers. * * @return A stream of providers of memory managers instances. */ static Stream> availableManagers() { return MemoryManagerLoader.stream(); } /** * Find a {@link MemoryManager} implementation by its {@linkplain #implementationName() implementation name}. * * @param implementationName The named implementation to look for. * @return A {@link MemoryManager} implementation, if any was found. */ static Optional lookupImplementation(String implementationName) { return availableManagers() .flatMap(provider -> { try { return Stream.ofNullable(provider.get()); } catch (ServiceConfigurationError | Exception e) { InternalLogger logger = InternalLoggerFactory.getInstance(MemoryManager.class); if (logger.isTraceEnabled()) { logger.debug("Failed to load a MemoryManager implementation.", e); } else { logger.debug("Failed to load a MemoryManager implementation: " + e.getMessage()); } return Stream.empty(); } }) .filter(impl -> implementationName.equals(impl.implementationName())) .findFirst(); } /** * Allocates a shared buffer. "Shared" is the normal type of buffer, and means the buffer permit concurrent access * from multiple threads, within the limited thread-safety guarantees of the {@link Buffer} interface. * * @param allocatorControl Call-back interface for controlling the {@linkplain BufferAllocator allocator} that * requested the allocation of this buffer. * @param size The size of the buffer to allocate. This size is assumed to be valid for the implementation. * @param drop The {@link Drop} instance to use when the buffer is {@linkplain Resource#close() closed}. * @param cleaner The {@link Cleaner} that the underlying memory should be attached to. Can be {@code null}. * @param allocationType The type of allocation to perform. * Typically, one of the {@linkplain StandardAllocationTypes}. * @return A {@link Buffer} instance with the given configuration. * @throws IllegalArgumentException For unknown {@link AllocationType}s. */ Buffer allocateShared(AllocatorControl allocatorControl, long size, Drop drop, Cleaner cleaner, AllocationType allocationType); /** * Allocates a constant buffer based on the given parent. A "constant" buffer is conceptually similar to a read-only * buffer, but the implementation may share the underlying memory across multiple buffer instance - something that * is normally not allowed by the API. This allows efficient implementation of the * {@link BufferAllocator#constBufferSupplier(byte[])} method. *

* Note: the const-parent buffer must be allocated by this memory manager. * * @param readOnlyConstParent The read-only parent buffer for which a const buffer should be created. The parent * buffer is allocated in the usual way, with * {@link #allocateShared(AllocatorControl, long, Drop, Cleaner, AllocationType)}, * initialised with contents, and then made {@linkplain Buffer#makeReadOnly() read-only}. * @return A const buffer with the same size, contents, and read-only state of the given parent buffer. */ Buffer allocateConstChild(Buffer readOnlyConstParent); /** * The buffer implementation-specific {@link Drop} implementation that will release the underlying memory. * * @return A new drop instance. */ Drop drop(); /** * Create an object that represents the internal memory of the given buffer. * * @param buf The buffer to unwrap. * @return The internal memory of the given buffer, as an opaque object. */ Object unwrapRecoverableMemory(Buffer buf); /** * Recover the memory from a prior {@link #unwrapRecoverableMemory(Buffer)} call, and wrap it in a {@link Buffer} * instance. * * @param allocatorControl The allocator control to attach to the buffer. * @param recoverableMemory The opaque memory to use for the buffer. * @param drop The {@link Drop} instance to use when the buffer is {@linkplain Resource#close() closed}. * @return A {@link Buffer} instance backed by the given recovered memory. */ Buffer recoverMemory(AllocatorControl allocatorControl, Object recoverableMemory, Drop drop); /** * Produces a slice of the given internal memory representation object. * * @param memory The opaque memory to slice. * @param offset The offset into the memory to slice from. * @param length The length of the slice. * @return A new opaque memory instance that represents the given slice of the original. */ Object sliceMemory(Object memory, int offset, int length); /** * Get the name for this implementation, which can be used for finding this particular implementation via the * {@link #lookupImplementation(String)} method. * * @return The name of this memory managers implementation. */ String implementationName(); }