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