View Javadoc
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.internal;
17  
18  import io.netty5.buffer.api.MemoryManager;
19  import io.netty5.buffer.api.bytebuffer.ByteBufferMemoryManager;
20  import io.netty5.buffer.api.unsafe.UnsafeMemoryManager;
21  import io.netty5.util.internal.PlatformDependent;
22  import io.netty5.util.internal.logging.InternalLogger;
23  import io.netty5.util.internal.logging.InternalLoggerFactory;
24  
25  import java.util.Collections;
26  import java.util.IdentityHashMap;
27  import java.util.Map;
28  import java.util.Optional;
29  import java.util.concurrent.atomic.AtomicInteger;
30  import java.util.function.Supplier;
31  
32  public final class MemoryManagerOverride {
33      private static final MemoryManager DEFAULT = createDefaultMemoryManagerInstance();
34      private static final AtomicInteger OVERRIDES_AVAILABLE = new AtomicInteger();
35      private static final Map<Thread, MemoryManager> OVERRIDES = Collections.synchronizedMap(new IdentityHashMap<>());
36  
37      private MemoryManagerOverride() {
38      }
39  
40      private static MemoryManager createDefaultMemoryManagerInstance() {
41          String systemProperty = "io.netty5.buffer.api.MemoryManager";
42          String configured = System.getProperty(systemProperty);
43          InternalLogger logger = InternalLoggerFactory.getInstance(MemoryManagerOverride.class);
44          if (configured != null) {
45              Optional<MemoryManager> candidateManager = MemoryManager.lookupImplementation(configured);
46              if (candidateManager.isPresent()) {
47                  logger.debug("{} configured: {}", systemProperty, configured);
48                  return candidateManager.get();
49              } else {
50                  MemoryManager fallback = new ByteBufferMemoryManager();
51                  logger.debug("{} requested implementation is unavailable: {} (using default {} implementation instead)",
52                               systemProperty, configured, fallback.implementationName());
53                  return fallback;
54              }
55          }
56          if (PlatformDependent.hasUnsafe() && PlatformDependent.hasDirectBufferNoCleanerConstructor()) {
57              try {
58                  return new UnsafeMemoryManager();
59              } catch (Exception exception) {
60                  // We will just fall back to ByteBuffer based memory management if Unsafe fails.
61                  logger.warn("Both sun.misc.Unsafe and DirectByteBuffer-without-Cleaner constructor are available, " +
62                              "yet an UnsafeMemoryManager could not be created.", exception);
63              }
64          }
65          return new ByteBufferMemoryManager();
66      }
67  
68      public static MemoryManager configuredOrDefaultManager() {
69          return configuredOrDefaultManager(DEFAULT);
70      }
71  
72      public static MemoryManager configuredOrDefaultManager(MemoryManager desiredDefault) {
73          if (OVERRIDES_AVAILABLE.get() > 0) {
74              return OVERRIDES.getOrDefault(Thread.currentThread(), desiredDefault);
75          }
76          return desiredDefault;
77      }
78  
79      public static <T> T using(MemoryManager managers, Supplier<T> supplier) {
80          Thread thread = Thread.currentThread();
81          OVERRIDES.put(thread, managers);
82          OVERRIDES_AVAILABLE.incrementAndGet();
83          try {
84              return supplier.get();
85          } finally {
86              OVERRIDES_AVAILABLE.decrementAndGet();
87              OVERRIDES.remove(thread);
88          }
89      }
90  }