View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.io;
20  
21  import java.nio.ByteBuffer;
22  import java.util.Queue;
23  import java.util.concurrent.ConcurrentLinkedQueue;
24  
25  import org.eclipse.jetty.util.BufferUtil;
26  
27  public class ArrayByteBufferPool implements ByteBufferPool
28  {
29      private final int _min;
30      private final Bucket[] _direct;
31      private final Bucket[] _indirect;
32      private final int _inc;
33  
34      public ArrayByteBufferPool()
35      {
36          this(0,1024,64*1024);
37      }
38  
39      public ArrayByteBufferPool(int minSize, int increment, int maxSize)
40      {
41          if (minSize>=increment)
42              throw new IllegalArgumentException("minSize >= increment");
43          if ((maxSize%increment)!=0 || increment>=maxSize)
44              throw new IllegalArgumentException("increment must be a divisor of maxSize");
45          _min=minSize;
46          _inc=increment;
47  
48          _direct=new Bucket[maxSize/increment];
49          _indirect=new Bucket[maxSize/increment];
50  
51          int size=0;
52          for (int i=0;i<_direct.length;i++)
53          {
54              size+=_inc;
55              _direct[i]=new Bucket(size);
56              _indirect[i]=new Bucket(size);
57          }
58      }
59  
60      @Override
61      public ByteBuffer acquire(int size, boolean direct)
62      {
63          Bucket bucket = bucketFor(size,direct);
64          ByteBuffer buffer = bucket==null?null:bucket._queue.poll();
65  
66          if (buffer == null)
67          {
68              int capacity = bucket==null?size:bucket._size;
69              buffer = direct ? BufferUtil.allocateDirect(capacity) : BufferUtil.allocate(capacity);
70          }
71  
72          return buffer;
73      }
74  
75      @Override
76      public void release(ByteBuffer buffer)
77      {
78          if (buffer!=null)
79          {    
80              Bucket bucket = bucketFor(buffer.capacity(),buffer.isDirect());
81              if (bucket!=null)
82              {
83                  BufferUtil.clear(buffer);
84                  bucket._queue.offer(buffer);
85              }
86          }
87      }
88  
89      public void clear()
90      {
91          for (int i=0;i<_direct.length;i++)
92          {
93              _direct[i]._queue.clear();
94              _indirect[i]._queue.clear();
95          }
96      }
97  
98      private Bucket bucketFor(int size,boolean direct)
99      {
100         if (size<=_min)
101             return null;
102         int b=(size-1)/_inc;
103         if (b>=_direct.length)
104             return null;
105         Bucket bucket = direct?_direct[b]:_indirect[b];
106                 
107         return bucket;
108     }
109 
110     public static class Bucket
111     {
112         public final int _size;
113         public final Queue<ByteBuffer> _queue= new ConcurrentLinkedQueue<>();
114 
115         Bucket(int size)
116         {
117             _size=size;
118         }
119         
120         @Override
121         public String toString()
122         {
123             return String.format("Bucket@%x{%d,%d}",hashCode(),_size,_queue.size());
124         }
125     }
126     
127 
128     // Package local for testing
129     Bucket[] bucketsFor(boolean direct)
130     {
131         return direct ? _direct : _indirect;
132     }
133 }