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      Thread initThread;
36      private ByteBuffer tmpNioBuf;
37  
38      @SuppressWarnings("unchecked")
39      protected PooledByteBuf(Recycler.Handle<? extends PooledByteBuf<T>> recyclerHandle, int maxCapacity) {
40          super(maxCapacity);
41          this.recyclerHandle = (Handle<PooledByteBuf<T>>) recyclerHandle;
42      }
43  
44      void init(PoolChunk<T> chunk, long handle, int offset, int length, int maxLength) {
45          assert handle >= 0;
46          assert chunk != null;
47  
48          this.chunk = chunk;
49          this.handle = handle;
50          memory = chunk.memory;
51          this.offset = offset;
52          this.length = length;
53          this.maxLength = maxLength;
54          setIndex(0, 0);
55          tmpNioBuf = null;
56          initThread = Thread.currentThread();
57      }
58  
59      void initUnpooled(PoolChunk<T> chunk, int length) {
60          assert chunk != null;
61  
62          this.chunk = chunk;
63          handle = 0;
64          memory = chunk.memory;
65          offset = 0;
66          this.length = maxLength = length;
67          setIndex(0, 0);
68          tmpNioBuf = null;
69          initThread = Thread.currentThread();
70      }
71  
72      @Override
73      public final int capacity() {
74          return length;
75      }
76  
77      @Override
78      public final ByteBuf capacity(int newCapacity) {
79          ensureAccessible();
80  
81          // If the request capacity does not require reallocation, just update the length of the memory.
82          if (chunk.unpooled) {
83              if (newCapacity == length) {
84                  return this;
85              }
86          } else {
87              if (newCapacity > length) {
88                  if (newCapacity <= maxLength) {
89                      length = newCapacity;
90                      return this;
91                  }
92              } else if (newCapacity < length) {
93                  if (newCapacity > maxLength >>> 1) {
94                      if (maxLength <= 512) {
95                          if (newCapacity > maxLength - 16) {
96                              length = newCapacity;
97                              setIndex(Math.min(readerIndex(), newCapacity), Math.min(writerIndex(), newCapacity));
98                              return this;
99                          }
100                     } else { // > 512 (i.e. >= 1024)
101                         length = newCapacity;
102                         setIndex(Math.min(readerIndex(), newCapacity), Math.min(writerIndex(), newCapacity));
103                         return this;
104                     }
105                 }
106             } else {
107                 return this;
108             }
109         }
110 
111         // Reallocation required.
112         chunk.arena.reallocate(this, newCapacity, true);
113         return this;
114     }
115 
116     @Override
117     public final ByteBufAllocator alloc() {
118         return chunk.arena.parent;
119     }
120 
121     @Override
122     public final ByteOrder order() {
123         return ByteOrder.BIG_ENDIAN;
124     }
125 
126     @Override
127     public final ByteBuf unwrap() {
128         return null;
129     }
130 
131     protected final ByteBuffer internalNioBuffer() {
132         ByteBuffer tmpNioBuf = this.tmpNioBuf;
133         if (tmpNioBuf == null) {
134             this.tmpNioBuf = tmpNioBuf = newInternalNioBuffer(memory);
135         }
136         return tmpNioBuf;
137     }
138 
139     protected abstract ByteBuffer newInternalNioBuffer(T memory);
140 
141     @Override
142     protected final void deallocate() {
143         if (handle >= 0) {
144             final long handle = this.handle;
145             this.handle = -1;
146             memory = null;
147             boolean sameThread = initThread == Thread.currentThread();
148             initThread = null;
149             chunk.arena.free(chunk, handle, maxLength, sameThread);
150             recycle();
151         }
152     }
153 
154     private void recycle() {
155         recyclerHandle.recycle(this);
156     }
157 
158     protected final int idx(int index) {
159         return offset + index;
160     }
161 }