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