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 }