1 /* 2 * Copyright 2013 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 module hunt.net.buffer.ReferenceCountUtil; 17 18 import hunt.net.buffer.ReferenceCounted; 19 import hunt.logging; 20 21 22 /** 23 * Collection of method to handle objects that may implement {@link ReferenceCounted}. 24 */ 25 final class ReferenceCountUtil { 26 27 28 // static { 29 // ResourceLeakDetector.addExclusions(ReferenceCountUtil.class, "touch"); 30 // } 31 32 // /** 33 // * Try to call {@link ReferenceCounted#retain()} if the specified message implements {@link ReferenceCounted}. 34 // * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing. 35 // */ 36 // static <T> T retain(T msg) { 37 // if (msg instanceof ReferenceCounted) { 38 // return (T) ((ReferenceCounted) msg).retain(); 39 // } 40 // return msg; 41 // } 42 43 // /** 44 // * Try to call {@link ReferenceCounted#retain(int)} if the specified message implements {@link ReferenceCounted}. 45 // * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing. 46 // */ 47 48 // static <T> T retain(T msg, int increment) { 49 // if (msg instanceof ReferenceCounted) { 50 // return (T) ((ReferenceCounted) msg).retain(increment); 51 // } 52 // return msg; 53 // } 54 55 // /** 56 // * Tries to call {@link ReferenceCounted#touch()} if the specified message implements {@link ReferenceCounted}. 57 // * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing. 58 // */ 59 60 // static <T> T touch(T msg) { 61 // if (msg instanceof ReferenceCounted) { 62 // return (T) ((ReferenceCounted) msg).touch(); 63 // } 64 // return msg; 65 // } 66 67 // /** 68 // * Tries to call {@link ReferenceCounted#touch(Object)} if the specified message implements 69 // * {@link ReferenceCounted}. If the specified message doesn't implement {@link ReferenceCounted}, 70 // * this method does nothing. 71 // */ 72 73 // static <T> T touch(T msg, Object hint) { 74 // if (msg instanceof ReferenceCounted) { 75 // return (T) ((ReferenceCounted) msg).touch(hint); 76 // } 77 // return msg; 78 // } 79 80 /** 81 * Try to call {@link ReferenceCounted#release()} if the specified message implements {@link ReferenceCounted}. 82 * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing. 83 */ 84 static bool release(Object msg) { 85 ReferenceCounted rc = cast(ReferenceCounted) msg; 86 if (rc !is null) { 87 return rc.release(); 88 } 89 return false; 90 } 91 92 /** 93 * Try to call {@link ReferenceCounted#release(int)} if the specified message implements {@link ReferenceCounted}. 94 * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing. 95 */ 96 static bool release(Object msg, int decrement) { 97 ReferenceCounted rc = cast(ReferenceCounted) msg; 98 if (rc !is null) { 99 return rc.release(decrement); 100 } 101 return false; 102 } 103 104 /** 105 * Try to call {@link ReferenceCounted#release()} if the specified message implements {@link ReferenceCounted}. 106 * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing. 107 * Unlike {@link #release(Object)} this method catches an exception raised by {@link ReferenceCounted#release()} 108 * and logs it, rather than rethrowing it to the caller. It is usually recommended to use {@link #release(Object)} 109 * instead, unless you absolutely need to swallow an exception. 110 */ 111 static void safeRelease(Object msg) { 112 try { 113 release(msg); 114 } catch (Throwable t) { 115 version(HUNT_DEBUG) { 116 warningf("Failed to release a message: %s, exception: %s", 117 msg.toString(), t); 118 } else { 119 warningf("Failed to release a message: %s, exception: %s", 120 msg.toString(), t.msg); 121 } 122 } 123 } 124 125 /** 126 * Try to call {@link ReferenceCounted#release(int)} if the specified message implements {@link ReferenceCounted}. 127 * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing. 128 * Unlike {@link #release(Object)} this method catches an exception raised by {@link ReferenceCounted#release(int)} 129 * and logs it, rather than rethrowing it to the caller. It is usually recommended to use 130 * {@link #release(Object, int)} instead, unless you absolutely need to swallow an exception. 131 */ 132 static void safeRelease(Object msg, int decrement) { 133 try { 134 release(msg, decrement); 135 } catch (Throwable t) { 136 137 version(HUNT_DEBUG) { 138 warningf("Failed to release a message: %s (decrement: %d), exception: %s", 139 msg.toString(), decrement, t); 140 } else { 141 warningf("Failed to release a message: %s (decrement: %d), exception: %s", 142 msg.toString(), decrement, t.msg); 143 } 144 } 145 } 146 147 // /** 148 // * Schedules the specified object to be released when the caller thread terminates. Note that this operation is 149 // * intended to simplify reference counting of ephemeral objects during unit tests. Do not use it beyond the 150 // * intended use case. 151 // * 152 // * deprecated("") this may introduce a lot of memory usage so it is generally preferable to manually release objects. 153 // */ 154 // deprecated("") 155 // static <T> T releaseLater(T msg) { 156 // return releaseLater(msg, 1); 157 // } 158 159 // /** 160 // * Schedules the specified object to be released when the caller thread terminates. Note that this operation is 161 // * intended to simplify reference counting of ephemeral objects during unit tests. Do not use it beyond the 162 // * intended use case. 163 // * 164 // * deprecated("") this may introduce a lot of memory usage so it is generally preferable to manually release objects. 165 // */ 166 // deprecated("") 167 // static <T> T releaseLater(T msg, int decrement) { 168 // if (msg instanceof ReferenceCounted) { 169 // ThreadDeathWatcher.watch(Thread.currentThread(), new ReleasingTask((ReferenceCounted) msg, decrement)); 170 // } 171 // return msg; 172 // } 173 174 // /** 175 // * Returns reference count of a {@link ReferenceCounted} object. If object is not type of 176 // * {@link ReferenceCounted}, {@code -1} is returned. 177 // */ 178 // static int refCnt(Object msg) { 179 // return msg instanceof ReferenceCounted ? ((ReferenceCounted) msg).refCnt() : -1; 180 // } 181 182 // /** 183 // * Releases the objects when the thread that called {@link #releaseLater(Object)} has been terminated. 184 // */ 185 // private static final class ReleasingTask implements Runnable { 186 187 // private final ReferenceCounted obj; 188 // private final int decrement; 189 190 // ReleasingTask(ReferenceCounted obj, int decrement) { 191 // this.obj = obj; 192 // this.decrement = decrement; 193 // } 194 195 // override 196 // void run() { 197 // try { 198 // if (!obj.release(decrement)) { 199 // warning("Non-zero refCnt: {}", this); 200 // } else { 201 // logger.debug("Released: {}", this); 202 // } 203 // } catch (Exception ex) { 204 // warning("Failed to release an object: {}", obj, ex); 205 // } 206 // } 207 208 // override 209 // String toString() { 210 // return StringUtil.simpleClassName(obj) ~ ".release(" ~ decrement ~ ") refCnt: " ~ obj.refCnt(); 211 // } 212 // } 213 214 private this() { } 215 }