1 package org.apache.lucene.util;
3 import java.util.concurrent.atomic.AtomicLong;
5 import org.apache.lucene.util.ByteBlockPool.Allocator;
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
15 * http://www.apache.org/licenses/LICENSE-2.0
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.
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()}.
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;
39 * Creates a new {@link RecyclingByteBlockAllocator}
42 * the block size in bytes
43 * @param maxBufferedBlocks
44 * maximum number of buffered byte block
46 * {@link AtomicLong} reference counting internally allocated bytes
48 * @see DummyConcurrentLock
50 public RecyclingByteBlockAllocator(int blockSize, int maxBufferedBlocks,
51 AtomicLong bytesUsed) {
53 freeByteBlocks = new byte[Math.min(10, maxBufferedBlocks)][];
54 this.maxBufferedBlocks = maxBufferedBlocks;
55 this.bytesUsed = bytesUsed;
59 * Creates a new {@link RecyclingByteBlockAllocator} with a
60 * {@link DummyConcurrentLock} instance.
63 * the block size in bytes
64 * @param maxBufferedBlocks
65 * maximum number of buffered byte block
67 public RecyclingByteBlockAllocator(int blockSize, int maxBufferedBlocks) {
68 this(blockSize, maxBufferedBlocks, new AtomicLong());
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.
78 public RecyclingByteBlockAllocator() {
79 this(ByteBlockPool.BYTE_BLOCK_SIZE, 64, new AtomicLong());
83 public synchronized byte[] getByteBlock() {
84 if (freeBlocks == 0) {
85 bytesUsed.addAndGet(blockSize);
86 return new byte[blockSize];
88 final byte[] b = freeByteBlocks[--freeBlocks];
89 freeByteBlocks[freeBlocks] = null;
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;
103 final int stop = start + numBlocks;
104 for (int i = start; i < stop; i++) {
105 freeByteBlocks[freeBlocks++] = blocks[i];
108 for (int i = stop; i < end; i++) {
111 bytesUsed.addAndGet(-(end - stop) * blockSize);
112 assert bytesUsed.get() >= 0;
116 * @return the number of currently buffered blocks
118 public synchronized int numBufferedBlocks() {
123 * @return the number of bytes currently allocated by this {@link Allocator}
125 public long bytesUsed() {
126 return bytesUsed.get();
130 * @return the maximum number of buffered byte blocks
132 public int maxBufferedBlocks() {
133 return maxBufferedBlocks;
137 * Removes the given number of byte blocks from the buffer if possible.
140 * the number of byte blocks to remove
141 * @return the number of actually removed buffers
143 public synchronized int freeBlocks(int num) {
147 if (num > freeBlocks) {
151 stop = freeBlocks - num;
154 while (freeBlocks > stop) {
155 freeByteBlocks[--freeBlocks] = null;
157 bytesUsed.addAndGet(-count*blockSize);
158 assert bytesUsed.get() >= 0;