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