/* Copyright (c) 2001-2009, The HSQL Development Group * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the HSQL Development Group nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.hsqldb.store; import java.math.BigDecimal; import org.hsqldb.types.TimestampData; /** * Supports pooling of Integer, Long, Double, BigDecimal, String and Date * Java Objects. Leads to reduction in memory use when an Object is used more * then twice in the database. * * getXXX methods are used for retrival of values. If a value is not in * the pool, it is added to the pool and returned. When the pool gets * full, half the contents that have been accessed less recently are purged. * * @author Fred Toussi (fredt@users dot sourceforge.net) * @version 1.9.0 * @since 1.7.2 */ public class ValuePool { // static ValuePoolHashMap intPool; static ValuePoolHashMap longPool; static ValuePoolHashMap doublePool; static ValuePoolHashMap bigdecimalPool; static ValuePoolHashMap stringPool; static ValuePoolHashMap datePool; static final int SPACE_STRING_SIZE = 50; static final int DEFAULT_VALUE_POOL_SIZE = 8192; static final int[] defaultPoolLookupSize = new int[] { DEFAULT_VALUE_POOL_SIZE, DEFAULT_VALUE_POOL_SIZE, DEFAULT_VALUE_POOL_SIZE, DEFAULT_VALUE_POOL_SIZE, DEFAULT_VALUE_POOL_SIZE, DEFAULT_VALUE_POOL_SIZE }; static final int POOLS_COUNT = defaultPoolLookupSize.length; static final int defaultSizeFactor = 2; static final int defaultMaxStringLength = 16; // static ValuePoolHashMap[] poolList; // static int maxStringLength; // static String[] spaceStrings; // static { initPool(); } public static final Integer INTEGER_0 = ValuePool.getInt(0); public static final Integer INTEGER_1 = ValuePool.getInt(1); public static final BigDecimal BIG_DECIMAL_0 = ValuePool.getBigDecimal(new BigDecimal(0.0)); public static final BigDecimal BIG_DECIMAL_1 = ValuePool.getBigDecimal(new BigDecimal(1.0)); // public final static String[] emptyStringArray = new String[]{}; public final static Object[] emptyObjectArray = new Object[]{}; public final static int[] emptyIntArray = new int[]{}; // private static void initPool() { int[] sizeArray = defaultPoolLookupSize; int sizeFactor = defaultSizeFactor; spaceStrings = new String[SPACE_STRING_SIZE + 1]; synchronized (ValuePool.class) { maxStringLength = defaultMaxStringLength; poolList = new ValuePoolHashMap[POOLS_COUNT]; for (int i = 0; i < POOLS_COUNT; i++) { int size = sizeArray[i]; poolList[i] = new ValuePoolHashMap(size, size * sizeFactor, BaseHashMap.PURGE_HALF); } intPool = poolList[0]; longPool = poolList[1]; doublePool = poolList[2]; bigdecimalPool = poolList[3]; stringPool = poolList[4]; datePool = poolList[5]; char[] c = new char[SPACE_STRING_SIZE]; for (int i = 0; i < SPACE_STRING_SIZE; i++) { c[i] = ' '; } String s = new String(c); for (int i = 0; i <= SPACE_STRING_SIZE; i++) { spaceStrings[i] = s.substring(0, i); } } } public static int getMaxStringLength() { return maxStringLength; } public static void resetPool(int[] sizeArray, int sizeFactor) { synchronized (ValuePool.class) { for (int i = 0; i < POOLS_COUNT; i++) { poolList[i].resetCapacity(sizeArray[i] * sizeFactor, BaseHashMap.PURGE_HALF); } } } public static void resetPool() { synchronized (ValuePool.class) { resetPool(defaultPoolLookupSize, defaultSizeFactor); } } public static void clearPool() { synchronized (ValuePool.class) { for (int i = 0; i < POOLS_COUNT; i++) { poolList[i].clear(); } } } public static String getSpaces(int length) { if (length < SPACE_STRING_SIZE) { return spaceStrings[length]; } int times = length / SPACE_STRING_SIZE; int add = length % SPACE_STRING_SIZE; StringBuffer sb = new StringBuffer(length); for (int i = 0; i < times; i++) { sb.append(spaceStrings[SPACE_STRING_SIZE]); } sb.append(spaceStrings[add]); return sb.toString(); } public static Integer getInt(int val) { synchronized (intPool) { return intPool.getOrAddInteger(val); } } public static Long getLong(long val) { synchronized (longPool) { return longPool.getOrAddLong(val); } } public static Double getDouble(long val) { synchronized (doublePool) { return doublePool.getOrAddDouble(val); } } public static String getString(String val) { if (val == null || val.length() > maxStringLength) { return val; } synchronized (stringPool) { return stringPool.getOrAddString(val); } } public static String getSubString(String val, int start, int limit) { synchronized (stringPool) { return stringPool.getOrAddString(null); } } public static TimestampData getDate(long val) { synchronized (datePool) { return datePool.getOrAddDate(val); } } public static BigDecimal getBigDecimal(BigDecimal val) { if (val == null) { return val; } synchronized (bigdecimalPool) { return (BigDecimal) bigdecimalPool.getOrAddObject(val); } } public static Boolean getBoolean(boolean b) { return b ? Boolean.TRUE : Boolean.FALSE; } }