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 }