KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > je > recovery > RecoveryCheckpointTest


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002,2006 Oracle. All rights reserved.
5  *
6  * $Id: RecoveryCheckpointTest.java,v 1.37 2006/10/30 21:14:48 bostic Exp $
7  */

8
9 package com.sleepycat.je.recovery;
10
11 import java.util.Hashtable JavaDoc;
12
13 import com.sleepycat.je.CheckpointConfig;
14 import com.sleepycat.je.Cursor;
15 import com.sleepycat.je.Database;
16 import com.sleepycat.je.DatabaseConfig;
17 import com.sleepycat.je.DatabaseEntry;
18 import com.sleepycat.je.DatabaseException;
19 import com.sleepycat.je.DbInternal;
20 import com.sleepycat.je.Environment;
21 import com.sleepycat.je.EnvironmentConfig;
22 import com.sleepycat.je.EnvironmentStats;
23 import com.sleepycat.je.LockMode;
24 import com.sleepycat.je.OperationStatus;
25 import com.sleepycat.je.StatsConfig;
26 import com.sleepycat.je.Transaction;
27 import com.sleepycat.je.config.EnvironmentParams;
28 import com.sleepycat.je.dbi.DatabaseId;
29 import com.sleepycat.je.dbi.DatabaseImpl;
30 import com.sleepycat.je.dbi.DbTree;
31 import com.sleepycat.je.dbi.EnvironmentImpl;
32 import com.sleepycat.je.junit.JUnitThread;
33 import com.sleepycat.je.util.TestUtils;
34
35 public class RecoveryCheckpointTest extends RecoveryTestBase {
36
37     volatile int sequence = 0;
38
39     public void setExtraProperties()
40     throws DatabaseException {
41
42         /*
43          * Make sure that the environments in this unit test always run with
44          * checkpointing off, so we can call it explcitly.
45          */

46         envConfig.setConfigParam
47             (EnvironmentParams.ENV_RUN_CHECKPOINTER.getName(), "false");
48     /*
49         envConfig.setConfigParam
50             (EnvironmentParams.JE_LOGGING_LEVEL.getName(), "CONFIG");
51     */

52     }
53
54     /**
55      * Run checkpoints on empty dbs.
56      */

57     public void testEmptyCheckpoint()
58         throws Throwable JavaDoc {
59
60         createEnvAndDbs(1 << 20, true, NUM_DBS);
61
62         try {
63
64             /*
65          * Run checkpoint on empty environment. Should be the second one
66          * run, the first was run by recovery when the environment was
67          * opened.
68          */

69             env.checkpoint(forceConfig);
70             EnvironmentStats stats = env.getStats(TestUtils.FAST_STATS);
71             assertEquals(2, stats.getNCheckpoints());
72             assertEquals(2, stats.getLastCheckpointId());
73
74             /* Shutdown, recover. */
75             Hashtable JavaDoc expectedData = new Hashtable JavaDoc(); // expected values
76
closeEnv();
77             recoverAndVerify(expectedData, NUM_DBS); // 0 checkpoints
78

79             /* Another checkpoint. */
80             EnvironmentConfig envConfig = TestUtils.initEnvConfig();
81             envConfig.setTransactional(true);
82         envConfig.setConfigParam
83         (EnvironmentParams.JE_LOGGING_LEVEL.getName(), "CONFIG");
84             env = new Environment(envHome, envConfig);
85             env.checkpoint(forceConfig);
86             stats = env.getStats(TestUtils.FAST_STATS);
87             assertEquals(2, stats.getNCheckpoints());
88             assertEquals(4, stats.getLastCheckpointId());
89
90             /* Shutdown, recover. */
91             env.close();
92             recoverAndVerify(expectedData, NUM_DBS);
93         } catch (Throwable JavaDoc t) {
94             t.printStackTrace();
95             throw t;
96         }
97     }
98
99     /**
100      * Run checkpoints on empty dbs.
101      */

102     public void testNoCheckpointOnOpenSR11861()
103         throws Throwable JavaDoc {
104
105         createEnvAndDbs(1 << 20, true, NUM_DBS);
106
107         try {
108
109             EnvironmentStats stats = env.getStats(TestUtils.FAST_STATS);
110             assertEquals(1, stats.getNCheckpoints());
111             assertEquals(1, stats.getLastCheckpointId());
112
113             /* Shutdown, recover. */
114             Hashtable JavaDoc expectedData = new Hashtable JavaDoc(); // expected values
115
Transaction txn = env.beginTransaction(null, null);
116         insertData(txn, 0, 1, expectedData, 1, true, NUM_DBS);
117         txn.commit();
118             closeEnv(); // closes without a checkpoint
119
recoverAndVerify(expectedData, NUM_DBS); // 1 checkpoint
120

121             EnvironmentConfig envConfig = TestUtils.initEnvConfig();
122             envConfig.setTransactional(true);
123             env = new Environment(envHome, envConfig);
124             stats = env.getStats(TestUtils.FAST_STATS);
125             assertEquals(0, stats.getNCheckpoints());
126             assertEquals(2, stats.getLastCheckpointId());
127         env.close();
128             env = new Environment(envHome, envConfig);
129             stats = env.getStats(TestUtils.FAST_STATS);
130             assertEquals(0, stats.getNCheckpoints());
131             assertEquals(2, stats.getLastCheckpointId());
132
133             /* Shutdown, recover. */
134             env.close();
135             recoverAndVerify(expectedData, NUM_DBS);
136         } catch (Throwable JavaDoc t) {
137             t.printStackTrace();
138             throw t;
139         }
140     }
141
142     /**
143      * Test checkpoints that end up using BINDeltas -- the recovery must work.
144      */

145     public void testBinDelta()
146     throws Throwable JavaDoc {
147
148         doTestBinDelta(true);
149     }
150
151     /**
152      * Same as testBinDelta but disallows deltas, to ensure that the
153      * setMinimizeRecoveryTime API works.
154      */

155     public void testNoBinDelta()
156     throws Throwable JavaDoc {
157
158         doTestBinDelta(false);
159     }
160
161     private void doTestBinDelta(boolean useDeltas)
162     throws Throwable JavaDoc {
163
164     createEnvAndDbs(1 << 20, false, NUM_DBS);
165
166         StatsConfig statsConfig = new StatsConfig();
167         statsConfig.setClear(true);
168
169         CheckpointConfig deltaConfig = new CheckpointConfig();
170         deltaConfig.setForce(true);
171         deltaConfig.setMinimizeRecoveryTime(!useDeltas);
172
173         try {
174             
175             /*
176              * Insert 4 records (nodeMax is 6), checkpoint, then insert 1
177              * record. The 1 record insertion will qualify for a delta,
178              * because the threshold percentage is 25%, and 25% of 4 is 1.
179              */

180             int numRecs = 4;
181             Hashtable JavaDoc expectedData = new Hashtable JavaDoc();
182             Transaction txn = env.beginTransaction(null, null);
183             insertData(txn, 0, numRecs, expectedData, 1, true, NUM_DBS);
184             env.checkpoint(forceConfig);
185             insertData(txn, numRecs+1, numRecs+2, expectedData,
186                1, true, NUM_DBS);
187             txn.commit();
188             
189             /*
190              * If useDeltas is true, this next checkpoint will end up using a
191              * BINDelta to log the last inserted record. It will have
192              * practically nothing but the root in the checkpoint.
193              */

194             EnvironmentStats stats = env.getStats(statsConfig);
195             env.checkpoint(deltaConfig);
196             stats = env.getStats(statsConfig);
197             if (useDeltas) {
198                 assertTrue(stats.getNDeltaINFlush() > 0);
199             } else {
200                 assertTrue(stats.getNDeltaINFlush() == 0);
201             }
202
203             /* Shutdown, recover from a checkpoint that uses BINDeltas. */
204             closeEnv();
205             recoverAndVerify(expectedData, NUM_DBS);
206         } catch (Throwable JavaDoc t) {
207             t.printStackTrace();
208             throw t;
209         }
210     }
211
212     /**
213      * Test the rollback of transactions that are active during a checkpoint.
214      */

215     public void testActiveWhileCheckpointing()
216         throws Throwable JavaDoc {
217
218     createEnvAndDbs(1 << 20, true, NUM_DBS);
219
220         try {
221             int numRecs = 1;
222             Hashtable JavaDoc expectedData = new Hashtable JavaDoc();
223             Transaction txn = env.beginTransaction(null, null);
224             insertData(txn, 0, numRecs, expectedData, 1, false, NUM_DBS);
225
226             /* Now run a checkpoint while this operation hasn't finished. */
227             env.checkpoint(forceConfig);
228             txn.abort();
229             
230             /* Shutdown, recover. */
231             closeEnv();
232             recoverAndVerify(expectedData, NUM_DBS);
233         } catch (Throwable JavaDoc t) {
234             t.printStackTrace();
235             throw t;
236         }
237     }
238
239     public void testSR11293()
240     throws Throwable JavaDoc {
241
242     createEnv(1 << 20, false);
243
244     Transaction dbTxn = env.beginTransaction(null, null);
245     EnvironmentImpl envImpl = DbInternal.envGetEnvironmentImpl(env);
246     final DbTree dbTree = envImpl.getDbMapTree();
247
248         DatabaseConfig dbConfig = new DatabaseConfig();
249         dbConfig.setTransactional(true);
250         dbConfig.setAllowCreate(true);
251         dbConfig.setSortedDuplicates(true);
252     final Database db = env.openDatabase(dbTxn, "foo", dbConfig);
253     dbTxn.commit();
254     final Transaction txn = env.beginTransaction(null, null);
255     sequence = 0;
256
257     /**
258      * The sequence between the two tester threads is:
259      *
260      * tester2: write 1/1 into the database. This causes the initial tree
261      * to be created (IN/BIN/LN). Flush that out to the disk with a full
262      * checkpoint. Signal tester1 and wait.
263      *
264      * tester1: Lock the MapLN for "foo" db. Signal tester2 and wait.
265      *
266      * tester2: Add 2/2 to the tree which causes the BIN to be dirtied.
267      * Signal tester1 to continue, perform a full checkpoint which will
268      * causes the root IN to be dirtied and flushed. DbTree.modifyDbRoot
269      * will block on the MapLN lock held by tester1.
270      *
271      * tester1: while tester2 is blocking on the MapLN lock, this thread is
272      * sleeping. When it wakes up, it releases the MapLN lock by aborting
273      * the transaction.
274      *
275      * tester2: modifyDbRoot finally acquires the write lock on foo-db's
276      * MapLN write lock, performs the update to the DbTree and returns from
277      * the sync().
278      */

279     JUnitThread tester1 =
280         new JUnitThread("testSR11293DbTreeLocker") {
281             public void testBody() {
282             try {
283                 /* Wait for tester2. */
284                 while (sequence < 1) {
285                 Thread.yield();
286                 }
287
288                 /* Lock the MapLN for the database. */
289                 DatabaseId fooId =
290                 DbInternal.dbGetDatabaseImpl(db).getId();
291                 DatabaseImpl fooDb = dbTree.getDb(fooId, 500000L);
292                 assert fooDb != null;
293
294                 sequence++;
295
296                 /* Wait for tester2. */
297                 while (sequence < 3) {
298                 Thread.yield();
299                 }
300
301                 try {
302                 Thread.sleep(3000);
303                 } catch (Exception JavaDoc E) {
304                 }
305
306                 try {
307                 txn.abort();
308                 db.close();
309                 env.close();
310                 } catch (DatabaseException DBE) {
311                 DBE.printStackTrace();
312                 fail("unexpected exception: " + DBE);
313                 }
314             } catch (DatabaseException DBE) {
315                 DBE.printStackTrace();
316                 fail("caught DatabaseException " + DBE);
317             }
318             }
319         };
320
321     JUnitThread tester2 =
322         new JUnitThread("testSR11293DbWriter") {
323             public void testBody() {
324             try {
325                 DatabaseEntry key =
326                 new DatabaseEntry(new byte[] { 1 });
327                 DatabaseEntry data =
328                 new DatabaseEntry(new byte[] { 1 });
329                 assertEquals(OperationStatus.SUCCESS,
330                      db.put(null, key, data));
331                 env.sync();
332
333                 sequence++;
334                 while (sequence < 2) {
335                 Thread.yield();
336                 }
337
338                 key.setData(new byte[] { 2 });
339                 data.setData(new byte[] { 2 });
340                 assertEquals(OperationStatus.SUCCESS,
341                      db.put(null, key, data));
342                 sequence++;
343                 env.sync();
344             } catch (DatabaseException DBE) {
345                 DBE.printStackTrace();
346                 fail("unexpected exception: " + DBE);
347             }
348             }
349         };
350
351     tester1.start();
352     tester2.start();
353     tester1.finishTest();
354     tester2.finishTest();
355
356         EnvironmentConfig recoveryConfig = TestUtils.initEnvConfig();
357
358         recoveryConfig.setConfigParam
359         (EnvironmentParams.ENV_RUN_CHECKPOINTER.getName(), "false");
360     recoveryConfig.setConfigParam
361         (EnvironmentParams.ENV_RUN_CLEANER.getName(), "false");
362     recoveryConfig.setConfigParam
363         (EnvironmentParams.ENV_RUN_EVICTOR.getName(), "false");
364
365         env = new Environment(envHome, recoveryConfig);
366     dbConfig.setAllowCreate(false);
367     dbConfig.setTransactional(false);
368     Database db2 = env.openDatabase(null, "foo", dbConfig);
369     Cursor c = db2.openCursor(null, null);
370     DatabaseEntry key = new DatabaseEntry();
371     DatabaseEntry data = new DatabaseEntry();
372     assertEquals(OperationStatus.SUCCESS,
373              c.getNext(key, data, LockMode.DEFAULT));
374     assertEquals((key.getData())[0], 1);
375     assertEquals((data.getData())[0], 1);
376
377     assertEquals(OperationStatus.SUCCESS,
378              c.getNext(key, data, LockMode.DEFAULT));
379     assertEquals((key.getData())[0], 2);
380     assertEquals((data.getData())[0], 2);
381     assertEquals(OperationStatus.NOTFOUND,
382              c.getNext(key, data, LockMode.DEFAULT));
383
384     c.close();
385     db2.close();
386     env.close();
387     }
388
389     /*
390      * See what happens if someone calls checkpoint on a read only environment.
391      */

392     public void testReadOnlyCheckpoint()
393         throws DatabaseException {
394         /* Create an environment, close. */
395         EnvironmentConfig c = TestUtils.initEnvConfig();
396         c.setAllowCreate(true);
397         Environment e = new Environment(envHome, c);
398         e.close();
399
400         /* Now open read only. */
401         c.setAllowCreate(false);
402         c.setReadOnly(true);
403         e = new Environment(envHome, c);
404         try {
405             CheckpointConfig ckptConfig = new CheckpointConfig();
406             ckptConfig.setForce(true);
407             e.checkpoint(ckptConfig);
408         } finally {
409             e.close();
410         }
411     }
412 }
413
Popular Tags