001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: MemorySizeTest.java,v 1.21.2.6 2008/01/07 15:14:33 cwl Exp $
007: */
008:
009: package com.sleepycat.je.tree;
010:
011: import java.io.File;
012: import java.io.IOException;
013: import java.util.Iterator;
014:
015: import junit.framework.TestCase;
016:
017: import com.sleepycat.je.CheckpointConfig;
018: import com.sleepycat.je.Cursor;
019: import com.sleepycat.je.Database;
020: import com.sleepycat.je.DatabaseConfig;
021: import com.sleepycat.je.DatabaseEntry;
022: import com.sleepycat.je.DatabaseException;
023: import com.sleepycat.je.DbInternal;
024: import com.sleepycat.je.Environment;
025: import com.sleepycat.je.EnvironmentConfig;
026: import com.sleepycat.je.LockMode;
027: import com.sleepycat.je.OperationStatus;
028: import com.sleepycat.je.Transaction;
029: import com.sleepycat.je.config.EnvironmentParams;
030: import com.sleepycat.je.dbi.DbTree;
031: import com.sleepycat.je.dbi.EnvironmentImpl;
032: import com.sleepycat.je.dbi.INList;
033: import com.sleepycat.je.log.FileManager;
034: import com.sleepycat.je.tree.Key.DumpType;
035: import com.sleepycat.je.txn.Txn;
036: import com.sleepycat.je.util.TestUtils;
037:
038: /**
039: * Check maintenance of the memory size count within nodes.
040: */
041: public class MemorySizeTest extends TestCase {
042: private static final boolean DEBUG = false;
043:
044: private Environment env;
045: private File envHome;
046: private Database db;
047:
048: public MemorySizeTest() throws DatabaseException {
049:
050: envHome = new File(System.getProperty(TestUtils.DEST_DIR));
051:
052: /* Print keys as numbers */
053: Key.DUMP_TYPE = DumpType.BINARY;
054: }
055:
056: public void setUp() throws IOException, DatabaseException {
057:
058: IN.ACCUMULATED_LIMIT = 0;
059: Txn.ACCUMULATED_LIMIT = 0;
060:
061: TestUtils.removeFiles("Setup", envHome, FileManager.JE_SUFFIX);
062:
063: /*
064: * Properties for creating an environment.
065: * Disable the evictor for this test, use larger BINS
066: */
067: EnvironmentConfig envConfig = TestUtils.initEnvConfig();
068: envConfig.setConfigParam(EnvironmentParams.ENV_RUN_EVICTOR
069: .getName(), "false");
070: envConfig.setConfigParam(EnvironmentParams.ENV_RUN_INCOMPRESSOR
071: .getName(), "false");
072: envConfig.setConfigParam(EnvironmentParams.ENV_RUN_CHECKPOINTER
073: .getName(), "false");
074: envConfig.setConfigParam(EnvironmentParams.ENV_RUN_CLEANER
075: .getName(), "false");
076:
077: /* Don't checkpoint utilization info for this test. */
078: DbInternal.setCheckpointUP(envConfig, false);
079:
080: envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(),
081: "4");
082: envConfig.setAllowCreate(true);
083: envConfig.setTxnNoSync(Boolean.getBoolean(TestUtils.NO_SYNC));
084: envConfig.setTransactional(true);
085: env = new Environment(envHome, envConfig);
086: }
087:
088: public void tearDown() throws IOException, DatabaseException {
089:
090: if (env != null) {
091: try {
092: env.close();
093: } catch (DatabaseException E) {
094: }
095: }
096: TestUtils.removeFiles("TearDown", envHome,
097: FileManager.JE_SUFFIX, true);
098: }
099:
100: /*
101: * Do a series of these actions and make sure that the stored memory
102: * sizes match the calculated memory size.
103: * - create db
104: * - insert records, no split
105: * - cause IN split
106: * - modify
107: * - delete, compress
108: * - checkpoint
109: * - evict
110: * - insert duplicates
111: * - cause duplicate IN split
112: * - do an abort
113: */
114: public void testMemSizeMaintenance() throws Throwable {
115:
116: EnvironmentImpl envImpl = DbInternal.envGetEnvironmentImpl(env);
117: try {
118: initDb();
119:
120: /* Insert one record. Adds two INs and an LN to our cost.*/
121: insert((byte) 1, 10, (byte) 1, 100, true);
122: long newSize = TestUtils
123: .validateNodeMemUsage(envImpl, true);
124: assertTrue(newSize > 0);
125:
126: /* Fill out the node. */
127: insert((byte) 2, 10, (byte) 2, 100, true);
128: insert((byte) 3, 10, (byte) 3, 100, true);
129: insert((byte) 4, 10, (byte) 4, 100, true);
130: long oldSize = newSize;
131: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
132: assertTrue(newSize > oldSize);
133:
134: /* Cause a split */
135: insert((byte) 5, 10, (byte) 5, 100, true);
136: insert((byte) 6, 10, (byte) 6, 100, true);
137: insert((byte) 7, 10, (byte) 7, 100, true);
138: oldSize = newSize;
139: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
140: assertTrue(newSize > oldSize);
141:
142: /* Modify data */
143: modify((byte) 1, 10, (byte) 1, 1010, true);
144: modify((byte) 7, 10, (byte) 7, 1010, true);
145: oldSize = newSize;
146: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
147: assertTrue(newSize > oldSize);
148:
149: /* Delete data */
150: delete((byte) 2, 10, true);
151: delete((byte) 6, 10, true);
152: oldSize = newSize;
153: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
154: assertTrue(newSize < oldSize);
155:
156: /* Compress. */
157: compress();
158: oldSize = newSize;
159: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
160: assertTrue(newSize < oldSize);
161:
162: /* Checkpoint */
163: CheckpointConfig ckptConfig = new CheckpointConfig();
164: ckptConfig.setForce(true);
165: env.checkpoint(ckptConfig);
166: oldSize = newSize;
167: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
168: assertEquals(oldSize, newSize);
169:
170: /* Evict by doing LN stripping. */
171: evict();
172: TestUtils.validateNodeMemUsage(envImpl, true);
173: oldSize = newSize;
174: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
175: assertTrue(newSize < oldSize);
176:
177: /* insert duplicates */
178: insert((byte) 3, 10, (byte) 30, 200, true);
179: insert((byte) 3, 10, (byte) 31, 200, true);
180: insert((byte) 3, 10, (byte) 32, 200, true);
181: insert((byte) 3, 10, (byte) 33, 200, true);
182: oldSize = newSize;
183: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
184: assertTrue(newSize > oldSize);
185:
186: /* create duplicate split. */
187: insert((byte) 3, 10, (byte) 34, 200, true);
188: insert((byte) 3, 10, (byte) 35, 200, true);
189: oldSize = newSize;
190: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
191: assertTrue(newSize > oldSize);
192:
193: /* There should be 11 records. */
194: checkCount(11);
195: oldSize = newSize;
196: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
197: assertTrue(newSize > oldSize);
198:
199: /* modify and abort */
200: modify((byte) 5, 10, (byte) 30, 1000, false);
201: oldSize = newSize;
202: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
203: assertTrue(newSize == oldSize);
204:
205: /* delete and abort */
206: delete((byte) 1, 10, false);
207: delete((byte) 7, 10, false);
208: oldSize = newSize;
209: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
210:
211: /* Delete dup */
212: delete((byte) 3, 10, (byte) 34, 200, false);
213: oldSize = newSize;
214: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
215:
216: /* insert and abort */
217: insert((byte) 2, 10, (byte) 5, 100, false);
218: insert((byte) 6, 10, (byte) 6, 100, false);
219: insert((byte) 8, 10, (byte) 7, 100, false);
220: oldSize = newSize;
221: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
222:
223: } catch (Throwable t) {
224: t.printStackTrace();
225: throw t;
226: } finally {
227: if (db != null) {
228: db.close();
229: }
230:
231: if (env != null) {
232: env.close();
233: }
234:
235: }
236: }
237:
238: /*
239: * Do a series of these actions and make sure that the stored memory
240: * sizes match the calculated memory size.
241: * - create db
242: * - insert records, cause split
243: * - delete
244: * - insert and re-use slots.
245: */
246: public void testSlotReuseMaintenance() throws Exception {
247:
248: EnvironmentImpl envImpl = DbInternal.envGetEnvironmentImpl(env);
249: try {
250:
251: initDb();
252:
253: /* Insert enough records to create one node. */
254: insert((byte) 1, 10, (byte) 1, 100, true);
255: insert((byte) 2, 10, (byte) 2, 100, true);
256: insert((byte) 3, 10, (byte) 3, 100, true);
257: long newSize = TestUtils
258: .validateNodeMemUsage(envImpl, true);
259:
260: /* Delete */
261: delete((byte) 3, 10, true);
262: long oldSize = newSize;
263: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
264: assertTrue(newSize < oldSize);
265:
266: /* Insert again, reuse those slots */
267: insert((byte) 3, 10, (byte) 2, 400, true);
268: oldSize = newSize;
269: newSize = TestUtils.validateNodeMemUsage(envImpl, true);
270: assertTrue(newSize > oldSize);
271: } catch (Exception e) {
272: e.printStackTrace();
273: throw e;
274: } finally {
275: if (db != null) {
276: db.close();
277: }
278:
279: if (env != null) {
280: env.close();
281: }
282: }
283: }
284:
285: private void initDb() throws DatabaseException {
286:
287: DatabaseConfig dbConfig = new DatabaseConfig();
288: dbConfig.setAllowCreate(true);
289: dbConfig.setSortedDuplicates(true);
290: dbConfig.setTransactional(true);
291: db = env.openDatabase(null, "foo", dbConfig);
292: }
293:
294: private void insert(byte keyVal, int keySize, byte dataVal,
295: int dataSize, boolean commit) throws DatabaseException {
296:
297: Transaction txn = null;
298: if (!commit) {
299: txn = env.beginTransaction(null, null);
300: }
301: assertEquals(OperationStatus.SUCCESS, db.put(null, getEntry(
302: keyVal, keySize), getEntry(dataVal, dataSize)));
303: if (!commit) {
304: txn.abort();
305: }
306: }
307:
308: private void modify(byte keyVal, int keySize, byte dataVal,
309: int dataSize, boolean commit) throws DatabaseException {
310:
311: Transaction txn = null;
312:
313: txn = env.beginTransaction(null, null);
314: Cursor cursor = db.openCursor(txn, null);
315: assertEquals(OperationStatus.SUCCESS, cursor.getSearchKey(
316: getEntry(keyVal, keySize), new DatabaseEntry(),
317: LockMode.DEFAULT));
318: assertEquals(OperationStatus.SUCCESS, cursor.delete());
319: assertEquals(OperationStatus.SUCCESS, cursor.put(getEntry(
320: keyVal, keySize), getEntry(dataVal, dataSize)));
321: cursor.close();
322:
323: if (commit) {
324: txn.commit();
325: } else {
326: txn.abort();
327: }
328: }
329:
330: private void delete(byte keyVal, int keySize, boolean commit)
331: throws DatabaseException {
332:
333: Transaction txn = null;
334: if (!commit) {
335: txn = env.beginTransaction(null, null);
336: }
337: assertEquals(OperationStatus.SUCCESS, db.delete(txn, getEntry(
338: keyVal, keySize)));
339: if (!commit) {
340: txn.abort();
341: }
342: }
343:
344: private void delete(byte keyVal, int keySize, byte dataVal,
345: int dataSize, boolean commit) throws DatabaseException {
346:
347: Transaction txn = env.beginTransaction(null, null);
348: Cursor cursor = db.openCursor(txn, null);
349: assertEquals(OperationStatus.SUCCESS, cursor.getSearchBoth(
350: getEntry(keyVal, keySize), getEntry(dataVal, dataSize),
351: LockMode.DEFAULT));
352: assertEquals(OperationStatus.SUCCESS, cursor.delete());
353: cursor.close();
354:
355: if (commit) {
356: txn.commit();
357: } else {
358: txn.abort();
359: }
360: }
361:
362: /*
363: * Fake compressing daemon by call BIN.compress explicitly on all
364: * BINS on the IN list.
365: */
366: private void compress() throws DatabaseException {
367:
368: INList inList = DbInternal.envGetEnvironmentImpl(env)
369: .getInMemoryINs();
370: inList.latchMajor();
371: try {
372: Iterator iter = inList.iterator();
373: while (iter.hasNext()) {
374: IN in = (IN) iter.next();
375: in.latch();
376: if (in instanceof BIN) {
377: in.compress(null, true, null);
378: }
379: in.releaseLatch();
380: }
381: } finally {
382: inList.releaseMajorLatch();
383: }
384: }
385:
386: /*
387: * Fake eviction daemon by call BIN.evictLNs explicitly on all
388: * BINS on the IN list.
389: */
390: private void evict() throws DatabaseException {
391:
392: INList inList = DbInternal.envGetEnvironmentImpl(env)
393: .getInMemoryINs();
394: inList.latchMajor();
395: try {
396: Iterator iter = inList.iterator();
397: while (iter.hasNext()) {
398: IN in = (IN) iter.next();
399: if (in instanceof BIN
400: && !in.getDatabase().getId().equals(
401: DbTree.ID_DB_ID)) {
402: BIN bin = (BIN) in;
403: bin.latch();
404: assertTrue(bin.evictLNs() > 0);
405: bin.releaseLatch();
406: }
407: }
408: } finally {
409: inList.releaseMajorLatch();
410: }
411: }
412:
413: private DatabaseEntry getEntry(byte val, int size) {
414: byte[] bArray = new byte[size];
415: bArray[0] = val;
416: return new DatabaseEntry(bArray);
417: }
418:
419: private void checkCount(int expectedCount) throws DatabaseException {
420:
421: Cursor cursor = db.openCursor(null, null);
422: int count = 0;
423: while (cursor.getNext(new DatabaseEntry(), new DatabaseEntry(),
424: LockMode.DEFAULT) == OperationStatus.SUCCESS) {
425: count++;
426: }
427: cursor.close();
428: assertEquals(expectedCount, count);
429: }
430:
431: private void dumpINList() throws DatabaseException {
432:
433: EnvironmentImpl envImpl = DbInternal.envGetEnvironmentImpl(env);
434: INList inList = envImpl.getInMemoryINs();
435: inList.latchMajor();
436: try {
437: Iterator iter = inList.iterator();
438: while (iter.hasNext()) {
439: IN in = (IN) iter.next();
440: System.out.println("in nodeId=" + in.getNodeId());
441: }
442: } finally {
443: inList.releaseMajorLatch();
444: }
445: }
446: }
|