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