View Javadoc
1   /*
2    * Copyright 2012 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  
17  package io.netty.buffer;
18  
19  import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
20  
21  import io.netty.util.ResourceLeakDetector;
22  import io.netty.util.ResourceLeakTracker;
23  import io.netty.util.internal.MathUtil;
24  import io.netty.util.internal.PlatformDependent;
25  import io.netty.util.internal.StringUtil;
26  
27  /**
28   * Skeletal {@link ByteBufAllocator} implementation to extend.
29   */
30  public abstract class AbstractByteBufAllocator implements ByteBufAllocator {
31      static final int DEFAULT_INITIAL_CAPACITY = 256;
32      static final int DEFAULT_MAX_CAPACITY = Integer.MAX_VALUE;
33      static final int DEFAULT_MAX_COMPONENTS = 16;
34      static final int CALCULATE_THRESHOLD = 1048576 * 4; // 4 MiB page
35  
36      static {
37          ResourceLeakDetector.addExclusions(AbstractByteBufAllocator.class, "toLeakAwareBuffer");
38      }
39  
40      protected static ByteBuf toLeakAwareBuffer(ByteBuf buf) {
41          ResourceLeakTracker<ByteBuf> leak = AbstractByteBuf.leakDetector.track(buf);
42          if (leak != null) {
43              if (AbstractByteBuf.leakDetector.isRecordEnabled()) {
44                  buf = new AdvancedLeakAwareByteBuf(buf, leak);
45              } else {
46                  buf = new SimpleLeakAwareByteBuf(buf, leak);
47              }
48          }
49          return buf;
50      }
51  
52      protected static CompositeByteBuf toLeakAwareBuffer(CompositeByteBuf buf) {
53          ResourceLeakTracker<ByteBuf> leak = AbstractByteBuf.leakDetector.track(buf);
54          if (leak != null) {
55              if (AbstractByteBuf.leakDetector.isRecordEnabled()) {
56                  buf = new AdvancedLeakAwareCompositeByteBuf(buf, leak);
57              } else {
58                  buf = new SimpleLeakAwareCompositeByteBuf(buf, leak);
59              }
60          }
61          return buf;
62      }
63  
64      private final boolean directByDefault;
65      private final ByteBuf emptyBuf;
66  
67      /**
68       * Instance use heap buffers by default
69       */
70      protected AbstractByteBufAllocator() {
71          this(false);
72      }
73  
74      /**
75       * Create new instance
76       *
77       * @param preferDirect {@code true} if {@link #buffer(int)} should try to allocate a direct buffer rather than
78       *                     a heap buffer
79       */
80      protected AbstractByteBufAllocator(boolean preferDirect) {
81          directByDefault = preferDirect && PlatformDependent.canReliabilyFreeDirectBuffers();
82          emptyBuf = new EmptyByteBuf(this);
83      }
84  
85      @Override
86      public ByteBuf buffer() {
87          if (directByDefault) {
88              return directBuffer();
89          }
90          return heapBuffer();
91      }
92  
93      @Override
94      public ByteBuf buffer(int initialCapacity) {
95          if (directByDefault) {
96              return directBuffer(initialCapacity);
97          }
98          return heapBuffer(initialCapacity);
99      }
100 
101     @Override
102     public ByteBuf buffer(int initialCapacity, int maxCapacity) {
103         if (directByDefault) {
104             return directBuffer(initialCapacity, maxCapacity);
105         }
106         return heapBuffer(initialCapacity, maxCapacity);
107     }
108 
109     @Override
110     public ByteBuf ioBuffer() {
111         if (PlatformDependent.canReliabilyFreeDirectBuffers() || isDirectBufferPooled()) {
112             return directBuffer(DEFAULT_INITIAL_CAPACITY);
113         }
114         return heapBuffer(DEFAULT_INITIAL_CAPACITY);
115     }
116 
117     @Override
118     public ByteBuf ioBuffer(int initialCapacity) {
119         if (PlatformDependent.canReliabilyFreeDirectBuffers() || isDirectBufferPooled()) {
120             return directBuffer(initialCapacity);
121         }
122         return heapBuffer(initialCapacity);
123     }
124 
125     @Override
126     public ByteBuf ioBuffer(int initialCapacity, int maxCapacity) {
127         if (PlatformDependent.canReliabilyFreeDirectBuffers() || isDirectBufferPooled()) {
128             return directBuffer(initialCapacity, maxCapacity);
129         }
130         return heapBuffer(initialCapacity, maxCapacity);
131     }
132 
133     @Override
134     public ByteBuf heapBuffer() {
135         return heapBuffer(DEFAULT_INITIAL_CAPACITY, DEFAULT_MAX_CAPACITY);
136     }
137 
138     @Override
139     public ByteBuf heapBuffer(int initialCapacity) {
140         return heapBuffer(initialCapacity, DEFAULT_MAX_CAPACITY);
141     }
142 
143     @Override
144     public ByteBuf heapBuffer(int initialCapacity, int maxCapacity) {
145         if (initialCapacity == 0 && maxCapacity == 0) {
146             return emptyBuf;
147         }
148         validate(initialCapacity, maxCapacity);
149         return newHeapBuffer(initialCapacity, maxCapacity);
150     }
151 
152     @Override
153     public ByteBuf directBuffer() {
154         return directBuffer(DEFAULT_INITIAL_CAPACITY, DEFAULT_MAX_CAPACITY);
155     }
156 
157     @Override
158     public ByteBuf directBuffer(int initialCapacity) {
159         return directBuffer(initialCapacity, DEFAULT_MAX_CAPACITY);
160     }
161 
162     @Override
163     public ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
164         if (initialCapacity == 0 && maxCapacity == 0) {
165             return emptyBuf;
166         }
167         validate(initialCapacity, maxCapacity);
168         return newDirectBuffer(initialCapacity, maxCapacity);
169     }
170 
171     @Override
172     public CompositeByteBuf compositeBuffer() {
173         if (directByDefault) {
174             return compositeDirectBuffer();
175         }
176         return compositeHeapBuffer();
177     }
178 
179     @Override
180     public CompositeByteBuf compositeBuffer(int maxNumComponents) {
181         if (directByDefault) {
182             return compositeDirectBuffer(maxNumComponents);
183         }
184         return compositeHeapBuffer(maxNumComponents);
185     }
186 
187     @Override
188     public CompositeByteBuf compositeHeapBuffer() {
189         return compositeHeapBuffer(DEFAULT_MAX_COMPONENTS);
190     }
191 
192     @Override
193     public CompositeByteBuf compositeHeapBuffer(int maxNumComponents) {
194         return toLeakAwareBuffer(new CompositeByteBuf(this, false, maxNumComponents));
195     }
196 
197     @Override
198     public CompositeByteBuf compositeDirectBuffer() {
199         return compositeDirectBuffer(DEFAULT_MAX_COMPONENTS);
200     }
201 
202     @Override
203     public CompositeByteBuf compositeDirectBuffer(int maxNumComponents) {
204         return toLeakAwareBuffer(new CompositeByteBuf(this, true, maxNumComponents));
205     }
206 
207     private static void validate(int initialCapacity, int maxCapacity) {
208         checkPositiveOrZero(initialCapacity, "initialCapacity");
209         if (initialCapacity > maxCapacity) {
210             throw new IllegalArgumentException(String.format(
211                     "initialCapacity: %d (expected: not greater than maxCapacity(%d)",
212                     initialCapacity, maxCapacity));
213         }
214     }
215 
216     /**
217      * Create a heap {@link ByteBuf} with the given initialCapacity and maxCapacity.
218      */
219     protected abstract ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity);
220 
221     /**
222      * Create a direct {@link ByteBuf} with the given initialCapacity and maxCapacity.
223      */
224     protected abstract ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity);
225 
226     @Override
227     public String toString() {
228         return StringUtil.simpleClassName(this) + "(directByDefault: " + directByDefault + ')';
229     }
230 
231     @Override
232     public int calculateNewCapacity(int minNewCapacity, int maxCapacity) {
233         checkPositiveOrZero(minNewCapacity, "minNewCapacity");
234         if (minNewCapacity > maxCapacity) {
235             throw new IllegalArgumentException(String.format(
236                     "minNewCapacity: %d (expected: not greater than maxCapacity(%d)",
237                     minNewCapacity, maxCapacity));
238         }
239         final int threshold = CALCULATE_THRESHOLD; // 4 MiB page
240 
241         if (minNewCapacity == threshold) {
242             return threshold;
243         }
244 
245         // If over threshold, do not double but just increase by threshold.
246         if (minNewCapacity > threshold) {
247             int newCapacity = minNewCapacity / threshold * threshold;
248             if (newCapacity > maxCapacity - threshold) {
249                 newCapacity = maxCapacity;
250             } else {
251                 newCapacity += threshold;
252             }
253             return newCapacity;
254         }
255 
256         // 64 <= newCapacity is a power of 2 <= threshold
257         final int newCapacity = MathUtil.findNextPositivePowerOfTwo(Math.max(minNewCapacity, 64));
258         return Math.min(newCapacity, maxCapacity);
259     }
260 }