View Javadoc
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    *   https://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.IllegalReferenceCountException;
20  import io.netty.util.ResourceLeakDetector;
21  import io.netty.util.ResourceLeakTracker;
22  import io.netty.util.internal.ObjectUtil;
23  import io.netty.util.internal.ThrowableUtil;
24  
25  import java.nio.ByteOrder;
26  
27  class SimpleLeakAwareByteBuf extends WrappedByteBuf {
28  
29      /**
30       * This object's is associated with the {@link ResourceLeakTracker}. When {@link ResourceLeakTracker#close(Object)}
31       * is called this object will be used as the argument. It is also assumed that this object is used when
32       * {@link ResourceLeakDetector#track(Object)} is called to create {@link #leak}.
33       */
34      private final ByteBuf trackedByteBuf;
35      final ResourceLeakTracker<ByteBuf> leak;
36  
37      SimpleLeakAwareByteBuf(ByteBuf wrapped, ByteBuf trackedByteBuf, ResourceLeakTracker<ByteBuf> leak) {
38          super(wrapped);
39          this.trackedByteBuf = ObjectUtil.checkNotNull(trackedByteBuf, "trackedByteBuf");
40          this.leak = ObjectUtil.checkNotNull(leak, "leak");
41      }
42  
43      SimpleLeakAwareByteBuf(ByteBuf wrapped, ResourceLeakTracker<ByteBuf> leak) {
44          this(wrapped, wrapped, leak);
45      }
46  
47      @Override
48      public ByteBuf slice() {
49          return newSharedLeakAwareByteBuf(super.slice());
50      }
51  
52      @Override
53      public ByteBuf retainedSlice() {
54          try {
55              return unwrappedDerived(super.retainedSlice());
56          } catch (IllegalReferenceCountException irce) {
57              ThrowableUtil.addSuppressed(irce, leak.getCloseStackTraceIfAny());
58              throw irce;
59          }
60      }
61  
62      @Override
63      public ByteBuf retainedSlice(int index, int length) {
64          try {
65              return unwrappedDerived(super.retainedSlice(index, length));
66          } catch (IllegalReferenceCountException irce) {
67              ThrowableUtil.addSuppressed(irce, leak.getCloseStackTraceIfAny());
68              throw irce;
69          }
70      }
71  
72      @Override
73      public ByteBuf retainedDuplicate() {
74          try {
75              return unwrappedDerived(super.retainedDuplicate());
76          } catch (IllegalReferenceCountException irce) {
77              ThrowableUtil.addSuppressed(irce, leak.getCloseStackTraceIfAny());
78              throw irce;
79          }
80      }
81  
82      @Override
83      public ByteBuf readRetainedSlice(int length) {
84          try {
85              return unwrappedDerived(super.readRetainedSlice(length));
86          } catch (IllegalReferenceCountException irce) {
87              ThrowableUtil.addSuppressed(irce, leak.getCloseStackTraceIfAny());
88              throw irce;
89          }
90      }
91  
92      @Override
93      public ByteBuf slice(int index, int length) {
94          return newSharedLeakAwareByteBuf(super.slice(index, length));
95      }
96  
97      @Override
98      public ByteBuf duplicate() {
99          return newSharedLeakAwareByteBuf(super.duplicate());
100     }
101 
102     @Override
103     public ByteBuf readSlice(int length) {
104         return newSharedLeakAwareByteBuf(super.readSlice(length));
105     }
106 
107     @Override
108     public ByteBuf asReadOnly() {
109         return newSharedLeakAwareByteBuf(super.asReadOnly());
110     }
111 
112     @Override
113     public ByteBuf touch() {
114         return this;
115     }
116 
117     @Override
118     public ByteBuf touch(Object hint) {
119         return this;
120     }
121 
122     @Override
123     public ByteBuf retain() {
124         try {
125             return super.retain();
126         } catch (IllegalReferenceCountException irce) {
127             ThrowableUtil.addSuppressed(irce, leak.getCloseStackTraceIfAny());
128             throw irce;
129         }
130     }
131 
132     @Override
133     public ByteBuf retain(int increment) {
134         try {
135             return super.retain(increment);
136         } catch (IllegalReferenceCountException irce) {
137             ThrowableUtil.addSuppressed(irce, leak.getCloseStackTraceIfAny());
138             throw irce;
139         }
140     }
141 
142     @Override
143     public boolean release() {
144         try {
145             if (super.release()) {
146                 closeLeak();
147                 return true;
148             }
149             return false;
150         } catch (IllegalReferenceCountException irce) {
151             ThrowableUtil.addSuppressed(irce, leak.getCloseStackTraceIfAny());
152             throw irce;
153         }
154     }
155 
156     @Override
157     public boolean release(int decrement) {
158         try {
159             if (super.release(decrement)) {
160                 closeLeak();
161                 return true;
162             }
163             return false;
164         } catch (IllegalReferenceCountException irce) {
165             ThrowableUtil.addSuppressed(irce, leak.getCloseStackTraceIfAny());
166             throw irce;
167         }
168     }
169 
170     private void closeLeak() {
171         // Close the ResourceLeakTracker with the tracked ByteBuf as argument. This must be the same that was used when
172         // calling DefaultResourceLeak.track(...).
173         boolean closed = leak.close(trackedByteBuf);
174         assert closed;
175     }
176 
177     @Override
178     public ByteBuf order(ByteOrder endianness) {
179         if (order() == endianness) {
180             return this;
181         } else {
182             return newSharedLeakAwareByteBuf(super.order(endianness));
183         }
184     }
185 
186     private ByteBuf unwrappedDerived(ByteBuf derived) {
187         // We only need to unwrap SwappedByteBuf implementations as these will be the only ones that may end up in
188         // the AbstractLeakAwareByteBuf implementations beside slices / duplicates and "real" buffers.
189         ByteBuf unwrappedDerived = unwrapSwapped(derived);
190 
191         if (unwrappedDerived instanceof AbstractPooledDerivedByteBuf) {
192             // Update the parent to point to this buffer so we correctly close the ResourceLeakTracker.
193             ((AbstractPooledDerivedByteBuf) unwrappedDerived).parent(this);
194 
195             // force tracking of derived buffers (see issue #13414)
196             return newLeakAwareByteBuf(derived, AbstractByteBuf.leakDetector.trackForcibly(derived));
197         }
198         return newSharedLeakAwareByteBuf(derived);
199     }
200 
201     @SuppressWarnings("deprecation")
202     private static ByteBuf unwrapSwapped(ByteBuf buf) {
203         if (buf instanceof SwappedByteBuf) {
204             do {
205                 buf = buf.unwrap();
206             } while (buf instanceof SwappedByteBuf);
207 
208             return buf;
209         }
210         return buf;
211     }
212 
213     private SimpleLeakAwareByteBuf newSharedLeakAwareByteBuf(
214             ByteBuf wrapped) {
215         return newLeakAwareByteBuf(wrapped, trackedByteBuf, leak);
216     }
217 
218     private SimpleLeakAwareByteBuf newLeakAwareByteBuf(
219             ByteBuf wrapped, ResourceLeakTracker<ByteBuf> leakTracker) {
220         return newLeakAwareByteBuf(wrapped, wrapped, leakTracker);
221     }
222 
223     protected SimpleLeakAwareByteBuf newLeakAwareByteBuf(
224             ByteBuf buf, ByteBuf trackedByteBuf, ResourceLeakTracker<ByteBuf> leakTracker) {
225         return new SimpleLeakAwareByteBuf(buf, trackedByteBuf, leakTracker);
226     }
227 }