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.ArrayList;
23  import java.util.List;
24  import java.util.Queue;
25  import java.util.concurrent.atomic.AtomicInteger;
26  
27  import org.eclipse.jetty.util.BufferUtil;
28  import org.eclipse.jetty.util.ConcurrentArrayQueue;
29  
30  /**
31   * <p>A {@link ByteBuffer} pool.</p>
32   * <p>Acquired buffers may be {@link #release(ByteBuffer) released} but they do not need to;
33   * if they are released, they may be recycled and reused, otherwise they will be garbage
34   * collected as usual.</p>
35   */
36  public interface ByteBufferPool
37  {
38      /**
39       * <p>Requests a {@link ByteBuffer} of the given size.</p>
40       * <p>The returned buffer may have a bigger capacity than the size being
41       * requested but it will have the limit set to the given size.</p>
42       *
43       * @param size   the size of the buffer
44       * @param direct whether the buffer must be direct or not
45       * @return the requested buffer
46       * @see #release(ByteBuffer)
47       */
48      public ByteBuffer acquire(int size, boolean direct);
49  
50      /**
51       * <p>Returns a {@link ByteBuffer}, usually obtained with {@link #acquire(int, boolean)}
52       * (but not necessarily), making it available for recycling and reuse.</p>
53       *
54       * @param buffer the buffer to return
55       * @see #acquire(int, boolean)
56       */
57      public void release(ByteBuffer buffer);
58      
59      default ByteBuffer newByteBuffer(int capacity, boolean direct)
60      {
61          return direct ? BufferUtil.allocateDirect(capacity) : BufferUtil.allocate(capacity);
62      }
63  
64      public static class Lease
65      {
66          private final ByteBufferPool byteBufferPool;
67          private final List<ByteBuffer> buffers;
68          private final List<Boolean> recycles;
69  
70          public Lease(ByteBufferPool byteBufferPool)
71          {
72              this.byteBufferPool = byteBufferPool;
73              this.buffers = new ArrayList<>();
74              this.recycles = new ArrayList<>();
75          }
76  
77          public ByteBuffer acquire(int capacity, boolean direct)
78          {
79              ByteBuffer buffer = byteBufferPool.acquire(capacity, direct);
80              BufferUtil.clearToFill(buffer);
81              return buffer;
82          }
83  
84          public void append(ByteBuffer buffer, boolean recycle)
85          {
86              buffers.add(buffer);
87              recycles.add(recycle);
88          }
89  
90          public void insert(int index, ByteBuffer buffer, boolean recycle)
91          {
92              buffers.add(index, buffer);
93              recycles.add(index, recycle);
94          }
95  
96          public List<ByteBuffer> getByteBuffers()
97          {
98              return buffers;
99          }
100 
101         public long getTotalLength()
102         {
103             long length = 0;
104             for (int i = 0; i < buffers.size(); ++i)
105                 length += buffers.get(i).remaining();
106             return length;
107         }
108 
109         public int getSize()
110         {
111             return buffers.size();
112         }
113 
114         public void recycle()
115         {
116             for (int i = 0; i < buffers.size(); ++i)
117             {
118                 ByteBuffer buffer = buffers.get(i);
119                 if (recycles.get(i))
120                     byteBufferPool.release(buffer);
121             }
122             buffers.clear();
123             recycles.clear();
124         }
125     }
126 
127     
128     class Bucket
129     {
130         private final ByteBufferPool _pool;
131         private final int _capacity;
132         private final AtomicInteger _space;
133         private final Queue<ByteBuffer> _queue= new ConcurrentArrayQueue<>();
134 
135         public Bucket(ByteBufferPool pool, int bufferSize,int maxSize)
136         {
137             _pool=pool;
138             _capacity=bufferSize;
139             _space=maxSize>0?new AtomicInteger(maxSize):null;
140         }
141     
142         public void release(ByteBuffer buffer)
143         {
144             BufferUtil.clear(buffer);
145             if (_space==null)
146                 _queue.offer(buffer);
147             else if (_space.decrementAndGet()>=0)
148                 _queue.offer(buffer);
149             else
150                 _space.incrementAndGet();
151         }
152     
153         public ByteBuffer acquire(boolean direct)
154         {
155             ByteBuffer buffer = _queue.poll();
156             if (buffer == null) 
157                return _pool.newByteBuffer(_capacity,direct);
158             if (_space!=null)
159                 _space.incrementAndGet();
160             return buffer;        
161         }
162     
163         public void clear()
164         {
165             if (_space==null)
166                 _queue.clear();
167             else
168             {
169                 int s=_space.getAndSet(0);
170                 while(s-->0)
171                 {
172                     if (_queue.poll()==null)
173                         _space.incrementAndGet();
174                 }
175             }
176         }
177         
178         boolean isEmpty()
179         {
180             return _queue.isEmpty();
181         }
182         
183         int size()
184         {
185             return _queue.size();
186         }
187         
188         @Override
189         public String toString()
190         {
191             return String.format("Bucket@%x{%d,%d}",hashCode(),_capacity,_queue.size());
192         }
193     }
194     
195     
196 }