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  package org.jboss.netty.handler.ssl;
17  
18  import java.nio.ByteBuffer;
19  
20  import javax.net.ssl.SSLEngine;
21  
22  /**
23   * A {@link ByteBuffer} pool dedicated for {@link SslHandler} performance
24   * improvement.
25   * <p>
26   * In most cases, you won't need to create a new pool instance because
27   * {@link SslHandler} has a default pool instance internally.
28   * <p>
29   * The reason why {@link SslHandler} requires a buffer pool is because the
30   * current {@link SSLEngine} implementation always requires a 17KiB buffer for
31   * every 'wrap' and 'unwrap' operation.  In most cases, the actual size of the
32   * required buffer is much smaller than that, and therefore allocating a 17KiB
33   * buffer for every 'wrap' and 'unwrap' operation wastes a lot of memory
34   * bandwidth, resulting in the application performance degradation.
35   */
36  public class SslBufferPool {
37  
38      // Add 1024 as a room for compressed data and another 1024 for Apache Harmony compatibility.
39      private static final int MAX_PACKET_SIZE = 16665 + 2048;
40      private static final int DEFAULT_POOL_SIZE = MAX_PACKET_SIZE * 1024;
41  
42      private final ByteBuffer[] pool;
43      private final int maxBufferCount;
44      private int index;
45  
46      /**
47       * Creates a new buffer pool whose size is {@code 18113536}, which can
48       * hold {@code 1024} buffers.
49       */
50      public SslBufferPool() {
51          this(DEFAULT_POOL_SIZE);
52      }
53  
54      /**
55       * Creates a new buffer pool.
56       *
57       * @param maxPoolSize the maximum number of bytes that this pool can hold
58       */
59      public SslBufferPool(int maxPoolSize) {
60          if (maxPoolSize <= 0) {
61              throw new IllegalArgumentException("maxPoolSize: " + maxPoolSize);
62          }
63  
64          int maxBufferCount = maxPoolSize / MAX_PACKET_SIZE;
65          if (maxPoolSize % MAX_PACKET_SIZE != 0) {
66              maxBufferCount ++;
67          }
68  
69          pool = new ByteBuffer[maxBufferCount];
70          this.maxBufferCount = maxBufferCount;
71      }
72  
73      /**
74       * Returns the maximum size of this pool in byte unit.  The returned value
75       * can be somewhat different from what was specified in the constructor.
76       */
77      public int getMaxPoolSize() {
78          return maxBufferCount * MAX_PACKET_SIZE;
79      }
80  
81      /**
82       * Returns the number of bytes which were allocated but have not been
83       * acquired yet.  You can estimate how optimal the specified maximum pool
84       * size is from this value.  If it keeps returning {@code 0}, it means the
85       * pool is getting exhausted.  If it keeps returns a unnecessarily big
86       * value, it means the pool is wasting the heap space.
87       */
88      public synchronized int getUnacquiredPoolSize() {
89          return index * MAX_PACKET_SIZE;
90      }
91  
92      /**
93       * Acquire a new {@link ByteBuffer} out of the {@link SslBufferPool}
94       *
95       */
96      public ByteBuffer acquireBuffer() {
97          return acquire();
98      }
99  
100     /**
101      * Will get removed. Please use {@link #acquireBuffer()}
102      *
103      */
104     @Deprecated
105     synchronized ByteBuffer acquire() {
106         if (index == 0) {
107             return ByteBuffer.allocate(MAX_PACKET_SIZE);
108         } else {
109             return (ByteBuffer) pool[-- index].clear();
110         }
111     }
112 
113 
114     /**
115      * Release a previous acquired {@link ByteBuffer}
116      *
117      * @param buffer
118      */
119     public void releaseBuffer(ByteBuffer buffer) {
120         release(buffer);
121     }
122 
123     /**
124      * Will get removed. Please use {@link #releaseBuffer(ByteBuffer)}
125      *
126      * @deprecated
127      *
128      */
129     @Deprecated
130     synchronized void release(ByteBuffer buffer) {
131         if (index < maxBufferCount) {
132             pool[index ++] = buffer;
133         }
134     }
135 }