1 /* 2 * Copyright 2021 The Netty Project 3 * 4 * The Netty Project licenses this file to you under the Apache License, 5 * version 2.0 (the "License"); you may not use this file except in compliance 6 * with the License. You may obtain a copy of the License at: 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 package io.netty5.buffer.api; 17 18 import io.netty5.buffer.api.internal.ArcDrop; 19 import io.netty5.buffer.api.internal.LeakDetection; 20 import io.netty5.buffer.api.internal.MemoryManagerLoader; 21 import io.netty5.buffer.api.internal.MemoryManagerOverride; 22 import io.netty5.buffer.api.internal.WrappingAllocation; 23 import io.netty5.util.Resource; 24 import io.netty5.util.SafeCloseable; 25 import io.netty5.util.internal.UnstableApi; 26 import io.netty5.util.internal.logging.InternalLogger; 27 import io.netty5.util.internal.logging.InternalLoggerFactory; 28 29 import java.util.Optional; 30 import java.util.ServiceConfigurationError; 31 import java.util.ServiceLoader.Provider; 32 import java.util.function.Consumer; 33 import java.util.function.Function; 34 import java.util.function.Supplier; 35 import java.util.stream.Stream; 36 37 /** 38 * The choice of {@code MemoryManager} implementation also determines the choice of {@link Buffer} implementation. 39 * It is the MemoryManager that implement memory allocation, and how to wrap the allocated memory in a {@link Buffer} 40 * interface. 41 * 42 * @apiNote This is a low-level, {@linkplain UnstableApi unstable}, API that is used for 43 * {@link BufferAllocator BufferAllocator} implementations to build upon. 44 * The methods in this interface are unsafe, because they can be used to violate the safety guarantees of the 45 * {@link Buffer} API, and potentially also the safety guarantees of the JVM. 46 */ 47 @UnstableApi 48 public interface MemoryManager { 49 /** 50 * Get the default, or currently configured, memory managers instance. 51 * @return A MemoryManagers instance. 52 */ 53 static MemoryManager instance() { 54 return MemoryManagerOverride.configuredOrDefaultManager(); 55 } 56 57 /** 58 * Register a callback that will be called whenever a {@link Buffer} instance is leaked. 59 * <p> 60 * Be mindful that the callback must be fast, and not take any locks or call any blocking methods, 61 * as this might interfere with the garbage collectors reference processing and cleaning. 62 * <p> 63 * This also applies to callbacks that perform logging. 64 * In these cases, asynchronous logging should be preferred, for the avoidance of blocking calls and IO. 65 * <p> 66 * If the same callback object is registered multiple times, it will only be informed once for each leak, 67 * but each of the associated {@link SafeCloseable} objects will need to be closed before the callback is removed. 68 * 69 * @param callback The callback that will be called when a buffer leak is detected. 70 * @return An {@link SafeCloseable} instance that, when closed, removes the given callback again. 71 */ 72 @UnstableApi 73 static SafeCloseable onLeakDetected(Consumer<LeakInfo> callback) { 74 return LeakDetection.onLeakDetected(callback); 75 } 76 77 /** 78 * Temporarily override the default configured memory managers instance. 79 * <p> 80 * Calls to {@link #instance()} from within the given supplier will get the given managers instance. 81 * 82 * @param manager Override the default configured managers instance with this instance. 83 * @param supplier The supplier function to be called while the override is in place. 84 * @param <T> The result type from the supplier. 85 * @return The result from the supplier. 86 */ 87 static <T> T using(MemoryManager manager, Supplier<T> supplier) { 88 return MemoryManagerOverride.using(manager, supplier); 89 } 90 91 /** 92 * Get a stream of all available memory managers. 93 * 94 * @return A stream of providers of memory managers instances. 95 */ 96 static Stream<Provider<MemoryManager>> availableManagers() { 97 return MemoryManagerLoader.stream(); 98 } 99 100 /** 101 * Find a {@link MemoryManager} implementation by its {@linkplain #implementationName() implementation name}. 102 * 103 * @param implementationName The named implementation to look for. 104 * @return A {@link MemoryManager} implementation, if any was found. 105 */ 106 static Optional<MemoryManager> lookupImplementation(String implementationName) { 107 return availableManagers() 108 .flatMap(provider -> { 109 try { 110 return Stream.ofNullable(provider.get()); 111 } catch (ServiceConfigurationError | Exception e) { 112 InternalLogger logger = InternalLoggerFactory.getInstance(MemoryManager.class); 113 if (logger.isTraceEnabled()) { 114 logger.debug("Failed to load a MemoryManager implementation.", e); 115 } else { 116 logger.debug("Failed to load a MemoryManager implementation: " + e.getMessage()); 117 } 118 return Stream.empty(); 119 } 120 }) 121 .filter(impl -> implementationName.equals(impl.implementationName())) 122 .findFirst(); 123 } 124 125 /** 126 * Create a new on-heap {@link Buffer} instance that directly wraps the given array. 127 * <p> 128 * This is <em>unsafe</em> because it allows the memory (the array) to be aliased (multiple references to the same 129 * memory) in an uncontrolled way. 130 * <p> 131 * The returned buffer will be {@linkplain Buffer#readOnly() read-only}, but changes to the byte array will be 132 * reflected in the buffers contents. 133 * <p> 134 * <strong>Note:</strong> Wrapping buffers created with this method are not subject to leak detection, and if they 135 * are garbage collected without being {@linkplain Buffer#close() closed} first, then no callback will be issued 136 * to any {@linkplain #onLeakDetected(Consumer) on-leak callback handler}. 137 * 138 * @param array The byte array that will be embedded in the created buffer. 139 * @return A buffer that wraps the given byte array 140 */ 141 @UnstableApi 142 static Buffer unsafeWrap(byte[] array) { 143 MemoryManager manager = instance(); 144 ManagedBufferAllocator allocator = new ManagedBufferAllocator(manager, false); 145 WrappingAllocation allocationType = new WrappingAllocation(array); 146 Buffer buffer = manager.allocateShared(allocator, array.length, ArcDrop::wrap, allocationType); 147 buffer.skipWritableBytes(array.length); 148 return buffer.makeReadOnly(); 149 } 150 151 /** 152 * Allocates a shared buffer. "Shared" is the normal type of buffer, and means the buffer permit concurrent access 153 * from multiple threads, within the limited thread-safety guarantees of the {@link Buffer} interface. 154 * 155 * @param allocatorControl Call-back interface for controlling the {@linkplain BufferAllocator allocator} that 156 * requested the allocation of this buffer. 157 * @param size The size of the buffer to allocate. This size is assumed to be valid for the implementation. 158 * @param dropDecorator A function to decorate the memory managers {@link Drop} instance. 159 * The {@link Drop} instance returned by this function will be used when the buffer is 160 * {@linkplain Resource#close() closed}. 161 * @param allocationType The type of allocation to perform. 162 * Typically, one of the {@linkplain StandardAllocationTypes}. 163 * @return A {@link Buffer} instance with the given configuration. 164 * @throws IllegalArgumentException For unknown {@link AllocationType}s. 165 */ 166 Buffer allocateShared(AllocatorControl allocatorControl, long size, 167 Function<Drop<Buffer>, Drop<Buffer>> dropDecorator, 168 AllocationType allocationType); 169 170 /** 171 * Allocates a constant buffer based on the given parent. A "constant" buffer is conceptually similar to a read-only 172 * buffer, but the implementation may share the underlying memory across multiple buffer instance - something that 173 * is normally not allowed by the API. This allows efficient implementation of the 174 * {@link BufferAllocator#constBufferSupplier(byte[])} method. 175 * <p> 176 * <strong>Note:</strong> The const-parent buffer must be allocated by this memory manager. 177 * 178 * @param readOnlyConstParent The read-only parent buffer for which a const buffer should be created. The parent 179 * buffer is allocated in the usual way, with 180 * {@link #allocateShared(AllocatorControl, long, Function, AllocationType)}, 181 * initialised with contents, and then made {@linkplain Buffer#makeReadOnly() read-only}. 182 * @return A const buffer with the same size, contents, and read-only state of the given parent buffer. 183 */ 184 Buffer allocateConstChild(Buffer readOnlyConstParent); 185 186 /** 187 * Create an object that represents the internal memory of the given buffer. 188 * 189 * @param buf The buffer to unwrap. 190 * @return The internal memory of the given buffer, as an opaque object. 191 */ 192 Object unwrapRecoverableMemory(Buffer buf); 193 194 /** 195 * Recover the memory from a prior {@link #unwrapRecoverableMemory(Buffer)} call, and wrap it in a {@link Buffer} 196 * instance. 197 * 198 * @param allocatorControl The allocator control to attach to the buffer. 199 * @param recoverableMemory The opaque memory to use for the buffer. 200 * @param drop The {@link Drop} instance to use when the buffer is {@linkplain Resource#close() closed}. 201 * @return A {@link Buffer} instance backed by the given recovered memory. 202 */ 203 Buffer recoverMemory(AllocatorControl allocatorControl, Object recoverableMemory, Drop<Buffer> drop); 204 205 /** 206 * Produces a slice of the given internal memory representation object. 207 * 208 * @param memory The opaque memory to slice. 209 * @param offset The offset into the memory to slice from. 210 * @param length The length of the slice. 211 * @return A new opaque memory instance that represents the given slice of the original. 212 */ 213 Object sliceMemory(Object memory, int offset, int length); 214 215 /** 216 * Overwrite the given recoverable memory object with zeroes, erasing all data that it contains. 217 * <p> 218 * This is used by the {@link SensitiveBufferAllocator} to erase data on deallocation. 219 * 220 * @param memory The memory that should be overwritten. 221 */ 222 void clearMemory(Object memory); 223 224 /** 225 * Get the name for this implementation, which can be used for finding this particular implementation via the 226 * {@link #lookupImplementation(String)} method. 227 * 228 * @return The name of this memory managers implementation. 229 */ 230 String implementationName(); 231 }