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