001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (license2)
004: * Initial Developer: H2 Group
005: */
006: package org.h2.test.unit;
007:
008: import java.io.ByteArrayInputStream;
009: import java.io.StringReader;
010: import java.math.BigDecimal;
011: import java.sql.SQLException;
012: import java.util.ArrayList;
013: import java.util.IdentityHashMap;
014: import java.util.Random;
015:
016: import org.h2.constant.SysProperties;
017: import org.h2.store.DataHandler;
018: import org.h2.store.FileStore;
019: import org.h2.test.TestBase;
020: import org.h2.util.MemoryUtils;
021: import org.h2.util.SmallLRUCache;
022: import org.h2.value.Value;
023: import org.h2.value.ValueArray;
024: import org.h2.value.ValueBoolean;
025: import org.h2.value.ValueByte;
026: import org.h2.value.ValueBytes;
027: import org.h2.value.ValueDate;
028: import org.h2.value.ValueDecimal;
029: import org.h2.value.ValueDouble;
030: import org.h2.value.ValueFloat;
031: import org.h2.value.ValueInt;
032: import org.h2.value.ValueJavaObject;
033: import org.h2.value.ValueLob;
034: import org.h2.value.ValueLong;
035: import org.h2.value.ValueNull;
036: import org.h2.value.ValueShort;
037: import org.h2.value.ValueString;
038: import org.h2.value.ValueStringFixed;
039: import org.h2.value.ValueStringIgnoreCase;
040: import org.h2.value.ValueTime;
041: import org.h2.value.ValueTimestamp;
042: import org.h2.value.ValueUuid;
043:
044: /**
045: * Tests the memory consumption of values. Values can estimate how much memory
046: * they occupy, and this tests if this estimation is correct.
047: */
048: public class TestValueMemory extends TestBase implements DataHandler {
049:
050: private Random random = new Random(1);
051:
052: public void test() throws Exception {
053: for (int i = 0; i < Value.TYPE_COUNT; i++) {
054: testType(i);
055: }
056: }
057:
058: private void testType(int type) throws Exception {
059: System.gc();
060: System.gc();
061: long first = MemoryUtils.getMemoryUsed();
062: ArrayList list = new ArrayList();
063: long memory = 0;
064: for (int i = 0; memory < 1000000; i++) {
065: Value v = create(type);
066: memory += v.getMemory();
067: list.add(v);
068: }
069: Object[] array = list.toArray();
070: IdentityHashMap map = new IdentityHashMap();
071: for (int i = 0; i < array.length; i++) {
072: map.put(array[i], array[i]);
073: }
074: int size = map.size();
075: map.clear();
076: map = null;
077: list = null;
078: System.gc();
079: System.gc();
080: long used = MemoryUtils.getMemoryUsed() - first;
081: memory /= 1024;
082: if (used > memory * 3) {
083: error("Type: " + type + " Used memory: " + used
084: + " calculated: " + memory + " " + array.length
085: + " size: " + size);
086: }
087: }
088:
089: Value create(int type) throws SQLException {
090: switch (type) {
091: case Value.NULL:
092: return ValueNull.INSTANCE;
093: case Value.BOOLEAN:
094: return ValueBoolean.get(false);
095: case Value.BYTE:
096: return ValueByte.get((byte) random.nextInt());
097: case Value.SHORT:
098: return ValueShort.get((short) random.nextInt());
099: case Value.INT:
100: return ValueInt.get(random.nextInt());
101: case Value.LONG:
102: return ValueLong.get(random.nextLong());
103: case Value.DECIMAL:
104: return ValueDecimal.get(new BigDecimal(random.nextInt()));
105: // + "12123344563456345634565234523451312312"
106: case Value.DOUBLE:
107: return ValueDouble.get(random.nextDouble());
108: case Value.FLOAT:
109: return ValueFloat.get(random.nextFloat());
110: case Value.TIME:
111: return ValueTime.get(new java.sql.Time(random.nextLong()));
112: case Value.DATE:
113: return ValueDate.get(new java.sql.Date(random.nextLong()));
114: case Value.TIMESTAMP:
115: return ValueTimestamp.get(new java.sql.Timestamp(random
116: .nextLong()));
117: case Value.BYTES:
118: return ValueBytes.get(randomBytes(random.nextInt(1000)));
119: case Value.STRING:
120: return ValueString.get(randomString(random.nextInt(100)));
121: case Value.STRING_IGNORECASE:
122: return ValueStringIgnoreCase.get(randomString(random
123: .nextInt(100)));
124: case Value.BLOB: {
125: int len = (int) Math.abs(random.nextGaussian() * 100);
126: byte[] data = randomBytes(len);
127: return ValueLob.createBlob(new ByteArrayInputStream(data),
128: len, this );
129: }
130: case Value.CLOB: {
131: int len = (int) Math.abs(random.nextGaussian() * 100);
132: String s = randomString(len);
133: return ValueLob.createClob(new StringReader(s), len, this );
134: }
135: case Value.ARRAY: {
136: int len = random.nextInt(20);
137: Value[] list = new Value[len];
138: for (int i = 0; i < list.length; i++) {
139: list[i] = create(Value.STRING);
140: }
141: return ValueArray.get(list);
142: }
143: case Value.RESULT_SET:
144: // not supported currently
145: return ValueNull.INSTANCE;
146: case Value.JAVA_OBJECT:
147: return ValueJavaObject.getNoCopy(randomBytes(random
148: .nextInt(100)));
149: case Value.UUID:
150: return ValueUuid.get(random.nextLong(), random.nextLong());
151: case Value.STRING_FIXED:
152: return ValueStringFixed.get(randomString(random
153: .nextInt(100)));
154: default:
155: throw new Error("type=" + type);
156: }
157: }
158:
159: byte[] randomBytes(int len) {
160: byte[] data = new byte[len];
161: if (random.nextBoolean()) {
162: // don't initialize always (compression)
163: random.nextBytes(data);
164: }
165: return data;
166: }
167:
168: String randomString(int len) {
169: char[] chars = new char[len];
170: if (random.nextBoolean()) {
171: // don't initialize always (compression)
172: for (int i = 0; i < chars.length; i++) {
173: chars[i] = (char) (random.nextGaussian() * 100);
174: }
175: }
176: return new String(chars);
177: }
178:
179: public int allocateObjectId(boolean needFresh, boolean dataFile) {
180: return 0;
181: }
182:
183: public void checkPowerOff() throws SQLException {
184: }
185:
186: public void checkWritingAllowed() throws SQLException {
187: }
188:
189: public int compareTypeSave(Value a, Value b) throws SQLException {
190: return 0;
191: }
192:
193: public String createTempFile() throws SQLException {
194: return baseDir + "/valueMemory/data";
195: }
196:
197: public void freeUpDiskSpace() throws SQLException {
198: }
199:
200: public int getChecksum(byte[] data, int start, int end) {
201: return 0;
202: }
203:
204: public String getDatabasePath() {
205: return baseDir + "/valueMemory";
206: }
207:
208: public String getLobCompressionAlgorithm(int type) {
209: return "LZF";
210: }
211:
212: public Object getLobSyncObject() {
213: return this ;
214: }
215:
216: public int getMaxLengthInplaceLob() {
217: return 100;
218: }
219:
220: public boolean getTextStorage() {
221: return false;
222: }
223:
224: public void handleInvalidChecksum() throws SQLException {
225: }
226:
227: public FileStore openFile(String name, String mode,
228: boolean mustExist) throws SQLException {
229: return FileStore.open(this , name, mode, null);
230: }
231:
232: public boolean getLobFilesInDirectories() {
233: return SysProperties.LOB_FILES_IN_DIRECTORIES;
234: }
235:
236: public SmallLRUCache getLobFileListCache() {
237: return null;
238: }
239:
240: }
|