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