View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2014 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.ConcurrentHashMap;
24  import java.util.concurrent.ConcurrentLinkedQueue;
25  import java.util.concurrent.ConcurrentMap;
26  
27  import org.eclipse.jetty.util.BufferUtil;
28  
29  public class MappedByteBufferPool implements ByteBufferPool
30  {
31      private final ConcurrentMap<Integer, Queue<ByteBuffer>> directBuffers = new ConcurrentHashMap<>();
32      private final ConcurrentMap<Integer, Queue<ByteBuffer>> heapBuffers = new ConcurrentHashMap<>();
33      private final int factor;
34  
35      public MappedByteBufferPool()
36      {
37          this(1024);
38      }
39  
40      public MappedByteBufferPool(int factor)
41      {
42          this.factor = factor;
43      }
44  
45      @Override
46      public ByteBuffer acquire(int size, boolean direct)
47      {
48          int bucket = bucketFor(size);
49          ConcurrentMap<Integer, Queue<ByteBuffer>> buffers = buffersFor(direct);
50  
51          ByteBuffer result = null;
52          Queue<ByteBuffer> byteBuffers = buffers.get(bucket);
53          if (byteBuffers != null)
54              result = byteBuffers.poll();
55  
56          if (result == null)
57          {
58              int capacity = bucket * factor;
59              result = direct ? BufferUtil.allocateDirect(capacity) : BufferUtil.allocate(capacity);
60          }
61  
62          BufferUtil.clear(result);
63          return result;
64      }
65  
66      @Override
67      public void release(ByteBuffer buffer)
68      {
69          if (buffer == null)
70              return; // nothing to do
71          
72          // validate that this buffer is from this pool
73          assert((buffer.capacity() % factor) == 0);
74          
75          int bucket = bucketFor(buffer.capacity());
76          ConcurrentMap<Integer, Queue<ByteBuffer>> buffers = buffersFor(buffer.isDirect());
77  
78          // Avoid to create a new queue every time, just to be discarded immediately
79          Queue<ByteBuffer> byteBuffers = buffers.get(bucket);
80          if (byteBuffers == null)
81          {
82              byteBuffers = new ConcurrentLinkedQueue<>();
83              Queue<ByteBuffer> existing = buffers.putIfAbsent(bucket, byteBuffers);
84              if (existing != null)
85                  byteBuffers = existing;
86          }
87  
88          BufferUtil.clear(buffer);
89          byteBuffers.offer(buffer);
90      }
91  
92      public void clear()
93      {
94          directBuffers.clear();
95          heapBuffers.clear();
96      }
97  
98      private int bucketFor(int size)
99      {
100         int bucket = size / factor;
101         if (size % factor > 0)
102             ++bucket;
103         return bucket;
104     }
105 
106     // Package local for testing
107     ConcurrentMap<Integer, Queue<ByteBuffer>> buffersFor(boolean direct)
108     {
109         return direct ? directBuffers : heapBuffers;
110     }
111 }