View Javadoc
1   /*
2    * Copyright 2022 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License, version 2.0 (the
5    * "License"); you may not use this file except in compliance with the License. You may obtain a
6    * 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 distributed under the License
11   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing permissions and limitations under
13   * the License.
14   */
15  package io.netty5.buffer.api;
16  
17  import io.netty5.util.internal.PlatformDependent;
18  import io.netty5.util.internal.SystemPropertyUtil;
19  import io.netty5.util.internal.logging.InternalLogger;
20  import io.netty5.util.internal.logging.InternalLoggerFactory;
21  
22  import java.util.Locale;
23  import java.util.function.Supplier;
24  
25  import static io.netty5.util.internal.PlatformDependent.directBufferPreferred;
26  import static java.lang.Runtime.getRuntime;
27  
28  /**
29   * Accessor for the default, shared {@link BufferAllocator} instances.
30   * Two allocators are provided; one on-heap allocator, and one off-heap allocator.
31   * <p>
32   * These default allocators are configured via system properties.
33   * <p>
34   * These allocators cannot be {@linkplain Buffer#close() closed} directly.
35   * They will instead be disposed of when the {@link Runtime} is shutdown.
36   */
37  public final class DefaultBufferAllocators {
38      private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultBufferAllocators.class);
39      private static final BufferAllocator DEFAULT_PREFERRED_ALLOCATOR;
40      private static final BufferAllocator DEFAULT_ON_HEAP_ALLOCATOR;
41      private static final BufferAllocator DEFAULT_OFF_HEAP_ALLOCATOR;
42  
43      static {
44          String allocType = SystemPropertyUtil.get(
45                  "io.netty5.allocator.type", PlatformDependent.isAndroid() ? "unpooled" : "pooled");
46          allocType = allocType.toLowerCase(Locale.US).trim();
47          boolean directBufferPreferred = directBufferPreferred();
48  
49          final BufferAllocator onHeap;
50          final BufferAllocator offHeap;
51          if ("unpooled".equals(allocType)) {
52              onHeap = BufferAllocator.onHeapUnpooled();
53              offHeap = BufferAllocator.offHeapUnpooled();
54              logger.debug("-Dio.netty5.allocator.type: {}", allocType);
55          } else if ("pooled".equals(allocType)) {
56              onHeap = BufferAllocator.onHeapPooled();
57              offHeap = BufferAllocator.offHeapPooled();
58              logger.debug("-Dio.netty5.allocator.type: {}", allocType);
59          } else {
60              onHeap = BufferAllocator.onHeapPooled();
61              offHeap = BufferAllocator.offHeapPooled();
62              logger.debug("-Dio.netty5.allocator.type: pooled (unknown: {})", allocType);
63          }
64          getRuntime().addShutdownHook(new Thread(() -> {
65              //noinspection EmptyTryBlock
66              try (onHeap; offHeap) {
67                  // Left blank.
68              }
69          }));
70          UncloseableBufferAllocator onHeapUnclosable = new UncloseableBufferAllocator(onHeap);
71          UncloseableBufferAllocator offHeapUnclosable = new UncloseableBufferAllocator(offHeap);
72          DEFAULT_PREFERRED_ALLOCATOR = directBufferPreferred? offHeapUnclosable : onHeapUnclosable;
73          DEFAULT_ON_HEAP_ALLOCATOR = onHeapUnclosable;
74          DEFAULT_OFF_HEAP_ALLOCATOR = offHeapUnclosable;
75      }
76  
77      private DefaultBufferAllocators() {
78      }
79  
80      /**
81       * Get the preferred, shared allocator.
82       * This allocator is either on- or off-heap, and either pooling or unpooled, depending on the global configuration.
83       *
84       * @return The shared, generally preferred allocator.
85       */
86      public static BufferAllocator preferredAllocator() {
87          return DEFAULT_PREFERRED_ALLOCATOR;
88      }
89  
90      /**
91       * Get the shared on-heap allocator.
92       * This allocator always allocates on-heap buffers, and is either pooled, or unpooled.
93       *
94       * @return The shared on-heap allocator.
95       */
96      public static BufferAllocator onHeapAllocator() {
97          return DEFAULT_ON_HEAP_ALLOCATOR;
98      }
99  
100     /**
101      * Get the shared off-heap allocator.
102      * This allocator always allocates off-heap buffers, and is either pooled, or unpooled.
103      *
104      * @return The shared off-heap allocator.
105      */
106     public static BufferAllocator offHeapAllocator() {
107         return DEFAULT_OFF_HEAP_ALLOCATOR;
108     }
109 
110     private static final class UncloseableBufferAllocator implements BufferAllocator {
111         private final BufferAllocator delegate;
112 
113         UncloseableBufferAllocator(BufferAllocator delegate) {
114             this.delegate = delegate;
115         }
116 
117         @Override
118         public boolean isPooling() {
119             return delegate.isPooling();
120         }
121 
122         @Override
123         public AllocationType getAllocationType() {
124             return delegate.getAllocationType();
125         }
126 
127         @Override
128         public Buffer allocate(int size) {
129             return delegate.allocate(size);
130         }
131 
132         @Override
133         public Supplier<Buffer> constBufferSupplier(byte[] bytes) {
134             return delegate.constBufferSupplier(bytes);
135         }
136 
137         /**
138          * @throws UnsupportedOperationException Close is not supported on this allocator.
139          */
140         @Override
141         public void close() {
142             throw new UnsupportedOperationException("Global default buffer allocator can not be closed explicitly.");
143         }
144     }
145 }