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