001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: FileSelectionTest.java,v 1.31.2.3 2008/01/07 15:14:25 cwl Exp $
007: */
008:
009: package com.sleepycat.je.cleaner;
010:
011: import java.io.File;
012: import java.io.IOException;
013: import java.util.ArrayList;
014: import java.util.HashSet;
015: import java.util.Iterator;
016: import java.util.List;
017: import java.util.Set;
018:
019: import junit.framework.TestCase;
020:
021: import com.sleepycat.je.CheckpointConfig;
022: import com.sleepycat.je.Cursor;
023: import com.sleepycat.je.Database;
024: import com.sleepycat.je.DatabaseConfig;
025: import com.sleepycat.je.DatabaseEntry;
026: import com.sleepycat.je.DatabaseException;
027: import com.sleepycat.je.DbInternal;
028: import com.sleepycat.je.DbTestProxy;
029: import com.sleepycat.je.Environment;
030: import com.sleepycat.je.EnvironmentConfig;
031: import com.sleepycat.je.LockMode;
032: import com.sleepycat.je.OperationStatus;
033: import com.sleepycat.je.Transaction;
034: import com.sleepycat.je.config.EnvironmentParams;
035: import com.sleepycat.je.dbi.CursorImpl;
036: import com.sleepycat.je.dbi.EnvironmentImpl;
037: import com.sleepycat.je.log.FileManager;
038: import com.sleepycat.je.tree.BIN;
039: import com.sleepycat.je.util.TestUtils;
040: import com.sleepycat.je.utilint.DbLsn;
041:
042: public class FileSelectionTest extends TestCase {
043:
044: private static final int DATA_SIZE = 100;
045: private static final int FILE_SIZE = 4096 * 10;
046: private static final int INITIAL_FILES = 5;
047: private static final byte[] MAIN_KEY_FOR_DUPS = { 0, 1, 2, 3, 4, 5 };
048:
049: private static final EnvironmentConfig envConfig = initConfig();
050: private static final EnvironmentConfig highUtilizationConfig = initConfig();
051: private static final EnvironmentConfig steadyStateAutoConfig = initConfig();
052: static {
053: highUtilizationConfig.setConfigParam(
054: EnvironmentParams.CLEANER_MIN_UTILIZATION.getName(),
055: String.valueOf(90));
056:
057: steadyStateAutoConfig.setConfigParam(
058: EnvironmentParams.ENV_RUN_CLEANER.getName(), "true");
059: }
060:
061: static EnvironmentConfig initConfig() {
062: EnvironmentConfig config = TestUtils.initEnvConfig();
063: DbInternal.disableParameterValidation(config);
064: config.setTransactional(true);
065: config.setAllowCreate(true);
066: config.setTxnNoSync(Boolean.getBoolean(TestUtils.NO_SYNC));
067: config.setConfigParam(EnvironmentParams.LOG_FILE_MAX.getName(),
068: Integer.toString(FILE_SIZE));
069: config.setConfigParam(EnvironmentParams.ENV_CHECK_LEAKS
070: .getName(), "false");
071: config.setConfigParam(EnvironmentParams.ENV_RUN_CLEANER
072: .getName(), "false");
073: config.setConfigParam(EnvironmentParams.CLEANER_REMOVE
074: .getName(), "false");
075: config.setConfigParam(EnvironmentParams.ENV_RUN_CHECKPOINTER
076: .getName(), "false");
077: config
078: .setConfigParam(
079: EnvironmentParams.CLEANER_MIN_FILES_TO_DELETE
080: .getName(), "1");
081: config.setConfigParam(EnvironmentParams.CLEANER_LOCK_TIMEOUT
082: .getName(), "1");
083: config.setConfigParam(EnvironmentParams.CLEANER_MAX_BATCH_FILES
084: .getName(), "1");
085: return config;
086: }
087:
088: private static final CheckpointConfig forceConfig = new CheckpointConfig();
089: static {
090: forceConfig.setForce(true);
091: }
092:
093: private File envHome;
094: private Environment env;
095: private EnvironmentImpl envImpl;
096: private Database db;
097: private boolean dups;
098:
099: /* The index is the file number, the value is the first key in the file. */
100: private List firstKeysInFiles;
101:
102: /* Set of keys that should exist. */
103: private Set existingKeys;
104:
105: public FileSelectionTest() {
106: envHome = new File(System.getProperty(TestUtils.DEST_DIR));
107: }
108:
109: public void setUp() throws IOException, DatabaseException {
110:
111: TestUtils.removeLogFiles("Setup", envHome, false);
112: TestUtils.removeFiles("Setup", envHome, FileManager.DEL_SUFFIX);
113: }
114:
115: public void tearDown() throws IOException, DatabaseException {
116:
117: try {
118: if (env != null) {
119: env.close();
120: }
121: } catch (Throwable e) {
122: System.out.println("tearDown: " + e);
123: }
124:
125: //*
126: try {
127: TestUtils.removeLogFiles("tearDown", envHome, true);
128: TestUtils.removeFiles("tearDown", envHome,
129: FileManager.DEL_SUFFIX);
130: } catch (Throwable e) {
131: System.out.println("tearDown: " + e);
132: }
133: //*/
134:
135: db = null;
136: env = null;
137: envImpl = null;
138: envHome = null;
139: firstKeysInFiles = null;
140: }
141:
142: private void openEnv() throws DatabaseException {
143:
144: openEnv(envConfig);
145: }
146:
147: private void openEnv(EnvironmentConfig config)
148: throws DatabaseException {
149:
150: env = new Environment(envHome, config);
151: envImpl = DbInternal.envGetEnvironmentImpl(env);
152:
153: DatabaseConfig dbConfig = new DatabaseConfig();
154: dbConfig.setTransactional(true);
155: dbConfig.setAllowCreate(true);
156: dbConfig.setSortedDuplicates(dups);
157: db = env.openDatabase(null, "cleanerFileSelection", dbConfig);
158: }
159:
160: private void closeEnv() throws DatabaseException {
161:
162: if (db != null) {
163: db.close();
164: db = null;
165: }
166: if (env != null) {
167: env.close();
168: env = null;
169: }
170: }
171:
172: /**
173: * Tests that the test utilities work.
174: */
175: public void testBaseline() throws DatabaseException {
176:
177: openEnv();
178: writeData();
179: verifyData();
180: verifyDeletedFiles(null);
181: closeEnv();
182: openEnv();
183: verifyData();
184: verifyDeletedFiles(null);
185: closeEnv();
186: }
187:
188: public void testBaselineDups() throws DatabaseException {
189:
190: dups = true;
191: testBaseline();
192: }
193:
194: /**
195: * Tests that the expected files are selected for cleaning.
196: */
197: public void testBasic() throws DatabaseException {
198:
199: openEnv();
200: writeData();
201: verifyDeletedFiles(null);
202:
203: /*
204: * The first file should be the first to be cleaned because it has
205: * relatively few LNs.
206: */
207: forceCleanOne();
208: verifyDeletedFiles(new int[] { 0 });
209: verifyData();
210:
211: /*
212: * Delete most of the LNs in two middle files. They should be the next
213: * two files cleaned.
214: */
215: int fileNum = INITIAL_FILES / 2;
216: int firstKey = ((Integer) firstKeysInFiles.get(fileNum))
217: .intValue();
218: int nextKey = ((Integer) firstKeysInFiles.get(fileNum + 1))
219: .intValue();
220: int count = nextKey - firstKey - 4;
221: deleteData(firstKey, count);
222:
223: fileNum += 1;
224: firstKey = ((Integer) firstKeysInFiles.get(fileNum)).intValue();
225: nextKey = ((Integer) firstKeysInFiles.get(fileNum + 1))
226: .intValue();
227: count = nextKey - firstKey - 4;
228: deleteData(firstKey, count);
229:
230: forceCleanOne();
231: forceCleanOne();
232: verifyDeletedFiles(new int[] { 0, fileNum - 1, fileNum });
233: verifyData();
234:
235: closeEnv();
236: }
237:
238: public void testBasicDups() throws DatabaseException {
239:
240: dups = true;
241: testBasic();
242: }
243:
244: /*
245: * testCleaningMode, testTruncateDatabase, and testRemoveDatabase and are
246: * not tested with dups=true because with duplicates the total utilization
247: * after calling writeData() is 47%, so cleaning will occur and the tests
248: * don't expect that.
249: */
250:
251: /**
252: * Tests that routine cleaning does not clean when it should not.
253: */
254: public void testCleaningMode() throws DatabaseException {
255:
256: int nextFile = -1;
257: int nCleaned;
258:
259: /*
260: * Nothing is cleaned with routine cleaning, even after reopening the
261: * environment.
262: */
263: openEnv();
264: writeData();
265:
266: nCleaned = cleanRoutine();
267: assertEquals(0, nCleaned);
268: nextFile = getNextDeletedFile(nextFile);
269: assertTrue(nextFile == -1);
270:
271: verifyData();
272: closeEnv();
273: openEnv();
274: verifyData();
275:
276: nCleaned = cleanRoutine();
277: assertEquals(0, nCleaned);
278: nextFile = getNextDeletedFile(nextFile);
279: assertTrue(nextFile == -1);
280:
281: verifyData();
282:
283: closeEnv();
284: }
285:
286: /**
287: * Test retries after cleaning fails because an LN was write-locked.
288: */
289: public void testRetry() throws DatabaseException {
290:
291: openEnv(highUtilizationConfig);
292: writeData();
293: verifyData();
294:
295: /*
296: * The first file is full of LNs. Delete all but the last record to
297: * cause it to be selected next for cleaning.
298: */
299: int firstKey = ((Integer) firstKeysInFiles.get(1)).intValue();
300: int nextKey = ((Integer) firstKeysInFiles.get(2)).intValue();
301: int count = nextKey - firstKey - 1;
302: deleteData(firstKey, count);
303: verifyData();
304:
305: /* Write-lock the last record to cause cleaning to fail. */
306: Transaction txn = env.beginTransaction(null, null);
307: Cursor cursor = db.openCursor(txn, null);
308: DatabaseEntry key = new DatabaseEntry();
309: DatabaseEntry data = new DatabaseEntry();
310: OperationStatus status;
311: if (dups) {
312: key.setData(MAIN_KEY_FOR_DUPS);
313: data.setData(TestUtils.getTestArray(nextKey - 1));
314: status = cursor.getSearchBoth(key, data, LockMode.RMW);
315: } else {
316: key.setData(TestUtils.getTestArray(nextKey - 1));
317: status = cursor.getSearchKey(key, data, LockMode.RMW);
318: }
319: assertEquals(OperationStatus.SUCCESS, status);
320: status = cursor.delete();
321: assertEquals(OperationStatus.SUCCESS, status);
322:
323: /* Cleaning should fail. */
324: forceCleanOne();
325: verifyDeletedFiles(null);
326: forceCleanOne();
327: verifyDeletedFiles(null);
328:
329: /* Release the write-lock. */
330: cursor.close();
331: txn.abort();
332: verifyData();
333:
334: /* Cleaning should succeed, with all files deleted. */
335: forceCleanOne();
336: verifyDeletedFiles(new int[] { 0, 1, 2 });
337: verifyData();
338:
339: closeEnv();
340: }
341:
342: /**
343: * Tests that the je.cleaner.minFileUtilization property works as expected.
344: */
345: public void testMinFileUtilization() throws DatabaseException {
346:
347: /* Open with minUtilization=10 and minFileUtilization=0. */
348: EnvironmentConfig myConfig = initConfig();
349: myConfig.setConfigParam(
350: EnvironmentParams.CLEANER_MIN_UTILIZATION.getName(),
351: String.valueOf(10));
352: myConfig.setConfigParam(
353: EnvironmentParams.CLEANER_MIN_FILE_UTILIZATION
354: .getName(), String.valueOf(0));
355: openEnv(myConfig);
356:
357: /* Write data and delete two thirds of the LNs in the middle file. */
358: writeData();
359: verifyDeletedFiles(null);
360: int fileNum = INITIAL_FILES / 2;
361: int firstKey = ((Integer) firstKeysInFiles.get(fileNum))
362: .intValue();
363: int nextKey = ((Integer) firstKeysInFiles.get(fileNum + 1))
364: .intValue();
365: int count = ((nextKey - firstKey) * 2) / 3;
366: deleteData(firstKey, count);
367:
368: /* The file should not be deleted. */
369: env.cleanLog();
370: env.checkpoint(forceConfig);
371: verifyDeletedFiles(null);
372:
373: /* Change minFileUtilization=50 */
374: myConfig.setConfigParam(
375: EnvironmentParams.CLEANER_MIN_FILE_UTILIZATION
376: .getName(), String.valueOf(50));
377: env.setMutableConfig(myConfig);
378:
379: /* The file should now be deleted. */
380: env.cleanLog();
381: env.checkpoint(forceConfig);
382: verifyDeletedFiles(new int[] { fileNum });
383: verifyData();
384:
385: closeEnv();
386: }
387:
388: private void printFiles(String msg) {
389: System.out.print(msg);
390: Long lastNum = envImpl.getFileManager().getLastFileNum();
391: for (int i = 0; i <= (int) lastNum.longValue(); i += 1) {
392: String name = envImpl.getFileManager().getFullFileName(i,
393: FileManager.JE_SUFFIX);
394: if (new File(name).exists()) {
395: System.out.print(" " + i);
396: }
397: }
398: System.out.println("");
399: }
400:
401: public void testRetryDups() throws DatabaseException {
402:
403: dups = true;
404: testRetry();
405: }
406:
407: /**
408: * Steady state should occur with normal (50% utilization) configuration
409: * and automatic checkpointing and cleaning.
410: */
411: public void testSteadyStateAutomatic() throws DatabaseException {
412:
413: doSteadyState(steadyStateAutoConfig, false, 13);
414: }
415:
416: public void testSteadyStateAutomaticDups() throws DatabaseException {
417:
418: dups = true;
419: testSteadyStateAutomatic();
420: }
421:
422: /**
423: * Steady state utilization with manual checkpointing and cleaning.
424: */
425: public void testSteadyStateManual() throws DatabaseException {
426:
427: doSteadyState(envConfig, true, 13);
428: }
429:
430: public void testSteadyStateManualDups() throws DatabaseException {
431:
432: dups = true;
433: testSteadyStateManual();
434: }
435:
436: /**
437: * Steady state should occur when utilization is at the maximum.
438: */
439: public void testSteadyStateHighUtilization()
440: throws DatabaseException {
441:
442: doSteadyState(highUtilizationConfig, true, 9);
443: }
444:
445: public void testSteadyStateHighUtilizationDups()
446: throws DatabaseException {
447:
448: dups = true;
449: testSteadyStateHighUtilization();
450: }
451:
452: /**
453: * Tests that we quickly reach a steady state of disk usage when updates
454: * are made but no net increase in data occurs.
455: *
456: * @param manualCleaning is whether to run cleaning manually every
457: * iteration, or to rely on the cleaner thread.
458: *
459: * @param maxFileCount the maximum number of files allowed for this test.
460: */
461: private void doSteadyState(EnvironmentConfig config,
462: boolean manualCleaning, int maxFileCount)
463: throws DatabaseException {
464:
465: openEnv(config);
466: writeData();
467: verifyData();
468:
469: final int iterations = 100;
470:
471: for (int i = 0; i < iterations; i += 1) {
472: updateData(100, 100);
473: int cleaned = -1;
474: if (manualCleaning) {
475: cleaned = cleanRoutine();
476: } else {
477: /* Need to delay a bit for the cleaner to keep up. */
478: try {
479: Thread.sleep(25);
480: } catch (InterruptedException e) {
481: }
482: }
483:
484: /*
485: * Checkpoints need to occur often for the cleaner to keep up.
486: * and to delete files that were cleaned.
487: */
488: env.checkpoint(forceConfig);
489: verifyData();
490: int fileCount = envImpl.getFileManager()
491: .getAllFileNumbers().length;
492: assertTrue("fileCount=" + fileCount + " maxFileCount="
493: + maxFileCount, fileCount <= maxFileCount);
494: if (false) {
495: System.out.println("fileCount=" + fileCount
496: + " cleaned=" + cleaned);
497: }
498: }
499: closeEnv();
500: }
501:
502: /**
503: * Tests that truncate causes cleaning.
504: * @deprecated use of Database.truncate
505: */
506: public void testTruncateDatabase() throws DatabaseException {
507:
508: int nCleaned;
509:
510: openEnv();
511: writeData();
512:
513: nCleaned = cleanRoutine();
514: assertEquals(0, nCleaned);
515:
516: db.truncate(null, false);
517: nCleaned = cleanRoutine();
518: assertEquals(4, nCleaned);
519:
520: closeEnv();
521: }
522:
523: /**
524: * Tests that remove causes cleaning.
525: */
526: public void testRemoveDatabase() throws DatabaseException {
527:
528: int nCleaned;
529:
530: openEnv();
531: writeData();
532:
533: String dbName = db.getDatabaseName();
534: db.close();
535: db = null;
536:
537: nCleaned = cleanRoutine();
538: assertEquals(0, nCleaned);
539:
540: env.removeDatabase(null, dbName);
541: nCleaned = cleanRoutine();
542: assertEquals(4, nCleaned);
543:
544: closeEnv();
545: }
546:
547: public void testForceCleanFiles() throws DatabaseException {
548:
549: /* No files force cleaned. */
550: EnvironmentConfig myConfig = initConfig();
551: openEnv(myConfig);
552: writeData();
553: verifyData();
554: env.cleanLog();
555: env.checkpoint(forceConfig);
556: verifyDeletedFiles(null);
557: closeEnv();
558:
559: /* Force cleaning: 3 */
560: myConfig.setConfigParam(
561: EnvironmentParams.CLEANER_FORCE_CLEAN_FILES.getName(),
562: "3");
563: openEnv(myConfig);
564: forceCleanOne();
565: verifyDeletedFiles(new int[] { 3 });
566: closeEnv();
567:
568: /* Force cleaning: 0 - 1 */
569: myConfig.setConfigParam(
570: EnvironmentParams.CLEANER_FORCE_CLEAN_FILES.getName(),
571: "0-1");
572: openEnv(myConfig);
573: forceCleanOne();
574: forceCleanOne();
575: verifyDeletedFiles(new int[] { 0, 1, 3 });
576: closeEnv();
577: }
578:
579: /**
580: * Force cleaning of one file.
581: */
582: private void forceCleanOne() throws DatabaseException {
583:
584: envImpl.getCleaner().doClean(false, // cleanMultipleFiles
585: true); // forceCleaning
586: /* To force file deletion a checkpoint is necessary. */
587: env.checkpoint(forceConfig);
588: }
589:
590: /**
591: * Do routine cleaning just as normally done via the cleaner daemon, and
592: * return the number of files cleaned.
593: */
594: private int cleanRoutine() throws DatabaseException {
595:
596: return env.cleanLog();
597: }
598:
599: /**
600: * Writes data to create INITIAL_FILES number of files, storing the first
601: * key for each file in the firstKeysInFiles list. One extra file is
602: * actually created, to ensure that the firstActiveLSN is not in any of
603: * INITIAL_FILES files.
604: */
605: private void writeData() throws DatabaseException {
606:
607: DatabaseEntry key = new DatabaseEntry();
608: DatabaseEntry data = new DatabaseEntry(new byte[DATA_SIZE]);
609: firstKeysInFiles = new ArrayList();
610: existingKeys = new HashSet();
611:
612: Transaction txn = env.beginTransaction(null, null);
613: Cursor cursor = db.openCursor(txn, null);
614: int fileNum = -1;
615:
616: for (int nextKey = 0; fileNum < INITIAL_FILES; nextKey += 1) {
617:
618: OperationStatus status;
619: if (dups) {
620: key.setData(MAIN_KEY_FOR_DUPS);
621: data.setData(TestUtils.getTestArray(nextKey));
622: status = cursor.putNoDupData(key, data);
623: } else {
624: key.setData(TestUtils.getTestArray(nextKey));
625: data.setData(new byte[DATA_SIZE]);
626: status = cursor.putNoOverwrite(key, data);
627: }
628:
629: assertEquals(OperationStatus.SUCCESS, status);
630: existingKeys.add(new Integer(nextKey));
631:
632: long lsn = getLsn(cursor);
633: if (DbLsn.getFileNumber(lsn) != fileNum) {
634: assertTrue(fileNum < DbLsn.getFileNumber(lsn));
635: fileNum = (int) DbLsn.getFileNumber(lsn);
636: assertEquals(fileNum, firstKeysInFiles.size());
637: firstKeysInFiles.add(new Integer(nextKey));
638: }
639: }
640:
641: cursor.close();
642: txn.commit();
643: env.checkpoint(forceConfig);
644:
645: long firstActiveLsn = envImpl.getCheckpointer()
646: .getFirstActiveLsn();
647: assertTrue(firstActiveLsn != DbLsn.NULL_LSN);
648: assertTrue(DbLsn.getFileNumber(firstActiveLsn) >= INITIAL_FILES);
649: }
650:
651: /**
652: * Deletes the specified keys.
653: */
654: private void deleteData(int firstKey, int keyCount)
655: throws DatabaseException {
656:
657: DatabaseEntry key = new DatabaseEntry();
658: DatabaseEntry data = new DatabaseEntry();
659:
660: Transaction txn = env.beginTransaction(null, null);
661: Cursor cursor = db.openCursor(txn, null);
662:
663: for (int i = 0; i < keyCount; i += 1) {
664: int nextKey = firstKey + i;
665: OperationStatus status;
666: if (dups) {
667: key.setData(MAIN_KEY_FOR_DUPS);
668: data.setData(TestUtils.getTestArray(nextKey));
669: status = cursor.getSearchBoth(key, data, null);
670: } else {
671: key.setData(TestUtils.getTestArray(nextKey));
672: status = cursor.getSearchKey(key, data, null);
673: }
674: assertEquals(OperationStatus.SUCCESS, status);
675: status = cursor.delete();
676: assertEquals(OperationStatus.SUCCESS, status);
677: existingKeys.remove(new Integer(nextKey));
678: }
679:
680: cursor.close();
681: txn.commit();
682: }
683:
684: /**
685: * Updates the specified keys.
686: */
687: private void updateData(int firstKey, int keyCount)
688: throws DatabaseException {
689:
690: DatabaseEntry key = new DatabaseEntry();
691: DatabaseEntry data = new DatabaseEntry();
692:
693: Transaction txn = env.beginTransaction(null, null);
694: Cursor cursor = db.openCursor(txn, null);
695:
696: for (int i = 0; i < keyCount; i += 1) {
697: int nextKey = firstKey + i;
698: OperationStatus status;
699: if (dups) {
700: key.setData(MAIN_KEY_FOR_DUPS);
701: data.setData(TestUtils.getTestArray(nextKey));
702: status = cursor.getSearchBoth(key, data, null);
703: assertEquals(OperationStatus.SUCCESS, status);
704: assertEquals(MAIN_KEY_FOR_DUPS.length, key.getSize());
705: assertEquals(nextKey, TestUtils.getTestVal(data
706: .getData()));
707: } else {
708: key.setData(TestUtils.getTestArray(nextKey));
709: status = cursor.getSearchKey(key, data, null);
710: assertEquals(OperationStatus.SUCCESS, status);
711: assertEquals(nextKey, TestUtils.getTestVal(key
712: .getData()));
713: assertEquals(DATA_SIZE, data.getSize());
714: }
715: status = cursor.putCurrent(data);
716: assertEquals(OperationStatus.SUCCESS, status);
717: }
718:
719: cursor.close();
720: txn.commit();
721: }
722:
723: /**
724: * Verifies that the data written by writeData can be read.
725: */
726: private void verifyData() throws DatabaseException {
727:
728: DatabaseEntry key = new DatabaseEntry();
729: DatabaseEntry data = new DatabaseEntry();
730:
731: Transaction txn = env.beginTransaction(null, null);
732: Cursor cursor = db.openCursor(txn, null);
733:
734: for (Iterator i = existingKeys.iterator(); i.hasNext();) {
735: int nextKey = ((Integer) i.next()).intValue();
736: OperationStatus status;
737: if (dups) {
738: key.setData(MAIN_KEY_FOR_DUPS);
739: data.setData(TestUtils.getTestArray(nextKey));
740: status = cursor.getSearchBoth(key, data, null);
741: assertEquals(OperationStatus.SUCCESS, status);
742: assertEquals(MAIN_KEY_FOR_DUPS.length, key.getSize());
743: assertEquals(nextKey, TestUtils.getTestVal(data
744: .getData()));
745: } else {
746: key.setData(TestUtils.getTestArray(nextKey));
747: status = cursor.getSearchKey(key, data, null);
748: assertEquals(OperationStatus.SUCCESS, status);
749: assertEquals(nextKey, TestUtils.getTestVal(key
750: .getData()));
751: assertEquals(DATA_SIZE, data.getSize());
752: }
753: }
754:
755: cursor.close();
756: txn.commit();
757: }
758:
759: /**
760: * Checks that all log files exist except those specified.
761: */
762: private void verifyDeletedFiles(int[] shouldNotExist) {
763: Long lastNum = envImpl.getFileManager().getLastFileNum();
764: for (int i = 0; i <= (int) lastNum.longValue(); i += 1) {
765: boolean shouldExist = true;
766: if (shouldNotExist != null) {
767: for (int j = 0; j < shouldNotExist.length; j += 1) {
768: if (i == shouldNotExist[j]) {
769: shouldExist = false;
770: break;
771: }
772: }
773: }
774: String name = envImpl.getFileManager().getFullFileName(i,
775: FileManager.JE_SUFFIX);
776: assertEquals(name, shouldExist, new File(name).exists());
777: }
778: }
779:
780: /**
781: * Returns the first deleted file number or -1 if none.
782: */
783: private int getNextDeletedFile(int afterFile) {
784: Long lastNum = envImpl.getFileManager().getLastFileNum();
785: for (int i = afterFile + 1; i <= (int) lastNum.longValue(); i += 1) {
786: String name = envImpl.getFileManager().getFullFileName(i,
787: FileManager.JE_SUFFIX);
788: if (!(new File(name).exists())) {
789: return i;
790: }
791: }
792: return -1;
793: }
794:
795: /**
796: * Gets the LSN at the cursor position, using internal methods.
797: */
798: private long getLsn(Cursor cursor) throws DatabaseException {
799:
800: CursorImpl impl = DbTestProxy.dbcGetCursorImpl(cursor);
801: BIN bin;
802: int index;
803: if (dups) {
804: bin = impl.getDupBIN();
805: index = impl.getDupIndex();
806: if (bin == null) {
807: bin = impl.getBIN();
808: index = impl.getIndex();
809: assertNotNull(bin);
810: }
811: } else {
812: assertNull(impl.getDupBIN());
813: bin = impl.getBIN();
814: index = impl.getIndex();
815: assertNotNull(bin);
816: }
817: assertTrue(index >= 0);
818: long lsn = bin.getLsn(index);
819: assertTrue(lsn != DbLsn.NULL_LSN);
820: return lsn;
821: }
822: }
|