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 }