add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / src / java / org / apache / lucene / util / RecyclingByteBlockAllocator.java
1 package org.apache.lucene.util;
2
3 import java.util.concurrent.atomic.AtomicLong;
4
5 import org.apache.lucene.util.ByteBlockPool.Allocator;
6
7 /**
8  * Licensed to the Apache Software Foundation (ASF) under one or more
9  * contributor license agreements.  See the NOTICE file distributed with
10  * this work for additional information regarding copyright ownership.
11  * The ASF licenses this file to You under the Apache License, Version 2.0
12  * (the "License"); you may not use this file except in compliance with
13  * the License.  You may obtain a copy of the License at
14  *
15  *     http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23
24 /**
25  * A {@link ByteBlockPool.Allocator} implementation that recycles unused byte
26  * blocks in a buffer and reuses them in subsequent calls to
27  * {@link #getByteBlock()}.
28  * 
29  * @lucene.internal
30  */
31 public final class RecyclingByteBlockAllocator extends ByteBlockPool.Allocator {
32   private byte[][] freeByteBlocks;
33   private final int maxBufferedBlocks;
34   private int freeBlocks = 0;
35   private final AtomicLong bytesUsed;
36   public static final int DEFAULT_BUFFERED_BLOCKS = 64;
37
38   /**
39    * Creates a new {@link RecyclingByteBlockAllocator}
40    * 
41    * @param blockSize
42    *          the block size in bytes
43    * @param maxBufferedBlocks
44    *          maximum number of buffered byte block
45    * @param bytesUsed
46    *          {@link AtomicLong} reference counting internally allocated bytes
47    * 
48    * @see DummyConcurrentLock
49    */
50   public RecyclingByteBlockAllocator(int blockSize, int maxBufferedBlocks,
51       AtomicLong bytesUsed) {
52     super(blockSize);
53     freeByteBlocks = new byte[Math.min(10, maxBufferedBlocks)][];
54     this.maxBufferedBlocks = maxBufferedBlocks;
55     this.bytesUsed = bytesUsed;
56   }
57
58   /**
59    * Creates a new {@link RecyclingByteBlockAllocator} with a
60    * {@link DummyConcurrentLock} instance.
61    * 
62    * @param blockSize
63    *          the block size in bytes
64    * @param maxBufferedBlocks
65    *          maximum number of buffered byte block
66    */
67   public RecyclingByteBlockAllocator(int blockSize, int maxBufferedBlocks) {
68     this(blockSize, maxBufferedBlocks, new AtomicLong());
69   }
70
71   /**
72    * Creates a new {@link RecyclingByteBlockAllocator} with a block size of
73    * {@link ByteBlockPool#BYTE_BLOCK_SIZE}, upper buffered docs limit of
74    * {@link #DEFAULT_BUFFERED_BLOCKS} ({@value #DEFAULT_BUFFERED_BLOCKS}) and a
75    * {@link DummyConcurrentLock} instance.
76    * 
77    */
78   public RecyclingByteBlockAllocator() {
79     this(ByteBlockPool.BYTE_BLOCK_SIZE, 64, new AtomicLong());
80   }
81
82   @Override
83   public synchronized byte[] getByteBlock() {
84     if (freeBlocks == 0) {
85       bytesUsed.addAndGet(blockSize);
86       return new byte[blockSize];
87     }
88     final byte[] b = freeByteBlocks[--freeBlocks];
89     freeByteBlocks[freeBlocks] = null;
90     return b;
91   }
92
93   @Override
94   public synchronized void recycleByteBlocks(byte[][] blocks, int start, int end) {
95     final int numBlocks = Math.min(maxBufferedBlocks - freeBlocks, end - start);
96     final int size = freeBlocks + numBlocks;
97     if (size >= freeByteBlocks.length) {
98       final byte[][] newBlocks = new byte[ArrayUtil.oversize(size,
99           RamUsageEstimator.NUM_BYTES_OBJECT_REF)][];
100       System.arraycopy(freeByteBlocks, 0, newBlocks, 0, freeBlocks);
101       freeByteBlocks = newBlocks;
102     }
103     final int stop = start + numBlocks;
104     for (int i = start; i < stop; i++) {
105       freeByteBlocks[freeBlocks++] = blocks[i];
106       blocks[i] = null;
107     }
108     for (int i = stop; i < end; i++) {
109       blocks[i] = null;
110     }
111     bytesUsed.addAndGet(-(end - stop) * blockSize);
112     assert bytesUsed.get() >= 0;
113   }
114
115   /**
116    * @return the number of currently buffered blocks
117    */
118   public synchronized int numBufferedBlocks() {
119     return freeBlocks;
120   }
121
122   /**
123    * @return the number of bytes currently allocated by this {@link Allocator}
124    */
125   public long bytesUsed() {
126     return bytesUsed.get();
127   }
128
129   /**
130    * @return the maximum number of buffered byte blocks
131    */
132   public int maxBufferedBlocks() {
133     return maxBufferedBlocks;
134   }
135
136   /**
137    * Removes the given number of byte blocks from the buffer if possible.
138    * 
139    * @param num
140    *          the number of byte blocks to remove
141    * @return the number of actually removed buffers
142    */
143   public synchronized int freeBlocks(int num) {
144     assert num >= 0;
145     final int stop;
146     final int count;
147     if (num > freeBlocks) {
148       stop = 0;
149       count = freeBlocks;
150     } else {
151       stop = freeBlocks - num;
152       count = num;
153     }
154     while (freeBlocks > stop) {
155       freeByteBlocks[--freeBlocks] = null;
156     }
157     bytesUsed.addAndGet(-count*blockSize);
158     assert bytesUsed.get() >= 0;
159     return count;
160   }
161 }