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.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 }
323