001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.mina.util.byteaccess;
021
022import java.util.ArrayList;
023import java.util.Stack;
024
025import org.apache.mina.core.buffer.IoBuffer;
026
027/**
028 * Creates <code>ByteArray</code>s, using a pool to reduce allocation where possible.
029 *
030 * WARNING: This code has never been run!
031 * 
032 *
033 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
034 */
035public class ByteArrayPool implements ByteArrayFactory {
036
037    private final int MAX_BITS = 32;
038
039    private boolean freed;
040
041    private final boolean direct;
042
043    private ArrayList<Stack<DirectBufferByteArray>> freeBuffers;
044
045    private int freeBufferCount = 0;
046
047    private long freeMemory = 0;
048
049    private final int maxFreeBuffers;
050
051    private final int maxFreeMemory;
052
053    /**
054     * Creates a new instance of ByteArrayPool.
055     *
056     * @param direct
057     *  If we should use direct buffers
058     * @param maxFreeBuffers
059     *  The maximum number of free buffers
060     * @param maxFreeMemory
061     *  The maximum amount of free memory allowed
062     */
063    public ByteArrayPool(boolean direct, int maxFreeBuffers, int maxFreeMemory) {
064        this.direct = direct;
065        freeBuffers = new ArrayList<Stack<DirectBufferByteArray>>();
066        for (int i = 0; i < MAX_BITS; i++) {
067            freeBuffers.add(new Stack<DirectBufferByteArray>());
068        }
069        this.maxFreeBuffers = maxFreeBuffers;
070        this.maxFreeMemory = maxFreeMemory;
071        this.freed = false;
072    }
073
074    /**
075     * Creates a new instance of a {@link ByteArray}
076     * 
077     * @param size
078     *  The size of the array to build
079     */
080    public ByteArray create(int size) {
081        if (size < 1) {
082            throw new IllegalArgumentException("Buffer size must be at least 1: " + size);
083        }
084        int bits = bits(size);
085        synchronized (this) {
086            if (!freeBuffers.get(bits).isEmpty()) {
087                DirectBufferByteArray ba = freeBuffers.get(bits).pop();
088                ba.setFreed(false);
089                ba.getSingleIoBuffer().limit(size);
090                return ba;
091            }
092        }
093        IoBuffer bb;
094        int bbSize = 1 << bits;
095        bb = IoBuffer.allocate(bbSize, direct);
096        bb.limit(size);
097        DirectBufferByteArray ba = new DirectBufferByteArray(bb);
098        ba.setFreed(false);
099        return ba;
100    }
101
102    private int bits(int index) {
103        int bits = 0;
104        while (1 << bits < index) {
105            bits++;
106        }
107        return bits;
108    }
109
110    /**
111     * Frees the buffers
112     *
113     */
114    public void free() {
115        synchronized (this) {
116            if (freed) {
117                throw new IllegalStateException("Already freed.");
118            }
119            freed = true;
120            freeBuffers.clear();
121            freeBuffers = null;
122        }
123    }
124
125    private class DirectBufferByteArray extends BufferByteArray {
126
127        private boolean freed;
128
129        public DirectBufferByteArray(IoBuffer bb) {
130            super(bb);
131        }
132
133        public void setFreed(boolean freed) {
134            this.freed = freed;
135        }
136
137        @Override
138        public void free() {
139            synchronized (this) {
140                if (freed) {
141                    throw new IllegalStateException("Already freed.");
142                }
143                freed = true;
144            }
145            int bits = bits(last());
146            synchronized (ByteArrayPool.this) {
147                if (freeBuffers != null && freeBufferCount < maxFreeBuffers && freeMemory + last() <= maxFreeMemory) {
148                    freeBuffers.get(bits).push(this);
149                    freeBufferCount++;
150                    freeMemory += last();
151                    return;
152                }
153            }
154        }
155
156    }
157
158}