View Javadoc
1   /*
2    * Copyright 2012 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;
20  import io.netty.util.Recycler.Handle;
21  
22  import java.nio.ByteBuffer;
23  import java.nio.ByteOrder;
24  
25  abstract class PooledByteBuf<T> extends AbstractReferenceCountedByteBuf {
26  
27      private final Recycler.Handle<PooledByteBuf<T>> recyclerHandle;
28  
29      protected PoolChunk<T> chunk;
30      protected long handle;
31      protected T memory;
32      protected int offset;
33      protected int length;
34      int maxLength;
35      PoolThreadCache cache;
36      private ByteBuffer tmpNioBuf;
37      private ByteBufAllocator allocator;
38  
39      @SuppressWarnings("unchecked")
40      protected PooledByteBuf(Recycler.Handle<? extends PooledByteBuf<T>> recyclerHandle, int maxCapacity) {
41          super(maxCapacity);
42          this.recyclerHandle = (Handle<PooledByteBuf<T>>) recyclerHandle;
43      }
44  
45      void init(PoolChunk<T> chunk, long handle, int offset, int length, int maxLength, PoolThreadCache cache) {
46          init0(chunk, handle, offset, length, maxLength, cache);
47      }
48  
49      void initUnpooled(PoolChunk<T> chunk, int length) {
50          init0(chunk, 0, chunk.offset, length, length, null);
51      }
52  
53      private void init0(PoolChunk<T> chunk, long handle, int offset, int length, int maxLength, PoolThreadCache cache) {
54          assert handle >= 0;
55          assert chunk != null;
56  
57          this.chunk = chunk;
58          memory = chunk.memory;
59          allocator = chunk.arena.parent;
60          this.cache = cache;
61          this.handle = handle;
62          this.offset = offset;
63          this.length = length;
64          this.maxLength = maxLength;
65          tmpNioBuf = null;
66      }
67  
68      /**
69       * Method must be called before reuse this {@link PooledByteBufAllocator}
70       */
71      final void reuse(int maxCapacity) {
72          maxCapacity(maxCapacity);
73          setRefCnt(1);
74          setIndex0(0, 0);
75          discardMarks();
76      }
77  
78      @Override
79      public final int capacity() {
80          return length;
81      }
82  
83      @Override
84      public final ByteBuf capacity(int newCapacity) {
85          checkNewCapacity(newCapacity);
86  
87          // If the request capacity does not require reallocation, just update the length of the memory.
88          if (chunk.unpooled) {
89              if (newCapacity == length) {
90                  return this;
91              }
92          } else {
93              if (newCapacity > length) {
94                  if (newCapacity <= maxLength) {
95                      length = newCapacity;
96                      return this;
97                  }
98              } else if (newCapacity < length) {
99                  if (newCapacity > maxLength >>> 1) {
100                     if (maxLength <= 512) {
101                         if (newCapacity > maxLength - 16) {
102                             length = newCapacity;
103                             setIndex(Math.min(readerIndex(), newCapacity), Math.min(writerIndex(), newCapacity));
104                             return this;
105                         }
106                     } else { // > 512 (i.e. >= 1024)
107                         length = newCapacity;
108                         setIndex(Math.min(readerIndex(), newCapacity), Math.min(writerIndex(), newCapacity));
109                         return this;
110                     }
111                 }
112             } else {
113                 return this;
114             }
115         }
116 
117         // Reallocation required.
118         chunk.arena.reallocate(this, newCapacity, true);
119         return this;
120     }
121 
122     @Override
123     public final ByteBufAllocator alloc() {
124         return allocator;
125     }
126 
127     @Override
128     public final ByteOrder order() {
129         return ByteOrder.BIG_ENDIAN;
130     }
131 
132     @Override
133     public final ByteBuf unwrap() {
134         return null;
135     }
136 
137     @Override
138     public final ByteBuf retainedDuplicate() {
139         return PooledDuplicatedByteBuf.newInstance(this, this, readerIndex(), writerIndex());
140     }
141 
142     @Override
143     public final ByteBuf retainedSlice() {
144         final int index = readerIndex();
145         return retainedSlice(index, writerIndex() - index);
146     }
147 
148     @Override
149     public final ByteBuf retainedSlice(int index, int length) {
150         return PooledSlicedByteBuf.newInstance(this, this, index, length);
151     }
152 
153     protected final ByteBuffer internalNioBuffer() {
154         ByteBuffer tmpNioBuf = this.tmpNioBuf;
155         if (tmpNioBuf == null) {
156             this.tmpNioBuf = tmpNioBuf = newInternalNioBuffer(memory);
157         }
158         return tmpNioBuf;
159     }
160 
161     protected abstract ByteBuffer newInternalNioBuffer(T memory);
162 
163     @Override
164     protected final void deallocate() {
165         if (handle >= 0) {
166             final long handle = this.handle;
167             this.handle = -1;
168             memory = null;
169             tmpNioBuf = null;
170             chunk.arena.free(chunk, handle, maxLength, cache);
171             chunk = null;
172             recycle();
173         }
174     }
175 
176     private void recycle() {
177         recyclerHandle.recycle(this);
178     }
179 
180     protected final int idx(int index) {
181         return offset + index;
182     }
183 }