View Javadoc
1   /*
2    * Copyright 2016 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.Recycler.EnhancedHandle;
20  import io.netty.util.internal.ObjectPool.Handle;
21  
22  import java.nio.ByteBuffer;
23  import java.nio.ByteOrder;
24  
25  /**
26   * Abstract base class for derived {@link ByteBuf} implementations.
27   */
28  abstract class AbstractPooledDerivedByteBuf extends AbstractReferenceCountedByteBuf {
29  
30      private final EnhancedHandle<AbstractPooledDerivedByteBuf> recyclerHandle;
31      private AbstractByteBuf rootParent;
32      /**
33       * Deallocations of a pooled derived buffer should always propagate through the entire chain of derived buffers.
34       * This is because each pooled derived buffer maintains its own reference count and we should respect each one.
35       * If deallocations cause a release of the "root parent" then then we may prematurely release the underlying
36       * content before all the derived buffers have been released.
37       */
38      private ByteBuf parent;
39  
40      @SuppressWarnings("unchecked")
41      AbstractPooledDerivedByteBuf(Handle<? extends AbstractPooledDerivedByteBuf> recyclerHandle) {
42          super(0);
43          this.recyclerHandle = (EnhancedHandle<AbstractPooledDerivedByteBuf>) recyclerHandle;
44      }
45  
46      // Called from within SimpleLeakAwareByteBuf and AdvancedLeakAwareByteBuf.
47      final void parent(ByteBuf newParent) {
48          assert newParent instanceof SimpleLeakAwareByteBuf;
49          parent = newParent;
50      }
51  
52      @Override
53      public final AbstractByteBuf unwrap() {
54          return rootParent;
55      }
56  
57      final <U extends AbstractPooledDerivedByteBuf> U init(
58              AbstractByteBuf unwrapped, ByteBuf wrapped, int readerIndex, int writerIndex, int maxCapacity) {
59          wrapped.retain(); // Retain up front to ensure the parent is accessible before doing more work.
60          parent = wrapped;
61          rootParent = unwrapped;
62  
63          try {
64              maxCapacity(maxCapacity);
65              setIndex0(readerIndex, writerIndex); // It is assumed the bounds checking is done by the caller.
66              resetRefCnt();
67  
68              @SuppressWarnings("unchecked")
69              final U castThis = (U) this;
70              wrapped = null;
71              return castThis;
72          } finally {
73              if (wrapped != null) {
74                  parent = rootParent = null;
75                  wrapped.release();
76              }
77          }
78      }
79  
80      @Override
81      protected final void deallocate() {
82          // We need to first store a reference to the parent before recycle this instance. This is needed as
83          // otherwise it is possible that the same AbstractPooledDerivedByteBuf is again obtained and init(...) is
84          // called before we actually have a chance to call release(). This leads to call release() on the wrong parent.
85          ByteBuf parent = this.parent;
86          recyclerHandle.unguardedRecycle(this);
87          parent.release();
88      }
89  
90      @Override
91      public final ByteBufAllocator alloc() {
92          return unwrap().alloc();
93      }
94  
95      @Override
96      @Deprecated
97      public final ByteOrder order() {
98          return unwrap().order();
99      }
100 
101     @Override
102     public boolean isReadOnly() {
103         return unwrap().isReadOnly();
104     }
105 
106     @Override
107     public final boolean isDirect() {
108         return unwrap().isDirect();
109     }
110 
111     @Override
112     public boolean hasArray() {
113         return unwrap().hasArray();
114     }
115 
116     @Override
117     public byte[] array() {
118         return unwrap().array();
119     }
120 
121     @Override
122     public boolean hasMemoryAddress() {
123         return unwrap().hasMemoryAddress();
124     }
125 
126     @Override
127     public boolean isContiguous() {
128         return unwrap().isContiguous();
129     }
130 
131     @Override
132     public final int nioBufferCount() {
133         return unwrap().nioBufferCount();
134     }
135 
136     @Override
137     public final ByteBuffer internalNioBuffer(int index, int length) {
138         return nioBuffer(index, length);
139     }
140 
141     @Override
142     public final ByteBuf retainedSlice() {
143         final int index = readerIndex();
144         return retainedSlice(index, writerIndex() - index);
145     }
146 
147     @Override
148     public ByteBuf slice(int index, int length) {
149         ensureAccessible();
150         // All reference count methods should be inherited from this object (this is the "parent").
151         return new PooledNonRetainedSlicedByteBuf(this, unwrap(), index, length);
152     }
153 
154     final ByteBuf duplicate0() {
155         ensureAccessible();
156         // All reference count methods should be inherited from this object (this is the "parent").
157         return new PooledNonRetainedDuplicateByteBuf(this, unwrap());
158     }
159 
160     private static final class PooledNonRetainedDuplicateByteBuf extends UnpooledDuplicatedByteBuf {
161         private final ByteBuf referenceCountDelegate;
162 
163         PooledNonRetainedDuplicateByteBuf(ByteBuf referenceCountDelegate, AbstractByteBuf buffer) {
164             super(buffer);
165             this.referenceCountDelegate = referenceCountDelegate;
166         }
167 
168         @Override
169         boolean isAccessible0() {
170             return referenceCountDelegate.isAccessible();
171         }
172 
173         @Override
174         int refCnt0() {
175             return referenceCountDelegate.refCnt();
176         }
177 
178         @Override
179         ByteBuf retain0() {
180             referenceCountDelegate.retain();
181             return this;
182         }
183 
184         @Override
185         ByteBuf retain0(int increment) {
186             referenceCountDelegate.retain(increment);
187             return this;
188         }
189 
190         @Override
191         ByteBuf touch0() {
192             referenceCountDelegate.touch();
193             return this;
194         }
195 
196         @Override
197         ByteBuf touch0(Object hint) {
198             referenceCountDelegate.touch(hint);
199             return this;
200         }
201 
202         @Override
203         boolean release0() {
204             return referenceCountDelegate.release();
205         }
206 
207         @Override
208         boolean release0(int decrement) {
209             return referenceCountDelegate.release(decrement);
210         }
211 
212         @Override
213         public ByteBuf duplicate() {
214             ensureAccessible();
215             return new PooledNonRetainedDuplicateByteBuf(referenceCountDelegate, this);
216         }
217 
218         @Override
219         public ByteBuf retainedDuplicate() {
220             return PooledDuplicatedByteBuf.newInstance(unwrap(), this, readerIndex(), writerIndex());
221         }
222 
223         @Override
224         public ByteBuf slice(int index, int length) {
225             checkIndex(index, length);
226             return new PooledNonRetainedSlicedByteBuf(referenceCountDelegate, unwrap(), index, length);
227         }
228 
229         @Override
230         public ByteBuf retainedSlice() {
231             // Capacity is not allowed to change for a sliced ByteBuf, so length == capacity()
232             return retainedSlice(readerIndex(), capacity());
233         }
234 
235         @Override
236         public ByteBuf retainedSlice(int index, int length) {
237             return PooledSlicedByteBuf.newInstance(unwrap(), this, index, length);
238         }
239     }
240 
241     private static final class PooledNonRetainedSlicedByteBuf extends UnpooledSlicedByteBuf {
242         private final ByteBuf referenceCountDelegate;
243 
244         PooledNonRetainedSlicedByteBuf(ByteBuf referenceCountDelegate,
245                                        AbstractByteBuf buffer, int index, int length) {
246             super(buffer, index, length);
247             this.referenceCountDelegate = referenceCountDelegate;
248         }
249 
250         @Override
251         boolean isAccessible0() {
252             return referenceCountDelegate.isAccessible();
253         }
254 
255         @Override
256         int refCnt0() {
257             return referenceCountDelegate.refCnt();
258         }
259 
260         @Override
261         ByteBuf retain0() {
262             referenceCountDelegate.retain();
263             return this;
264         }
265 
266         @Override
267         ByteBuf retain0(int increment) {
268             referenceCountDelegate.retain(increment);
269             return this;
270         }
271 
272         @Override
273         ByteBuf touch0() {
274             referenceCountDelegate.touch();
275             return this;
276         }
277 
278         @Override
279         ByteBuf touch0(Object hint) {
280             referenceCountDelegate.touch(hint);
281             return this;
282         }
283 
284         @Override
285         boolean release0() {
286             return referenceCountDelegate.release();
287         }
288 
289         @Override
290         boolean release0(int decrement) {
291             return referenceCountDelegate.release(decrement);
292         }
293 
294         @Override
295         public ByteBuf duplicate() {
296             ensureAccessible();
297             return new PooledNonRetainedDuplicateByteBuf(referenceCountDelegate, unwrap())
298                     .setIndex(idx(readerIndex()), idx(writerIndex()));
299         }
300 
301         @Override
302         public ByteBuf retainedDuplicate() {
303             return PooledDuplicatedByteBuf.newInstance(unwrap(), this, idx(readerIndex()), idx(writerIndex()));
304         }
305 
306         @Override
307         public ByteBuf slice(int index, int length) {
308             checkIndex(index, length);
309             return new PooledNonRetainedSlicedByteBuf(referenceCountDelegate, unwrap(), idx(index), length);
310         }
311 
312         @Override
313         public ByteBuf retainedSlice() {
314             // Capacity is not allowed to change for a sliced ByteBuf, so length == capacity()
315             return retainedSlice(0, capacity());
316         }
317 
318         @Override
319         public ByteBuf retainedSlice(int index, int length) {
320             return PooledSlicedByteBuf.newInstance(unwrap(), this, idx(index), length);
321         }
322     }
323 }