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    *   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  
17  package io.netty.buffer;
18  
19  import io.netty.util.Recycler.Handle;
20  import io.netty.util.ReferenceCounted;
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 Handle<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 = (Handle<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              setRefCnt(1);
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.recycle(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 final int nioBufferCount() {
128         return unwrap().nioBufferCount();
129     }
130 
131     @Override
132     public final ByteBuffer internalNioBuffer(int index, int length) {
133         return nioBuffer(index, length);
134     }
135 
136     @Override
137     public final ByteBuf retainedSlice() {
138         final int index = readerIndex();
139         return retainedSlice(index, writerIndex() - index);
140     }
141 
142     @Override
143     public ByteBuf slice(int index, int length) {
144         ensureAccessible();
145         // All reference count methods should be inherited from this object (this is the "parent").
146         return new PooledNonRetainedSlicedByteBuf(this, unwrap(), index, length);
147     }
148 
149     final ByteBuf duplicate0() {
150         ensureAccessible();
151         // All reference count methods should be inherited from this object (this is the "parent").
152         return new PooledNonRetainedDuplicateByteBuf(this, unwrap());
153     }
154 
155     private static final class PooledNonRetainedDuplicateByteBuf extends UnpooledDuplicatedByteBuf {
156         private final ReferenceCounted referenceCountDelegate;
157 
158         PooledNonRetainedDuplicateByteBuf(ReferenceCounted referenceCountDelegate, AbstractByteBuf buffer) {
159             super(buffer);
160             this.referenceCountDelegate = referenceCountDelegate;
161         }
162 
163         @Override
164         int refCnt0() {
165             return referenceCountDelegate.refCnt();
166         }
167 
168         @Override
169         ByteBuf retain0() {
170             referenceCountDelegate.retain();
171             return this;
172         }
173 
174         @Override
175         ByteBuf retain0(int increment) {
176             referenceCountDelegate.retain(increment);
177             return this;
178         }
179 
180         @Override
181         ByteBuf touch0() {
182             referenceCountDelegate.touch();
183             return this;
184         }
185 
186         @Override
187         ByteBuf touch0(Object hint) {
188             referenceCountDelegate.touch(hint);
189             return this;
190         }
191 
192         @Override
193         boolean release0() {
194             return referenceCountDelegate.release();
195         }
196 
197         @Override
198         boolean release0(int decrement) {
199             return referenceCountDelegate.release(decrement);
200         }
201 
202         @Override
203         public ByteBuf duplicate() {
204             ensureAccessible();
205             return new PooledNonRetainedDuplicateByteBuf(referenceCountDelegate, this);
206         }
207 
208         @Override
209         public ByteBuf retainedDuplicate() {
210             return PooledDuplicatedByteBuf.newInstance(unwrap(), this, readerIndex(), writerIndex());
211         }
212 
213         @Override
214         public ByteBuf slice(int index, int length) {
215             checkIndex(index, length);
216             return new PooledNonRetainedSlicedByteBuf(referenceCountDelegate, unwrap(), index, length);
217         }
218 
219         @Override
220         public ByteBuf retainedSlice() {
221             // Capacity is not allowed to change for a sliced ByteBuf, so length == capacity()
222             return retainedSlice(readerIndex(), capacity());
223         }
224 
225         @Override
226         public ByteBuf retainedSlice(int index, int length) {
227             return PooledSlicedByteBuf.newInstance(unwrap(), this, index, length);
228         }
229     }
230 
231     private static final class PooledNonRetainedSlicedByteBuf extends UnpooledSlicedByteBuf {
232         private final ReferenceCounted referenceCountDelegate;
233 
234         PooledNonRetainedSlicedByteBuf(ReferenceCounted referenceCountDelegate,
235                                        AbstractByteBuf buffer, int index, int length) {
236             super(buffer, index, length);
237             this.referenceCountDelegate = referenceCountDelegate;
238         }
239 
240         @Override
241         int refCnt0() {
242             return referenceCountDelegate.refCnt();
243         }
244 
245         @Override
246         ByteBuf retain0() {
247             referenceCountDelegate.retain();
248             return this;
249         }
250 
251         @Override
252         ByteBuf retain0(int increment) {
253             referenceCountDelegate.retain(increment);
254             return this;
255         }
256 
257         @Override
258         ByteBuf touch0() {
259             referenceCountDelegate.touch();
260             return this;
261         }
262 
263         @Override
264         ByteBuf touch0(Object hint) {
265             referenceCountDelegate.touch(hint);
266             return this;
267         }
268 
269         @Override
270         boolean release0() {
271             return referenceCountDelegate.release();
272         }
273 
274         @Override
275         boolean release0(int decrement) {
276             return referenceCountDelegate.release(decrement);
277         }
278 
279         @Override
280         public ByteBuf duplicate() {
281             ensureAccessible();
282             return new PooledNonRetainedDuplicateByteBuf(referenceCountDelegate, unwrap())
283                     .setIndex(idx(readerIndex()), idx(writerIndex()));
284         }
285 
286         @Override
287         public ByteBuf retainedDuplicate() {
288             return PooledDuplicatedByteBuf.newInstance(unwrap(), this, idx(readerIndex()), idx(writerIndex()));
289         }
290 
291         @Override
292         public ByteBuf slice(int index, int length) {
293             checkIndex(index, length);
294             return new PooledNonRetainedSlicedByteBuf(referenceCountDelegate, unwrap(), idx(index), length);
295         }
296 
297         @Override
298         public ByteBuf retainedSlice() {
299             // Capacity is not allowed to change for a sliced ByteBuf, so length == capacity()
300             return retainedSlice(0, capacity());
301         }
302 
303         @Override
304         public ByteBuf retainedSlice(int index, int length) {
305             return PooledSlicedByteBuf.newInstance(unwrap(), this, idx(index), length);
306         }
307     }
308 }