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