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 }