KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > je > cleaner > INUtilizationTest


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002,2006 Oracle. All rights reserved.
5  *
6  * $Id: INUtilizationTest.java,v 1.21 2006/11/17 23:47:28 mark Exp $
7  */

8
9 package com.sleepycat.je.cleaner;
10
11 import java.io.File JavaDoc;
12 import java.io.IOException JavaDoc;
13
14 import junit.framework.TestCase;
15
16 import com.sleepycat.bind.tuple.IntegerBinding;
17 import com.sleepycat.je.CheckpointConfig;
18 import com.sleepycat.je.Cursor;
19 import com.sleepycat.je.Database;
20 import com.sleepycat.je.DatabaseConfig;
21 import com.sleepycat.je.DatabaseEntry;
22 import com.sleepycat.je.DatabaseException;
23 import com.sleepycat.je.DbInternal;
24 import com.sleepycat.je.Environment;
25 import com.sleepycat.je.EnvironmentConfig;
26 import com.sleepycat.je.Transaction;
27 import com.sleepycat.je.config.EnvironmentParams;
28 import com.sleepycat.je.dbi.EnvironmentImpl;
29 import com.sleepycat.je.log.FileManager;
30 import com.sleepycat.je.log.LogEntryType;
31 import com.sleepycat.je.log.SearchFileReader;
32 import com.sleepycat.je.tree.IN;
33 import com.sleepycat.je.util.TestUtils;
34 import com.sleepycat.je.utilint.CmdUtil;
35 import com.sleepycat.je.utilint.DbLsn;
36
37 public class INUtilizationTest extends TestCase {
38
39     private static final String JavaDoc DB_NAME = "foo";
40
41     private static final CheckpointConfig forceConfig = new CheckpointConfig();
42     static {
43         forceConfig.setForce(true);
44     }
45
46     private File JavaDoc envHome;
47     private Environment env;
48     private EnvironmentImpl envImpl;
49     private Database db;
50     private Transaction txn;
51     private Cursor cursor;
52     private boolean dups = false;
53     private DatabaseEntry keyEntry = new DatabaseEntry();
54     private DatabaseEntry dataEntry = new DatabaseEntry();
55
56     public INUtilizationTest() {
57         envHome = new File JavaDoc(System.getProperty(TestUtils.DEST_DIR));
58     }
59
60     public void setUp()
61         throws IOException JavaDoc, DatabaseException {
62
63         TestUtils.removeLogFiles("Setup", envHome, false);
64         TestUtils.removeFiles("Setup", envHome, FileManager.DEL_SUFFIX);
65     }
66
67     public void tearDown()
68         throws IOException JavaDoc, DatabaseException {
69
70         try {
71             if (env != null) {
72                 env.close();
73             }
74         } catch (Throwable JavaDoc e) {
75             System.out.println("tearDown: " + e);
76         }
77                 
78         try {
79             //*
80
TestUtils.removeLogFiles("tearDown", envHome, true);
81             TestUtils.removeFiles("tearDown", envHome, FileManager.DEL_SUFFIX);
82             //*/
83
} catch (Throwable JavaDoc e) {
84             System.out.println("tearDown: " + e);
85         }
86
87         envHome = null;
88         env = null;
89         envImpl = null;
90         db = null;
91         txn = null;
92         cursor = null;
93         keyEntry = null;
94         dataEntry = null;
95     }
96
97     /**
98      * Opens the environment and database.
99      */

100     private void openEnv()
101         throws DatabaseException {
102
103         EnvironmentConfig config = TestUtils.initEnvConfig();
104     DbInternal.disableParameterValidation(config);
105         config.setTransactional(true);
106         config.setTxnNoSync(true);
107         config.setAllowCreate(true);
108         /* Do not run the daemons. */
109         config.setConfigParam
110             (EnvironmentParams.ENV_RUN_CLEANER.getName(), "false");
111         config.setConfigParam
112             (EnvironmentParams.ENV_RUN_EVICTOR.getName(), "false");
113         config.setConfigParam
114         (EnvironmentParams.ENV_RUN_CHECKPOINTER.getName(), "false");
115         config.setConfigParam
116             (EnvironmentParams.ENV_RUN_INCOMPRESSOR.getName(), "false");
117         /* Use a tiny log file size to write one node per file. */
118         config.setConfigParam(EnvironmentParams.LOG_FILE_MAX.getName(),
119                               Integer.toString(64));
120         env = new Environment(envHome, config);
121         envImpl = DbInternal.envGetEnvironmentImpl(env);
122
123         /* Speed up test that uses lots of very small files. */
124         envImpl.getFileManager().setSyncAtFileEnd(false);
125
126         openDb();
127     }
128
129     /**
130      * Opens the database.
131      */

132     private void openDb()
133         throws DatabaseException {
134
135         DatabaseConfig dbConfig = new DatabaseConfig();
136         dbConfig.setTransactional(true);
137         dbConfig.setAllowCreate(true);
138         dbConfig.setSortedDuplicates(dups);
139         db = env.openDatabase(null, DB_NAME, dbConfig);
140     }
141
142     private void closeEnv(boolean doCheckpoint)
143         throws DatabaseException {
144
145         closeEnv(doCheckpoint,
146                  true, // expectAccurateObsoleteLNCount
147
true); // expectAccurateObsoleteLNSize
148
}
149
150     private void closeEnv(boolean doCheckpoint,
151                           boolean expectAccurateObsoleteLNCount)
152         throws DatabaseException {
153
154         closeEnv(doCheckpoint,
155                  expectAccurateObsoleteLNCount,
156                  expectAccurateObsoleteLNCount);
157     }
158
159     /**
160      * Closes the environment and database.
161      *
162      * @param expectAccurateObsoleteLNCount should be false if
163      * performPartialCheckpoint was called previously.
164      */

165     private void closeEnv(boolean doCheckpoint,
166                           boolean expectAccurateObsoleteLNCount,
167                           boolean expectAccurateObsoleteLNSize)
168         throws DatabaseException {
169
170         /*
171          * Verify utilization using UtilizationFileReader.
172          * expectAccurateObsoleteLNCount is false if performPartialCheckpoint
173          * was called previously -- see CleanerTestUtils.verifyUtilization.
174          * expectAccurateObsoleteLNSize is false for truncate and remove tests.
175          */

176         CleanerTestUtils.verifyUtilization
177             (envImpl, expectAccurateObsoleteLNCount,
178              expectAccurateObsoleteLNSize);
179
180         if (db != null) {
181             db.close();
182             db = null;
183         }
184         if (envImpl != null) {
185             envImpl.close(doCheckpoint);
186             envImpl = null;
187             env = null;
188         }
189     }
190
191     /**
192      * Initial setup for all tests -- open env, put one record (or two for
193      * dups) and sync.
194      */

195     private void openAndWriteDatabase()
196         throws DatabaseException {
197
198         openEnv();
199         txn = env.beginTransaction(null, null);
200         cursor = db.openCursor(txn, null);
201
202         /* Put one record. */
203         IntegerBinding.intToEntry(0, keyEntry);
204         IntegerBinding.intToEntry(0, dataEntry);
205         cursor.put(keyEntry, dataEntry);
206
207         /* Add a duplicate but move cursor back to the first record. */
208         if (dups) {
209             IntegerBinding.intToEntry(1, dataEntry);
210             cursor.put(keyEntry, dataEntry);
211             cursor.getFirst(keyEntry, dataEntry, null);
212         }
213
214         /* Checkpoint to the root so nothing is dirty. */
215         env.sync();
216
217         /* Expect that BIN and parent IN files are not obsolete. */
218         long binFile = getBINFile(cursor);
219         long inFile = getINFile(cursor);
220         expectObsolete(binFile, false);
221         expectObsolete(inFile, false);
222     }
223
224     /**
225      * Tests that BIN and IN utilization counting works.
226      */

227     public void testBasic()
228         throws DatabaseException {
229
230         openAndWriteDatabase();
231         long binFile = getBINFile(cursor);
232         long inFile = getINFile(cursor);
233
234         /* Update to make BIN dirty. */
235         cursor.put(keyEntry, dataEntry);
236
237         /* Checkpoint */
238         env.checkpoint(forceConfig);
239
240         if (!dups) {
241             /* After checkpoint, expect BIN file is obsolete but not IN. */
242             expectObsolete(binFile, true);
243             expectObsolete(inFile, false);
244             assertTrue(binFile != getBINFile(cursor));
245             assertEquals(inFile, getINFile(cursor));
246
247             /* After second checkpoint, IN file becomes obsolete also. */
248             env.checkpoint(forceConfig);
249         }
250
251         /* Both BIN and IN are obsolete. */
252         expectObsolete(binFile, true);
253         expectObsolete(inFile, true);
254         assertTrue(binFile != getBINFile(cursor));
255         assertTrue(inFile != getINFile(cursor));
256
257         /* Expect that new files are not obsolete. */
258         long binFile2 = getBINFile(cursor);
259         long inFile2 = getINFile(cursor);
260         expectObsolete(binFile2, false);
261         expectObsolete(inFile2, false);
262
263         cursor.close();
264         txn.commit();
265         closeEnv(true);
266     }
267
268     /**
269      * Performs testBasic with duplicates.
270      */

271     public void testBasicDup()
272         throws DatabaseException {
273
274         dups = true;
275         testBasic();
276     }
277
278     /**
279      * Similar to testBasic, but logs INs explicitly and performs recovery to
280      * ensure utilization recovery works.
281      */

282     public void testRecovery()
283         throws DatabaseException {
284
285         openAndWriteDatabase();
286         long binFile = getBINFile(cursor);
287         long inFile = getINFile(cursor);
288
289         /* Close normally and reopen. */
290         cursor.close();
291         txn.commit();
292         closeEnv(true);
293         openEnv();
294         txn = env.beginTransaction(null, null);
295         cursor = db.openCursor(txn, null);
296
297         /* Position cursor to load BIN and IN. */
298         cursor.getSearchKey(keyEntry, dataEntry, null);
299
300         /* Expect BIN and IN files have not changed. */
301         assertEquals(binFile, getBINFile(cursor));
302         assertEquals(inFile, getINFile(cursor));
303         expectObsolete(binFile, false);
304         expectObsolete(inFile, false);
305
306         /*
307          * Log explicitly since we have no way to do a partial checkpoint.
308          * The BIN is logged provisionally and the IN non-provisionally.
309          */

310         TestUtils.logBINAndIN(env, cursor);
311
312         /* Expect to obsolete the BIN and IN. */
313         expectObsolete(binFile, true);
314         expectObsolete(inFile, true);
315         assertTrue(binFile != getBINFile(cursor));
316         assertTrue(inFile != getINFile(cursor));
317
318         /* Save current BIN and IN files. */
319         long binFile2 = getBINFile(cursor);
320         long inFile2 = getINFile(cursor);
321         expectObsolete(binFile2, false);
322         expectObsolete(inFile2, false);
323
324         /* Shutdown without a checkpoint and reopen. */
325         cursor.close();
326         txn.commit();
327         closeEnv(false);
328         openEnv();
329         txn = env.beginTransaction(null, null);
330         cursor = db.openCursor(txn, null);
331
332         /* Position cursor to load BIN and IN. */
333         cursor.getSearchKey(keyEntry, dataEntry, null);
334
335         /* Expect that recovery counts BIN and IN as obsolete. */
336         expectObsolete(binFile, true);
337         expectObsolete(inFile, true);
338         assertTrue(binFile != getBINFile(cursor));
339         assertTrue(inFile != getINFile(cursor));
340
341         /*
342          * Even though it is provisional, expect that current BIN is not
343          * obsolete because it is not part of partial checkpoint. This is
344          * similar to what happens with a split. The current IN is not
345          * obsolete either (nor is it provisional).
346          */

347         assertTrue(binFile2 == getBINFile(cursor));
348         assertTrue(inFile2 == getINFile(cursor));
349         expectObsolete(binFile2, false);
350         expectObsolete(inFile2, false);
351
352         /* Update to make BIN dirty. */
353         cursor.put(keyEntry, dataEntry);
354
355         /* Check current BIN and IN files. */
356         assertTrue(binFile2 == getBINFile(cursor));
357         assertTrue(inFile2 == getINFile(cursor));
358         expectObsolete(binFile2, false);
359         expectObsolete(inFile2, false);
360
361         /* Close normally and reopen to cause checkpoint of dirty BIN/IN. */
362         cursor.close();
363         txn.commit();
364         closeEnv(true);
365         openEnv();
366         txn = env.beginTransaction(null, null);
367         cursor = db.openCursor(txn, null);
368
369         /* Position cursor to load BIN and IN. */
370         cursor.getSearchKey(keyEntry, dataEntry, null);
371
372         /* Expect BIN and IN were checkpointed during close. */
373         assertTrue(binFile2 != getBINFile(cursor));
374         assertTrue(inFile2 != getINFile(cursor));
375         expectObsolete(binFile2, true);
376         expectObsolete(inFile2, true);
377
378         cursor.close();
379         txn.commit();
380         closeEnv(true);
381     }
382
383     /**
384      * Performs testRecovery with duplicates.
385      */

386     public void testRecoveryDup()
387         throws DatabaseException {
388
389         dups = true;
390         testRecovery();
391     }
392
393     /**
394      * Tests that in a partial checkpoint (CkptStart with no CkptEnd) all
395      * provisional INs are counted as obsolete.
396      */

397     public void testPartialCheckpoint()
398         throws DatabaseException, IOException JavaDoc {
399
400         openAndWriteDatabase();
401         long binFile = getBINFile(cursor);
402         long inFile = getINFile(cursor);
403
404         /* Close with partial checkpoint and reopen. */
405         cursor.close();
406         txn.commit();
407         performPartialCheckpoint(true); // truncateFileSummariesAlso
408
openEnv();
409         txn = env.beginTransaction(null, null);
410         cursor = db.openCursor(txn, null);
411
412         /* Position cursor to load BIN and IN. */
413         cursor.getSearchKey(keyEntry, dataEntry, null);
414
415         /* Expect BIN and IN files have not changed. */
416         assertEquals(binFile, getBINFile(cursor));
417         assertEquals(inFile, getINFile(cursor));
418         expectObsolete(binFile, false);
419         expectObsolete(inFile, false);
420
421         /* Update to make BIN dirty. */
422         cursor.put(keyEntry, dataEntry);
423
424         /* Check current BIN and IN files. */
425         assertTrue(binFile == getBINFile(cursor));
426         assertTrue(inFile == getINFile(cursor));
427         expectObsolete(binFile, false);
428         expectObsolete(inFile, false);
429
430         /* Close with partial checkpoint and reopen. */
431         cursor.close();
432         txn.commit();
433         performPartialCheckpoint(true, // truncateFileSummariesAlso
434
false); // expectAccurateObsoleteLNCount
435
openEnv();
436         txn = env.beginTransaction(null, null);
437         cursor = db.openCursor(txn, null);
438
439         /* Position cursor to load BIN and IN. */
440         cursor.getSearchKey(keyEntry, dataEntry, null);
441
442         /* Expect BIN and IN files are obsolete. */
443         assertTrue(binFile != getBINFile(cursor));
444         assertTrue(inFile != getINFile(cursor));
445         expectObsolete(binFile, true);
446         expectObsolete(inFile, true);
447
448         /*
449          * Expect that the current BIN is obsolete because it was provisional,
450          * and provisional nodes following CkptStart are counted obsolete
451          * even if that is sometimes incorrect. The parent IN file is not
452          * obsolete if dups are not configured, because it is not provisonal;
453          * it is provisional if dups are configured, because we dirty farther
454          * up the tree.
455          */

456         long binFile2 = getBINFile(cursor);
457         long inFile2 = getINFile(cursor);
458         expectObsolete(binFile2, true);
459         expectObsolete(inFile2, dups);
460
461         /*
462          * Now repeat the test above but do not truncate the FileSummaryLNs.
463          * The counting will be accurate because the FileSummaryLNs override
464          * what is counted manually during recovery.
465          */

466
467         /* Update to make BIN dirty. */
468         cursor.put(keyEntry, dataEntry);
469
470         /* Close with partial checkpoint and reopen. */
471         cursor.close();
472         txn.commit();
473         performPartialCheckpoint(false, // truncateFileSummariesAlso
474
false); // expectAccurateObsoleteLNCount
475
openEnv();
476         txn = env.beginTransaction(null, null);
477         cursor = db.openCursor(txn, null);
478
479         /* Position cursor to load BIN and IN. */
480         cursor.getSearchKey(keyEntry, dataEntry, null);
481
482         /* The prior BIN and IN files are now double-counted as obsolete. */
483         assertTrue(binFile2 != getBINFile(cursor));
484         assertTrue(inFile2 != getINFile(cursor));
485         expectObsolete(binFile2, 2);
486         expectObsolete(inFile2, dups ? 2 : 1);
487
488         /* Expect current BIN and IN files are not obsolete. */
489         binFile2 = getBINFile(cursor);
490         inFile2 = getINFile(cursor);
491         expectObsolete(binFile2, false);
492         expectObsolete(inFile2, false);
493
494         cursor.close();
495         txn.commit();
496         closeEnv(true, // doCheckpoint
497
false); // expectAccurateObsoleteLNCount
498
}
499
500     /**
501      * Performs testPartialCheckpoint with duplicates.
502      */

503     public void testPartialCheckpointDup()
504         throws DatabaseException, IOException JavaDoc {
505
506         dups = true;
507         testPartialCheckpoint();
508     }
509
510     /**
511      * Tests that deleting a subtree (by deleting the last LN in a BIN) is
512      * counted correctly.
513      */

514     public void testDelete()
515         throws DatabaseException, IOException JavaDoc {
516
517         openAndWriteDatabase();
518         long binFile = getBINFile(cursor);
519         long inFile = getINFile(cursor);
520
521         /* Close normally and reopen. */
522         cursor.close();
523         txn.commit();
524         closeEnv(true);
525         openEnv();
526         txn = env.beginTransaction(null, null);
527         cursor = db.openCursor(txn, null);
528
529         /* Position cursor to load BIN and IN. */
530         cursor.getSearchKey(keyEntry, dataEntry, null);
531
532         /* Expect BIN and IN are still not obsolete. */
533         assertEquals(binFile, getBINFile(cursor));
534         assertEquals(inFile, getINFile(cursor));
535         expectObsolete(binFile, false);
536         expectObsolete(inFile, false);
537
538         if (dups) {
539             /* Delete both records. */
540             cursor.delete();
541             cursor.getNext(keyEntry, dataEntry, null);
542             cursor.delete();
543         } else {
544
545             /*
546              * Add records until we move to the next BIN, so that the
547              * compressor would not need to delete the root in order to delete
548              * the BIN (deleting the root is not configured by default).
549              */

550             int keyVal = 0;
551             while (binFile == getBINFile(cursor)) {
552                 keyVal += 1;
553                 IntegerBinding.intToEntry(keyVal, keyEntry);
554                 cursor.put(keyEntry, dataEntry);
555             }
556             binFile = getBINFile(cursor);
557             inFile = getINFile(cursor);
558
559             /* Delete all records in the last BIN. */
560             while (binFile == getBINFile(cursor)) {
561                 cursor.delete();
562                 cursor.getLast(keyEntry, dataEntry, null);
563             }
564         }
565
566         /* Compressor daemon is not running -- they're not obsolete yet. */
567         expectObsolete(binFile, false);
568         expectObsolete(inFile, false);
569
570         /* Close cursor and compress. */
571         cursor.close();
572         txn.commit();
573         env.compress();
574
575         /*
576          * Now expect BIN and IN to be obsolete.
577          */

578         expectObsolete(binFile, true);
579         expectObsolete(inFile, true);
580
581         /* Close with partial checkpoint and reopen. */
582         performPartialCheckpoint(true); // truncateFileSummariesAlso
583
openEnv();
584
585         /*
586          * Expect both files to be obsolete after recovery, since the IN will
587          * have been dirtied and rewritten.
588          */

589         expectObsolete(binFile, true);
590         expectObsolete(inFile, true);
591
592         closeEnv(true, // doCheckpoint
593
false); // expectAccurateObsoleteLNCount
594
}
595
596     /**
597      * Performs testDelete with duplicates.
598      */

599     public void testDeleteDup()
600         throws DatabaseException, IOException JavaDoc {
601
602         dups = true;
603         testDelete();
604     }
605
606     /**
607      * Tests that truncating a database is counted correctly.
608      * Tests recovery also.
609      * @deprecated use of Database.truncate
610      */

611     public void testTruncate()
612         throws DatabaseException, IOException JavaDoc {
613
614         openAndWriteDatabase();
615         long binFile = getBINFile(cursor);
616         long inFile = getINFile(cursor);
617
618         /* Close normally and reopen. */
619         cursor.close();
620         txn.commit();
621         closeEnv(true, // doCheckpoint
622
true, // expectAccurateObsoleteLNCount
623
false); // expectAccurateObsoleteLNSize
624
openEnv();
625
626         /* Truncate. */
627         txn = env.beginTransaction(null, null);
628         db.truncate(txn, false);
629         txn.commit();
630
631         /* Expect BIN and IN are obsolete. */
632         expectObsolete(binFile, true);
633         expectObsolete(inFile, true);
634
635         /* Close with partial checkpoint and reopen. */
636         performPartialCheckpoint(true, // truncateFileSummariesAlso
637
true, // expectAccurateObsoleteLNCount
638
false); // expectAccurateObsoleteLNSize
639
openEnv();
640
641         /* Expect BIN and IN are counted obsolete during recovery. */
642         expectObsolete(binFile, true);
643         expectObsolete(inFile, true);
644
645         closeEnv(true, // doCheckpoint
646
false); // expectAccurateObsoleteLNCount
647
}
648
649     /**
650      * Tests that truncating a database is counted correctly.
651      * Tests recovery also.
652      */

653     public void testRemove()
654         throws DatabaseException, IOException JavaDoc {
655
656         openAndWriteDatabase();
657         long binFile = getBINFile(cursor);
658         long inFile = getINFile(cursor);
659
660         /* Close normally and reopen. */
661         cursor.close();
662         txn.commit();
663         closeEnv(true, // doCheckpoint
664
true, // expectAccurateObsoleteLNCount
665
false); // expectAccurateObsoleteLNSize
666
openEnv();
667
668         /* Remove. */
669         db.close();
670         db = null;
671         txn = env.beginTransaction(null, null);
672         env.removeDatabase(txn, DB_NAME);
673         txn.commit();
674
675         /* Expect BIN and IN are obsolete. */
676         expectObsolete(binFile, true);
677         expectObsolete(inFile, true);
678
679         /* Close with partial checkpoint and reopen. */
680         performPartialCheckpoint(true, // truncateFileSummariesAlso
681
true, // expectAccurateObsoleteLNCount
682
false); // expectAccurateObsoleteLNSize
683
openEnv();
684
685         /* Expect BIN and IN are counted obsolete during recovery. */
686         expectObsolete(binFile, true);
687         expectObsolete(inFile, true);
688
689         closeEnv(true, // doCheckpoint
690
false); // expectAccurateObsoleteLNCount
691
}
692
693     private void expectObsolete(long file, boolean obsolete)
694         throws DatabaseException {
695
696         FileSummary summary = getSummary(file);
697         assertEquals("totalINCount",
698                      1, summary.totalINCount);
699         assertEquals("obsoleteINCount",
700                      obsolete ? 1 : 0, summary.obsoleteINCount);
701     }
702
703     private void expectObsolete(long file, int obsoleteCount)
704         throws DatabaseException {
705
706         FileSummary summary = getSummary(file);
707         assertEquals("totalINCount",
708                      1, summary.totalINCount);
709         assertEquals("obsoleteINCount",
710                      obsoleteCount, summary.obsoleteINCount);
711     }
712
713     private long getINFile(Cursor cursor)
714         throws DatabaseException {
715
716         IN in = TestUtils.getIN(TestUtils.getBIN(cursor));
717         long lsn = in.getLastFullVersion();
718         assertTrue(lsn != DbLsn.NULL_LSN);
719         return DbLsn.getFileNumber(lsn);
720     }
721
722     private long getBINFile(Cursor cursor)
723         throws DatabaseException {
724
725         long lsn = TestUtils.getBIN(cursor).getLastFullVersion();
726         assertTrue(lsn != DbLsn.NULL_LSN);
727         return DbLsn.getFileNumber(lsn);
728     }
729
730     /**
731      * Returns the utilization summary for a given log file.
732      */

733     private FileSummary getSummary(long file)
734         throws DatabaseException {
735
736     return (FileSummary) envImpl.getUtilizationProfile()
737                                     .getFileSummaryMap(true)
738                                     .get(new Long JavaDoc(file));
739     }
740
741     private void performPartialCheckpoint(boolean truncateFileSummariesAlso)
742         throws DatabaseException, IOException JavaDoc {
743
744         performPartialCheckpoint(truncateFileSummariesAlso,
745                                  true, // expectAccurateObsoleteLNCount
746
true); // expectAccurateObsoleteLNSize
747
}
748
749     private void performPartialCheckpoint(boolean truncateFileSummariesAlso,
750                                           boolean
751                                           expectAccurateObsoleteLNCount)
752         throws DatabaseException, IOException JavaDoc {
753
754         performPartialCheckpoint(truncateFileSummariesAlso,
755                                  expectAccurateObsoleteLNCount,
756                                  expectAccurateObsoleteLNCount);
757     }
758
759     /**
760      * Performs a checkpoint and truncates the log before the last CkptEnd. If
761      * truncateFileSummariesAlso is true, truncates before the FileSummaryLNs
762      * that appear at the end of the checkpoint. The environment should be
763      * open when this method is called, and it will be closed when it returns.
764      */

765     private void performPartialCheckpoint
766                     (boolean truncateFileSummariesAlso,
767                      boolean expectAccurateObsoleteLNCount,
768                      boolean expectAccurateObsoleteLNSize)
769         throws DatabaseException, IOException JavaDoc {
770
771         /* Do a normal checkpoint. */
772         env.checkpoint(forceConfig);
773         long eofLsn = envImpl.getFileManager().getNextLsn();
774         long lastLsn = envImpl.getFileManager().getLastUsedLsn();
775         long truncateLsn;
776
777         /* Searching backward from end, find last CkptEnd. */
778         SearchFileReader searcher =
779             new SearchFileReader(envImpl, 1000, false, lastLsn, eofLsn,
780                                  LogEntryType.LOG_CKPT_END);
781         assertTrue(searcher.readNextEntry());
782         long ckptEnd = searcher.getLastLsn();
783
784         if (truncateFileSummariesAlso) {
785
786             /* Searching backward from CkptEnd, find last CkptStart. */
787             searcher =
788                 new SearchFileReader(envImpl, 1000, false, ckptEnd, eofLsn,
789                                      LogEntryType.LOG_CKPT_START);
790             assertTrue(searcher.readNextEntry());
791             long ckptStart = searcher.getLastLsn();
792
793             /* Searching forward from CkptStart, find first FileSummaryLN. */
794             searcher =
795                 new SearchFileReader(envImpl, 1000, true, ckptStart, eofLsn,
796                                      LogEntryType.LOG_FILESUMMARYLN);
797             assertTrue(searcher.readNextEntry());
798             truncateLsn = searcher.getLastLsn();
799         } else {
800             truncateLsn = ckptEnd;
801         }
802         
803         /*
804          * Close without another checkpoint, although it doesn't matter since
805          * we would truncate before it.
806          */

807         closeEnv(false, // doCheckpoint
808
expectAccurateObsoleteLNCount,
809                  expectAccurateObsoleteLNSize);
810
811         /* Truncate the log. */
812         EnvironmentImpl cmdEnv =
813         CmdUtil.makeUtilityEnvironment(envHome, false);
814         cmdEnv.getFileManager().truncateLog(DbLsn.getFileNumber(truncateLsn),
815                                             DbLsn.getFileOffset(truncateLsn));
816         cmdEnv.close(false);
817
818         /* Delete files following the truncated file. */
819         String JavaDoc[] fileNames = envHome.list();
820         for (int i = 0; i < fileNames.length; i += 1) {
821             String JavaDoc name = fileNames[i];
822             if (name.endsWith(".jdb")) {
823                 String JavaDoc numStr = name.substring(0, name.length() - 4);
824                 long fileNum = Long.parseLong(numStr, 16);
825                 if (fileNum > DbLsn.getFileNumber(truncateLsn)) {
826                     assertTrue(new File JavaDoc(envHome, name).delete());
827                 }
828             }
829         }
830     }
831 }
832
Popular Tags